github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/routes/panel/forums.go (about) 1 package panel 2 3 import ( 4 "database/sql" 5 "errors" 6 "net/http" 7 "strconv" 8 "strings" 9 10 c "github.com/Azareal/Gosora/common" 11 p "github.com/Azareal/Gosora/common/phrases" 12 ) 13 14 func Forums(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError { 15 bp, ferr := buildBasePage(w, r, u, "forums", "forums") 16 if ferr != nil { 17 return ferr 18 } 19 if !u.Perms.ManageForums { 20 return c.NoPermissions(w, r, u) 21 } 22 bp.Header.AddScript("Sortable-1.4.0/Sortable.min.js") 23 bp.Header.AddScriptAsync("panel_forums.js") 24 25 // TODO: Paginate this? 26 var forumList []interface{} 27 forums, err := c.Forums.GetAll() 28 if err != nil { 29 return c.InternalError(err, w, r) 30 } 31 32 // ? - Should we generate something similar to the forumView? It might be a little overkill for a page which is rarely loaded in comparison to /forums/ 33 for _, f := range forums { 34 if f.Name != "" && f.ParentID == 0 { 35 fadmin := c.ForumAdmin{f.ID, f.Name, f.Desc, f.Active, f.Preset, f.TopicCount, c.PresetToLang(f.Preset)} 36 if fadmin.Preset == "" { 37 fadmin.Preset = "custom" 38 } 39 forumList = append(forumList, fadmin) 40 } 41 } 42 43 if r.FormValue("created") == "1" { 44 bp.AddNotice("panel_forum_created") 45 } else if r.FormValue("deleted") == "1" { 46 bp.AddNotice("panel_forum_deleted") 47 } else if r.FormValue("updated") == "1" { 48 bp.AddNotice("panel_forum_updated") 49 } 50 51 pi := c.PanelPage{bp, forumList, nil} 52 return renderTemplate("panel", w, r, bp.Header, c.Panel{bp, "", "", "panel_forums", &pi}) 53 } 54 55 func ForumsCreateSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError { 56 _, ferr := c.SimplePanelUserCheck(w, r, u) 57 if ferr != nil { 58 return ferr 59 } 60 if !u.Perms.ManageForums { 61 return c.NoPermissions(w, r, u) 62 } 63 64 name := r.PostFormValue("name") 65 desc := r.PostFormValue("desc") 66 preset := c.StripInvalidPreset(r.PostFormValue("preset")) 67 factive := r.PostFormValue("active") 68 active := (factive == "on" || factive == "1") 69 70 fid, err := c.Forums.Create(name, desc, active, preset) 71 if err != nil { 72 return c.InternalError(err, w, r) 73 } 74 err = c.AdminLogs.Create("create", fid, "forum", u.GetIP(), u.ID) 75 if err != nil { 76 return c.InternalError(err, w, r) 77 } 78 79 http.Redirect(w, r, "/panel/forums/?created=1", http.StatusSeeOther) 80 return nil 81 } 82 83 // TODO: Revamp this 84 func ForumsDelete(w http.ResponseWriter, r *http.Request, u *c.User, sfid string) c.RouteError { 85 basePage, ferr := buildBasePage(w, r, u, "delete_forum", "forums") 86 if ferr != nil { 87 return ferr 88 } 89 if !u.Perms.ManageForums { 90 return c.NoPermissions(w, r, u) 91 } 92 93 fid, err := strconv.Atoi(sfid) 94 if err != nil { 95 return c.LocalError("The provided Forum ID is not a valid number.", w, r, u) 96 } 97 forum, err := c.Forums.Get(fid) 98 if err == sql.ErrNoRows { 99 return c.LocalError("The forum you're trying to delete doesn't exist.", w, r, u) 100 } else if err != nil { 101 return c.InternalError(err, w, r) 102 } 103 104 confirmMsg := p.GetTmplPhrasef("panel_forum_delete_are_you_sure", forum.Name) 105 youSure := c.AreYouSure{"/panel/forums/delete/submit/" + strconv.Itoa(fid), confirmMsg} 106 107 pi := c.PanelPage{basePage, tList, youSure} 108 if c.RunPreRenderHook("pre_render_panel_delete_forum", w, r, u, &pi) { 109 return nil 110 } 111 return renderTemplate("panel_are_you_sure", w, r, basePage.Header, &pi) 112 } 113 114 func ForumsDeleteSubmit(w http.ResponseWriter, r *http.Request, u *c.User, sfid string) c.RouteError { 115 _, ferr := c.SimplePanelUserCheck(w, r, u) 116 if ferr != nil { 117 return ferr 118 } 119 if !u.Perms.ManageForums { 120 return c.NoPermissions(w, r, u) 121 } 122 123 fid, err := strconv.Atoi(sfid) 124 if err != nil { 125 return c.LocalError("The provided Forum ID is not a valid number.", w, r, u) 126 } 127 err = c.Forums.Delete(fid) 128 if err == sql.ErrNoRows { 129 return c.LocalError("The forum you're trying to delete doesn't exist.", w, r, u) 130 } else if err != nil { 131 return c.InternalError(err, w, r) 132 } 133 err = c.AdminLogs.Create("delete", fid, "forum", u.GetIP(), u.ID) 134 if err != nil { 135 return c.InternalError(err, w, r) 136 } 137 138 http.Redirect(w, r, "/panel/forums/?deleted=1", http.StatusSeeOther) 139 return nil 140 } 141 142 func ForumsOrderSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError { 143 _, ferr := c.SimplePanelUserCheck(w, r, u) 144 if ferr != nil { 145 return ferr 146 } 147 // TODO: Move this even earlier? 148 js := r.PostFormValue("js") == "1" 149 if !u.Perms.ManageForums { 150 return c.NoPermissionsJSQ(w, r, u, js) 151 } 152 sitems := strings.TrimSuffix(strings.TrimPrefix(r.PostFormValue("items"), "{"), "}") 153 //fmt.Printf("sitems: %+v\n", sitems) 154 155 updateMap := make(map[int]int) 156 for index, sfid := range strings.Split(sitems, ",") { 157 fid, err := strconv.Atoi(sfid) 158 if err != nil { 159 return c.LocalErrorJSQ("Invalid integer in forum list", w, r, u, js) 160 } 161 updateMap[fid] = index 162 } 163 err := c.Forums.UpdateOrder(updateMap) 164 if err != nil { 165 return c.InternalErrorJSQ(err, w, r, js) 166 } 167 168 err = c.AdminLogs.Create("reorder", 0, "forum", u.GetIP(), u.ID) 169 if err != nil { 170 return c.InternalErrorJSQ(err, w, r, js) 171 } 172 173 return successRedirect("/panel/forums/", w, r, js) 174 } 175 176 func ForumsEdit(w http.ResponseWriter, r *http.Request, u *c.User, sfid string) c.RouteError { 177 basePage, ferr := buildBasePage(w, r, u, "edit_forum", "forums") 178 if ferr != nil { 179 return ferr 180 } 181 if !u.Perms.ManageForums { 182 return c.NoPermissions(w, r, u) 183 } 184 185 fid, err := strconv.Atoi(sfid) 186 if err != nil { 187 return c.SimpleError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, basePage.Header) 188 } 189 basePage.Header.AddScriptAsync("panel_forum_edit.js") 190 191 f, err := c.Forums.Get(fid) 192 if err == sql.ErrNoRows { 193 return c.LocalError("The forum you're trying to edit doesn't exist.", w, r, u) 194 } else if err != nil { 195 return c.InternalError(err, w, r) 196 } 197 if f.Preset == "" { 198 f.Preset = "custom" 199 } 200 201 glist, err := c.Groups.GetAll() 202 if err != nil { 203 return c.InternalError(err, w, r) 204 } 205 206 var gplist []c.GroupForumPermPreset 207 for gid, group := range glist { 208 if gid == 0 { 209 continue 210 } 211 forumPerms, err := c.FPStore.Get(fid, group.ID) 212 if err == sql.ErrNoRows { 213 forumPerms = c.BlankForumPerms() 214 } else if err != nil { 215 return c.InternalError(err, w, r) 216 } 217 preset := c.ForumPermsToGroupForumPreset(forumPerms) 218 gplist = append(gplist, c.GroupForumPermPreset{group, preset, preset == "default"}) 219 } 220 221 if r.FormValue("updated") == "1" { 222 basePage.AddNotice("panel_forum_updated") 223 } 224 225 falist, e := c.ForumActionStore.GetInForum(f.ID) 226 if err != sql.ErrNoRows && e != nil { 227 return c.InternalError(e, w, r) 228 } 229 afalist := make([]*c.ForumActionAction, len(falist)) 230 for i, faitem := range falist { 231 afalist[i] = &c.ForumActionAction{faitem, c.ConvActToString(faitem.Action)} 232 } 233 234 pi := c.PanelEditForumPage{basePage, f.ID, f.Name, f.Desc, f.Active, f.Preset, gplist, afalist} 235 return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_forum_edit", &pi}) 236 } 237 238 func ForumsEditSubmit(w http.ResponseWriter, r *http.Request, u *c.User, sfid string) c.RouteError { 239 _, ferr := c.SimplePanelUserCheck(w, r, u) 240 if ferr != nil { 241 return ferr 242 } 243 if !u.Perms.ManageForums { 244 return c.NoPermissions(w, r, u) 245 } 246 js := r.PostFormValue("js") == "1" 247 248 fid, err := strconv.Atoi(sfid) 249 if err != nil { 250 return c.LocalErrorJSQ("The provided Forum ID is not a valid number.", w, r, u, js) 251 } 252 forum, err := c.Forums.Get(fid) 253 if err == sql.ErrNoRows { 254 return c.LocalErrorJSQ("The forum you're trying to edit doesn't exist.", w, r, u, js) 255 } else if err != nil { 256 return c.InternalErrorJSQ(err, w, r, js) 257 } 258 259 name := r.PostFormValue("forum_name") 260 desc := r.PostFormValue("forum_desc") 261 preset := c.StripInvalidPreset(r.PostFormValue("forum_preset")) 262 factive := r.PostFormValue("forum_active") 263 264 active := false 265 if factive == "" { 266 active = forum.Active 267 } else if factive == "1" || factive == "Show" { 268 active = true 269 } 270 271 err = forum.Update(name, desc, active, preset) 272 if err != nil { 273 return c.InternalErrorJSQ(err, w, r, js) 274 } 275 err = c.AdminLogs.Create("edit", fid, "forum", u.GetIP(), u.ID) 276 if err != nil { 277 return c.InternalError(err, w, r) 278 } 279 280 // ? Should we redirect to the forum editor instead? 281 return successRedirect("/panel/forums/", w, r, js) 282 } 283 284 func ForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, u *c.User, sfid string) c.RouteError { 285 _, ferr := c.SimplePanelUserCheck(w, r, u) 286 if ferr != nil { 287 return ferr 288 } 289 if !u.Perms.ManageForums { 290 return c.NoPermissions(w, r, u) 291 } 292 js := r.PostFormValue("js") == "1" 293 294 fid, err := strconv.Atoi(sfid) 295 if err != nil { 296 return c.LocalErrorJSQ("The provided Forum ID is not a valid number.", w, r, u, js) 297 } 298 gid, err := strconv.Atoi(r.PostFormValue("gid")) 299 if err != nil { 300 return c.LocalErrorJSQ("Invalid Group ID", w, r, u, js) 301 } 302 303 f, err := c.Forums.Get(fid) 304 if err == sql.ErrNoRows { 305 return c.LocalErrorJSQ("This forum doesn't exist", w, r, u, js) 306 } else if err != nil { 307 return c.InternalErrorJSQ(err, w, r, js) 308 } 309 310 permPreset := c.StripInvalidGroupForumPreset(r.PostFormValue("perm_preset")) 311 err = f.SetPreset(permPreset, gid) 312 if err != nil { 313 return c.LocalErrorJSQ(err.Error(), w, r, u, js) 314 } 315 err = c.AdminLogs.Create("edit", fid, "forum", u.GetIP(), u.ID) 316 if err != nil { 317 return c.InternalError(err, w, r) 318 } 319 320 return successRedirect("/panel/forums/edit/"+strconv.Itoa(fid)+"?updated=1", w, r, js) 321 } 322 323 // A helper function for the Advanced portion of the Forum Perms Editor 324 func forumPermsExtractDash(paramList string) (fid, gid int, e error) { 325 params := strings.Split(paramList, "-") 326 if len(params) != 2 { 327 return fid, gid, errors.New("Parameter count mismatch") 328 } 329 fid, e = strconv.Atoi(params[0]) 330 if e != nil { 331 return fid, gid, errors.New("The provided Forum ID is not a valid number.") 332 } 333 gid, e = strconv.Atoi(params[1]) 334 if e != nil { 335 e = errors.New("The provided Group ID is not a valid number.") 336 } 337 return fid, gid, e 338 } 339 340 func ForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, u *c.User, paramList string) c.RouteError { 341 bp, ferr := buildBasePage(w, r, u, "edit_forum", "forums") 342 if ferr != nil { 343 return ferr 344 } 345 if !u.Perms.ManageForums { 346 return c.NoPermissions(w, r, u) 347 } 348 349 fid, gid, err := forumPermsExtractDash(paramList) 350 if err != nil { 351 return c.LocalError(err.Error(), w, r, u) 352 } 353 354 f, err := c.Forums.Get(fid) 355 if err == sql.ErrNoRows { 356 return c.LocalError("The forum you're trying to edit doesn't exist.", w, r, u) 357 } else if err != nil { 358 return c.InternalError(err, w, r) 359 } 360 if f.Preset == "" { 361 f.Preset = "custom" 362 } 363 364 fp, err := c.FPStore.Get(fid, gid) 365 if err == sql.ErrNoRows { 366 fp = c.BlankForumPerms() 367 } else if err != nil { 368 return c.InternalError(err, w, r) 369 } 370 371 var formattedPermList []c.NameLangToggle 372 // TODO: Load the phrases in bulk for efficiency? 373 // TODO: Reduce the amount of code duplication between this and the group editor. Also, can we grind this down into one line or use a code generator to stay current more easily? 374 addToggle := func(permStr string, perm bool) { 375 formattedPermList = append(formattedPermList, c.NameLangToggle{permStr, p.GetPermPhrase(permStr), perm}) 376 } 377 addToggle("ViewTopic", fp.ViewTopic) 378 addToggle("LikeItem", fp.LikeItem) 379 addToggle("CreateTopic", fp.CreateTopic) 380 //<-- 381 addToggle("EditTopic", fp.EditTopic) 382 addToggle("DeleteTopic", fp.DeleteTopic) 383 addToggle("CreateReply", fp.CreateReply) 384 addToggle("EditReply", fp.EditReply) 385 addToggle("DeleteReply", fp.DeleteReply) 386 addToggle("PinTopic", fp.PinTopic) 387 addToggle("CloseTopic", fp.CloseTopic) 388 addToggle("MoveTopic", fp.MoveTopic) 389 390 if r.FormValue("updated") == "1" { 391 bp.AddNotice("panel_forum_perms_updated") 392 } 393 394 pi := c.PanelEditForumGroupPage{bp, f.ID, gid, f.Name, f.Desc, f.Active, f.Preset, formattedPermList} 395 return renderTemplate("panel", w, r, bp.Header, c.Panel{bp, "", "", "panel_forum_edit_perms", &pi}) 396 } 397 398 func ForumsEditPermsAdvanceSubmit(w http.ResponseWriter, r *http.Request, u *c.User, paramList string) c.RouteError { 399 _, ferr := c.SimplePanelUserCheck(w, r, u) 400 if ferr != nil { 401 return ferr 402 } 403 if !u.Perms.ManageForums { 404 return c.NoPermissions(w, r, u) 405 } 406 js := r.PostFormValue("js") == "1" 407 408 fid, gid, err := forumPermsExtractDash(paramList) 409 if err != nil { 410 return c.LocalError(err.Error(), w, r, u) 411 } 412 413 f, err := c.Forums.Get(fid) 414 if err == sql.ErrNoRows { 415 return c.LocalError("The forum you're trying to edit doesn't exist.", w, r, u) 416 } else if err != nil { 417 return c.InternalError(err, w, r) 418 } 419 420 fp, err := c.FPStore.GetCopy(fid, gid) 421 if err == sql.ErrNoRows { 422 fp = *c.BlankForumPerms() 423 } else if err != nil { 424 return c.InternalError(err, w, r) 425 } 426 427 ep := func(name string) bool { 428 pvalue := r.PostFormValue("perm-" + name) 429 return (pvalue == "1") 430 } 431 // TODO: Generate this code? 432 fp.ViewTopic = ep("ViewTopic") 433 fp.LikeItem = ep("LikeItem") 434 fp.CreateTopic = ep("CreateTopic") 435 fp.EditTopic = ep("EditTopic") 436 fp.DeleteTopic = ep("DeleteTopic") 437 fp.CreateReply = ep("CreateReply") 438 fp.EditReply = ep("EditReply") 439 fp.DeleteReply = ep("DeleteReply") 440 fp.PinTopic = ep("PinTopic") 441 fp.CloseTopic = ep("CloseTopic") 442 fp.MoveTopic = ep("MoveTopic") 443 444 err = f.SetPerms(&fp, "custom", gid) 445 if err != nil { 446 return c.LocalErrorJSQ(err.Error(), w, r, u, js) 447 } 448 err = c.AdminLogs.Create("edit", fid, "forum", u.GetIP(), u.ID) 449 if err != nil { 450 return c.InternalError(err, w, r) 451 } 452 453 return successRedirect("/panel/forums/edit/perms/"+strconv.Itoa(fid)+"-"+strconv.Itoa(gid)+"?updated=1", w, r, js) 454 } 455 456 func ForumsEditActionDeleteSubmit(w http.ResponseWriter, r *http.Request, u *c.User, sfaid string) c.RouteError { 457 _, ferr := c.SimplePanelUserCheck(w, r, u) 458 if ferr != nil { 459 return ferr 460 } 461 // TODO: Should we split this permission? 462 if !u.Perms.ManageForums { 463 return c.NoPermissions(w, r, u) 464 } 465 js := r.PostFormValue("js") == "1" 466 467 faid, e := strconv.Atoi(sfaid) 468 if e != nil { 469 return c.LocalError("The forum action ID is not a valid integer.", w, r, u) 470 } 471 e = c.ForumActionStore.Delete(faid) 472 if e != nil { 473 return c.InternalError(e, w, r) 474 } 475 476 fid, e := strconv.Atoi(r.FormValue("ret")) 477 if e != nil { 478 return c.LocalError("The forum action ID is not a valid integer.", w, r, u) 479 } 480 if !c.Forums.Exists(fid) { 481 return c.LocalError("The target forum doesn't exist.", w, r, u) 482 } 483 484 return successRedirect("/panel/forums/edit/"+strconv.Itoa(fid)+"?updated=1", w, r, js) 485 } 486 487 func ForumsEditActionCreateSubmit(w http.ResponseWriter, r *http.Request, u *c.User, sfid string) c.RouteError { 488 _, ferr := c.SimplePanelUserCheck(w, r, u) 489 if ferr != nil { 490 return ferr 491 } 492 // TODO: Should we split this permission? 493 if !u.Perms.ManageForums { 494 return c.NoPermissions(w, r, u) 495 } 496 js := r.PostFormValue("js") == "1" 497 498 fid, e := strconv.Atoi(sfid) 499 if e != nil { 500 return c.LocalError("The provided Forum ID is not a valid number.", w, r, u) 501 } 502 if !c.Forums.Exists(fid) { 503 return c.LocalError("This forum does not exist", w, r, u) 504 } 505 506 runOnTopicCreation := r.PostFormValue("action_run_on_topic_creation") == "1" 507 508 f := func(s string) (int, c.RouteError) { 509 i, e := strconv.Atoi(r.PostFormValue(s)) 510 if e != nil { 511 return i, c.LocalError(s+" is not a valid integer.", w, r, u) 512 } 513 if i < 0 { 514 return i, c.LocalError(s+" cannot be less than 0", w, r, u) 515 } 516 return i, nil 517 } 518 runDaysAfterTopicCreation, re := f("action_run_days_after_topic_creation") 519 if re != nil { 520 return re 521 } 522 runDaysAfterTopicLastReply, re := f("action_run_days_after_topic_last_reply") 523 if re != nil { 524 return re 525 } 526 527 action := r.PostFormValue("action_action") 528 aint := c.ConvStringToAct(action) 529 if aint == -1 { 530 return c.LocalError("invalid action", w, r, u) 531 } 532 533 extra := r.PostFormValue("action_extra") 534 switch aint { 535 case c.ForumActionMove: 536 conv, e := strconv.Atoi(extra) 537 if e != nil { 538 return c.LocalError("action_extra is not a valid integer.", w, r, u) 539 } 540 extra = strconv.Itoa(conv) 541 default: 542 extra = "" 543 } 544 545 _, e = c.ForumActionStore.Add(&c.ForumAction{ 546 Forum: fid, 547 RunOnTopicCreation: runOnTopicCreation, 548 RunDaysAfterTopicCreation: runDaysAfterTopicCreation, 549 RunDaysAfterTopicLastReply: runDaysAfterTopicLastReply, 550 Action: aint, 551 Extra: extra, 552 }) 553 if e != nil { 554 return c.InternalError(e, w, r) 555 } 556 557 return successRedirect("/panel/forums/edit/"+strconv.Itoa(fid)+"?updated=1", w, r, js) 558 }