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  }