5a43432b80
Replaced the io.Writers with http.ResponseWriters. Refactored the compiled template calls. Redirect port 443 to port 80. Catch more errors from templates. Fixed a few mutexes which are never unlocked. Eliminated an unnecessary parameter in InternalError() Temporarily commented out users_penalties so that the installer will succeed. A couple more template types can be remapped now. Tweaked the theme.
669 lines
21 KiB
Go
669 lines
21 KiB
Go
package main
|
|
|
|
import (
|
|
//"fmt"
|
|
"bytes"
|
|
"strings"
|
|
"strconv"
|
|
"errors"
|
|
"context"
|
|
"net/http"
|
|
"html"
|
|
"html/template"
|
|
"database/sql"
|
|
|
|
"./query_gen/lib"
|
|
)
|
|
|
|
var socialgroups_list_stmt *sql.Stmt
|
|
var socialgroups_member_list_stmt *sql.Stmt
|
|
var socialgroups_member_list_join_stmt *sql.Stmt
|
|
var socialgroups_get_member_stmt *sql.Stmt
|
|
var socialgroups_get_group_stmt *sql.Stmt
|
|
var socialgroups_create_group_stmt *sql.Stmt
|
|
var socialgroups_attach_forum_stmt *sql.Stmt
|
|
var socialgroups_unattach_forum_stmt *sql.Stmt
|
|
var socialgroups_add_member_stmt *sql.Stmt
|
|
|
|
// TO-DO: Add a better way of splitting up giant plugins like this
|
|
type SocialGroup struct
|
|
{
|
|
ID int
|
|
Link string
|
|
Name string
|
|
Desc string
|
|
Active bool
|
|
Privacy int /* 0: Public, 1: Protected, 2: Private */
|
|
|
|
// Who should be able to accept applications and create invites? Mods+ or just admins? Mods is a good start, we can ponder over whether we should make this more flexible in the future.
|
|
Joinable int /* 0: Private, 1: Anyone can join, 2: Applications, 3: Invite-only */
|
|
|
|
MemberCount int
|
|
Owner int
|
|
Backdrop string
|
|
CreatedAt string
|
|
LastUpdateTime string
|
|
|
|
MainForumID int
|
|
MainForum *Forum
|
|
Forums []*Forum
|
|
ExtData ExtData
|
|
}
|
|
|
|
type SocialGroupPage struct
|
|
{
|
|
Title string
|
|
CurrentUser User
|
|
Header HeaderVars
|
|
ItemList []*TopicsRow
|
|
Forum Forum
|
|
SocialGroup SocialGroup
|
|
Page int
|
|
LastPage int
|
|
ExtData ExtData
|
|
}
|
|
|
|
type SocialGroupListPage struct
|
|
{
|
|
Title string
|
|
CurrentUser User
|
|
Header HeaderVars
|
|
GroupList []SocialGroup
|
|
ExtData ExtData
|
|
}
|
|
|
|
type SocialGroupMemberListPage struct
|
|
{
|
|
Title string
|
|
CurrentUser User
|
|
Header HeaderVars
|
|
ItemList []SocialGroupMember
|
|
SocialGroup SocialGroup
|
|
Page int
|
|
LastPage int
|
|
ExtData ExtData
|
|
}
|
|
|
|
type SocialGroupMember struct
|
|
{
|
|
Link string
|
|
Rank int /* 0: Member. 1: Mod. 2: Admin. */
|
|
RankString string /* Member, Mod, Admin, Owner */
|
|
PostCount int
|
|
JoinedAt string
|
|
Offline bool // TO-DO: Need to track the online states of members when WebSockets are enabled
|
|
|
|
User User
|
|
}
|
|
|
|
func init() {
|
|
plugins["socialgroups"] = NewPlugin("socialgroups","Social Groups","Azareal","http://github.com/Azareal","","","",init_socialgroups,nil,deactivate_socialgroups,install_socialgroups,nil)
|
|
}
|
|
|
|
func init_socialgroups() (err error) {
|
|
plugins["socialgroups"].AddHook("intercept_build_widgets", socialgroups_widgets)
|
|
plugins["socialgroups"].AddHook("trow_assign", socialgroups_trow_assign)
|
|
plugins["socialgroups"].AddHook("topic_create_pre_loop", socialgroups_topic_create_pre_loop)
|
|
plugins["socialgroups"].AddHook("pre_render_view_forum", socialgroups_pre_render_view_forum)
|
|
plugins["socialgroups"].AddHook("simple_forum_check_pre_perms", socialgroups_forum_check)
|
|
plugins["socialgroups"].AddHook("forum_check_pre_perms", socialgroups_forum_check)
|
|
// TO-DO: Auto-grant this perm to admins upon installation?
|
|
register_plugin_perm("CreateSocialGroup")
|
|
router.HandleFunc("/groups/", socialgroups_group_list)
|
|
router.HandleFunc("/group/", socialgroups_view_group)
|
|
router.HandleFunc("/group/create/", socialgroups_create_group)
|
|
router.HandleFunc("/group/create/submit/", socialgroups_create_group_submit)
|
|
router.HandleFunc("/group/members/", socialgroups_member_list)
|
|
|
|
socialgroups_list_stmt, err = qgen.Builder.SimpleSelect("socialgroups","sgid, name, desc, active, privacy, joinable, owner, memberCount, createdAt, lastUpdateTime","","","")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
socialgroups_get_group_stmt, err = qgen.Builder.SimpleSelect("socialgroups","name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime","sgid = ?","","")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
socialgroups_member_list_stmt, err = qgen.Builder.SimpleSelect("socialgroups_members","sgid, uid, rank, posts, joinedAt","","","")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
socialgroups_member_list_join_stmt, err = qgen.Builder.SimpleLeftJoin("socialgroups_members","users","users.uid, socialgroups_members.rank, socialgroups_members.posts, socialgroups_members.joinedAt, users.name, users.avatar","socialgroups_members.uid = users.uid","socialgroups_members.sgid = ?","socialgroups_members.rank DESC, socialgroups_members.joinedat ASC","")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
socialgroups_get_member_stmt, err = qgen.Builder.SimpleSelect("socialgroups_members","rank, posts, joinedAt","sgid = ? AND uid = ?","","")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
socialgroups_create_group_stmt, err = qgen.Builder.SimpleInsert("socialgroups","name, desc, active, privacy, joinable, owner, memberCount, mainForum, backdrop, createdAt, lastUpdateTime","?,?,?,?,1,?,1,?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP()")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
socialgroups_attach_forum_stmt, err = qgen.Builder.SimpleUpdate("forums","parentID = ?, parentType = 'socialgroup'","fid = ?")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
socialgroups_unattach_forum_stmt, err = qgen.Builder.SimpleUpdate("forums","parentID = 0, parentType = ''","fid = ?")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
socialgroups_add_member_stmt, err = qgen.Builder.SimpleInsert("socialgroups_members","sgid, uid, rank, posts, joinedAt","?,?,?,0,UTC_TIMESTAMP()")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func deactivate_socialgroups() {
|
|
plugins["socialgroups"].RemoveHook("intercept_build_widgets", socialgroups_widgets)
|
|
plugins["socialgroups"].RemoveHook("trow_assign", socialgroups_trow_assign)
|
|
plugins["socialgroups"].RemoveHook("topic_create_pre_loop", socialgroups_topic_create_pre_loop)
|
|
plugins["socialgroups"].RemoveHook("pre_render_view_forum", socialgroups_pre_render_view_forum)
|
|
plugins["socialgroups"].RemoveHook("simple_forum_check_pre_perms", socialgroups_forum_check)
|
|
plugins["socialgroups"].RemoveHook("forum_check_pre_perms", socialgroups_forum_check)
|
|
deregister_plugin_perm("CreateSocialGroup")
|
|
_ = router.RemoveFunc("/groups/")
|
|
_ = router.RemoveFunc("/group/")
|
|
_ = router.RemoveFunc("/group/create/")
|
|
_ = router.RemoveFunc("/group/create/submit/")
|
|
_ = socialgroups_list_stmt.Close()
|
|
_ = socialgroups_member_list_stmt.Close()
|
|
_ = socialgroups_member_list_join_stmt.Close()
|
|
_ = socialgroups_get_member_stmt.Close()
|
|
_ = socialgroups_get_group_stmt.Close()
|
|
_ = socialgroups_create_group_stmt.Close()
|
|
_ = socialgroups_attach_forum_stmt.Close()
|
|
_ = socialgroups_unattach_forum_stmt.Close()
|
|
_ = socialgroups_add_member_stmt.Close()
|
|
}
|
|
|
|
// TO-DO: Stop accessing the query builder directly and add a feature in Gosora which is more easily reversed, if an error comes up during the installation process
|
|
func install_socialgroups() error {
|
|
sg_table_stmt, err := qgen.Builder.CreateTable("socialgroups","utf8mb4","utf8mb4_general_ci",
|
|
[]qgen.DB_Table_Column{
|
|
qgen.DB_Table_Column{"sgid","int",0,false,true,""},
|
|
qgen.DB_Table_Column{"name","varchar",100,false,false,""},
|
|
qgen.DB_Table_Column{"desc","varchar",200,false,false,""},
|
|
qgen.DB_Table_Column{"active","boolean",1,false,false,""},
|
|
qgen.DB_Table_Column{"privacy","smallint",0,false,false,""},
|
|
qgen.DB_Table_Column{"joinable","smallint",0,false,false,"0"},
|
|
qgen.DB_Table_Column{"owner","int",0,false,false,""},
|
|
qgen.DB_Table_Column{"memberCount","int",0,false,false,""},
|
|
qgen.DB_Table_Column{"mainForum","int",0,false,false,"0"}, // The board the user lands on when they click on a group, we'll make it possible for group admins to change what users land on
|
|
//qgen.DB_Table_Column{"boards","varchar",255,false,false,""}, // Cap the max number of boards at 8 to avoid overflowing the confines of a 64-bit integer?
|
|
qgen.DB_Table_Column{"backdrop","varchar",200,false,false,""}, // File extension for the uploaded file, or an external link
|
|
qgen.DB_Table_Column{"createdAt","createdAt",0,false,false,""},
|
|
qgen.DB_Table_Column{"lastUpdateTime","datetime",0,false,false,""},
|
|
},
|
|
[]qgen.DB_Table_Key{
|
|
qgen.DB_Table_Key{"sgid","primary"},
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = sg_table_stmt.Exec()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sg_members_table_stmt, err := qgen.Builder.CreateTable("socialgroups_members","","",
|
|
[]qgen.DB_Table_Column{
|
|
qgen.DB_Table_Column{"sgid","int",0,false,false,""},
|
|
qgen.DB_Table_Column{"uid","int",0,false,false,""},
|
|
qgen.DB_Table_Column{"rank","int",0,false,false,"0"}, /* 0: Member. 1: Mod. 2: Admin. */
|
|
qgen.DB_Table_Column{"posts","int",0,false,false,"0"}, /* Per-Group post count. Should we do some sort of score system? */
|
|
qgen.DB_Table_Column{"joinedAt","datetime",0,false,false,""},
|
|
},
|
|
[]qgen.DB_Table_Key{},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = sg_members_table_stmt.Exec()
|
|
return err
|
|
}
|
|
|
|
// TO-DO; Implement an uninstallation system into Gosora. And a better installation system.
|
|
func uninstall_socialgroups() error {
|
|
return nil
|
|
}
|
|
|
|
// TO-DO: Do this properly via the widget system
|
|
func socialgroups_common_area_widgets(headerVars *HeaderVars) {
|
|
// TO-DO: Hot Groups? Featured Groups? Official Groups?
|
|
var b bytes.Buffer
|
|
var menu WidgetMenu = WidgetMenu{"Social Groups",[]WidgetMenuItem{
|
|
WidgetMenuItem{"Create Group","/group/create/",false},
|
|
}}
|
|
|
|
err := templates.ExecuteTemplate(&b,"widget_menu.html",menu)
|
|
if err != nil {
|
|
LogError(err)
|
|
return
|
|
}
|
|
|
|
if themes[defaultTheme].Sidebars == "left" {
|
|
headerVars.Widgets.LeftSidebar = template.HTML(string(b.Bytes()))
|
|
} else if themes[defaultTheme].Sidebars == "right" || themes[defaultTheme].Sidebars == "both" {
|
|
headerVars.Widgets.RightSidebar = template.HTML(string(b.Bytes()))
|
|
}
|
|
}
|
|
|
|
// TO-DO: Do this properly via the widget system
|
|
// TO-DO: Make a better more customisable group widget system
|
|
func socialgroups_group_widgets(headerVars *HeaderVars, sgItem SocialGroup) (success bool) {
|
|
return false // Disabled until the next commit
|
|
|
|
var b bytes.Buffer
|
|
var menu WidgetMenu = WidgetMenu{"Group Options",[]WidgetMenuItem{
|
|
WidgetMenuItem{"Join","/group/join/" + strconv.Itoa(sgItem.ID),false},
|
|
WidgetMenuItem{"Members","/group/members/" + strconv.Itoa(sgItem.ID),false},
|
|
}}
|
|
|
|
err := templates.ExecuteTemplate(&b,"widget_menu.html",menu)
|
|
if err != nil {
|
|
LogError(err)
|
|
return false
|
|
}
|
|
|
|
if themes[defaultTheme].Sidebars == "left" {
|
|
headerVars.Widgets.LeftSidebar = template.HTML(string(b.Bytes()))
|
|
} else if themes[defaultTheme].Sidebars == "right" || themes[defaultTheme].Sidebars == "both" {
|
|
headerVars.Widgets.RightSidebar = template.HTML(string(b.Bytes()))
|
|
} else {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
/*
|
|
Custom Pages
|
|
*/
|
|
|
|
func socialgroups_group_list(w http.ResponseWriter, r *http.Request, user User) {
|
|
headerVars, ok := SessionCheck(w,r,&user)
|
|
if !ok {
|
|
return
|
|
}
|
|
socialgroups_common_area_widgets(&headerVars)
|
|
|
|
rows, err := socialgroups_list_stmt.Query()
|
|
if err != nil && err != ErrNoRows {
|
|
InternalError(err,w)
|
|
return
|
|
}
|
|
|
|
var sgList []SocialGroup
|
|
for rows.Next() {
|
|
sgItem := SocialGroup{ID:0}
|
|
err := rows.Scan(&sgItem.ID, &sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Joinable, &sgItem.Owner, &sgItem.MemberCount, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
|
|
if err != nil {
|
|
InternalError(err,w)
|
|
return
|
|
}
|
|
sgItem.Link = socialgroups_build_group_url(name_to_slug(sgItem.Name),sgItem.ID)
|
|
sgList = append(sgList,sgItem)
|
|
}
|
|
err = rows.Err()
|
|
if err != nil {
|
|
InternalError(err,w)
|
|
return
|
|
}
|
|
rows.Close()
|
|
|
|
pi := SocialGroupListPage{"Group List",user,headerVars,sgList,extData}
|
|
err = templates.ExecuteTemplate(w,"socialgroups_group_list.html", pi)
|
|
if err != nil {
|
|
InternalError(err,w)
|
|
}
|
|
}
|
|
|
|
func socialgroups_get_group(sgid int) (sgItem SocialGroup, err error) {
|
|
sgItem = SocialGroup{ID:sgid}
|
|
err = socialgroups_get_group_stmt.QueryRow(sgid).Scan(&sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Joinable, &sgItem.Owner, &sgItem.MemberCount, &sgItem.MainForumID, &sgItem.Backdrop, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
|
|
return sgItem, err
|
|
}
|
|
|
|
func socialgroups_view_group(w http.ResponseWriter, r *http.Request, user User) {
|
|
// SEO URLs...
|
|
halves := strings.Split(r.URL.Path[len("/group/"):],".")
|
|
if len(halves) < 2 {
|
|
halves = append(halves,halves[0])
|
|
}
|
|
sgid, err := strconv.Atoi(halves[1])
|
|
if err != nil {
|
|
PreError("Not a valid group ID",w,r)
|
|
return
|
|
}
|
|
|
|
sgItem, err := socialgroups_get_group(sgid)
|
|
if err != nil {
|
|
LocalError("Bad group",w,r,user)
|
|
return
|
|
}
|
|
if !sgItem.Active {
|
|
NotFound(w,r)
|
|
}
|
|
|
|
// Re-route the request to route_forums
|
|
var ctx context.Context = context.WithValue(r.Context(),"socialgroups_current_group",sgItem)
|
|
route_forum(w,r.WithContext(ctx),user,strconv.Itoa(sgItem.MainForumID))
|
|
}
|
|
|
|
func socialgroups_create_group(w http.ResponseWriter, r *http.Request, user User) {
|
|
headerVars, ok := SessionCheck(w,r,&user)
|
|
if !ok {
|
|
return
|
|
}
|
|
// TO-DO: Add an approval queue mode for group creation
|
|
if !user.Loggedin || !user.PluginPerms["CreateSocialGroup"] {
|
|
NoPermissions(w,r,user)
|
|
return
|
|
}
|
|
socialgroups_common_area_widgets(&headerVars)
|
|
|
|
pi := Page{"Create Group",user,headerVars,tList,nil}
|
|
err := templates.ExecuteTemplate(w,"socialgroups_create_group.html", pi)
|
|
if err != nil {
|
|
InternalError(err,w)
|
|
}
|
|
}
|
|
|
|
func socialgroups_create_group_submit(w http.ResponseWriter, r *http.Request, user User) {
|
|
// TO-DO: Add an approval queue mode for group creation
|
|
if !user.Loggedin || !user.PluginPerms["CreateSocialGroup"] {
|
|
NoPermissions(w,r,user)
|
|
return
|
|
}
|
|
|
|
var group_active bool = true
|
|
var group_name string = html.EscapeString(r.PostFormValue("group_name"))
|
|
var group_desc string = html.EscapeString(r.PostFormValue("group_desc"))
|
|
var gprivacy string = r.PostFormValue("group_privacy")
|
|
|
|
var group_privacy int
|
|
switch(gprivacy) {
|
|
case "0": group_privacy = 0 // Public
|
|
case "1": group_privacy = 1 // Protected
|
|
case "2": group_privacy = 2 // private
|
|
default: group_privacy = 0
|
|
}
|
|
|
|
// Create the backing forum
|
|
fid, err := fstore.CreateForum(group_name,"",true,"")
|
|
if err != nil {
|
|
InternalError(err,w)
|
|
return
|
|
}
|
|
|
|
res, err := socialgroups_create_group_stmt.Exec(group_name, group_desc, group_active, group_privacy, user.ID, fid)
|
|
if err != nil {
|
|
InternalError(err,w)
|
|
return
|
|
}
|
|
lastId, err := res.LastInsertId()
|
|
if err != nil {
|
|
InternalError(err,w)
|
|
return
|
|
}
|
|
|
|
// Add the main backing forum to the forum list
|
|
err = socialgroups_attach_forum(int(lastId),fid)
|
|
if err != nil {
|
|
InternalError(err,w)
|
|
return
|
|
}
|
|
|
|
_, err = socialgroups_add_member_stmt.Exec(lastId,user.ID,2)
|
|
if err != nil {
|
|
InternalError(err,w)
|
|
return
|
|
}
|
|
|
|
http.Redirect(w,r,socialgroups_build_group_url(name_to_slug(group_name),int(lastId)), http.StatusSeeOther)
|
|
}
|
|
|
|
func socialgroups_member_list(w http.ResponseWriter, r *http.Request, user User) {
|
|
headerVars, ok := SessionCheck(w,r,&user)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
// SEO URLs...
|
|
halves := strings.Split(r.URL.Path[len("/group/members/"):],".")
|
|
if len(halves) < 2 {
|
|
halves = append(halves,halves[0])
|
|
}
|
|
sgid, err := strconv.Atoi(halves[1])
|
|
if err != nil {
|
|
PreError("Not a valid group ID",w,r)
|
|
return
|
|
}
|
|
|
|
var sgItem SocialGroup = SocialGroup{ID:sgid}
|
|
var mainForum int // Unused
|
|
err = socialgroups_get_group_stmt.QueryRow(sgid).Scan(&sgItem.Name, &sgItem.Desc, &sgItem.Active, &sgItem.Privacy, &sgItem.Joinable, &sgItem.Owner, &sgItem.MemberCount, &mainForum, &sgItem.Backdrop, &sgItem.CreatedAt, &sgItem.LastUpdateTime)
|
|
if err != nil {
|
|
LocalError("Bad group",w,r,user)
|
|
return
|
|
}
|
|
sgItem.Link = socialgroups_build_group_url(name_to_slug(sgItem.Name),sgItem.ID)
|
|
|
|
socialgroups_group_widgets(&headerVars, sgItem)
|
|
|
|
rows, err := socialgroups_member_list_join_stmt.Query(sgid)
|
|
if err != nil && err != ErrNoRows {
|
|
InternalError(err,w)
|
|
return
|
|
}
|
|
|
|
var sgMembers []SocialGroupMember
|
|
for rows.Next() {
|
|
sgMember := SocialGroupMember{PostCount:0}
|
|
err := rows.Scan(&sgMember.User.ID,&sgMember.Rank,&sgMember.PostCount,&sgMember.JoinedAt,&sgMember.User.Name, &sgMember.User.Avatar)
|
|
if err != nil {
|
|
InternalError(err,w)
|
|
return
|
|
}
|
|
sgMember.Link = build_profile_url(name_to_slug(sgMember.User.Name),sgMember.User.ID)
|
|
if sgMember.User.Avatar != "" {
|
|
if sgMember.User.Avatar[0] == '.' {
|
|
sgMember.User.Avatar = "/uploads/avatar_" + strconv.Itoa(sgMember.User.ID) + sgMember.User.Avatar
|
|
}
|
|
} else {
|
|
sgMember.User.Avatar = strings.Replace(config.Noavatar,"{id}",strconv.Itoa(sgMember.User.ID),1)
|
|
}
|
|
sgMember.JoinedAt, _ = relative_time(sgMember.JoinedAt)
|
|
if sgItem.Owner == sgMember.User.ID {
|
|
sgMember.RankString = "Owner"
|
|
} else {
|
|
switch(sgMember.Rank) {
|
|
case 0: sgMember.RankString = "Member"
|
|
case 1: sgMember.RankString = "Mod"
|
|
case 2: sgMember.RankString = "Admin"
|
|
}
|
|
}
|
|
sgMembers = append(sgMembers,sgMember)
|
|
}
|
|
err = rows.Err()
|
|
if err != nil {
|
|
InternalError(err,w)
|
|
return
|
|
}
|
|
rows.Close()
|
|
|
|
pi := SocialGroupMemberListPage{"Group Member List",user,headerVars,sgMembers,sgItem,0,0,extData}
|
|
// A plugin with plugins. Pluginception!
|
|
if pre_render_hooks["pre_render_socialgroups_member_list"] != nil {
|
|
if run_pre_render_hook("pre_render_socialgroups_member_list", w, r, &user, &pi) {
|
|
return
|
|
}
|
|
}
|
|
err = templates.ExecuteTemplate(w,"socialgroups_member_list.html", pi)
|
|
if err != nil {
|
|
InternalError(err,w)
|
|
}
|
|
}
|
|
|
|
func socialgroups_attach_forum(sgid int, fid int) error {
|
|
_, err := socialgroups_attach_forum_stmt.Exec(sgid,fid)
|
|
return err
|
|
}
|
|
|
|
func socialgroups_unattach_forum(fid int) error {
|
|
_, err := socialgroups_attach_forum_stmt.Exec(fid)
|
|
return err
|
|
}
|
|
|
|
func socialgroups_build_group_url(slug string, id int) string {
|
|
if slug == "" {
|
|
return "/group/" + slug + "." + strconv.Itoa(id)
|
|
}
|
|
return "/group/" + strconv.Itoa(id)
|
|
}
|
|
|
|
/*
|
|
Hooks
|
|
*/
|
|
|
|
func socialgroups_pre_render_view_forum(w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) {
|
|
pi := data.(*ForumPage)
|
|
if pi.Header.ExtData.items != nil {
|
|
if sgData, ok := pi.Header.ExtData.items["socialgroups_current_group"]; ok {
|
|
sgItem := sgData.(SocialGroup)
|
|
|
|
sgpi := SocialGroupPage{pi.Title,pi.CurrentUser,pi.Header,pi.ItemList,pi.Forum,sgItem,pi.Page,pi.LastPage,pi.ExtData}
|
|
err := templates.ExecuteTemplate(w,"socialgroups_view_group.html", sgpi)
|
|
if err != nil {
|
|
LogError(err)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func socialgroups_trow_assign(args ...interface{}) interface{} {
|
|
var forum *Forum = args[1].(*Forum)
|
|
if forum.ParentType == "socialgroup" {
|
|
var topicItem *TopicsRow = args[0].(*TopicsRow)
|
|
topicItem.ForumLink = "/group/" + strings.TrimPrefix(topicItem.ForumLink,get_forum_url_prefix())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// TO-DO: It would be nice, if you could select one of the boards in the group from that drop-down rather than just the one you got linked from
|
|
func socialgroups_topic_create_pre_loop(args ...interface{}) interface{} {
|
|
var fid int = args[2].(int)
|
|
if fstore.DirtyGet(fid).ParentType == "socialgroup" {
|
|
var strictmode *bool = args[5].(*bool)
|
|
*strictmode = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// TO-DO: Add privacy options
|
|
// TO-DO: Add support for multiple boards and add per-board simplified permissions
|
|
// TO-DO: Take is_js into account for routes which expect JSON responses
|
|
func socialgroups_forum_check(args ...interface{}) (skip interface{}) {
|
|
var r = args[1].(*http.Request)
|
|
var fid *int = args[3].(*int)
|
|
var forum *Forum = fstore.DirtyGet(*fid)
|
|
|
|
if forum.ParentType == "socialgroup" {
|
|
var err error
|
|
var w = args[0].(http.ResponseWriter)
|
|
var success *bool = args[4].(*bool)
|
|
sgItem, ok := r.Context().Value("socialgroups_current_group").(SocialGroup)
|
|
if !ok {
|
|
sgItem, err = socialgroups_get_group(forum.ParentID)
|
|
if err != nil {
|
|
InternalError(errors.New("Unable to find the parent group for a forum"),w)
|
|
*success = false
|
|
return false
|
|
}
|
|
if !sgItem.Active {
|
|
NotFound(w,r)
|
|
*success = false
|
|
return false
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(),"socialgroups_current_group",sgItem))
|
|
}
|
|
|
|
var user *User = args[2].(*User)
|
|
var rank int
|
|
var posts int
|
|
var joinedAt string
|
|
|
|
// TO-DO: Group privacy settings. For now, groups are all globally visible
|
|
|
|
// Clear the default group permissions
|
|
// TO-DO: Do this more efficiently, doing it quick and dirty for now to get this out quickly
|
|
override_forum_perms(&user.Perms, false)
|
|
user.Perms.ViewTopic = true
|
|
|
|
err = socialgroups_get_member_stmt.QueryRow(sgItem.ID,user.ID).Scan(&rank,&posts,&joinedAt)
|
|
if err != nil && err != ErrNoRows {
|
|
*success = false
|
|
InternalError(err,w)
|
|
return false
|
|
} else if err != nil {
|
|
return true
|
|
}
|
|
|
|
// TO-DO: Implement bans properly by adding the Local Ban API in the next commit
|
|
if rank < 0 {
|
|
return true
|
|
}
|
|
|
|
// Basic permissions for members, more complicated permissions coming in the next commit!
|
|
if sgItem.Owner == user.ID {
|
|
override_forum_perms(&user.Perms,true)
|
|
} else if rank == 0 {
|
|
user.Perms.LikeItem = true
|
|
user.Perms.CreateTopic = true
|
|
user.Perms.CreateReply = true
|
|
} else {
|
|
override_forum_perms(&user.Perms,true)
|
|
}
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// TO-DO: Override redirects? I don't think this is needed quite yet
|
|
|
|
func socialgroups_widgets(args ...interface{}) interface{} {
|
|
var zone string = args[0].(string)
|
|
var headerVars *HeaderVars = args[2].(*HeaderVars)
|
|
var request *http.Request = args[3].(*http.Request)
|
|
|
|
if zone != "view_forum" {
|
|
return false
|
|
}
|
|
|
|
var forum *Forum = args[1].(*Forum)
|
|
if forum.ParentType == "socialgroup" {
|
|
// This is why I hate using contexts, all the daisy chains and interface casts x.x
|
|
sgItem, ok := request.Context().Value("socialgroups_current_group").(SocialGroup)
|
|
if !ok {
|
|
LogError(errors.New("Unable to find a parent group in the context data"))
|
|
return false
|
|
}
|
|
|
|
if headerVars.ExtData.items == nil {
|
|
headerVars.ExtData.items = make(map[string]interface{})
|
|
}
|
|
headerVars.ExtData.items["socialgroups_current_group"] = sgItem
|
|
|
|
return socialgroups_group_widgets(headerVars,sgItem)
|
|
}
|
|
return false
|
|
}
|