From 0afa28de0953ed528486a7d7ad6000f344624710 Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Tue, 9 Aug 2016 09:53:22 -0400 Subject: [PATCH] Changed autodetection of SiteURL (#3764) * Changed autoconfiguration of SiteURL to be done on every request * Added SiteURL to system console --- api/context.go | 16 +++++++---- api/post.go | 1 + model/config.go | 4 --- utils/config.go | 6 +--- webapp/actions/websocket_actions.jsx | 2 +- .../admin_console/configuration_settings.jsx | 20 +++++++++++++ .../create_team/components/team_url.jsx | 2 +- .../components/installed_incoming_webhook.jsx | 2 +- webapp/i18n/en.json | 3 ++ webapp/stores/team_store.jsx | 28 +++++++++---------- webapp/utils/utils.jsx | 4 +++ 11 files changed, 56 insertions(+), 32 deletions(-) diff --git a/api/context.go b/api/context.go index 08f41aa6dd..c0e6bf3b5d 100644 --- a/api/context.go +++ b/api/context.go @@ -39,6 +39,7 @@ type Context struct { Err *model.AppError teamURLValid bool teamURL string + siteURL string T goi18n.TranslateFunc Locale string TeamId string @@ -141,10 +142,11 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { isTokenFromQueryString = true } - // if the site url in the config isn't specified, infer if from this request and write it back to the config - if *utils.Cfg.ServiceSettings.SiteURL == "" { - *utils.Cfg.ServiceSettings.SiteURL = GetProtocol(r) + "://" + r.Host - utils.RegenerateClientConfig() + if *utils.Cfg.ServiceSettings.SiteURL != "" { + c.SetSiteURL(*utils.Cfg.ServiceSettings.SiteURL) + } else { + protocol := GetProtocol(r) + c.SetSiteURL(protocol + "://" + r.Host) } w.Header().Set(model.HEADER_REQUEST_ID, c.RequestId) @@ -439,6 +441,10 @@ func (c *Context) SetTeamURLFromSession() { } } +func (c *Context) SetSiteURL(url string) { + c.siteURL = url +} + func (c *Context) GetTeamURLFromTeam(team *model.Team) string { return c.GetSiteURL() + "/" + team.Name } @@ -454,7 +460,7 @@ func (c *Context) GetTeamURL() string { } func (c *Context) GetSiteURL() string { - return *utils.Cfg.ServiceSettings.SiteURL + return c.siteURL } func IsApiCall(r *http.Request) bool { diff --git a/api/post.go b/api/post.go index 0c7654df1e..d32d1c6a51 100644 --- a/api/post.go +++ b/api/post.go @@ -458,6 +458,7 @@ func handleWebhookEvents(c *Context, post *model.Post, team *model.Team, channel Err: nil, teamURLValid: c.teamURLValid, teamURL: c.teamURL, + siteURL: c.siteURL, T: c.T, Locale: c.Locale, TeamId: hook.TeamId, diff --git a/model/config.go b/model/config.go index 61d13360c8..d13ba19e66 100644 --- a/model/config.go +++ b/model/config.go @@ -870,10 +870,6 @@ func (o *Config) IsValid() *AppError { return NewLocAppError("Config.IsValid", "model.config.is_valid.listen_address.app_error", nil, "") } - if len(o.ServiceSettings.ListenAddress) == 0 { - return NewLocAppError("Config.IsValid", "model.config.is_valid.listen_address.app_error", nil, "") - } - if o.TeamSettings.MaxUsersPerTeam <= 0 { return NewLocAppError("Config.IsValid", "model.config.is_valid.max_users.app_error", nil, "") } diff --git a/utils/config.go b/utils/config.go index a1a6becd18..6646a341e8 100644 --- a/utils/config.go +++ b/utils/config.go @@ -186,7 +186,7 @@ func LoadConfig(fileName string) { Cfg = &config CfgHash = fmt.Sprintf("%x", md5.Sum([]byte(Cfg.ToJson()))) - RegenerateClientConfig() + ClientCfg = getClientConfig(Cfg) // Actions that need to run every time the config is loaded if ldapI := einterfaces.GetLdapInterface(); ldapI != nil { @@ -199,10 +199,6 @@ func LoadConfig(fileName string) { } } -func RegenerateClientConfig() { - ClientCfg = getClientConfig(Cfg) -} - func getClientConfig(c *model.Config) map[string]string { props := make(map[string]string) diff --git a/webapp/actions/websocket_actions.jsx b/webapp/actions/websocket_actions.jsx index e93b2d25be..9150e41119 100644 --- a/webapp/actions/websocket_actions.jsx +++ b/webapp/actions/websocket_actions.jsx @@ -32,7 +32,7 @@ const MAX_WEBSOCKET_FAILS = 7; export function initialize() { if (window.WebSocket) { - let connUrl = window.mm_config.SiteURL; + let connUrl = Utils.getSiteURL(); // replace the protocol with a websocket one if (connUrl.startsWith('https:')) { diff --git a/webapp/components/admin_console/configuration_settings.jsx b/webapp/components/admin_console/configuration_settings.jsx index e34167a30d..6a07e31cdb 100644 --- a/webapp/components/admin_console/configuration_settings.jsx +++ b/webapp/components/admin_console/configuration_settings.jsx @@ -28,6 +28,7 @@ export default class ConfigurationSettings extends AdminSettings { } getConfigFromState(config) { + config.ServiceSettings.SiteURL = this.state.siteURL; config.ServiceSettings.ListenAddress = this.state.listenAddress; config.ServiceSettings.WebserverMode = this.state.webserverMode; @@ -36,6 +37,7 @@ export default class ConfigurationSettings extends AdminSettings { getStateFromConfig(config) { return { + siteURL: config.ServiceSettings.SiteURL, listenAddress: config.ServiceSettings.ListenAddress, webserverMode: config.ServiceSettings.WebserverMode }; @@ -55,6 +57,24 @@ export default class ConfigurationSettings extends AdminSettings { renderSettings() { return ( + + } + placeholder={Utils.localizeMessage('admin.service.siteURLExample', 'Ex "https://mattermost.example.com:1234"')} + helpText={ + + } + value={this.state.siteURL} + onChange={this.handleChange} + /> {title} ); diff --git a/webapp/components/integrations/components/installed_incoming_webhook.jsx b/webapp/components/integrations/components/installed_incoming_webhook.jsx index 008000012f..965ed2bc9a 100644 --- a/webapp/components/integrations/components/installed_incoming_webhook.jsx +++ b/webapp/components/integrations/components/installed_incoming_webhook.jsx @@ -97,7 +97,7 @@ export default class InstalledIncomingWebhook extends React.Component { id='installed_integrations.url' defaultMessage='URL: {url}' values={{ - url: window.mm_config.SiteURL + '/hooks/' + incomingWebhook.id + url: Utils.getSiteURL() + '/hooks/' + incomingWebhook.id }} /> diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index 1dc2f49d1b..478fbf362f 100644 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -640,6 +640,9 @@ "admin.service.sessionCache": "Session Cache (minutes):", "admin.service.sessionCacheDesc": "The number of minutes to cache a session in memory.", "admin.service.sessionDaysEx": "Ex \"30\"", + "admin.service.siteURL": "Site URL:", + "admin.service.siteURLDescription": "The URL, including port number and protocol, from which users will access Mattermost. Leave blank to automatically configure based on incoming traffic.", + "admin.service.siteURLExample": "Ex \"https://mattermost.example.com:1234\"", "admin.service.ssoSessionDays": "Session length SSO (days):", "admin.service.ssoSessionDaysDesc": "The number of days from the last time a user entered their credentials to the expiry of the user's session. If the authentication method is SAML or GitLab, the user may automatically be logged back in to Mattermost if they are already logged in to SAML or GitLab. After changing this setting, the setting will take effect after the next time the user enters their credentials.", "admin.service.testingDescription": "When true, /loadtest slash command is enabled to load test accounts, data and text formatting. Changing this requires a server restart before taking effect.", diff --git a/webapp/stores/team_store.jsx b/webapp/stores/team_store.jsx index a482fa3a14..90cb66bb20 100644 --- a/webapp/stores/team_store.jsx +++ b/webapp/stores/team_store.jsx @@ -60,13 +60,7 @@ class TeamStoreClass extends EventEmitter { } getCurrentId() { - var team = this.get(this.currentTeamId); - - if (team) { - return team.id; - } - - return null; + return this.currentTeamId; } getCurrent() { @@ -80,10 +74,7 @@ class TeamStoreClass extends EventEmitter { } getCurrentTeamUrl() { - if (this.getCurrent()) { - return window.mm_config.SiteURL + '/' + this.getCurrent().name; - } - return ''; + return this.getTeamUrl(this.currentTeamId); } getCurrentTeamRelativeUrl() { @@ -97,7 +88,10 @@ class TeamStoreClass extends EventEmitter { const current = this.getCurrent(); if (current) { - return window.mm_config.SiteURL + '/signup_user_complete/?id=' + current.invite_id; + // can't call Utils.getSiteURL here because that introduces a circular dependency + const origin = window.mm_config.SiteURL || window.location.origin; + + return origin + '/signup_user_complete/?id=' + current.invite_id; } return ''; @@ -105,11 +99,15 @@ class TeamStoreClass extends EventEmitter { getTeamUrl(id) { const team = this.get(id); - if (team) { - return window.mm_config.SiteURL + '/' + team.name; + + if (!team) { + return ''; } - return ''; + // can't call Utils.getSiteURL here because that introduces a circular dependency + const origin = window.mm_config.SiteURL || window.location.origin; + + return origin + '/' + team.name; } saveTeam(team) { diff --git a/webapp/utils/utils.jsx b/webapp/utils/utils.jsx index e3db6d827a..9731d3ce26 100644 --- a/webapp/utils/utils.jsx +++ b/webapp/utils/utils.jsx @@ -1338,3 +1338,7 @@ export function isValidPassword(password) { return errorMsg; } + +export function getSiteURL() { + return global.mm_config.SiteURL || window.location.origin; +} \ No newline at end of file