diff --git a/object/application.go b/object/application.go index 1b96bd9e..237e8f3f 100644 --- a/object/application.go +++ b/object/application.go @@ -105,6 +105,7 @@ type Application struct { SignupHtml string `xorm:"mediumtext" json:"signupHtml"` SigninHtml string `xorm:"mediumtext" json:"signinHtml"` ThemeData *ThemeData `xorm:"json" json:"themeData"` + FooterHtml string `xorm:"mediumtext" json:"footerHtml"` FormCss string `xorm:"text" json:"formCss"` FormCssMobile string `xorm:"text" json:"formCssMobile"` FormOffset int `json:"formOffset"` diff --git a/web/src/App.js b/web/src/App.js index bd90d2c5..be05c1bc 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -34,6 +34,7 @@ const ManagementPage = lazy(() => import("./ManagementPage")); const {Footer, Content} = Layout; import {setTwoToneColor} from "@ant-design/icons"; +import * as ApplicationBackend from "./backend/ApplicationBackend"; setTwoToneColor("rgb(87,52,211)"); @@ -56,6 +57,7 @@ class App extends Component { logo: this.getLogo(storageThemeAlgorithm), requiredEnableMfa: false, isAiAssistantOpen: false, + application: undefined, }; Setting.initServerUrl(); Auth.initAuthWithConfig({ @@ -67,6 +69,7 @@ class App extends Component { UNSAFE_componentWillMount() { this.updateMenuKey(); this.getAccount(); + this.getApplication(); } componentDidUpdate(prevProps, prevState, snapshot) { @@ -190,6 +193,24 @@ class App extends Component { } }; + getApplication() { + const applicationName = localStorage.getItem("applicationName"); + if (!applicationName) { + return; + } + ApplicationBackend.getApplication("admin", applicationName) + .then((res) => { + if (res.status === "error") { + Setting.showMessage("error", res.msg); + return; + } + + this.setState({ + application: res.data, + }); + }); + } + getAccount() { const params = new URLSearchParams(this.props.location.search); @@ -245,11 +266,17 @@ class App extends Component { } }> { - Conf.CustomFooter !== null ? Conf.CustomFooter : ( + this.state.application?.footerHtml && this.state.application.footerHtml !== "" ? - Powered by {"Casdoor"} +
- ) + : ( + Conf.CustomFooter !== null ? Conf.CustomFooter : ( + + Powered by {"Casdoor"} + + ) + ) } @@ -330,6 +357,11 @@ class App extends Component { { + this.setState({ + application: application, + }); + }} onLoginSuccess={(redirectUrl) => { if (redirectUrl) { localStorage.setItem("mfaRedirectUrl", redirectUrl); diff --git a/web/src/ApplicationEditPage.js b/web/src/ApplicationEditPage.js index 499754ba..45a373e5 100644 --- a/web/src/ApplicationEditPage.js +++ b/web/src/ApplicationEditPage.js @@ -887,6 +887,38 @@ class ApplicationEditPage extends React.Component { + + + {Setting.getLabel(i18next.t("application:Footer HTML"), i18next.t("application:Footer HTML - Tooltip"))} : + + + + { + this.updateApplicationField("footerHtml", value); + }} + /> +
+ } title={i18next.t("application:Footer HTML - Edit")} trigger="click"> + { + this.updateApplicationField("footerHtml", e.target.value); + }} /> + + + + + + + + + { diff --git a/web/src/EntryPage.js b/web/src/EntryPage.js index 13f495eb..b6fa155c 100644 --- a/web/src/EntryPage.js +++ b/web/src/EntryPage.js @@ -69,6 +69,9 @@ class EntryPage extends React.Component { }); const themeData = application !== null ? Setting.getThemeData(application.organizationObj, application) : Conf.ThemeDefault; this.props.updataThemeData(themeData); + this.props.updateApplication(application); + + localStorage.setItem("applicationName", application.name); }; const onUpdatePricing = (pricing) => { diff --git a/web/src/Setting.js b/web/src/Setting.js index 462c5c81..ed764cdf 100644 --- a/web/src/Setting.js +++ b/web/src/Setting.js @@ -1467,6 +1467,19 @@ export function getUserCommonFields() { "PreferredMfaType", "TotpSecret", "SignupApplication"]; } +export function getDefaultFooterContent() { + return "Powered by \"Casdoor\""; +} + +export function getEmptyFooterContent() { + return `