Refactored a few bits and pieces.

Added Riot as a dependency, I'm still deciding over whether to use this or Bleve.
Tweaked the topic view for Cosora.
Fixed a crash bug in the group creator.
Moved a few things from permissions.go into the ForumPermsStore, more to come here!
Added more tests.
Refactored the MySQL Query Generator.
Refactored the BBCode Parser.
Moved the presets into the Phrase System.
This commit is contained in:
Azareal 2017-11-05 01:04:57 +00:00
parent d0363f3eb1
commit d0ffc4be78
20 changed files with 508 additions and 585 deletions

View File

@ -63,11 +63,11 @@ func initDatabase() (err error) {
}
log.Print("Loading the forum permissions.")
err = buildForumPermissions()
fpstore = NewForumPermsStore()
err = fpstore.Init()
if err != nil {
return err
}
fpstore = NewForumPermsStore()
log.Print("Loading the settings.")
err = LoadSettings()

View File

@ -1,5 +1,10 @@
package main
import (
"encoding/json"
"log"
)
var fpstore *ForumPermsStore
type ForumPermsStore struct {
@ -9,6 +14,156 @@ func NewForumPermsStore() *ForumPermsStore {
return &ForumPermsStore{}
}
func (fps *ForumPermsStore) Init() error {
fids, err := fstore.GetAllIDs()
if err != nil {
return err
}
if dev.SuperDebug {
log.Print("fids: ", fids)
}
rows, err := getForumsPermissionsStmt.Query()
if err != nil {
return err
}
defer rows.Close()
if dev.DebugMode {
log.Print("Adding the forum permissions")
if dev.SuperDebug {
log.Print("forumPerms[gid][fid]")
}
}
// Temporarily store the forum perms in a map before transferring it to a much faster and thread-safe slice
forumPerms = make(map[int]map[int]ForumPerms)
for rows.Next() {
var gid, fid int
var perms []byte
var pperms ForumPerms
err = rows.Scan(&gid, &fid, &perms)
if err != nil {
return err
}
if dev.SuperDebug {
log.Print("perms: ", string(perms))
}
err = json.Unmarshal(perms, &pperms)
if err != nil {
return err
}
pperms.ExtData = make(map[string]bool)
pperms.Overrides = true
_, ok := forumPerms[gid]
if !ok {
forumPerms[gid] = make(map[int]ForumPerms)
}
if dev.SuperDebug {
log.Print("gid: ", gid)
log.Print("fid: ", fid)
log.Printf("perms: %+v\n", pperms)
}
forumPerms[gid][fid] = pperms
}
return fps.cascadePermSetToGroups(forumPerms, fids)
}
// TODO: Need a more thread-safe way of doing this. Possibly with sync.Map?
func (fps *ForumPermsStore) Reload(fid int) error {
if dev.DebugMode {
log.Printf("Reloading the forum permissions for forum #%d", fid)
}
fids, err := fstore.GetAllIDs()
if err != nil {
return err
}
rows, err := db.Query("select gid, permissions from forums_permissions where fid = ? order by gid asc", fid)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var gid int
var perms []byte
var pperms ForumPerms
err := rows.Scan(&gid, &perms)
if err != nil {
return err
}
err = json.Unmarshal(perms, &pperms)
if err != nil {
return err
}
pperms.ExtData = make(map[string]bool)
pperms.Overrides = true
_, ok := forumPerms[gid]
if !ok {
forumPerms[gid] = make(map[int]ForumPerms)
}
forumPerms[gid][fid] = pperms
}
return fps.cascadePermSetToGroups(forumPerms, fids)
}
func (fps *ForumPermsStore) cascadePermSetToGroups(forumPerms map[int]map[int]ForumPerms, fids []int) error {
groups, err := gstore.GetAll()
if err != nil {
return err
}
for _, group := range groups {
if dev.DebugMode {
log.Printf("Updating the forum permissions for Group #%d", group.ID)
}
group.Forums = []ForumPerms{BlankForumPerms}
group.CanSee = []int{}
fps.cascadePermSetToGroup(forumPerms, group, fids)
if dev.SuperDebug {
log.Printf("group.CanSee (length %d): %+v \n", len(group.CanSee), group.CanSee)
log.Printf("group.Forums (length %d): %+v\n", len(group.Forums), group.Forums)
}
}
return nil
}
func (fps *ForumPermsStore) cascadePermSetToGroup(forumPerms map[int]map[int]ForumPerms, group *Group, fids []int) {
for _, fid := range fids {
if dev.SuperDebug {
log.Printf("Forum #%+v\n", fid)
}
forumPerm, ok := forumPerms[group.ID][fid]
if ok {
//log.Print("Overriding permissions for forum #%d",fid)
group.Forums = append(group.Forums, forumPerm)
} else {
//log.Printf("Inheriting from group defaults for forum #%d",fid)
forumPerm = BlankForumPerms
group.Forums = append(group.Forums, forumPerm)
}
if forumPerm.Overrides {
if forumPerm.ViewTopic {
group.CanSee = append(group.CanSee, fid)
}
} else if group.Perms.ViewTopic {
group.CanSee = append(group.CanSee, fid)
}
if dev.SuperDebug {
log.Print("group.ID: ", group.ID)
log.Printf("forumPerm: %+v\n", forumPerm)
log.Print("group.CanSee: ", group.CanSee)
}
}
}
func (fps *ForumPermsStore) Get(fid int, gid int) (fperms ForumPerms, err error) {
// TODO: Add a hook here and have plugin_guilds use it
group, err := gstore.Get(gid)

View File

@ -157,21 +157,24 @@ func (mgs *MemoryGroupStore) Reload(id int) error {
func (mgs *MemoryGroupStore) initGroup(group *Group) error {
err := json.Unmarshal(group.PermissionsText, &group.Perms)
if err != nil {
log.Printf("group: %+v\n", group)
log.Print("bad group perms: ", group.PermissionsText)
return err
}
if dev.DebugMode {
log.Print(group.Name + ": ")
log.Printf("%+v\n", group.Perms)
log.Printf(group.Name+": %+v\n", group.Perms)
}
err = json.Unmarshal(group.PluginPermsText, &group.PluginPerms)
if err != nil {
log.Printf("group: %+v\n", group)
log.Print("bad group plugin perms: ", group.PluginPermsText)
return err
}
if dev.DebugMode {
log.Print(group.Name + ": ")
log.Printf("%+v\n", group.PluginPerms)
log.Printf(group.Name+": %+v\n", group.PluginPerms)
}
//group.Perms.ExtData = make(map[string]bool)
// TODO: Can we optimise the bit where this cascades down to the user now?
if group.IsAdmin || group.IsMod {
@ -204,7 +207,7 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod
}
defer tx.Rollback()
insertTx, err := qgen.Builder.SimpleInsertTx(tx, "users_groups", "name, tag, is_admin, is_mod, is_banned, permissions", "?,?,?,?,?,?")
insertTx, err := qgen.Builder.SimpleInsertTx(tx, "users_groups", "name, tag, is_admin, is_mod, is_banned, permissions, plugin_perms", "?,?,?,?,?,?,'{}'")
if err != nil {
return 0, err
}
@ -279,7 +282,7 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod
mgs.Unlock()
for _, forum := range fdata {
err = rebuildForumPermissions(forum.ID)
err = fpstore.Reload(forum.ID)
if err != nil {
return gid, err
}

View File

@ -22,6 +22,9 @@ go get -u gopkg.in/sourcemap.v1
echo "Installing OttoJS"
go get -u github.com/robertkrimen/otto
echo "Installing the Riot Search Engine"
go get -u github.com/robertkrimen/otto
echo "Building the installer"
cd ./install

View File

@ -71,6 +71,13 @@ if %errorlevel% neq 0 (
exit /b %errorlevel%
)
echo Installing the Riot Search Engine
go get -u github.com/go-ego/riot
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
echo Building the installer
go generate

View File

@ -42,6 +42,16 @@
"SettingLabels": {
"activation_type": "Activate All,Email Activation,Admin Approval"
},
"PermPresets": {
"all":"Public",
"announce":"Announcements",
"members":"Member Only",
"staff":"Staff Only",
"admins":"Admin Only",
"archive":"Archive",
"custom":"Custom",
"unknown":"Unknown"
},
"Accounts": {
"VerifyEmailSubject": "Validate Your Email @ {{name}}",
"VerifyEmailBody": "Dear {{username}}, following your registration on our forums, we ask you to validate your email, so that we can confirm that this email actually belongs to you.\n\nClick on the following link to do so. {{schema}}://{{url}}/user/edit/token/{{token}}\n\nIf you haven't created an account here, then please feel free to ignore this email.\nWe're sorry for the inconvenience this may have caused."

View File

@ -421,6 +421,8 @@ func userStoreTest(t *testing.T, newUserID int) {
_, err = users.Get(newUserID)
recordMustNotExist(t, err, "UID #%d shouldn't exist", newUserID)
// TODO: Add tests for the Cache* methods
}
// TODO: Add an error message to this?
@ -445,6 +447,36 @@ func expect(t *testing.T, item bool, errmsg string) {
}
}
func TestPermsMiddleware(t *testing.T) {
if !gloinited {
err := gloinit()
if err != nil {
t.Fatal(err)
}
}
if !pluginsInited {
initPlugins()
}
dummyResponseRecorder := httptest.NewRecorder()
bytesBuffer := bytes.NewBuffer([]byte(""))
dummyRequest := httptest.NewRequest("", "/forum/1", bytesBuffer)
user := getDummyUser()
ferr := SuperModOnly(dummyResponseRecorder, dummyRequest, *user)
expect(t, ferr != nil, "Blank users shouldn't be supermods")
user.IsSuperMod = false
ferr = SuperModOnly(dummyResponseRecorder, dummyRequest, *user)
expect(t, ferr != nil, "Non-supermods shouldn't be allowed through supermod gates")
user.IsSuperMod = true
ferr = SuperModOnly(dummyResponseRecorder, dummyRequest, *user)
expect(t, ferr == nil, "Supermods should be allowed through supermod gates")
// TODO: Loop over the Control Panel routes and make sure only supermods can get in
}
func TestTopicStore(t *testing.T) {
if !gloinited {
err := gloinit()
@ -525,31 +557,44 @@ func TestForumStore(t *testing.T) {
if forum.ID != 1 {
t.Error("forum.ID doesn't not match the requested FID. Got '" + strconv.Itoa(forum.ID) + "' instead.'")
}
if forum.Name != "Reports" {
t.Error("FID #0 is named '" + forum.Name + "' and not 'Reports'")
}
// TODO: Check the preset and forum permissions
expect(t, forum.Name == "Reports", fmt.Sprintf("FID #0 is named '%s' and not 'Reports'", forum.Name))
expect(t, !forum.Active, fmt.Sprintf("The reports forum shouldn't be active"))
var expectDesc = "All the reports go here"
expect(t, forum.Desc == expectDesc, fmt.Sprintf("The forum description should be '%s' not '%s'", expectDesc, forum.Desc))
forum, err = fstore.Get(2)
recordMustExist(t, err, "Couldn't find FID #1")
_ = forum
expect(t, forum.ID == 2, fmt.Sprintf("The FID should be 2 not %d", forum.ID))
expect(t, forum.Name == "General", fmt.Sprintf("The name of the forum should be 'General' not '%s'", forum.Name))
expect(t, forum.Active, fmt.Sprintf("The general forum should be active"))
expectDesc = "A place for general discussions which don't fit elsewhere"
expect(t, forum.Desc == expectDesc, fmt.Sprintf("The forum description should be '%s' not '%s'", expectDesc, forum.Desc))
ok := fstore.Exists(-1)
if ok {
t.Error("FID #-1 shouldn't exist")
}
expect(t, !ok, "FID #-1 shouldn't exist")
ok = fstore.Exists(0)
if ok {
t.Error("FID #0 shouldn't exist")
}
expect(t, !ok, "FID #0 shouldn't exist")
ok = fstore.Exists(1)
if !ok {
t.Error("FID #1 should exist")
expect(t, ok, "FID #1 should exist")
// TODO: Test forum creation
// TODO: Test forum deletion
// TODO: Test forum update
}
// TODO: Implement this
func TestForumPermsStore(t *testing.T) {
if !gloinited {
gloinit()
}
if !pluginsInited {
initPlugins()
}
}
// TODO: Test the group permissions
func TestGroupStore(t *testing.T) {
if !gloinited {
gloinit()
@ -646,7 +691,19 @@ func TestGroupStore(t *testing.T) {
expect(t, group.IsMod, "This should be a mod group")
expect(t, !group.IsBanned, "This shouldn't be a ban group")
// Make sure the data is static
gstore.Reload(gid)
group, err = gstore.Get(gid)
expectNilErr(t, err)
expect(t, group.ID == gid, "The group ID should match the requested ID")
expect(t, !group.IsAdmin, "This shouldn't be an admin group")
expect(t, group.IsMod, "This should be a mod group")
expect(t, !group.IsBanned, "This shouldn't be a ban group")
// TODO: Test group deletion
// TODO: Test group reload
// TODO: Test group cache set
}
func TestReplyStore(t *testing.T) {
@ -714,6 +771,7 @@ func TestSlugs(t *testing.T) {
msgList = addMEPair(msgList, "--", "untitled")
msgList = addMEPair(msgList, "é", "é")
msgList = addMEPair(msgList, "-é-", "é")
msgList = addMEPair(msgList, "-你好-", "untitled")
for _, item := range msgList {
t.Log("Testing string '" + item.Msg + "'")

View File

@ -338,7 +338,6 @@ func routePanelForumsEdit(w http.ResponseWriter, r *http.Request, user User, sfi
if err == ErrNoRows {
return LocalError("The forum you're trying to edit doesn't exist.", w, r, user)
} else if err != nil {
return InternalError(err, w, r)
}
@ -465,6 +464,8 @@ func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use
return InternalErrorJSQ(err, w, r, isJs)
}
// ! IMPORTANT
// TODO: Refactor this
forumUpdateMutex.Lock()
defer forumUpdateMutex.Unlock()
if changed {
@ -488,7 +489,6 @@ func routePanelForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, use
}
err = fstore.Reload(fid)
if err != nil {
// TODO: Log this? -- Another admin might have deleted it
return LocalErrorJSQ("Unable to reload forum", w, r, user, isJs)
}
}

View File

@ -349,7 +349,7 @@ func permmapToQuery(permmap map[string]ForumPerms, fid int) error {
permUpdateMutex.Lock()
defer permUpdateMutex.Unlock()
return rebuildForumPermissions(fid)
return fpstore.Reload(fid)
}
func replaceForumPermsForGroup(gid int, presetSet map[int]string, permSets map[int]ForumPerms) error {
@ -393,163 +393,7 @@ func replaceForumPermsForGroupTx(tx *sql.Tx, gid int, presetSets map[int]string,
return nil
}
// TODO: Need a more thread-safe way of doing this. Possibly with sync.Map?
func rebuildForumPermissions(fid int) error {
if dev.DebugMode {
log.Print("Loading the forum permissions")
}
fids, err := fstore.GetAllIDs()
if err != nil {
return err
}
rows, err := db.Query("select gid, permissions from forums_permissions where fid = ? order by gid asc", fid)
if err != nil {
return err
}
defer rows.Close()
if dev.DebugMode {
log.Print("Updating the forum permissions")
}
for rows.Next() {
var gid int
var perms []byte
var pperms ForumPerms
err := rows.Scan(&gid, &perms)
if err != nil {
return err
}
err = json.Unmarshal(perms, &pperms)
if err != nil {
return err
}
pperms.ExtData = make(map[string]bool)
pperms.Overrides = true
_, ok := forumPerms[gid]
if !ok {
forumPerms[gid] = make(map[int]ForumPerms)
}
forumPerms[gid][fid] = pperms
}
return cascadePermSetToGroups(forumPerms, fids)
}
func buildForumPermissions() error {
fids, err := fstore.GetAllIDs()
if err != nil {
return err
}
if dev.SuperDebug {
log.Print("fids: ", fids)
}
rows, err := getForumsPermissionsStmt.Query()
if err != nil {
return err
}
defer rows.Close()
if dev.DebugMode {
log.Print("Adding the forum permissions")
if dev.SuperDebug {
log.Print("forumPerms[gid][fid]")
}
}
// Temporarily store the forum perms in a map before transferring it to a much faster and thread-safe slice
forumPerms = make(map[int]map[int]ForumPerms)
for rows.Next() {
var gid, fid int
var perms []byte
var pperms ForumPerms
err = rows.Scan(&gid, &fid, &perms)
if err != nil {
return err
}
if dev.SuperDebug {
log.Print("perms: ", string(perms))
}
err = json.Unmarshal(perms, &pperms)
if err != nil {
return err
}
pperms.ExtData = make(map[string]bool)
pperms.Overrides = true
_, ok := forumPerms[gid]
if !ok {
forumPerms[gid] = make(map[int]ForumPerms)
}
if dev.SuperDebug {
log.Print("gid: ", gid)
log.Print("fid: ", fid)
log.Printf("perms: %+v;", pperms)
}
forumPerms[gid][fid] = pperms
}
return cascadePermSetToGroups(forumPerms, fids)
}
func cascadePermSetToGroups(forumPerms map[int]map[int]ForumPerms, fids []int) error {
groups, err := gstore.GetAll()
if err != nil {
return err
}
for _, group := range groups {
if dev.DebugMode {
log.Printf("Updating the forum permissions for Group #%d", group.ID)
}
group.Forums = []ForumPerms{BlankForumPerms}
group.CanSee = []int{}
cascadePermSetToGroup(forumPerms, group, fids)
if dev.SuperDebug {
log.Printf("group.CanSee %+v\n", group.CanSee)
log.Printf("group.Forums %+v\n", group.Forums)
log.Print("len(group.CanSee): ", len(group.CanSee))
log.Print("len(group.Forums): ", len(group.Forums)) // This counts blank aka 0
}
}
return nil
}
func cascadePermSetToGroup(forumPerms map[int]map[int]ForumPerms, group *Group, fids []int) {
for _, fid := range fids {
if dev.SuperDebug {
log.Printf("Forum #%+v\n", fid)
}
forumPerm, ok := forumPerms[group.ID][fid]
if ok {
// Override group perms
//log.Print("Overriding permissions for forum #" + strconv.Itoa(fid))
group.Forums = append(group.Forums, forumPerm)
} else {
// Inherit from Group
//log.Print("Inheriting from default for forum #" + strconv.Itoa(fid))
forumPerm = BlankForumPerms
group.Forums = append(group.Forums, forumPerm)
}
if forumPerm.Overrides {
if forumPerm.ViewTopic {
group.CanSee = append(group.CanSee, fid)
}
} else if group.Perms.ViewTopic {
group.CanSee = append(group.CanSee, fid)
}
if dev.SuperDebug {
log.Print("group.ID: ", group.ID)
log.Printf("forumPerm: %+v\n", forumPerm)
log.Print("group.CanSee: ", group.CanSee)
}
}
}
// TODO: Refactor this and write tests for it
func forumPermsToGroupForumPreset(fperms ForumPerms) string {
if !fperms.Overrides {
return "default"
@ -614,24 +458,12 @@ func stripInvalidPreset(preset string) string {
// TODO: Move this into the phrase system?
func presetToLang(preset string) string {
switch preset {
case "all":
return "Public"
case "announce":
return "Announcements"
case "members":
return "Member Only"
case "staff":
return "Staff Only"
case "admins":
return "Admin Only"
case "archive":
return "Archive"
case "custom":
return "Custom"
default:
return ""
phrases := GetAllPermPresets()
phrase, ok := phrases[preset]
if !ok {
phrase = phrases["unknown"]
}
return phrase
}
// TODO: Is this racey?

View File

@ -39,6 +39,7 @@ type LanguagePack struct {
GlobalPerms map[string]string
LocalPerms map[string]string
SettingLabels map[string]string
PermPresets map[string]string
Accounts map[string]string // TODO: Apply these phrases in the software proper
}
@ -139,6 +140,10 @@ func GetAllSettingLabels() map[string]string {
return currentLangPack.Load().(*LanguagePack).SettingLabels
}
func GetAllPermPresets() map[string]string {
return currentLangPack.Load().(*LanguagePack).PermPresets
}
func GetAccountPhrase(name string) string {
res, ok := currentLangPack.Load().(*LanguagePack).Accounts[name]
if !ok {

View File

@ -261,8 +261,7 @@ func bbcodeFullParse(msg string) string {
i += 6
}
//if msglen >= (i+5) {
// log.Print("boo2")
// log.Print(string(msgbytes[i:i+5]))
// log.Print("boo2: ", string(msgbytes[i:i+5]))
//}
complexBbc = true
}
@ -317,73 +316,15 @@ func bbcodeFullParse(msg string) string {
//log.Print("BBCode Pre:","`"+string(msgbytes)+"`")
//log.Print("----")
for ; i < len(msgbytes); i++ {
MainLoop:
if msgbytes[i] == '[' {
OuterComplex:
if msgbytes[i+1] == 'u' {
if msgbytes[i+2] == 'r' && msgbytes[i+3] == 'l' && msgbytes[i+4] == ']' {
start = i + 5
outbytes = append(outbytes, msgbytes[lastTag:i]...)
i = start
i += partialURLBytesLen(msgbytes[start:])
//log.Print("Partial Bytes:",string(msgbytes[start:]))
//log.Print("-----")
if !bytes.Equal(msgbytes[i:i+6], []byte("[/url]")) {
//log.Print("Invalid Bytes:",string(msgbytes[i:i+6]))
//log.Print("-----")
outbytes = append(outbytes, invalidURL...)
goto MainLoop
}
outbytes = append(outbytes, urlOpen...)
outbytes = append(outbytes, msgbytes[start:i]...)
outbytes = append(outbytes, urlOpen2...)
outbytes = append(outbytes, msgbytes[start:i]...)
outbytes = append(outbytes, urlClose...)
i += 6
lastTag = i
i, start, lastTag, outbytes = bbcodeParseURL(i, start, lastTag, msgbytes, outbytes)
continue
}
} else if msgbytes[i+1] == 'r' {
if bytes.Equal(msgbytes[i+2:i+6], []byte("and]")) {
outbytes = append(outbytes, msgbytes[lastTag:i]...)
start = i + 6
i = start
for ; ; i++ {
if msgbytes[i] == '[' {
if !bytes.Equal(msgbytes[i+1:i+7], []byte("/rand]")) {
outbytes = append(outbytes, bbcodeMissingTag...)
goto OuterComplex
}
break
} else if (len(msgbytes) - 1) < (i + 10) {
outbytes = append(outbytes, bbcodeMissingTag...)
goto OuterComplex
}
}
number, err := strconv.ParseInt(string(msgbytes[start:i]), 10, 64)
if err != nil {
outbytes = append(outbytes, bbcodeInvalidNumber...)
goto MainLoop
}
// TODO: Add support for negative numbers?
if number < 0 {
outbytes = append(outbytes, bbcodeNoNegative...)
goto MainLoop
}
var dat []byte
if number == 0 {
dat = []byte("0")
} else {
dat = []byte(strconv.FormatInt((random.Int63n(number)), 10))
}
outbytes = append(outbytes, dat...)
//log.Print("Outputted the random number")
i += 7
lastTag = i
i, start, lastTag, outbytes = bbcodeParseRand(i, start, lastTag, msgbytes, outbytes)
}
}
}
@ -411,3 +352,71 @@ func bbcodeFullParse(msg string) string {
return msg
}
func bbcodeParseURL(i int, start int, lastTag int, msgbytes []byte, outbytes []byte) (int, int, int, []byte) {
start = i + 5
outbytes = append(outbytes, msgbytes[lastTag:i]...)
i = start
i += partialURLBytesLen(msgbytes[start:])
//log.Print("Partial Bytes: ", string(msgbytes[start:]))
//log.Print("-----")
if !bytes.Equal(msgbytes[i:i+6], []byte("[/url]")) {
//log.Print("Invalid Bytes: ", string(msgbytes[i:i+6]))
//log.Print("-----")
outbytes = append(outbytes, invalidURL...)
return i, start, lastTag, outbytes
}
outbytes = append(outbytes, urlOpen...)
outbytes = append(outbytes, msgbytes[start:i]...)
outbytes = append(outbytes, urlOpen2...)
outbytes = append(outbytes, msgbytes[start:i]...)
outbytes = append(outbytes, urlClose...)
i += 6
lastTag = i
return i, start, lastTag, outbytes
}
func bbcodeParseRand(i int, start int, lastTag int, msgbytes []byte, outbytes []byte) (int, int, int, []byte) {
outbytes = append(outbytes, msgbytes[lastTag:i]...)
start = i + 6
i = start
for ; ; i++ {
if msgbytes[i] == '[' {
if !bytes.Equal(msgbytes[i+1:i+7], []byte("/rand]")) {
outbytes = append(outbytes, bbcodeMissingTag...)
return i, start, lastTag, outbytes
}
break
} else if (len(msgbytes) - 1) < (i + 10) {
outbytes = append(outbytes, bbcodeMissingTag...)
return i, start, lastTag, outbytes
}
}
number, err := strconv.ParseInt(string(msgbytes[start:i]), 10, 64)
if err != nil {
outbytes = append(outbytes, bbcodeInvalidNumber...)
return i, start, lastTag, outbytes
}
// TODO: Add support for negative numbers?
if number < 0 {
outbytes = append(outbytes, bbcodeNoNegative...)
return i, start, lastTag, outbytes
}
var dat []byte
if number == 0 {
dat = []byte("0")
} else {
dat = []byte(strconv.FormatInt((random.Int63n(number)), 10))
}
outbytes = append(outbytes, dat...)
//log.Print("Outputted the random number")
i += 7
lastTag = i
return i, start, lastTag, outbytes
}

View File

@ -48,6 +48,8 @@ func TestBBCodeRender(t *testing.T) {
msgList = addMEPair(msgList, "[quote][b]hi[/b][/quote]", "<span class='postQuote'><b>hi</b></span>")
msgList = addMEPair(msgList, "[quote][b]h[/b][/quote]", "<span class='postQuote'><b>h</b></span>")
msgList = addMEPair(msgList, "[quote][b][/b][/quote]", "<span class='postQuote'><b></b></span>")
msgList = addMEPair(msgList, "-你好-", "-你好-")
msgList = addMEPair(msgList, "[i]-你好-[/i]", "<i>-你好-</i>") // TODO: More of these Unicode tests? Emoji, Chinese, etc.?
t.Log("Testing bbcodeFullParse")
for _, item := range msgList {
@ -249,6 +251,8 @@ func TestMarkdownRender(t *testing.T) {
msgList = addMEPair(msgList, "* *", "<i> </i>")
msgList = addMEPair(msgList, "** **", "<b> </b>")
msgList = addMEPair(msgList, "*** ***", "<b><i> </i></b>")
msgList = addMEPair(msgList, "-你好-", "-你好-")
msgList = addMEPair(msgList, "*-你好-*", "<i>-你好-</i>") // TODO: More of these Unicode tests? Emoji, Chinese, etc.?
for _, item := range msgList {
res = markdownParse(item.Msg)

View File

@ -118,21 +118,7 @@ func (adapter *MysqlAdapter) SimpleInsert(name string, table string, columns str
return "", errors.New("No input data found for SimpleInsert")
}
var querystr = "INSERT INTO `" + table + "`("
// Escape the column names, just in case we've used a reserved keyword
for _, column := range processColumns(columns) {
if column.Type == "function" {
querystr += column.Left + ","
} else {
querystr += "`" + column.Left + "`,"
}
}
// Remove the trailing comma
querystr = querystr[0 : len(querystr)-1]
querystr += ") VALUES ("
var querystr = "INSERT INTO `" + table + "`(" + adapter.buildColumns(columns) + ") VALUES ("
for _, field := range processFields(fields) {
nameLen := len(field.Name)
if field.Name[0] == '"' && field.Name[nameLen-1] == '"' && nameLen >= 3 {
@ -149,6 +135,18 @@ func (adapter *MysqlAdapter) SimpleInsert(name string, table string, columns str
return querystr + ")", nil
}
func (adapter *MysqlAdapter) buildColumns(columns string) (querystr string) {
// Escape the column names, just in case we've used a reserved keyword
for _, column := range processColumns(columns) {
if column.Type == "function" {
querystr += column.Left + ","
} else {
querystr += "`" + column.Left + "`,"
}
}
return querystr[0 : len(querystr)-1]
}
// ! DEPRECATED
func (adapter *MysqlAdapter) SimpleReplace(name string, table string, columns string, fields string) (string, error) {
if name == "" {
@ -164,20 +162,7 @@ func (adapter *MysqlAdapter) SimpleReplace(name string, table string, columns st
return "", errors.New("No input data found for SimpleInsert")
}
var querystr = "REPLACE INTO `" + table + "`("
// Escape the column names, just in case we've used a reserved keyword
for _, column := range processColumns(columns) {
if column.Type == "function" {
querystr += column.Left + ","
} else {
querystr += "`" + column.Left + "`,"
}
}
// Remove the trailing comma
querystr = querystr[0 : len(querystr)-1]
querystr += ") VALUES ("
var querystr = "REPLACE INTO `" + table + "`(" + adapter.buildColumns(columns) + ") VALUES ("
for _, field := range processFields(fields) {
querystr += field.Name + ","
}
@ -260,29 +245,13 @@ func (adapter *MysqlAdapter) SimpleUpdate(name string, table string, set string,
}
querystr += ","
}
// Remove the trailing comma
querystr = querystr[0 : len(querystr)-1]
// Add support for BETWEEN x.x
if len(where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
querystr += " `" + token.Contents + "`"
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
whereStr, err := adapter.buildWhere(where)
if err != nil {
return querystr, err
}
querystr += whereStr
adapter.pushStatement(name, "update", querystr)
return querystr, nil
@ -335,32 +304,8 @@ func (adapter *MysqlAdapter) Purge(name string, table string) (string, error) {
return "DELETE FROM `" + table + "`", nil
}
func (adapter *MysqlAdapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
if table == "" {
return "", errors.New("You need a name for this table")
}
if len(columns) == 0 {
return "", errors.New("No columns found for SimpleSelect")
}
// Slice up the user friendly strings into something easier to process
var colslice = strings.Split(strings.TrimSpace(columns), ",")
var querystr = "SELECT "
// Escape the column names, just in case we've used a reserved keyword
for _, column := range colslice {
querystr += "`" + strings.TrimSpace(column) + "`,"
}
// Remove the trailing comma
querystr = querystr[0 : len(querystr)-1]
querystr += " FROM `" + table + "`"
// Add support for BETWEEN x.x
// TODO: Add support for BETWEEN x.x
func (adapter *MysqlAdapter) buildWhere(where string) (querystr string, err error) {
if len(where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(where) {
@ -373,14 +318,17 @@ func (adapter *MysqlAdapter) SimpleSelect(name string, table string, columns str
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
return querystr, errors.New("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
}
return querystr, nil
}
func (adapter *MysqlAdapter) buildOrderby(orderby string) (querystr string) {
if len(orderby) != 0 {
querystr += " ORDER BY "
for _, column := range processOrderby(orderby) {
@ -389,10 +337,35 @@ func (adapter *MysqlAdapter) SimpleSelect(name string, table string, columns str
}
querystr = querystr[0 : len(querystr)-1]
}
return querystr
}
if limit != "" {
querystr += " LIMIT " + limit
func (adapter *MysqlAdapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
if table == "" {
return "", errors.New("You need a name for this table")
}
if len(columns) == 0 {
return "", errors.New("No columns found for SimpleSelect")
}
var querystr = "SELECT "
// Slice up the user friendly strings into something easier to process
var colslice = strings.Split(strings.TrimSpace(columns), ",")
for _, column := range colslice {
querystr += "`" + strings.TrimSpace(column) + "`,"
}
querystr = querystr[0 : len(querystr)-1]
whereStr, err := adapter.buildWhere(where)
if err != nil {
return querystr, err
}
querystr += " FROM `" + table + "`" + whereStr + adapter.buildOrderby(orderby) + adapter.buildLimit(limit)
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "select", querystr)
@ -435,54 +408,15 @@ func (adapter *MysqlAdapter) SimpleLeftJoin(name string, table1 string, table2 s
}
querystr += source + alias + ","
}
// Remove the trailing comma
querystr = querystr[0 : len(querystr)-1]
querystr += " FROM `" + table1 + "` LEFT JOIN `" + table2 + "` ON "
for _, joiner := range processJoiner(joiners) {
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
}
// Remove the trailing AND
querystr = querystr[0 : len(querystr)-4]
// Add support for BETWEEN x.x
if len(where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
halves := strings.Split(token.Contents, ".")
if len(halves) == 2 {
querystr += " `" + halves[0] + "`.`" + halves[1] + "`"
} else {
querystr += " `" + token.Contents + "`"
}
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
whereStr, err := adapter.buildJoinWhere(where)
if err != nil {
return querystr, err
}
if len(orderby) != 0 {
querystr += " ORDER BY "
for _, column := range processOrderby(orderby) {
querystr += column.Column + " " + strings.ToUpper(column.Order) + ","
}
querystr = querystr[0 : len(querystr)-1]
}
if limit != "" {
querystr += " LIMIT " + limit
}
querystr += " FROM `" + table1 + "` LEFT JOIN `" + table2 + "` ON " + adapter.buildJoiners(joiners) + whereStr + adapter.buildOrderby(orderby) + adapter.buildLimit(limit)
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "select", querystr)
@ -529,50 +463,12 @@ func (adapter *MysqlAdapter) SimpleInnerJoin(name string, table1 string, table2
// Remove the trailing comma
querystr = querystr[0 : len(querystr)-1]
querystr += " FROM `" + table1 + "` INNER JOIN `" + table2 + "` ON "
for _, joiner := range processJoiner(joiners) {
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
}
// Remove the trailing AND
querystr = querystr[0 : len(querystr)-4]
// Add support for BETWEEN x.x
if len(where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
halves := strings.Split(token.Contents, ".")
if len(halves) == 2 {
querystr += " `" + halves[0] + "`.`" + halves[1] + "`"
} else {
querystr += " `" + token.Contents + "`"
}
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
whereStr, err := adapter.buildJoinWhere(where)
if err != nil {
return querystr, err
}
if len(orderby) != 0 {
querystr += " ORDER BY "
for _, column := range processOrderby(orderby) {
querystr += column.Column + " " + strings.ToUpper(column.Order) + ","
}
querystr = querystr[0 : len(querystr)-1]
}
if limit != "" {
querystr += " LIMIT " + limit
}
querystr += " FROM `" + table1 + "` INNER JOIN `" + table2 + "` ON " + adapter.buildJoiners(joiners) + whereStr + adapter.buildOrderby(orderby) + adapter.buildLimit(limit)
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "select", querystr)
@ -581,7 +477,6 @@ func (adapter *MysqlAdapter) SimpleInnerJoin(name string, table1 string, table2
func (adapter *MysqlAdapter) SimpleInsertSelect(name string, ins DB_Insert, sel DB_Select) (string, error) {
/* Insert Portion */
var querystr = "INSERT INTO `" + ins.Table + "`("
// Escape the column names, just in case we've used a reserved keyword
@ -613,40 +508,12 @@ func (adapter *MysqlAdapter) SimpleInsertSelect(name string, ins DB_Insert, sel
}
querystr = querystr[0 : len(querystr)-1]
querystr += " FROM `" + sel.Table + "`"
// Add support for BETWEEN x.x
if len(sel.Where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(sel.Where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
querystr += " `" + token.Contents + "`"
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
whereStr, err := adapter.buildWhere(sel.Where)
if err != nil {
return querystr, err
}
if len(sel.Orderby) != 0 {
querystr += " ORDER BY "
for _, column := range processOrderby(sel.Orderby) {
querystr += column.Column + " " + strings.ToUpper(column.Order) + ","
}
querystr = querystr[0 : len(querystr)-1]
}
if sel.Limit != "" {
querystr += " LIMIT " + sel.Limit
}
querystr += " FROM `" + sel.Table + "`" + whereStr + adapter.buildOrderby(sel.Orderby) + adapter.buildLimit(sel.Limit)
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "insert", querystr)
@ -655,7 +522,6 @@ func (adapter *MysqlAdapter) SimpleInsertSelect(name string, ins DB_Insert, sel
func (adapter *MysqlAdapter) SimpleInsertLeftJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
/* Insert Portion */
var querystr = "INSERT INTO `" + ins.Table + "`("
// Escape the column names, just in case we've used a reserved keyword
@ -689,16 +555,32 @@ func (adapter *MysqlAdapter) SimpleInsertLeftJoin(name string, ins DB_Insert, se
}
querystr = querystr[0 : len(querystr)-1]
querystr += " FROM `" + sel.Table1 + "` LEFT JOIN `" + sel.Table2 + "` ON "
for _, joiner := range processJoiner(sel.Joiners) {
whereStr, err := adapter.buildJoinWhere(sel.Where)
if err != nil {
return querystr, err
}
querystr += " FROM `" + sel.Table1 + "` LEFT JOIN `" + sel.Table2 + "` ON " + adapter.buildJoiners(sel.Joiners) + whereStr + adapter.buildOrderby(sel.Orderby) + adapter.buildLimit(sel.Limit)
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "insert", querystr)
return querystr, nil
}
// TODO: Make this more consistent with the other build* methods?
func (adapter *MysqlAdapter) buildJoiners(joiners string) (querystr string) {
for _, joiner := range processJoiner(joiners) {
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
}
querystr = querystr[0 : len(querystr)-4]
// Remove the trailing AND
return querystr[0 : len(querystr)-4]
}
// Add support for BETWEEN x.x
if len(sel.Where) != 0 {
// Add support for BETWEEN x.x
func (adapter *MysqlAdapter) buildJoinWhere(where string) (querystr string, err error) {
if len(where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(sel.Where) {
for _, loc := range processWhere(where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
@ -713,34 +595,25 @@ func (adapter *MysqlAdapter) SimpleInsertLeftJoin(name string, ins DB_Insert, se
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
return querystr, errors.New("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
}
if len(sel.Orderby) != 0 {
querystr += " ORDER BY "
for _, column := range processOrderby(sel.Orderby) {
querystr += column.Column + " " + strings.ToUpper(column.Order) + ","
}
querystr = querystr[0 : len(querystr)-1]
}
if sel.Limit != "" {
querystr += " LIMIT " + sel.Limit
}
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "insert", querystr)
return querystr, nil
}
func (adapter *MysqlAdapter) buildLimit(limit string) (querystr string) {
if limit != "" {
querystr += " LIMIT " + limit
}
return querystr
}
func (adapter *MysqlAdapter) SimpleInsertInnerJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
/* Insert Portion */
var querystr = "INSERT INTO `" + ins.Table + "`("
// Escape the column names, just in case we've used a reserved keyword
@ -774,56 +647,19 @@ func (adapter *MysqlAdapter) SimpleInsertInnerJoin(name string, ins DB_Insert, s
}
querystr = querystr[0 : len(querystr)-1]
querystr += " FROM `" + sel.Table1 + "` INNER JOIN `" + sel.Table2 + "` ON "
for _, joiner := range processJoiner(sel.Joiners) {
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
}
querystr = querystr[0 : len(querystr)-4]
// Add support for BETWEEN x.x
if len(sel.Where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(sel.Where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
halves := strings.Split(token.Contents, ".")
if len(halves) == 2 {
querystr += " `" + halves[0] + "`.`" + halves[1] + "`"
} else {
querystr += " `" + token.Contents + "`"
}
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
whereStr, err := adapter.buildJoinWhere(sel.Where)
if err != nil {
return querystr, err
}
if len(sel.Orderby) != 0 {
querystr += " ORDER BY "
for _, column := range processOrderby(sel.Orderby) {
querystr += column.Column + " " + strings.ToUpper(column.Order) + ","
}
querystr = querystr[0 : len(querystr)-1]
}
if sel.Limit != "" {
querystr += " LIMIT " + sel.Limit
}
querystr += " FROM `" + sel.Table1 + "` INNER JOIN `" + sel.Table2 + "` ON " + adapter.buildJoiners(sel.Joiners) + whereStr + adapter.buildOrderby(sel.Orderby) + adapter.buildLimit(sel.Limit)
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "insert", querystr)
return querystr, nil
}
func (adapter *MysqlAdapter) SimpleCount(name string, table string, where string, limit string) (string, error) {
func (adapter *MysqlAdapter) SimpleCount(name string, table string, where string, limit string) (querystr string, err error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
@ -831,31 +667,12 @@ func (adapter *MysqlAdapter) SimpleCount(name string, table string, where string
return "", errors.New("You need a name for this table")
}
var querystr = "SELECT COUNT(*) AS `count` FROM `" + table + "`"
// TODO: Add support for BETWEEN x.x
if len(where) != 0 {
querystr += " WHERE"
//log.Print("SimpleCount: ", name)
//log.Print("where: ", where)
//log.Print("processWhere: ", processWhere(where))
for _, loc := range processWhere(where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
querystr += " `" + token.Contents + "`"
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
querystr = "SELECT COUNT(*) AS `count` FROM `" + table + "`"
whereStr, err := adapter.buildWhere(where)
if err != nil {
return "", err
}
querystr += whereStr
if limit != "" {
querystr += " LIMIT " + limit

View File

@ -351,7 +351,7 @@ var topic_alt_29 = []byte(`</textarea>
<div class="button_container">
`)
var topic_alt_30 = []byte(`<a href="/topic/like/submit/`)
var topic_alt_31 = []byte(`" class="action_button like_item">+1</a>`)
var topic_alt_31 = []byte(`" class="action_button like_item add_like">+1</a>`)
var topic_alt_32 = []byte(`<a href="/topic/edit/`)
var topic_alt_33 = []byte(`" class="action_button open_edit">Edit</a>`)
var topic_alt_34 = []byte(`<a href="/topic/delete/submit/`)
@ -420,7 +420,7 @@ var topic_alt_72 = []byte(`</div>
<div class="button_container">
`)
var topic_alt_73 = []byte(`<a href="/reply/like/submit/`)
var topic_alt_74 = []byte(`" class="action_button like_item">+1</a>`)
var topic_alt_74 = []byte(`" class="action_button like_item add_like">+1</a>`)
var topic_alt_75 = []byte(`<a href="/reply/edit/submit/`)
var topic_alt_76 = []byte(`" class="action_button edit_item">Edit</a>`)
var topic_alt_77 = []byte(`<a href="/reply/delete/submit/`)

View File

@ -34,7 +34,7 @@
<textarea name="topic_content" class="show_on_edit topic_content_input">{{.Topic.Content}}</textarea>
<div class="button_container">
{{if .CurrentUser.Loggedin}}
{{if .CurrentUser.Perms.LikeItem}}<a href="/topic/like/submit/{{.Topic.ID}}" class="action_button like_item">+1</a>{{end}}
{{if .CurrentUser.Perms.LikeItem}}<a href="/topic/like/submit/{{.Topic.ID}}" class="action_button like_item add_like">+1</a>{{end}}
{{if .CurrentUser.Perms.EditTopic}}<a href="/topic/edit/{{.Topic.ID}}" class="action_button open_edit">Edit</a>{{end}}
{{if .CurrentUser.Perms.DeleteTopic}}<a href="/topic/delete/submit/{{.Topic.ID}}" class="action_button delete_item">Delete</a>{{end}}
{{if .CurrentUser.Perms.CloseTopic}}
@ -68,7 +68,7 @@
<div class="editable_block user_content" itemprop="text">{{.ContentHtml}}</div>
<div class="button_container">
{{if $.CurrentUser.Loggedin}}
{{if $.CurrentUser.Perms.LikeItem}}<a href="/reply/like/submit/{{.ID}}" class="action_button like_item">+1</a>{{end}}
{{if $.CurrentUser.Perms.LikeItem}}<a href="/reply/like/submit/{{.ID}}" class="action_button like_item add_like">+1</a>{{end}}
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}" class="action_button edit_item">Edit</a>{{end}}
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}" class="action_button delete_item">Delete</a>{{end}}
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="action_button report_item">Report</a>

View File

@ -411,13 +411,20 @@ select, input, textarea {
.topic_reply_form {
margin: 0px;
width: 100%;
height: min-content;
}
.topic_reply_form .trumbowyg-button-pane:after {
display: none;
}
.topic_reply_form .trumbowyg-box {
min-height: auto;
}
.topic_reply_form .trumbowyg-editor {
border-left: none;
border-right: none;
min-height: 103px;
max-height: 200px;
overflow-y: scroll;
}
.topic_reply_form .quick_button_row {
margin-bottom: 7px;
@ -673,13 +680,21 @@ select, input, textarea {
content: " likes";
margin-right: 6px;
}
.created_at:before, .ip_item:before {
.post_item .add_like:after, .created_at:before, .ip_item:before {
border-left: 1px solid var(--element-border-color);
content: "";
margin-right: 10px;
margin-top: 1px;
margin-bottom: 1px;
}
.created_at:before, .ip_item:before {
margin-right: 10px;
}
.post_item .add_like:after {
margin-left: 10px;
margin-right: 5px;
}
.created_at {
margin-right: 10px;
}

View File

@ -9,8 +9,13 @@ $(document).ready(function(){
$(".topic_create_form").addClass("selectedInput");
});
//$.trumbowyg.svgPath = false;
$('#input_content').trumbowyg({
$('.topic_create_form #input_content').trumbowyg({
btns: [['viewHTML'],['undo','redo'],['formatting'],['strong','em','del'],['link'],['insertImage'],['unorderedList','orderedList'],['removeformat']],
//hideButtonTexts: true
});
$('.topic_reply_form #input_content').trumbowyg({
btns: [['viewHTML'],['undo','redo'],['formatting'],['strong','em','del'],['link'],['insertImage'],['unorderedList','orderedList'],['removeformat']],
autogrow: true,
//hideButtonTexts: true
});
});

View File

@ -21,3 +21,6 @@ go get -u gopkg.in/sourcemap.v1
echo "Updating OttoJS"
go get -u github.com/robertkrimen/otto
echo "Updating the Riot Search Engine"
go get -u github.com/go-ego/riot

View File

@ -68,5 +68,12 @@ if %errorlevel% neq 0 (
exit /b %errorlevel%
)
echo Installing the Riot Search Engine
go get -u github.com/go-ego/riot
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
echo The dependencies were successfully updated
pause

50
user.go
View File

@ -228,11 +228,11 @@ func (user *User) ChangeGroup(group int) (err error) {
return err
}
func (user *User) increasePostStats(wcount int, topic bool) error {
func (user *User) increasePostStats(wcount int, topic bool) (err error) {
var mod int
baseScore := 1
if topic {
_, err := incrementUserTopicsStmt.Exec(1, user.ID)
_, err = incrementUserTopicsStmt.Exec(1, user.ID)
if err != nil {
return err
}
@ -241,24 +241,19 @@ func (user *User) increasePostStats(wcount int, topic bool) error {
settings := settingBox.Load().(SettingBox)
if wcount >= settings["megapost_min_words"].(int) {
_, err := incrementUserMegapostsStmt.Exec(1, 1, 1, user.ID)
if err != nil {
return err
}
_, err = incrementUserMegapostsStmt.Exec(1, 1, 1, user.ID)
mod = 4
} else if wcount >= settings["bigpost_min_words"].(int) {
_, err := incrementUserBigpostsStmt.Exec(1, 1, user.ID)
if err != nil {
return err
}
_, err = incrementUserBigpostsStmt.Exec(1, 1, user.ID)
mod = 1
} else {
_, err := incrementUserPostsStmt.Exec(1, user.ID)
if err != nil {
return err
}
_, err = incrementUserPostsStmt.Exec(1, user.ID)
}
_, err := incrementUserScoreStmt.Exec(baseScore+mod, user.ID)
if err != nil {
return err
}
_, err = incrementUserScoreStmt.Exec(baseScore+mod, user.ID)
if err != nil {
return err
}
@ -269,11 +264,11 @@ func (user *User) increasePostStats(wcount int, topic bool) error {
return err
}
func (user *User) decreasePostStats(wcount int, topic bool) error {
func (user *User) decreasePostStats(wcount int, topic bool) (err error) {
var mod int
baseScore := -1
if topic {
_, err := incrementUserTopicsStmt.Exec(-1, user.ID)
_, err = incrementUserTopicsStmt.Exec(-1, user.ID)
if err != nil {
return err
}
@ -282,24 +277,19 @@ func (user *User) decreasePostStats(wcount int, topic bool) error {
settings := settingBox.Load().(SettingBox)
if wcount >= settings["megapost_min_words"].(int) {
_, err := incrementUserMegapostsStmt.Exec(-1, -1, -1, user.ID)
if err != nil {
return err
}
_, err = incrementUserMegapostsStmt.Exec(-1, -1, -1, user.ID)
mod = 4
} else if wcount >= settings["bigpost_min_words"].(int) {
_, err := incrementUserBigpostsStmt.Exec(-1, -1, user.ID)
if err != nil {
return err
}
_, err = incrementUserBigpostsStmt.Exec(-1, -1, user.ID)
mod = 1
} else {
_, err := incrementUserPostsStmt.Exec(-1, user.ID)
if err != nil {
return err
}
_, err = incrementUserPostsStmt.Exec(-1, user.ID)
}
_, err := incrementUserScoreStmt.Exec(baseScore-mod, user.ID)
if err != nil {
return err
}
_, err = incrementUserScoreStmt.Exec(baseScore-mod, user.ID)
if err != nil {
return err
}