mirror of https://github.com/casbin/casnode.git
fix: the 404 page in the footer (#517)
* fix: 404 page in footer * Update ReplyBox.js * Update AdminFrontConf.js * Update frontConf.go * Update router.go * Update Footer.js * Update FooterRenderBox.js Co-authored-by: Yang Luo <hsluoyz@qq.com>
This commit is contained in:
parent
ccc6af382a
commit
ab5466e0b2
|
@ -18,66 +18,85 @@ import (
|
|||
"encoding/json"
|
||||
|
||||
"github.com/casbin/casnode/object"
|
||||
"github.com/casbin/casnode/service"
|
||||
)
|
||||
|
||||
// @Title GetFrontConfById
|
||||
// @Description Get front conf by id
|
||||
// @Success 200 {object} object.FrontConf The Response object
|
||||
// @router /get-front-conf-by-id [get]
|
||||
// @Tag FrontConf API
|
||||
func (c *ApiController) GetFrontConfById() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
conf := object.GetFrontConfById(id)
|
||||
c.ResponseOk(conf)
|
||||
}
|
||||
|
||||
// @Title GetFrontConfsByField
|
||||
// @Description Get front confs by field
|
||||
// @Success 200 {array} object.FrontConf The Response object
|
||||
// @router /get-front-conf-by-field [get]
|
||||
// @router /get-front-confs-by-field [get]
|
||||
// @Tag FrontConf API
|
||||
func (c *ApiController) GetFrontConfByField() {
|
||||
func (c *ApiController) GetFrontConfsByField() {
|
||||
field := c.Input().Get("field")
|
||||
|
||||
c.Data["json"] = object.GetFrontConfByField(field)
|
||||
c.ServeJSON()
|
||||
confs := object.GetFrontConfsByField(field)
|
||||
c.ResponseOk(confs)
|
||||
}
|
||||
|
||||
// @Title GetFrontConfs
|
||||
// @Description Get all front confs
|
||||
// @Success 200 {array} array The Response object
|
||||
// @router /get-front-confs [get]
|
||||
// @router /update-front-conf-by-id [post]
|
||||
// @Tag FrontConf API
|
||||
func (c *ApiController) GetFrontConfs() {
|
||||
confs := make(map[string]string)
|
||||
conf := object.GetFrontConfs()
|
||||
|
||||
for _, frontconf := range conf {
|
||||
confs[frontconf.Id] = frontconf.Value
|
||||
}
|
||||
|
||||
c.Data["json"] = confs
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// @router /update-front-conf [post]
|
||||
// @Tag FrontConf API
|
||||
// @Title UpdateFrontConf
|
||||
func (c *ApiController) UpdateFrontConf() {
|
||||
var confs []*object.FrontConf
|
||||
|
||||
// @Title UpdateFrontConfById
|
||||
func (c *ApiController) UpdateFrontConfById() {
|
||||
if c.RequireAdmin() {
|
||||
return
|
||||
}
|
||||
|
||||
id := c.Input().Get("id")
|
||||
// get from body
|
||||
var value string
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &value)
|
||||
tags := service.Finalword(value)
|
||||
affect, err := object.UpdateFrontConfById(id, value, tags)
|
||||
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
}
|
||||
c.ResponseOk(affect)
|
||||
}
|
||||
|
||||
// @router /update-front-confs-by-filed [post]
|
||||
// @Tag FrontConf API
|
||||
// @Title UpdateFrontConfsByField
|
||||
func (c *ApiController) UpdateFrontConfsByField() {
|
||||
if c.RequireAdmin() {
|
||||
return
|
||||
}
|
||||
|
||||
filed := c.Input().Get("field")
|
||||
var confs []*object.FrontConf
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &confs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
c.ResponseError(err.Error())
|
||||
}
|
||||
res := object.UpdateFrontConf(confs)
|
||||
c.ResponseOk(res)
|
||||
|
||||
err = object.UpdateFrontConfsByField(confs, filed)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
}
|
||||
c.ResponseOk(nil)
|
||||
}
|
||||
|
||||
// @router /update-to-default-conf [post]
|
||||
// @router /restore-front-confs [post]
|
||||
// @Tag FrontConf API
|
||||
// @Title UpdateFrontConfToDefault
|
||||
func (c *ApiController) UpdateFrontConfToDefault() {
|
||||
|
||||
// @Title RestoreFrontConfs
|
||||
func (c *ApiController) RestoreFrontConfs() {
|
||||
if c.RequireAdmin() {
|
||||
return
|
||||
}
|
||||
|
||||
res := object.UpdateFrontConf(object.Confs)
|
||||
filed := c.Input().Get("field")
|
||||
res := object.UpdateFrontConfsByField(object.Confs, filed)
|
||||
c.ResponseOk(res)
|
||||
|
||||
}
|
||||
|
|
|
@ -15,50 +15,47 @@
|
|||
package object
|
||||
|
||||
type FrontConf struct {
|
||||
Id string `xorm:"varchar(100) notnull pk"`
|
||||
Value string `xorm:"mediumtext"`
|
||||
Field string `xorm:"varchar(100)`
|
||||
Id string `xorm:"varchar(100) notnull pk" json:"id"`
|
||||
Value string `xorm:"mediumtext" json:"value"`
|
||||
Field string `xorm:"varchar(100)" json:"field"`
|
||||
Tags []string `xorm:"varchar(200)" json:"tags"`
|
||||
}
|
||||
|
||||
var (
|
||||
Confs = []*FrontConf{
|
||||
{Id: "forumName", Value: "Casnode", Field: "visualConf"},
|
||||
{Id: "logoImage", Value: "https://cdn.casbin.com/forum/static/img/logo.png", Field: "visualConf"},
|
||||
{Id: "footerLogoImage", Value: "https://cdn.casbin.com/forum/static/img/logo-footer.png", Field: "visualConf"},
|
||||
{Id: "footerLogoUrl", Value: "https://www.digitalocean.com/", Field: "visualConf"},
|
||||
{Id: "signinBoxStrong", Value: "Casbin = way to authorization", Field: "visualConf"},
|
||||
{Id: "signinBoxSpan", Value: "A place for Casbin developers and users", Field: "visualConf"},
|
||||
{Id: "footerDeclaration", Value: "World is powered by code", Field: "visualConf"},
|
||||
{Id: "footerAdvise", Value: "♥ Do have faith in what you're doing.", Field: "visualConf"},
|
||||
{Id: "forumName", Value: "Casnode", Field: "visualConf", Tags: nil},
|
||||
{Id: "logoImage", Value: "https://cdn.casbin.com/forum/static/img/logo.png", Field: "visualConf", Tags: nil},
|
||||
{Id: "footerLogoImage", Value: "https://cdn.casbin.com/forum/static/img/logo-footer.png", Field: "visualConf", Tags: nil},
|
||||
{Id: "footerLogoUrl", Value: "https://www.digitalocean.com/", Field: "visualConf", Tags: nil},
|
||||
{Id: "signinBoxStrong", Value: "Casbin = way to authorization", Field: "visualConf", Tags: nil},
|
||||
{Id: "signinBoxSpan", Value: "A place for Casbin developers and users", Field: "visualConf", Tags: nil},
|
||||
{Id: "footerDeclaration", Value: "World is powered by code", Field: "visualConf", Tags: nil},
|
||||
{Id: "footerAdvise", Value: "♥ Do have faith in what you're doing.", Field: "visualConf", Tags: nil},
|
||||
{Id: "faq", Value: "Not yet", Field: "", Tags: nil},
|
||||
{Id: "mission", Value: "Not yet", Field: "", Tags: nil},
|
||||
{Id: "advertise", Value: "Not yet", Field: "", Tags: nil},
|
||||
{Id: "thanks", Value: "Not yet", Field: "", Tags: nil},
|
||||
}
|
||||
)
|
||||
|
||||
func InitFrontConf() {
|
||||
conf := GetFrontConfs()
|
||||
if len(conf) > 0 {
|
||||
var confs []*FrontConf
|
||||
err := adapter.Engine.Find(&confs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if len(confs) > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
conf = Confs
|
||||
|
||||
_, err := adapter.Engine.Insert(&conf)
|
||||
confs = Confs
|
||||
_, err = adapter.Engine.Insert(&confs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func GetFrontConfByField(field string) []*FrontConf {
|
||||
confs := []*FrontConf{}
|
||||
err := adapter.Engine.Where("field = ?", field).Find(&confs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return confs
|
||||
}
|
||||
|
||||
func GetFrontConfById(id string) *FrontConf {
|
||||
confs := []*FrontConf{}
|
||||
var confs []*FrontConf
|
||||
err := adapter.Engine.Where("id = ?", id).Find(&confs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -71,9 +68,9 @@ func GetFrontConfById(id string) *FrontConf {
|
|||
}
|
||||
}
|
||||
|
||||
func GetFrontConfs() []*FrontConf {
|
||||
confs := []*FrontConf{}
|
||||
err := adapter.Engine.Find(&confs)
|
||||
func GetFrontConfsByField(field string) []*FrontConf {
|
||||
var confs []*FrontConf
|
||||
err := adapter.Engine.Where("field = ?", field).Find(&confs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -81,10 +78,10 @@ func GetFrontConfs() []*FrontConf {
|
|||
return confs
|
||||
}
|
||||
|
||||
func UpdateFrontConf(confs []*FrontConf) bool {
|
||||
func UpdateFrontConfs(confs []*FrontConf) bool {
|
||||
var err error
|
||||
for _, v := range confs {
|
||||
_, err = adapter.Engine.Id(v.Id).Cols("value").Update(v)
|
||||
for _, conf := range confs {
|
||||
_, err = adapter.Engine.Where("id = ?", conf.Id).Update(conf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -92,3 +89,19 @@ func UpdateFrontConf(confs []*FrontConf) bool {
|
|||
|
||||
return true
|
||||
}
|
||||
|
||||
func UpdateFrontConfById(id string, value string, tags []string) (int64, error) {
|
||||
return adapter.Engine.Id(id).Cols("value", "tags").Update(&FrontConf{Value: value, Tags: tags})
|
||||
}
|
||||
|
||||
func UpdateFrontConfsByField(confs []*FrontConf, field string) error {
|
||||
for _, conf := range confs {
|
||||
if conf.Field == field {
|
||||
_, err := adapter.Engine.Id(conf.Id).Cols("value").Update(conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -157,8 +157,9 @@ func initAPI() {
|
|||
beego.Router("/api/node-navigation", &controllers.ApiController{}, "GET:GetNodeNavigation")
|
||||
beego.Router("/api/search", &controllers.ApiController{}, "GET:Search")
|
||||
|
||||
beego.Router("/api/get-front-conf-by-field", &controllers.ApiController{}, "GET:GetFrontConfByField")
|
||||
beego.Router("/api/get-front-confs", &controllers.ApiController{}, "GET:GetFrontConfs")
|
||||
beego.Router("/api/update-front-conf", &controllers.ApiController{}, "POST:UpdateFrontConf")
|
||||
beego.Router("/api/update-to-default-conf", &controllers.ApiController{}, "POST:UpdateFrontConfToDefault")
|
||||
beego.Router("/api/get-front-conf-by-id", &controllers.ApiController{}, "GET:GetFrontConfById")
|
||||
beego.Router("/api/get-front-confs-by-field", &controllers.ApiController{}, "GET:GetFrontConfsByField")
|
||||
beego.Router("/api/update-front-conf-by-id", &controllers.ApiController{}, "POST:UpdateFrontConfById")
|
||||
beego.Router("/api/update-front-confs-by-field", &controllers.ApiController{}, "POST:UpdateFrontConfsByField")
|
||||
beego.Router("/api/restore-front-confs", &controllers.ApiController{}, "POST:RestoreFrontConfs")
|
||||
}
|
||||
|
|
|
@ -72,10 +72,12 @@ import AdminPlane from "./admin/AdminPlane";
|
|||
import AdminTopic from "./admin/AdminTopic";
|
||||
import AdminSensitive from "./admin/AdminSensitive";
|
||||
import AdminFrontConf from "./admin/AdminFrontConf";
|
||||
import AdminFooterEdit from "./admin/AdminFooterEdit";
|
||||
import AboutForum from "./main/AboutForum";
|
||||
import SearchResultPage from "./SearchResultPage";
|
||||
import NoMatch from "./main/NoMatch";
|
||||
import Embed from "./Embed";
|
||||
import FooterRenderBox from "./main/FooterRenderBox";
|
||||
|
||||
class App extends Component {
|
||||
constructor(props) {
|
||||
|
@ -442,6 +444,57 @@ class App extends Component {
|
|||
<AdminFrontConf account={this.state.account} />
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
<Route exact path="/admin/faq">
|
||||
<div id={pcBrowser ? "Main" : ""}>
|
||||
{pcBrowser ? <div className="sep20" /> : null}
|
||||
<AdminFooterEdit account={this.state.account} id={"faq"} />
|
||||
</div>
|
||||
</Route>
|
||||
<Route exact path="/admin/mission">
|
||||
<div id={pcBrowser ? "Main" : ""}>
|
||||
{pcBrowser ? <div className="sep20" /> : null}
|
||||
<AdminFooterEdit account={this.state.account} id={"mission"} />
|
||||
</div>
|
||||
</Route>
|
||||
<Route exact path="/admin/advertise">
|
||||
<div id={pcBrowser ? "Main" : ""}>
|
||||
{pcBrowser ? <div className="sep20" /> : null}
|
||||
<AdminFooterEdit account={this.state.account} id={"advertise"} />
|
||||
</div>
|
||||
</Route>
|
||||
<Route exact path="/admin/thanks">
|
||||
<div id={pcBrowser ? "Main" : ""}>
|
||||
{pcBrowser ? <div className="sep20" /> : null}
|
||||
<AdminFooterEdit account={this.state.account} id={"thanks"} />
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
<Route exact path="/faq">
|
||||
<div id={pcBrowser ? "Main" : ""}>
|
||||
{pcBrowser ? <div className="sep20" /> : null}
|
||||
<FooterRenderBox id={"faq"} key={"faq"} />
|
||||
</div>
|
||||
</Route>
|
||||
<Route exact path="/mission">
|
||||
<div id={pcBrowser ? "Main" : ""}>
|
||||
{pcBrowser ? <div className="sep20" /> : null}
|
||||
<FooterRenderBox id={"mission"} key={"mission"} />
|
||||
</div>
|
||||
</Route>
|
||||
<Route exact path="/advertise">
|
||||
<div id={pcBrowser ? "Main" : ""}>
|
||||
{pcBrowser ? <div className="sep20" /> : null}
|
||||
<FooterRenderBox id={"advertise"} key={"advertise"} />
|
||||
</div>
|
||||
</Route>
|
||||
<Route exact path="/thanks">
|
||||
<div id={pcBrowser ? "Main" : ""}>
|
||||
{pcBrowser ? <div className="sep20" /> : null}
|
||||
<FooterRenderBox id={"thanks"} key={"thanks"} />
|
||||
</div>
|
||||
</Route>
|
||||
|
||||
<Route exact path="/about">
|
||||
<div id={pcBrowser ? "Main" : ""}>
|
||||
{pcBrowser ? <div className="sep20" /> : null}
|
||||
|
|
|
@ -124,9 +124,9 @@ class Footer extends React.Component {
|
|||
FAQ
|
||||
</Link>{" "}
|
||||
<span className="snow">·</span> {" "}
|
||||
<Link to="/api" className="dark" target="_self">
|
||||
<a href={`${Setting.ServerUrl}/swagger`} className="dark" target="_self">
|
||||
API
|
||||
</Link>{" "}
|
||||
</a>{" "}
|
||||
<span className="snow">·</span> {" "}
|
||||
<Link to="/mission" className="dark" target="_self">
|
||||
{i18next.t("footer:Mission")}
|
||||
|
@ -136,7 +136,7 @@ class Footer extends React.Component {
|
|||
{i18next.t("footer:Advertise")}
|
||||
</Link>{" "}
|
||||
<span className="snow">·</span> {" "}
|
||||
<Link to="/advertise/2019.html" className="dark" target="_self">
|
||||
<Link to="/thanks" className="dark" target="_self">
|
||||
{i18next.t("footer:Thanks")}
|
||||
</Link>{" "}
|
||||
<span className="snow">·</span> {" "}
|
||||
|
|
|
@ -320,12 +320,12 @@ export function getFrontConf(field) {
|
|||
}
|
||||
}
|
||||
|
||||
ConfBackend.getFrontConfByField(field).then((res) => {
|
||||
for (let key in res) {
|
||||
if (res[key].Value !== "") {
|
||||
FrontConfig[res[key].Id] = res[key].Value;
|
||||
ConfBackend.getFrontConfsByField(field).then((res) => {
|
||||
for (let key in res.data) {
|
||||
if (res.data[key].Value !== "") {
|
||||
FrontConfig[res.data[key].id] = res.data[key].value;
|
||||
}
|
||||
storage[res[key].Id] = FrontConfig[res[key].Id];
|
||||
storage[res.data[key].id] = FrontConfig[res.data[key].id];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
// Copyright 2022 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import { Link, withRouter } from "react-router-dom";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import * as ConfBackend from "../backend/ConfBackend";
|
||||
import * as Tools from "../main/Tools";
|
||||
import { Controlled as CodeMirrorsEditor } from "react-codemirror2";
|
||||
|
||||
class AdminFrontConf extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
content: "",
|
||||
publishClicked: false,
|
||||
id: this.props.id,
|
||||
message: "",
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.i18nTag = `admin:${this.state?.id.charAt(0).toUpperCase() + this.state?.id.slice(1)}`;
|
||||
this.getContent(this.state.id);
|
||||
this.getFrontConf(this.state.id);
|
||||
}
|
||||
|
||||
changeField(field) {
|
||||
this.setState(
|
||||
{
|
||||
field: field,
|
||||
},
|
||||
() => {
|
||||
this.getFrontConf(this.state.field);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
getContent(id) {
|
||||
ConfBackend.getFrontConfById(id).then((res) => {
|
||||
console.log(res.data.value);
|
||||
this.setState({
|
||||
content: res.data.value,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
renderManagementList(item) {
|
||||
return (
|
||||
<a href="javascript:void(0);" className={this.state.field === item.value ? "tab_current" : "tab"} onClick={() => this.changeField(item.value)}>
|
||||
{item.label}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
updateFormField(key, value) {
|
||||
let form = this.state.form;
|
||||
form[key] = value;
|
||||
this.setState({
|
||||
form: form,
|
||||
isTypingStarted: true,
|
||||
});
|
||||
}
|
||||
|
||||
getFrontConf(id) {
|
||||
ConfBackend.getFrontConfById(id).then((res) => {
|
||||
console.log(res.data[0]);
|
||||
});
|
||||
}
|
||||
|
||||
clearMessage() {
|
||||
this.setState({
|
||||
message: "",
|
||||
});
|
||||
}
|
||||
|
||||
updateConf() {
|
||||
this.setState({ publishClicked: true });
|
||||
let confs = [];
|
||||
for (const k in this.state.changeForm) {
|
||||
confs.push({ id: k, value: this.state.changeForm[k], field: this.state.field });
|
||||
}
|
||||
ConfBackend.updateFrontConfById(this.state.id, this.state.content).then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
message: i18next.t("poster:Update frontconf information success"),
|
||||
publishClicked: false,
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
message: res?.msg,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
renderEditor() {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
overflow: "hidden",
|
||||
overflowWrap: "break-word",
|
||||
resize: "none",
|
||||
height: "auto",
|
||||
}}
|
||||
className={`mll`}
|
||||
id="reply_content"
|
||||
>
|
||||
<div className={`cm-short-content`}>
|
||||
<CodeMirrorsEditor
|
||||
editorDidMount={(editor) => Tools.attachEditor(editor)}
|
||||
onPaste={() => Tools.uploadMdFile()}
|
||||
value={this.state.content}
|
||||
onDrop={() => Tools.uploadMdFile()}
|
||||
options={{
|
||||
mode: "markdown",
|
||||
lineNumbers: false,
|
||||
lineWrapping: true,
|
||||
extraKeys: { "Ctrl-Space": "autocomplete" },
|
||||
hintOptions: {
|
||||
alignWithWord: false,
|
||||
closeOnUnfocus: false,
|
||||
closeOnBlur: false,
|
||||
className: "textcomplete-item",
|
||||
},
|
||||
}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
this.setState({ content: value });
|
||||
}}
|
||||
onChange={(editor, data, value) => {}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
let blurStyle = { color: "#ccc", pointerEvents: "none" };
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="box">
|
||||
<div className="header">
|
||||
<Link to="/">{Setting.getForumName()}</Link> <span className="chevron"> › </span>
|
||||
<Link to="/admin">{i18next.t("admin:Backstage management")}</Link>
|
||||
<span className="chevron"> › </span> {i18next.t(this.i18nTag)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="box">
|
||||
{this.state.message !== "" ? (
|
||||
<div className="message" onClick={() => this.clearMessage()}>
|
||||
<li className="fa fa-exclamation-triangle"></li>
|
||||
{this.state.message}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="inner">
|
||||
<div className={`cell ${this.props.nodeId}`}>
|
||||
<div
|
||||
style={{
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{this.renderEditor()}
|
||||
</div>
|
||||
<div className="sep10" />
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<button type="button" onClick={this.updateConf.bind(this)} type="submit" className="super normal button">
|
||||
<li className={this.state.publishClicked ? "fa fa-circle-o-notch fa-spin" : "fa fa-paper-plane"} />
|
||||
{this.state.publishClicked ? i18next.t("new:Publishing...") : i18next.t("frontConf:Save")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<div style={blurStyle} className="fr">
|
||||
<div className="sep5" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(AdminFrontConf);
|
|
@ -13,7 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import { withRouter, Link } from "react-router-dom";
|
||||
import { Link, withRouter } from "react-router-dom";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import * as ConfBackend from "../backend/ConfBackend";
|
||||
|
@ -26,14 +26,14 @@ class AdminFrontConf extends React.Component {
|
|||
Management_LIST: [{ label: "Visual Conf", value: "visualConf" }],
|
||||
field: "visualConf",
|
||||
conf: [
|
||||
{ Id: "forumName", Value: "" },
|
||||
{ Id: "logoImage", Value: "" },
|
||||
{ Id: "signinBoxStrong", Value: "" },
|
||||
{ Id: "signinBoxSpan", Value: "" },
|
||||
{ Id: "footerAdvise", Value: "" },
|
||||
{ Id: "footerDeclaration", Value: "" },
|
||||
{ Id: "footerLogoImage", Value: "" },
|
||||
{ Id: "footerLogoUrl", Value: "" },
|
||||
{ id: "forumName", value: "" },
|
||||
{ id: "logoImage", value: "" },
|
||||
{ id: "signinBoxStrong", value: "" },
|
||||
{ id: "signinBoxSpan", value: "" },
|
||||
{ id: "footerAdvise", value: "" },
|
||||
{ id: "footerDeclaration", value: "" },
|
||||
{ id: "footerLogoImage", value: "" },
|
||||
{ id: "footerLogoUrl", value: "" },
|
||||
],
|
||||
form: {},
|
||||
changeForm: {},
|
||||
|
@ -67,14 +67,14 @@ class AdminFrontConf extends React.Component {
|
|||
}
|
||||
|
||||
getFrontConf(field) {
|
||||
ConfBackend.getFrontConfByField(field).then((res) => {
|
||||
ConfBackend.getFrontConfsByField(field).then((res) => {
|
||||
let form = this.state.form;
|
||||
let conf = this.state.conf;
|
||||
for (var k in res) {
|
||||
form[res[k].Id] = res[k].Value;
|
||||
for (let k in res.data) {
|
||||
form[res.data[k].id] = res.data[k].value;
|
||||
}
|
||||
for (var i in conf) {
|
||||
conf[i].Value = form[conf[i].Id];
|
||||
for (let i in conf) {
|
||||
conf[i].value = form[conf[i].id];
|
||||
}
|
||||
this.setState({
|
||||
conf: conf,
|
||||
|
@ -103,10 +103,11 @@ class AdminFrontConf extends React.Component {
|
|||
|
||||
updateConf() {
|
||||
let confs = [];
|
||||
for (var k in this.state.changeForm) {
|
||||
confs.push({ Id: k, Value: this.state.changeForm[k] });
|
||||
for (const k in this.state.changeForm) {
|
||||
confs.push({ id: k, value: this.state.changeForm[k], field: this.state.field });
|
||||
}
|
||||
ConfBackend.updateFrontConfs(confs).then((res) => {
|
||||
|
||||
ConfBackend.updateFrontConfsByField(this.state.field, confs).then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
message: i18next.t("poster:Update frontconf information success"),
|
||||
|
@ -120,7 +121,7 @@ class AdminFrontConf extends React.Component {
|
|||
}
|
||||
|
||||
updateConfToDefault() {
|
||||
ConfBackend.updateFrontConfToDefault().then((res) => {
|
||||
ConfBackend.restoreFrontConfs(this.state.field).then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
message: i18next.t("poster:Update frontconf information success"),
|
||||
|
@ -194,10 +195,10 @@ class AdminFrontConf extends React.Component {
|
|||
return (
|
||||
<tr>
|
||||
<td width={Setting.PcBrowser ? "120" : "90"} align="right">
|
||||
{this.convert(item.Id)}
|
||||
{this.convert(item.id)}
|
||||
</td>
|
||||
<td width="auto" align="left">
|
||||
<textarea rows="1" style={{ width: "80%" }} value={this.state.form[item.Id]} onChange={(event) => this.inputChange(event, item.Id)} />
|
||||
<textarea rows="1" style={{ width: "80%" }} value={this.state.form[item.id]} onChange={(event) => this.inputChange(event, item.id)} />
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
|
|
|
@ -70,6 +70,26 @@ class AdminHomepage extends React.Component {
|
|||
value: "frontconf",
|
||||
image: Setting.getStatic("/img/settings.png"),
|
||||
},
|
||||
{
|
||||
label: i18next.t("admin:Faq"),
|
||||
value: "faq",
|
||||
image: Setting.getStatic("/img/settings.png"),
|
||||
},
|
||||
{
|
||||
label: i18next.t("admin:Mission"),
|
||||
value: "mission",
|
||||
image: Setting.getStatic("/img/settings.png"),
|
||||
},
|
||||
{
|
||||
label: i18next.t("admin:Advertise"),
|
||||
value: "advertise",
|
||||
image: Setting.getStatic("/img/settings.png"),
|
||||
},
|
||||
{
|
||||
label: i18next.t("admin:Thanks"),
|
||||
value: "thanks",
|
||||
image: Setting.getStatic("/img/settings.png"),
|
||||
},
|
||||
],
|
||||
message: "",
|
||||
};
|
||||
|
|
|
@ -71,7 +71,6 @@ class AdminPoster extends React.Component {
|
|||
}
|
||||
);
|
||||
}
|
||||
console.log(poster);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -14,23 +14,38 @@
|
|||
|
||||
import * as Setting from "../Setting";
|
||||
|
||||
export function getFrontConfByField(field) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-front-conf-by-field?field=${field}`, {
|
||||
export function getFrontConfById(id) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-front-conf-by-id?id=${id}`, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
}).then((res) => res.json());
|
||||
}
|
||||
|
||||
export function updateFrontConfs(confs) {
|
||||
return fetch(`${Setting.ServerUrl}/api/update-front-conf`, {
|
||||
export function getFrontConfsByField(field) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-front-confs-by-field?field=${field}`, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
}).then((res) => res.json());
|
||||
}
|
||||
|
||||
export function updateFrontConfById(id, value) {
|
||||
return fetch(`${Setting.ServerUrl}/api/update-front-conf-by-id?id=${id}`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify(value),
|
||||
}).then((res) => res.json());
|
||||
}
|
||||
|
||||
export function updateFrontConfsByField(field, confs) {
|
||||
return fetch(`${Setting.ServerUrl}/api/update-front-confs-by-field?field=${field}`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify(confs),
|
||||
}).then((res) => res.json());
|
||||
}
|
||||
|
||||
export function updateFrontConfToDefault() {
|
||||
return fetch(`${Setting.ServerUrl}/api/update-to-default-conf`, {
|
||||
export function restoreFrontConfs(field) {
|
||||
return fetch(`${Setting.ServerUrl}/api/restore-front-confs?field=${field}`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
}).then((res) => res.json());
|
||||
|
|
|
@ -7,16 +7,19 @@
|
|||
"Version": "Version"
|
||||
},
|
||||
"admin": {
|
||||
"Advertise": "Advertise",
|
||||
"Asc": "Aufsteigend",
|
||||
"Backstage management": "Backstage Management",
|
||||
"Condition search": "Zustandssuche",
|
||||
"Desc": "Absteigend",
|
||||
"Faq": "Faq",
|
||||
"FrontConf management": "FrontConf Verwaltung",
|
||||
"Get search result success": "Suchergebnis erfolgreich abrufen",
|
||||
"Hidden": "Hidden",
|
||||
"Ignore": "Ignorieren",
|
||||
"Manage": "Verwalten",
|
||||
"Member management": "Mitglieder verwalten",
|
||||
"Mission": "Mission",
|
||||
"No matching data": "Keine übereinstimmenden Daten",
|
||||
"Node management": "Verwaltung von Knoten(punkten)",
|
||||
"Plane management": "Ebenenmanagement",
|
||||
|
@ -25,6 +28,7 @@
|
|||
"Show": "Anzeigen",
|
||||
"Sorter": "Sortierer",
|
||||
"Tab management": "Tab-Einstellungen",
|
||||
"Thanks": "Thanks",
|
||||
"Topic management": "Themen-Verwaltung",
|
||||
"Translation management": "Übersetzungsverwaltung"
|
||||
},
|
||||
|
|
|
@ -7,16 +7,19 @@
|
|||
"Version": "Version"
|
||||
},
|
||||
"admin": {
|
||||
"Advertise": "Advertise",
|
||||
"Asc": "Asc",
|
||||
"Backstage management": "Backstage management",
|
||||
"Condition search": "Condition search",
|
||||
"Desc": "Desc",
|
||||
"Faq": "Faq",
|
||||
"FrontConf management": "FrontConf management",
|
||||
"Get search result success": "Get search result success",
|
||||
"Hidden": "Hidden",
|
||||
"Ignore": "Ignore",
|
||||
"Manage": "Manage",
|
||||
"Member management": "Member management",
|
||||
"Mission": "Mission",
|
||||
"No matching data": "No matching data",
|
||||
"Node management": "Node management",
|
||||
"Plane management": "Plane management",
|
||||
|
@ -25,6 +28,7 @@
|
|||
"Show": "Show",
|
||||
"Sorter": "Sorter",
|
||||
"Tab management": "Tab management",
|
||||
"Thanks": "Thanks",
|
||||
"Topic management": "Topic management",
|
||||
"Translation management": "Translation management"
|
||||
},
|
||||
|
|
|
@ -7,16 +7,19 @@
|
|||
"Version": "Version"
|
||||
},
|
||||
"admin": {
|
||||
"Advertise": "Advertise",
|
||||
"Asc": "Ascendant",
|
||||
"Backstage management": "Gestion des coulisses",
|
||||
"Condition search": "Recherche de conditions",
|
||||
"Desc": "Desc",
|
||||
"Faq": "Faq",
|
||||
"FrontConf management": "Gestion FrontConf",
|
||||
"Get search result success": "Réussite du résultat de la recherche",
|
||||
"Hidden": "Hidden",
|
||||
"Ignore": "Ignorer",
|
||||
"Manage": "Gérer",
|
||||
"Member management": "Gestion des membres",
|
||||
"Mission": "Mission",
|
||||
"No matching data": "Aucune donnée correspondante",
|
||||
"Node management": "Gestion des nœuds",
|
||||
"Plane management": "Gestion des plans",
|
||||
|
@ -25,6 +28,7 @@
|
|||
"Show": "Afficher",
|
||||
"Sorter": "Tri",
|
||||
"Tab management": "Gestion des onglets",
|
||||
"Thanks": "Thanks",
|
||||
"Topic management": "Gestion des sujets",
|
||||
"Translation management": "Gestion des traductions"
|
||||
},
|
||||
|
|
|
@ -7,16 +7,19 @@
|
|||
"Version": "バージョン"
|
||||
},
|
||||
"admin": {
|
||||
"Advertise": "Advertise",
|
||||
"Asc": "Asc",
|
||||
"Backstage management": "バックステージ管理",
|
||||
"Condition search": "条件検索",
|
||||
"Desc": "Desc",
|
||||
"Faq": "Faq",
|
||||
"FrontConf management": "FrontConf管理",
|
||||
"Get search result success": "検索結果を取得しました",
|
||||
"Hidden": "Hidden",
|
||||
"Ignore": "無視",
|
||||
"Manage": "管理",
|
||||
"Member management": "メンバー管理",
|
||||
"Mission": "Mission",
|
||||
"No matching data": "一致するデータがありません",
|
||||
"Node management": "ノード管理",
|
||||
"Plane management": "平面管理",
|
||||
|
@ -25,6 +28,7 @@
|
|||
"Show": "表示",
|
||||
"Sorter": "ソート",
|
||||
"Tab management": "タブ管理",
|
||||
"Thanks": "Thanks",
|
||||
"Topic management": "トピック管理",
|
||||
"Translation management": "翻訳管理"
|
||||
},
|
||||
|
|
|
@ -7,16 +7,19 @@
|
|||
"Version": "Версе"
|
||||
},
|
||||
"admin": {
|
||||
"Advertise": "Advertise",
|
||||
"Asc": "Көтерілу (Asc)",
|
||||
"Backstage management": "Backstage'ді басқару",
|
||||
"Condition search": "Шартты іздеу",
|
||||
"Desc": "Desc",
|
||||
"Faq": "Faq",
|
||||
"FrontConf management": "FrontConf'ті басқару",
|
||||
"Get search result success": "Іздеу нәтижесі сәтті алынды",
|
||||
"Hidden": "Жасырын",
|
||||
"Ignore": "Ескермеу",
|
||||
"Manage": "Басқару",
|
||||
"Member management": "Мүшелерді басқару",
|
||||
"Mission": "Mission",
|
||||
"No matching data": "Сәйкес деректер жоқ",
|
||||
"Node management": "Түйіндерді басқару",
|
||||
"Plane management": "Plane басқару",
|
||||
|
@ -25,6 +28,7 @@
|
|||
"Show": "Көрсету",
|
||||
"Sorter": "Сұрыптау",
|
||||
"Tab management": "Tab'ты басқару",
|
||||
"Thanks": "Thanks",
|
||||
"Topic management": "Топиктерді басқару",
|
||||
"Translation management": "Аударманы басқару"
|
||||
},
|
||||
|
|
|
@ -7,16 +7,19 @@
|
|||
"Version": "Version"
|
||||
},
|
||||
"admin": {
|
||||
"Advertise": "Advertise",
|
||||
"Asc": "Asc",
|
||||
"Backstage management": "Backstage management",
|
||||
"Condition search": "Condition search",
|
||||
"Desc": "Desc",
|
||||
"Faq": "Faq",
|
||||
"FrontConf management": "FrontConf management",
|
||||
"Get search result success": "Get search result success",
|
||||
"Hidden": "Hidden",
|
||||
"Ignore": "Ignore",
|
||||
"Manage": "Manage",
|
||||
"Member management": "Member management",
|
||||
"Mission": "Mission",
|
||||
"No matching data": "No matching data",
|
||||
"Node management": "Node management",
|
||||
"Plane management": "Plane management",
|
||||
|
@ -25,6 +28,7 @@
|
|||
"Show": "Show",
|
||||
"Sorter": "Sorter",
|
||||
"Tab management": "Tab management",
|
||||
"Thanks": "Thanks",
|
||||
"Topic management": "Topic management",
|
||||
"Translation management": "Translation management"
|
||||
},
|
||||
|
|
|
@ -7,16 +7,19 @@
|
|||
"Version": "Версия"
|
||||
},
|
||||
"admin": {
|
||||
"Advertise": "Advertise",
|
||||
"Asc": "Аск",
|
||||
"Backstage management": "Управление бэкстадией",
|
||||
"Condition search": "Поиск условий",
|
||||
"Desc": "Desc",
|
||||
"Faq": "Faq",
|
||||
"FrontConf management": "Управление FrontConf",
|
||||
"Get search result success": "Результат поиска выполнен",
|
||||
"Hidden": "Hidden",
|
||||
"Ignore": "Пропустить",
|
||||
"Manage": "Управлять",
|
||||
"Member management": "Управление участниками",
|
||||
"Mission": "Mission",
|
||||
"No matching data": "Нет подходящих данных",
|
||||
"Node management": "Управление узлами",
|
||||
"Plane management": "Управление плоскостью",
|
||||
|
@ -25,6 +28,7 @@
|
|||
"Show": "Показать",
|
||||
"Sorter": "Сортировать",
|
||||
"Tab management": "Управление вкладками",
|
||||
"Thanks": "Thanks",
|
||||
"Topic management": "Управление темами",
|
||||
"Translation management": "Управление переводами"
|
||||
},
|
||||
|
|
|
@ -7,16 +7,19 @@
|
|||
"Version": "版本"
|
||||
},
|
||||
"admin": {
|
||||
"Advertise": "廣告",
|
||||
"Asc": "升序",
|
||||
"Backstage management": "後臺管理",
|
||||
"Condition search": "條件搜索",
|
||||
"Desc": "降序",
|
||||
"Faq": "常見問題",
|
||||
"FrontConf management": "前端配置管理",
|
||||
"Get search result success": "獲取搜索結果成功",
|
||||
"Hidden": "隱藏",
|
||||
"Ignore": "忽略",
|
||||
"Manage": "管理",
|
||||
"Member management": "用戶管理",
|
||||
"Mission": "願景",
|
||||
"No matching data": "沒有匹配信息",
|
||||
"Node management": "節點管理",
|
||||
"Plane management": "位面管理",
|
||||
|
@ -25,6 +28,7 @@
|
|||
"Show": "顯示",
|
||||
"Sorter": "排序",
|
||||
"Tab management": "類別管理",
|
||||
"Thanks": "致謝",
|
||||
"Topic management": "帖子管理",
|
||||
"Translation management": "翻譯管理"
|
||||
},
|
||||
|
|
|
@ -7,16 +7,19 @@
|
|||
"Version": "版本"
|
||||
},
|
||||
"admin": {
|
||||
"Advertise": "广告投放",
|
||||
"Asc": "升序",
|
||||
"Backstage management": "后台管理",
|
||||
"Condition search": "条件搜索",
|
||||
"Desc": "降序",
|
||||
"Faq": "常见问题",
|
||||
"FrontConf management": "前端配置管理",
|
||||
"Get search result success": "获取搜索结果成功",
|
||||
"Hidden": "隐藏",
|
||||
"Ignore": "忽略",
|
||||
"Manage": "管理",
|
||||
"Member management": "用户管理",
|
||||
"Mission": "愿景",
|
||||
"No matching data": "没有匹配信息",
|
||||
"Node management": "节点管理",
|
||||
"Plane management": "位面管理",
|
||||
|
@ -25,6 +28,7 @@
|
|||
"Show": "显示",
|
||||
"Sorter": "排序",
|
||||
"Tab management": "类别管理",
|
||||
"Thanks": "致谢",
|
||||
"Topic management": "帖子管理",
|
||||
"Translation management": "翻译管理"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright 2022 The casbin Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import { withRouter, Link } from "react-router-dom";
|
||||
import * as Setting from "../Setting";
|
||||
import * as ConfBackend from "../backend/ConfBackend";
|
||||
import "./NoMatch.css";
|
||||
import i18next from "i18next";
|
||||
import { Helmet } from "react-helmet";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
|
||||
class NoMatch extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
id: this.props.id,
|
||||
conf: null,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.i18nTag = `admin:${this.state?.id.charAt(0).toUpperCase() + this.state?.id.slice(1)}`;
|
||||
this.getContent(this.state.id);
|
||||
}
|
||||
|
||||
getContent(id) {
|
||||
ConfBackend.getFrontConfById(id).then((res) => {
|
||||
this.setState({
|
||||
conf: res.data,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
renderBox() {
|
||||
return (
|
||||
<div>
|
||||
<div className="box">
|
||||
<Helmet>
|
||||
<title>
|
||||
{i18next.t(this.i18nTag)} - {Setting.getForumName()}
|
||||
</title>
|
||||
<meta name="keywords" content={this.state.conf?.tags} />
|
||||
</Helmet>
|
||||
<div className="header">
|
||||
<Link to="/">{Setting.getForumName()}</Link>
|
||||
<span className="chevron"> › </span> {i18next.t(this.i18nTag)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="box">
|
||||
<div className="inner" id="topic_preview">
|
||||
<div className="topic_content">
|
||||
<div className="markdown_body">
|
||||
<ReactMarkdown source={this.state.conf?.value} escapeHtml={false} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="main">
|
||||
{this.renderBox()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default withRouter(NoMatch);
|
Loading…
Reference in New Issue