diff --git a/server/channels/api4/system.go b/server/channels/api4/system.go index f2a4044e3e3..fb655792041 100644 --- a/server/channels/api4/system.go +++ b/server/channels/api4/system.go @@ -153,7 +153,7 @@ func getSystemPing(c *Context, w http.ResponseWriter, r *http.Request) { // Enhanced ping health check: // If an extra form value is provided then perform extra health checks for // database and file storage backends. - if r.FormValue("get_server_status") != "" { + if r.FormValue("get_server_status") == "true" { dbStatusKey := "database_status" s[dbStatusKey] = model.StatusOk diff --git a/webapp/channels/src/actions/admin_actions.jsx b/webapp/channels/src/actions/admin_actions.jsx index 704940c740d..366f8cbe5e5 100644 --- a/webapp/channels/src/actions/admin_actions.jsx +++ b/webapp/channels/src/actions/admin_actions.jsx @@ -444,9 +444,9 @@ export function restartServer() { }; } -export function ping() { +export function ping(getServerStatus, deviceId) { return async () => { - const data = await Client4.ping(); + const data = await Client4.ping(getServerStatus, deviceId); return data; }; } diff --git a/webapp/channels/src/components/admin_console/workspace-optimization/dashboard_checks/config.ts b/webapp/channels/src/components/admin_console/workspace-optimization/dashboard_checks/config.ts index 921addae37b..72c1e5f9ec9 100644 --- a/webapp/channels/src/components/admin_console/workspace-optimization/dashboard_checks/config.ts +++ b/webapp/channels/src/components/admin_console/workspace-optimization/dashboard_checks/config.ts @@ -7,6 +7,8 @@ import type {useIntl} from 'react-intl'; import type {AdminConfig} from '@mattermost/types/config'; +import {Client4} from 'mattermost-redux/client'; + import {ConsolePages, DocLinks} from 'utils/constants'; import {impactModifiers} from '../dashboard.data'; @@ -74,6 +76,40 @@ const sessionLength = ( }; }; +const fileStorage = async ( + config: Partial, + formatMessage: ReturnType['formatMessage'], + options: Options, +) => { + const testFileStorage = async () => { + const pingResponse = await Client4.ping(true); + + return pingResponse.filestore_status === 'OK' ? ItemStatus.OK : ItemStatus.ERROR; + }; + + const status = await testFileStorage(); + + return { + id: 'file_storage,', + title: formatMessage({ + id: 'admin.reporting.workspace_optimization.configuration.file_storage.title', + defaultMessage: 'File storage access is faulty.', + }), + description: formatMessage({ + id: 'admin.reporting.workspace_optimization.configuration.file_storage.description', + defaultMessage: 'Check your file storage settings to ensure your Mattermost workspace has access to the configured file storage.', + }), + configUrl: ConsolePages.FILE_STORAGE, + configText: formatMessage({id: 'admin.reporting.workspace_optimization.configuration.file_storage.cta', defaultMessage: 'Config file storage'}), + infoUrl: DocLinks.FILE_STORAGE, + infoText: formatMessage({id: 'admin.reporting.workspace_optimization.cta.learnMore', defaultMessage: 'Learn more'}), + telemetryAction: 'file_storage', + status, + scoreImpact: 50, + impactModifier: impactModifiers[status], + }; +}; + export const runConfigChecks = async ( config: Partial, formatMessage: ReturnType['formatMessage'], @@ -82,6 +118,7 @@ export const runConfigChecks = async ( const checks = [ ssl, sessionLength, + fileStorage, ]; const results = await Promise.all(checks.map((check) => check(config, formatMessage, options))); return results; diff --git a/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.tsx b/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.tsx index d2f4d3e1a8c..5dbfeee03a8 100644 --- a/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.tsx +++ b/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.tsx @@ -52,7 +52,7 @@ const RenewalLink = (props: RenewalLinkProps) => { const handleLinkClick = async (e: React.MouseEvent) => { e.preventDefault(); try { - const {status} = await Client4.ping(); + const {status} = await Client4.ping(false); if (status === 'OK' && renewalLink !== '') { if (props.telemetryInfo?.success) { trackEvent('renew_license', props.telemetryInfo.success); diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index 402d3f2a2a8..76654b9596d 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -1972,6 +1972,9 @@ "admin.reporting.workspace_optimization.chip_warnings": "Warnings: {count}", "admin.reporting.workspace_optimization.configuration.description": "You have configuration issues to resolve", "admin.reporting.workspace_optimization.configuration.descriptionOk": "You seem to have good configuration for SSL and Session Lengths!", + "admin.reporting.workspace_optimization.configuration.file_storage.cta": "Config file storage", + "admin.reporting.workspace_optimization.configuration.file_storage.description": "Check your file storage settings to ensure your Mattermost workspace has access to the configured file storage.", + "admin.reporting.workspace_optimization.configuration.file_storage.title": "File storage access is faulty.", "admin.reporting.workspace_optimization.configuration.session_length.cta": "Configure session length", "admin.reporting.workspace_optimization.configuration.session_length.description": "Your session length is set to the default of 30 days. A longer session length provides convenience, and a shorter session provides tighter security. We recommend adjusting this based on your organization's security policies.", "admin.reporting.workspace_optimization.configuration.session_length.title": "Session lengths is set to default", diff --git a/webapp/channels/src/utils/constants.tsx b/webapp/channels/src/utils/constants.tsx index 152264d4525..ad1e64a9cec 100644 --- a/webapp/channels/src/utils/constants.tsx +++ b/webapp/channels/src/utils/constants.tsx @@ -1100,6 +1100,7 @@ export const DocLinks = { ENABLE_CLIENT_SIDE_CERTIFICATION: 'https://mattermost.com/pl/enable-client-side-certification', ENABLE_HARDENED_MODE: 'https://mattermost.com/pl/enable-hardened-mode', FORMAT_MESSAGES: 'https://mattermost.com/pl/format-messages', + FILE_STORAGE: 'https://mattermost.com/pl/configure-file-storage', GUEST_ACCOUNTS: 'https://docs.mattermost.com/onboard/guest-accounts.html', HIGH_AVAILABILITY_CLUSTER: 'https://mattermost.com/pl/high-availability-cluster', IN_PRODUCT_NOTICES: 'https://mattermost.com/pl/in-product-notices', @@ -2044,6 +2045,7 @@ export const ConsolePages = { GUEST_ACCOUNTS: '/admin_console/authentication/guest_access', LICENSE: '/admin_console/about/license', SAML: '/admin_console/authentication/saml', + FILE_STORAGE: '/admin_console/environment/file_storage', SESSION_LENGTHS: '/admin_console/environment/session_lengths', WEB_SERVER: '/admin_console/environment/web_server', PUSH_NOTIFICATION_CENTER: '/admin_console/environment/push_notification_server', diff --git a/webapp/platform/client/src/client4.ts b/webapp/platform/client/src/client4.ts index ae4582c20a1..0e40561b1d5 100644 --- a/webapp/platform/client/src/client4.ts +++ b/webapp/platform/client/src/client4.ts @@ -2343,13 +2343,15 @@ export default class Client4 { // General Routes - ping = () => { + ping = (getServerStatus: boolean, deviceId?: string) => { return this.doFetch<{ status: string; ActiveSearchBackend: string; + database_status: string; + filestore_status: string; }>( - `${this.getBaseRoute()}/system/ping?time=${Date.now()}`, - {method: 'get'}, + `${this.getBaseRoute()}/system/ping${buildQueryString({get_server_status: getServerStatus, device_id: deviceId})}`, + {method: 'get', ignoreStatus: true}, ); }; @@ -4086,7 +4088,7 @@ export default class Client4 { } } - if (response.ok) { + if (response.ok || options.ignoreStatus) { return { response, headers, diff --git a/webapp/platform/types/src/client4.ts b/webapp/platform/types/src/client4.ts index cbe7587a773..150d9cf0c9d 100644 --- a/webapp/platform/types/src/client4.ts +++ b/webapp/platform/types/src/client4.ts @@ -20,6 +20,7 @@ export type Options = { url?: string; credentials?: 'omit' | 'same-origin' | 'include'; body?: any; + ignoreStatus?: boolean; /** If true, status codes > 300 are ignored and don't cause an error */ }; export type StatusOK = {