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 }