github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/routes/panel/themes.go (about)

     1  package panel
     2  
     3  import (
     4  	"database/sql"
     5  	"encoding/json"
     6  	"errors"
     7  	"net/http"
     8  	"strconv"
     9  	"strings"
    10  
    11  	c "github.com/Azareal/Gosora/common"
    12  	p "github.com/Azareal/Gosora/common/phrases"
    13  )
    14  
    15  func Themes(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
    16  	basePage, ferr := buildBasePage(w, r, u, "themes", "themes")
    17  	if ferr != nil {
    18  		return ferr
    19  	}
    20  	if !u.Perms.ManageThemes {
    21  		return c.NoPermissions(w, r, u)
    22  	}
    23  
    24  	var pThemeList, vThemeList []*c.Theme
    25  	for _, theme := range c.Themes {
    26  		if theme.HideFromThemes {
    27  			continue
    28  		}
    29  		if theme.ForkOf == "" {
    30  			pThemeList = append(pThemeList, theme)
    31  		} else {
    32  			vThemeList = append(vThemeList, theme)
    33  		}
    34  	}
    35  
    36  	pi := c.PanelThemesPage{basePage, pThemeList, vThemeList}
    37  	return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_themes", "", "panel_themes", &pi})
    38  }
    39  
    40  func ThemesSetDefault(w http.ResponseWriter, r *http.Request, u *c.User, uname string) c.RouteError {
    41  	_, ferr := c.SimplePanelUserCheck(w, r, u)
    42  	if ferr != nil {
    43  		return ferr
    44  	}
    45  	if !u.Perms.ManageThemes {
    46  		return c.NoPermissions(w, r, u)
    47  	}
    48  
    49  	theme, ok := c.Themes[uname]
    50  	if !ok {
    51  		return c.LocalError("The theme isn't registered in the system", w, r, u)
    52  	}
    53  	if theme.Disabled {
    54  		return c.LocalError("You must not enable this theme", w, r, u)
    55  	}
    56  
    57  	err := c.UpdateDefaultTheme(theme)
    58  	if err != nil {
    59  		return c.InternalError(err, w, r)
    60  	}
    61  	err = c.AdminLogs.CreateExtra("set_default", 0, "theme", u.GetIP(), u.ID, c.SanitiseSingleLine(theme.Name))
    62  	if err != nil {
    63  		return c.InternalError(err, w, r)
    64  	}
    65  
    66  	http.Redirect(w, r, "/panel/themes/", http.StatusSeeOther)
    67  	return nil
    68  }
    69  
    70  func ThemesMenus(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
    71  	basePage, ferr := buildBasePage(w, r, u, "themes_menus", "themes")
    72  	if ferr != nil {
    73  		return ferr
    74  	}
    75  	if !u.Perms.ManageThemes {
    76  		return c.NoPermissions(w, r, u)
    77  	}
    78  
    79  	var menuList []c.PanelMenuListItem
    80  	for mid, list := range c.Menus.GetAllMap() {
    81  		name := ""
    82  		if mid == 1 {
    83  			name = p.GetTmplPhrase("panel_themes_menus_main")
    84  		}
    85  		menuList = append(menuList, c.PanelMenuListItem{
    86  			Name:      name,
    87  			ID:        mid,
    88  			ItemCount: len(list.List),
    89  		})
    90  	}
    91  
    92  	return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_themes_menus", &c.PanelMenuListPage{basePage, menuList}})
    93  }
    94  
    95  func ThemesMenusEdit(w http.ResponseWriter, r *http.Request, u *c.User, smid string) c.RouteError {
    96  	// TODO: Something like Menu #1 for the title?
    97  	basePage, ferr := buildBasePage(w, r, u, "themes_menus_edit", "themes")
    98  	if ferr != nil {
    99  		return ferr
   100  	}
   101  	if !u.Perms.ManageThemes {
   102  		return c.NoPermissions(w, r, u)
   103  	}
   104  	basePage.Header.AddScript("Sortable-1.4.0/Sortable.min.js")
   105  	basePage.Header.AddScriptAsync("panel_menu_items.js")
   106  
   107  	mid, err := strconv.Atoi(smid)
   108  	if err != nil {
   109  		return c.LocalError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, u)
   110  	}
   111  	menuHold, err := c.Menus.Get(mid)
   112  	if err == sql.ErrNoRows {
   113  		return c.NotFound(w, r, basePage.Header)
   114  	} else if err != nil {
   115  		return c.InternalError(err, w, r)
   116  	}
   117  
   118  	var menuList []c.MenuItem
   119  	for _, item := range menuHold.List {
   120  		menuTmpls := map[string]c.MenuTmpl{
   121  			item.TmplName: menuHold.Parse(item.Name, []byte("{{.Name}}")),
   122  		}
   123  		var renderBuffer [][]byte
   124  		var variableIndices []int
   125  		renderBuffer, _ = menuHold.ScanItem(menuTmpls, item, renderBuffer, variableIndices)
   126  
   127  		var out string
   128  		for _, renderItem := range renderBuffer {
   129  			out += string(renderItem)
   130  		}
   131  		item.Name = out
   132  		if item.Name == "" {
   133  			item.Name = "???"
   134  		}
   135  		menuList = append(menuList, item)
   136  	}
   137  
   138  	return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_themes_menus_items", &c.PanelMenuPage{basePage, mid, menuList}})
   139  }
   140  
   141  func ThemesMenuItemEdit(w http.ResponseWriter, r *http.Request, u *c.User, sitemID string) c.RouteError {
   142  	// TODO: Something like Menu #1 for the title?
   143  	basePage, ferr := buildBasePage(w, r, u, "themes_menus_edit", "themes")
   144  	if ferr != nil {
   145  		return ferr
   146  	}
   147  	if !u.Perms.ManageThemes {
   148  		return c.NoPermissions(w, r, u)
   149  	}
   150  
   151  	itemID, err := strconv.Atoi(sitemID)
   152  	if err != nil {
   153  		return c.LocalError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, u)
   154  	}
   155  	menuItem, err := c.Menus.ItemStore().Get(itemID)
   156  	if err == sql.ErrNoRows {
   157  		return c.NotFound(w, r, basePage.Header)
   158  	} else if err != nil {
   159  		return c.InternalError(err, w, r)
   160  	}
   161  
   162  	return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_themes_menus_item_edit", &c.PanelMenuItemPage{basePage, menuItem}})
   163  }
   164  
   165  func themesMenuItemSetters(r *http.Request, i c.MenuItem) c.MenuItem {
   166  	getItem := func(name string) string {
   167  		return c.SanitiseSingleLine(r.PostFormValue("item-" + name))
   168  	}
   169  	i.Name = getItem("name")
   170  	i.HTMLID = getItem("htmlid")
   171  	i.CSSClass = getItem("cssclass")
   172  	i.Position = getItem("position")
   173  	if i.Position != "left" && i.Position != "right" {
   174  		i.Position = "left"
   175  	}
   176  	i.Path = getItem("path")
   177  	i.Aria = getItem("aria")
   178  	i.Tooltip = getItem("tooltip")
   179  	i.TmplName = getItem("tmplname")
   180  	i.GuestOnly = false
   181  
   182  	switch getItem("permissions") {
   183  	case "everyone":
   184  		i.MemberOnly = false
   185  		i.SuperModOnly = false
   186  		i.AdminOnly = false
   187  	case "guest-only":
   188  		i.GuestOnly = true
   189  		i.MemberOnly = false
   190  		i.SuperModOnly = false
   191  		i.AdminOnly = false
   192  	case "member-only":
   193  		i.MemberOnly = true
   194  		i.SuperModOnly = false
   195  		i.AdminOnly = false
   196  	case "supermod-only":
   197  		i.MemberOnly = true
   198  		i.SuperModOnly = true
   199  		i.AdminOnly = false
   200  	case "admin-only":
   201  		i.MemberOnly = true
   202  		i.SuperModOnly = true
   203  		i.AdminOnly = true
   204  	}
   205  	return i
   206  }
   207  
   208  func ThemesMenuItemEditSubmit(w http.ResponseWriter, r *http.Request, u *c.User, sitemID string) c.RouteError {
   209  	_, ferr := c.SimplePanelUserCheck(w, r, u)
   210  	if ferr != nil {
   211  		return ferr
   212  	}
   213  	js := r.PostFormValue("js") == "1"
   214  	if !u.Perms.ManageThemes {
   215  		return c.NoPermissionsJSQ(w, r, u, js)
   216  	}
   217  
   218  	itemID, err := strconv.Atoi(sitemID)
   219  	if err != nil {
   220  		return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, u, js)
   221  	}
   222  	menuItem, err := c.Menus.ItemStore().Get(itemID)
   223  	if err == sql.ErrNoRows {
   224  		return c.LocalErrorJSQ("This item doesn't exist.", w, r, u, js)
   225  	} else if err != nil {
   226  		return c.InternalErrorJSQ(err, w, r, js)
   227  	}
   228  	//menuItem = menuItem.Copy() // If we switch this for a pointer, we might need this as a scratchpad
   229  	menuItem = themesMenuItemSetters(r, menuItem)
   230  
   231  	err = menuItem.Commit()
   232  	if err != nil {
   233  		return c.InternalErrorJSQ(err, w, r, js)
   234  	}
   235  	err = c.AdminLogs.Create("edit", menuItem.ID, "menu_item", u.GetIP(), u.ID)
   236  	if err != nil {
   237  		return c.InternalError(err, w, r)
   238  	}
   239  
   240  	return successRedirect("/panel/themes/menus/item/edit/"+strconv.Itoa(itemID), w, r, js)
   241  }
   242  
   243  func ThemesMenuItemCreateSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
   244  	_, ferr := c.SimplePanelUserCheck(w, r, u)
   245  	if ferr != nil {
   246  		return ferr
   247  	}
   248  	js := r.PostFormValue("js") == "1"
   249  	if !u.Perms.ManageThemes {
   250  		return c.NoPermissionsJSQ(w, r, u, js)
   251  	}
   252  
   253  	smenuID := r.PostFormValue("mid")
   254  	if smenuID == "" {
   255  		return c.LocalErrorJSQ("No menuID provided", w, r, u, js)
   256  	}
   257  	menuID, err := strconv.Atoi(smenuID)
   258  	if err != nil {
   259  		return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, u, js)
   260  	}
   261  
   262  	menuItem := c.MenuItem{MenuID: menuID}
   263  	menuItem = themesMenuItemSetters(r, menuItem)
   264  	itemID, err := menuItem.Create()
   265  	if err != nil {
   266  		return c.InternalErrorJSQ(err, w, r, js)
   267  	}
   268  	err = c.AdminLogs.Create("create", itemID, "menu_item", u.GetIP(), u.ID)
   269  	if err != nil {
   270  		return c.InternalError(err, w, r)
   271  	}
   272  
   273  	return successRedirect("/panel/themes/menus/item/edit/"+strconv.Itoa(itemID), w, r, js)
   274  }
   275  
   276  func ThemesMenuItemDeleteSubmit(w http.ResponseWriter, r *http.Request, u *c.User, sitemID string) c.RouteError {
   277  	_, ferr := c.SimplePanelUserCheck(w, r, u)
   278  	if ferr != nil {
   279  		return ferr
   280  	}
   281  	js := r.PostFormValue("js") == "1"
   282  	if !u.Perms.ManageThemes {
   283  		return c.NoPermissionsJSQ(w, r, u, js)
   284  	}
   285  
   286  	itemID, err := strconv.Atoi(sitemID)
   287  	if err != nil {
   288  		return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, u, js)
   289  	}
   290  	menuItem, err := c.Menus.ItemStore().Get(itemID)
   291  	if err == sql.ErrNoRows {
   292  		return c.LocalErrorJSQ("This item doesn't exist.", w, r, u, js)
   293  	} else if err != nil {
   294  		return c.InternalErrorJSQ(err, w, r, js)
   295  	}
   296  	//menuItem = menuItem.Copy() // If we switch this for a pointer, we might need this as a scratchpad
   297  
   298  	err = menuItem.Delete()
   299  	if err != nil {
   300  		return c.InternalErrorJSQ(err, w, r, js)
   301  	}
   302  	err = c.AdminLogs.Create("delete", menuItem.ID, "menu_item", u.GetIP(), u.ID)
   303  	if err != nil {
   304  		return c.InternalError(err, w, r)
   305  	}
   306  
   307  	return successRedirect("/panel/themes/menus/", w, r, js)
   308  }
   309  
   310  func ThemesMenuItemOrderSubmit(w http.ResponseWriter, r *http.Request, u *c.User, smid string) c.RouteError {
   311  	_, ferr := c.SimplePanelUserCheck(w, r, u)
   312  	if ferr != nil {
   313  		return ferr
   314  	}
   315  	js := r.PostFormValue("js") == "1"
   316  	if !u.Perms.ManageThemes {
   317  		return c.NoPermissionsJSQ(w, r, u, js)
   318  	}
   319  
   320  	mid, err := strconv.Atoi(smid)
   321  	if err != nil {
   322  		return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, u, js)
   323  	}
   324  	menuHold, err := c.Menus.Get(mid)
   325  	if err == sql.ErrNoRows {
   326  		return c.LocalErrorJSQ("Can't find menu", w, r, u, js)
   327  	} else if err != nil {
   328  		return c.InternalErrorJSQ(err, w, r, js)
   329  	}
   330  
   331  	sitems := strings.TrimSuffix(strings.TrimPrefix(r.PostFormValue("items"), "{"), "}")
   332  	//fmt.Printf("sitems: %+v\n", sitems)
   333  
   334  	updateMap := make(map[int]int)
   335  	for index, smiid := range strings.Split(sitems, ",") {
   336  		miid, err := strconv.Atoi(smiid)
   337  		if err != nil {
   338  			return c.LocalErrorJSQ("Invalid integer in menu item list", w, r, u, js)
   339  		}
   340  		updateMap[miid] = index
   341  	}
   342  	menuHold.UpdateOrder(updateMap)
   343  
   344  	err = c.AdminLogs.Create("suborder", menuHold.MenuID, "menu", u.GetIP(), u.ID)
   345  	if err != nil {
   346  		return c.InternalError(err, w, r)
   347  	}
   348  
   349  	return successRedirect("/panel/themes/menus/edit/"+strconv.Itoa(mid), w, r, js)
   350  }
   351  
   352  func ThemesWidgets(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
   353  	basePage, ferr := buildBasePage(w, r, u, "themes_widgets", "themes")
   354  	if ferr != nil {
   355  		return ferr
   356  	}
   357  	if !u.Perms.ManageThemes {
   358  		return c.NoPermissions(w, r, u)
   359  	}
   360  	basePage.Header.AddScript("widgets.js")
   361  
   362  	docks := make(map[string][]c.WidgetEdit)
   363  	for _, name := range c.GetDockList() {
   364  		if name == "leftOfNav" || name == "rightOfNav" {
   365  			continue
   366  		}
   367  		var widgets []c.WidgetEdit
   368  		for _, widget := range c.GetDock(name) {
   369  			data := make(map[string]string)
   370  			err := json.Unmarshal([]byte(widget.RawBody), &data)
   371  			if err != nil {
   372  				return c.InternalError(err, w, r)
   373  			}
   374  			widgets = append(widgets, c.WidgetEdit{widget, data})
   375  		}
   376  		docks[name] = widgets
   377  	}
   378  
   379  	pi := c.PanelWidgetListPage{basePage, docks, c.WidgetEdit{&c.Widget{ID: 0, Type: "simple"}, make(map[string]string)}}
   380  	return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_themes_widgets", pi})
   381  }
   382  
   383  func widgetsParseInputs(r *http.Request, widget *c.Widget) (*c.WidgetEdit, error) {
   384  	data := make(map[string]string)
   385  	widget.Enabled = r.FormValue("wenabled") == "1"
   386  	widget.Location = r.FormValue("wlocation")
   387  	if widget.Location == "" {
   388  		return nil, errors.New("You need to specify a location for this widget.")
   389  	}
   390  	widget.Side = r.FormValue("wside")
   391  	if !c.HasDock(widget.Side) {
   392  		return nil, errors.New("The widget dock you specified doesn't exist.")
   393  	}
   394  
   395  	wtype := r.FormValue("wtype")
   396  	switch wtype {
   397  	case "simple", "about":
   398  		data["Name"] = r.FormValue("wname")
   399  		if data["Name"] == "" {
   400  			return nil, errors.New("You need to specify a title for this widget.")
   401  		}
   402  		data["Text"] = r.FormValue("wtext")
   403  		if data["Text"] == "" {
   404  			return nil, errors.New("You need to fill in the body for this widget.")
   405  		}
   406  		widget.Type = wtype // ? - Are we sure we should be directly assigning user provided data even if it's validated?
   407  	case "wol", "wol_context", "search_and_filter":
   408  		widget.Type = wtype // ? - Are we sure we should be directly assigning user provided data even if it's validated?
   409  	default:
   410  		return nil, errors.New("Unknown widget type")
   411  	}
   412  
   413  	return &c.WidgetEdit{widget, data}, nil
   414  }
   415  
   416  // ThemesWidgetsEditSubmit is an action which is triggered when someone sends an update request for a widget
   417  func ThemesWidgetsEditSubmit(w http.ResponseWriter, r *http.Request, u *c.User, swid string) c.RouteError {
   418  	//fmt.Println("in ThemesWidgetsEditSubmit")
   419  	_, ferr := c.SimplePanelUserCheck(w, r, u)
   420  	if ferr != nil {
   421  		return ferr
   422  	}
   423  	js := r.PostFormValue("js") == "1"
   424  	if !u.Perms.ManageThemes {
   425  		return c.NoPermissionsJSQ(w, r, u, js)
   426  	}
   427  
   428  	wid, err := strconv.Atoi(swid)
   429  	if err != nil {
   430  		return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, u, js)
   431  	}
   432  	widget, err := c.Widgets.Get(wid)
   433  	if err == sql.ErrNoRows {
   434  		return c.NotFoundJSQ(w, r, nil, js)
   435  	} else if err != nil {
   436  		return c.InternalErrorJSQ(err, w, r, js)
   437  	}
   438  
   439  	ewidget, err := widgetsParseInputs(r, widget.Copy())
   440  	if err != nil {
   441  		return c.LocalErrorJSQ(err.Error(), w, r, u, js)
   442  	}
   443  
   444  	err = ewidget.Commit()
   445  	if err != nil {
   446  		return c.InternalErrorJSQ(err, w, r, js)
   447  	}
   448  	err = c.AdminLogs.Create("edit", widget.ID, "widget", u.GetIP(), u.ID)
   449  	if err != nil {
   450  		return c.InternalError(err, w, r)
   451  	}
   452  
   453  	return successRedirect("/panel/themes/widgets/", w, r, js)
   454  }
   455  
   456  // ThemesWidgetsCreateSubmit is an action which is triggered when someone sends a create request for a widget
   457  func ThemesWidgetsCreateSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
   458  	js := r.PostFormValue("js") == "1"
   459  	_, ferr := c.SimplePanelUserCheck(w, r, u)
   460  	if ferr != nil {
   461  		return ferr
   462  	}
   463  	if !u.Perms.ManageThemes {
   464  		return c.NoPermissionsJSQ(w, r, u, js)
   465  	}
   466  
   467  	ewidget, err := widgetsParseInputs(r, &c.Widget{})
   468  	if err != nil {
   469  		return c.LocalErrorJSQ(err.Error(), w, r, u, js)
   470  	}
   471  	wid, err := ewidget.Create()
   472  	if err != nil {
   473  		return c.InternalErrorJSQ(err, w, r, js)
   474  	}
   475  	err = c.AdminLogs.Create("create", wid, "widget", u.GetIP(), u.ID)
   476  	if err != nil {
   477  		return c.InternalError(err, w, r)
   478  	}
   479  
   480  	return successRedirect("/panel/themes/widgets/", w, r, js)
   481  }
   482  
   483  func ThemesWidgetsDeleteSubmit(w http.ResponseWriter, r *http.Request, u *c.User, swid string) c.RouteError {
   484  	_, ferr := c.SimplePanelUserCheck(w, r, u)
   485  	if ferr != nil {
   486  		return ferr
   487  	}
   488  	js := r.PostFormValue("js") == "1"
   489  	if !u.Perms.ManageThemes {
   490  		return c.NoPermissionsJSQ(w, r, u, js)
   491  	}
   492  
   493  	wid, err := strconv.Atoi(swid)
   494  	if err != nil {
   495  		return c.LocalErrorJSQ(p.GetErrorPhrase("id_must_be_integer"), w, r, u, js)
   496  	}
   497  	widget, err := c.Widgets.Get(wid)
   498  	if err == sql.ErrNoRows {
   499  		return c.NotFound(w, r, nil)
   500  	} else if err != nil {
   501  		return c.InternalError(err, w, r)
   502  	}
   503  	err = widget.Delete()
   504  	if err != nil {
   505  		return c.InternalError(err, w, r)
   506  	}
   507  	err = c.AdminLogs.Create("delete", widget.ID, "widget", u.GetIP(), u.ID)
   508  	if err != nil {
   509  		return c.InternalError(err, w, r)
   510  	}
   511  
   512  	return successRedirect("/panel/themes/widgets/", w, r, js)
   513  }