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  }