github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/cmd/query_gen/main.go (about) 1 /* WIP Under Construction */ 2 package main // import "github.com/Azareal/Gosora/query_gen" 3 4 import ( 5 "encoding/json" 6 "fmt" 7 "log" 8 "os" 9 "runtime/debug" 10 "strconv" 11 "strings" 12 13 c "github.com/Azareal/Gosora/common" 14 qgen "github.com/Azareal/Gosora/query_gen" 15 ) 16 17 // TODO: Make sure all the errors in this file propagate upwards properly 18 func main() { 19 // Capture panics instead of closing the window at a superhuman speed before the user can read the message on Windows 20 defer func() { 21 if r := recover(); r != nil { 22 fmt.Println(r) 23 debug.PrintStack() 24 return 25 } 26 }() 27 28 log.Println("Running the query generator") 29 for _, a := range qgen.Registry { 30 log.Printf("Building the queries for the %s adapter", a.GetName()) 31 qgen.Install.SetAdapterInstance(a) 32 qgen.Install.AddPlugins(NewPrimaryKeySpitter()) // TODO: Do we really need to fill the spitter for every adapter? 33 34 e := writeStatements(a) 35 if e != nil { 36 log.Print(e) 37 } 38 e = qgen.Install.Write() 39 if e != nil { 40 log.Print(e) 41 } 42 e = a.Write() 43 if e != nil { 44 log.Print(e) 45 } 46 } 47 } 48 49 // nolint 50 func writeStatements(a qgen.Adapter) (err error) { 51 e := func(f func(qgen.Adapter) error) { 52 if err != nil { 53 return 54 } 55 err = f(a) 56 } 57 e(createTables) 58 e(seedTables) 59 e(writeSelects) 60 e(writeLeftJoins) 61 e(writeInnerJoins) 62 e(writeInserts) 63 e(writeUpdates) 64 e(writeDeletes) 65 e(writeSimpleCounts) 66 e(writeInsertSelects) 67 e(writeInsertLeftJoins) 68 e(writeInsertInnerJoins) 69 return err 70 } 71 72 type si = map[string]interface{} 73 type tK = tblKey 74 75 func seedTables(a qgen.Adapter) error { 76 qgen.Install.AddIndex("topics", "parentID", "parentID") 77 qgen.Install.AddIndex("replies", "tid", "tid") 78 qgen.Install.AddIndex("polls", "parentID", "parentID") 79 qgen.Install.AddIndex("likes", "targetItem", "targetItem") 80 qgen.Install.AddIndex("emails", "uid", "uid") 81 qgen.Install.AddIndex("attachments", "originID", "originID") 82 qgen.Install.AddIndex("attachments", "path", "path") 83 qgen.Install.AddIndex("activity_stream_matches", "watcher", "watcher") 84 // TODO: Remove these keys to save space when Elasticsearch is active? 85 //qgen.Install.AddKey("topics", "title", tK{"title", "fulltext", "", false}) 86 //qgen.Install.AddKey("topics", "content", tK{"content", "fulltext", "", false}) 87 //qgen.Install.AddKey("topics", "title,content", tK{"title,content", "fulltext", "", false}) 88 //qgen.Install.AddKey("replies", "content", tK{"content", "fulltext", "", false}) 89 90 insert := func(tbl, cols, vals string) { 91 qgen.Install.SimpleInsert(tbl, cols, vals) 92 } 93 insert("sync", "last_update", "UTC_TIMESTAMP()") 94 addSetting := func(name, content, stype string, constraints ...string) { 95 if strings.Contains(name, "'") { 96 panic("name contains '") 97 } 98 if strings.Contains(stype, "'") { 99 panic("stype contains '") 100 } 101 // TODO: Add more field validators 102 cols := "name,content,type" 103 if len(constraints) > 0 { 104 cols += ",constraints" 105 } 106 q := func(s string) string { 107 return "'" + s + "'" 108 } 109 c := func() string { 110 if len(constraints) == 0 { 111 return "" 112 } 113 return "," + q(constraints[0]) 114 } 115 insert("settings", cols, q(name)+","+q(content)+","+q(stype)+c()) 116 } 117 addSetting("activation_type", "1", "list", "1-3") 118 addSetting("bigpost_min_words", "250", "int") 119 addSetting("megapost_min_words", "1000", "int") 120 addSetting("meta_desc", "", "html-attribute") 121 addSetting("rapid_loading", "1", "bool") 122 addSetting("google_site_verify", "", "html-attribute") 123 addSetting("avatar_visibility", "0", "list", "0-1") 124 insert("themes", "uname, default", "'cosora',1") 125 insert("emails", "email, uid, validated", "'admin@localhost',1,1") // ? - Use a different default email or let the admin input it during installation? 126 127 /* 128 The Permissions: 129 130 Global Permissions: 131 BanUsers 132 ActivateUsers 133 EditUser 134 EditUserEmail 135 EditUserPassword 136 EditUserGroup 137 EditUserGroupSuperMod 138 EditUserGroupAdmin 139 EditGroup 140 EditGroupLocalPerms 141 EditGroupGlobalPerms 142 EditGroupSuperMod 143 EditGroupAdmin 144 ManageForums 145 EditSettings 146 ManageThemes 147 ManagePlugins 148 ViewAdminLogs 149 ViewIPs 150 151 Non-staff Global Permissions: 152 UploadFiles 153 UploadAvatars 154 UseConvos 155 UseConvosOnlyWithMod 156 CreateProfileReply 157 AutoEmbed 158 AutoLink 159 // CreateConvo ? 160 // CreateConvoReply ? 161 162 Forum Permissions: 163 ViewTopic 164 LikeItem 165 CreateTopic 166 EditTopic 167 DeleteTopic 168 CreateReply 169 EditReply 170 DeleteReply 171 PinTopic 172 CloseTopic 173 MoveTopic 174 */ 175 176 p := func(perms *c.Perms) string { 177 jBytes, err := json.Marshal(perms) 178 if err != nil { 179 panic(err) 180 } 181 return string(jBytes) 182 } 183 addGroup := func(name string, perms c.Perms, mod, admin, banned bool, tag string) { 184 mi, ai, bi := "0", "0", "0" 185 if mod { 186 mi = "1" 187 } 188 if admin { 189 ai = "1" 190 } 191 if banned { 192 bi = "1" 193 } 194 insert("users_groups", "name, permissions, plugin_perms, is_mod, is_admin, is_banned, tag", `'`+name+`','`+p(&perms)+`','{}',`+mi+`,`+ai+`,`+bi+`,"`+tag+`"`) 195 } 196 197 perms := c.AllPerms 198 perms.EditUserGroupAdmin = false 199 perms.EditGroupAdmin = false 200 addGroup("Administrator", perms, true, true, false, "Admin") 201 202 perms = c.Perms{BanUsers: true, ActivateUsers: true, EditUser: true, EditUserEmail: false, EditUserGroup: true, ViewIPs: true, UploadFiles: true, UploadAvatars: true, UseConvos: true, UseConvosOnlyWithMod: true, CreateProfileReply: true, AutoEmbed: true, AutoLink: true, ViewTopic: true, LikeItem: true, CreateTopic: true, EditTopic: true, DeleteTopic: true, CreateReply: true, EditReply: true, DeleteReply: true, PinTopic: true, CloseTopic: true, MoveTopic: true} 203 addGroup("Moderator", perms, true, false, false, "Mod") 204 205 perms = c.Perms{UploadFiles: true, UploadAvatars: true, UseConvos: true, UseConvosOnlyWithMod: true, CreateProfileReply: true, AutoEmbed: true, AutoLink: true, ViewTopic: true, LikeItem: true, CreateTopic: true, CreateReply: true} 206 addGroup("Member", perms, false, false, false, "") 207 208 perms = c.Perms{ViewTopic: true} 209 addGroup("Banned", perms, false, false, true, "") 210 addGroup("Awaiting Activation", c.Perms{ViewTopic: true, UseConvosOnlyWithMod: true}, false, false, false, "") 211 addGroup("Not Loggedin", perms, false, false, false, "Guest") 212 213 // 214 // TODO: Stop processFields() from stripping the spaces in the descriptions in the next commit 215 216 insert("forums", "name, active, desc, tmpl", "'Reports',0,'All the reports go here',''") 217 insert("forums", "name, lastTopicID, lastReplyerID, desc, tmpl", "'General',1,1,'A place for general discussions which don't fit elsewhere',''") 218 219 // 220 221 /*var addForumPerm = func(gid, fid int, permStr string) { 222 insert("forums_permissions", "gid, fid, permissions", strconv.Itoa(gid)+`,`+strconv.Itoa(fid)+`,'`+permStr+`'`) 223 }*/ 224 225 insert("forums_permissions", "gid, fid, permissions", `1,1,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"PinTopic":true,"CloseTopic":true}'`) 226 insert("forums_permissions", "gid, fid, permissions", `2,1,'{"ViewTopic":true,"CreateReply":true,"CloseTopic":true}'`) 227 insert("forums_permissions", "gid, fid, permissions", "3,1,'{}'") 228 insert("forums_permissions", "gid, fid, permissions", "4,1,'{}'") 229 insert("forums_permissions", "gid, fid, permissions", "5,1,'{}'") 230 insert("forums_permissions", "gid, fid, permissions", "6,1,'{}'") 231 232 // 233 234 insert("forums_permissions", "gid, fid, permissions", `1,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true,"EditTopic":true,"DeleteTopic":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}'`) 235 236 insert("forums_permissions", "gid, fid, permissions", `2,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true,"EditTopic":true,"DeleteTopic":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true,"MoveTopic":true}'`) 237 238 insert("forums_permissions", "gid, fid, permissions", `3,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true}'`) 239 240 insert("forums_permissions", "gid, fid, permissions", `4,2,'{"ViewTopic":true}'`) 241 242 insert("forums_permissions", "gid, fid, permissions", `5,2,'{"ViewTopic":true}'`) 243 244 insert("forums_permissions", "gid, fid, permissions", `6,2,'{"ViewTopic":true}'`) 245 246 // 247 248 insert("topics", "title, content, parsed_content, createdAt, lastReplyAt, lastReplyBy, createdBy, parentID, ip", "'Test Topic','A topic automatically generated by the software.','A topic automatically generated by the software.',UTC_TIMESTAMP(),UTC_TIMESTAMP(),1,1,2,''") 249 250 insert("replies", "tid, content, parsed_content, createdAt, createdBy, lastUpdated, lastEdit, lastEditBy, ip", "1,'A reply!','A reply!',UTC_TIMESTAMP(),1,UTC_TIMESTAMP(),0,0,''") 251 252 insert("menus", "", "") 253 254 // Go maps have a random iteration order, so we have to do this, otherwise the schema files will become unstable and harder to audit 255 order := 0 256 mOrder := "mid, name, htmlID, cssClass, position, path, aria, tooltip, guestOnly, memberOnly, staffOnly, adminOnly" 257 addMenuItem := func(data map[string]interface{}) { 258 if data["mid"] == nil { 259 data["mid"] = 1 260 } 261 if data["position"] == nil { 262 data["position"] = "left" 263 } 264 cols, values := qgen.InterfaceMapToInsertStrings(data, mOrder) 265 insert("menu_items", cols+", order", values+","+strconv.Itoa(order)) 266 order++ 267 } 268 269 addMenuItem(si{"name": "{lang.menu_forums}", "htmlID": "menu_forums", "path": "/forums/", "aria": "{lang.menu_forums_aria}", "tooltip": "{lang.menu_forums_tooltip}"}) 270 271 addMenuItem(si{"name": "{lang.menu_topics}", "htmlID": "menu_topics", "cssClass": "menu_topics", "path": "/topics/", "aria": "{lang.menu_topics_aria}", "tooltip": "{lang.menu_topics_tooltip}"}) 272 273 addMenuItem(si{"htmlID": "general_alerts", "cssClass": "menu_alerts", "position": "right", "tmplName": "menu_alerts"}) 274 275 addMenuItem(si{"name": "{lang.menu_account}", "cssClass": "menu_account", "path": "/user/edit/", "aria": "{lang.menu_account_aria}", "tooltip": "{lang.menu_account_tooltip}", "memberOnly": true}) 276 277 addMenuItem(si{"name": "{lang.menu_profile}", "cssClass": "menu_profile", "path": "{me.Link}", "aria": "{lang.menu_profile_aria}", "tooltip": "{lang.menu_profile_tooltip}", "memberOnly": true}) 278 279 addMenuItem(si{"name": "{lang.menu_panel}", "cssClass": "menu_panel menu_account", "path": "/panel/", "aria": "{lang.menu_panel_aria}", "tooltip": "{lang.menu_panel_tooltip}", "memberOnly": true, "staffOnly": true}) 280 281 addMenuItem(si{"name": "{lang.menu_logout}", "cssClass": "menu_logout", "path": "/accounts/logout/?s={me.Session}", "aria": "{lang.menu_logout_aria}", "tooltip": "{lang.menu_logout_tooltip}", "memberOnly": true}) 282 283 addMenuItem(si{"name": "{lang.menu_register}", "cssClass": "menu_register", "path": "/accounts/create/", "aria": "{lang.menu_register_aria}", "tooltip": "{lang.menu_register_tooltip}", "guestOnly": true}) 284 285 addMenuItem(si{"name": "{lang.menu_login}", "cssClass": "menu_login", "path": "/accounts/login/", "aria": "{lang.menu_login_aria}", "tooltip": "{lang.menu_login_tooltip}", "guestOnly": true}) 286 287 /*var fSet []string 288 for _, table := range tables { 289 fSet = append(fSet, "'"+table+"'") 290 } 291 qgen.Install.SimpleBulkInsert("tables", "name", fSet)*/ 292 293 return nil 294 } 295 296 // ? - What is this for? 297 /*func copyInsertMap(in map[string]interface{}) (out map[string]interface{}) { 298 out = make(map[string]interface{}) 299 for col, value := range in { 300 out[col] = value 301 } 302 return out 303 }*/ 304 305 type LitStr string 306 307 func writeSelects(a qgen.Adapter) error { 308 b := a.Builder() 309 310 // Looking for getTopic? Your statement is in another castle 311 312 //b.Select("isPluginInstalled").Table("plugins").Columns("installed").Where("uname = ?").Parse() 313 314 b.Select("forumEntryExists").Table("forums").Columns("fid").Where("name = ''").Orderby("fid ASC").Limit("0,1").Parse() 315 316 b.Select("groupEntryExists").Table("users_groups").Columns("gid").Where("name = ''").Orderby("gid ASC").Limit("0,1").Parse() 317 318 return nil 319 } 320 321 func writeLeftJoins(a qgen.Adapter) error { 322 a.SimpleLeftJoin("getForumTopics", "topics", "users", "topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, users.name, users.avatar", "topics.createdBy = users.uid", "topics.parentID = ?", "topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy desc", "") 323 324 return nil 325 } 326 327 func writeInnerJoins(a qgen.Adapter) (err error) { 328 return nil 329 } 330 331 func writeInserts(a qgen.Adapter) error { 332 b := a.Builder() 333 334 b.Insert("addForumPermsToForum").Table("forums_permissions").Columns("gid,fid,preset,permissions").Fields("?,?,?,?").Parse() 335 336 return nil 337 } 338 339 func writeUpdates(a qgen.Adapter) error { 340 b := a.Builder() 341 342 b.Update("updateEmail").Table("emails").Set("email = ?, uid = ?, validated = ?, token = ?").Where("email = ?").Parse() 343 344 b.Update("setTempGroup").Table("users").Set("temp_group = ?").Where("uid = ?").Parse() 345 346 b.Update("bumpSync").Table("sync").Set("last_update = UTC_TIMESTAMP()").Parse() 347 348 return nil 349 } 350 351 func writeDeletes(a qgen.Adapter) error { 352 b := a.Builder() 353 354 //b.Delete("deleteForumPermsByForum").Table("forums_permissions").Where("fid=?").Parse() 355 356 b.Delete("deleteActivityStreamMatch").Table("activity_stream_matches").Where("watcher=? AND asid=?").Parse() 357 //b.Delete("deleteActivityStreamMatchesByWatcher").Table("activity_stream_matches").Where("watcher=?").Parse() 358 359 return nil 360 } 361 362 func writeSimpleCounts(a qgen.Adapter) error { 363 return nil 364 } 365 366 func writeInsertSelects(a qgen.Adapter) error { 367 /*a.SimpleInsertSelect("addForumPermsToForumAdmins", 368 qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""}, 369 qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 1", "", ""}, 370 )*/ 371 372 /*a.SimpleInsertSelect("addForumPermsToForumStaff", 373 qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""}, 374 qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 1", "", ""}, 375 )*/ 376 377 /*a.SimpleInsertSelect("addForumPermsToForumMembers", 378 qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""}, 379 qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 0 AND is_banned = 0", "", ""}, 380 )*/ 381 382 return nil 383 } 384 385 // nolint 386 func writeInsertLeftJoins(a qgen.Adapter) error { 387 return nil 388 } 389 390 func writeInsertInnerJoins(a qgen.Adapter) error { 391 return nil 392 } 393 394 func writeFile(name, content string) (err error) { 395 f, err := os.Create(name) 396 if err != nil { 397 return err 398 } 399 _, err = f.WriteString(content) 400 if err != nil { 401 return err 402 } 403 err = f.Sync() 404 if err != nil { 405 return err 406 } 407 return f.Close() 408 }