Moved all but one of the control panel theme routes into /routes/panel/
This commit is contained in:
parent
dea74eb32a
commit
750c0ff442
|
@ -60,15 +60,15 @@ var RouteMap = map[string]interface{}{
|
||||||
"panel.PagesEdit": panel.PagesEdit,
|
"panel.PagesEdit": panel.PagesEdit,
|
||||||
"panel.PagesEditSubmit": panel.PagesEditSubmit,
|
"panel.PagesEditSubmit": panel.PagesEditSubmit,
|
||||||
"panel.PagesDeleteSubmit": panel.PagesDeleteSubmit,
|
"panel.PagesDeleteSubmit": panel.PagesDeleteSubmit,
|
||||||
"routePanelThemes": routePanelThemes,
|
"panel.Themes": panel.Themes,
|
||||||
"routePanelThemesSetDefault": routePanelThemesSetDefault,
|
"routePanelThemesSetDefault": routePanelThemesSetDefault,
|
||||||
"routePanelThemesMenus": routePanelThemesMenus,
|
"panel.ThemesMenus": panel.ThemesMenus,
|
||||||
"routePanelThemesMenusEdit": routePanelThemesMenusEdit,
|
"panel.ThemesMenusEdit": panel.ThemesMenusEdit,
|
||||||
"routePanelThemesMenuItemEdit": routePanelThemesMenuItemEdit,
|
"panel.ThemesMenuItemEdit": panel.ThemesMenuItemEdit,
|
||||||
"routePanelThemesMenuItemEditSubmit": routePanelThemesMenuItemEditSubmit,
|
"panel.ThemesMenuItemEditSubmit": panel.ThemesMenuItemEditSubmit,
|
||||||
"routePanelThemesMenuItemCreateSubmit": routePanelThemesMenuItemCreateSubmit,
|
"panel.ThemesMenuItemCreateSubmit": panel.ThemesMenuItemCreateSubmit,
|
||||||
"routePanelThemesMenuItemDeleteSubmit": routePanelThemesMenuItemDeleteSubmit,
|
"panel.ThemesMenuItemDeleteSubmit": panel.ThemesMenuItemDeleteSubmit,
|
||||||
"routePanelThemesMenuItemOrderSubmit": routePanelThemesMenuItemOrderSubmit,
|
"panel.ThemesMenuItemOrderSubmit": panel.ThemesMenuItemOrderSubmit,
|
||||||
"panel.Plugins": panel.Plugins,
|
"panel.Plugins": panel.Plugins,
|
||||||
"panel.PluginsActivate": panel.PluginsActivate,
|
"panel.PluginsActivate": panel.PluginsActivate,
|
||||||
"panel.PluginsDeactivate": panel.PluginsDeactivate,
|
"panel.PluginsDeactivate": panel.PluginsDeactivate,
|
||||||
|
@ -191,15 +191,15 @@ var routeMapEnum = map[string]int{
|
||||||
"panel.PagesEdit": 34,
|
"panel.PagesEdit": 34,
|
||||||
"panel.PagesEditSubmit": 35,
|
"panel.PagesEditSubmit": 35,
|
||||||
"panel.PagesDeleteSubmit": 36,
|
"panel.PagesDeleteSubmit": 36,
|
||||||
"routePanelThemes": 37,
|
"panel.Themes": 37,
|
||||||
"routePanelThemesSetDefault": 38,
|
"routePanelThemesSetDefault": 38,
|
||||||
"routePanelThemesMenus": 39,
|
"panel.ThemesMenus": 39,
|
||||||
"routePanelThemesMenusEdit": 40,
|
"panel.ThemesMenusEdit": 40,
|
||||||
"routePanelThemesMenuItemEdit": 41,
|
"panel.ThemesMenuItemEdit": 41,
|
||||||
"routePanelThemesMenuItemEditSubmit": 42,
|
"panel.ThemesMenuItemEditSubmit": 42,
|
||||||
"routePanelThemesMenuItemCreateSubmit": 43,
|
"panel.ThemesMenuItemCreateSubmit": 43,
|
||||||
"routePanelThemesMenuItemDeleteSubmit": 44,
|
"panel.ThemesMenuItemDeleteSubmit": 44,
|
||||||
"routePanelThemesMenuItemOrderSubmit": 45,
|
"panel.ThemesMenuItemOrderSubmit": 45,
|
||||||
"panel.Plugins": 46,
|
"panel.Plugins": 46,
|
||||||
"panel.PluginsActivate": 47,
|
"panel.PluginsActivate": 47,
|
||||||
"panel.PluginsDeactivate": 48,
|
"panel.PluginsDeactivate": 48,
|
||||||
|
@ -320,15 +320,15 @@ var reverseRouteMapEnum = map[int]string{
|
||||||
34: "panel.PagesEdit",
|
34: "panel.PagesEdit",
|
||||||
35: "panel.PagesEditSubmit",
|
35: "panel.PagesEditSubmit",
|
||||||
36: "panel.PagesDeleteSubmit",
|
36: "panel.PagesDeleteSubmit",
|
||||||
37: "routePanelThemes",
|
37: "panel.Themes",
|
||||||
38: "routePanelThemesSetDefault",
|
38: "routePanelThemesSetDefault",
|
||||||
39: "routePanelThemesMenus",
|
39: "panel.ThemesMenus",
|
||||||
40: "routePanelThemesMenusEdit",
|
40: "panel.ThemesMenusEdit",
|
||||||
41: "routePanelThemesMenuItemEdit",
|
41: "panel.ThemesMenuItemEdit",
|
||||||
42: "routePanelThemesMenuItemEditSubmit",
|
42: "panel.ThemesMenuItemEditSubmit",
|
||||||
43: "routePanelThemesMenuItemCreateSubmit",
|
43: "panel.ThemesMenuItemCreateSubmit",
|
||||||
44: "routePanelThemesMenuItemDeleteSubmit",
|
44: "panel.ThemesMenuItemDeleteSubmit",
|
||||||
45: "routePanelThemesMenuItemOrderSubmit",
|
45: "panel.ThemesMenuItemOrderSubmit",
|
||||||
46: "panel.Plugins",
|
46: "panel.Plugins",
|
||||||
47: "panel.PluginsActivate",
|
47: "panel.PluginsActivate",
|
||||||
48: "panel.PluginsDeactivate",
|
48: "panel.PluginsDeactivate",
|
||||||
|
@ -1175,7 +1175,7 @@ func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, u
|
||||||
err = panel.PagesDeleteSubmit(w,req,user,extraData)
|
err = panel.PagesDeleteSubmit(w,req,user,extraData)
|
||||||
case "/panel/themes/":
|
case "/panel/themes/":
|
||||||
counters.RouteViewCounter.Bump(37)
|
counters.RouteViewCounter.Bump(37)
|
||||||
err = routePanelThemes(w,req,user)
|
err = panel.Themes(w,req,user)
|
||||||
case "/panel/themes/default/":
|
case "/panel/themes/default/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1187,13 +1187,13 @@ func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, u
|
||||||
err = routePanelThemesSetDefault(w,req,user,extraData)
|
err = routePanelThemesSetDefault(w,req,user,extraData)
|
||||||
case "/panel/themes/menus/":
|
case "/panel/themes/menus/":
|
||||||
counters.RouteViewCounter.Bump(39)
|
counters.RouteViewCounter.Bump(39)
|
||||||
err = routePanelThemesMenus(w,req,user)
|
err = panel.ThemesMenus(w,req,user)
|
||||||
case "/panel/themes/menus/edit/":
|
case "/panel/themes/menus/edit/":
|
||||||
counters.RouteViewCounter.Bump(40)
|
counters.RouteViewCounter.Bump(40)
|
||||||
err = routePanelThemesMenusEdit(w,req,user,extraData)
|
err = panel.ThemesMenusEdit(w,req,user,extraData)
|
||||||
case "/panel/themes/menus/item/edit/":
|
case "/panel/themes/menus/item/edit/":
|
||||||
counters.RouteViewCounter.Bump(41)
|
counters.RouteViewCounter.Bump(41)
|
||||||
err = routePanelThemesMenuItemEdit(w,req,user,extraData)
|
err = panel.ThemesMenuItemEdit(w,req,user,extraData)
|
||||||
case "/panel/themes/menus/item/edit/submit/":
|
case "/panel/themes/menus/item/edit/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1202,7 +1202,7 @@ func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, u
|
||||||
}
|
}
|
||||||
|
|
||||||
counters.RouteViewCounter.Bump(42)
|
counters.RouteViewCounter.Bump(42)
|
||||||
err = routePanelThemesMenuItemEditSubmit(w,req,user,extraData)
|
err = panel.ThemesMenuItemEditSubmit(w,req,user,extraData)
|
||||||
case "/panel/themes/menus/item/create/submit/":
|
case "/panel/themes/menus/item/create/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1211,7 +1211,7 @@ func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, u
|
||||||
}
|
}
|
||||||
|
|
||||||
counters.RouteViewCounter.Bump(43)
|
counters.RouteViewCounter.Bump(43)
|
||||||
err = routePanelThemesMenuItemCreateSubmit(w,req,user)
|
err = panel.ThemesMenuItemCreateSubmit(w,req,user)
|
||||||
case "/panel/themes/menus/item/delete/submit/":
|
case "/panel/themes/menus/item/delete/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1220,7 +1220,7 @@ func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, u
|
||||||
}
|
}
|
||||||
|
|
||||||
counters.RouteViewCounter.Bump(44)
|
counters.RouteViewCounter.Bump(44)
|
||||||
err = routePanelThemesMenuItemDeleteSubmit(w,req,user,extraData)
|
err = panel.ThemesMenuItemDeleteSubmit(w,req,user,extraData)
|
||||||
case "/panel/themes/menus/item/order/edit/submit/":
|
case "/panel/themes/menus/item/order/edit/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1229,7 +1229,7 @@ func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, u
|
||||||
}
|
}
|
||||||
|
|
||||||
counters.RouteViewCounter.Bump(45)
|
counters.RouteViewCounter.Bump(45)
|
||||||
err = routePanelThemesMenuItemOrderSubmit(w,req,user,extraData)
|
err = panel.ThemesMenuItemOrderSubmit(w,req,user,extraData)
|
||||||
case "/panel/plugins/":
|
case "/panel/plugins/":
|
||||||
counters.RouteViewCounter.Bump(46)
|
counters.RouteViewCounter.Bump(46)
|
||||||
err = panel.Plugins(w,req,user)
|
err = panel.Plugins(w,req,user)
|
||||||
|
|
301
panel_routes.go
301
panel_routes.go
|
@ -7,7 +7,6 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"./common"
|
"./common"
|
||||||
"github.com/Azareal/gopsutil/mem"
|
"github.com/Azareal/gopsutil/mem"
|
||||||
|
@ -170,33 +169,6 @@ func routePanelDashboard(w http.ResponseWriter, r *http.Request, user common.Use
|
||||||
return panelRenderTemplate("panel_dashboard", w, r, user, &pi)
|
return panelRenderTemplate("panel_dashboard", w, r, user, &pi)
|
||||||
}
|
}
|
||||||
|
|
||||||
func routePanelThemes(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
|
||||||
header, stats, ferr := common.PanelUserCheck(w, r, &user)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
if !user.Perms.ManageThemes {
|
|
||||||
return common.NoPermissions(w, r, user)
|
|
||||||
}
|
|
||||||
header.Title = common.GetTitlePhrase("panel_themes")
|
|
||||||
|
|
||||||
var pThemeList, vThemeList []*common.Theme
|
|
||||||
for _, theme := range common.Themes {
|
|
||||||
if theme.HideFromThemes {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if theme.ForkOf == "" {
|
|
||||||
pThemeList = append(pThemeList, theme)
|
|
||||||
} else {
|
|
||||||
vThemeList = append(vThemeList, theme)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pi := common.PanelThemesPage{&common.BasePanelPage{header, stats, "themes", common.ReportForumID}, pThemeList, vThemeList}
|
|
||||||
return panelRenderTemplate("panel_themes", w, r, user, &pi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func routePanelThemesSetDefault(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError {
|
func routePanelThemesSetDefault(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError {
|
||||||
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
|
@ -261,276 +233,3 @@ func routePanelThemesSetDefault(w http.ResponseWriter, r *http.Request, user com
|
||||||
http.Redirect(w, r, "/panel/themes/", http.StatusSeeOther)
|
http.Redirect(w, r, "/panel/themes/", http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func routePanelThemesMenus(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
|
||||||
header, stats, ferr := common.PanelUserCheck(w, r, &user)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
if !user.Perms.ManageThemes {
|
|
||||||
return common.NoPermissions(w, r, user)
|
|
||||||
}
|
|
||||||
header.Title = common.GetTitlePhrase("panel_themes_menus")
|
|
||||||
|
|
||||||
var menuList []common.PanelMenuListItem
|
|
||||||
for mid, list := range common.Menus.GetAllMap() {
|
|
||||||
var name = ""
|
|
||||||
if mid == 1 {
|
|
||||||
name = common.GetTmplPhrase("panel_themes_menus_main")
|
|
||||||
}
|
|
||||||
menuList = append(menuList, common.PanelMenuListItem{
|
|
||||||
Name: name,
|
|
||||||
ID: mid,
|
|
||||||
ItemCount: len(list.List),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pi := common.PanelMenuListPage{&common.BasePanelPage{header, stats, "themes", common.ReportForumID}, menuList}
|
|
||||||
return panelRenderTemplate("panel_themes_menus", w, r, user, &pi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func routePanelThemesMenusEdit(w http.ResponseWriter, r *http.Request, user common.User, smid string) common.RouteError {
|
|
||||||
header, stats, ferr := common.PanelUserCheck(w, r, &user)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
if !user.Perms.ManageThemes {
|
|
||||||
return common.NoPermissions(w, r, user)
|
|
||||||
}
|
|
||||||
// TODO: Something like Menu #1 for the title?
|
|
||||||
header.Title = common.GetTitlePhrase("panel_themes_menus_edit")
|
|
||||||
header.AddScript("Sortable-1.4.0/Sortable.min.js")
|
|
||||||
|
|
||||||
mid, err := strconv.Atoi(smid)
|
|
||||||
if err != nil {
|
|
||||||
return common.LocalError("Invalid integer", w, r, user)
|
|
||||||
}
|
|
||||||
|
|
||||||
menuHold, err := common.Menus.Get(mid)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.NotFound(w, r, header)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
var menuList []common.MenuItem
|
|
||||||
for _, item := range menuHold.List {
|
|
||||||
var menuTmpls = map[string]common.MenuTmpl{
|
|
||||||
item.TmplName: menuHold.Parse(item.Name, []byte("{{.Name}}")),
|
|
||||||
}
|
|
||||||
var renderBuffer [][]byte
|
|
||||||
var variableIndices []int
|
|
||||||
renderBuffer, _ = menuHold.ScanItem(menuTmpls, item, renderBuffer, variableIndices)
|
|
||||||
|
|
||||||
var out string
|
|
||||||
for _, renderItem := range renderBuffer {
|
|
||||||
out += string(renderItem)
|
|
||||||
}
|
|
||||||
item.Name = out
|
|
||||||
if item.Name == "" {
|
|
||||||
item.Name = "???"
|
|
||||||
}
|
|
||||||
menuList = append(menuList, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
pi := common.PanelMenuPage{&common.BasePanelPage{header, stats, "themes", common.ReportForumID}, mid, menuList}
|
|
||||||
return panelRenderTemplate("panel_themes_menus_items", w, r, user, &pi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func routePanelThemesMenuItemEdit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError {
|
|
||||||
header, stats, ferr := common.PanelUserCheck(w, r, &user)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
if !user.Perms.ManageThemes {
|
|
||||||
return common.NoPermissions(w, r, user)
|
|
||||||
}
|
|
||||||
// TODO: Something like Menu #1 for the title?
|
|
||||||
header.Title = common.GetTitlePhrase("panel_themes_menus_edit")
|
|
||||||
|
|
||||||
itemID, err := strconv.Atoi(sitemID)
|
|
||||||
if err != nil {
|
|
||||||
return common.LocalError("Invalid integer", w, r, user)
|
|
||||||
}
|
|
||||||
|
|
||||||
menuItem, err := common.Menus.ItemStore().Get(itemID)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.NotFound(w, r, header)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
pi := common.PanelMenuItemPage{&common.BasePanelPage{header, stats, "themes", common.ReportForumID}, menuItem}
|
|
||||||
return panelRenderTemplate("panel_themes_menus_item_edit", w, r, user, &pi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func routePanelThemesMenuItemSetters(r *http.Request, menuItem common.MenuItem) common.MenuItem {
|
|
||||||
var getItem = func(name string) string {
|
|
||||||
return common.SanitiseSingleLine(r.PostFormValue("item-" + name))
|
|
||||||
}
|
|
||||||
menuItem.Name = getItem("name")
|
|
||||||
menuItem.HTMLID = getItem("htmlid")
|
|
||||||
menuItem.CSSClass = getItem("cssclass")
|
|
||||||
menuItem.Position = getItem("position")
|
|
||||||
if menuItem.Position != "left" && menuItem.Position != "right" {
|
|
||||||
menuItem.Position = "left"
|
|
||||||
}
|
|
||||||
menuItem.Path = getItem("path")
|
|
||||||
menuItem.Aria = getItem("aria")
|
|
||||||
menuItem.Tooltip = getItem("tooltip")
|
|
||||||
menuItem.TmplName = getItem("tmplname")
|
|
||||||
|
|
||||||
switch getItem("permissions") {
|
|
||||||
case "everyone":
|
|
||||||
menuItem.GuestOnly = false
|
|
||||||
menuItem.MemberOnly = false
|
|
||||||
menuItem.SuperModOnly = false
|
|
||||||
menuItem.AdminOnly = false
|
|
||||||
case "guest-only":
|
|
||||||
menuItem.GuestOnly = true
|
|
||||||
menuItem.MemberOnly = false
|
|
||||||
menuItem.SuperModOnly = false
|
|
||||||
menuItem.AdminOnly = false
|
|
||||||
case "member-only":
|
|
||||||
menuItem.GuestOnly = false
|
|
||||||
menuItem.MemberOnly = true
|
|
||||||
menuItem.SuperModOnly = false
|
|
||||||
menuItem.AdminOnly = false
|
|
||||||
case "supermod-only":
|
|
||||||
menuItem.GuestOnly = false
|
|
||||||
menuItem.MemberOnly = true
|
|
||||||
menuItem.SuperModOnly = true
|
|
||||||
menuItem.AdminOnly = false
|
|
||||||
case "admin-only":
|
|
||||||
menuItem.GuestOnly = false
|
|
||||||
menuItem.MemberOnly = true
|
|
||||||
menuItem.SuperModOnly = true
|
|
||||||
menuItem.AdminOnly = true
|
|
||||||
}
|
|
||||||
return menuItem
|
|
||||||
}
|
|
||||||
|
|
||||||
func routePanelThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError {
|
|
||||||
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
isJs := (r.PostFormValue("js") == "1")
|
|
||||||
if !user.Perms.ManageThemes {
|
|
||||||
return common.NoPermissionsJSQ(w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
itemID, err := strconv.Atoi(sitemID)
|
|
||||||
if err != nil {
|
|
||||||
return common.LocalErrorJSQ("Invalid integer", w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
menuItem, err := common.Menus.ItemStore().Get(itemID)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.LocalErrorJSQ("This item doesn't exist.", w, r, user, isJs)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
//menuItem = menuItem.Copy() // If we switch this for a pointer, we might need this as a scratchpad
|
|
||||||
menuItem = routePanelThemesMenuItemSetters(r, menuItem)
|
|
||||||
|
|
||||||
err = menuItem.Commit()
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
return panelSuccessRedirect("/panel/themes/menus/item/edit/"+strconv.Itoa(itemID), w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func routePanelThemesMenuItemCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
|
||||||
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
|
|
||||||
isJs := (r.PostFormValue("js") == "1")
|
|
||||||
if !user.Perms.ManageThemes {
|
|
||||||
return common.NoPermissionsJSQ(w, r, user, isJs)
|
|
||||||
}
|
|
||||||
smenuID := r.PostFormValue("mid")
|
|
||||||
if smenuID == "" {
|
|
||||||
return common.LocalErrorJSQ("No menuID provided", w, r, user, isJs)
|
|
||||||
}
|
|
||||||
menuID, err := strconv.Atoi(smenuID)
|
|
||||||
if err != nil {
|
|
||||||
return common.LocalErrorJSQ("Invalid integer", w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
menuItem := common.MenuItem{MenuID: menuID}
|
|
||||||
menuItem = routePanelThemesMenuItemSetters(r, menuItem)
|
|
||||||
itemID, err := menuItem.Create()
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
return panelSuccessRedirect("/panel/themes/menus/item/edit/"+strconv.Itoa(itemID), w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func routePanelThemesMenuItemDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError {
|
|
||||||
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
isJs := (r.PostFormValue("js") == "1")
|
|
||||||
if !user.Perms.ManageThemes {
|
|
||||||
return common.NoPermissionsJSQ(w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
itemID, err := strconv.Atoi(sitemID)
|
|
||||||
if err != nil {
|
|
||||||
return common.LocalErrorJSQ("Invalid integer", w, r, user, isJs)
|
|
||||||
}
|
|
||||||
menuItem, err := common.Menus.ItemStore().Get(itemID)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.LocalErrorJSQ("This item doesn't exist.", w, r, user, isJs)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
//menuItem = menuItem.Copy() // If we switch this for a pointer, we might need this as a scratchpad
|
|
||||||
|
|
||||||
err = menuItem.Delete()
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
return panelSuccessRedirect("/panel/themes/menus/", w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func routePanelThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, user common.User, smid string) common.RouteError {
|
|
||||||
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
isJs := (r.PostFormValue("js") == "1")
|
|
||||||
if !user.Perms.ManageThemes {
|
|
||||||
return common.NoPermissionsJSQ(w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
mid, err := strconv.Atoi(smid)
|
|
||||||
if err != nil {
|
|
||||||
return common.LocalErrorJSQ("Invalid integer", w, r, user, isJs)
|
|
||||||
}
|
|
||||||
menuHold, err := common.Menus.Get(mid)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.LocalErrorJSQ("Can't find menu", w, r, user, isJs)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
sitems := strings.TrimSuffix(strings.TrimPrefix(r.PostFormValue("items"), "{"), "}")
|
|
||||||
fmt.Printf("sitems: %+v\n", sitems)
|
|
||||||
|
|
||||||
var updateMap = make(map[int]int)
|
|
||||||
for index, smiid := range strings.Split(sitems, ",") {
|
|
||||||
miid, err := strconv.Atoi(smiid)
|
|
||||||
if err != nil {
|
|
||||||
return common.LocalErrorJSQ("Invalid integer in menu item list", w, r, user, isJs)
|
|
||||||
}
|
|
||||||
updateMap[miid] = index
|
|
||||||
}
|
|
||||||
menuHold.UpdateOrder(updateMap)
|
|
||||||
|
|
||||||
return panelSuccessRedirect("/panel/themes/menus/edit/"+strconv.Itoa(mid), w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
|
@ -169,15 +169,15 @@ func buildPanelRoutes() {
|
||||||
Action("panel.PagesEditSubmit", "/panel/pages/edit/submit/", "extraData").Before("AdminOnly"),
|
Action("panel.PagesEditSubmit", "/panel/pages/edit/submit/", "extraData").Before("AdminOnly"),
|
||||||
Action("panel.PagesDeleteSubmit", "/panel/pages/delete/submit/", "extraData").Before("AdminOnly"),
|
Action("panel.PagesDeleteSubmit", "/panel/pages/delete/submit/", "extraData").Before("AdminOnly"),
|
||||||
|
|
||||||
View("routePanelThemes", "/panel/themes/"),
|
View("panel.Themes", "/panel/themes/"),
|
||||||
Action("routePanelThemesSetDefault", "/panel/themes/default/", "extraData"),
|
Action("routePanelThemesSetDefault", "/panel/themes/default/", "extraData"),
|
||||||
View("routePanelThemesMenus", "/panel/themes/menus/"),
|
View("panel.ThemesMenus", "/panel/themes/menus/"),
|
||||||
View("routePanelThemesMenusEdit", "/panel/themes/menus/edit/", "extraData"),
|
View("panel.ThemesMenusEdit", "/panel/themes/menus/edit/", "extraData"),
|
||||||
View("routePanelThemesMenuItemEdit", "/panel/themes/menus/item/edit/", "extraData"),
|
View("panel.ThemesMenuItemEdit", "/panel/themes/menus/item/edit/", "extraData"),
|
||||||
Action("routePanelThemesMenuItemEditSubmit", "/panel/themes/menus/item/edit/submit/", "extraData"),
|
Action("panel.ThemesMenuItemEditSubmit", "/panel/themes/menus/item/edit/submit/", "extraData"),
|
||||||
Action("routePanelThemesMenuItemCreateSubmit", "/panel/themes/menus/item/create/submit/"),
|
Action("panel.ThemesMenuItemCreateSubmit", "/panel/themes/menus/item/create/submit/"),
|
||||||
Action("routePanelThemesMenuItemDeleteSubmit", "/panel/themes/menus/item/delete/submit/", "extraData"),
|
Action("panel.ThemesMenuItemDeleteSubmit", "/panel/themes/menus/item/delete/submit/", "extraData"),
|
||||||
Action("routePanelThemesMenuItemOrderSubmit", "/panel/themes/menus/item/order/edit/submit/", "extraData"),
|
Action("panel.ThemesMenuItemOrderSubmit", "/panel/themes/menus/item/order/edit/submit/", "extraData"),
|
||||||
|
|
||||||
View("panel.Plugins", "/panel/plugins/"),
|
View("panel.Plugins", "/panel/plugins/"),
|
||||||
Action("panel.PluginsActivate", "/panel/plugins/activate/", "extraData"),
|
Action("panel.PluginsActivate", "/panel/plugins/activate/", "extraData"),
|
||||||
|
|
|
@ -0,0 +1,313 @@
|
||||||
|
package panel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"../../common"
|
||||||
|
)
|
||||||
|
|
||||||
|
//routePanelThemes
|
||||||
|
func Themes(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||||
|
basePage, ferr := buildBasePage(w, r, &user, "themes", "themes")
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
if !user.Perms.ManageThemes {
|
||||||
|
return common.NoPermissions(w, r, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
var pThemeList, vThemeList []*common.Theme
|
||||||
|
for _, theme := range common.Themes {
|
||||||
|
if theme.HideFromThemes {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if theme.ForkOf == "" {
|
||||||
|
pThemeList = append(pThemeList, theme)
|
||||||
|
} else {
|
||||||
|
vThemeList = append(vThemeList, theme)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pi := common.PanelThemesPage{basePage, pThemeList, vThemeList}
|
||||||
|
return panelRenderTemplate("panel_themes", w, r, user, &pi)
|
||||||
|
}
|
||||||
|
|
||||||
|
//routePanelThemesMenus
|
||||||
|
func ThemesMenus(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||||
|
basePage, ferr := buildBasePage(w, r, &user, "themes_menus", "themes")
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
if !user.Perms.ManageThemes {
|
||||||
|
return common.NoPermissions(w, r, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
var menuList []common.PanelMenuListItem
|
||||||
|
for mid, list := range common.Menus.GetAllMap() {
|
||||||
|
var name = ""
|
||||||
|
if mid == 1 {
|
||||||
|
name = common.GetTmplPhrase("panel_themes_menus_main")
|
||||||
|
}
|
||||||
|
menuList = append(menuList, common.PanelMenuListItem{
|
||||||
|
Name: name,
|
||||||
|
ID: mid,
|
||||||
|
ItemCount: len(list.List),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pi := common.PanelMenuListPage{basePage, menuList}
|
||||||
|
return panelRenderTemplate("panel_themes_menus", w, r, user, &pi)
|
||||||
|
}
|
||||||
|
|
||||||
|
//routePanelThemesMenusEdit
|
||||||
|
func ThemesMenusEdit(w http.ResponseWriter, r *http.Request, user common.User, smid string) common.RouteError {
|
||||||
|
// TODO: Something like Menu #1 for the title?
|
||||||
|
basePage, ferr := buildBasePage(w, r, &user, "themes_menus_edit", "themes")
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
if !user.Perms.ManageThemes {
|
||||||
|
return common.NoPermissions(w, r, user)
|
||||||
|
}
|
||||||
|
basePage.Header.AddScript("Sortable-1.4.0/Sortable.min.js")
|
||||||
|
|
||||||
|
mid, err := strconv.Atoi(smid)
|
||||||
|
if err != nil {
|
||||||
|
return common.LocalError(common.GetErrorPhrase("url_id_must_be_integer"), w, r, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
menuHold, err := common.Menus.Get(mid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.NotFound(w, r, basePage.Header)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
var menuList []common.MenuItem
|
||||||
|
for _, item := range menuHold.List {
|
||||||
|
var menuTmpls = map[string]common.MenuTmpl{
|
||||||
|
item.TmplName: menuHold.Parse(item.Name, []byte("{{.Name}}")),
|
||||||
|
}
|
||||||
|
var renderBuffer [][]byte
|
||||||
|
var variableIndices []int
|
||||||
|
renderBuffer, _ = menuHold.ScanItem(menuTmpls, item, renderBuffer, variableIndices)
|
||||||
|
|
||||||
|
var out string
|
||||||
|
for _, renderItem := range renderBuffer {
|
||||||
|
out += string(renderItem)
|
||||||
|
}
|
||||||
|
item.Name = out
|
||||||
|
if item.Name == "" {
|
||||||
|
item.Name = "???"
|
||||||
|
}
|
||||||
|
menuList = append(menuList, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
pi := common.PanelMenuPage{basePage, mid, menuList}
|
||||||
|
return panelRenderTemplate("panel_themes_menus_items", w, r, user, &pi)
|
||||||
|
}
|
||||||
|
|
||||||
|
//routePanelThemesMenuItemEdit
|
||||||
|
func ThemesMenuItemEdit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError {
|
||||||
|
// TODO: Something like Menu #1 for the title?
|
||||||
|
basePage, ferr := buildBasePage(w, r, &user, "themes_menus_edit", "themes")
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
if !user.Perms.ManageThemes {
|
||||||
|
return common.NoPermissions(w, r, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
itemID, err := strconv.Atoi(sitemID)
|
||||||
|
if err != nil {
|
||||||
|
return common.LocalError(common.GetErrorPhrase("url_id_must_be_integer"), w, r, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItem, err := common.Menus.ItemStore().Get(itemID)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.NotFound(w, r, basePage.Header)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
pi := common.PanelMenuItemPage{basePage, menuItem}
|
||||||
|
return panelRenderTemplate("panel_themes_menus_item_edit", w, r, user, &pi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func themesMenuItemSetters(r *http.Request, menuItem common.MenuItem) common.MenuItem {
|
||||||
|
var getItem = func(name string) string {
|
||||||
|
return common.SanitiseSingleLine(r.PostFormValue("item-" + name))
|
||||||
|
}
|
||||||
|
menuItem.Name = getItem("name")
|
||||||
|
menuItem.HTMLID = getItem("htmlid")
|
||||||
|
menuItem.CSSClass = getItem("cssclass")
|
||||||
|
menuItem.Position = getItem("position")
|
||||||
|
if menuItem.Position != "left" && menuItem.Position != "right" {
|
||||||
|
menuItem.Position = "left"
|
||||||
|
}
|
||||||
|
menuItem.Path = getItem("path")
|
||||||
|
menuItem.Aria = getItem("aria")
|
||||||
|
menuItem.Tooltip = getItem("tooltip")
|
||||||
|
menuItem.TmplName = getItem("tmplname")
|
||||||
|
|
||||||
|
switch getItem("permissions") {
|
||||||
|
case "everyone":
|
||||||
|
menuItem.GuestOnly = false
|
||||||
|
menuItem.MemberOnly = false
|
||||||
|
menuItem.SuperModOnly = false
|
||||||
|
menuItem.AdminOnly = false
|
||||||
|
case "guest-only":
|
||||||
|
menuItem.GuestOnly = true
|
||||||
|
menuItem.MemberOnly = false
|
||||||
|
menuItem.SuperModOnly = false
|
||||||
|
menuItem.AdminOnly = false
|
||||||
|
case "member-only":
|
||||||
|
menuItem.GuestOnly = false
|
||||||
|
menuItem.MemberOnly = true
|
||||||
|
menuItem.SuperModOnly = false
|
||||||
|
menuItem.AdminOnly = false
|
||||||
|
case "supermod-only":
|
||||||
|
menuItem.GuestOnly = false
|
||||||
|
menuItem.MemberOnly = true
|
||||||
|
menuItem.SuperModOnly = true
|
||||||
|
menuItem.AdminOnly = false
|
||||||
|
case "admin-only":
|
||||||
|
menuItem.GuestOnly = false
|
||||||
|
menuItem.MemberOnly = true
|
||||||
|
menuItem.SuperModOnly = true
|
||||||
|
menuItem.AdminOnly = true
|
||||||
|
}
|
||||||
|
return menuItem
|
||||||
|
}
|
||||||
|
|
||||||
|
//routePanelThemesMenuItemEditSubmit
|
||||||
|
func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError {
|
||||||
|
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
isJs := (r.PostFormValue("js") == "1")
|
||||||
|
if !user.Perms.ManageThemes {
|
||||||
|
return common.NoPermissionsJSQ(w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
itemID, err := strconv.Atoi(sitemID)
|
||||||
|
if err != nil {
|
||||||
|
return common.LocalErrorJSQ(common.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItem, err := common.Menus.ItemStore().Get(itemID)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.LocalErrorJSQ("This item doesn't exist.", w, r, user, isJs)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
//menuItem = menuItem.Copy() // If we switch this for a pointer, we might need this as a scratchpad
|
||||||
|
menuItem = themesMenuItemSetters(r, menuItem)
|
||||||
|
|
||||||
|
err = menuItem.Commit()
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
return panelSuccessRedirect("/panel/themes/menus/item/edit/"+strconv.Itoa(itemID), w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
//routePanelThemesMenuItemCreateSubmit
|
||||||
|
func ThemesMenuItemCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||||
|
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
|
||||||
|
isJs := (r.PostFormValue("js") == "1")
|
||||||
|
if !user.Perms.ManageThemes {
|
||||||
|
return common.NoPermissionsJSQ(w, r, user, isJs)
|
||||||
|
}
|
||||||
|
smenuID := r.PostFormValue("mid")
|
||||||
|
if smenuID == "" {
|
||||||
|
return common.LocalErrorJSQ("No menuID provided", w, r, user, isJs)
|
||||||
|
}
|
||||||
|
menuID, err := strconv.Atoi(smenuID)
|
||||||
|
if err != nil {
|
||||||
|
return common.LocalErrorJSQ(common.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItem := common.MenuItem{MenuID: menuID}
|
||||||
|
menuItem = themesMenuItemSetters(r, menuItem)
|
||||||
|
itemID, err := menuItem.Create()
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
return panelSuccessRedirect("/panel/themes/menus/item/edit/"+strconv.Itoa(itemID), w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
//routePanelThemesMenuItemDeleteSubmit
|
||||||
|
func ThemesMenuItemDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, sitemID string) common.RouteError {
|
||||||
|
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
isJs := (r.PostFormValue("js") == "1")
|
||||||
|
if !user.Perms.ManageThemes {
|
||||||
|
return common.NoPermissionsJSQ(w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
itemID, err := strconv.Atoi(sitemID)
|
||||||
|
if err != nil {
|
||||||
|
return common.LocalErrorJSQ(common.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs)
|
||||||
|
}
|
||||||
|
menuItem, err := common.Menus.ItemStore().Get(itemID)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.LocalErrorJSQ("This item doesn't exist.", w, r, user, isJs)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
//menuItem = menuItem.Copy() // If we switch this for a pointer, we might need this as a scratchpad
|
||||||
|
|
||||||
|
err = menuItem.Delete()
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
return panelSuccessRedirect("/panel/themes/menus/", w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
//routePanelThemesMenuItemOrderSubmit
|
||||||
|
func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, user common.User, smid string) common.RouteError {
|
||||||
|
_, ferr := common.SimplePanelUserCheck(w, r, &user)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
isJs := (r.PostFormValue("js") == "1")
|
||||||
|
if !user.Perms.ManageThemes {
|
||||||
|
return common.NoPermissionsJSQ(w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
mid, err := strconv.Atoi(smid)
|
||||||
|
if err != nil {
|
||||||
|
return common.LocalErrorJSQ(common.GetErrorPhrase("id_must_be_integer"), w, r, user, isJs)
|
||||||
|
}
|
||||||
|
menuHold, err := common.Menus.Get(mid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.LocalErrorJSQ("Can't find menu", w, r, user, isJs)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
sitems := strings.TrimSuffix(strings.TrimPrefix(r.PostFormValue("items"), "{"), "}")
|
||||||
|
//fmt.Printf("sitems: %+v\n", sitems)
|
||||||
|
|
||||||
|
var updateMap = make(map[int]int)
|
||||||
|
for index, smiid := range strings.Split(sitems, ",") {
|
||||||
|
miid, err := strconv.Atoi(smiid)
|
||||||
|
if err != nil {
|
||||||
|
return common.LocalErrorJSQ("Invalid integer in menu item list", w, r, user, isJs)
|
||||||
|
}
|
||||||
|
updateMap[miid] = index
|
||||||
|
}
|
||||||
|
menuHold.UpdateOrder(updateMap)
|
||||||
|
|
||||||
|
return panelSuccessRedirect("/panel/themes/menus/edit/"+strconv.Itoa(mid), w, r, isJs)
|
||||||
|
}
|
Loading…
Reference in New Issue