mirror of
https://github.com/ngoduykhanh/wireguard-ui.git
synced 2025-06-08 00:56:58 +03:00
Added branding settings page
Added branding settings page, where you can change favicon, brand name and brand logo from UI.
This commit is contained in:
parent
46ac9ef2c1
commit
12d0dc6288
8 changed files with 384 additions and 15 deletions
|
@ -5,8 +5,10 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -33,11 +35,48 @@ func Health() echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Favicon() echo.HandlerFunc {
|
func Favicon(db store.IStore) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
if favicon, ok := os.LookupEnv(util.FaviconFilePathEnvVar); ok {
|
if favicon, ok := os.LookupEnv(util.FaviconFilePathEnvVar); ok {
|
||||||
return c.File(favicon)
|
return c.File(favicon)
|
||||||
|
} else {
|
||||||
|
_, err := os.OpenFile(path.Join(db.GetPath(), "branding")+"/favicon.ico", os.O_RDONLY, 0777)
|
||||||
|
if err != nil {
|
||||||
|
return c.Redirect(http.StatusFound, util.BasePath+"/static/custom/img/favicon.ico")
|
||||||
}
|
}
|
||||||
|
return c.File(path.Join(db.GetPath(), "branding") + "/favicon.ico")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BrandLogo(db store.IStore) echo.HandlerFunc {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
|
||||||
|
_, err := os.OpenFile(path.Join(db.GetPath(), "branding")+"/logo.png", os.O_RDONLY, 0777)
|
||||||
|
if err == nil {
|
||||||
|
return c.File(path.Join(db.GetPath(), "branding") + "/logo.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = os.OpenFile(path.Join(db.GetPath(), "branding")+"/logo.jpg", os.O_RDONLY, 0777)
|
||||||
|
if err == nil {
|
||||||
|
return c.File(path.Join(db.GetPath(), "branding") + "/logo.jpg")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = os.OpenFile(path.Join(db.GetPath(), "branding")+"/logo.jpeg", os.O_RDONLY, 0777)
|
||||||
|
if err == nil {
|
||||||
|
return c.File(path.Join(db.GetPath(), "branding") + "/logo.jpeg")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = os.OpenFile(path.Join(db.GetPath(), "branding")+"/logo.gif", os.O_RDONLY, 0777)
|
||||||
|
if err == nil {
|
||||||
|
return c.File(path.Join(db.GetPath(), "branding") + "/logo.gif")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = os.OpenFile(path.Join(db.GetPath(), "branding")+"/logo.ico", os.O_RDONLY, 0777)
|
||||||
|
if err == nil {
|
||||||
|
return c.File(path.Join(db.GetPath(), "branding") + "/logo.ico")
|
||||||
|
}
|
||||||
|
|
||||||
return c.Redirect(http.StatusFound, util.BasePath+"/static/custom/img/favicon.ico")
|
return c.Redirect(http.StatusFound, util.BasePath+"/static/custom/img/favicon.ico")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +159,7 @@ func LoadProfile(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "profile.html", map[string]interface{}{
|
return c.Render(http.StatusOK, "profile.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "profile", CurrentUser: currentUser(c)},
|
"baseData": model.BaseData{Active: "profile", CurrentUser: currentUser(c), BrandName: db.GetBrandName()},
|
||||||
"userInfo": userInfo,
|
"userInfo": userInfo,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -179,7 +218,7 @@ func WireGuardClients(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "clients.html", map[string]interface{}{
|
return c.Render(http.StatusOK, "clients.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "", CurrentUser: currentUser(c)},
|
"baseData": model.BaseData{Active: "", CurrentUser: currentUser(c), BrandName: db.GetBrandName()},
|
||||||
"clientDataList": clientDataList,
|
"clientDataList": clientDataList,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -532,7 +571,7 @@ func WireGuardServer(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "server.html", map[string]interface{}{
|
return c.Render(http.StatusOK, "server.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "wg-server", CurrentUser: currentUser(c)},
|
"baseData": model.BaseData{Active: "wg-server", CurrentUser: currentUser(c), BrandName: db.GetBrandName()},
|
||||||
"serverInterface": server.Interface,
|
"serverInterface": server.Interface,
|
||||||
"serverKeyPair": server.KeyPair,
|
"serverKeyPair": server.KeyPair,
|
||||||
})
|
})
|
||||||
|
@ -600,7 +639,7 @@ func GlobalSettings(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "global_settings.html", map[string]interface{}{
|
return c.Render(http.StatusOK, "global_settings.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "global-settings", CurrentUser: currentUser(c)},
|
"baseData": model.BaseData{Active: "global-settings", CurrentUser: currentUser(c), BrandName: db.GetBrandName()},
|
||||||
"globalSettings": globalSettings,
|
"globalSettings": globalSettings,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -630,7 +669,7 @@ func Status(db store.IStore) echo.HandlerFunc {
|
||||||
wgClient, err := wgctrl.New()
|
wgClient, err := wgctrl.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)},
|
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c), BrandName: db.GetBrandName()},
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
"devices": nil,
|
"devices": nil,
|
||||||
})
|
})
|
||||||
|
@ -639,7 +678,7 @@ func Status(db store.IStore) echo.HandlerFunc {
|
||||||
devices, err := wgClient.Devices()
|
devices, err := wgClient.Devices()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)},
|
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c), BrandName: db.GetBrandName()},
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
"devices": nil,
|
"devices": nil,
|
||||||
})
|
})
|
||||||
|
@ -651,7 +690,7 @@ func Status(db store.IStore) echo.HandlerFunc {
|
||||||
clients, err := db.GetClients(false)
|
clients, err := db.GetClients(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)},
|
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c), BrandName: db.GetBrandName()},
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
"devices": nil,
|
"devices": nil,
|
||||||
})
|
})
|
||||||
|
@ -697,7 +736,7 @@ func Status(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "status.html", map[string]interface{}{
|
return c.Render(http.StatusOK, "status.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)},
|
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c), BrandName: db.GetBrandName()},
|
||||||
"devices": devicesVm,
|
"devices": devicesVm,
|
||||||
"error": "",
|
"error": "",
|
||||||
})
|
})
|
||||||
|
@ -831,11 +870,75 @@ func ApplyServerConfig(db store.IStore, tmplBox *rice.Box) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AboutPage handler
|
// AboutPage handler
|
||||||
func AboutPage() echo.HandlerFunc {
|
func AboutPage(db store.IStore) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
return c.Render(http.StatusOK, "about.html", map[string]interface{}{
|
return c.Render(http.StatusOK, "about.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "about", CurrentUser: currentUser(c)},
|
"baseData": model.BaseData{Active: "about", CurrentUser: currentUser(c), BrandName: db.GetBrandName()},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Branding handler
|
||||||
|
func BrandingSettings(db store.IStore) echo.HandlerFunc {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
return c.Render(http.StatusOK, "branding_settings.html", map[string]interface{}{
|
||||||
|
"baseData": model.BaseData{Active: "branding-settings", CurrentUser: currentUser(c), BrandName: db.GetBrandName()},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateBranding(db store.IStore) echo.HandlerFunc {
|
||||||
|
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
|
||||||
|
c.Request().ParseMultipartForm(32 << 20)
|
||||||
|
brand_name := c.Request().Form.Get("brand_name")
|
||||||
|
favicon_exist := true
|
||||||
|
logo_exist := true
|
||||||
|
|
||||||
|
// check if favicon exist
|
||||||
|
favicon_file, favicon_handler, err := c.Request().FormFile("favicon")
|
||||||
|
if err != nil {
|
||||||
|
favicon_exist = false
|
||||||
|
} else {
|
||||||
|
defer favicon_file.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if logo exist
|
||||||
|
logo_file, logo_handler, err := c.Request().FormFile("logo")
|
||||||
|
if err != nil {
|
||||||
|
logo_exist = false
|
||||||
|
} else {
|
||||||
|
defer logo_file.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if favicon_exist {
|
||||||
|
f, err := os.OpenFile(path.Join(db.GetPath(), "branding")+"/favicon."+strings.Split(favicon_handler.Filename, ".")[1], os.O_WRONLY|os.O_CREATE, 0777)
|
||||||
|
if err != nil {
|
||||||
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot open " + path.Join(db.GetPath(), "branding") + "/favicon." + strings.Split(favicon_handler.Filename, ".")[1]})
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
io.Copy(f, favicon_file)
|
||||||
|
}
|
||||||
|
|
||||||
|
if logo_exist {
|
||||||
|
os.Remove(path.Join(db.GetPath(), "branding") + "/logo.png")
|
||||||
|
os.Remove(path.Join(db.GetPath(), "branding") + "/logo.jpg")
|
||||||
|
os.Remove(path.Join(db.GetPath(), "branding") + "/logo.jpeg")
|
||||||
|
os.Remove(path.Join(db.GetPath(), "branding") + "/logo.gif")
|
||||||
|
os.Remove(path.Join(db.GetPath(), "branding") + "/logo.ico")
|
||||||
|
f, err := os.OpenFile(path.Join(db.GetPath(), "branding")+"/logo."+strings.Split(logo_handler.Filename, ".")[1], os.O_WRONLY|os.O_CREATE, 0777)
|
||||||
|
if err != nil {
|
||||||
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot open " + path.Join(db.GetPath(), "branding") + "/logo." + strings.Split(logo_handler.Filename, ".")[1]})
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
io.Copy(f, logo_file)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.SetBrandName(brand_name); err != nil {
|
||||||
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot set brand name"})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Updated branding settings successfully"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
7
main.go
7
main.go
|
@ -147,9 +147,10 @@ func main() {
|
||||||
sendmail = emailer.NewSmtpMail(util.SmtpHostname, util.SmtpPort, util.SmtpUsername, util.SmtpPassword, util.SmtpNoTLSCheck, util.SmtpAuthType, util.EmailFromName, util.EmailFrom, util.SmtpEncryption)
|
sendmail = emailer.NewSmtpMail(util.SmtpHostname, util.SmtpPort, util.SmtpUsername, util.SmtpPassword, util.SmtpNoTLSCheck, util.SmtpAuthType, util.EmailFromName, util.EmailFrom, util.SmtpEncryption)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.GET(util.BasePath+"/about", handler.AboutPage())
|
app.GET(util.BasePath+"/about", handler.AboutPage(db))
|
||||||
app.GET(util.BasePath+"/_health", handler.Health())
|
app.GET(util.BasePath+"/_health", handler.Health())
|
||||||
app.GET(util.BasePath+"/favicon", handler.Favicon())
|
app.GET(util.BasePath+"/favicon", handler.Favicon(db))
|
||||||
|
app.GET(util.BasePath+"/brand-logo", handler.BrandLogo(db))
|
||||||
app.POST(util.BasePath+"/new-client", handler.NewClient(db), handler.ValidSession, handler.ContentTypeJson)
|
app.POST(util.BasePath+"/new-client", handler.NewClient(db), handler.ValidSession, handler.ContentTypeJson)
|
||||||
app.POST(util.BasePath+"/update-client", handler.UpdateClient(db), handler.ValidSession, handler.ContentTypeJson)
|
app.POST(util.BasePath+"/update-client", handler.UpdateClient(db), handler.ValidSession, handler.ContentTypeJson)
|
||||||
app.POST(util.BasePath+"/email-client", handler.EmailClient(db, sendmail, defaultEmailSubject, defaultEmailContent), handler.ValidSession, handler.ContentTypeJson)
|
app.POST(util.BasePath+"/email-client", handler.EmailClient(db, sendmail, defaultEmailSubject, defaultEmailContent), handler.ValidSession, handler.ContentTypeJson)
|
||||||
|
@ -171,6 +172,8 @@ func main() {
|
||||||
app.POST(util.BasePath+"/wake_on_lan_host", handler.SaveWakeOnLanHost(db), handler.ValidSession, handler.ContentTypeJson)
|
app.POST(util.BasePath+"/wake_on_lan_host", handler.SaveWakeOnLanHost(db), handler.ValidSession, handler.ContentTypeJson)
|
||||||
app.DELETE(util.BasePath+"/wake_on_lan_host/:mac_address", handler.DeleteWakeOnHost(db), handler.ValidSession, handler.ContentTypeJson)
|
app.DELETE(util.BasePath+"/wake_on_lan_host/:mac_address", handler.DeleteWakeOnHost(db), handler.ValidSession, handler.ContentTypeJson)
|
||||||
app.PUT(util.BasePath+"/wake_on_lan_host/:mac_address", handler.WakeOnHost(db), handler.ValidSession, handler.ContentTypeJson)
|
app.PUT(util.BasePath+"/wake_on_lan_host/:mac_address", handler.WakeOnHost(db), handler.ValidSession, handler.ContentTypeJson)
|
||||||
|
app.GET(util.BasePath+"/branding-settings", handler.BrandingSettings(db), handler.ValidSession)
|
||||||
|
app.POST(util.BasePath+"/update-branding", handler.UpdateBranding(db), handler.ValidSession)
|
||||||
|
|
||||||
// servers other static files
|
// servers other static files
|
||||||
app.GET(util.BasePath+"/static/*", echo.WrapHandler(http.StripPrefix(util.BasePath+"/static/", assetHandler)))
|
app.GET(util.BasePath+"/static/*", echo.WrapHandler(http.StripPrefix(util.BasePath+"/static/", assetHandler)))
|
||||||
|
|
|
@ -10,4 +10,5 @@ type Interface struct {
|
||||||
type BaseData struct {
|
type BaseData struct {
|
||||||
Active string
|
Active string
|
||||||
CurrentUser string
|
CurrentUser string
|
||||||
|
BrandName string
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,11 @@ func New(tmplBox *rice.Box, extraData map[string]string, secret []byte) *echo.Ec
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
brandingSettingsString, err := tmplBox.String("branding_settings.html")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// create template list
|
// create template list
|
||||||
funcs := template.FuncMap{
|
funcs := template.FuncMap{
|
||||||
"StringsJoin": strings.Join,
|
"StringsJoin": strings.Join,
|
||||||
|
@ -111,6 +116,7 @@ func New(tmplBox *rice.Box, extraData map[string]string, secret []byte) *echo.Ec
|
||||||
templates["status.html"] = template.Must(template.New("status").Funcs(funcs).Parse(tmplBaseString + tmplStatusString))
|
templates["status.html"] = template.Must(template.New("status").Funcs(funcs).Parse(tmplBaseString + tmplStatusString))
|
||||||
templates["wake_on_lan_hosts.html"] = template.Must(template.New("wake_on_lan_hosts").Funcs(funcs).Parse(tmplBaseString + tmplWakeOnLanHostsString))
|
templates["wake_on_lan_hosts.html"] = template.Must(template.New("wake_on_lan_hosts").Funcs(funcs).Parse(tmplBaseString + tmplWakeOnLanHostsString))
|
||||||
templates["about.html"] = template.Must(template.New("about").Funcs(funcs).Parse(tmplBaseString + aboutPageString))
|
templates["about.html"] = template.Must(template.New("about").Funcs(funcs).Parse(tmplBaseString + aboutPageString))
|
||||||
|
templates["branding_settings.html"] = template.Must(template.New("branding_settings").Funcs(funcs).Parse(tmplBaseString + brandingSettingsString))
|
||||||
|
|
||||||
e.Logger.SetLevel(log.DEBUG)
|
e.Logger.SetLevel(log.DEBUG)
|
||||||
e.Pre(middleware.RemoveTrailingSlash())
|
e.Pre(middleware.RemoveTrailingSlash())
|
||||||
|
|
|
@ -43,6 +43,9 @@ func (o *JsonDB) Init() error {
|
||||||
var serverKeyPairPath string = path.Join(serverPath, "keypair.json")
|
var serverKeyPairPath string = path.Join(serverPath, "keypair.json")
|
||||||
var globalSettingPath string = path.Join(serverPath, "global_settings.json")
|
var globalSettingPath string = path.Join(serverPath, "global_settings.json")
|
||||||
var userPath string = path.Join(serverPath, "users.json")
|
var userPath string = path.Join(serverPath, "users.json")
|
||||||
|
var brandingPath string = path.Join(o.dbPath, "branding")
|
||||||
|
var brandNamePath string = path.Join(brandingPath, "brand_name.json")
|
||||||
|
|
||||||
// create directories if they do not exist
|
// create directories if they do not exist
|
||||||
if _, err := os.Stat(clientPath); os.IsNotExist(err) {
|
if _, err := os.Stat(clientPath); os.IsNotExist(err) {
|
||||||
os.MkdirAll(clientPath, os.ModePerm)
|
os.MkdirAll(clientPath, os.ModePerm)
|
||||||
|
@ -53,6 +56,9 @@ func (o *JsonDB) Init() error {
|
||||||
if _, err := os.Stat(wakeOnLanHostsPath); os.IsNotExist(err) {
|
if _, err := os.Stat(wakeOnLanHostsPath); os.IsNotExist(err) {
|
||||||
os.MkdirAll(wakeOnLanHostsPath, os.ModePerm)
|
os.MkdirAll(wakeOnLanHostsPath, os.ModePerm)
|
||||||
}
|
}
|
||||||
|
if _, err := os.Stat(brandingPath); os.IsNotExist(err) {
|
||||||
|
os.MkdirAll(brandingPath, os.ModePerm)
|
||||||
|
}
|
||||||
|
|
||||||
// server's interface
|
// server's interface
|
||||||
if _, err := os.Stat(serverInterfacePath); os.IsNotExist(err) {
|
if _, err := os.Stat(serverInterfacePath); os.IsNotExist(err) {
|
||||||
|
@ -117,6 +123,14 @@ func (o *JsonDB) Init() error {
|
||||||
}
|
}
|
||||||
o.conn.Write("server", "users", user)
|
o.conn.Write("server", "users", user)
|
||||||
}
|
}
|
||||||
|
// brand name
|
||||||
|
if _, err := os.Stat(brandNamePath); os.IsNotExist(err) {
|
||||||
|
type brandName struct {
|
||||||
|
BrandName string `json:"brand_name"`
|
||||||
|
}
|
||||||
|
name := brandName{BrandName: "WIREGUARD UI"}
|
||||||
|
o.conn.Write("branding", "brand_name", name)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -255,3 +269,30 @@ func (o *JsonDB) SaveServerKeyPair(serverKeyPair model.ServerKeypair) error {
|
||||||
func (o *JsonDB) SaveGlobalSettings(globalSettings model.GlobalSetting) error {
|
func (o *JsonDB) SaveGlobalSettings(globalSettings model.GlobalSetting) error {
|
||||||
return o.conn.Write("server", "global_settings", globalSettings)
|
return o.conn.Write("server", "global_settings", globalSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBrandName func to get brand name from the database
|
||||||
|
func (o *JsonDB) GetBrandName() string {
|
||||||
|
type brandName struct {
|
||||||
|
BrandName string `json:"brand_name"`
|
||||||
|
}
|
||||||
|
name := brandName{}
|
||||||
|
o.conn.Read("branding", "brand_name", &name)
|
||||||
|
|
||||||
|
if err := o.conn.Read("branding", "brand_name", &name); err != nil {
|
||||||
|
return "WIREGUARD UI"
|
||||||
|
}
|
||||||
|
|
||||||
|
return name.BrandName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *JsonDB) SetBrandName(brandName string) error {
|
||||||
|
type brandNameStruct struct {
|
||||||
|
BrandName string `json:"brand_name"`
|
||||||
|
}
|
||||||
|
name := brandNameStruct{BrandName: brandName}
|
||||||
|
return o.conn.Write("branding", "brand_name", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *JsonDB) GetPath() string {
|
||||||
|
return o.dbPath
|
||||||
|
}
|
||||||
|
|
|
@ -22,4 +22,7 @@ type IStore interface {
|
||||||
DeleteWakeOnHostLanHost(macAddress string) error
|
DeleteWakeOnHostLanHost(macAddress string) error
|
||||||
SaveWakeOnLanHost(host model.WakeOnLanHost) error
|
SaveWakeOnLanHost(host model.WakeOnLanHost) error
|
||||||
DeleteWakeOnHost(host model.WakeOnLanHost) error
|
DeleteWakeOnHost(host model.WakeOnLanHost) error
|
||||||
|
GetBrandName() string
|
||||||
|
SetBrandName(brandName string) error
|
||||||
|
GetPath() string
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,9 @@
|
||||||
<aside class="main-sidebar sidebar-dark-primary elevation-4">
|
<aside class="main-sidebar sidebar-dark-primary elevation-4">
|
||||||
<!-- Brand Logo -->
|
<!-- Brand Logo -->
|
||||||
<a href="{{.basePath}}" class="brand-link">
|
<a href="{{.basePath}}" class="brand-link">
|
||||||
<span class="brand-text"> WIREGUARD UI</span>
|
<img src="{{.basePath}}/brand-logo" style="width: 100%">
|
||||||
|
</br>
|
||||||
|
<span class="brand-text"> {{.baseData.BrandName}}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
|
@ -126,6 +128,14 @@
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="{{.basePath}}/branding-settings" class="nav-link {{if eq .baseData.Active "branding-settings" }}active{{end}}">
|
||||||
|
<i class="nav-icon fas fa-cog"></i>
|
||||||
|
<p>
|
||||||
|
Branding Settings
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="nav-header">UTILITIES</li>
|
<li class="nav-header">UTILITIES</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="{{.basePath}}/status" class="nav-link {{if eq .baseData.Active "status" }}active{{end}}">
|
<a href="{{.basePath}}/status" class="nav-link {{if eq .baseData.Active "status" }}active{{end}}">
|
||||||
|
|
202
templates/branding_settings.html
Normal file
202
templates/branding_settings.html
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
{{define "title"}}
|
||||||
|
Branding Settings
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "top_css"}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "username"}}
|
||||||
|
{{ .username }}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "page_title"}}
|
||||||
|
Branding Settings
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "page_content"}}
|
||||||
|
<section class="content">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<!-- <h5 class="mt-4 mb-2">Global Settings</h5> -->
|
||||||
|
<div class="row">
|
||||||
|
<!-- left column -->
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card card-success">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">Wireguard-UI Branding Settings</h3>
|
||||||
|
</div>
|
||||||
|
<!-- /.card-header -->
|
||||||
|
<!-- form start -->
|
||||||
|
<form role="form" id="frm_branding_settings" name="frm_branding_settings">
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="favicon">Favicon</label>
|
||||||
|
<div class="input-group input-group">
|
||||||
|
<input type="text" class="form-control" id="favicon" name="favicon" disabled>
|
||||||
|
<span class="input-group-append">
|
||||||
|
<label class="btn btn-default">Select favicon<input type="file"
|
||||||
|
id="favicon_input"
|
||||||
|
accept=".ico" hidden>
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="brand_logo">Brand logo</label>
|
||||||
|
<div class="input-group input-group">
|
||||||
|
<input type="text" class="form-control" id="brand_logo" name="brand_logo" disabled>
|
||||||
|
<span class="input-group-append">
|
||||||
|
<label class="btn btn-default">Select logo<input type="file"
|
||||||
|
id="brand_logo_input" accept=".png,.jpg,.jpeg,.gif,.ico" hidden>
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="brand_name">Brand name</label>
|
||||||
|
<input type="text" class="form-control" id="brand_name"
|
||||||
|
name="brand_name" placeholder="WIREGUARD UI"
|
||||||
|
value="{{if .baseData.BrandName }}{{ .baseData.BrandName }}{{end}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.card-body -->
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<button type="submit" class="btn btn-success">Save</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<!-- /.card -->
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card card-success">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">Help</h3>
|
||||||
|
</div>
|
||||||
|
<!-- /.card-header -->
|
||||||
|
<div class="card-body">
|
||||||
|
<dl>
|
||||||
|
<dt>1. Favicon</dt>
|
||||||
|
<dd>Formats accepted: <code>.ico</code></dd>
|
||||||
|
<dd>Optional - leave blank or clear to continue using current favicon.</dd>
|
||||||
|
<dt>2. Brand logo</dt>
|
||||||
|
<dd>The logo, displayed in the upper left corner.</dd>
|
||||||
|
<dd>Formats accepted: <code>.png</code>, <code>.jpg</code>, <code>.jpeg</code>, <code>.gif</code>, <code>.ico</code></dd>
|
||||||
|
<dd>Optional - leave blank or clear to continue using current brand logo.</dd>
|
||||||
|
<dt>3. Brand name</dt>
|
||||||
|
<dd>The name, displayed in the upper left corner.</dd>
|
||||||
|
<dd>Mandatory - must contain at least one symbol.</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.card -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.row -->
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "bottom_js"}}
|
||||||
|
<script>
|
||||||
|
function submitBrandingSettings() {
|
||||||
|
|
||||||
|
|
||||||
|
var data = new FormData();
|
||||||
|
data.append("brand_name", $("#brand_name").val());
|
||||||
|
|
||||||
|
var count = 1;
|
||||||
|
if (typeof document.getElementById("favicon_input").files[0] !== 'undefined') {
|
||||||
|
readFile(data, 'favicon', "favicon_input");
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if (typeof document.getElementById("brand_logo_input").files[0] !== 'undefined') {
|
||||||
|
readFile(data, 'logo', "brand_logo_input");
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitForRead() {
|
||||||
|
var temp = 0;
|
||||||
|
for (const pair of data.entries()) {
|
||||||
|
temp++;
|
||||||
|
}
|
||||||
|
if (temp !== count) {
|
||||||
|
setTimeout(() => waitForRead(), 50);
|
||||||
|
} else {
|
||||||
|
$.ajax({
|
||||||
|
url: "{{.basePath}}/update-branding",
|
||||||
|
data: data,
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
type: "POST",
|
||||||
|
success: function(data) {
|
||||||
|
toastr.success('Updated branding successfully');
|
||||||
|
},
|
||||||
|
error: function(jqXHR, exception) {
|
||||||
|
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
||||||
|
toastr.error(responseJson['message']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
waitForRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
function readFile(data, name, element) {
|
||||||
|
var image = document.getElementById(element).files[0];
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.readAsArrayBuffer(image);
|
||||||
|
reader.onloadend = function () {
|
||||||
|
data.append(name, image);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
$("#favicon_input").on('change', function () {
|
||||||
|
$("#favicon").val($("#favicon_input").val());
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#brand_logo_input").on('change', function () {
|
||||||
|
$("#brand_logo").val($("#brand_logo_input").val());
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Form validation
|
||||||
|
$(document).ready(function () {
|
||||||
|
$.validator.setDefaults({
|
||||||
|
submitHandler: function () {
|
||||||
|
submitBrandingSettings();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#frm_branding_settings").validate({
|
||||||
|
rules: {
|
||||||
|
brand_name: {
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
brand_name: {
|
||||||
|
required: "Please enter a brand name"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
errorElement: 'span',
|
||||||
|
errorPlacement: function (error, element) {
|
||||||
|
error.addClass('invalid-feedback');
|
||||||
|
element.closest('.form-group').append(error);
|
||||||
|
},
|
||||||
|
highlight: function (element, errorClass, validClass) {
|
||||||
|
$(element).addClass('is-invalid');
|
||||||
|
},
|
||||||
|
unhighlight: function (element, errorClass, validClass) {
|
||||||
|
$(element).removeClass('is-invalid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{{end}}
|
Loading…
Add table
Add a link
Reference in a new issue