Added proper pagination to the topic list.
Fixed two existence checks. Tweaked the profile CSS for Cosora. Added the TopicByReplyID function. Split off the profile logic from Reply into ProfileReply. Moved various hard-coded bits in the profile reply routes into ProfileReply. Moved four reply routes into /routes/reply.go Moved six topic routes into /routes/topic.go We should now capture more suspicious activity. Changed the definition of the revisions table.
This commit is contained in:
parent
ef839a601c
commit
2997135e80
|
@ -96,9 +96,7 @@ func buildAlert(asid int, event string, elementType string, actorID int, targetU
|
||||||
endFrag = "'s profile"
|
endFrag = "'s profile"
|
||||||
url = targetUser.Link
|
url = targetUser.Link
|
||||||
case "post":
|
case "post":
|
||||||
reply := common.BlankReply()
|
topic, err := common.TopicByReplyID(elementID)
|
||||||
reply.ID = elementID
|
|
||||||
topic, err := reply.Topic()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New("Unable to find the linked reply or parent topic")
|
return "", errors.New("Unable to find the linked reply or parent topic")
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,9 @@ type TopicsPage struct {
|
||||||
TopicList []*TopicsRow
|
TopicList []*TopicsRow
|
||||||
ForumList []Forum
|
ForumList []Forum
|
||||||
DefaultForum int
|
DefaultForum int
|
||||||
|
PageList []int
|
||||||
|
Page int
|
||||||
|
LastPage int
|
||||||
}
|
}
|
||||||
|
|
||||||
type ForumPage struct {
|
type ForumPage struct {
|
||||||
|
|
|
@ -353,9 +353,7 @@ func ParseMessage(msg string, sectionID int, sectionType string /*, user User*/)
|
||||||
rid, intLen := CoerceIntBytes(msgbytes[start:])
|
rid, intLen := CoerceIntBytes(msgbytes[start:])
|
||||||
i += intLen
|
i += intLen
|
||||||
|
|
||||||
reply := BlankReply()
|
topic, err := TopicByReplyID(rid)
|
||||||
reply.ID = rid
|
|
||||||
topic, err := reply.Topic()
|
|
||||||
if err != nil || !Forums.Exists(topic.ParentID) {
|
if err != nil || !Forums.Exists(topic.ParentID) {
|
||||||
outbytes = append(outbytes, InvalidTopic...)
|
outbytes = append(outbytes, InvalidTopic...)
|
||||||
lastItem = i
|
lastItem = i
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"html"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"../query_gen/lib"
|
||||||
|
)
|
||||||
|
|
||||||
|
var profileReplyStmts ProfileReplyStmts
|
||||||
|
|
||||||
|
type ProfileReply struct {
|
||||||
|
ID int
|
||||||
|
ParentID int
|
||||||
|
Content string
|
||||||
|
CreatedBy int
|
||||||
|
Group int
|
||||||
|
CreatedAt time.Time
|
||||||
|
RelativeCreatedAt string
|
||||||
|
LastEdit int
|
||||||
|
LastEditBy int
|
||||||
|
ContentLines int
|
||||||
|
IPAddress string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProfileReplyStmts struct {
|
||||||
|
edit *sql.Stmt
|
||||||
|
delete *sql.Stmt
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
DbInits.Add(func(acc *qgen.Accumulator) error {
|
||||||
|
profileReplyStmts = ProfileReplyStmts{
|
||||||
|
edit: acc.Update("users_replies").Set("content = ?, parsed_content = ?").Where("rid = ?").Prepare(),
|
||||||
|
delete: acc.Delete("users_replies").Where("rid = ?").Prepare(),
|
||||||
|
}
|
||||||
|
return acc.FirstError()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Write tests for this
|
||||||
|
func (reply *ProfileReply) Delete() error {
|
||||||
|
_, err := profileReplyStmts.delete.Exec(reply.ID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reply *ProfileReply) SetBody(content string) error {
|
||||||
|
content = PreparseMessage(html.UnescapeString(content))
|
||||||
|
parsedContent := ParseMessage(content, 0, "")
|
||||||
|
_, err := profileReplyStmts.edit.Exec(content, parsedContent, reply.ID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: We can get this from the topic store instead of a query which will always miss the cache...
|
||||||
|
func (reply *ProfileReply) Creator() (*User, error) {
|
||||||
|
return Users.Get(reply.CreatedBy)
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ import (
|
||||||
var Prstore ProfileReplyStore
|
var Prstore ProfileReplyStore
|
||||||
|
|
||||||
type ProfileReplyStore interface {
|
type ProfileReplyStore interface {
|
||||||
Get(id int) (*Reply, error)
|
Get(id int) (*ProfileReply, error)
|
||||||
Create(profileID int, content string, createdBy int, ipaddress string) (id int, err error)
|
Create(profileID int, content string, createdBy int, ipaddress string) (id int, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +28,8 @@ func NewSQLProfileReplyStore() (*SQLProfileReplyStore, error) {
|
||||||
}, acc.FirstError()
|
}, acc.FirstError()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *SQLProfileReplyStore) Get(id int) (*Reply, error) {
|
func (store *SQLProfileReplyStore) Get(id int) (*ProfileReply, error) {
|
||||||
reply := Reply{ID: id}
|
reply := ProfileReply{ID: id}
|
||||||
err := store.get.QueryRow(id).Scan(&reply.ParentID, &reply.Content, &reply.CreatedBy, &reply.CreatedAt, &reply.LastEdit, &reply.LastEditBy, &reply.IPAddress)
|
err := store.get.QueryRow(id).Scan(&reply.ParentID, &reply.Content, &reply.CreatedBy, &reply.CreatedAt, &reply.LastEdit, &reply.LastEditBy, &reply.IPAddress)
|
||||||
return &reply, err
|
return &reply, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ package common
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
"html"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"../query_gen/lib"
|
"../query_gen/lib"
|
||||||
|
@ -64,10 +65,10 @@ var replyStmts ReplyStmts
|
||||||
type ReplyStmts struct {
|
type ReplyStmts struct {
|
||||||
isLiked *sql.Stmt
|
isLiked *sql.Stmt
|
||||||
createLike *sql.Stmt
|
createLike *sql.Stmt
|
||||||
|
edit *sql.Stmt
|
||||||
delete *sql.Stmt
|
delete *sql.Stmt
|
||||||
addLikesToReply *sql.Stmt
|
addLikesToReply *sql.Stmt
|
||||||
removeRepliesFromTopic *sql.Stmt
|
removeRepliesFromTopic *sql.Stmt
|
||||||
getParent *sql.Stmt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -75,10 +76,10 @@ func init() {
|
||||||
replyStmts = ReplyStmts{
|
replyStmts = ReplyStmts{
|
||||||
isLiked: acc.Select("likes").Columns("targetItem").Where("sentBy = ? and targetItem = ? and targetType = 'replies'").Prepare(),
|
isLiked: acc.Select("likes").Columns("targetItem").Where("sentBy = ? and targetItem = ? and targetType = 'replies'").Prepare(),
|
||||||
createLike: acc.Insert("likes").Columns("weight, targetItem, targetType, sentBy").Fields("?,?,?,?").Prepare(),
|
createLike: acc.Insert("likes").Columns("weight, targetItem, targetType, sentBy").Fields("?,?,?,?").Prepare(),
|
||||||
|
edit: acc.Update("replies").Set("content = ?, parsed_content = ?").Where("rid = ?").Prepare(),
|
||||||
delete: acc.Delete("replies").Where("rid = ?").Prepare(),
|
delete: acc.Delete("replies").Where("rid = ?").Prepare(),
|
||||||
addLikesToReply: acc.Update("replies").Set("likeCount = likeCount + ?").Where("rid = ?").Prepare(),
|
addLikesToReply: acc.Update("replies").Set("likeCount = likeCount + ?").Where("rid = ?").Prepare(),
|
||||||
removeRepliesFromTopic: acc.Update("topics").Set("postCount = postCount - ?").Where("tid = ?").Prepare(),
|
removeRepliesFromTopic: acc.Update("topics").Set("postCount = postCount - ?").Where("tid = ?").Prepare(),
|
||||||
getParent: acc.SimpleLeftJoin("replies", "topics", "topics.tid, topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, topics.data", "replies.tid = topics.tid", "rid = ?", "", ""),
|
|
||||||
}
|
}
|
||||||
return acc.FirstError()
|
return acc.FirstError()
|
||||||
})
|
})
|
||||||
|
@ -119,22 +120,22 @@ func (reply *Reply) Delete() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (reply *Reply) SetBody(content string) error {
|
||||||
|
topic, err := reply.Topic()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
content = PreparseMessage(html.UnescapeString(content))
|
||||||
|
parsedContent := ParseMessage(content, topic.ParentID, "forums")
|
||||||
|
_, err = replyStmts.edit.Exec(content, parsedContent, reply.ID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (reply *Reply) Topic() (*Topic, error) {
|
func (reply *Reply) Topic() (*Topic, error) {
|
||||||
topic := Topic{ID: 0}
|
return Topics.Get(reply.ParentID)
|
||||||
err := replyStmts.getParent.QueryRow(reply.ID).Scan(&topic.ID, &topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
|
||||||
topic.Link = BuildTopicURL(NameToSlug(topic.Title), topic.ID)
|
|
||||||
return &topic, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy gives you a non-pointer concurrency safe copy of the reply
|
// Copy gives you a non-pointer concurrency safe copy of the reply
|
||||||
func (reply *Reply) Copy() Reply {
|
func (reply *Reply) Copy() Reply {
|
||||||
return *reply
|
return *reply
|
||||||
}
|
}
|
||||||
|
|
||||||
func BlankReply(ids ...int) *Reply {
|
|
||||||
var id int
|
|
||||||
if len(ids) != 0 {
|
|
||||||
id = ids[0]
|
|
||||||
}
|
|
||||||
return &Reply{ID: id}
|
|
||||||
}
|
|
||||||
|
|
|
@ -149,7 +149,7 @@ func compileTemplates() error {
|
||||||
|
|
||||||
var topicsList []*TopicsRow
|
var topicsList []*TopicsRow
|
||||||
topicsList = append(topicsList, &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, "Date", time.Now(), "Date", user3.ID, 1, "", "127.0.0.1", 0, 1, "classname", "", &user2, "", 0, &user3, "General", "/forum/general.2"})
|
topicsList = append(topicsList, &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, "Date", time.Now(), "Date", user3.ID, 1, "", "127.0.0.1", 0, 1, "classname", "", &user2, "", 0, &user3, "General", "/forum/general.2"})
|
||||||
topicsPage := TopicsPage{"Topic List", user, headerVars, topicsList, forumList, Config.DefaultForum}
|
topicsPage := TopicsPage{"Topic List", user, headerVars, topicsList, forumList, Config.DefaultForum, []int{1}, 1, 1}
|
||||||
topicsTmpl, err := c.Compile("topics.html", "templates/", "common.TopicsPage", topicsPage, varList)
|
topicsTmpl, err := c.Compile("topics.html", "templates/", "common.TopicsPage", topicsPage, varList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -123,6 +123,7 @@ type TopicStmts struct {
|
||||||
createActionReply *sql.Stmt
|
createActionReply *sql.Stmt
|
||||||
|
|
||||||
getTopicUser *sql.Stmt // TODO: Can we get rid of this?
|
getTopicUser *sql.Stmt // TODO: Can we get rid of this?
|
||||||
|
getByReplyID *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
var topicStmts TopicStmts
|
var topicStmts TopicStmts
|
||||||
|
@ -144,6 +145,7 @@ func init() {
|
||||||
createActionReply: acc.Insert("replies").Columns("tid, actionType, ipaddress, createdBy, createdAt, lastUpdated, content, parsed_content").Fields("?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'',''").Prepare(),
|
createActionReply: acc.Insert("replies").Columns("tid, actionType, ipaddress, createdBy, createdAt, lastUpdated, content, parsed_content").Fields("?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'',''").Prepare(),
|
||||||
|
|
||||||
getTopicUser: acc.SimpleLeftJoin("topics", "users", "topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level", "topics.createdBy = users.uid", "tid = ?", "", ""),
|
getTopicUser: acc.SimpleLeftJoin("topics", "users", "topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level", "topics.createdBy = users.uid", "tid = ?", "", ""),
|
||||||
|
getByReplyID: acc.SimpleLeftJoin("replies", "topics", "topics.tid, topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, topics.data", "replies.tid = topics.tid", "rid = ?", "", ""),
|
||||||
}
|
}
|
||||||
return acc.FirstError()
|
return acc.FirstError()
|
||||||
})
|
})
|
||||||
|
@ -272,6 +274,13 @@ func (topic *Topic) Copy() Topic {
|
||||||
return *topic
|
return *topic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TopicByReplyID(rid int) (*Topic, error) {
|
||||||
|
topic := Topic{ID: 0}
|
||||||
|
err := topicStmts.getByReplyID.QueryRow(rid).Scan(&topic.ID, &topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
|
||||||
|
topic.Link = BuildTopicURL(NameToSlug(topic.Title), topic.ID)
|
||||||
|
return &topic, err
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Refactor the caller to take a Topic and a User rather than a combined TopicUser
|
// TODO: Refactor the caller to take a Topic and a User rather than a combined TopicUser
|
||||||
func GetTopicUser(tid int) (TopicUser, error) {
|
func GetTopicUser(tid int) (TopicUser, error) {
|
||||||
tcache := Topics.GetCache()
|
tcache := Topics.GetCache()
|
||||||
|
|
32
gen_mssql.go
32
gen_mssql.go
|
@ -16,9 +16,7 @@ type Stmts struct {
|
||||||
getModlogs *sql.Stmt
|
getModlogs *sql.Stmt
|
||||||
getModlogsOffset *sql.Stmt
|
getModlogsOffset *sql.Stmt
|
||||||
getAdminlogsOffset *sql.Stmt
|
getAdminlogsOffset *sql.Stmt
|
||||||
getReplyTID *sql.Stmt
|
|
||||||
getTopicFID *sql.Stmt
|
getTopicFID *sql.Stmt
|
||||||
getUserReplyUID *sql.Stmt
|
|
||||||
getUserName *sql.Stmt
|
getUserName *sql.Stmt
|
||||||
getEmailsByUser *sql.Stmt
|
getEmailsByUser *sql.Stmt
|
||||||
getTopicBasic *sql.Stmt
|
getTopicBasic *sql.Stmt
|
||||||
|
@ -44,7 +42,6 @@ type Stmts struct {
|
||||||
addAttachment *sql.Stmt
|
addAttachment *sql.Stmt
|
||||||
createWordFilter *sql.Stmt
|
createWordFilter *sql.Stmt
|
||||||
editReply *sql.Stmt
|
editReply *sql.Stmt
|
||||||
editProfileReply *sql.Stmt
|
|
||||||
updatePlugin *sql.Stmt
|
updatePlugin *sql.Stmt
|
||||||
updatePluginInstall *sql.Stmt
|
updatePluginInstall *sql.Stmt
|
||||||
updateTheme *sql.Stmt
|
updateTheme *sql.Stmt
|
||||||
|
@ -56,7 +53,6 @@ type Stmts struct {
|
||||||
setTempGroup *sql.Stmt
|
setTempGroup *sql.Stmt
|
||||||
updateWordFilter *sql.Stmt
|
updateWordFilter *sql.Stmt
|
||||||
bumpSync *sql.Stmt
|
bumpSync *sql.Stmt
|
||||||
deleteProfileReply *sql.Stmt
|
|
||||||
deleteActivityStreamMatch *sql.Stmt
|
deleteActivityStreamMatch *sql.Stmt
|
||||||
deleteWordFilter *sql.Stmt
|
deleteWordFilter *sql.Stmt
|
||||||
reportExists *sql.Stmt
|
reportExists *sql.Stmt
|
||||||
|
@ -130,13 +126,6 @@ func _gen_mssql() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Preparing getReplyTID statement.")
|
|
||||||
stmts.getReplyTID, err = db.Prepare("SELECT [tid] FROM [replies] WHERE [rid] = ?1")
|
|
||||||
if err != nil {
|
|
||||||
log.Print("Bad Query: ","SELECT [tid] FROM [replies] WHERE [rid] = ?1")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing getTopicFID statement.")
|
log.Print("Preparing getTopicFID statement.")
|
||||||
stmts.getTopicFID, err = db.Prepare("SELECT [parentID] FROM [topics] WHERE [tid] = ?1")
|
stmts.getTopicFID, err = db.Prepare("SELECT [parentID] FROM [topics] WHERE [tid] = ?1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -144,13 +133,6 @@ func _gen_mssql() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Preparing getUserReplyUID statement.")
|
|
||||||
stmts.getUserReplyUID, err = db.Prepare("SELECT [uid] FROM [users_replies] WHERE [rid] = ?1")
|
|
||||||
if err != nil {
|
|
||||||
log.Print("Bad Query: ","SELECT [uid] FROM [users_replies] WHERE [rid] = ?1")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing getUserName statement.")
|
log.Print("Preparing getUserName statement.")
|
||||||
stmts.getUserName, err = db.Prepare("SELECT [name] FROM [users] WHERE [uid] = ?1")
|
stmts.getUserName, err = db.Prepare("SELECT [name] FROM [users] WHERE [uid] = ?1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -326,13 +308,6 @@ func _gen_mssql() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Preparing editProfileReply statement.")
|
|
||||||
stmts.editProfileReply, err = db.Prepare("UPDATE [users_replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?")
|
|
||||||
if err != nil {
|
|
||||||
log.Print("Bad Query: ","UPDATE [users_replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing updatePlugin statement.")
|
log.Print("Preparing updatePlugin statement.")
|
||||||
stmts.updatePlugin, err = db.Prepare("UPDATE [plugins] SET [active] = ? WHERE [uname] = ?")
|
stmts.updatePlugin, err = db.Prepare("UPDATE [plugins] SET [active] = ? WHERE [uname] = ?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -410,13 +385,6 @@ func _gen_mssql() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Preparing deleteProfileReply statement.")
|
|
||||||
stmts.deleteProfileReply, err = db.Prepare("DELETE FROM [users_replies] WHERE [rid] = ?")
|
|
||||||
if err != nil {
|
|
||||||
log.Print("Bad Query: ","DELETE FROM [users_replies] WHERE [rid] = ?")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing deleteActivityStreamMatch statement.")
|
log.Print("Preparing deleteActivityStreamMatch statement.")
|
||||||
stmts.deleteActivityStreamMatch, err = db.Prepare("DELETE FROM [activity_stream_matches] WHERE [watcher] = ? AND [asid] = ?")
|
stmts.deleteActivityStreamMatch, err = db.Prepare("DELETE FROM [activity_stream_matches] WHERE [watcher] = ? AND [asid] = ?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
28
gen_mysql.go
28
gen_mysql.go
|
@ -18,9 +18,7 @@ type Stmts struct {
|
||||||
getModlogs *sql.Stmt
|
getModlogs *sql.Stmt
|
||||||
getModlogsOffset *sql.Stmt
|
getModlogsOffset *sql.Stmt
|
||||||
getAdminlogsOffset *sql.Stmt
|
getAdminlogsOffset *sql.Stmt
|
||||||
getReplyTID *sql.Stmt
|
|
||||||
getTopicFID *sql.Stmt
|
getTopicFID *sql.Stmt
|
||||||
getUserReplyUID *sql.Stmt
|
|
||||||
getUserName *sql.Stmt
|
getUserName *sql.Stmt
|
||||||
getEmailsByUser *sql.Stmt
|
getEmailsByUser *sql.Stmt
|
||||||
getTopicBasic *sql.Stmt
|
getTopicBasic *sql.Stmt
|
||||||
|
@ -46,7 +44,6 @@ type Stmts struct {
|
||||||
addAttachment *sql.Stmt
|
addAttachment *sql.Stmt
|
||||||
createWordFilter *sql.Stmt
|
createWordFilter *sql.Stmt
|
||||||
editReply *sql.Stmt
|
editReply *sql.Stmt
|
||||||
editProfileReply *sql.Stmt
|
|
||||||
updatePlugin *sql.Stmt
|
updatePlugin *sql.Stmt
|
||||||
updatePluginInstall *sql.Stmt
|
updatePluginInstall *sql.Stmt
|
||||||
updateTheme *sql.Stmt
|
updateTheme *sql.Stmt
|
||||||
|
@ -58,7 +55,6 @@ type Stmts struct {
|
||||||
setTempGroup *sql.Stmt
|
setTempGroup *sql.Stmt
|
||||||
updateWordFilter *sql.Stmt
|
updateWordFilter *sql.Stmt
|
||||||
bumpSync *sql.Stmt
|
bumpSync *sql.Stmt
|
||||||
deleteProfileReply *sql.Stmt
|
|
||||||
deleteActivityStreamMatch *sql.Stmt
|
deleteActivityStreamMatch *sql.Stmt
|
||||||
deleteWordFilter *sql.Stmt
|
deleteWordFilter *sql.Stmt
|
||||||
reportExists *sql.Stmt
|
reportExists *sql.Stmt
|
||||||
|
@ -125,24 +121,12 @@ func _gen_mysql() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Preparing getReplyTID statement.")
|
|
||||||
stmts.getReplyTID, err = db.Prepare("SELECT `tid` FROM `replies` WHERE `rid` = ?")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing getTopicFID statement.")
|
log.Print("Preparing getTopicFID statement.")
|
||||||
stmts.getTopicFID, err = db.Prepare("SELECT `parentID` FROM `topics` WHERE `tid` = ?")
|
stmts.getTopicFID, err = db.Prepare("SELECT `parentID` FROM `topics` WHERE `tid` = ?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Preparing getUserReplyUID statement.")
|
|
||||||
stmts.getUserReplyUID, err = db.Prepare("SELECT `uid` FROM `users_replies` WHERE `rid` = ?")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing getUserName statement.")
|
log.Print("Preparing getUserName statement.")
|
||||||
stmts.getUserName, err = db.Prepare("SELECT `name` FROM `users` WHERE `uid` = ?")
|
stmts.getUserName, err = db.Prepare("SELECT `name` FROM `users` WHERE `uid` = ?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -293,12 +277,6 @@ func _gen_mysql() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Preparing editProfileReply statement.")
|
|
||||||
stmts.editProfileReply, err = db.Prepare("UPDATE `users_replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing updatePlugin statement.")
|
log.Print("Preparing updatePlugin statement.")
|
||||||
stmts.updatePlugin, err = db.Prepare("UPDATE `plugins` SET `active` = ? WHERE `uname` = ?")
|
stmts.updatePlugin, err = db.Prepare("UPDATE `plugins` SET `active` = ? WHERE `uname` = ?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -365,12 +343,6 @@ func _gen_mysql() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Preparing deleteProfileReply statement.")
|
|
||||||
stmts.deleteProfileReply, err = db.Prepare("DELETE FROM `users_replies` WHERE `rid` = ?")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing deleteActivityStreamMatch statement.")
|
log.Print("Preparing deleteActivityStreamMatch statement.")
|
||||||
stmts.deleteActivityStreamMatch, err = db.Prepare("DELETE FROM `activity_stream_matches` WHERE `watcher` = ? AND `asid` = ?")
|
stmts.deleteActivityStreamMatch, err = db.Prepare("DELETE FROM `activity_stream_matches` WHERE `watcher` = ? AND `asid` = ?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -10,7 +10,6 @@ import "./common"
|
||||||
// nolint
|
// nolint
|
||||||
type Stmts struct {
|
type Stmts struct {
|
||||||
editReply *sql.Stmt
|
editReply *sql.Stmt
|
||||||
editProfileReply *sql.Stmt
|
|
||||||
updatePlugin *sql.Stmt
|
updatePlugin *sql.Stmt
|
||||||
updatePluginInstall *sql.Stmt
|
updatePluginInstall *sql.Stmt
|
||||||
updateTheme *sql.Stmt
|
updateTheme *sql.Stmt
|
||||||
|
@ -48,12 +47,6 @@ func _gen_pgsql() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("Preparing editProfileReply statement.")
|
|
||||||
stmts.editProfileReply, err = db.Prepare("UPDATE `users_replies` SET `content` = ?,`parsed_content` = ? WHERE `rid` = ?")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print("Preparing updatePlugin statement.")
|
log.Print("Preparing updatePlugin statement.")
|
||||||
stmts.updatePlugin, err = db.Prepare("UPDATE `plugins` SET `active` = ? WHERE `uname` = ?")
|
stmts.updatePlugin, err = db.Prepare("UPDATE `plugins` SET `active` = ? WHERE `uname` = ?")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -85,21 +85,21 @@ var RouteMap = map[string]interface{}{
|
||||||
"routeIps": routeIps,
|
"routeIps": routeIps,
|
||||||
"routeTopicCreateSubmit": routeTopicCreateSubmit,
|
"routeTopicCreateSubmit": routeTopicCreateSubmit,
|
||||||
"routes.EditTopicSubmit": routes.EditTopicSubmit,
|
"routes.EditTopicSubmit": routes.EditTopicSubmit,
|
||||||
"routeDeleteTopicSubmit": routeDeleteTopicSubmit,
|
"routes.DeleteTopicSubmit": routes.DeleteTopicSubmit,
|
||||||
"routeStickTopicSubmit": routeStickTopicSubmit,
|
"routes.StickTopicSubmit": routes.StickTopicSubmit,
|
||||||
"routeUnstickTopicSubmit": routeUnstickTopicSubmit,
|
"routes.UnstickTopicSubmit": routes.UnstickTopicSubmit,
|
||||||
"routeLockTopicSubmit": routeLockTopicSubmit,
|
"routes.LockTopicSubmit": routes.LockTopicSubmit,
|
||||||
"routeUnlockTopicSubmit": routeUnlockTopicSubmit,
|
"routes.UnlockTopicSubmit": routes.UnlockTopicSubmit,
|
||||||
"routeMoveTopicSubmit": routeMoveTopicSubmit,
|
"routes.MoveTopicSubmit": routes.MoveTopicSubmit,
|
||||||
"routeLikeTopicSubmit": routeLikeTopicSubmit,
|
"routeLikeTopicSubmit": routeLikeTopicSubmit,
|
||||||
"routeTopicID": routeTopicID,
|
"routeTopicID": routeTopicID,
|
||||||
"routeCreateReplySubmit": routeCreateReplySubmit,
|
"routeCreateReplySubmit": routeCreateReplySubmit,
|
||||||
"routeReplyEditSubmit": routeReplyEditSubmit,
|
"routes.ReplyEditSubmit": routes.ReplyEditSubmit,
|
||||||
"routeReplyDeleteSubmit": routeReplyDeleteSubmit,
|
"routes.ReplyDeleteSubmit": routes.ReplyDeleteSubmit,
|
||||||
"routeReplyLikeSubmit": routeReplyLikeSubmit,
|
"routeReplyLikeSubmit": routeReplyLikeSubmit,
|
||||||
"routeProfileReplyCreateSubmit": routeProfileReplyCreateSubmit,
|
"routeProfileReplyCreateSubmit": routeProfileReplyCreateSubmit,
|
||||||
"routeProfileReplyEditSubmit": routeProfileReplyEditSubmit,
|
"routes.ProfileReplyEditSubmit": routes.ProfileReplyEditSubmit,
|
||||||
"routeProfileReplyDeleteSubmit": routeProfileReplyDeleteSubmit,
|
"routes.ProfileReplyDeleteSubmit": routes.ProfileReplyDeleteSubmit,
|
||||||
"routeLogin": routeLogin,
|
"routeLogin": routeLogin,
|
||||||
"routeRegister": routeRegister,
|
"routeRegister": routeRegister,
|
||||||
"routeLogout": routeLogout,
|
"routeLogout": routeLogout,
|
||||||
|
@ -180,21 +180,21 @@ var routeMapEnum = map[string]int{
|
||||||
"routeIps": 66,
|
"routeIps": 66,
|
||||||
"routeTopicCreateSubmit": 67,
|
"routeTopicCreateSubmit": 67,
|
||||||
"routes.EditTopicSubmit": 68,
|
"routes.EditTopicSubmit": 68,
|
||||||
"routeDeleteTopicSubmit": 69,
|
"routes.DeleteTopicSubmit": 69,
|
||||||
"routeStickTopicSubmit": 70,
|
"routes.StickTopicSubmit": 70,
|
||||||
"routeUnstickTopicSubmit": 71,
|
"routes.UnstickTopicSubmit": 71,
|
||||||
"routeLockTopicSubmit": 72,
|
"routes.LockTopicSubmit": 72,
|
||||||
"routeUnlockTopicSubmit": 73,
|
"routes.UnlockTopicSubmit": 73,
|
||||||
"routeMoveTopicSubmit": 74,
|
"routes.MoveTopicSubmit": 74,
|
||||||
"routeLikeTopicSubmit": 75,
|
"routeLikeTopicSubmit": 75,
|
||||||
"routeTopicID": 76,
|
"routeTopicID": 76,
|
||||||
"routeCreateReplySubmit": 77,
|
"routeCreateReplySubmit": 77,
|
||||||
"routeReplyEditSubmit": 78,
|
"routes.ReplyEditSubmit": 78,
|
||||||
"routeReplyDeleteSubmit": 79,
|
"routes.ReplyDeleteSubmit": 79,
|
||||||
"routeReplyLikeSubmit": 80,
|
"routeReplyLikeSubmit": 80,
|
||||||
"routeProfileReplyCreateSubmit": 81,
|
"routeProfileReplyCreateSubmit": 81,
|
||||||
"routeProfileReplyEditSubmit": 82,
|
"routes.ProfileReplyEditSubmit": 82,
|
||||||
"routeProfileReplyDeleteSubmit": 83,
|
"routes.ProfileReplyDeleteSubmit": 83,
|
||||||
"routeLogin": 84,
|
"routeLogin": 84,
|
||||||
"routeRegister": 85,
|
"routeRegister": 85,
|
||||||
"routeLogout": 86,
|
"routeLogout": 86,
|
||||||
|
@ -273,21 +273,21 @@ var reverseRouteMapEnum = map[int]string{
|
||||||
66: "routeIps",
|
66: "routeIps",
|
||||||
67: "routeTopicCreateSubmit",
|
67: "routeTopicCreateSubmit",
|
||||||
68: "routes.EditTopicSubmit",
|
68: "routes.EditTopicSubmit",
|
||||||
69: "routeDeleteTopicSubmit",
|
69: "routes.DeleteTopicSubmit",
|
||||||
70: "routeStickTopicSubmit",
|
70: "routes.StickTopicSubmit",
|
||||||
71: "routeUnstickTopicSubmit",
|
71: "routes.UnstickTopicSubmit",
|
||||||
72: "routeLockTopicSubmit",
|
72: "routes.LockTopicSubmit",
|
||||||
73: "routeUnlockTopicSubmit",
|
73: "routes.UnlockTopicSubmit",
|
||||||
74: "routeMoveTopicSubmit",
|
74: "routes.MoveTopicSubmit",
|
||||||
75: "routeLikeTopicSubmit",
|
75: "routeLikeTopicSubmit",
|
||||||
76: "routeTopicID",
|
76: "routeTopicID",
|
||||||
77: "routeCreateReplySubmit",
|
77: "routeCreateReplySubmit",
|
||||||
78: "routeReplyEditSubmit",
|
78: "routes.ReplyEditSubmit",
|
||||||
79: "routeReplyDeleteSubmit",
|
79: "routes.ReplyDeleteSubmit",
|
||||||
80: "routeReplyLikeSubmit",
|
80: "routeReplyLikeSubmit",
|
||||||
81: "routeProfileReplyCreateSubmit",
|
81: "routeProfileReplyCreateSubmit",
|
||||||
82: "routeProfileReplyEditSubmit",
|
82: "routes.ProfileReplyEditSubmit",
|
||||||
83: "routeProfileReplyDeleteSubmit",
|
83: "routes.ProfileReplyDeleteSubmit",
|
||||||
84: "routeLogin",
|
84: "routeLogin",
|
||||||
85: "routeRegister",
|
85: "routeRegister",
|
||||||
86: "routeLogout",
|
86: "routeLogout",
|
||||||
|
@ -395,9 +395,21 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
if len(req.URL.Path) == 0 || req.URL.Path[0] != '/' {
|
if len(req.URL.Path) == 0 || req.URL.Path[0] != '/' {
|
||||||
w.WriteHeader(405)
|
w.WriteHeader(405)
|
||||||
w.Write([]byte(""))
|
w.Write([]byte(""))
|
||||||
|
log.Print("Suspicious UA: ", req.UserAgent())
|
||||||
|
log.Print("Method: ", req.Method)
|
||||||
|
for key, value := range req.Header {
|
||||||
|
for _, vvalue := range value {
|
||||||
|
log.Print("Header '" + key + "': " + vvalue + "!!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Print("req.URL.Path: ", req.URL.Path)
|
||||||
|
log.Print("req.URL.RawQuery: ", req.URL.RawQuery)
|
||||||
|
log.Print("req.Referer(): ", req.Referer())
|
||||||
|
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if common.Dev.DebugMode {
|
||||||
// TODO: Cover more suspicious strings and at a lower layer than this
|
// TODO: Cover more suspicious strings and at a lower layer than this
|
||||||
for _, char := range req.URL.Path {
|
for _, char := range req.URL.Path {
|
||||||
if char != '&' && !(char > 44 && char < 58) && char != '=' && char != '?' && !(char > 64 && char < 91) && char != '\\' && char != '_' && !(char > 96 && char < 123) {
|
if char != '&' && !(char > 44 && char < 58) && char != '=' && char != '?' && !(char > 64 && char < 91) && char != '\\' && char != '_' && !(char > 96 && char < 123) {
|
||||||
|
@ -409,8 +421,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Print("req.URL.Path: ", req.URL.Path)
|
log.Print("req.URL.Path: ", req.URL.Path)
|
||||||
|
log.Print("req.URL.RawQuery: ", req.URL.RawQuery)
|
||||||
log.Print("req.Referer(): ", req.Referer())
|
log.Print("req.Referer(): ", req.Referer())
|
||||||
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if strings.Contains(req.URL.Path,"..") || strings.Contains(req.URL.Path,"--") {
|
if strings.Contains(req.URL.Path,"..") || strings.Contains(req.URL.Path,"--") {
|
||||||
|
@ -422,9 +436,11 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Print("req.URL.Path: ", req.URL.Path)
|
log.Print("req.URL.Path: ", req.URL.Path)
|
||||||
|
log.Print("req.URL.RawQuery: ", req.URL.RawQuery)
|
||||||
log.Print("req.Referer(): ", req.Referer())
|
log.Print("req.Referer(): ", req.Referer())
|
||||||
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var prefix, extraData string
|
var prefix, extraData string
|
||||||
prefix = req.URL.Path[0:strings.IndexByte(req.URL.Path[1:],'/') + 1]
|
prefix = req.URL.Path[0:strings.IndexByte(req.URL.Path[1:],'/') + 1]
|
||||||
|
@ -443,6 +459,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
log.Print("prefix: ", prefix)
|
log.Print("prefix: ", prefix)
|
||||||
log.Print("req.URL.Path: ", req.URL.Path)
|
log.Print("req.URL.Path: ", req.URL.Path)
|
||||||
|
log.Print("req.URL.RawQuery: ", req.URL.RawQuery)
|
||||||
log.Print("extraData: ", extraData)
|
log.Print("extraData: ", extraData)
|
||||||
log.Print("req.Referer(): ", req.Referer())
|
log.Print("req.Referer(): ", req.Referer())
|
||||||
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
||||||
|
@ -506,6 +523,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
log.Print("prefix: ", prefix)
|
log.Print("prefix: ", prefix)
|
||||||
log.Print("req.URL.Path: ", req.URL.Path)
|
log.Print("req.URL.Path: ", req.URL.Path)
|
||||||
|
log.Print("req.URL.RawQuery: ", req.URL.RawQuery)
|
||||||
log.Print("extraData: ", extraData)
|
log.Print("extraData: ", extraData)
|
||||||
log.Print("req.Referer(): ", req.Referer())
|
log.Print("req.Referer(): ", req.Referer())
|
||||||
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
||||||
|
@ -522,6 +540,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
log.Print("prefix: ", prefix)
|
log.Print("prefix: ", prefix)
|
||||||
log.Print("req.URL.Path: ", req.URL.Path)
|
log.Print("req.URL.Path: ", req.URL.Path)
|
||||||
|
log.Print("req.URL.RawQuery: ", req.URL.RawQuery)
|
||||||
log.Print("extraData: ", extraData)
|
log.Print("extraData: ", extraData)
|
||||||
log.Print("req.Referer(): ", req.Referer())
|
log.Print("req.Referer(): ", req.Referer())
|
||||||
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
||||||
|
@ -1155,7 +1174,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
req.URL.Path += extraData
|
req.URL.Path += extraData
|
||||||
common.RouteViewCounter.Bump(69)
|
common.RouteViewCounter.Bump(69)
|
||||||
err = routeDeleteTopicSubmit(w,req,user)
|
err = routes.DeleteTopicSubmit(w,req,user)
|
||||||
case "/topic/stick/submit/":
|
case "/topic/stick/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1170,7 +1189,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(70)
|
common.RouteViewCounter.Bump(70)
|
||||||
err = routeStickTopicSubmit(w,req,user,extraData)
|
err = routes.StickTopicSubmit(w,req,user,extraData)
|
||||||
case "/topic/unstick/submit/":
|
case "/topic/unstick/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1185,7 +1204,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(71)
|
common.RouteViewCounter.Bump(71)
|
||||||
err = routeUnstickTopicSubmit(w,req,user,extraData)
|
err = routes.UnstickTopicSubmit(w,req,user,extraData)
|
||||||
case "/topic/lock/submit/":
|
case "/topic/lock/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1201,7 +1220,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
req.URL.Path += extraData
|
req.URL.Path += extraData
|
||||||
common.RouteViewCounter.Bump(72)
|
common.RouteViewCounter.Bump(72)
|
||||||
err = routeLockTopicSubmit(w,req,user)
|
err = routes.LockTopicSubmit(w,req,user)
|
||||||
case "/topic/unlock/submit/":
|
case "/topic/unlock/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1216,7 +1235,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(73)
|
common.RouteViewCounter.Bump(73)
|
||||||
err = routeUnlockTopicSubmit(w,req,user,extraData)
|
err = routes.UnlockTopicSubmit(w,req,user,extraData)
|
||||||
case "/topic/move/submit/":
|
case "/topic/move/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1231,7 +1250,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(74)
|
common.RouteViewCounter.Bump(74)
|
||||||
err = routeMoveTopicSubmit(w,req,user,extraData)
|
err = routes.MoveTopicSubmit(w,req,user,extraData)
|
||||||
case "/topic/like/submit/":
|
case "/topic/like/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1290,7 +1309,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(78)
|
common.RouteViewCounter.Bump(78)
|
||||||
err = routeReplyEditSubmit(w,req,user,extraData)
|
err = routes.ReplyEditSubmit(w,req,user,extraData)
|
||||||
case "/reply/delete/submit/":
|
case "/reply/delete/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1305,7 +1324,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(79)
|
common.RouteViewCounter.Bump(79)
|
||||||
err = routeReplyDeleteSubmit(w,req,user,extraData)
|
err = routes.ReplyDeleteSubmit(w,req,user,extraData)
|
||||||
case "/reply/like/submit/":
|
case "/reply/like/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1356,7 +1375,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(82)
|
common.RouteViewCounter.Bump(82)
|
||||||
err = routeProfileReplyEditSubmit(w,req,user,extraData)
|
err = routes.ProfileReplyEditSubmit(w,req,user,extraData)
|
||||||
case "/profile/reply/delete/submit/":
|
case "/profile/reply/delete/submit/":
|
||||||
err = common.NoSessionMismatch(w,req,user)
|
err = common.NoSessionMismatch(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1371,7 +1390,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RouteViewCounter.Bump(83)
|
common.RouteViewCounter.Bump(83)
|
||||||
err = routeProfileReplyDeleteSubmit(w,req,user,extraData)
|
err = routes.ProfileReplyDeleteSubmit(w,req,user,extraData)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
router.handleError(err,w,req,user)
|
router.handleError(err,w,req,user)
|
||||||
|
|
498
mod_routes.go
498
mod_routes.go
|
@ -1,9 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"html"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
@ -11,501 +8,6 @@ import (
|
||||||
"./common"
|
"./common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Add support for soft-deletion and add a permission for hard delete in addition to the usual
|
|
||||||
// TODO: Disable stat updates in posts handled by plugin_guilds
|
|
||||||
func routeDeleteTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
|
||||||
// TODO: Move this to some sort of middleware
|
|
||||||
var tids []int
|
|
||||||
var isJs = false
|
|
||||||
if common.ReqIsJson(r) {
|
|
||||||
if r.Body == nil {
|
|
||||||
return common.PreErrorJS("No request body", w, r)
|
|
||||||
}
|
|
||||||
//log.Print("r.Body: ", r.Body)
|
|
||||||
err := json.NewDecoder(r.Body).Decode(&tids)
|
|
||||||
if err != nil {
|
|
||||||
//log.Print("parse err: ", err)
|
|
||||||
return common.PreErrorJS("We weren't able to parse your data", w, r)
|
|
||||||
}
|
|
||||||
isJs = true
|
|
||||||
} else {
|
|
||||||
tid, err := strconv.Atoi(r.URL.Path[len("/topic/delete/submit/"):])
|
|
||||||
if err != nil {
|
|
||||||
return common.PreError("The provided TopicID is not a valid number.", w, r)
|
|
||||||
}
|
|
||||||
tids = append(tids, tid)
|
|
||||||
}
|
|
||||||
if len(tids) == 0 {
|
|
||||||
return common.LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tid := range tids {
|
|
||||||
topic, err := common.Topics.Get(tid)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.PreErrorJSQ("The topic you tried to delete doesn't exist.", w, r, isJs)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add hooks to make use of headerLite
|
|
||||||
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
if !user.Perms.ViewTopic || !user.Perms.DeleteTopic {
|
|
||||||
return common.NoPermissionsJSQ(w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We might be able to handle this err better
|
|
||||||
err = topic.Delete()
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = common.ModLogs.Create("delete", tid, "topic", user.LastIP, user.ID)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ? - We might need to add soft-delete before we can do an action reply for this
|
|
||||||
/*_, err = stmts.createActionReply.Exec(tid,"delete",ipaddress,user.ID)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err,w,r,isJs)
|
|
||||||
}*/
|
|
||||||
|
|
||||||
log.Printf("Topic #%d was deleted by common.User #%d", tid, user.ID)
|
|
||||||
}
|
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func routeStickTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError {
|
|
||||||
tid, err := strconv.Atoi(stid)
|
|
||||||
if err != nil {
|
|
||||||
return common.PreError("The provided TopicID is not a valid number.", w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
topic, err := common.Topics.Get(tid)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.PreError("The topic you tried to pin doesn't exist.", w, r)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add hooks to make use of headerLite
|
|
||||||
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
if !user.Perms.ViewTopic || !user.Perms.PinTopic {
|
|
||||||
return common.NoPermissions(w, r, user)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = topic.Stick()
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = common.ModLogs.Create("stick", tid, "topic", user.LastIP, user.ID)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
err = topic.CreateActionReply("stick", user.LastIP, user)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func routeUnstickTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError {
|
|
||||||
tid, err := strconv.Atoi(stid)
|
|
||||||
if err != nil {
|
|
||||||
return common.PreError("The provided TopicID is not a valid number.", w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
topic, err := common.Topics.Get(tid)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.PreError("The topic you tried to unpin doesn't exist.", w, r)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add hooks to make use of headerLite
|
|
||||||
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
if !user.Perms.ViewTopic || !user.Perms.PinTopic {
|
|
||||||
return common.NoPermissions(w, r, user)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = topic.Unstick()
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = common.ModLogs.Create("unstick", tid, "topic", user.LastIP, user.ID)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
err = topic.CreateActionReply("unstick", user.LastIP, user)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func routeLockTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
|
||||||
// TODO: Move this to some sort of middleware
|
|
||||||
var tids []int
|
|
||||||
var isJs = false
|
|
||||||
if common.ReqIsJson(r) {
|
|
||||||
if r.Body == nil {
|
|
||||||
return common.PreErrorJS("No request body", w, r)
|
|
||||||
}
|
|
||||||
err := json.NewDecoder(r.Body).Decode(&tids)
|
|
||||||
if err != nil {
|
|
||||||
return common.PreErrorJS("We weren't able to parse your data", w, r)
|
|
||||||
}
|
|
||||||
isJs = true
|
|
||||||
} else {
|
|
||||||
tid, err := strconv.Atoi(r.URL.Path[len("/topic/lock/submit/"):])
|
|
||||||
if err != nil {
|
|
||||||
return common.PreError("The provided TopicID is not a valid number.", w, r)
|
|
||||||
}
|
|
||||||
tids = append(tids, tid)
|
|
||||||
}
|
|
||||||
if len(tids) == 0 {
|
|
||||||
return common.LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tid := range tids {
|
|
||||||
topic, err := common.Topics.Get(tid)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.PreErrorJSQ("The topic you tried to lock doesn't exist.", w, r, isJs)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add hooks to make use of headerLite
|
|
||||||
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
if !user.Perms.ViewTopic || !user.Perms.CloseTopic {
|
|
||||||
return common.NoPermissionsJSQ(w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = topic.Lock()
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = common.ModLogs.Create("lock", tid, "topic", user.LastIP, user.ID)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
err = topic.CreateActionReply("lock", user.LastIP, user)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(tids) == 1 {
|
|
||||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tids[0]), http.StatusSeeOther)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func routeUnlockTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError {
|
|
||||||
tid, err := strconv.Atoi(stid)
|
|
||||||
if err != nil {
|
|
||||||
return common.PreError("The provided TopicID is not a valid number.", w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
topic, err := common.Topics.Get(tid)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.PreError("The topic you tried to unlock doesn't exist.", w, r)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add hooks to make use of headerLite
|
|
||||||
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
if !user.Perms.ViewTopic || !user.Perms.CloseTopic {
|
|
||||||
return common.NoPermissions(w, r, user)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = topic.Unlock()
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = common.ModLogs.Create("unlock", tid, "topic", user.LastIP, user.ID)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
err = topic.CreateActionReply("unlock", user.LastIP, user)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ! JS only route
|
|
||||||
// TODO: Figure a way to get this route to work without JS
|
|
||||||
func routeMoveTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError {
|
|
||||||
fid, err := strconv.Atoi(sfid)
|
|
||||||
if err != nil {
|
|
||||||
return common.PreErrorJS("The provided Forum ID is not a valid number.", w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Move this to some sort of middleware
|
|
||||||
var tids []int
|
|
||||||
if r.Body == nil {
|
|
||||||
return common.PreErrorJS("No request body", w, r)
|
|
||||||
}
|
|
||||||
err = json.NewDecoder(r.Body).Decode(&tids)
|
|
||||||
if err != nil {
|
|
||||||
return common.PreErrorJS("We weren't able to parse your data", w, r)
|
|
||||||
}
|
|
||||||
if len(tids) == 0 {
|
|
||||||
return common.LocalErrorJS("You haven't provided any IDs", w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tid := range tids {
|
|
||||||
topic, err := common.Topics.Get(tid)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.PreErrorJS("The topic you tried to move doesn't exist.", w, r)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalErrorJS(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add hooks to make use of headerLite
|
|
||||||
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
if !user.Perms.ViewTopic || !user.Perms.MoveTopic {
|
|
||||||
return common.NoPermissionsJS(w, r, user)
|
|
||||||
}
|
|
||||||
_, ferr = common.SimpleForumUserCheck(w, r, &user, fid)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
if !user.Perms.ViewTopic || !user.Perms.MoveTopic {
|
|
||||||
return common.NoPermissionsJS(w, r, user)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = topic.MoveTo(fid)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJS(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Log more data so we can list the destination forum in the action post?
|
|
||||||
err = common.ModLogs.Create("move", tid, "topic", user.LastIP, user.ID)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJS(err, w, r)
|
|
||||||
}
|
|
||||||
err = topic.CreateActionReply("move", user.LastIP, user)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJS(err, w, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(tids) == 1 {
|
|
||||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tids[0]), http.StatusSeeOther)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Disable stat updates in posts handled by plugin_guilds
|
|
||||||
// TODO: Update the stats after edits so that we don't under or over decrement stats during deletes
|
|
||||||
func routeReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError {
|
|
||||||
isJs := (r.PostFormValue("js") == "1")
|
|
||||||
|
|
||||||
rid, err := strconv.Atoi(srid)
|
|
||||||
if err != nil {
|
|
||||||
return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the Reply ID..
|
|
||||||
var tid int
|
|
||||||
err = stmts.getReplyTID.QueryRow(rid).Scan(&tid)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
var fid int
|
|
||||||
err = stmts.getTopicFID.QueryRow(tid).Scan(&fid)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add hooks to make use of headerLite
|
|
||||||
_, ferr := common.SimpleForumUserCheck(w, r, &user, fid)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
if !user.Perms.ViewTopic || !user.Perms.EditReply {
|
|
||||||
return common.NoPermissionsJSQ(w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
content := common.PreparseMessage(html.UnescapeString(r.PostFormValue("edit_item")))
|
|
||||||
_, err = stmts.editReply.Exec(content, common.ParseMessage(content, fid, "forums"), rid)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isJs {
|
|
||||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
|
||||||
} else {
|
|
||||||
w.Write(successJSONBytes)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Refactor this
|
|
||||||
// TODO: Disable stat updates in posts handled by plugin_guilds
|
|
||||||
func routeReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError {
|
|
||||||
isJs := (r.PostFormValue("isJs") == "1")
|
|
||||||
|
|
||||||
rid, err := strconv.Atoi(srid)
|
|
||||||
if err != nil {
|
|
||||||
return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
reply, err := common.Rstore.Get(rid)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.PreErrorJSQ("The reply you tried to delete doesn't exist.", w, r, isJs)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
var fid int
|
|
||||||
err = stmts.getTopicFID.QueryRow(reply.ParentID).Scan(&fid)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add hooks to make use of headerLite
|
|
||||||
_, ferr := common.SimpleForumUserCheck(w, r, &user, fid)
|
|
||||||
if ferr != nil {
|
|
||||||
return ferr
|
|
||||||
}
|
|
||||||
if !user.Perms.ViewTopic || !user.Perms.DeleteReply {
|
|
||||||
return common.NoPermissionsJSQ(w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = reply.Delete()
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
//log.Printf("Reply #%d was deleted by common.User #%d", rid, user.ID)
|
|
||||||
if !isJs {
|
|
||||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(reply.ParentID), http.StatusSeeOther)
|
|
||||||
} else {
|
|
||||||
w.Write(successJSONBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
replyCreator, err := common.Users.Get(reply.CreatedBy)
|
|
||||||
if err == nil {
|
|
||||||
wcount := common.WordCount(reply.Content)
|
|
||||||
err = replyCreator.DecreasePostStats(wcount, false)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
} else if err != ErrNoRows {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = common.ModLogs.Create("delete", reply.ParentID, "reply", user.LastIP, user.ID)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func routeProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError {
|
|
||||||
isJs := (r.PostFormValue("js") == "1")
|
|
||||||
|
|
||||||
rid, err := strconv.Atoi(srid)
|
|
||||||
if err != nil {
|
|
||||||
return common.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the Reply ID..
|
|
||||||
var uid int
|
|
||||||
err = stmts.getUserReplyUID.QueryRow(rid).Scan(&uid)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.ID != uid && !user.Perms.EditReply {
|
|
||||||
return common.NoPermissionsJSQ(w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
content := common.PreparseMessage(html.UnescapeString(r.PostFormValue("edit_item")))
|
|
||||||
_, err = stmts.editProfileReply.Exec(content, common.ParseMessage(content, 0, ""), rid)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isJs {
|
|
||||||
http.Redirect(w, r, "/user/"+strconv.Itoa(uid)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
|
||||||
} else {
|
|
||||||
w.Write(successJSONBytes)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func routeProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError {
|
|
||||||
isJs := (r.PostFormValue("isJs") == "1")
|
|
||||||
|
|
||||||
rid, err := strconv.Atoi(srid)
|
|
||||||
if err != nil {
|
|
||||||
return common.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
var uid int
|
|
||||||
err = stmts.getUserReplyUID.QueryRow(rid).Scan(&uid)
|
|
||||||
if err == ErrNoRows {
|
|
||||||
return common.LocalErrorJSQ("The reply you tried to delete doesn't exist.", w, r, user, isJs)
|
|
||||||
} else if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.ID != uid && !user.Perms.DeleteReply {
|
|
||||||
return common.NoPermissionsJSQ(w, r, user, isJs)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = stmts.deleteProfileReply.Exec(rid)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalErrorJSQ(err, w, r, isJs)
|
|
||||||
}
|
|
||||||
//log.Printf("The profile post '%d' was deleted by common.User #%d", rid, user.ID)
|
|
||||||
|
|
||||||
if !isJs {
|
|
||||||
//http.Redirect(w,r, "/user/" + strconv.Itoa(uid), http.StatusSeeOther)
|
|
||||||
} else {
|
|
||||||
w.Write(successJSONBytes)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func routeIps(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
func routeIps(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||||
headerVars, ferr := common.UserCheck(w, r, &user)
|
headerVars, ferr := common.UserCheck(w, r, &user)
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
|
|
|
@ -2236,7 +2236,7 @@ func modlogsElementType(action string, elementType string, elementID int, actor
|
||||||
out = fmt.Sprintf(out, targetUser.Link, targetUser.Name, actor.Link, actor.Name)
|
out = fmt.Sprintf(out, targetUser.Link, targetUser.Name, actor.Link, actor.Name)
|
||||||
case "reply":
|
case "reply":
|
||||||
if action == "delete" {
|
if action == "delete" {
|
||||||
topic := handleUnknownTopic(common.BlankReply(elementID).Topic())
|
topic := handleUnknownTopic(common.TopicByReplyID(elementID))
|
||||||
out = fmt.Sprintf("A reply in <a href='%s'>%s</a> was deleted by <a href='%s'>%s</a>", topic.Link, topic.Title, actor.Link, actor.Name)
|
out = fmt.Sprintf("A reply in <a href='%s'>%s</a> was deleted by <a href='%s'>%s</a>", topic.Link, topic.Title, actor.Link, actor.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,12 +233,8 @@ func writeSelects(adapter qgen.Adapter) error {
|
||||||
|
|
||||||
build.Select("getAdminlogsOffset").Table("administration_logs").Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Orderby("doneAt DESC").Limit("?,?").Parse()
|
build.Select("getAdminlogsOffset").Table("administration_logs").Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Orderby("doneAt DESC").Limit("?,?").Parse()
|
||||||
|
|
||||||
build.Select("getReplyTID").Table("replies").Columns("tid").Where("rid = ?").Parse()
|
|
||||||
|
|
||||||
build.Select("getTopicFID").Table("topics").Columns("parentID").Where("tid = ?").Parse()
|
build.Select("getTopicFID").Table("topics").Columns("parentID").Where("tid = ?").Parse()
|
||||||
|
|
||||||
build.Select("getUserReplyUID").Table("users_replies").Columns("uid").Where("rid = ?").Parse()
|
|
||||||
|
|
||||||
build.Select("getUserName").Table("users").Columns("name").Where("uid = ?").Parse()
|
build.Select("getUserName").Table("users").Columns("name").Where("uid = ?").Parse()
|
||||||
|
|
||||||
build.Select("getEmailsByUser").Table("emails").Columns("email, validated, token").Where("uid = ?").Parse()
|
build.Select("getEmailsByUser").Table("emails").Columns("email, validated, token").Where("uid = ?").Parse()
|
||||||
|
@ -312,8 +308,6 @@ func writeUpdates(adapter qgen.Adapter) error {
|
||||||
|
|
||||||
build.Update("editReply").Table("replies").Set("content = ?, parsed_content = ?").Where("rid = ?").Parse()
|
build.Update("editReply").Table("replies").Set("content = ?, parsed_content = ?").Where("rid = ?").Parse()
|
||||||
|
|
||||||
build.Update("editProfileReply").Table("users_replies").Set("content = ?, parsed_content = ?").Where("rid = ?").Parse()
|
|
||||||
|
|
||||||
build.Update("updatePlugin").Table("plugins").Set("active = ?").Where("uname = ?").Parse()
|
build.Update("updatePlugin").Table("plugins").Set("active = ?").Where("uname = ?").Parse()
|
||||||
|
|
||||||
build.Update("updatePluginInstall").Table("plugins").Set("installed = ?").Where("uname = ?").Parse()
|
build.Update("updatePluginInstall").Table("plugins").Set("installed = ?").Where("uname = ?").Parse()
|
||||||
|
@ -342,8 +336,6 @@ func writeUpdates(adapter qgen.Adapter) error {
|
||||||
func writeDeletes(adapter qgen.Adapter) error {
|
func writeDeletes(adapter qgen.Adapter) error {
|
||||||
build := adapter.Builder()
|
build := adapter.Builder()
|
||||||
|
|
||||||
build.Delete("deleteProfileReply").Table("users_replies").Where("rid = ?").Parse()
|
|
||||||
|
|
||||||
//build.Delete("deleteForumPermsByForum").Table("forums_permissions").Where("fid = ?").Parse()
|
//build.Delete("deleteForumPermsByForum").Table("forums_permissions").Where("fid = ?").Parse()
|
||||||
|
|
||||||
build.Delete("deleteActivityStreamMatch").Table("activity_stream_matches").Where("watcher = ? AND asid = ?").Parse()
|
build.Delete("deleteActivityStreamMatch").Table("activity_stream_matches").Where("watcher = ? AND asid = ?").Parse()
|
||||||
|
|
|
@ -207,10 +207,11 @@ func createTables(adapter qgen.Adapter) error {
|
||||||
|
|
||||||
qgen.Install.CreateTable("revisions", "utf8mb4", "utf8mb4_general_ci",
|
qgen.Install.CreateTable("revisions", "utf8mb4", "utf8mb4_general_ci",
|
||||||
[]qgen.DBTableColumn{
|
[]qgen.DBTableColumn{
|
||||||
qgen.DBTableColumn{"index", "int", 0, false, false, ""}, // TODO: Replace this with a proper revision ID x.x
|
qgen.DBTableColumn{"reviseID", "int", 0, false, true, ""},
|
||||||
qgen.DBTableColumn{"content", "text", 0, false, false, ""},
|
qgen.DBTableColumn{"content", "text", 0, false, false, ""},
|
||||||
qgen.DBTableColumn{"contentID", "int", 0, false, false, ""},
|
qgen.DBTableColumn{"contentID", "int", 0, false, false, ""},
|
||||||
qgen.DBTableColumn{"contentType", "varchar", 100, false, false, "replies"},
|
qgen.DBTableColumn{"contentType", "varchar", 100, false, false, "replies"},
|
||||||
|
qgen.DBTableColumn{"createdAt", "createdAt", 0, false, false, ""},
|
||||||
},
|
},
|
||||||
[]qgen.DBTableKey{},
|
[]qgen.DBTableKey{},
|
||||||
)
|
)
|
||||||
|
|
|
@ -279,9 +279,21 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
if len(req.URL.Path) == 0 || req.URL.Path[0] != '/' {
|
if len(req.URL.Path) == 0 || req.URL.Path[0] != '/' {
|
||||||
w.WriteHeader(405)
|
w.WriteHeader(405)
|
||||||
w.Write([]byte(""))
|
w.Write([]byte(""))
|
||||||
|
log.Print("Suspicious UA: ", req.UserAgent())
|
||||||
|
log.Print("Method: ", req.Method)
|
||||||
|
for key, value := range req.Header {
|
||||||
|
for _, vvalue := range value {
|
||||||
|
log.Print("Header '" + key + "': " + vvalue + "!!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Print("req.URL.Path: ", req.URL.Path)
|
||||||
|
log.Print("req.URL.RawQuery: ", req.URL.RawQuery)
|
||||||
|
log.Print("req.Referer(): ", req.Referer())
|
||||||
|
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if common.Dev.DebugMode {
|
||||||
// TODO: Cover more suspicious strings and at a lower layer than this
|
// TODO: Cover more suspicious strings and at a lower layer than this
|
||||||
for _, char := range req.URL.Path {
|
for _, char := range req.URL.Path {
|
||||||
if char != '&' && !(char > 44 && char < 58) && char != '=' && char != '?' && !(char > 64 && char < 91) && char != '\\' && char != '_' && !(char > 96 && char < 123) {
|
if char != '&' && !(char > 44 && char < 58) && char != '=' && char != '?' && !(char > 64 && char < 91) && char != '\\' && char != '_' && !(char > 96 && char < 123) {
|
||||||
|
@ -293,8 +305,10 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Print("req.URL.Path: ", req.URL.Path)
|
log.Print("req.URL.Path: ", req.URL.Path)
|
||||||
|
log.Print("req.URL.RawQuery: ", req.URL.RawQuery)
|
||||||
log.Print("req.Referer(): ", req.Referer())
|
log.Print("req.Referer(): ", req.Referer())
|
||||||
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if strings.Contains(req.URL.Path,"..") || strings.Contains(req.URL.Path,"--") {
|
if strings.Contains(req.URL.Path,"..") || strings.Contains(req.URL.Path,"--") {
|
||||||
|
@ -306,9 +320,11 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Print("req.URL.Path: ", req.URL.Path)
|
log.Print("req.URL.Path: ", req.URL.Path)
|
||||||
|
log.Print("req.URL.RawQuery: ", req.URL.RawQuery)
|
||||||
log.Print("req.Referer(): ", req.Referer())
|
log.Print("req.Referer(): ", req.Referer())
|
||||||
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var prefix, extraData string
|
var prefix, extraData string
|
||||||
prefix = req.URL.Path[0:strings.IndexByte(req.URL.Path[1:],'/') + 1]
|
prefix = req.URL.Path[0:strings.IndexByte(req.URL.Path[1:],'/') + 1]
|
||||||
|
@ -327,6 +343,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
log.Print("prefix: ", prefix)
|
log.Print("prefix: ", prefix)
|
||||||
log.Print("req.URL.Path: ", req.URL.Path)
|
log.Print("req.URL.Path: ", req.URL.Path)
|
||||||
|
log.Print("req.URL.RawQuery: ", req.URL.RawQuery)
|
||||||
log.Print("extraData: ", extraData)
|
log.Print("extraData: ", extraData)
|
||||||
log.Print("req.Referer(): ", req.Referer())
|
log.Print("req.Referer(): ", req.Referer())
|
||||||
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
||||||
|
@ -390,6 +407,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
log.Print("prefix: ", prefix)
|
log.Print("prefix: ", prefix)
|
||||||
log.Print("req.URL.Path: ", req.URL.Path)
|
log.Print("req.URL.Path: ", req.URL.Path)
|
||||||
|
log.Print("req.URL.RawQuery: ", req.URL.RawQuery)
|
||||||
log.Print("extraData: ", extraData)
|
log.Print("extraData: ", extraData)
|
||||||
log.Print("req.Referer(): ", req.Referer())
|
log.Print("req.Referer(): ", req.Referer())
|
||||||
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
||||||
|
@ -406,6 +424,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
log.Print("prefix: ", prefix)
|
log.Print("prefix: ", prefix)
|
||||||
log.Print("req.URL.Path: ", req.URL.Path)
|
log.Print("req.URL.Path: ", req.URL.Path)
|
||||||
|
log.Print("req.URL.RawQuery: ", req.URL.RawQuery)
|
||||||
log.Print("extraData: ", extraData)
|
log.Print("extraData: ", extraData)
|
||||||
log.Print("req.Referer(): ", req.Referer())
|
log.Print("req.Referer(): ", req.Referer())
|
||||||
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
log.Print("req.RemoteAddr: ", req.RemoteAddr)
|
||||||
|
|
|
@ -67,12 +67,12 @@ func buildTopicRoutes() {
|
||||||
View("routeTopicID", "/topic/", "extraData"),
|
View("routeTopicID", "/topic/", "extraData"),
|
||||||
Action("routeTopicCreateSubmit", "/topic/create/submit/"),
|
Action("routeTopicCreateSubmit", "/topic/create/submit/"),
|
||||||
Action("routes.EditTopicSubmit", "/topic/edit/submit/", "extraData"),
|
Action("routes.EditTopicSubmit", "/topic/edit/submit/", "extraData"),
|
||||||
Action("routeDeleteTopicSubmit", "/topic/delete/submit/").LitBefore("req.URL.Path += extraData"),
|
Action("routes.DeleteTopicSubmit", "/topic/delete/submit/").LitBefore("req.URL.Path += extraData"),
|
||||||
Action("routeStickTopicSubmit", "/topic/stick/submit/", "extraData"),
|
Action("routes.StickTopicSubmit", "/topic/stick/submit/", "extraData"),
|
||||||
Action("routeUnstickTopicSubmit", "/topic/unstick/submit/", "extraData"),
|
Action("routes.UnstickTopicSubmit", "/topic/unstick/submit/", "extraData"),
|
||||||
Action("routeLockTopicSubmit", "/topic/lock/submit/").LitBefore("req.URL.Path += extraData"),
|
Action("routes.LockTopicSubmit", "/topic/lock/submit/").LitBefore("req.URL.Path += extraData"),
|
||||||
Action("routeUnlockTopicSubmit", "/topic/unlock/submit/", "extraData"),
|
Action("routes.UnlockTopicSubmit", "/topic/unlock/submit/", "extraData"),
|
||||||
Action("routeMoveTopicSubmit", "/topic/move/submit/", "extraData"),
|
Action("routes.MoveTopicSubmit", "/topic/move/submit/", "extraData"),
|
||||||
Action("routeLikeTopicSubmit", "/topic/like/submit/", "extraData"),
|
Action("routeLikeTopicSubmit", "/topic/like/submit/", "extraData"),
|
||||||
)
|
)
|
||||||
addRouteGroup(topicGroup)
|
addRouteGroup(topicGroup)
|
||||||
|
@ -85,8 +85,8 @@ func buildReplyRoutes() {
|
||||||
replyGroup.Routes(
|
replyGroup.Routes(
|
||||||
// TODO: Reduce this to 1MB for attachments for each file?
|
// TODO: Reduce this to 1MB for attachments for each file?
|
||||||
UploadAction("routeCreateReplySubmit", "/reply/create/").MaxSizeVar("common.Config.MaxRequestSize"), // TODO: Rename the route so it's /reply/create/submit/
|
UploadAction("routeCreateReplySubmit", "/reply/create/").MaxSizeVar("common.Config.MaxRequestSize"), // TODO: Rename the route so it's /reply/create/submit/
|
||||||
Action("routeReplyEditSubmit", "/reply/edit/submit/", "extraData"),
|
Action("routes.ReplyEditSubmit", "/reply/edit/submit/", "extraData"),
|
||||||
Action("routeReplyDeleteSubmit", "/reply/delete/submit/", "extraData"),
|
Action("routes.ReplyDeleteSubmit", "/reply/delete/submit/", "extraData"),
|
||||||
Action("routeReplyLikeSubmit", "/reply/like/submit/", "extraData"),
|
Action("routeReplyLikeSubmit", "/reply/like/submit/", "extraData"),
|
||||||
)
|
)
|
||||||
addRouteGroup(replyGroup)
|
addRouteGroup(replyGroup)
|
||||||
|
@ -98,8 +98,8 @@ func buildProfileReplyRoutes() {
|
||||||
pReplyGroup := newRouteGroup("/profile/")
|
pReplyGroup := newRouteGroup("/profile/")
|
||||||
pReplyGroup.Routes(
|
pReplyGroup.Routes(
|
||||||
Action("routeProfileReplyCreateSubmit", "/profile/reply/create/"), // TODO: Add /submit/ to the end
|
Action("routeProfileReplyCreateSubmit", "/profile/reply/create/"), // TODO: Add /submit/ to the end
|
||||||
Action("routeProfileReplyEditSubmit", "/profile/reply/edit/submit/", "extraData"),
|
Action("routes.ProfileReplyEditSubmit", "/profile/reply/edit/submit/", "extraData"),
|
||||||
Action("routeProfileReplyDeleteSubmit", "/profile/reply/delete/submit/", "extraData"),
|
Action("routes.ProfileReplyDeleteSubmit", "/profile/reply/delete/submit/", "extraData"),
|
||||||
)
|
)
|
||||||
addRouteGroup(pReplyGroup)
|
addRouteGroup(pReplyGroup)
|
||||||
}
|
}
|
||||||
|
|
16
routes.go
16
routes.go
|
@ -179,18 +179,7 @@ func routeTopics(w http.ResponseWriter, r *http.Request, user common.User) commo
|
||||||
|
|
||||||
// Get the current page
|
// Get the current page
|
||||||
page, _ := strconv.Atoi(r.FormValue("page"))
|
page, _ := strconv.Atoi(r.FormValue("page"))
|
||||||
|
offset, page, lastPage := common.PageOffset(topicCount, page, common.Config.ItemsPerPage)
|
||||||
// Calculate the offset
|
|
||||||
var offset int
|
|
||||||
lastPage := (topicCount / common.Config.ItemsPerPage) + 1
|
|
||||||
if page > 1 {
|
|
||||||
offset = (common.Config.ItemsPerPage * page) - common.Config.ItemsPerPage
|
|
||||||
} else if page == -1 {
|
|
||||||
page = lastPage
|
|
||||||
offset = (common.Config.ItemsPerPage * page) - common.Config.ItemsPerPage
|
|
||||||
} else {
|
|
||||||
page = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
var topicList []*common.TopicsRow
|
var topicList []*common.TopicsRow
|
||||||
stmt, err := qgen.Builder.SimpleSelect("topics", "tid, title, content, createdBy, is_closed, sticky, createdAt, lastReplyAt, lastReplyBy, parentID, postCount, likeCount", "parentID IN("+qlist+")", "sticky DESC, lastReplyAt DESC, createdBy DESC", "?,?")
|
stmt, err := qgen.Builder.SimpleSelect("topics", "tid, title, content, createdBy, is_closed, sticky, createdAt, lastReplyAt, lastReplyBy, parentID, postCount, likeCount", "parentID IN("+qlist+")", "sticky DESC, lastReplyAt DESC, createdBy DESC", "?,?")
|
||||||
|
@ -258,7 +247,8 @@ func routeTopics(w http.ResponseWriter, r *http.Request, user common.User) commo
|
||||||
topicItem.LastUser = userList[topicItem.LastReplyBy]
|
topicItem.LastUser = userList[topicItem.LastReplyBy]
|
||||||
}
|
}
|
||||||
|
|
||||||
pi := common.TopicsPage{common.GetTitlePhrase("topics"), user, headerVars, topicList, forumList, common.Config.DefaultForum}
|
pageList := common.Paginate(topicCount, common.Config.ItemsPerPage, 5)
|
||||||
|
pi := common.TopicsPage{common.GetTitlePhrase("topics"), user, headerVars, topicList, forumList, common.Config.DefaultForum, pageList, page, lastPage}
|
||||||
if common.PreRenderHooks["pre_render_topic_list"] != nil {
|
if common.PreRenderHooks["pre_render_topic_list"] != nil {
|
||||||
if common.RunPreRenderHook("pre_render_topic_list", w, r, &user, &pi) {
|
if common.RunPreRenderHook("pre_render_topic_list", w, r, &user, &pi) {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"../common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: Disable stat updates in posts handled by plugin_guilds
|
||||||
|
// TODO: Update the stats after edits so that we don't under or over decrement stats during deletes
|
||||||
|
func ReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError {
|
||||||
|
isJs := (r.PostFormValue("js") == "1")
|
||||||
|
|
||||||
|
rid, err := strconv.Atoi(srid)
|
||||||
|
if err != nil {
|
||||||
|
return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := common.Rstore.Get(rid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.PreErrorJSQ("The target reply doesn't exist.", w, r, isJs)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
topic, err := reply.Topic()
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add hooks to make use of headerLite
|
||||||
|
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
if !user.Perms.ViewTopic || !user.Perms.EditReply {
|
||||||
|
return common.NoPermissionsJSQ(w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = reply.SetBody(r.PostFormValue("edit_item"))
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isJs {
|
||||||
|
http.Redirect(w, r, "/topic/"+strconv.Itoa(topic.ID)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
||||||
|
} else {
|
||||||
|
w.Write(successJSONBytes)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Refactor this
|
||||||
|
// TODO: Disable stat updates in posts handled by plugin_guilds
|
||||||
|
func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError {
|
||||||
|
isJs := (r.PostFormValue("isJs") == "1")
|
||||||
|
|
||||||
|
rid, err := strconv.Atoi(srid)
|
||||||
|
if err != nil {
|
||||||
|
return common.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := common.Rstore.Get(rid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.PreErrorJSQ("The reply you tried to delete doesn't exist.", w, r, isJs)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
topic, err := common.Topics.Get(reply.ParentID)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.PreErrorJSQ("The parent topic doesn't exist.", w, r, isJs)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add hooks to make use of headerLite
|
||||||
|
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
if !user.Perms.ViewTopic || !user.Perms.DeleteReply {
|
||||||
|
return common.NoPermissionsJSQ(w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = reply.Delete()
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
//log.Printf("Reply #%d was deleted by common.User #%d", rid, user.ID)
|
||||||
|
if !isJs {
|
||||||
|
http.Redirect(w, r, "/topic/"+strconv.Itoa(reply.ParentID), http.StatusSeeOther)
|
||||||
|
} else {
|
||||||
|
w.Write(successJSONBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
replyCreator, err := common.Users.Get(reply.CreatedBy)
|
||||||
|
if err == nil {
|
||||||
|
wcount := common.WordCount(reply.Content)
|
||||||
|
err = replyCreator.DecreasePostStats(wcount, false)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
} else if err != sql.ErrNoRows {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = common.ModLogs.Create("delete", reply.ParentID, "reply", user.LastIP, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError {
|
||||||
|
isJs := (r.PostFormValue("js") == "1")
|
||||||
|
|
||||||
|
rid, err := strconv.Atoi(srid)
|
||||||
|
if err != nil {
|
||||||
|
return common.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := common.Prstore.Get(rid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.PreErrorJSQ("The target reply doesn't exist.", w, r, isJs)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
creator, err := common.Users.Get(reply.CreatedBy)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ? Does the admin understand that this group perm affects this?
|
||||||
|
if user.ID != creator.ID && !user.Perms.EditReply {
|
||||||
|
return common.NoPermissionsJSQ(w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = reply.SetBody(r.PostFormValue("edit_item"))
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isJs {
|
||||||
|
http.Redirect(w, r, "/user/"+strconv.Itoa(creator.ID)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
||||||
|
} else {
|
||||||
|
w.Write(successJSONBytes)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user common.User, srid string) common.RouteError {
|
||||||
|
isJs := (r.PostFormValue("isJs") == "1")
|
||||||
|
|
||||||
|
rid, err := strconv.Atoi(srid)
|
||||||
|
if err != nil {
|
||||||
|
return common.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := common.Prstore.Get(rid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.PreErrorJSQ("The target reply doesn't exist.", w, r, isJs)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
creator, err := common.Users.Get(reply.CreatedBy)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.ID != creator.ID && !user.Perms.DeleteReply {
|
||||||
|
return common.NoPermissionsJSQ(w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = reply.Delete()
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
//log.Printf("The profile post '%d' was deleted by common.User #%d", reply.ID, user.ID)
|
||||||
|
|
||||||
|
if !isJs {
|
||||||
|
//http.Redirect(w,r, "/user/" + strconv.Itoa(creator.ID), http.StatusSeeOther)
|
||||||
|
} else {
|
||||||
|
w.Write(successJSONBytes)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
316
routes/topic.go
316
routes/topic.go
|
@ -2,6 +2,8 @@ package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
@ -53,3 +55,317 @@ func EditTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, s
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Add support for soft-deletion and add a permission for hard delete in addition to the usual
|
||||||
|
// TODO: Disable stat updates in posts handled by plugin_guilds
|
||||||
|
func DeleteTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||||
|
// TODO: Move this to some sort of middleware
|
||||||
|
var tids []int
|
||||||
|
var isJs = false
|
||||||
|
if common.ReqIsJson(r) {
|
||||||
|
if r.Body == nil {
|
||||||
|
return common.PreErrorJS("No request body", w, r)
|
||||||
|
}
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&tids)
|
||||||
|
if err != nil {
|
||||||
|
return common.PreErrorJS("We weren't able to parse your data", w, r)
|
||||||
|
}
|
||||||
|
isJs = true
|
||||||
|
} else {
|
||||||
|
tid, err := strconv.Atoi(r.URL.Path[len("/topic/delete/submit/"):])
|
||||||
|
if err != nil {
|
||||||
|
return common.PreError("The provided TopicID is not a valid number.", w, r)
|
||||||
|
}
|
||||||
|
tids = append(tids, tid)
|
||||||
|
}
|
||||||
|
if len(tids) == 0 {
|
||||||
|
return common.LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tid := range tids {
|
||||||
|
topic, err := common.Topics.Get(tid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.PreErrorJSQ("The topic you tried to delete doesn't exist.", w, r, isJs)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add hooks to make use of headerLite
|
||||||
|
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
if !user.Perms.ViewTopic || !user.Perms.DeleteTopic {
|
||||||
|
return common.NoPermissionsJSQ(w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We might be able to handle this err better
|
||||||
|
err = topic.Delete()
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = common.ModLogs.Create("delete", tid, "topic", user.LastIP, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ? - We might need to add soft-delete before we can do an action reply for this
|
||||||
|
/*_, err = stmts.createActionReply.Exec(tid,"delete",ipaddress,user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err,w,r,isJs)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
log.Printf("Topic #%d was deleted by common.User #%d", tid, user.ID)
|
||||||
|
}
|
||||||
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func StickTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError {
|
||||||
|
tid, err := strconv.Atoi(stid)
|
||||||
|
if err != nil {
|
||||||
|
return common.PreError("The provided TopicID is not a valid number.", w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
topic, err := common.Topics.Get(tid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.PreError("The topic you tried to pin doesn't exist.", w, r)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add hooks to make use of headerLite
|
||||||
|
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
if !user.Perms.ViewTopic || !user.Perms.PinTopic {
|
||||||
|
return common.NoPermissions(w, r, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = topic.Stick()
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = common.ModLogs.Create("stick", tid, "topic", user.LastIP, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
err = topic.CreateActionReply("stick", user.LastIP, user)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnstickTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError {
|
||||||
|
tid, err := strconv.Atoi(stid)
|
||||||
|
if err != nil {
|
||||||
|
return common.PreError("The provided TopicID is not a valid number.", w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
topic, err := common.Topics.Get(tid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.PreError("The topic you tried to unpin doesn't exist.", w, r)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add hooks to make use of headerLite
|
||||||
|
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
if !user.Perms.ViewTopic || !user.Perms.PinTopic {
|
||||||
|
return common.NoPermissions(w, r, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = topic.Unstick()
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = common.ModLogs.Create("unstick", tid, "topic", user.LastIP, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
err = topic.CreateActionReply("unstick", user.LastIP, user)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func LockTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||||
|
// TODO: Move this to some sort of middleware
|
||||||
|
var tids []int
|
||||||
|
var isJs = false
|
||||||
|
if common.ReqIsJson(r) {
|
||||||
|
if r.Body == nil {
|
||||||
|
return common.PreErrorJS("No request body", w, r)
|
||||||
|
}
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&tids)
|
||||||
|
if err != nil {
|
||||||
|
return common.PreErrorJS("We weren't able to parse your data", w, r)
|
||||||
|
}
|
||||||
|
isJs = true
|
||||||
|
} else {
|
||||||
|
tid, err := strconv.Atoi(r.URL.Path[len("/topic/lock/submit/"):])
|
||||||
|
if err != nil {
|
||||||
|
return common.PreError("The provided TopicID is not a valid number.", w, r)
|
||||||
|
}
|
||||||
|
tids = append(tids, tid)
|
||||||
|
}
|
||||||
|
if len(tids) == 0 {
|
||||||
|
return common.LocalErrorJSQ("You haven't provided any IDs", w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tid := range tids {
|
||||||
|
topic, err := common.Topics.Get(tid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.PreErrorJSQ("The topic you tried to lock doesn't exist.", w, r, isJs)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add hooks to make use of headerLite
|
||||||
|
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
if !user.Perms.ViewTopic || !user.Perms.CloseTopic {
|
||||||
|
return common.NoPermissionsJSQ(w, r, user, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = topic.Lock()
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = common.ModLogs.Create("lock", tid, "topic", user.LastIP, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
err = topic.CreateActionReply("lock", user.LastIP, user)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJSQ(err, w, r, isJs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tids) == 1 {
|
||||||
|
http.Redirect(w, r, "/topic/"+strconv.Itoa(tids[0]), http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnlockTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, stid string) common.RouteError {
|
||||||
|
tid, err := strconv.Atoi(stid)
|
||||||
|
if err != nil {
|
||||||
|
return common.PreError("The provided TopicID is not a valid number.", w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
topic, err := common.Topics.Get(tid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.PreError("The topic you tried to unlock doesn't exist.", w, r)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add hooks to make use of headerLite
|
||||||
|
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
if !user.Perms.ViewTopic || !user.Perms.CloseTopic {
|
||||||
|
return common.NoPermissions(w, r, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = topic.Unlock()
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = common.ModLogs.Create("unlock", tid, "topic", user.LastIP, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
err = topic.CreateActionReply("unlock", user.LastIP, user)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ! JS only route
|
||||||
|
// TODO: Figure a way to get this route to work without JS
|
||||||
|
func MoveTopicSubmit(w http.ResponseWriter, r *http.Request, user common.User, sfid string) common.RouteError {
|
||||||
|
fid, err := strconv.Atoi(sfid)
|
||||||
|
if err != nil {
|
||||||
|
return common.PreErrorJS("The provided Forum ID is not a valid number.", w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Move this to some sort of middleware
|
||||||
|
var tids []int
|
||||||
|
if r.Body == nil {
|
||||||
|
return common.PreErrorJS("No request body", w, r)
|
||||||
|
}
|
||||||
|
err = json.NewDecoder(r.Body).Decode(&tids)
|
||||||
|
if err != nil {
|
||||||
|
return common.PreErrorJS("We weren't able to parse your data", w, r)
|
||||||
|
}
|
||||||
|
if len(tids) == 0 {
|
||||||
|
return common.LocalErrorJS("You haven't provided any IDs", w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tid := range tids {
|
||||||
|
topic, err := common.Topics.Get(tid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return common.PreErrorJS("The topic you tried to move doesn't exist.", w, r)
|
||||||
|
} else if err != nil {
|
||||||
|
return common.InternalErrorJS(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add hooks to make use of headerLite
|
||||||
|
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
if !user.Perms.ViewTopic || !user.Perms.MoveTopic {
|
||||||
|
return common.NoPermissionsJS(w, r, user)
|
||||||
|
}
|
||||||
|
_, ferr = common.SimpleForumUserCheck(w, r, &user, fid)
|
||||||
|
if ferr != nil {
|
||||||
|
return ferr
|
||||||
|
}
|
||||||
|
if !user.Perms.ViewTopic || !user.Perms.MoveTopic {
|
||||||
|
return common.NoPermissionsJS(w, r, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = topic.MoveTo(fid)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJS(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Log more data so we can list the destination forum in the action post?
|
||||||
|
err = common.ModLogs.Create("move", tid, "topic", user.LastIP, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJS(err, w, r)
|
||||||
|
}
|
||||||
|
err = topic.CreateActionReply("move", user.LastIP, user)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalErrorJS(err, w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tids) == 1 {
|
||||||
|
http.Redirect(w, r, "/topic/"+strconv.Itoa(tids[0]), http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
CREATE TABLE [revisions] (
|
CREATE TABLE [revisions] (
|
||||||
[index] int not null,
|
[reviseID] int not null IDENTITY,
|
||||||
[content] nvarchar (MAX) not null,
|
[content] nvarchar (MAX) not null,
|
||||||
[contentID] int not null,
|
[contentID] int not null,
|
||||||
[contentType] nvarchar (100) DEFAULT 'replies' not null
|
[contentType] nvarchar (100) DEFAULT 'replies' not null,
|
||||||
|
[createdAt] datetime not null
|
||||||
);
|
);
|
|
@ -1,6 +1,7 @@
|
||||||
CREATE TABLE `revisions` (
|
CREATE TABLE `revisions` (
|
||||||
`index` int not null,
|
`reviseID` int not null AUTO_INCREMENT,
|
||||||
`content` text not null,
|
`content` text not null,
|
||||||
`contentID` int not null,
|
`contentID` int not null,
|
||||||
`contentType` varchar(100) DEFAULT 'replies' not null
|
`contentType` varchar(100) DEFAULT 'replies' not null,
|
||||||
|
`createdAt` datetime not null
|
||||||
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
|
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
|
|
@ -1,6 +1,7 @@
|
||||||
CREATE TABLE `revisions` (
|
CREATE TABLE `revisions` (
|
||||||
`index` int not null,
|
`reviseID` serial not null,
|
||||||
`content` text not null,
|
`content` text not null,
|
||||||
`contentID` int not null,
|
`contentID` int not null,
|
||||||
`contentType` varchar (100) DEFAULT 'replies' not null
|
`contentType` varchar (100) DEFAULT 'replies' not null,
|
||||||
|
`createdAt` timestamp not null
|
||||||
);
|
);
|
|
@ -669,6 +669,7 @@ var profile_comments_row_18 = []byte(`
|
||||||
var profile_comments_row_19 = []byte(`
|
var profile_comments_row_19 = []byte(`
|
||||||
<div class="rowitem passive deletable_block editable_parent comment `)
|
<div class="rowitem passive deletable_block editable_parent comment `)
|
||||||
var profile_comments_row_20 = []byte(`">
|
var profile_comments_row_20 = []byte(`">
|
||||||
|
<div class="topRow">
|
||||||
<div class="userbit">
|
<div class="userbit">
|
||||||
<img src="`)
|
<img src="`)
|
||||||
var profile_comments_row_21 = []byte(`" alt="`)
|
var profile_comments_row_21 = []byte(`" alt="`)
|
||||||
|
@ -684,25 +685,26 @@ var profile_comments_row_27 = []byte(`</a>`)
|
||||||
var profile_comments_row_28 = []byte(`
|
var profile_comments_row_28 = []byte(`
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="content_column">
|
|
||||||
<span class="editable_block user_content">`)
|
|
||||||
var profile_comments_row_29 = []byte(`</span>
|
|
||||||
<span class="controls">
|
<span class="controls">
|
||||||
`)
|
`)
|
||||||
var profile_comments_row_30 = []byte(`
|
var profile_comments_row_29 = []byte(`
|
||||||
<a href="/profile/reply/edit/submit/`)
|
<a href="/profile/reply/edit/submit/`)
|
||||||
var profile_comments_row_31 = []byte(`?session=`)
|
var profile_comments_row_30 = []byte(`?session=`)
|
||||||
var profile_comments_row_32 = []byte(`" class="mod_button" title="Edit Item"><button class="username edit_item edit_label"></button></a>
|
var profile_comments_row_31 = []byte(`" class="mod_button" title="Edit Item"><button class="username edit_item edit_label"></button></a>
|
||||||
<a href="/profile/reply/delete/submit/`)
|
<a href="/profile/reply/delete/submit/`)
|
||||||
var profile_comments_row_33 = []byte(`?session=`)
|
var profile_comments_row_32 = []byte(`?session=`)
|
||||||
var profile_comments_row_34 = []byte(`" class="mod_button" title="Delete Item"><button class="username delete_item trash_label"></button></a>
|
var profile_comments_row_33 = []byte(`" class="mod_button" title="Delete Item"><button class="username delete_item trash_label"></button></a>
|
||||||
`)
|
`)
|
||||||
var profile_comments_row_35 = []byte(`
|
var profile_comments_row_34 = []byte(`
|
||||||
<a class="mod_button" href="/report/submit/`)
|
<a class="mod_button" href="/report/submit/`)
|
||||||
var profile_comments_row_36 = []byte(`?session=`)
|
var profile_comments_row_35 = []byte(`?session=`)
|
||||||
var profile_comments_row_37 = []byte(`&type=user-reply"><button class="username report_item flag_label"></button></a>
|
var profile_comments_row_36 = []byte(`&type=user-reply"><button class="username report_item flag_label"></button></a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="content_column">
|
||||||
|
<span class="editable_block user_content">`)
|
||||||
|
var profile_comments_row_37 = []byte(`</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`)
|
`)
|
||||||
var profile_22 = []byte(`</div>
|
var profile_22 = []byte(`</div>
|
||||||
|
@ -975,6 +977,24 @@ var topics_61 = []byte(`</div>`)
|
||||||
var topics_62 = []byte(`
|
var topics_62 = []byte(`
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
`)
|
||||||
|
var topics_63 = []byte(`
|
||||||
|
<div class="pageset">
|
||||||
|
`)
|
||||||
|
var topics_64 = []byte(`<div class="pageitem"><a href="?page=`)
|
||||||
|
var topics_65 = []byte(`">Prev</a></div>`)
|
||||||
|
var topics_66 = []byte(`
|
||||||
|
<div class="pageitem"><a href="?page=`)
|
||||||
|
var topics_67 = []byte(`">`)
|
||||||
|
var topics_68 = []byte(`</a></div>
|
||||||
|
`)
|
||||||
|
var topics_69 = []byte(`<div class="pageitem"><a href="?page=`)
|
||||||
|
var topics_70 = []byte(`">Next</a></div>`)
|
||||||
|
var topics_71 = []byte(`
|
||||||
|
</div>
|
||||||
|
`)
|
||||||
|
var topics_72 = []byte(`
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
`)
|
`)
|
||||||
var forum_0 = []byte(`<div id="prevFloat" class="prev_button"><a class="prev_link" aria-label="Go to the previous page" rel="prev" href="/forum/`)
|
var forum_0 = []byte(`<div id="prevFloat" class="prev_button"><a class="prev_link" aria-label="Go to the previous page" rel="prev" href="/forum/`)
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
// Code generated by Gosora. More below:
|
// Code generated by Gosora. More below:
|
||||||
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
|
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
|
||||||
package main
|
package main
|
||||||
import "net/http"
|
|
||||||
import "./common"
|
import "./common"
|
||||||
import "strconv"
|
import "strconv"
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
// nolint
|
// nolint
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -186,23 +186,23 @@ w.Write([]byte(item.Tag))
|
||||||
w.Write(profile_comments_row_27)
|
w.Write(profile_comments_row_27)
|
||||||
}
|
}
|
||||||
w.Write(profile_comments_row_28)
|
w.Write(profile_comments_row_28)
|
||||||
w.Write([]byte(item.ContentHtml))
|
|
||||||
w.Write(profile_comments_row_29)
|
|
||||||
if tmpl_profile_vars.CurrentUser.IsMod {
|
if tmpl_profile_vars.CurrentUser.IsMod {
|
||||||
|
w.Write(profile_comments_row_29)
|
||||||
|
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||||
w.Write(profile_comments_row_30)
|
w.Write(profile_comments_row_30)
|
||||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
||||||
w.Write(profile_comments_row_31)
|
w.Write(profile_comments_row_31)
|
||||||
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||||
w.Write(profile_comments_row_32)
|
w.Write(profile_comments_row_32)
|
||||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
||||||
w.Write(profile_comments_row_33)
|
w.Write(profile_comments_row_33)
|
||||||
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
|
||||||
w.Write(profile_comments_row_34)
|
|
||||||
}
|
}
|
||||||
w.Write(profile_comments_row_35)
|
w.Write(profile_comments_row_34)
|
||||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||||
w.Write(profile_comments_row_36)
|
w.Write(profile_comments_row_35)
|
||||||
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
w.Write([]byte(tmpl_profile_vars.CurrentUser.Session))
|
||||||
|
w.Write(profile_comments_row_36)
|
||||||
|
w.Write([]byte(item.ContentHtml))
|
||||||
w.Write(profile_comments_row_37)
|
w.Write(profile_comments_row_37)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,6 +217,30 @@ w.Write(topics_60)
|
||||||
w.Write(topics_61)
|
w.Write(topics_61)
|
||||||
}
|
}
|
||||||
w.Write(topics_62)
|
w.Write(topics_62)
|
||||||
|
if tmpl_topics_vars.LastPage > 1 {
|
||||||
|
w.Write(topics_63)
|
||||||
|
if tmpl_topics_vars.Page > 1 {
|
||||||
|
w.Write(topics_64)
|
||||||
|
w.Write([]byte(strconv.Itoa(tmpl_topics_vars.Page - 1)))
|
||||||
|
w.Write(topics_65)
|
||||||
|
}
|
||||||
|
if len(tmpl_topics_vars.PageList) != 0 {
|
||||||
|
for _, item := range tmpl_topics_vars.PageList {
|
||||||
|
w.Write(topics_66)
|
||||||
|
w.Write([]byte(strconv.Itoa(item)))
|
||||||
|
w.Write(topics_67)
|
||||||
|
w.Write([]byte(strconv.Itoa(item)))
|
||||||
|
w.Write(topics_68)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tmpl_topics_vars.LastPage != tmpl_topics_vars.Page {
|
||||||
|
w.Write(topics_69)
|
||||||
|
w.Write([]byte(strconv.Itoa(tmpl_topics_vars.Page + 1)))
|
||||||
|
w.Write(topics_70)
|
||||||
|
}
|
||||||
|
w.Write(topics_71)
|
||||||
|
}
|
||||||
|
w.Write(topics_72)
|
||||||
w.Write(footer_0)
|
w.Write(footer_0)
|
||||||
w.Write([]byte(common.BuildWidget("footer",tmpl_topics_vars.Header)))
|
w.Write([]byte(common.BuildWidget("footer",tmpl_topics_vars.Header)))
|
||||||
w.Write(footer_1)
|
w.Write(footer_1)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
{{else}}
|
{{else}}
|
||||||
{{range .ItemList}}
|
{{range .ItemList}}
|
||||||
<div class="rowitem passive deletable_block editable_parent comment {{.ClassName}}">
|
<div class="rowitem passive deletable_block editable_parent comment {{.ClassName}}">
|
||||||
|
<div class="topRow">
|
||||||
<div class="userbit">
|
<div class="userbit">
|
||||||
<img src="{{.Avatar}}" alt="{{.CreatedByName}}'s Avatar" title="{{.CreatedByName}}'s Avatar" />
|
<img src="{{.Avatar}}" alt="{{.CreatedByName}}'s Avatar" title="{{.CreatedByName}}'s Avatar" />
|
||||||
<span class="nameAndTitle">
|
<span class="nameAndTitle">
|
||||||
|
@ -26,8 +27,6 @@
|
||||||
{{if .Tag}}<a class="username hide_on_mobile user_tag" style="float: right;">{{.Tag}}</a>{{end}}
|
{{if .Tag}}<a class="username hide_on_mobile user_tag" style="float: right;">{{.Tag}}</a>{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="content_column">
|
|
||||||
<span class="editable_block user_content">{{.ContentHtml}}</span>
|
|
||||||
<span class="controls">
|
<span class="controls">
|
||||||
{{if $.CurrentUser.IsMod}}
|
{{if $.CurrentUser.IsMod}}
|
||||||
<a href="/profile/reply/edit/submit/{{.ID}}?session={{$.CurrentUser.Session}}" class="mod_button" title="Edit Item"><button class="username edit_item edit_label"></button></a>
|
<a href="/profile/reply/edit/submit/{{.ID}}?session={{$.CurrentUser.Session}}" class="mod_button" title="Edit Item"><button class="username edit_item edit_label"></button></a>
|
||||||
|
@ -36,6 +35,9 @@
|
||||||
<a class="mod_button" href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=user-reply"><button class="username report_item flag_label"></button></a>
|
<a class="mod_button" href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=user-reply"><button class="username report_item flag_label"></button></a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="content_column">
|
||||||
|
<span class="editable_block user_content">{{.ContentHtml}}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
|
@ -115,5 +115,15 @@
|
||||||
</div>{{else}}<div class="rowitem passive">There aren't any topics yet.{{if .CurrentUser.Perms.CreateTopic}} <a href="/topics/create/">Start one?</a>{{end}}</div>{{end}}
|
</div>{{else}}<div class="rowitem passive">There aren't any topics yet.{{if .CurrentUser.Perms.CreateTopic}} <a href="/topics/create/">Start one?</a>{{end}}</div>{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{if gt .LastPage 1}}
|
||||||
|
<div class="pageset">
|
||||||
|
{{if gt .Page 1}}<div class="pageitem"><a href="?page={{subtract .Page 1}}">Prev</a></div>{{end}}
|
||||||
|
{{range .PageList}}
|
||||||
|
<div class="pageitem"><a href="?page={{.}}">{{.}}</a></div>
|
||||||
|
{{end}}
|
||||||
|
{{if ne .LastPage .Page}}<div class="pageitem"><a href="?page={{add .Page 1}}">Next</a></div>{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
{{template "footer.html" . }}
|
{{template "footer.html" . }}
|
||||||
|
|
|
@ -1050,6 +1050,16 @@ textarea {
|
||||||
#profile_right_lane .topic_reply_form {
|
#profile_right_lane .topic_reply_form {
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
#profile_comments .topRow {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
#profile_comments .topRow .controls {
|
||||||
|
padding-top: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
#profile_comments .content_column {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
#profile_comments_head {
|
#profile_comments_head {
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue