gosora/patcher/patches.go

895 lines
28 KiB
Go

package main
import (
"bufio"
"database/sql"
"strconv"
"strings"
"unicode"
meta "github.com/Azareal/Gosora/common/meta"
qgen "github.com/Azareal/Gosora/query_gen"
)
type tblColumn = qgen.DBTableColumn
type tC = tblColumn
type tblKey = qgen.DBTableKey
type tK = tblKey
func init() {
addPatch(0, patch0)
addPatch(1, patch1)
addPatch(2, patch2)
addPatch(3, patch3)
addPatch(4, patch4)
addPatch(5, patch5)
addPatch(6, patch6)
addPatch(7, patch7)
addPatch(8, patch8)
addPatch(9, patch9)
addPatch(10, patch10)
addPatch(11, patch11)
addPatch(12, patch12)
addPatch(13, patch13)
addPatch(14, patch14)
addPatch(15, patch15)
addPatch(16, patch16)
addPatch(17, patch17)
addPatch(18, patch18)
addPatch(19, patch19)
addPatch(20, patch20)
addPatch(21, patch21)
addPatch(22, patch22)
addPatch(23, patch23)
addPatch(24, patch24)
addPatch(25, patch25)
addPatch(26, patch26)
addPatch(27, patch27)
addPatch(28, patch28)
addPatch(29, patch29)
addPatch(30, patch30)
addPatch(31, patch31)
}
func patch0(scanner *bufio.Scanner) (err error) {
err = execStmt(qgen.Builder.DropTable("menus"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.DropTable("menu_items"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.CreateTable("menus", "", "",
[]tC{
tC{"mid", "int", 0, false, true, ""},
},
[]tK{
tK{"mid", "primary", "", false},
},
))
if err != nil {
return err
}
err = execStmt(qgen.Builder.CreateTable("menu_items", "", "",
[]tC{
tC{"miid", "int", 0, false, true, ""},
tC{"mid", "int", 0, false, false, ""},
tC{"name", "varchar", 200, false, false, ""},
tC{"htmlID", "varchar", 200, false, false, "''"},
tC{"cssClass", "varchar", 200, false, false, "''"},
tC{"position", "varchar", 100, false, false, ""},
tC{"path", "varchar", 200, false, false, "''"},
tC{"aria", "varchar", 200, false, false, "''"},
tC{"tooltip", "varchar", 200, false, false, "''"},
tC{"tmplName", "varchar", 200, false, false, "''"},
tC{"order", "int", 0, false, false, "0"},
tC{"guestOnly", "boolean", 0, false, false, "0"},
tC{"memberOnly", "boolean", 0, false, false, "0"},
tC{"staffOnly", "boolean", 0, false, false, "0"},
tC{"adminOnly", "boolean", 0, false, false, "0"},
},
[]tK{
tK{"miid", "primary", "", false},
},
))
if err != nil {
return err
}
err = execStmt(qgen.Builder.SimpleInsert("menus", "", ""))
if err != nil {
return err
}
var order int
mOrder := "mid, name, htmlID, cssClass, position, path, aria, tooltip, guestOnly, memberOnly, staffOnly, adminOnly"
addMenuItem := func(data map[string]interface{}) error {
cols, values := qgen.InterfaceMapToInsertStrings(data, mOrder)
err := execStmt(qgen.Builder.SimpleInsert("menu_items", cols+", order", values+","+strconv.Itoa(order)))
order++
return err
}
err = addMenuItem(map[string]interface{}{"mid": 1, "name": "{lang.menu_forums}", "htmlID": "menu_forums", "position": "left", "path": "/forums/", "aria": "{lang.menu_forums_aria}", "tooltip": "{lang.menu_forums_tooltip}"})
if err != nil {
return err
}
err = addMenuItem(map[string]interface{}{"mid": 1, "name": "{lang.menu_topics}", "htmlID": "menu_topics", "cssClass": "menu_topics", "position": "left", "path": "/topics/", "aria": "{lang.menu_topics_aria}", "tooltip": "{lang.menu_topics_tooltip}"})
if err != nil {
return err
}
err = addMenuItem(map[string]interface{}{"mid": 1, "htmlID": "general_alerts", "cssClass": "menu_alerts", "position": "right", "tmplName": "menu_alerts"})
if err != nil {
return err
}
err = addMenuItem(map[string]interface{}{"mid": 1, "name": "{lang.menu_account}", "cssClass": "menu_account", "position": "left", "path": "/user/edit/critical/", "aria": "{lang.menu_account_aria}", "tooltip": "{lang.menu_account_tooltip}", "memberOnly": true})
if err != nil {
return err
}
err = addMenuItem(map[string]interface{}{"mid": 1, "name": "{lang.menu_profile}", "cssClass": "menu_profile", "position": "left", "path": "{me.Link}", "aria": "{lang.menu_profile_aria}", "tooltip": "{lang.menu_profile_tooltip}", "memberOnly": true})
if err != nil {
return err
}
err = addMenuItem(map[string]interface{}{"mid": 1, "name": "{lang.menu_panel}", "cssClass": "menu_panel menu_account", "position": "left", "path": "/panel/", "aria": "{lang.menu_panel_aria}", "tooltip": "{lang.menu_panel_tooltip}", "memberOnly": true, "staffOnly": true})
if err != nil {
return err
}
err = addMenuItem(map[string]interface{}{"mid": 1, "name": "{lang.menu_logout}", "cssClass": "menu_logout", "position": "left", "path": "/accounts/logout/?session={me.Session}", "aria": "{lang.menu_logout_aria}", "tooltip": "{lang.menu_logout_tooltip}", "memberOnly": true})
if err != nil {
return err
}
err = addMenuItem(map[string]interface{}{"mid": 1, "name": "{lang.menu_register}", "cssClass": "menu_register", "position": "left", "path": "/accounts/create/", "aria": "{lang.menu_register_aria}", "tooltip": "{lang.menu_register_tooltip}", "guestOnly": true})
if err != nil {
return err
}
err = addMenuItem(map[string]interface{}{"mid": 1, "name": "{lang.menu_login}", "cssClass": "menu_login", "position": "left", "path": "/accounts/login/", "aria": "{lang.menu_login_aria}", "tooltip": "{lang.menu_login_tooltip}", "guestOnly": true})
if err != nil {
return err
}
return nil
}
func patch1(scanner *bufio.Scanner) error {
routes := map[string]string{
"routeAccountEditCriticalSubmit": "routes.AccountEditCriticalSubmit",
"routeAccountEditAvatar": "routes.AccountEditAvatar",
"routeAccountEditAvatarSubmit": "routes.AccountEditAvatarSubmit",
"routeAccountEditUsername": "routes.AccountEditUsername",
"routeAccountEditUsernameSubmit": "routes.AccountEditUsernameSubmit",
}
return renameRoutes(routes)
}
func patch2(scanner *bufio.Scanner) error {
routes := map[string]string{
"routeLogout": "routes.AccountLogout",
"routeShowAttachment": "routes.ShowAttachment",
"routeChangeTheme": "routes.ChangeTheme",
"routeProfileReplyCreateSubmit": "routes.ProfileReplyCreateSubmit",
"routeLikeTopicSubmit": "routes.LikeTopicSubmit",
"routeReplyLikeSubmit": "routes.ReplyLikeSubmit",
"routeDynamic": "routes.DynamicRoute",
"routeUploads": "routes.UploadedFile",
"BadRoute": "routes.BadRoute",
}
return renameRoutes(routes)
}
func patch3(scanner *bufio.Scanner) error {
return execStmt(qgen.Builder.CreateTable("registration_logs", "", "",
[]tC{
tC{"rlid", "int", 0, false, true, ""},
tC{"username", "varchar", 100, false, false, ""},
tC{"email", "varchar", 100, false, false, ""},
tC{"failureReason", "varchar", 100, false, false, ""},
tC{"success", "bool", 0, false, false, "0"}, // Did this attempt succeed?
tC{"ipaddress", "varchar", 200, false, false, ""},
tC{"doneAt", "createdAt", 0, false, false, ""},
},
[]tK{
tK{"rlid", "primary", "", false},
},
))
}
func patch4(scanner *bufio.Scanner) error {
routes := map[string]string{
"routeReportSubmit": "routes.ReportSubmit",
"routeAccountEditEmail": "routes.AccountEditEmail",
"routeAccountEditEmailTokenSubmit": "routes.AccountEditEmailTokenSubmit",
"routePanelLogsRegs": "panel.LogsRegs",
"routePanelLogsMod": "panel.LogsMod",
"routePanelLogsAdmin": "panel.LogsAdmin",
"routePanelDebug": "panel.Debug",
"routePanelAnalyticsViews": "panel.AnalyticsViews",
"routePanelAnalyticsRouteViews": "panel.AnalyticsRouteViews",
"routePanelAnalyticsAgentViews": "panel.AnalyticsAgentViews",
"routePanelAnalyticsForumViews": "panel.AnalyticsForumViews",
"routePanelAnalyticsSystemViews": "panel.AnalyticsSystemViews",
"routePanelAnalyticsLanguageViews": "panel.AnalyticsLanguageViews",
"routePanelAnalyticsReferrerViews": "panel.AnalyticsReferrerViews",
"routePanelAnalyticsTopics": "panel.AnalyticsTopics",
"routePanelAnalyticsPosts": "panel.AnalyticsPosts",
"routePanelAnalyticsForums": "panel.AnalyticsForums",
"routePanelAnalyticsRoutes": "panel.AnalyticsRoutes",
"routePanelAnalyticsAgents": "panel.AnalyticsAgents",
"routePanelAnalyticsSystems": "panel.AnalyticsSystems",
"routePanelAnalyticsLanguages": "panel.AnalyticsLanguages",
"routePanelAnalyticsReferrers": "panel.AnalyticsReferrers",
"routePanelSettings": "panel.Settings",
"routePanelSettingEdit": "panel.SettingEdit",
"routePanelSettingEditSubmit": "panel.SettingEditSubmit",
"routePanelForums": "panel.Forums",
"routePanelForumsCreateSubmit": "panel.ForumsCreateSubmit",
"routePanelForumsDelete": "panel.ForumsDelete",
"routePanelForumsDeleteSubmit": "panel.ForumsDeleteSubmit",
"routePanelForumsEdit": "panel.ForumsEdit",
"routePanelForumsEditSubmit": "panel.ForumsEditSubmit",
"routePanelForumsEditPermsSubmit": "panel.ForumsEditPermsSubmit",
"routePanelForumsEditPermsAdvance": "panel.ForumsEditPermsAdvance",
"routePanelForumsEditPermsAdvanceSubmit": "panel.ForumsEditPermsAdvanceSubmit",
"routePanelBackups": "panel.Backups",
}
err := renameRoutes(routes)
if err != nil {
return err
}
err = execStmt(qgen.Builder.SimpleDelete("settings", "name='url_tags'"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.CreateTable("pages", "utf8mb4", "utf8mb4_general_ci",
[]tC{
tC{"pid", "int", 0, false, true, ""},
tC{"name", "varchar", 200, false, false, ""},
tC{"title", "varchar", 200, false, false, ""},
tC{"body", "text", 0, false, false, ""},
tC{"allowedGroups", "text", 0, false, false, ""},
tC{"menuID", "int", 0, false, false, "-1"},
},
[]tK{
tK{"pid", "primary", "", false},
},
))
if err != nil {
return err
}
return nil
}
func patch5(scanner *bufio.Scanner) error {
routes := map[string]string{
"routePanelUsers": "panel.Users",
"routePanelUsersEdit": "panel.UsersEdit",
"routePanelUsersEditSubmit": "panel.UsersEditSubmit",
"routes.AccountEditCritical": "routes.AccountEditPassword",
"routes.AccountEditCriticalSubmit": "routes.AccountEditPasswordSubmit",
}
err := renameRoutes(routes)
if err != nil {
return err
}
err = execStmt(qgen.Builder.SimpleUpdate("menu_items", "path='/user/edit/'", "path='/user/edit/critical/'"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.CreateTable("users_2fa_keys", "utf8mb4", "utf8mb4_general_ci",
[]tC{
tC{"uid", "int", 0, false, false, ""},
tC{"secret", "varchar", 100, false, false, ""},
tC{"scratch1", "varchar", 50, false, false, ""},
tC{"scratch2", "varchar", 50, false, false, ""},
tC{"scratch3", "varchar", 50, false, false, ""},
tC{"scratch4", "varchar", 50, false, false, ""},
tC{"scratch5", "varchar", 50, false, false, ""},
tC{"scratch6", "varchar", 50, false, false, ""},
tC{"scratch7", "varchar", 50, false, false, ""},
tC{"scratch8", "varchar", 50, false, false, ""},
tC{"createdAt", "createdAt", 0, false, false, ""},
},
[]tK{
tK{"uid", "primary", "", false},
},
))
if err != nil {
return err
}
return nil
}
func patch6(scanner *bufio.Scanner) error {
return execStmt(qgen.Builder.SimpleInsert("settings", "name, content, type", "'rapid_loading','1','bool'"))
}
func patch7(scanner *bufio.Scanner) error {
return execStmt(qgen.Builder.CreateTable("users_avatar_queue", "", "",
[]tC{
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
},
[]tK{
tK{"uid", "primary", "", false},
},
))
}
func renameRoutes(routes map[string]string) error {
// ! Don't reuse this function blindly, it doesn't escape apostrophes
replaceTextWhere := func(replaceThis string, withThis string) error {
return execStmt(qgen.Builder.SimpleUpdate("viewchunks", "route = '"+withThis+"'", "route = '"+replaceThis+"'"))
}
for key, value := range routes {
err := replaceTextWhere(key, value)
if err != nil {
return err
}
}
return nil
}
func patch8(scanner *bufio.Scanner) error {
routes := map[string]string{
"routePanelWordFilter": "panel.WordFilters",
"routePanelWordFiltersCreateSubmit": "panel.WordFiltersCreateSubmit",
"routePanelWordFiltersEdit": "panel.WordFiltersEdit",
"routePanelWordFiltersEditSubmit": "panel.WordFiltersEditSubmit",
"routePanelWordFiltersDeleteSubmit": "panel.WordFiltersDeleteSubmit",
"routePanelPlugins": "panel.Plugins",
"routePanelPluginsActivate": "panel.PluginsActivate",
"routePanelPluginsDeactivate": "panel.PluginsDeactivate",
"routePanelPluginsInstall": "panel.PluginsInstall",
"routePanelGroups": "panel.Groups",
"routePanelGroupsEdit": "panel.GroupsEdit",
"routePanelGroupsEditPerms": "panel.GroupsEditPerms",
"routePanelGroupsEditSubmit": "panel.GroupsEditSubmit",
"routePanelGroupsEditPermsSubmit": "panel.GroupsEditPermsSubmit",
"routePanelGroupsCreateSubmit": "panel.GroupsCreateSubmit",
"routePanelThemes": "panel.Themes",
"routePanelThemesSetDefault": "panel.ThemesSetDefault",
"routePanelThemesMenus": "panel.ThemesMenus",
"routePanelThemesMenusEdit": "panel.ThemesMenusEdit",
"routePanelThemesMenuItemEdit": "panel.ThemesMenuItemEdit",
"routePanelThemesMenuItemEditSubmit": "panel.ThemesMenuItemEditSubmit",
"routePanelThemesMenuItemCreateSubmit": "panel.ThemesMenuItemCreateSubmit",
"routePanelThemesMenuItemDeleteSubmit": "panel.ThemesMenuItemDeleteSubmit",
"routePanelThemesMenuItemOrderSubmit": "panel.ThemesMenuItemOrderSubmit",
"routePanelDashboard": "panel.Dashboard",
}
err := renameRoutes(routes)
if err != nil {
return err
}
err = execStmt(qgen.Builder.DropTable("updates"))
if err != nil {
return err
}
return execStmt(qgen.Builder.CreateTable("updates", "", "",
[]tC{
tC{"dbVersion", "int", 0, false, false, "0"},
}, nil,
))
}
func patch9(scanner *bufio.Scanner) error {
// Table "updates" might not exist due to the installer, so drop it and remake it if so
err := patch8(scanner)
if err != nil {
return err
}
return execStmt(qgen.Builder.CreateTable("login_logs", "", "",
[]tC{
tC{"lid", "int", 0, false, true, ""},
tC{"uid", "int", 0, false, false, ""},
tC{"success", "bool", 0, false, false, "0"}, // Did this attempt succeed?
tC{"ipaddress", "varchar", 200, false, false, ""},
tC{"doneAt", "createdAt", 0, false, false, ""},
},
[]tK{
tK{"lid", "primary", "", false},
},
))
}
var acc = qgen.NewAcc
var itoa = strconv.Itoa
func patch10(scanner *bufio.Scanner) error {
err := execStmt(qgen.Builder.AddColumn("topics", tC{"attachCount", "int", 0, false, false, "0"}, nil))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddColumn("topics", tC{"lastReplyID", "int", 0, false, false, "0"}, nil))
if err != nil {
return err
}
err = acc().Select("topics").Cols("tid").EachInt(func(tid int) error {
stid := itoa(tid)
count, err := acc().Count("attachments").Where("originTable = 'topics' and originID = " + stid).Total()
if err != nil {
return err
}
hasReply := false
err = acc().Select("replies").Cols("rid").Where("tid = " + stid).Orderby("rid DESC").Limit("1").EachInt(func(rid int) error {
hasReply = true
_, err := acc().Update("topics").Set("lastReplyID = ?, attachCount = ?").Where("tid = "+stid).Exec(rid, count)
return err
})
if err != nil {
return err
}
if !hasReply {
_, err = acc().Update("topics").Set("attachCount = ?").Where("tid = " + stid).Exec(count)
}
return err
})
if err != nil {
return err
}
_, err = acc().Insert("updates").Columns("dbVersion").Fields("0").Exec()
return err
}
func patch11(scanner *bufio.Scanner) error {
err := execStmt(qgen.Builder.AddColumn("replies", tC{"attachCount", "int", 0, false, false, "0"}, nil))
if err != nil {
return err
}
// Attachments for replies got the topicID rather than the replyID for a while in error, so we want to separate these out
_, err = acc().Update("attachments").Set("originTable = 'freplies'").Where("originTable = 'replies'").Exec()
if err != nil {
return err
}
// We could probably do something more efficient, but as there shouldn't be too many sites right now, we can probably cheat a little, otherwise it'll take forever to get things done
return acc().Select("topics").Cols("tid").EachInt(func(tid int) error {
stid := itoa(tid)
count, err := acc().Count("attachments").Where("originTable='topics' and originID=" + stid).Total()
if err != nil {
return err
}
_, err = acc().Update("topics").Set("attachCount = ?").Where("tid = " + stid).Exec(count)
return err
})
/*return acc().Select("replies").Cols("rid").EachInt(func(rid int) error {
srid := itoa(rid)
count, err := acc().Count("attachments").Where("originTable='replies' and originID=" + srid).Total()
if err != nil {
return err
}
_, err = acc().Update("replies").Set("attachCount = ?").Where("rid=" + srid).Exec(count)
return err
})*/
}
func patch12(scanner *bufio.Scanner) error {
err := execStmt(qgen.Builder.AddIndex("topics", "parentID", "parentID"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddIndex("replies", "tid", "tid"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddIndex("polls", "parentID", "parentID"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddIndex("likes", "targetItem", "targetItem"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddIndex("emails", "uid", "uid"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddIndex("attachments", "originID", "originID"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddIndex("attachments", "path", "path"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddIndex("activity_stream_matches", "watcher", "watcher"))
if err != nil {
return err
}
return nil
}
func patch13(scanner *bufio.Scanner) error {
return execStmt(qgen.Builder.AddColumn("widgets", tC{"wid", "int", 0, false, true, ""}, &tK{"wid", "primary", "", false}))
}
func patch14(scanner *bufio.Scanner) error {
/*err := execStmt(qgen.Builder.AddKey("topics", "title", tK{"title", "fulltext", "", false}))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddKey("topics", "content", tK{"content", "fulltext", "", false}))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddKey("replies", "content", tK{"content", "fulltext", "", false}))
if err != nil {
return err
}*/
return nil
}
func patch15(scanner *bufio.Scanner) error {
return execStmt(qgen.Builder.SimpleInsert("settings", "name, content, type", "'google_site_verify','','html-attribute'"))
}
func patch16(scanner *bufio.Scanner) error {
return execStmt(qgen.Builder.CreateTable("password_resets", "", "",
[]tC{
tC{"email", "varchar", 200, false, false, ""},
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
tC{"validated", "varchar", 200, false, false, ""}, // Token given once the one-use token is consumed, used to prevent multiple people consuming the same one-use token
tC{"token", "varchar", 200, false, false, ""},
tC{"createdAt", "createdAt", 0, false, false, ""},
}, nil,
))
}
func patch17(scanner *bufio.Scanner) error {
err := execStmt(qgen.Builder.AddColumn("attachments", tC{"extra", "varchar", 200, false, false, ""}, nil))
if err != nil {
return err
}
err = acc().Select("topics").Cols("tid, parentID").Where("attachCount > 0").Each(func(rows *sql.Rows) error {
var tid, parentID int
err := rows.Scan(&tid, &parentID)
if err != nil {
return err
}
_, err = acc().Update("attachments").Set("sectionID = ?").Where("originTable = 'topics' AND originID = ?").Exec(parentID, tid)
return err
})
if err != nil {
return err
}
return acc().Select("replies").Cols("rid, tid").Where("attachCount > 0").Each(func(rows *sql.Rows) error {
var rid, tid, sectionID int
err := rows.Scan(&rid, &tid)
if err != nil {
return err
}
err = acc().Select("topics").Cols("parentID").Where("tid = ?").QueryRow(tid).Scan(&sectionID)
if err != nil {
return err
}
_, err = acc().Update("attachments").Set("sectionID = ?, extra = ?").Where("originTable = 'replies' AND originID = ?").Exec(sectionID, tid, rid)
return err
})
}
func patch18(scanner *bufio.Scanner) error {
return execStmt(qgen.Builder.AddColumn("forums", tC{"order", "int", 0, false, false, "0"}, nil))
}
func patch19(scanner *bufio.Scanner) error {
return execStmt(qgen.Builder.CreateTable("memchunks", "", "",
[]tC{
tC{"count", "int", 0, false, false, "0"},
tC{"createdAt", "datetime", 0, false, false, ""},
}, nil,
))
}
func patch20(scanner *bufio.Scanner) error {
err := acc().Select("activity_stream_matches").Cols("asid").Each(func(rows *sql.Rows) error {
var asid int
err := rows.Scan(&asid)
if err != nil {
return err
}
err = acc().Select("activity_stream").Cols("asid").Where("asid = ?").QueryRow(asid).Scan(&asid)
if err != sql.ErrNoRows {
return err
}
_, err = acc().Delete("activity_stream_matches").Where("asid = ?").Run(asid)
return err
})
if err != nil {
return err
}
return execStmt(qgen.Builder.AddForeignKey("activity_stream_matches", "asid", "activity_stream", "asid", true))
}
func patch21(scanner *bufio.Scanner) error {
err := execStmt(qgen.Builder.AddColumn("memchunks", tC{"stack", "int", 0, false, false, "0"}, nil))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddColumn("memchunks", tC{"heap", "int", 0, false, false, "0"}, nil))
if err != nil {
return err
}
err = execStmt(qgen.Builder.CreateTable("meta", "", "",
[]tC{
tC{"name", "varchar", 200, false, false, ""},
tC{"value", "varchar", 200, false, false, ""},
}, nil,
))
if err != nil {
return err
}
return execStmt(qgen.Builder.AddColumn("activity_stream", tC{"createdAt", "createdAt", 0, false, false, ""}, nil))
}
func patch22(scanner *bufio.Scanner) error {
return execStmt(qgen.Builder.AddColumn("forums", tC{"tmpl", "varchar", 200, false, false, "''"}, nil))
}
func patch23(scanner *bufio.Scanner) error {
err := execStmt(qgen.Builder.DropTable("conversations"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.CreateTable("conversations", "", "",
[]tC{
tC{"cid", "int", 0, false, true, ""},
tC{"createdBy", "int", 0, false, false, ""}, // TODO: Make this a foreign key
tC{"createdAt", "createdAt", 0, false, false, ""},
tC{"lastReplyAt", "datetime", 0, false, false, ""},
tC{"lastReplyBy", "int", 0, false, false, ""},
},
[]tK{
tK{"cid", "primary", "", false},
},
))
if err != nil {
return err
}
err = execStmt(qgen.Builder.DropTable("conversations_posts"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.CreateTable("conversations_posts", "", "",
[]tC{
tC{"pid", "int", 0, false, true, ""},
tC{"cid", "int", 0, false, false, ""},
tC{"createdBy", "int", 0, false, false, ""},
tC{"body", "varchar", 50, false, false, ""},
tC{"post", "varchar", 50, false, false, "''"},
},
[]tK{
tK{"pid", "primary", "", false},
},
))
if err != nil {
return err
}
err = execStmt(qgen.Builder.DropTable("conversations_participants"))
if err != nil {
return err
}
return execStmt(qgen.Builder.CreateTable("conversations_participants", "", "",
[]tC{
tC{"uid", "int", 0, false, false, ""},
tC{"cid", "int", 0, false, false, ""},
}, nil,
))
}
func patch24(scanner *bufio.Scanner) error {
err := execStmt(qgen.Builder.DropTable("users_groups_promotions"))
if err != nil {
return err
}
return execStmt(qgen.Builder.CreateTable("users_groups_promotions", "", "",
[]tC{
tC{"pid", "int", 0, false, true, ""},
tC{"from_gid", "int", 0, false, false, ""},
tC{"to_gid", "int", 0, false, false, ""},
tC{"two_way", "boolean", 0, false, false, "0"}, // If a user no longer meets the requirements for this promotion then they will be demoted if this flag is set
// Requirements
tC{"level", "int", 0, false, false, ""},
tC{"minTime", "int", 0, false, false, ""}, // How long someone needs to have been in their current group before being promoted
},
[]tK{
tK{"pid", "primary", "", false},
},
))
}
func patch25(scanner *bufio.Scanner) error {
return execStmt(qgen.Builder.AddColumn("users_groups_promotions", tC{"posts", "int", 0, false, false, "0"}, nil))
}
func patch26(scanner *bufio.Scanner) error {
return execStmt(qgen.Builder.CreateTable("users_blocks", "", "",
[]tC{
tC{"blocker", "int", 0, false, false, ""},
tC{"blockedUser", "int", 0, false, false, ""},
}, nil,
))
}
func patch27(scanner *bufio.Scanner) error {
err := execStmt(qgen.Builder.AddColumn("moderation_logs", tC{"extra", "text", 0, false, false, ""}, nil))
if err != nil {
return err
}
return execStmt(qgen.Builder.AddColumn("administration_logs", tC{"extra", "text", 0, false, false, ""}, nil))
}
func patch28(scanner *bufio.Scanner) error {
return execStmt(qgen.Builder.AddColumn("users", tC{"enable_embeds", "int", 0, false, false, "-1"}, nil))
}
// The word counter might run into problems with some languages where words aren't as obviously demarcated, I would advise turning it off in those cases, or if it becomes annoying in general, really.
func WordCount(input string) (count int) {
input = strings.TrimSpace(input)
if input == "" {
return 0
}
var inSpace bool
for _, value := range input {
if unicode.IsSpace(value) || unicode.IsPunct(value) {
if !inSpace {
inSpace = true
}
} else if inSpace {
count++
inSpace = false
}
}
return count + 1
}
func patch29(scanner *bufio.Scanner) error {
f := func(tbl, idCol string) error {
return acc().Select(tbl).Cols(idCol + ",content").Each(func(rows *sql.Rows) error {
var id int
var content string
err := rows.Scan(&id, &content)
if err != nil {
return err
}
_, err = acc().Update(tbl).Set("words=?").Where(idCol+"=?").Exec(WordCount(content), id)
return err
})
}
err := f("topics", "tid")
if err != nil {
return err
}
err = f("replies", "rid")
if err != nil {
return err
}
meta, err := meta.NewDefaultMetaStore(acc())
if err != nil {
return err
}
err = meta.Set("sched", "recalc")
if err != nil {
return err
}
fixCol := func(tbl string) error {
//err := execStmt(qgen.Builder.RenameColumn(tbl, "ipaddress","ip"))
err := execStmt(qgen.Builder.ChangeColumn(tbl, "ipaddress", tC{"ip", "varchar", 200, false, false, "''"}))
if err != nil {
return err
}
return execStmt(qgen.Builder.SetDefaultColumn(tbl, "ip", "varchar", ""))
}
err = fixCol("topics")
if err != nil {
return err
}
err = fixCol("replies")
if err != nil {
return err
}
err = fixCol("polls_votes")
if err != nil {
return err
}
err = fixCol("users_replies")
if err != nil {
return err
}
err = execStmt(qgen.Builder.SetDefaultColumn("replies", "lastEdit", "int", "0"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.SetDefaultColumn("replies", "lastEditBy", "int", "0"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.SetDefaultColumn("users_replies", "lastEdit", "int", "0"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.SetDefaultColumn("users_replies", "lastEditBy", "int", "0"))
if err != nil {
return err
}
return execStmt(qgen.Builder.AddColumn("activity_stream", tC{"extra", "varchar", 200, false, false, "''"}, nil))
}
func patch30(scanner *bufio.Scanner) error {
err := execStmt(qgen.Builder.AddColumn("users_groups_promotions", tC{"registeredFor", "int", 0, false, false, "0"}, nil))
if err != nil {
return err
}
return execStmt(qgen.Builder.SetDefaultColumn("users", "last_ip", "varchar", ""))
}
func patch31(scanner *bufio.Scanner) error {
err := execStmt(qgen.Builder.RemoveIndex("topics", "title"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.RemoveIndex("topics", "content"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.RemoveIndex("replies", "content"))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddKey("topics", "title", tK{"title", "fulltext", "", false}))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddKey("topics", "content", tK{"content", "fulltext", "", false}))
if err != nil {
return err
}
err = execStmt(qgen.Builder.AddKey("replies", "content", tK{"content", "fulltext", "", false}))
if err != nil {
return err
}
return nil
}