All the control panel routes have been moved to /routes/panel/ now.
Moved the software version to common.go for better accessibility.
This commit is contained in:
parent
b2e97e47c1
commit
6634f3f64b
|
@ -9,6 +9,8 @@ import (
|
||||||
"../query_gen/lib"
|
"../query_gen/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var SoftwareVersion = Version{Major: 0, Minor: 2, Patch: 0, Tag: "dev"}
|
||||||
|
|
||||||
// nolint I don't want to write comments for each of these o.o
|
// nolint I don't want to write comments for each of these o.o
|
||||||
const Hour int = 60 * 60
|
const Hour int = 60 * 60
|
||||||
const Day int = Hour * 24
|
const Day int = Hour * 24
|
||||||
|
|
|
@ -20,10 +20,6 @@ type Stmts struct {
|
||||||
|
|
||||||
getActivityFeedByWatcher *sql.Stmt
|
getActivityFeedByWatcher *sql.Stmt
|
||||||
getActivityCountByWatcher *sql.Stmt
|
getActivityCountByWatcher *sql.Stmt
|
||||||
todaysPostCount *sql.Stmt
|
|
||||||
todaysTopicCount *sql.Stmt
|
|
||||||
todaysTopicCountByForum *sql.Stmt
|
|
||||||
todaysNewUserCount *sql.Stmt
|
|
||||||
|
|
||||||
Mocks bool
|
Mocks bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,6 @@ type Stmts struct {
|
||||||
|
|
||||||
getActivityFeedByWatcher *sql.Stmt
|
getActivityFeedByWatcher *sql.Stmt
|
||||||
getActivityCountByWatcher *sql.Stmt
|
getActivityCountByWatcher *sql.Stmt
|
||||||
todaysPostCount *sql.Stmt
|
|
||||||
todaysTopicCount *sql.Stmt
|
|
||||||
todaysTopicCountByForum *sql.Stmt
|
|
||||||
todaysNewUserCount *sql.Stmt
|
|
||||||
|
|
||||||
Mocks bool
|
Mocks bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,6 @@ type Stmts struct {
|
||||||
|
|
||||||
getActivityFeedByWatcher *sql.Stmt
|
getActivityFeedByWatcher *sql.Stmt
|
||||||
getActivityCountByWatcher *sql.Stmt
|
getActivityCountByWatcher *sql.Stmt
|
||||||
todaysPostCount *sql.Stmt
|
|
||||||
todaysTopicCount *sql.Stmt
|
|
||||||
todaysTopicCountByForum *sql.Stmt
|
|
||||||
todaysNewUserCount *sql.Stmt
|
|
||||||
|
|
||||||
Mocks bool
|
Mocks bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,7 @@ var RouteMap = map[string]interface{}{
|
||||||
"panel.LogsRegs": panel.LogsRegs,
|
"panel.LogsRegs": panel.LogsRegs,
|
||||||
"panel.LogsMod": panel.LogsMod,
|
"panel.LogsMod": panel.LogsMod,
|
||||||
"panel.Debug": panel.Debug,
|
"panel.Debug": panel.Debug,
|
||||||
"routePanelDashboard": routePanelDashboard,
|
"panel.Dashboard": panel.Dashboard,
|
||||||
"routes.AccountEdit": routes.AccountEdit,
|
"routes.AccountEdit": routes.AccountEdit,
|
||||||
"routes.AccountEditPassword": routes.AccountEditPassword,
|
"routes.AccountEditPassword": routes.AccountEditPassword,
|
||||||
"routes.AccountEditPasswordSubmit": routes.AccountEditPasswordSubmit,
|
"routes.AccountEditPasswordSubmit": routes.AccountEditPasswordSubmit,
|
||||||
|
@ -232,7 +232,7 @@ var routeMapEnum = map[string]int{
|
||||||
"panel.LogsRegs": 75,
|
"panel.LogsRegs": 75,
|
||||||
"panel.LogsMod": 76,
|
"panel.LogsMod": 76,
|
||||||
"panel.Debug": 77,
|
"panel.Debug": 77,
|
||||||
"routePanelDashboard": 78,
|
"panel.Dashboard": 78,
|
||||||
"routes.AccountEdit": 79,
|
"routes.AccountEdit": 79,
|
||||||
"routes.AccountEditPassword": 80,
|
"routes.AccountEditPassword": 80,
|
||||||
"routes.AccountEditPasswordSubmit": 81,
|
"routes.AccountEditPasswordSubmit": 81,
|
||||||
|
@ -361,7 +361,7 @@ var reverseRouteMapEnum = map[int]string{
|
||||||
75: "panel.LogsRegs",
|
75: "panel.LogsRegs",
|
||||||
76: "panel.LogsMod",
|
76: "panel.LogsMod",
|
||||||
77: "panel.Debug",
|
77: "panel.Debug",
|
||||||
78: "routePanelDashboard",
|
78: "panel.Dashboard",
|
||||||
79: "routes.AccountEdit",
|
79: "routes.AccountEdit",
|
||||||
80: "routes.AccountEditPassword",
|
80: "routes.AccountEditPassword",
|
||||||
81: "routes.AccountEditPasswordSubmit",
|
81: "routes.AccountEditPasswordSubmit",
|
||||||
|
@ -1442,7 +1442,7 @@ func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, u
|
||||||
err = panel.Debug(w,req,user)
|
err = panel.Debug(w,req,user)
|
||||||
default:
|
default:
|
||||||
counters.RouteViewCounter.Bump(78)
|
counters.RouteViewCounter.Bump(78)
|
||||||
err = routePanelDashboard(w,req,user)
|
err = panel.Dashboard(w,req,user)
|
||||||
}
|
}
|
||||||
case "/user":
|
case "/user":
|
||||||
switch(req.URL.Path) {
|
switch(req.URL.Path) {
|
||||||
|
|
3
main.go
3
main.go
|
@ -29,7 +29,6 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = common.Version{Major: 0, Minor: 2, Patch: 0, Tag: "dev"}
|
|
||||||
var router *GenRouter
|
var router *GenRouter
|
||||||
var logWriter = io.MultiWriter(os.Stderr)
|
var logWriter = io.MultiWriter(os.Stderr)
|
||||||
|
|
||||||
|
@ -224,7 +223,7 @@ func main() {
|
||||||
}
|
}
|
||||||
logWriter = io.MultiWriter(os.Stderr, f)
|
logWriter = io.MultiWriter(os.Stderr, f)
|
||||||
log.SetOutput(logWriter)
|
log.SetOutput(logWriter)
|
||||||
log.Print("Running Gosora v" + version.String())
|
log.Print("Running Gosora v" + common.SoftwareVersion.String())
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
common.StartTime = time.Now()
|
common.StartTime = time.Now()
|
||||||
|
|
||||||
|
|
29
mssql.go
29
mssql.go
|
@ -10,7 +10,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"log"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"./common"
|
"./common"
|
||||||
|
@ -74,7 +73,7 @@ func initMSSQL() (err error) {
|
||||||
|
|
||||||
// TODO: Is there a less noisy way of doing this for tests?
|
// TODO: Is there a less noisy way of doing this for tests?
|
||||||
/*log.Print("Preparing getActivityFeedByWatcher statement.")
|
/*log.Print("Preparing getActivityFeedByWatcher statement.")
|
||||||
stmts.getActivityFeedByWatcherStmt, err = db.Prepare("SELECT activity_stream_matches.asid, activity_stream.actor, activity_stream.targetUser, activity_stream.event, activity_stream.elementType, activity_stream.elementID FROM [activity_stream_matches] INNER JOIN [activity_stream] ON activity_stream_matches.asid = activity_stream.asid AND activity_stream_matches.watcher != activity_stream.actor WHERE [watcher] = ? ORDER BY activity_stream.asid DESC OFFSET 0 ROWS FETCH NEXT 8 ROWS ONLY")
|
stmts.getActivityFeedByWatcherStmt, err = db.Prepare("SELECT activity_stream_matches.asid, activity_stream.actor, activity_stream.targetUser, activity_stream.event, activity_stream.elementType, activity_stream.elementID FROM [activity_stream_matches] INNER JOIN [activity_stream] ON activity_stream_matches.asid = activity_stream.asid AND activity_stream_matches.watcher != activity_stream.actor WHERE [watcher] = ? ORDER BY activity_stream.asid DESC OFFSET 0 ROWS FETCH NEXT 16 ROWS ONLY")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -84,31 +83,7 @@ func initMSSQL() (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
log.Print("Preparing todaysPostCount statement.")
|
|
||||||
stmts.todaysPostCountStmt, err = db.Prepare("select count(*) from replies where createdAt >= DATEADD(DAY, -1, GETUTCDATE())")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing todaysTopicCount statement.")
|
|
||||||
stmts.todaysTopicCountStmt, err = db.Prepare("select count(*) from topics where createdAt >= DATEADD(DAY, -1, GETUTCDATE())")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}*/
|
|
||||||
|
|
||||||
log.Print("Preparing todaysTopicCountByForum statement.")
|
|
||||||
// TODO: Stop hard-coding this query
|
|
||||||
stmts.todaysTopicCountByForum, err = db.Prepare("select count(*) from topics where createdAt >= DATEADD(DAY, -1, GETUTCDATE()) and parentID = ?")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
/*log.Print("Preparing todaysNewUserCount statement.")
|
|
||||||
stmts.todaysNewUserCountStmt, err = db.Prepare("select count(*) from users where createdAt >= DATEADD(DAY, -1, GETUTCDATE())")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}*/
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
25
mysql.go
25
mysql.go
|
@ -64,30 +64,5 @@ func initMySQL() (err error) {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Preparing todaysPostCount statement.")
|
|
||||||
stmts.todaysPostCount, err = db.Prepare("select count(*) from replies where createdAt BETWEEN (utc_timestamp() - interval 1 day) and utc_timestamp()")
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing todaysTopicCount statement.")
|
|
||||||
stmts.todaysTopicCount, err = db.Prepare("select count(*) from topics where createdAt BETWEEN (utc_timestamp() - interval 1 day) and utc_timestamp()")
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing todaysTopicCountByForum statement.")
|
|
||||||
// TODO: Stop hard-coding this query
|
|
||||||
stmts.todaysTopicCountByForum, err = db.Prepare("select count(*) from topics where createdAt BETWEEN (utc_timestamp() - interval 1 day) and utc_timestamp() and parentID = ?")
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing todaysNewUserCount statement.")
|
|
||||||
stmts.todaysNewUserCount, err = db.Prepare("select count(*) from users where createdAt BETWEEN (utc_timestamp() - interval 1 day) and utc_timestamp()")
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1150,10 +1150,6 @@ type Stmts struct {
|
||||||
` + stmts + `
|
` + stmts + `
|
||||||
getActivityFeedByWatcher *sql.Stmt
|
getActivityFeedByWatcher *sql.Stmt
|
||||||
getActivityCountByWatcher *sql.Stmt
|
getActivityCountByWatcher *sql.Stmt
|
||||||
todaysPostCount *sql.Stmt
|
|
||||||
todaysTopicCount *sql.Stmt
|
|
||||||
todaysTopicCountByForum *sql.Stmt
|
|
||||||
todaysNewUserCount *sql.Stmt
|
|
||||||
|
|
||||||
Mocks bool
|
Mocks bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -756,10 +756,6 @@ type Stmts struct {
|
||||||
` + stmts + `
|
` + stmts + `
|
||||||
getActivityFeedByWatcher *sql.Stmt
|
getActivityFeedByWatcher *sql.Stmt
|
||||||
getActivityCountByWatcher *sql.Stmt
|
getActivityCountByWatcher *sql.Stmt
|
||||||
todaysPostCount *sql.Stmt
|
|
||||||
todaysTopicCount *sql.Stmt
|
|
||||||
todaysTopicCountByForum *sql.Stmt
|
|
||||||
todaysNewUserCount *sql.Stmt
|
|
||||||
|
|
||||||
Mocks bool
|
Mocks bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -438,10 +438,6 @@ type Stmts struct {
|
||||||
` + stmts + `
|
` + stmts + `
|
||||||
getActivityFeedByWatcher *sql.Stmt
|
getActivityFeedByWatcher *sql.Stmt
|
||||||
getActivityCountByWatcher *sql.Stmt
|
getActivityCountByWatcher *sql.Stmt
|
||||||
todaysPostCount *sql.Stmt
|
|
||||||
todaysTopicCount *sql.Stmt
|
|
||||||
todaysTopicCountByForum *sql.Stmt
|
|
||||||
todaysNewUserCount *sql.Stmt
|
|
||||||
|
|
||||||
Mocks bool
|
Mocks bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,7 +142,7 @@ func buildAccountRoutes() {
|
||||||
func buildPanelRoutes() {
|
func buildPanelRoutes() {
|
||||||
panelGroup := newRouteGroup("/panel/").Before("SuperModOnly")
|
panelGroup := newRouteGroup("/panel/").Before("SuperModOnly")
|
||||||
panelGroup.Routes(
|
panelGroup.Routes(
|
||||||
View("routePanelDashboard", "/panel/"),
|
View("panel.Dashboard", "/panel/"),
|
||||||
View("panel.Forums", "/panel/forums/"),
|
View("panel.Forums", "/panel/forums/"),
|
||||||
Action("panel.ForumsCreateSubmit", "/panel/forums/create/"),
|
Action("panel.ForumsCreateSubmit", "/panel/forums/create/"),
|
||||||
Action("panel.ForumsDelete", "/panel/forums/delete/", "extraData"),
|
Action("panel.ForumsDelete", "/panel/forums/delete/", "extraData"),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package panel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
@ -6,31 +6,63 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"./common"
|
"../../common"
|
||||||
|
"../../query_gen/lib"
|
||||||
"github.com/Azareal/gopsutil/mem"
|
"github.com/Azareal/gopsutil/mem"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// We're trying to reduce the amount of boilerplate in here, so I added these two functions, they might wind up circulating outside this file in the future
|
type dashStmts struct {
|
||||||
func panelSuccessRedirect(dest string, w http.ResponseWriter, r *http.Request, isJs bool) common.RouteError {
|
todaysPostCount *sql.Stmt
|
||||||
if !isJs {
|
todaysTopicCount *sql.Stmt
|
||||||
http.Redirect(w, r, dest, http.StatusSeeOther)
|
todaysTopicCountByForum *sql.Stmt
|
||||||
} else {
|
todaysNewUserCount *sql.Stmt
|
||||||
w.Write(successJSONBytes)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func panelRenderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, user common.User, pi interface{}) common.RouteError {
|
|
||||||
if common.RunPreRenderHook("pre_render_"+tmplName, w, r, &user, pi) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
err := common.Templates.ExecuteTemplate(w, tmplName+".html", pi)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func routePanelDashboard(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
// TODO: Stop hard-coding these queries
|
||||||
|
func dashMySQLStmts() (stmts dashStmts, err error) {
|
||||||
|
db := qgen.Builder.GetConn()
|
||||||
|
|
||||||
|
var prepareStmt = func(table string, ext string) *sql.Stmt {
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
stmt, ierr := db.Prepare("select count(*) from " + table + " where createdAt BETWEEN (utc_timestamp() - interval 1 day) and utc_timestamp() " + ext)
|
||||||
|
err = errors.WithStack(ierr)
|
||||||
|
return stmt
|
||||||
|
}
|
||||||
|
|
||||||
|
stmts.todaysPostCount = prepareStmt("replies", "")
|
||||||
|
stmts.todaysTopicCount = prepareStmt("topics", "")
|
||||||
|
stmts.todaysNewUserCount = prepareStmt("users", "")
|
||||||
|
stmts.todaysTopicCountByForum = prepareStmt("topics", " and parentID = ?")
|
||||||
|
|
||||||
|
return stmts, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Stop hard-coding these queries
|
||||||
|
func dashMSSQLStmts() (stmts dashStmts, err error) {
|
||||||
|
db := qgen.Builder.GetConn()
|
||||||
|
|
||||||
|
var prepareStmt = func(table string, ext string) *sql.Stmt {
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
stmt, ierr := db.Prepare("select count(*) from " + table + " where createdAt >= DATEADD(DAY, -1, GETUTCDATE())" + ext)
|
||||||
|
err = errors.WithStack(ierr)
|
||||||
|
return stmt
|
||||||
|
}
|
||||||
|
|
||||||
|
stmts.todaysPostCount = prepareStmt("replies", "")
|
||||||
|
stmts.todaysTopicCount = prepareStmt("topics", "")
|
||||||
|
stmts.todaysNewUserCount = prepareStmt("users", "")
|
||||||
|
stmts.todaysTopicCountByForum = prepareStmt("topics", " and parentID = ?")
|
||||||
|
|
||||||
|
return stmts, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//routePanelDashboard
|
||||||
|
func Dashboard(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||||
header, stats, ferr := common.PanelUserCheck(w, r, &user)
|
header, stats, ferr := common.PanelUserCheck(w, r, &user)
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
return ferr
|
return ferr
|
||||||
|
@ -91,12 +123,25 @@ func routePanelDashboard(w http.ResponseWriter, r *http.Request, user common.Use
|
||||||
var intErr error
|
var intErr error
|
||||||
var extractStat = func(stmt *sql.Stmt, args ...interface{}) (stat int) {
|
var extractStat = func(stmt *sql.Stmt, args ...interface{}) (stat int) {
|
||||||
err := stmt.QueryRow(args...).Scan(&stat)
|
err := stmt.QueryRow(args...).Scan(&stat)
|
||||||
if err != nil && err != ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
intErr = err
|
intErr = err
|
||||||
}
|
}
|
||||||
return stat
|
return stat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var stmts dashStmts
|
||||||
|
switch qgen.Builder.GetAdapter().GetName() {
|
||||||
|
case "mysql":
|
||||||
|
stmts, err = dashMySQLStmts()
|
||||||
|
case "mssql":
|
||||||
|
stmts, err = dashMSSQLStmts()
|
||||||
|
default:
|
||||||
|
return common.InternalError(errors.New("Unknown database adapter on dashboard"), w, r)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
var postCount = extractStat(stmts.todaysPostCount)
|
var postCount = extractStat(stmts.todaysPostCount)
|
||||||
var postInterval = "day"
|
var postInterval = "day"
|
||||||
var postColour = greaterThanSwitch(postCount, 5, 25)
|
var postColour = greaterThanSwitch(postCount, 5, 25)
|
||||||
|
@ -120,7 +165,7 @@ func routePanelDashboard(w http.ResponseWriter, r *http.Request, user common.Use
|
||||||
var gridElements = []common.GridElement{
|
var gridElements = []common.GridElement{
|
||||||
// TODO: Implement a check for new versions of Gosora
|
// TODO: Implement a check for new versions of Gosora
|
||||||
//common.GridElement{"dash-version", "v" + version.String(), 0, "grid_istat stat_green", "", "", "Gosora is up-to-date :)"},
|
//common.GridElement{"dash-version", "v" + version.String(), 0, "grid_istat stat_green", "", "", "Gosora is up-to-date :)"},
|
||||||
common.GridElement{"dash-version", "v" + version.String(), 0, "grid_istat", "", "", ""},
|
common.GridElement{"dash-version", "v" + common.SoftwareVersion.String(), 0, "grid_istat", "", "", ""},
|
||||||
|
|
||||||
common.GridElement{"dash-cpu", "CPU: " + cpustr, 1, "grid_istat " + cpuColour, "", "", "The global CPU usage of this server"},
|
common.GridElement{"dash-cpu", "CPU: " + cpustr, 1, "grid_istat " + cpuColour, "", "", "The global CPU usage of this server"},
|
||||||
common.GridElement{"dash-ram", "RAM: " + ramstr, 2, "grid_istat " + ramColour, "", "", "The global RAM usage of this server"},
|
common.GridElement{"dash-ram", "RAM: " + ramstr, 2, "grid_istat " + ramColour, "", "", "The global RAM usage of this server"},
|
||||||
|
@ -164,5 +209,5 @@ func routePanelDashboard(w http.ResponseWriter, r *http.Request, user common.Use
|
||||||
}
|
}
|
||||||
|
|
||||||
pi := common.PanelDashboardPage{&common.BasePanelPage{header, stats, "dashboard", common.ReportForumID}, gridElements}
|
pi := common.PanelDashboardPage{&common.BasePanelPage{header, stats, "dashboard", common.ReportForumID}, gridElements}
|
||||||
return panelRenderTemplate("panel_dashboard", w, r, user, &pi)
|
return renderTemplate("panel_dashboard", w, r, user, &pi)
|
||||||
}
|
}
|
Loading…
Reference in New Issue