Gosora now supports MSSQL (Microsoft SQL Server).

Fixed a bug with MemoryUserStore's length counter.
The upsert API is currently a confusing mess, we'll have it all fixed up soon.
Added the Delete method to the User struct.
Improved the test coverage for the user subsystem.
This commit is contained in:
Azareal 2017-10-16 08:32:58 +01:00
parent fdb6304e32
commit da6ae8d7d4
51 changed files with 2357 additions and 770 deletions

View File

@ -113,6 +113,7 @@ var verifyEmailStmt *sql.Stmt
var setTempGroupStmt *sql.Stmt var setTempGroupStmt *sql.Stmt
var updateWordFilterStmt *sql.Stmt var updateWordFilterStmt *sql.Stmt
var bumpSyncStmt *sql.Stmt var bumpSyncStmt *sql.Stmt
var deleteUserStmt *sql.Stmt
var deleteReplyStmt *sql.Stmt var deleteReplyStmt *sql.Stmt
var deleteProfileReplyStmt *sql.Stmt var deleteProfileReplyStmt *sql.Stmt
var deleteForumPermsByForumStmt *sql.Stmt var deleteForumPermsByForumStmt *sql.Stmt
@ -245,9 +246,9 @@ func _gen_mssql() (err error) {
} }
log.Print("Preparing getUsersOffset statement.") log.Print("Preparing getUsersOffset statement.")
getUsersOffsetStmt, err = db.Prepare("SELECT [uid],[name],[group],[active],[is_super_admin],[avatar] FROM [users] OFFSET ?1 ROWS FETCH NEXT ?2 ROWS ONLY") getUsersOffsetStmt, err = db.Prepare("SELECT [uid],[name],[group],[active],[is_super_admin],[avatar] FROM [users] ORDER BY uid ASC OFFSET ?1 ROWS FETCH NEXT ?2 ROWS ONLY")
if err != nil { if err != nil {
log.Print("Bad Query: ","SELECT [uid],[name],[group],[active],[is_super_admin],[avatar] FROM [users] OFFSET ?1 ROWS FETCH NEXT ?2 ROWS ONLY") log.Print("Bad Query: ","SELECT [uid],[name],[group],[active],[is_super_admin],[avatar] FROM [users] ORDER BY uid ASC OFFSET ?1 ROWS FETCH NEXT ?2 ROWS ONLY")
return err return err
} }
@ -273,9 +274,9 @@ func _gen_mssql() (err error) {
} }
log.Print("Preparing getModlogsOffset statement.") log.Print("Preparing getModlogsOffset statement.")
getModlogsOffsetStmt, err = db.Prepare("SELECT [action],[elementID],[elementType],[ipaddress],[actorID],[doneAt] FROM [moderation_logs] OFFSET ?1 ROWS FETCH NEXT ?2 ROWS ONLY") getModlogsOffsetStmt, err = db.Prepare("SELECT [action],[elementID],[elementType],[ipaddress],[actorID],[doneAt] FROM [moderation_logs] ORDER BY doneAt DESC OFFSET ?1 ROWS FETCH NEXT ?2 ROWS ONLY")
if err != nil { if err != nil {
log.Print("Bad Query: ","SELECT [action],[elementID],[elementType],[ipaddress],[actorID],[doneAt] FROM [moderation_logs] OFFSET ?1 ROWS FETCH NEXT ?2 ROWS ONLY") log.Print("Bad Query: ","SELECT [action],[elementID],[elementType],[ipaddress],[actorID],[doneAt] FROM [moderation_logs] ORDER BY doneAt DESC OFFSET ?1 ROWS FETCH NEXT ?2 ROWS ONLY")
return err return err
} }
@ -385,9 +386,9 @@ func _gen_mssql() (err error) {
} }
log.Print("Preparing getTopicRepliesOffset statement.") log.Print("Preparing getTopicRepliesOffset statement.")
getTopicRepliesOffsetStmt, err = db.Prepare("SELECT [replies].[rid],[replies].[content],[replies].[createdBy],[replies].[createdAt],[replies].[lastEdit],[replies].[lastEditBy],[users].[avatar],[users].[name],[users].[group],[users].[url_prefix],[users].[url_name],[users].[level],[replies].[ipaddress],[replies].[likeCount],[replies].[actionType] FROM [replies] LEFT JOIN [users] ON [replies].[createdBy] = [users].[uid] WHERE [replies].[tid] = ?1 OFFSET ?2 ROWS FETCH NEXT ?3 ROWS ONLY") getTopicRepliesOffsetStmt, err = db.Prepare("SELECT [replies].[rid],[replies].[content],[replies].[createdBy],[replies].[createdAt],[replies].[lastEdit],[replies].[lastEditBy],[users].[avatar],[users].[name],[users].[group],[users].[url_prefix],[users].[url_name],[users].[level],[replies].[ipaddress],[replies].[likeCount],[replies].[actionType] FROM [replies] LEFT JOIN [users] ON [replies].[createdBy] = [users].[uid] WHERE [replies].[tid] = ?1 ORDER BY replies.rid ASC OFFSET ?2 ROWS FETCH NEXT ?3 ROWS ONLY")
if err != nil { if err != nil {
log.Print("Bad Query: ","SELECT [replies].[rid],[replies].[content],[replies].[createdBy],[replies].[createdAt],[replies].[lastEdit],[replies].[lastEditBy],[users].[avatar],[users].[name],[users].[group],[users].[url_prefix],[users].[url_name],[users].[level],[replies].[ipaddress],[replies].[likeCount],[replies].[actionType] FROM [replies] LEFT JOIN [users] ON [replies].[createdBy] = [users].[uid] WHERE [replies].[tid] = ?1 OFFSET ?2 ROWS FETCH NEXT ?3 ROWS ONLY") log.Print("Bad Query: ","SELECT [replies].[rid],[replies].[content],[replies].[createdBy],[replies].[createdAt],[replies].[lastEdit],[replies].[lastEditBy],[users].[avatar],[users].[name],[users].[group],[users].[url_prefix],[users].[url_name],[users].[level],[replies].[ipaddress],[replies].[likeCount],[replies].[actionType] FROM [replies] LEFT JOIN [users] ON [replies].[createdBy] = [users].[uid] WHERE [replies].[tid] = ?1 ORDER BY replies.rid ASC OFFSET ?2 ROWS FETCH NEXT ?3 ROWS ONLY")
return err return err
} }
@ -434,9 +435,9 @@ func _gen_mssql() (err error) {
} }
log.Print("Preparing getWatchers statement.") log.Print("Preparing getWatchers statement.")
getWatchersStmt, err = db.Prepare("") getWatchersStmt, err = db.Prepare("SELECT [activity_subscriptions].[user] FROM [activity_stream] INNER JOIN [activity_subscriptions] ON [activity_subscriptions].[targetType] = [activity_stream].[elementType] AND [activity_subscriptions].[targetID] = [activity_stream].[elementID] AND [activity_subscriptions].[user] != [activity_stream].[actor] WHERE [asid] = ?1")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","SELECT [activity_subscriptions].[user] FROM [activity_stream] INNER JOIN [activity_subscriptions] ON [activity_subscriptions].[targetType] = [activity_stream].[elementType] AND [activity_subscriptions].[targetID] = [activity_stream].[elementID] AND [activity_subscriptions].[user] != [activity_stream].[actor] WHERE [asid] = ?1")
return err return err
} }
@ -448,23 +449,23 @@ func _gen_mssql() (err error) {
} }
log.Print("Preparing createReport statement.") log.Print("Preparing createReport statement.")
createReportStmt, err = db.Prepare("INSERT INTO [topics] ([title],[content],[parsed_content],[createdAt],[lastReplyAt],[createdBy],[data],[parentID],[css_class]) VALUES (?,?,?,GETUTCDATE(),GETUTCDATE(),?,?,1,'report')") createReportStmt, err = db.Prepare("INSERT INTO [topics] ([title],[content],[parsed_content],[createdAt],[lastReplyAt],[createdBy],[lastReplyBy],[data],[parentID],[css_class]) VALUES (?,?,?,GETUTCDATE(),GETUTCDATE(),?,?,?,1,'report')")
if err != nil { if err != nil {
log.Print("Bad Query: ","INSERT INTO [topics] ([title],[content],[parsed_content],[createdAt],[lastReplyAt],[createdBy],[data],[parentID],[css_class]) VALUES (?,?,?,GETUTCDATE(),GETUTCDATE(),?,?,1,'report')") log.Print("Bad Query: ","INSERT INTO [topics] ([title],[content],[parsed_content],[createdAt],[lastReplyAt],[createdBy],[lastReplyBy],[data],[parentID],[css_class]) VALUES (?,?,?,GETUTCDATE(),GETUTCDATE(),?,?,?,1,'report')")
return err return err
} }
log.Print("Preparing createReply statement.") log.Print("Preparing createReply statement.")
createReplyStmt, err = db.Prepare("INSERT INTO [replies] ([tid],[content],[parsed_content],[createdAt],[ipaddress],[words],[createdBy]) VALUES (?,?,?,GETUTCDATE(),?,?,?)") createReplyStmt, err = db.Prepare("INSERT INTO [replies] ([tid],[content],[parsed_content],[createdAt],[lastUpdated],[ipaddress],[words],[createdBy]) VALUES (?,?,?,GETUTCDATE(),GETUTCDATE(),?,?,?)")
if err != nil { if err != nil {
log.Print("Bad Query: ","INSERT INTO [replies] ([tid],[content],[parsed_content],[createdAt],[ipaddress],[words],[createdBy]) VALUES (?,?,?,GETUTCDATE(),?,?,?)") log.Print("Bad Query: ","INSERT INTO [replies] ([tid],[content],[parsed_content],[createdAt],[lastUpdated],[ipaddress],[words],[createdBy]) VALUES (?,?,?,GETUTCDATE(),GETUTCDATE(),?,?,?)")
return err return err
} }
log.Print("Preparing createActionReply statement.") log.Print("Preparing createActionReply statement.")
createActionReplyStmt, err = db.Prepare("INSERT INTO [replies] ([tid],[actionType],[ipaddress],[createdBy]) VALUES (?,?,?,?)") createActionReplyStmt, err = db.Prepare("INSERT INTO [replies] ([tid],[actionType],[ipaddress],[createdBy],[createdAt],[lastUpdated],[content],[parsed_content]) VALUES (?,?,?,?,GETUTCDATE(),GETUTCDATE(),'','')")
if err != nil { if err != nil {
log.Print("Bad Query: ","INSERT INTO [replies] ([tid],[actionType],[ipaddress],[createdBy]) VALUES (?,?,?,?)") log.Print("Bad Query: ","INSERT INTO [replies] ([tid],[actionType],[ipaddress],[createdBy],[createdAt],[lastUpdated],[content],[parsed_content]) VALUES (?,?,?,?,GETUTCDATE(),GETUTCDATE(),'','')")
return err return err
} }
@ -574,338 +575,345 @@ func _gen_mssql() (err error) {
} }
log.Print("Preparing addForumPermsToGroup statement.") log.Print("Preparing addForumPermsToGroup statement.")
addForumPermsToGroupStmt, err = db.Prepare("") addForumPermsToGroupStmt, err = db.Prepare("MERGE [forums_permissions] WITH(HOLDLOCK) as t1 USING (VALUES(?,?,?,?)) AS updates (f0,f1,f2,f3) ON [gid] = ? [fid] = ? WHEN MATCHED THEN UPDATE SET [gid] = f0,[fid] = f1,[preset] = f2,[permissions] = f3 WHEN NOT MATCHED THEN INSERT([gid],[fid],[preset],[permissions]) VALUES (f0,f1,f2,f3);")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","MERGE [forums_permissions] WITH(HOLDLOCK) as t1 USING (VALUES(?,?,?,?)) AS updates (f0,f1,f2,f3) ON [gid] = ? [fid] = ? WHEN MATCHED THEN UPDATE SET [gid] = f0,[fid] = f1,[preset] = f2,[permissions] = f3 WHEN NOT MATCHED THEN INSERT([gid],[fid],[preset],[permissions]) VALUES (f0,f1,f2,f3);")
return err return err
} }
log.Print("Preparing replaceScheduleGroup statement.") log.Print("Preparing replaceScheduleGroup statement.")
replaceScheduleGroupStmt, err = db.Prepare("") replaceScheduleGroupStmt, err = db.Prepare("MERGE [users_groups_scheduler] WITH(HOLDLOCK) as t1 USING (VALUES(?,?,?,GETUTCDATE(),?,?)) AS updates (f0,f1,f2,f3,f4,f5) ON [uid] = ? WHEN MATCHED THEN UPDATE SET [uid] = f0,[set_group] = f1,[issued_by] = f2,[issued_at] = f3,[revert_at] = f4,[temporary] = f5 WHEN NOT MATCHED THEN INSERT([uid],[set_group],[issued_by],[issued_at],[revert_at],[temporary]) VALUES (f0,f1,f2,f3,f4,f5);")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","MERGE [users_groups_scheduler] WITH(HOLDLOCK) as t1 USING (VALUES(?,?,?,GETUTCDATE(),?,?)) AS updates (f0,f1,f2,f3,f4,f5) ON [uid] = ? WHEN MATCHED THEN UPDATE SET [uid] = f0,[set_group] = f1,[issued_by] = f2,[issued_at] = f3,[revert_at] = f4,[temporary] = f5 WHEN NOT MATCHED THEN INSERT([uid],[set_group],[issued_by],[issued_at],[revert_at],[temporary]) VALUES (f0,f1,f2,f3,f4,f5);")
return err return err
} }
log.Print("Preparing addRepliesToTopic statement.") log.Print("Preparing addRepliesToTopic statement.")
addRepliesToTopicStmt, err = db.Prepare("") addRepliesToTopicStmt, err = db.Prepare("UPDATE [topics] SET [postCount] = [postCount] + ?,[lastReplyBy] = ?,[lastReplyAt] = GETUTCDATE() WHERE [tid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [topics] SET [postCount] = [postCount] + ?,[lastReplyBy] = ?,[lastReplyAt] = GETUTCDATE() WHERE [tid] = ?")
return err return err
} }
log.Print("Preparing removeRepliesFromTopic statement.") log.Print("Preparing removeRepliesFromTopic statement.")
removeRepliesFromTopicStmt, err = db.Prepare("") removeRepliesFromTopicStmt, err = db.Prepare("UPDATE [topics] SET [postCount] = [postCount] - ? WHERE [tid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [topics] SET [postCount] = [postCount] - ? WHERE [tid] = ?")
return err return err
} }
log.Print("Preparing addTopicsToForum statement.") log.Print("Preparing addTopicsToForum statement.")
addTopicsToForumStmt, err = db.Prepare("") addTopicsToForumStmt, err = db.Prepare("UPDATE [forums] SET [topicCount] = [topicCount] + ? WHERE [fid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [forums] SET [topicCount] = [topicCount] + ? WHERE [fid] = ?")
return err return err
} }
log.Print("Preparing removeTopicsFromForum statement.") log.Print("Preparing removeTopicsFromForum statement.")
removeTopicsFromForumStmt, err = db.Prepare("") removeTopicsFromForumStmt, err = db.Prepare("UPDATE [forums] SET [topicCount] = [topicCount] - ? WHERE [fid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [forums] SET [topicCount] = [topicCount] - ? WHERE [fid] = ?")
return err return err
} }
log.Print("Preparing updateForumCache statement.") log.Print("Preparing updateForumCache statement.")
updateForumCacheStmt, err = db.Prepare("") updateForumCacheStmt, err = db.Prepare("UPDATE [forums] SET [lastTopicID] = ?,[lastReplyerID] = ? WHERE [fid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [forums] SET [lastTopicID] = ?,[lastReplyerID] = ? WHERE [fid] = ?")
return err return err
} }
log.Print("Preparing addLikesToTopic statement.") log.Print("Preparing addLikesToTopic statement.")
addLikesToTopicStmt, err = db.Prepare("") addLikesToTopicStmt, err = db.Prepare("UPDATE [topics] SET [likeCount] = [likeCount] + ? WHERE [tid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [topics] SET [likeCount] = [likeCount] + ? WHERE [tid] = ?")
return err return err
} }
log.Print("Preparing addLikesToReply statement.") log.Print("Preparing addLikesToReply statement.")
addLikesToReplyStmt, err = db.Prepare("") addLikesToReplyStmt, err = db.Prepare("UPDATE [replies] SET [likeCount] = [likeCount] + ? WHERE [rid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [replies] SET [likeCount] = [likeCount] + ? WHERE [rid] = ?")
return err return err
} }
log.Print("Preparing editTopic statement.") log.Print("Preparing editTopic statement.")
editTopicStmt, err = db.Prepare("") editTopicStmt, err = db.Prepare("UPDATE [topics] SET [title] = ?,[content] = ?,[parsed_content] = ? WHERE [tid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [topics] SET [title] = ?,[content] = ?,[parsed_content] = ? WHERE [tid] = ?")
return err return err
} }
log.Print("Preparing editReply statement.") log.Print("Preparing editReply statement.")
editReplyStmt, err = db.Prepare("") editReplyStmt, err = db.Prepare("UPDATE [replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?")
return err return err
} }
log.Print("Preparing stickTopic statement.") log.Print("Preparing stickTopic statement.")
stickTopicStmt, err = db.Prepare("") stickTopicStmt, err = db.Prepare("UPDATE [topics] SET [sticky] = 1 WHERE [tid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [topics] SET [sticky] = 1 WHERE [tid] = ?")
return err return err
} }
log.Print("Preparing unstickTopic statement.") log.Print("Preparing unstickTopic statement.")
unstickTopicStmt, err = db.Prepare("") unstickTopicStmt, err = db.Prepare("UPDATE [topics] SET [sticky] = 0 WHERE [tid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [topics] SET [sticky] = 0 WHERE [tid] = ?")
return err return err
} }
log.Print("Preparing lockTopic statement.") log.Print("Preparing lockTopic statement.")
lockTopicStmt, err = db.Prepare("") lockTopicStmt, err = db.Prepare("UPDATE [topics] SET [is_closed] = 1 WHERE [tid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [topics] SET [is_closed] = 1 WHERE [tid] = ?")
return err return err
} }
log.Print("Preparing unlockTopic statement.") log.Print("Preparing unlockTopic statement.")
unlockTopicStmt, err = db.Prepare("") unlockTopicStmt, err = db.Prepare("UPDATE [topics] SET [is_closed] = 0 WHERE [tid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [topics] SET [is_closed] = 0 WHERE [tid] = ?")
return err return err
} }
log.Print("Preparing updateLastIP statement.") log.Print("Preparing updateLastIP statement.")
updateLastIPStmt, err = db.Prepare("") updateLastIPStmt, err = db.Prepare("UPDATE [users] SET [last_ip] = ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [last_ip] = ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing updateSession statement.") log.Print("Preparing updateSession statement.")
updateSessionStmt, err = db.Prepare("") updateSessionStmt, err = db.Prepare("UPDATE [users] SET [session] = ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [session] = ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing setPassword statement.") log.Print("Preparing setPassword statement.")
setPasswordStmt, err = db.Prepare("") setPasswordStmt, err = db.Prepare("UPDATE [users] SET [password] = ?,[salt] = ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [password] = ?,[salt] = ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing setAvatar statement.") log.Print("Preparing setAvatar statement.")
setAvatarStmt, err = db.Prepare("") setAvatarStmt, err = db.Prepare("UPDATE [users] SET [avatar] = ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [avatar] = ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing setUsername statement.") log.Print("Preparing setUsername statement.")
setUsernameStmt, err = db.Prepare("") setUsernameStmt, err = db.Prepare("UPDATE [users] SET [name] = ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [name] = ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing changeGroup statement.") log.Print("Preparing changeGroup statement.")
changeGroupStmt, err = db.Prepare("") changeGroupStmt, err = db.Prepare("UPDATE [users] SET [group] = ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [group] = ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing activateUser statement.") log.Print("Preparing activateUser statement.")
activateUserStmt, err = db.Prepare("") activateUserStmt, err = db.Prepare("UPDATE [users] SET [active] = 1 WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [active] = 1 WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing updateUserLevel statement.") log.Print("Preparing updateUserLevel statement.")
updateUserLevelStmt, err = db.Prepare("") updateUserLevelStmt, err = db.Prepare("UPDATE [users] SET [level] = ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [level] = ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing incrementUserScore statement.") log.Print("Preparing incrementUserScore statement.")
incrementUserScoreStmt, err = db.Prepare("") incrementUserScoreStmt, err = db.Prepare("UPDATE [users] SET [score] = [score] + ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [score] = [score] + ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing incrementUserPosts statement.") log.Print("Preparing incrementUserPosts statement.")
incrementUserPostsStmt, err = db.Prepare("") incrementUserPostsStmt, err = db.Prepare("UPDATE [users] SET [posts] = [posts] + ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [posts] = [posts] + ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing incrementUserBigposts statement.") log.Print("Preparing incrementUserBigposts statement.")
incrementUserBigpostsStmt, err = db.Prepare("") incrementUserBigpostsStmt, err = db.Prepare("UPDATE [users] SET [posts] = [posts] + ?,[bigposts] = [bigposts] + ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [posts] = [posts] + ?,[bigposts] = [bigposts] + ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing incrementUserMegaposts statement.") log.Print("Preparing incrementUserMegaposts statement.")
incrementUserMegapostsStmt, err = db.Prepare("") incrementUserMegapostsStmt, err = db.Prepare("UPDATE [users] SET [posts] = [posts] + ?,[bigposts] = [bigposts] + ?,[megaposts] = [megaposts] + ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [posts] = [posts] + ?,[bigposts] = [bigposts] + ?,[megaposts] = [megaposts] + ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing incrementUserTopics statement.") log.Print("Preparing incrementUserTopics statement.")
incrementUserTopicsStmt, err = db.Prepare("") incrementUserTopicsStmt, err = db.Prepare("UPDATE [users] SET [topics] = [topics] + ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [topics] = [topics] + ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing editProfileReply statement.") log.Print("Preparing editProfileReply statement.")
editProfileReplyStmt, err = db.Prepare("") editProfileReplyStmt, err = db.Prepare("UPDATE [users_replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users_replies] SET [content] = ?,[parsed_content] = ? WHERE [rid] = ?")
return err return err
} }
log.Print("Preparing updateForum statement.") log.Print("Preparing updateForum statement.")
updateForumStmt, err = db.Prepare("") updateForumStmt, err = db.Prepare("UPDATE [forums] SET [name] = ?,[desc] = ?,[active] = ?,[preset] = ? WHERE [fid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [forums] SET [name] = ?,[desc] = ?,[active] = ?,[preset] = ? WHERE [fid] = ?")
return err return err
} }
log.Print("Preparing updateSetting statement.") log.Print("Preparing updateSetting statement.")
updateSettingStmt, err = db.Prepare("") updateSettingStmt, err = db.Prepare("UPDATE [settings] SET [content] = ? WHERE [name] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [settings] SET [content] = ? WHERE [name] = ?")
return err return err
} }
log.Print("Preparing updatePlugin statement.") log.Print("Preparing updatePlugin statement.")
updatePluginStmt, err = db.Prepare("") updatePluginStmt, err = db.Prepare("UPDATE [plugins] SET [active] = ? WHERE [uname] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [plugins] SET [active] = ? WHERE [uname] = ?")
return err return err
} }
log.Print("Preparing updatePluginInstall statement.") log.Print("Preparing updatePluginInstall statement.")
updatePluginInstallStmt, err = db.Prepare("") updatePluginInstallStmt, err = db.Prepare("UPDATE [plugins] SET [installed] = ? WHERE [uname] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [plugins] SET [installed] = ? WHERE [uname] = ?")
return err return err
} }
log.Print("Preparing updateTheme statement.") log.Print("Preparing updateTheme statement.")
updateThemeStmt, err = db.Prepare("") updateThemeStmt, err = db.Prepare("UPDATE [themes] SET [default] = ? WHERE [uname] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [themes] SET [default] = ? WHERE [uname] = ?")
return err return err
} }
log.Print("Preparing updateUser statement.") log.Print("Preparing updateUser statement.")
updateUserStmt, err = db.Prepare("") updateUserStmt, err = db.Prepare("UPDATE [users] SET [name] = ?,[email] = ?,[group] = ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [name] = ?,[email] = ?,[group] = ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing updateGroupPerms statement.") log.Print("Preparing updateGroupPerms statement.")
updateGroupPermsStmt, err = db.Prepare("") updateGroupPermsStmt, err = db.Prepare("UPDATE [users_groups] SET [permissions] = ? WHERE [gid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users_groups] SET [permissions] = ? WHERE [gid] = ?")
return err return err
} }
log.Print("Preparing updateGroupRank statement.") log.Print("Preparing updateGroupRank statement.")
updateGroupRankStmt, err = db.Prepare("") updateGroupRankStmt, err = db.Prepare("UPDATE [users_groups] SET [is_admin] = ?,[is_mod] = ?,[is_banned] = ? WHERE [gid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users_groups] SET [is_admin] = ?,[is_mod] = ?,[is_banned] = ? WHERE [gid] = ?")
return err return err
} }
log.Print("Preparing updateGroup statement.") log.Print("Preparing updateGroup statement.")
updateGroupStmt, err = db.Prepare("") updateGroupStmt, err = db.Prepare("UPDATE [users_groups] SET [name] = ?,[tag] = ? WHERE [gid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users_groups] SET [name] = ?,[tag] = ? WHERE [gid] = ?")
return err return err
} }
log.Print("Preparing updateEmail statement.") log.Print("Preparing updateEmail statement.")
updateEmailStmt, err = db.Prepare("") updateEmailStmt, err = db.Prepare("UPDATE [emails] SET [email] = ?,[uid] = ?,[validated] = ?,[token] = ? WHERE [email] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [emails] SET [email] = ?,[uid] = ?,[validated] = ?,[token] = ? WHERE [email] = ?")
return err return err
} }
log.Print("Preparing verifyEmail statement.") log.Print("Preparing verifyEmail statement.")
verifyEmailStmt, err = db.Prepare("") verifyEmailStmt, err = db.Prepare("UPDATE [emails] SET [validated] = 1,[token] = '' WHERE [email] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [emails] SET [validated] = 1,[token] = '' WHERE [email] = ?")
return err return err
} }
log.Print("Preparing setTempGroup statement.") log.Print("Preparing setTempGroup statement.")
setTempGroupStmt, err = db.Prepare("") setTempGroupStmt, err = db.Prepare("UPDATE [users] SET [temp_group] = ? WHERE [uid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [users] SET [temp_group] = ? WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing updateWordFilter statement.") log.Print("Preparing updateWordFilter statement.")
updateWordFilterStmt, err = db.Prepare("") updateWordFilterStmt, err = db.Prepare("UPDATE [word_filters] SET [find] = ?,[replacement] = ? WHERE [wfid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [word_filters] SET [find] = ?,[replacement] = ? WHERE [wfid] = ?")
return err return err
} }
log.Print("Preparing bumpSync statement.") log.Print("Preparing bumpSync statement.")
bumpSyncStmt, err = db.Prepare("") bumpSyncStmt, err = db.Prepare("UPDATE [sync] SET [last_update] = GETUTCDATE()")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","UPDATE [sync] SET [last_update] = GETUTCDATE()")
return err
}
log.Print("Preparing deleteUser statement.")
deleteUserStmt, err = db.Prepare("DELETE FROM [users] WHERE [uid] = ?")
if err != nil {
log.Print("Bad Query: ","DELETE FROM [users] WHERE [uid] = ?")
return err return err
} }
log.Print("Preparing deleteReply statement.") log.Print("Preparing deleteReply statement.")
deleteReplyStmt, err = db.Prepare("") deleteReplyStmt, err = db.Prepare("DELETE FROM [replies] WHERE [rid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","DELETE FROM [replies] WHERE [rid] = ?")
return err return err
} }
log.Print("Preparing deleteProfileReply statement.") log.Print("Preparing deleteProfileReply statement.")
deleteProfileReplyStmt, err = db.Prepare("") deleteProfileReplyStmt, err = db.Prepare("DELETE FROM [users_replies] WHERE [rid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","DELETE FROM [users_replies] WHERE [rid] = ?")
return err return err
} }
log.Print("Preparing deleteForumPermsByForum statement.") log.Print("Preparing deleteForumPermsByForum statement.")
deleteForumPermsByForumStmt, err = db.Prepare("") deleteForumPermsByForumStmt, err = db.Prepare("DELETE FROM [forums_permissions] WHERE [fid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","DELETE FROM [forums_permissions] WHERE [fid] = ?")
return err return err
} }
log.Print("Preparing deleteActivityStreamMatch statement.") log.Print("Preparing deleteActivityStreamMatch statement.")
deleteActivityStreamMatchStmt, err = db.Prepare("") deleteActivityStreamMatchStmt, err = db.Prepare("DELETE FROM [activity_stream_matches] WHERE [watcher] = ? AND [asid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","DELETE FROM [activity_stream_matches] WHERE [watcher] = ? AND [asid] = ?")
return err return err
} }
log.Print("Preparing deleteWordFilter statement.") log.Print("Preparing deleteWordFilter statement.")
deleteWordFilterStmt, err = db.Prepare("") deleteWordFilterStmt, err = db.Prepare("DELETE FROM [word_filters] WHERE [wfid] = ?")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","DELETE FROM [word_filters] WHERE [wfid] = ?")
return err return err
} }
@ -931,30 +939,30 @@ func _gen_mssql() (err error) {
} }
log.Print("Preparing addForumPermsToForumAdmins statement.") log.Print("Preparing addForumPermsToForumAdmins statement.")
addForumPermsToForumAdminsStmt, err = db.Prepare("") addForumPermsToForumAdminsStmt, err = db.Prepare("INSERT INTO [forums_permissions] ([gid],[fid],[preset],[permissions]) SELECT [gid],[? AS fid],[? AS preset],[? AS permissions] FROM [users_groups] WHERE [is_admin] = 1")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","INSERT INTO [forums_permissions] ([gid],[fid],[preset],[permissions]) SELECT [gid],[? AS fid],[? AS preset],[? AS permissions] FROM [users_groups] WHERE [is_admin] = 1")
return err return err
} }
log.Print("Preparing addForumPermsToForumStaff statement.") log.Print("Preparing addForumPermsToForumStaff statement.")
addForumPermsToForumStaffStmt, err = db.Prepare("") addForumPermsToForumStaffStmt, err = db.Prepare("INSERT INTO [forums_permissions] ([gid],[fid],[preset],[permissions]) SELECT [gid],[? AS fid],[? AS preset],[? AS permissions] FROM [users_groups] WHERE [is_admin] = 0 AND [is_mod] = 1")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","INSERT INTO [forums_permissions] ([gid],[fid],[preset],[permissions]) SELECT [gid],[? AS fid],[? AS preset],[? AS permissions] FROM [users_groups] WHERE [is_admin] = 0 AND [is_mod] = 1")
return err return err
} }
log.Print("Preparing addForumPermsToForumMembers statement.") log.Print("Preparing addForumPermsToForumMembers statement.")
addForumPermsToForumMembersStmt, err = db.Prepare("") addForumPermsToForumMembersStmt, err = db.Prepare("INSERT INTO [forums_permissions] ([gid],[fid],[preset],[permissions]) SELECT [gid],[? AS fid],[? AS preset],[? AS permissions] FROM [users_groups] WHERE [is_admin] = 0 AND [is_mod] = 0 AND [is_banned] = 0")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","INSERT INTO [forums_permissions] ([gid],[fid],[preset],[permissions]) SELECT [gid],[? AS fid],[? AS preset],[? AS permissions] FROM [users_groups] WHERE [is_admin] = 0 AND [is_mod] = 0 AND [is_banned] = 0")
return err return err
} }
log.Print("Preparing notifyWatchers statement.") log.Print("Preparing notifyWatchers statement.")
notifyWatchersStmt, err = db.Prepare("") notifyWatchersStmt, err = db.Prepare("INSERT INTO [activity_stream_matches] ([watcher],[asid]) SELECT [activity_subscriptions].[user],[activity_stream].[asid] FROM [activity_stream] INNER JOIN [activity_subscriptions] ON [activity_subscriptions].[targetType] = [activity_stream].[elementType] AND [activity_subscriptions].[targetID] = [activity_stream].[elementID] AND [activity_subscriptions].[user] != [activity_stream].[actor] WHERE [asid] = ?1")
if err != nil { if err != nil {
log.Print("Bad Query: ","") log.Print("Bad Query: ","INSERT INTO [activity_stream_matches] ([watcher],[asid]) SELECT [activity_subscriptions].[user],[activity_stream].[asid] FROM [activity_stream] INNER JOIN [activity_subscriptions] ON [activity_subscriptions].[targetType] = [activity_stream].[elementType] AND [activity_subscriptions].[targetID] = [activity_stream].[elementID] AND [activity_subscriptions].[user] != [activity_stream].[actor] WHERE [asid] = ?1")
return err return err
} }

View File

@ -6,6 +6,7 @@ package main
import "log" import "log"
import "database/sql" import "database/sql"
import "./query_gen/lib"
// nolint // nolint
var getUserStmt *sql.Stmt var getUserStmt *sql.Stmt
@ -71,8 +72,8 @@ var addModlogEntryStmt *sql.Stmt
var addAdminlogEntryStmt *sql.Stmt var addAdminlogEntryStmt *sql.Stmt
var addAttachmentStmt *sql.Stmt var addAttachmentStmt *sql.Stmt
var createWordFilterStmt *sql.Stmt var createWordFilterStmt *sql.Stmt
var addForumPermsToGroupStmt *sql.Stmt var addForumPermsToGroupStmt *qgen.MySQLUpsertCallback
var replaceScheduleGroupStmt *sql.Stmt var replaceScheduleGroupStmt *qgen.MySQLUpsertCallback
var addRepliesToTopicStmt *sql.Stmt var addRepliesToTopicStmt *sql.Stmt
var removeRepliesFromTopicStmt *sql.Stmt var removeRepliesFromTopicStmt *sql.Stmt
var addTopicsToForumStmt *sql.Stmt var addTopicsToForumStmt *sql.Stmt
@ -114,6 +115,7 @@ var verifyEmailStmt *sql.Stmt
var setTempGroupStmt *sql.Stmt var setTempGroupStmt *sql.Stmt
var updateWordFilterStmt *sql.Stmt var updateWordFilterStmt *sql.Stmt
var bumpSyncStmt *sql.Stmt var bumpSyncStmt *sql.Stmt
var deleteUserStmt *sql.Stmt
var deleteReplyStmt *sql.Stmt var deleteReplyStmt *sql.Stmt
var deleteProfileReplyStmt *sql.Stmt var deleteProfileReplyStmt *sql.Stmt
var deleteForumPermsByForumStmt *sql.Stmt var deleteForumPermsByForumStmt *sql.Stmt
@ -230,7 +232,7 @@ func _gen_mysql() (err error) {
} }
log.Print("Preparing getUsersOffset statement.") log.Print("Preparing getUsersOffset statement.")
getUsersOffsetStmt, err = db.Prepare("SELECT `uid`,`name`,`group`,`active`,`is_super_admin`,`avatar` FROM `users` LIMIT ?,?") getUsersOffsetStmt, err = db.Prepare("SELECT `uid`,`name`,`group`,`active`,`is_super_admin`,`avatar` FROM `users` ORDER BY uid ASC LIMIT ?,?")
if err != nil { if err != nil {
return err return err
} }
@ -254,7 +256,7 @@ func _gen_mysql() (err error) {
} }
log.Print("Preparing getModlogsOffset statement.") log.Print("Preparing getModlogsOffset statement.")
getModlogsOffsetStmt, err = db.Prepare("SELECT `action`,`elementID`,`elementType`,`ipaddress`,`actorID`,`doneAt` FROM `moderation_logs` LIMIT ?,?") getModlogsOffsetStmt, err = db.Prepare("SELECT `action`,`elementID`,`elementType`,`ipaddress`,`actorID`,`doneAt` FROM `moderation_logs` ORDER BY doneAt DESC LIMIT ?,?")
if err != nil { if err != nil {
return err return err
} }
@ -350,7 +352,7 @@ func _gen_mysql() (err error) {
} }
log.Print("Preparing getTopicRepliesOffset statement.") log.Print("Preparing getTopicRepliesOffset statement.")
getTopicRepliesOffsetStmt, err = db.Prepare("SELECT `replies`.`rid`,`replies`.`content`,`replies`.`createdBy`,`replies`.`createdAt`,`replies`.`lastEdit`,`replies`.`lastEditBy`,`users`.`avatar`,`users`.`name`,`users`.`group`,`users`.`url_prefix`,`users`.`url_name`,`users`.`level`,`replies`.`ipaddress`,`replies`.`likeCount`,`replies`.`actionType` FROM `replies` LEFT JOIN `users` ON `replies`.`createdBy` = `users`.`uid` WHERE `replies`.`tid` = ? LIMIT ?,?") getTopicRepliesOffsetStmt, err = db.Prepare("SELECT `replies`.`rid`,`replies`.`content`,`replies`.`createdBy`,`replies`.`createdAt`,`replies`.`lastEdit`,`replies`.`lastEditBy`,`users`.`avatar`,`users`.`name`,`users`.`group`,`users`.`url_prefix`,`users`.`url_name`,`users`.`level`,`replies`.`ipaddress`,`replies`.`likeCount`,`replies`.`actionType` FROM `replies` LEFT JOIN `users` ON `replies`.`createdBy` = `users`.`uid` WHERE `replies`.`tid` = ? ORDER BY replies.rid ASC LIMIT ?,?")
if err != nil { if err != nil {
return err return err
} }
@ -404,19 +406,19 @@ func _gen_mysql() (err error) {
} }
log.Print("Preparing createReport statement.") log.Print("Preparing createReport statement.")
createReportStmt, err = db.Prepare("INSERT INTO `topics`(`title`,`content`,`parsed_content`,`createdAt`,`lastReplyAt`,`createdBy`,`data`,`parentID`,`css_class`) VALUES (?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,1,'report')") createReportStmt, err = db.Prepare("INSERT INTO `topics`(`title`,`content`,`parsed_content`,`createdAt`,`lastReplyAt`,`createdBy`,`lastReplyBy`,`data`,`parentID`,`css_class`) VALUES (?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?,1,'report')")
if err != nil { if err != nil {
return err return err
} }
log.Print("Preparing createReply statement.") log.Print("Preparing createReply statement.")
createReplyStmt, err = db.Prepare("INSERT INTO `replies`(`tid`,`content`,`parsed_content`,`createdAt`,`ipaddress`,`words`,`createdBy`) VALUES (?,?,?,UTC_TIMESTAMP(),?,?,?)") createReplyStmt, err = db.Prepare("INSERT INTO `replies`(`tid`,`content`,`parsed_content`,`createdAt`,`lastUpdated`,`ipaddress`,`words`,`createdBy`) VALUES (?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?)")
if err != nil { if err != nil {
return err return err
} }
log.Print("Preparing createActionReply statement.") log.Print("Preparing createActionReply statement.")
createActionReplyStmt, err = db.Prepare("INSERT INTO `replies`(`tid`,`actionType`,`ipaddress`,`createdBy`) VALUES (?,?,?,?)") createActionReplyStmt, err = db.Prepare("INSERT INTO `replies`(`tid`,`actionType`,`ipaddress`,`createdBy`,`createdAt`,`lastUpdated`,`content`,`parsed_content`) VALUES (?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'','')")
if err != nil { if err != nil {
return err return err
} }
@ -512,13 +514,13 @@ func _gen_mysql() (err error) {
} }
log.Print("Preparing addForumPermsToGroup statement.") log.Print("Preparing addForumPermsToGroup statement.")
addForumPermsToGroupStmt, err = db.Prepare("REPLACE INTO `forums_permissions`(`gid`,`fid`,`preset`,`permissions`) VALUES (?,?,?,?)") addForumPermsToGroupStmt, err = qgen.PrepareMySQLUpsertCallback(db, "INSERT INTO `forums_permissions`(`gid`,`fid`,`preset`,`permissions`) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE `gid` = ? AND `fid` = ? AND `preset` = ? AND `permissions` = ?")
if err != nil { if err != nil {
return err return err
} }
log.Print("Preparing replaceScheduleGroup statement.") log.Print("Preparing replaceScheduleGroup statement.")
replaceScheduleGroupStmt, err = db.Prepare("REPLACE INTO `users_groups_scheduler`(`uid`,`set_group`,`issued_by`,`issued_at`,`revert_at`,`temporary`) VALUES (?,?,?,UTC_TIMESTAMP(),?,?)") replaceScheduleGroupStmt, err = qgen.PrepareMySQLUpsertCallback(db, "INSERT INTO `users_groups_scheduler`(`uid`,`set_group`,`issued_by`,`issued_at`,`revert_at`,`temporary`) VALUES (?,?,?,UTC_TIMESTAMP(),?,?) ON DUPLICATE KEY UPDATE `uid` = ? AND `set_group` = ? AND `issued_by` = ? AND `issued_at` = UTC_TIMESTAMP() AND `revert_at` = ? AND `temporary` = ?")
if err != nil { if err != nil {
return err return err
} }
@ -769,6 +771,12 @@ func _gen_mysql() (err error) {
return err return err
} }
log.Print("Preparing deleteUser statement.")
deleteUserStmt, err = db.Prepare("DELETE FROM `users` WHERE `uid` = ?")
if err != nil {
return err
}
log.Print("Preparing deleteReply statement.") log.Print("Preparing deleteReply statement.")
deleteReplyStmt, err = db.Prepare("DELETE FROM `replies` WHERE `rid` = ?") deleteReplyStmt, err = db.Prepare("DELETE FROM `replies` WHERE `rid` = ?")
if err != nil { if err != nil {

15
gen_tables.go Normal file
View File

@ -0,0 +1,15 @@
// Generated by Gosora's Query Generator. DO NOT EDIT.
package main
var dbTablePrimaryKeys = map[string]string{
"forums":"fid",
"topics":"tid",
"attachments":"attachID",
"users_replies":"rid",
"word_filters":"wfid",
"users":"uid",
"users_groups":"gid",
"users_groups_scheduler":"uid",
"replies":"rid",
"activity_stream":"asid",
}

View File

@ -24,6 +24,26 @@ import (
//var dbTest *sql.DB //var dbTest *sql.DB
var dbProd *sql.DB var dbProd *sql.DB
var gloinited bool var gloinited bool
var installAdapter install.InstallAdapter
func ResetTables() (err error) {
err = installAdapter.InitDatabase()
if err != nil {
return err
}
err = installAdapter.TableDefs()
if err != nil {
return err
}
err = installAdapter.CreateAdmin()
if err != nil {
return err
}
return installAdapter.InitialData()
}
func gloinit() (err error) { func gloinit() (err error) {
dev.DebugMode = false dev.DebugMode = false
@ -42,28 +62,14 @@ func gloinit() (err error) {
switchToTestDB() switchToTestDB()
adap, ok := install.Lookup(dbAdapter) var ok bool
installAdapter, ok = install.Lookup(dbAdapter)
if !ok { if !ok {
return errors.New("We couldn't find the adapter '" + dbAdapter + "'") return errors.New("We couldn't find the adapter '" + dbAdapter + "'")
} }
adap.SetConfig(dbConfig.Host, dbConfig.Username, dbConfig.Password, dbConfig.Dbname, dbConfig.Port) installAdapter.SetConfig(dbConfig.Host, dbConfig.Username, dbConfig.Password, dbConfig.Dbname, dbConfig.Port)
err = adap.InitDatabase() err = ResetTables()
if err != nil {
return err
}
err = adap.TableDefs()
if err != nil {
return err
}
err = adap.CreateAdmin()
if err != nil {
return err
}
err = adap.InitialData()
if err != nil { if err != nil {
return err return err
} }
@ -110,6 +116,7 @@ func gloinit() (err error) {
func init() { func init() {
err := gloinit() err := gloinit()
if err != nil { if err != nil {
log.Print("Something bad happened")
log.Fatal(err) log.Fatal(err)
} }
} }

View File

@ -106,6 +106,13 @@ func (ins *MssqlInstaller) TableDefs() (err error) {
} }
table = strings.TrimSuffix(table, ext) table = strings.TrimSuffix(table, ext)
// ? - This is mainly here for tests, although it might allow the installer to overwrite a production database, so we might want to proceed with caution
_, err = ins.db.Exec("DROP TABLE IF EXISTS [" + table + "];")
if err != nil {
fmt.Println("Failed query:", "DROP TABLE IF EXISTS ["+table+"]")
return err
}
fmt.Println("Creating table '" + table + "'") fmt.Println("Creating table '" + table + "'")
data, err := ioutil.ReadFile("./schema/mssql/" + f.Name()) data, err := ioutil.ReadFile("./schema/mssql/" + f.Name())
if err != nil { if err != nil {

View File

@ -758,7 +758,7 @@ func routeReportSubmit(w http.ResponseWriter, r *http.Request, user User, sitemI
// TODO: Repost attachments in the reports forum, so that the mods can see them // TODO: Repost attachments in the reports forum, so that the mods can see them
// ? - Can we do this via the TopicStore? // ? - Can we do this via the TopicStore?
res, err := createReportStmt.Exec(title, content, parseMessage(content, 0, ""), user.ID, itemType+"_"+strconv.Itoa(itemID)) res, err := createReportStmt.Exec(title, content, parseMessage(content, 0, ""), user.ID, user.ID, itemType+"_"+strconv.Itoa(itemID))
if err != nil { if err != nil {
InternalError(err, w) InternalError(err, w)
return return

View File

@ -1,10 +1,29 @@
package main package main
import "strconv" import (
import "testing" "fmt"
"runtime/debug"
"strconv"
"testing"
"time"
)
func recordMustExist(t *testing.T, err error, errmsg string) {
if err == ErrNoRows {
t.Error(errmsg)
} else if err != nil {
t.Fatal(err)
}
}
func recordMustNotExist(t *testing.T, err error, errmsg string) {
if err == nil {
t.Error(errmsg)
} else if err != ErrNoRows {
t.Fatal(err)
}
}
// TODO: Generate a test database to work with rather than a live one
// TODO: We might need to refactor TestUserStore soon, as it's getting fairly complex
func TestUserStore(t *testing.T) { func TestUserStore(t *testing.T) {
if !gloinited { if !gloinited {
err := gloinit() err := gloinit()
@ -18,14 +37,13 @@ func TestUserStore(t *testing.T) {
users = NewMemoryUserStore(config.UserCacheCapacity) users = NewMemoryUserStore(config.UserCacheCapacity)
users.(UserCache).Flush() users.(UserCache).Flush()
userStoreTest(t) userStoreTest(t, 2)
users = NewSQLUserStore() users = NewSQLUserStore()
userStoreTest(t) userStoreTest(t, 3)
} }
func userStoreTest(t *testing.T) { func userStoreTest(t *testing.T, newUserID int) {
var user *User var user *User
var err error var err error
var length int
ucache, hasCache := users.(UserCache) ucache, hasCache := users.(UserCache)
if hasCache && ucache.Length() != 0 { if hasCache && ucache.Length() != 0 {
@ -33,60 +51,57 @@ func userStoreTest(t *testing.T) {
} }
_, err = users.Get(-1) _, err = users.Get(-1)
if err == nil { recordMustNotExist(t, err, "UID #-1 shouldn't exist")
t.Error("UID #-1 shouldn't exist")
} else if err != ErrNoRows {
t.Fatal(err)
}
if hasCache && ucache.Length() != 0 { if hasCache && ucache.Length() != 0 {
t.Error("There shouldn't be anything in the user cache") t.Error("There shouldn't be anything in the user cache")
} }
_, err = users.Get(0) _, err = users.Get(0)
if err == nil { recordMustNotExist(t, err, "UID #0 shouldn't exist")
t.Error("UID #0 shouldn't exist")
} else if err != ErrNoRows {
t.Fatal(err)
}
if hasCache && ucache.Length() != 0 { if hasCache && ucache.Length() != 0 {
t.Error("There shouldn't be anything in the user cache") t.Error("There shouldn't be anything in the user cache")
} }
user, err = users.Get(1) user, err = users.Get(1)
if err == ErrNoRows { recordMustExist(t, err, "Couldn't find UID #1")
t.Error("Couldn't find UID #1")
} else if err != nil {
t.Fatal(err)
}
if user.ID != 1 { if user.ID != 1 {
t.Error("user.ID does not match the requested UID. Got '" + strconv.Itoa(user.ID) + "' instead.") t.Error("user.ID does not match the requested UID. Got '" + strconv.Itoa(user.ID) + "' instead.")
} }
if user.Name != "Admin" {
t.Error("user.Name should be 'Admin', not '" + user.Name + "'")
}
if user.Group != 1 {
t.Error("Admin should be in group 1")
}
user, err = users.Get(newUserID)
recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't exist", newUserID))
if hasCache { if hasCache {
length = ucache.Length() expectIntToBeX(t, ucache.Length(), 1, "User cache length should be 1, not %d")
if length != 1 {
t.Error("User cache length should be 1, not " + strconv.Itoa(length))
}
user, err = ucache.CacheGet(-1)
recordMustNotExist(t, err, "UID #-1 shouldn't exist, even in the cache")
user, err = ucache.CacheGet(0)
recordMustNotExist(t, err, "UID #0 shouldn't exist, even in the cache")
user, err = ucache.CacheGet(1) user, err = ucache.CacheGet(1)
if err == ErrNoRows { recordMustExist(t, err, "Couldn't find UID #1 in the cache")
t.Error("Couldn't find UID #1 in the cache")
} else if err != nil {
t.Fatal(err)
}
if user.ID != 1 { if user.ID != 1 {
t.Error("user.ID does not match the requested UID. Got '" + strconv.Itoa(user.ID) + "' instead.") t.Error("user.ID does not match the requested UID. Got '" + strconv.Itoa(user.ID) + "' instead.")
} }
if user.Name != "Admin" {
t.Error("user.Name should be 'Admin', not '" + user.Name + "'")
}
user, err = ucache.CacheGet(newUserID)
recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't exist, even in the cache", newUserID))
ucache.Flush() ucache.Flush()
length = ucache.Length() expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
if length != 0 {
t.Error("User cache length should be 0, not " + strconv.Itoa(length))
}
} }
// TODO: Lock onto the specific error type. Is this even possible without sacrificing the detailed information in the error message? // TODO: Lock onto the specific error type. Is this even possible without sacrificing the detailed information in the error message?
@ -97,10 +112,7 @@ func userStoreTest(t *testing.T) {
} }
if hasCache { if hasCache {
length = ucache.Length() expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
if length != 0 {
t.Error("User cache length should be 0, not " + strconv.Itoa(length))
}
} }
userList, _ = users.BulkGetMap([]int{0}) userList, _ = users.BulkGetMap([]int{0})
@ -109,10 +121,7 @@ func userStoreTest(t *testing.T) {
} }
if hasCache { if hasCache {
length = ucache.Length() expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
if length != 0 {
t.Error("User cache length should be 0, not " + strconv.Itoa(length))
}
} }
userList, _ = users.BulkGetMap([]int{1}) userList, _ = users.BulkGetMap([]int{1})
@ -133,17 +142,9 @@ func userStoreTest(t *testing.T) {
} }
if hasCache { if hasCache {
length = ucache.Length() expectIntToBeX(t, ucache.Length(), 1, "User cache length should be 1, not %d")
if length != 1 {
t.Error("User cache length should be 1, not " + strconv.Itoa(length))
}
user, err = ucache.CacheGet(1) user, err = ucache.CacheGet(1)
if err == ErrNoRows { recordMustExist(t, err, "Couldn't find UID #1 in the cache")
t.Error("Couldn't find UID #1 in the cache")
} else if err != nil {
t.Fatal(err)
}
if user.ID != 1 { if user.ID != 1 {
t.Error("user.ID does not match the requested UID. Got '" + strconv.Itoa(user.ID) + "' instead.") t.Error("user.ID does not match the requested UID. Got '" + strconv.Itoa(user.ID) + "' instead.")
@ -152,32 +153,138 @@ func userStoreTest(t *testing.T) {
ucache.Flush() ucache.Flush()
} }
ok = users.Exists(-1) expect(t, !users.Exists(-1), "UID #-1 shouldn't exist")
if ok { expect(t, !users.Exists(0), "UID #0 shouldn't exist")
t.Error("UID #-1 shouldn't exist") expect(t, users.Exists(1), "UID #1 should exist")
} expect(t, !users.Exists(newUserID), fmt.Sprintf("UID #%d shouldn't exist", newUserID))
ok = users.Exists(0)
if ok {
t.Error("UID #0 shouldn't exist")
}
ok = users.Exists(1)
if !ok {
t.Error("UID #1 should exist")
}
if hasCache { if hasCache {
length = ucache.Length() expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
if length != 0 { }
t.Error("User cache length should be 0, not " + strconv.Itoa(length)) expectIntToBeX(t, users.GlobalCount(), 1, "The number of users should be one, not %d")
var awaitingActivation = 5
uid, err := users.Create("Sam", "ReallyBadPassword", "sam@localhost.loc", awaitingActivation, 0)
if err != nil {
t.Error(err)
}
if uid != newUserID {
t.Errorf("The UID of the new user should be %d", newUserID)
}
if !users.Exists(newUserID) {
t.Errorf("UID #%d should exist", newUserID)
}
user, err = users.Get(newUserID)
recordMustExist(t, err, fmt.Sprintf("Couldn't find UID #%d", newUserID))
if user.ID != newUserID {
t.Errorf("The UID of the user record should be %d", newUserID)
}
if user.Name != "Sam" {
t.Error("The user should be named Sam")
}
expectIntToBeX(t, user.Group, 5, "Sam should be in group 5")
if hasCache {
expectIntToBeX(t, ucache.Length(), 1, "User cache length should be 1, not %d")
user, err = ucache.CacheGet(newUserID)
recordMustExist(t, err, fmt.Sprintf("Couldn't find UID #%d in the cache", newUserID))
if user.ID != newUserID {
t.Error("user.ID does not match the requested UID. Got '" + strconv.Itoa(user.ID) + "' instead.")
} }
} }
count := users.GlobalCount() err = user.Activate()
if count <= 0 { if err != nil {
t.Error("The number of users should be bigger than zero") t.Error(err)
t.Error("count", count) }
expectIntToBeX(t, user.Group, 5, "Sam should still be in group 5 in this copy")
// ? - What if we change the caching mechanism so it isn't hard purged and reloaded? We'll deal with that when we come to it, but for now, this is a sign of a cache bug
if hasCache {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
_, err = ucache.CacheGet(newUserID)
recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't be in the cache", newUserID))
}
user, err = users.Get(newUserID)
recordMustExist(t, err, fmt.Sprintf("Couldn't find UID #%d", newUserID))
if user.ID != newUserID {
t.Errorf("The UID of the user record should be %d", newUserID)
}
expectIntToBeX(t, user.Group, config.DefaultGroup, "Sam should be in group "+strconv.Itoa(config.DefaultGroup))
// Permanent ban
duration, _ := time.ParseDuration("0")
// TODO: Attempt a double ban, double activation, and double unban
err = user.Ban(duration, 1)
if err != nil {
t.Error(err)
}
expectIntToBeX(t, user.Group, config.DefaultGroup, "Sam should still be in the default group in this copy")
if hasCache {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
_, err = ucache.CacheGet(2)
recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't be in the cache", newUserID))
}
user, err = users.Get(newUserID)
recordMustExist(t, err, fmt.Sprintf("Couldn't find UID #%d", newUserID))
if user.ID != newUserID {
t.Errorf("The UID of the user record should be %d", newUserID)
}
expectIntToBeX(t, user.Group, banGroup, "Sam should be in group "+strconv.Itoa(banGroup))
// TODO: Do tests against the scheduled updates table and the task system to make sure the ban exists there and gets revoked when it should
err = user.Unban()
if err != nil {
t.Error(err)
}
expectIntToBeX(t, user.Group, banGroup, "Sam should still be in the ban group in this copy")
if hasCache {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
_, err = ucache.CacheGet(newUserID)
recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't be in the cache", newUserID))
}
user, err = users.Get(newUserID)
recordMustExist(t, err, fmt.Sprintf("Couldn't find UID #%d", newUserID))
if user.ID != newUserID {
t.Errorf("The UID of the user record should be %d", newUserID)
}
expectIntToBeX(t, user.Group, config.DefaultGroup, "Sam should be back in group "+strconv.Itoa(config.DefaultGroup))
err = user.Delete()
if err != nil {
t.Error(err)
}
expect(t, !users.Exists(newUserID), fmt.Sprintf("UID #%d should not longer exist", newUserID))
if hasCache {
expectIntToBeX(t, ucache.Length(), 0, "User cache length should be 0, not %d")
_, err = ucache.CacheGet(newUserID)
recordMustNotExist(t, err, fmt.Sprintf("UID #%d shouldn't be in the cache", newUserID))
}
// TODO: Works for now but might cause a data race with the task system
//ResetTables()
}
func expectIntToBeX(t *testing.T, item int, expect int, errmsg string) {
if item != expect {
debug.PrintStack()
t.Fatalf(errmsg, item)
}
}
func expect(t *testing.T, item bool, errmsg string) {
if !item {
debug.PrintStack()
t.Fatalf(errmsg)
} }
} }
@ -216,11 +323,7 @@ func topicStoreTest(t *testing.T) {
} }
topic, err = topics.Get(1) topic, err = topics.Get(1)
if err == ErrNoRows { recordMustExist(t, err, "Couldn't find TID #1")
t.Error("Couldn't find TID #1")
} else if err != nil {
t.Fatal(err)
}
if topic.ID != 1 { if topic.ID != 1 {
t.Error("topic.ID does not match the requested TID. Got '" + strconv.Itoa(topic.ID) + "' instead.") t.Error("topic.ID does not match the requested TID. Got '" + strconv.Itoa(topic.ID) + "' instead.")
@ -276,11 +379,7 @@ func TestForumStore(t *testing.T) {
} }
forum, err = fstore.Get(1) forum, err = fstore.Get(1)
if err == ErrNoRows { recordMustExist(t, err, "Couldn't find FID #1")
t.Error("Couldn't find FID #1")
} else if err != nil {
t.Fatal(err)
}
if forum.ID != 1 { if forum.ID != 1 {
t.Error("forum.ID doesn't not match the requested FID. Got '" + strconv.Itoa(forum.ID) + "' instead.'") t.Error("forum.ID doesn't not match the requested FID. Got '" + strconv.Itoa(forum.ID) + "' instead.'")
@ -290,11 +389,7 @@ func TestForumStore(t *testing.T) {
} }
forum, err = fstore.Get(2) forum, err = fstore.Get(2)
if err == ErrNoRows { recordMustExist(t, err, "Couldn't find FID #1")
t.Error("Couldn't find FID #2")
} else if err != nil {
t.Fatal(err)
}
_ = forum _ = forum
@ -332,12 +427,9 @@ func TestGroupStore(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
// TODO: Refactor the group store to remove GID #0
group, err = gstore.Get(0) group, err = gstore.Get(0)
if err == ErrNoRows { recordMustExist(t, err, "Couldn't find GID #0")
t.Error("Couldn't find GID #0")
} else if err != nil {
t.Fatal(err)
}
if group.ID != 0 { if group.ID != 0 {
t.Error("group.ID doesn't not match the requested GID. Got '" + strconv.Itoa(group.ID) + "' instead.") t.Error("group.ID doesn't not match the requested GID. Got '" + strconv.Itoa(group.ID) + "' instead.")
@ -346,14 +438,8 @@ func TestGroupStore(t *testing.T) {
t.Error("GID #0 is named '" + group.Name + "' and not 'Unknown'") t.Error("GID #0 is named '" + group.Name + "' and not 'Unknown'")
} }
// ? - What if they delete this group? x.x
// ? - Maybe, pick a random group ID? That would take an extra query, and I'm not sure if I want to be rewriting custom test queries. Possibly, a Random() method on the GroupStore? Seems useless for normal use, it might have some merit for the TopicStore though
group, err = gstore.Get(1) group, err = gstore.Get(1)
if err == ErrNoRows { recordMustExist(t, err, "Couldn't find GID #1")
t.Error("Couldn't find GID #1")
} else if err != nil {
t.Fatal(err)
}
if group.ID != 1 { if group.ID != 1 {
t.Error("group.ID doesn't not match the requested GID. Got '" + strconv.Itoa(group.ID) + "' instead.'") t.Error("group.ID doesn't not match the requested GID. Got '" + strconv.Itoa(group.ID) + "' instead.'")

View File

@ -11,6 +11,7 @@ package main
//import "time" //import "time"
import ( import (
"database/sql" "database/sql"
"log"
"net/url" "net/url"
"./query_gen/lib" "./query_gen/lib"
@ -78,7 +79,62 @@ func initMSSQL() (err error) {
return err return err
} }
// TODO: Add the custom queries setter, ok := qgen.Builder.GetAdapter().(qgen.SetPrimaryKeys)
if ok {
setter.SetPrimaryKeys(dbTablePrimaryKeys)
}
return nil // TODO: Is there a less noisy way of doing this for tests?
log.Print("Preparing get_activity_feed_by_watcher statement.")
getActivityFeedByWatcherStmt, err = db.Prepare("SELECT activity_stream_matches.asid, activity_stream.actor, activity_stream.targetUser, activity_stream.event, activity_stream.elementType, activity_stream.elementID FROM [activity_stream_matches] INNER JOIN [activity_stream] ON activity_stream_matches.asid = activity_stream.asid AND activity_stream_matches.watcher != activity_stream.actor WHERE [watcher] = ? ORDER BY activity_stream.asid ASC OFFSET 0 ROWS FETCH NEXT 8 ROWS ONLY")
if err != nil {
return err
}
log.Print("Preparing get_activity_count_by_watcher statement.")
getActivityCountByWatcherStmt, err = db.Prepare("SELECT count(*) FROM [activity_stream_matches] INNER JOIN [activity_stream] ON activity_stream_matches.asid = activity_stream.asid AND activity_stream_matches.watcher != activity_stream.actor WHERE [watcher] = ?")
if err != nil {
return err
}
log.Print("Preparing todays_post_count statement.")
todaysPostCountStmt, err = db.Prepare("select count(*) from replies where createdAt >= DATEADD(DAY, -1, GETUTCDATE())")
if err != nil {
return err
}
log.Print("Preparing todays_topic_count statement.")
todaysTopicCountStmt, err = db.Prepare("select count(*) from topics where createdAt >= DATEADD(DAY, -1, GETUTCDATE())")
if err != nil {
return err
}
log.Print("Preparing todays_report_count statement.")
todaysReportCountStmt, err = db.Prepare("select count(*) from topics where createdAt >= DATEADD(DAY, -1, GETUTCDATE()) and parentID = 1")
if err != nil {
return err
}
log.Print("Preparing todays_newuser_count statement.")
todaysNewUserCountStmt, err = db.Prepare("select count(*) from users where createdAt >= DATEADD(DAY, -1, GETUTCDATE())")
if err != nil {
return err
}
// ? - Why is this a custom query? Are we planning a union or something?
log.Print("Preparing find_users_by_ip_users statement.")
findUsersByIPUsersStmt, err = db.Prepare("select uid from users where last_ip = ?")
if err != nil {
return err
}
log.Print("Preparing find_users_by_ip_topics statement.")
findUsersByIPTopicsStmt, err = db.Prepare("select uid from users where uid in(select createdBy from topics where ipaddress = ?)")
if err != nil {
return err
}
log.Print("Preparing find_users_by_ip_replies statement.")
findUsersByIPRepliesStmt, err = db.Prepare("select uid from users where uid in(select createdBy from replies where ipaddress = ?)")
return err
} }

View File

@ -180,7 +180,7 @@ func TestBBCodeRender(t *testing.T) {
t.Error("Expected a number between 0 and 170141183460469231731687303715884105727") t.Error("Expected a number between 0 and 170141183460469231731687303715884105727")
} }
t.Log("Testing bbcode_regex_parse") /*t.Log("Testing bbcode_regex_parse")
for _, item := range msgList { for _, item := range msgList {
t.Log("Testing string '" + item.Msg + "'") t.Log("Testing string '" + item.Msg + "'")
res = bbcodeRegexParse(item.Msg) res = bbcodeRegexParse(item.Msg)
@ -188,7 +188,7 @@ func TestBBCodeRender(t *testing.T) {
t.Error("Bad output:", "'"+res+"'") t.Error("Bad output:", "'"+res+"'")
t.Error("Expected:", item.Expects) t.Error("Expected:", item.Expects)
} }
} }*/
} }
func TestMarkdownRender(t *testing.T) { func TestMarkdownRender(t *testing.T) {

View File

@ -210,22 +210,22 @@ $(document).ready(function(){
$(".hide_on_edit").show(); $(".hide_on_edit").show();
$(".show_on_edit").hide(); $(".show_on_edit").hide();
var topic_name_input = $('.topic_name_input').val(); let topicNameInput = $('.topic_name_input').val();
var topic_status_input = $('.topic_status_input').val(); let topicStatusInput = $('.topic_status_input').val();
var topic_content_input = $('.topic_content_input').val(); let topicContentInput = $('.topic_content_input').val();
var form_action = this.form.getAttribute("action"); let formAction = this.form.getAttribute("action");
//console.log("New Topic Name: " + topic_name_input); //console.log("New Topic Name: " + topicNameInput);
//console.log("New Topic Status: " + topic_status_input); //console.log("New Topic Status: " + topicStatusInput);
//console.log("New Topic Content: " + topic_content_input); //console.log("New Topic Content: " + topicContentInput);
//console.log("Form Action: " + form_action); //console.log("Form Action: " + formAction);
$.ajax({ $.ajax({
url: form_action, url: formAction,
type: "POST", type: "POST",
dataType: "json", dataType: "json",
data: { data: {
topic_name: topic_name_input, topic_name: topicNameInput,
topic_status: topic_status_input, topic_status: topicStatusInput,
topic_content: topic_content_input, topic_content: topicContentInput,
topic_js: 1 topic_js: 1
} }
}); });
@ -234,28 +234,27 @@ $(document).ready(function(){
$(".delete_item").click(function(event) $(".delete_item").click(function(event)
{ {
post_link(event); post_link(event);
var block = $(this).closest('.deletable_block'); $(this).closest('.deletable_block').remove();
block.remove();
}); });
$(".edit_item").click(function(event) $(".edit_item").click(function(event)
{ {
event.preventDefault(); event.preventDefault();
var block_parent = $(this).closest('.editable_parent'); let blockParent = $(this).closest('.editable_parent');
var block = block_parent.find('.editable_block').eq(0); let block = blockParent.find('.editable_block').eq(0);
block.html("<textarea style='width: 99%;' name='edit_item'>" + block.html() + "</textarea><br /><a href='" + $(this).closest('a').attr("href") + "'><button class='submit_edit' type='submit'>Update</button></a>"); block.html("<textarea style='width: 99%;' name='edit_item'>" + block.html() + "</textarea><br /><a href='" + $(this).closest('a').attr("href") + "'><button class='submit_edit' type='submit'>Update</button></a>");
$(".submit_edit").click(function(event) $(".submit_edit").click(function(event)
{ {
event.preventDefault(); event.preventDefault();
var block_parent = $(this).closest('.editable_parent'); let blockParent = $(this).closest('.editable_parent');
var block = block_parent.find('.editable_block').eq(0); let block = blockParent.find('.editable_block').eq(0);
var newContent = block.find('textarea').eq(0).val(); let newContent = block.find('textarea').eq(0).val();
block.html(newContent); block.html(newContent);
var form_action = $(this).closest('a').attr("href"); var formAction = $(this).closest('a').attr("href");
//console.log("Form Action: " + form_action); //console.log("Form Action: " + form_action);
$.ajax({ url: form_action, type: "POST", dataType: "json", data: { isJs: "1", edit_item: newContent } $.ajax({ url: formAction, type: "POST", dataType: "json", data: { isJs: "1", edit_item: newContent }
}); });
}); });
}); });
@ -263,22 +262,22 @@ $(document).ready(function(){
$(".edit_field").click(function(event) $(".edit_field").click(function(event)
{ {
event.preventDefault(); event.preventDefault();
var block_parent = $(this).closest('.editable_parent'); let blockParent = $(this).closest('.editable_parent');
var block = block_parent.find('.editable_block').eq(0); let block = blockParent.find('.editable_block').eq(0);
block.html("<input name='edit_field' value='" + block.text() + "' type='text'/><a href='" + $(this).closest('a').attr("href") + "'><button class='submit_edit' type='submit'>Update</button></a>"); block.html("<input name='edit_field' value='" + block.text() + "' type='text'/><a href='" + $(this).closest('a').attr("href") + "'><button class='submit_edit' type='submit'>Update</button></a>");
$(".submit_edit").click(function(event) $(".submit_edit").click(function(event)
{ {
event.preventDefault(); event.preventDefault();
var block_parent = $(this).closest('.editable_parent'); let blockParent = $(this).closest('.editable_parent');
var block = block_parent.find('.editable_block').eq(0); let block = blockParent.find('.editable_block').eq(0);
var newContent = block.find('input').eq(0).val(); let newContent = block.find('input').eq(0).val();
block.html(newContent); block.html(newContent);
var form_action = $(this).closest('a').attr("href"); let formAction = $(this).closest('a').attr("href");
//console.log("Form Action: " + form_action); //console.log("Form Action: " + formAction);
$.ajax({ $.ajax({
url: form_action + "?session=" + session, url: formAction + "?session=" + session,
type: "POST", type: "POST",
dataType: "json", dataType: "json",
data: {isJs: "1",edit_item: newContent} data: {isJs: "1",edit_item: newContent}

View File

@ -7,12 +7,11 @@ import "database/sql"
var Builder *builder var Builder *builder
func init() { func init() {
Builder = &builder{conn:nil} Builder = &builder{conn: nil}
} }
// A set of wrappers around the generator methods, so that we can use this inline in Gosora // A set of wrappers around the generator methods, so that we can use this inline in Gosora
type builder struct type builder struct {
{
conn *sql.DB conn *sql.DB
adapter DB_Adapter adapter DB_Adapter
} }
@ -30,6 +29,10 @@ func (build *builder) SetAdapter(name string) error {
return nil return nil
} }
func (build *builder) GetAdapter() DB_Adapter {
return build.adapter
}
func (build *builder) SimpleSelect(table string, columns string, where string, orderby string, limit string) (stmt *sql.Stmt, err error) { func (build *builder) SimpleSelect(table string, columns string, where string, orderby string, limit string) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleSelect("_builder", table, columns, where, orderby, limit) res, err := build.adapter.SimpleSelect("_builder", table, columns, where, orderby, limit)
if err != nil { if err != nil {

View File

@ -18,6 +18,7 @@ type DB_Install_Instruction struct {
type installer struct { type installer struct {
adapter DB_Adapter adapter DB_Adapter
instructions []DB_Install_Instruction instructions []DB_Install_Instruction
plugins []QueryPlugin
} }
func (install *installer) SetAdapter(name string) error { func (install *installer) SetAdapter(name string) error {
@ -35,20 +36,48 @@ func (install *installer) SetAdapterInstance(adapter DB_Adapter) {
install.instructions = []DB_Install_Instruction{} install.instructions = []DB_Install_Instruction{}
} }
func (install *installer) RegisterPlugin(plugin QueryPlugin) {
install.plugins = append(install.plugins, plugin)
}
func (install *installer) CreateTable(table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) error { func (install *installer) CreateTable(table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) error {
for _, plugin := range install.plugins {
err := plugin.Hook("CreateTableStart", table, charset, collation, columns, keys)
if err != nil {
return err
}
}
res, err := install.adapter.CreateTable("_installer", table, charset, collation, columns, keys) res, err := install.adapter.CreateTable("_installer", table, charset, collation, columns, keys)
if err != nil { if err != nil {
return err return err
} }
for _, plugin := range install.plugins {
err := plugin.Hook("CreateTableAfter", table, charset, collation, columns, keys, res)
if err != nil {
return err
}
}
install.instructions = append(install.instructions, DB_Install_Instruction{table, res, "create-table"}) install.instructions = append(install.instructions, DB_Install_Instruction{table, res, "create-table"})
return nil return nil
} }
func (install *installer) SimpleInsert(table string, columns string, fields string) error { func (install *installer) SimpleInsert(table string, columns string, fields string) error {
for _, plugin := range install.plugins {
err := plugin.Hook("SimpleInsertStart", table, columns, fields)
if err != nil {
return err
}
}
res, err := install.adapter.SimpleInsert("_installer", table, columns, fields) res, err := install.adapter.SimpleInsert("_installer", table, columns, fields)
if err != nil { if err != nil {
return err return err
} }
for _, plugin := range install.plugins {
err := plugin.Hook("SimpleInsertAfter", table, columns, fields, res)
if err != nil {
return err
}
}
install.instructions = append(install.instructions, DB_Install_Instruction{table, res, "insert"}) install.instructions = append(install.instructions, DB_Install_Instruction{table, res, "insert"})
return nil return nil
} }
@ -66,5 +95,18 @@ func (install *installer) Write() error {
inserts += instr.Contents + ";\n" inserts += instr.Contents + ";\n"
} }
} }
return writeFile("./schema/"+install.adapter.GetName()+"/inserts.sql", inserts)
err := writeFile("./schema/"+install.adapter.GetName()+"/inserts.sql", inserts)
if err != nil {
return err
}
for _, plugin := range install.plugins {
err := plugin.Write()
if err != nil {
return err
}
}
return nil
} }

1130
query_gen/lib/mssql.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -149,6 +149,7 @@ func (adapter *Mysql_Adapter) SimpleInsert(name string, table string, columns st
return querystr + ")", nil return querystr + ")", nil
} }
// ! DEPRECATED
func (adapter *Mysql_Adapter) SimpleReplace(name string, table string, columns string, fields string) (string, error) { func (adapter *Mysql_Adapter) SimpleReplace(name string, table string, columns string, fields string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
@ -186,6 +187,53 @@ func (adapter *Mysql_Adapter) SimpleReplace(name string, table string, columns s
return querystr + ")", nil return querystr + ")", nil
} }
func (adapter *Mysql_Adapter) SimpleUpsert(name string, table string, columns string, fields string, where 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 SimpleInsert")
}
if len(fields) == 0 {
return "", errors.New("No input data found for SimpleInsert")
}
if where == "" {
return "", errors.New("You need a where for this upsert")
}
var querystr = "INSERT INTO `" + table + "`("
var parsedFields = processFields(fields)
var insertColumns string
var insertValues string
var setBit = ") ON DUPLICATE KEY UPDATE "
for columnID, column := range processColumns(columns) {
field := parsedFields[columnID]
if column.Type == "function" {
insertColumns += column.Left + ","
insertValues += field.Name + ","
setBit += column.Left + " = " + field.Name + " AND "
} else {
insertColumns += "`" + column.Left + "`,"
insertValues += field.Name + ","
setBit += "`" + column.Left + "` = " + field.Name + " AND "
}
}
insertColumns = insertColumns[0 : len(insertColumns)-1]
insertValues = insertValues[0 : len(insertValues)-1]
insertColumns += ") VALUES (" + insertValues
setBit = setBit[0 : len(setBit)-5]
querystr += insertColumns + setBit
adapter.pushStatement(name, "upsert", querystr)
return querystr, nil
}
func (adapter *Mysql_Adapter) SimpleUpdate(name string, table string, set string, where string) (string, error) { func (adapter *Mysql_Adapter) SimpleUpdate(name string, table string, set string, where string) (string, error) {
if name == "" { if name == "" {
return "", errors.New("You need a name for this statement") return "", errors.New("You need a name for this statement")
@ -212,7 +260,6 @@ func (adapter *Mysql_Adapter) SimpleUpdate(name string, table string, set string
} }
querystr += "," querystr += ","
} }
// Remove the trailing comma // Remove the trailing comma
querystr = querystr[0 : len(querystr)-1] querystr = querystr[0 : len(querystr)-1]
@ -826,8 +873,17 @@ func (adapter *Mysql_Adapter) Write() error {
continue continue
} }
stmt := adapter.Buffer[name] stmt := adapter.Buffer[name]
// TODO: Add support for create-table? Table creation might be a little complex for Go to do outside a SQL file :( // ? - Table creation might be a little complex for Go to do outside a SQL file :(
if stmt.Type != "create-table" { if stmt.Type == "upsert" {
stmts += "var " + name + "Stmt *qgen.MySQLUpsertCallback\n"
body += `
log.Print("Preparing ` + name + ` statement.")
` + name + `Stmt, err = qgen.PrepareMySQLUpsertCallback(db, "` + stmt.Contents + `")
if err != nil {
return err
}
`
} else if stmt.Type != "create-table" {
stmts += "var " + name + "Stmt *sql.Stmt\n" stmts += "var " + name + "Stmt *sql.Stmt\n"
body += ` body += `
log.Print("Preparing ` + name + ` statement.") log.Print("Preparing ` + name + ` statement.")
@ -847,6 +903,7 @@ package main
import "log" import "log"
import "database/sql" import "database/sql"
import "./query_gen/lib"
// nolint // nolint
` + stmts + ` ` + stmts + `

View File

@ -128,6 +128,23 @@ func (adapter *Pgsql_Adapter) SimpleReplace(name string, table string, columns s
return "", nil return "", nil
} }
// TODO: Implement this
func (adapter *Pgsql_Adapter) SimpleUpsert(name string, table string, columns string, fields string, where 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 SimpleInsert")
}
if len(fields) == 0 {
return "", errors.New("No input data found for SimpleInsert")
}
return "", nil
}
// TODO: Implemented, but we need CreateTable and a better installer to *test* it // TODO: Implemented, but we need CreateTable and a better installer to *test* it
func (adapter *Pgsql_Adapter) SimpleUpdate(name string, table string, set string, where string) (string, error) { func (adapter *Pgsql_Adapter) SimpleUpdate(name string, table string, set string, where string) (string, error) {
if name == "" { if name == "" {

View File

@ -1,10 +1,13 @@
/* WIP Under Construction */ /* WIP Under Construction */
package qgen package qgen
import "errors" import (
"database/sql"
"errors"
)
var DB_Registry []DB_Adapter var DB_Registry []DB_Adapter
var No_Adapter = errors.New("This adapter doesn't exist") var ErrNoAdapter = errors.New("This adapter doesn't exist")
type DB_Table_Column struct { type DB_Table_Column struct {
Name string Name string
@ -97,7 +100,12 @@ type DB_Adapter interface {
GetName() string GetName() string
CreateTable(name string, table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (string, error) CreateTable(name string, table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (string, error)
SimpleInsert(name string, table string, columns string, fields string) (string, error) SimpleInsert(name string, table string, columns string, fields string) (string, error)
// ! DEPRECATED
SimpleReplace(name string, table string, columns string, fields string) (string, error) SimpleReplace(name string, table string, columns string, fields string) (string, error)
// ! NOTE: MySQL doesn't support upserts properly, asides from for keys, so this is just a less destructive replace atm
SimpleUpsert(name string, table string, columns string, fields string, where string) (string, error)
SimpleUpdate(name string, table string, set string, where string) (string, error) SimpleUpdate(name string, table string, set string, where string) (string, error)
SimpleDelete(name string, table string, where string) (string, error) SimpleDelete(name string, table string, where string) (string, error)
Purge(name string, table string) (string, error) Purge(name string, table string) (string, error)
@ -119,5 +127,27 @@ func GetAdapter(name string) (adap DB_Adapter, err error) {
return adapter, nil return adapter, nil
} }
} }
return adap, No_Adapter return adap, ErrNoAdapter
}
type QueryPlugin interface {
Hook(name string, args ...interface{}) error
Write() error
}
type MySQLUpsertCallback struct {
stmt *sql.Stmt
}
func (double *MySQLUpsertCallback) Exec(args ...interface{}) (res sql.Result, err error) {
if len(args) < 2 {
return res, errors.New("Need two or more arguments")
}
args = args[:len(args)-1]
return double.stmt.Exec(append(args, args...)...)
}
func PrepareMySQLUpsertCallback(db *sql.DB, query string) (*MySQLUpsertCallback, error) {
stmt, err := db.Prepare(query)
return &MySQLUpsertCallback{stmt}, err
} }

View File

@ -8,8 +8,10 @@
package qgen package qgen
//import "fmt" //import "fmt"
import "strings" import (
import "os" "os"
"strings"
)
func processColumns(colstr string) (columns []DB_Column) { func processColumns(colstr string) (columns []DB_Column) {
if colstr == "" { if colstr == "" {
@ -46,6 +48,7 @@ func processColumns(colstr string) (columns []DB_Column) {
return columns return columns
} }
// TODO: Allow order by statements without a direction
func processOrderby(orderstr string) (order []DB_Order) { func processOrderby(orderstr string) (order []DB_Order) {
if orderstr == "" { if orderstr == "" {
return order return order

View File

@ -1,83 +1,116 @@
/* WIP Under Construction */ /* WIP Under Construction */
package main package main
import "log" import (
import "./lib" "fmt"
"log"
"os"
"runtime/debug"
"./lib"
)
// TODO: Make sure all the errors in this file propagate upwards properly
func main() { func main() {
// Capture panics instead of closing the window at a superhuman speed before the user can read the message on Windows
defer func() {
r := recover()
if r != nil {
fmt.Println(r)
debug.PrintStack()
return
}
}()
log.Println("Running the query generator") log.Println("Running the query generator")
for _, adapter := range qgen.DB_Registry { for _, adapter := range qgen.DB_Registry {
log.Println("Building the queries for the " + adapter.GetName() + " adapter") log.Println("Building the queries for the " + adapter.GetName() + " adapter")
qgen.Install.SetAdapterInstance(adapter) qgen.Install.SetAdapterInstance(adapter)
write_statements(adapter) qgen.Install.RegisterPlugin(NewPrimaryKeySpitter()) // TODO: Do we really need to fill the spitter for every adapter?
qgen.Install.Write()
adapter.Write() err := writeStatements(adapter)
if err != nil {
log.Print(err)
}
err = qgen.Install.Write()
if err != nil {
log.Print(err)
}
err = adapter.Write()
if err != nil {
log.Print(err)
}
} }
} }
// nolint // nolint
func write_statements(adapter qgen.DB_Adapter) error { func writeStatements(adapter qgen.DB_Adapter) error {
err := create_tables(adapter) err := createTables(adapter)
if err != nil { if err != nil {
return err return err
} }
err = seed_tables(adapter) err = seedTables(adapter)
if err != nil { if err != nil {
return err return err
} }
err = write_selects(adapter) err = writeSelects(adapter)
if err != nil { if err != nil {
return err return err
} }
err = write_left_joins(adapter) err = writeLeftJoins(adapter)
if err != nil { if err != nil {
return err return err
} }
err = write_inner_joins(adapter) err = writeInnerJoins(adapter)
if err != nil { if err != nil {
return err return err
} }
err = write_inserts(adapter) err = writeInserts(adapter)
if err != nil { if err != nil {
return err return err
} }
err = write_replaces(adapter) err = writeReplaces(adapter)
if err != nil { if err != nil {
return err return err
} }
err = write_updates(adapter) err = writeUpserts(adapter)
if err != nil { if err != nil {
return err return err
} }
err = write_deletes(adapter) err = writeUpdates(adapter)
if err != nil { if err != nil {
return err return err
} }
err = write_simple_counts(adapter) err = writeDeletes(adapter)
if err != nil { if err != nil {
return err return err
} }
err = write_insert_selects(adapter) err = writeSimpleCounts(adapter)
if err != nil { if err != nil {
return err return err
} }
err = write_insert_left_joins(adapter) err = writeInsertSelects(adapter)
if err != nil { if err != nil {
return err return err
} }
err = write_insert_inner_joins(adapter) err = writeInsertLeftJoins(adapter)
if err != nil {
return err
}
err = writeInsertInnerJoins(adapter)
if err != nil { if err != nil {
return err return err
} }
@ -85,368 +118,7 @@ func write_statements(adapter qgen.DB_Adapter) error {
return nil return nil
} }
// nolint func seedTables(adapter qgen.DB_Adapter) error {
func create_tables(adapter qgen.DB_Adapter) error {
qgen.Install.CreateTable("users", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"uid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"name", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"password", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"salt", "varchar", 80, false, false, "''"},
qgen.DB_Table_Column{"group", "int", 0, false, false, ""},
qgen.DB_Table_Column{"active", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"is_super_admin", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"createdAt", "createdAt", 0, false, false, ""},
qgen.DB_Table_Column{"lastActiveAt", "datetime", 0, false, false, ""},
qgen.DB_Table_Column{"session", "varchar", 200, false, false, "''"},
qgen.DB_Table_Column{"last_ip", "varchar", 200, false, false, "0.0.0.0.0"},
qgen.DB_Table_Column{"email", "varchar", 200, false, false, "''"},
qgen.DB_Table_Column{"avatar", "varchar", 100, false, false, "''"},
qgen.DB_Table_Column{"message", "text", 0, false, false, "''"},
qgen.DB_Table_Column{"url_prefix", "varchar", 20, false, false, "''"},
qgen.DB_Table_Column{"url_name", "varchar", 100, false, false, "''"},
qgen.DB_Table_Column{"level", "smallint", 0, false, false, "0"},
qgen.DB_Table_Column{"score", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"posts", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"bigposts", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"megaposts", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"topics", "int", 0, false, false, "0"},
//qgen.DB_Table_Column{"penalty_count","int",0,false,false,"0"},
qgen.DB_Table_Column{"temp_group", "int", 0, false, false, "0"}, // For temporary groups, set this to zero when a temporary group isn't in effect
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"uid", "primary"},
qgen.DB_Table_Key{"name", "unique"},
},
)
qgen.Install.CreateTable("users_groups", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"gid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"name", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"permissions", "text", 0, false, false, ""},
qgen.DB_Table_Column{"plugin_perms", "text", 0, false, false, ""},
qgen.DB_Table_Column{"is_mod", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"is_admin", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"is_banned", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"tag", "varchar", 50, false, false, "''"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"gid", "primary"},
},
)
// What should we do about global penalties? Put them on the users table for speed? Or keep them here?
// Should we add IP Penalties? No, that's a stupid idea, just implement IP Bans properly. What about shadowbans?
// TODO: Perm overrides
// TODO: Add a mod-queue and other basic auto-mod features. This is needed for awaiting activation and the mod_queue penalty flag
// TODO: Add a penalty type where a user is stopped from creating plugin_socialgroups social groups
// TODO: Shadow bans. We will probably have a CanShadowBan permission for this, as we *really* don't want people using this lightly.
/*qgen.Install.CreateTable("users_penalties","","",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"uid","int",0,false,false,""},
qgen.DB_Table_Column{"element_id","int",0,false,false,""},
qgen.DB_Table_Column{"element_type","varchar",50,false,false,""}, //forum, profile?, and social_group. Leave blank for global.
qgen.DB_Table_Column{"overrides","text",0,false,false,"{}"},
qgen.DB_Table_Column{"mod_queue","boolean",0,false,false,"0"},
qgen.DB_Table_Column{"shadow_ban","boolean",0,false,false,"0"},
qgen.DB_Table_Column{"no_avatar","boolean",0,false,false,"0"}, // Coming Soon. Should this be a perm override instead?
// Do we *really* need rate-limit penalty types? Are we going to be allowing bots or something?
//qgen.DB_Table_Column{"posts_per_hour","int",0,false,false,"0"},
//qgen.DB_Table_Column{"topics_per_hour","int",0,false,false,"0"},
//qgen.DB_Table_Column{"posts_count","int",0,false,false,"0"},
//qgen.DB_Table_Column{"topic_count","int",0,false,false,"0"},
//qgen.DB_Table_Column{"last_hour","int",0,false,false,"0"}, // UNIX Time, as we don't need to do anything too fancy here. When an hour has elapsed since that time, reset the hourly penalty counters.
qgen.DB_Table_Column{"issued_by","int",0,false,false,""},
qgen.DB_Table_Column{"issued_at","createdAt",0,false,false,""},
qgen.DB_Table_Column{"expires_at","datetime",0,false,false,""},
},
[]qgen.DB_Table_Key{},
)*/
qgen.Install.CreateTable("users_groups_scheduler", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"uid", "int", 0, false, false, ""},
qgen.DB_Table_Column{"set_group", "int", 0, false, false, ""},
qgen.DB_Table_Column{"issued_by", "int", 0, false, false, ""},
qgen.DB_Table_Column{"issued_at", "createdAt", 0, false, false, ""},
qgen.DB_Table_Column{"revert_at", "datetime", 0, false, false, ""},
qgen.DB_Table_Column{"temporary", "boolean", 0, false, false, ""}, // special case for permanent bans to do the necessary bookkeeping, might be removed in the future
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"uid", "primary"},
},
)
qgen.Install.CreateTable("emails", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"email", "varchar", 200, false, false, ""},
qgen.DB_Table_Column{"uid", "int", 0, false, false, ""},
qgen.DB_Table_Column{"validated", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"token", "varchar", 200, false, false, "''"},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("forums", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"fid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"name", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"desc", "varchar", 200, false, false, ""},
qgen.DB_Table_Column{"active", "boolean", 0, false, false, "1"},
qgen.DB_Table_Column{"topicCount", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"preset", "varchar", 100, false, false, "''"},
qgen.DB_Table_Column{"parentID", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"parentType", "varchar", 50, false, false, "''"},
qgen.DB_Table_Column{"lastTopicID", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"lastReplyerID", "int", 0, false, false, "0"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"fid", "primary"},
},
)
qgen.Install.CreateTable("forums_permissions", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"fid", "int", 0, false, false, ""},
qgen.DB_Table_Column{"gid", "int", 0, false, false, ""},
qgen.DB_Table_Column{"preset", "varchar", 100, false, false, "''"},
qgen.DB_Table_Column{"permissions", "text", 0, false, false, ""},
},
[]qgen.DB_Table_Key{
// TODO: Test to see that the compound primary key works
qgen.DB_Table_Key{"fid,gid", "primary"},
},
)
qgen.Install.CreateTable("topics", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"tid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"title", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"parsed_content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"createdAt", "createdAt", 0, false, false, ""},
qgen.DB_Table_Column{"lastReplyAt", "datetime", 0, false, false, ""},
qgen.DB_Table_Column{"lastReplyBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"createdBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"is_closed", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"sticky", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"parentID", "int", 0, false, false, "2"},
qgen.DB_Table_Column{"ipaddress", "varchar", 200, false, false, "0.0.0.0.0"},
qgen.DB_Table_Column{"postCount", "int", 0, false, false, "1"},
qgen.DB_Table_Column{"likeCount", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"words", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"css_class", "varchar", 100, false, false, "''"},
qgen.DB_Table_Column{"data", "varchar", 200, false, false, "''"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"tid", "primary"},
},
)
qgen.Install.CreateTable("replies", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"rid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"tid", "int", 0, false, false, ""},
qgen.DB_Table_Column{"content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"parsed_content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"createdAt", "createdAt", 0, false, false, ""},
qgen.DB_Table_Column{"createdBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"lastEdit", "int", 0, false, false, ""},
qgen.DB_Table_Column{"lastEditBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"lastUpdated", "datetime", 0, false, false, ""},
qgen.DB_Table_Column{"ipaddress", "varchar", 200, false, false, "0.0.0.0.0"},
qgen.DB_Table_Column{"likeCount", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"words", "int", 0, false, false, "1"}, // ? - replies has a default of 1 and topics has 0? why?
qgen.DB_Table_Column{"actionType", "varchar", 20, false, false, "''"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"rid", "primary"},
},
)
qgen.Install.CreateTable("attachments", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"attachID", "int", 0, false, true, ""},
qgen.DB_Table_Column{"sectionID", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"sectionTable", "varchar", 200, false, false, "forums"},
qgen.DB_Table_Column{"originID", "int", 0, false, false, ""},
qgen.DB_Table_Column{"originTable", "varchar", 200, false, false, "replies"},
qgen.DB_Table_Column{"uploadedBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"path", "varchar", 200, false, false, ""},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"attachID", "primary"},
},
)
qgen.Install.CreateTable("revisions", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"index", "int", 0, false, false, ""}, // TODO: Replace this with a proper revision ID x.x
qgen.DB_Table_Column{"content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"contentID", "int", 0, false, false, ""},
qgen.DB_Table_Column{"contentType", "varchar", 100, false, false, "replies"},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("users_replies", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"rid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"uid", "int", 0, false, false, ""},
qgen.DB_Table_Column{"content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"parsed_content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"createdAt", "createdAt", 0, false, false, ""},
qgen.DB_Table_Column{"createdBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"lastEdit", "int", 0, false, false, ""},
qgen.DB_Table_Column{"lastEditBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"ipaddress", "varchar", 200, false, false, "0.0.0.0.0"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"rid", "primary"},
},
)
qgen.Install.CreateTable("likes", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"weight", "tinyint", 0, false, false, "1"},
qgen.DB_Table_Column{"targetItem", "int", 0, false, false, ""},
qgen.DB_Table_Column{"targetType", "varchar", 50, false, false, "replies"},
qgen.DB_Table_Column{"sentBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"recalc", "tinyint", 0, false, false, "0"},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("activity_stream_matches", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"watcher", "int", 0, false, false, ""},
qgen.DB_Table_Column{"asid", "int", 0, false, false, ""},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("activity_stream", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"asid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"actor", "int", 0, false, false, ""}, /* the one doing the act */
qgen.DB_Table_Column{"targetUser", "int", 0, false, false, ""}, /* the user who created the item the actor is acting on, some items like forums may lack a targetUser field */
qgen.DB_Table_Column{"event", "varchar", 50, false, false, ""}, /* mention, like, reply (as in the act of replying to an item, not the reply item type, you can "reply" to a forum by making a topic in it), friend_invite */
qgen.DB_Table_Column{"elementType", "varchar", 50, false, false, ""}, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
qgen.DB_Table_Column{"elementID", "int", 0, false, false, ""}, /* the ID of the element being acted upon */
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"asid", "primary"},
},
)
qgen.Install.CreateTable("activity_subscriptions", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"user", "int", 0, false, false, ""},
qgen.DB_Table_Column{"targetID", "int", 0, false, false, ""}, /* the ID of the element being acted upon */
qgen.DB_Table_Column{"targetType", "varchar", 50, false, false, ""}, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
qgen.DB_Table_Column{"level", "int", 0, false, false, "0"}, /* 0: Mentions (aka the global default for any post), 1: Replies To You, 2: All Replies*/
},
[]qgen.DB_Table_Key{},
)
/* Due to MySQL's design, we have to drop the unique keys for table settings, plugins, and themes down from 200 to 180 or it will error */
qgen.Install.CreateTable("settings", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"name", "varchar", 180, false, false, ""},
qgen.DB_Table_Column{"content", "varchar", 250, false, false, ""},
qgen.DB_Table_Column{"type", "varchar", 50, false, false, ""},
qgen.DB_Table_Column{"constraints", "varchar", 200, false, false, "''"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"name", "unique"},
},
)
qgen.Install.CreateTable("word_filters", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"wfid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"find", "varchar", 200, false, false, ""},
qgen.DB_Table_Column{"replacement", "varchar", 200, false, false, ""},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"wfid", "primary"},
},
)
qgen.Install.CreateTable("plugins", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"uname", "varchar", 180, false, false, ""},
qgen.DB_Table_Column{"active", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"installed", "boolean", 0, false, false, "0"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"uname", "unique"},
},
)
qgen.Install.CreateTable("themes", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"uname", "varchar", 180, false, false, ""},
qgen.DB_Table_Column{"default", "boolean", 0, false, false, "0"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"uname", "unique"},
},
)
qgen.Install.CreateTable("widgets", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"position", "int", 0, false, false, ""},
qgen.DB_Table_Column{"side", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"type", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"active", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"location", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"data", "text", 0, false, false, "''"},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("moderation_logs", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"action", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"elementID", "int", 0, false, false, ""},
qgen.DB_Table_Column{"elementType", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"ipaddress", "varchar", 200, false, false, ""},
qgen.DB_Table_Column{"actorID", "int", 0, false, false, ""},
qgen.DB_Table_Column{"doneAt", "datetime", 0, false, false, ""},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("administration_logs", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"action", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"elementID", "int", 0, false, false, ""},
qgen.DB_Table_Column{"elementType", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"ipaddress", "varchar", 200, false, false, ""},
qgen.DB_Table_Column{"actorID", "int", 0, false, false, ""},
qgen.DB_Table_Column{"doneAt", "datetime", 0, false, false, ""},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("sync", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"last_update", "datetime", 0, false, false, ""},
},
[]qgen.DB_Table_Key{},
)
return nil
}
// nolint
func seed_tables(adapter qgen.DB_Adapter) error {
qgen.Install.SimpleInsert("sync", "last_update", "UTC_TIMESTAMP()") qgen.Install.SimpleInsert("sync", "last_update", "UTC_TIMESTAMP()")
qgen.Install.SimpleInsert("settings", "name, content, type", "'url_tags','1','bool'") qgen.Install.SimpleInsert("settings", "name, content, type", "'url_tags','1','bool'")
@ -547,8 +219,7 @@ func seed_tables(adapter qgen.DB_Adapter) error {
return nil return nil
} }
// nolint func writeSelects(adapter qgen.DB_Adapter) error {
func write_selects(adapter qgen.DB_Adapter) error {
// url_prefix and url_name will be removed from this query in a later commit // url_prefix and url_name will be removed from this query in a later commit
adapter.SimpleSelect("getUser", "users", "name, group, is_super_admin, avatar, message, url_prefix, url_name, level", "uid = ?", "", "") adapter.SimpleSelect("getUser", "users", "name, group, is_super_admin, avatar, message, url_prefix, url_name, level", "uid = ?", "", "")
@ -586,7 +257,7 @@ func write_selects(adapter qgen.DB_Adapter) error {
adapter.SimpleSelect("getUsers", "users", "uid, name, group, active, is_super_admin, avatar", "", "", "") adapter.SimpleSelect("getUsers", "users", "uid, name, group, active, is_super_admin, avatar", "", "", "")
adapter.SimpleSelect("getUsersOffset", "users", "uid, name, group, active, is_super_admin, avatar", "", "", "?,?") adapter.SimpleSelect("getUsersOffset", "users", "uid, name, group, active, is_super_admin, avatar", "", "uid ASC", "?,?")
adapter.SimpleSelect("getWordFilters", "word_filters", "wfid, find, replacement", "", "", "") adapter.SimpleSelect("getWordFilters", "word_filters", "wfid, find, replacement", "", "", "")
@ -594,7 +265,7 @@ func write_selects(adapter qgen.DB_Adapter) error {
adapter.SimpleSelect("getModlogs", "moderation_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "", "", "") adapter.SimpleSelect("getModlogs", "moderation_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "", "", "")
adapter.SimpleSelect("getModlogsOffset", "moderation_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "", "", "?,?") adapter.SimpleSelect("getModlogsOffset", "moderation_logs", "action, elementID, elementType, ipaddress, actorID, doneAt", "", "doneAt DESC", "?,?")
adapter.SimpleSelect("getReplyTID", "replies", "tid", "rid = ?", "", "") adapter.SimpleSelect("getReplyTID", "replies", "tid", "rid = ?", "", "")
@ -629,9 +300,8 @@ func write_selects(adapter qgen.DB_Adapter) error {
return nil return nil
} }
// nolint func writeLeftJoins(adapter qgen.DB_Adapter) error {
func write_left_joins(adapter qgen.DB_Adapter) error { adapter.SimpleLeftJoin("getTopicRepliesOffset", "replies", "users", "replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress, replies.likeCount, replies.actionType", "replies.createdBy = users.uid", "replies.tid = ?", "replies.rid ASC", "?,?")
adapter.SimpleLeftJoin("getTopicRepliesOffset", "replies", "users", "replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress, replies.likeCount, replies.actionType", "replies.createdBy = users.uid", "replies.tid = ?", "", "?,?")
adapter.SimpleLeftJoin("getTopicList", "topics", "users", "topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.parentID, users.name, users.avatar", "topics.createdBy = users.uid", "", "topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC", "") adapter.SimpleLeftJoin("getTopicList", "topics", "users", "topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.parentID, users.name, users.avatar", "topics.createdBy = users.uid", "", "topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC", "")
@ -648,22 +318,23 @@ func write_left_joins(adapter qgen.DB_Adapter) error {
return nil return nil
} }
// nolint func writeInnerJoins(adapter qgen.DB_Adapter) (err error) {
func write_inner_joins(adapter qgen.DB_Adapter) error { _, err = adapter.SimpleInnerJoin("getWatchers", "activity_stream", "activity_subscriptions", "activity_subscriptions.user", "activity_subscriptions.targetType = activity_stream.elementType AND activity_subscriptions.targetID = activity_stream.elementID AND activity_subscriptions.user != activity_stream.actor", "asid = ?", "", "")
adapter.SimpleInnerJoin("getWatchers", "activity_stream", "activity_subscriptions", "activity_subscriptions.user", "activity_subscriptions.targetType = activity_stream.elementType AND activity_subscriptions.targetID = activity_stream.elementID AND activity_subscriptions.user != activity_stream.actor", "asid = ?", "", "") if err != nil {
return err
}
return nil return nil
} }
// nolint func writeInserts(adapter qgen.DB_Adapter) error {
func write_inserts(adapter qgen.DB_Adapter) error {
adapter.SimpleInsert("createTopic", "topics", "parentID, title, content, parsed_content, createdAt, lastReplyAt, lastReplyBy, ipaddress, words, createdBy", "?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?,?") adapter.SimpleInsert("createTopic", "topics", "parentID, title, content, parsed_content, createdAt, lastReplyAt, lastReplyBy, ipaddress, words, createdBy", "?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?,?")
adapter.SimpleInsert("createReport", "topics", "title, content, parsed_content, createdAt, lastReplyAt, createdBy, data, parentID, css_class", "?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,1,'report'") adapter.SimpleInsert("createReport", "topics", "title, content, parsed_content, createdAt, lastReplyAt, createdBy, lastReplyBy, data, parentID, css_class", "?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?,1,'report'")
adapter.SimpleInsert("createReply", "replies", "tid, content, parsed_content, createdAt, ipaddress, words, createdBy", "?,?,?,UTC_TIMESTAMP(),?,?,?") adapter.SimpleInsert("createReply", "replies", "tid, content, parsed_content, createdAt, lastUpdated, ipaddress, words, createdBy", "?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?")
adapter.SimpleInsert("createActionReply", "replies", "tid, actionType, ipaddress, createdBy", "?,?,?,?") adapter.SimpleInsert("createActionReply", "replies", "tid, actionType, ipaddress, createdBy, createdAt, lastUpdated, content, parsed_content", "?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'',''")
adapter.SimpleInsert("createLike", "likes", "weight, targetItem, targetType, sentBy", "?,?,?,?") adapter.SimpleInsert("createLike", "likes", "weight, targetItem, targetType, sentBy", "?,?,?,?")
@ -698,17 +369,25 @@ func write_inserts(adapter qgen.DB_Adapter) error {
return nil return nil
} }
// nolint func writeReplaces(adapter qgen.DB_Adapter) (err error) {
func write_replaces(adapter qgen.DB_Adapter) error { return nil
adapter.SimpleReplace("addForumPermsToGroup", "forums_permissions", "gid, fid, preset, permissions", "?,?,?,?") }
adapter.SimpleReplace("replaceScheduleGroup", "users_groups_scheduler", "uid, set_group, issued_by, issued_at, revert_at, temporary", "?,?,?,UTC_TIMESTAMP(),?,?") func writeUpserts(adapter qgen.DB_Adapter) (err error) {
_, err = adapter.SimpleUpsert("addForumPermsToGroup", "forums_permissions", "gid, fid, preset, permissions", "?,?,?,?", "gid = ? AND fid = ?")
if err != nil {
return err
}
_, err = adapter.SimpleUpsert("replaceScheduleGroup", "users_groups_scheduler", "uid, set_group, issued_by, issued_at, revert_at, temporary", "?,?,?,UTC_TIMESTAMP(),?,?", "uid = ?")
if err != nil {
return err
}
return nil return nil
} }
// nolint func writeUpdates(adapter qgen.DB_Adapter) error {
func write_updates(adapter qgen.DB_Adapter) error {
adapter.SimpleUpdate("addRepliesToTopic", "topics", "postCount = postCount + ?, lastReplyBy = ?, lastReplyAt = UTC_TIMESTAMP()", "tid = ?") adapter.SimpleUpdate("addRepliesToTopic", "topics", "postCount = postCount + ?, lastReplyBy = ?, lastReplyAt = UTC_TIMESTAMP()", "tid = ?")
adapter.SimpleUpdate("removeRepliesFromTopic", "topics", "postCount = postCount - ?", "tid = ?") adapter.SimpleUpdate("removeRepliesFromTopic", "topics", "postCount = postCount - ?", "tid = ?")
@ -794,8 +473,9 @@ func write_updates(adapter qgen.DB_Adapter) error {
return nil return nil
} }
// nolint func writeDeletes(adapter qgen.DB_Adapter) error {
func write_deletes(adapter qgen.DB_Adapter) error { adapter.SimpleDelete("deleteUser", "users", "uid = ?")
adapter.SimpleDelete("deleteReply", "replies", "rid = ?") adapter.SimpleDelete("deleteReply", "replies", "rid = ?")
adapter.SimpleDelete("deleteProfileReply", "users_replies", "rid = ?") adapter.SimpleDelete("deleteProfileReply", "users_replies", "rid = ?")
@ -810,8 +490,7 @@ func write_deletes(adapter qgen.DB_Adapter) error {
return nil return nil
} }
// nolint func writeSimpleCounts(adapter qgen.DB_Adapter) error {
func write_simple_counts(adapter qgen.DB_Adapter) error {
adapter.SimpleCount("reportExists", "topics", "data = ? AND data != '' AND parentID = 1", "") adapter.SimpleCount("reportExists", "topics", "data = ? AND data != '' AND parentID = 1", "")
adapter.SimpleCount("groupCount", "users_groups", "", "") adapter.SimpleCount("groupCount", "users_groups", "", "")
@ -821,8 +500,7 @@ func write_simple_counts(adapter qgen.DB_Adapter) error {
return nil return nil
} }
// nolint func writeInsertSelects(adapter qgen.DB_Adapter) error {
func write_insert_selects(adapter qgen.DB_Adapter) error {
adapter.SimpleInsertSelect("addForumPermsToForumAdmins", adapter.SimpleInsertSelect("addForumPermsToForumAdmins",
qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""}, qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""},
qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 1", "", ""}, qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 1", "", ""},
@ -842,12 +520,11 @@ func write_insert_selects(adapter qgen.DB_Adapter) error {
} }
// nolint // nolint
func write_insert_left_joins(adapter qgen.DB_Adapter) error { func writeInsertLeftJoins(adapter qgen.DB_Adapter) error {
return nil return nil
} }
// nolint func writeInsertInnerJoins(adapter qgen.DB_Adapter) error {
func write_insert_inner_joins(adapter qgen.DB_Adapter) error {
adapter.SimpleInsertInnerJoin("notifyWatchers", adapter.SimpleInsertInnerJoin("notifyWatchers",
qgen.DB_Insert{"activity_stream_matches", "watcher, asid", ""}, qgen.DB_Insert{"activity_stream_matches", "watcher, asid", ""},
qgen.DB_Join{"activity_stream", "activity_subscriptions", "activity_subscriptions.user, activity_stream.asid", "activity_subscriptions.targetType = activity_stream.elementType AND activity_subscriptions.targetID = activity_stream.elementID AND activity_subscriptions.user != activity_stream.actor", "asid = ?", "", ""}, qgen.DB_Join{"activity_stream", "activity_subscriptions", "activity_subscriptions.user, activity_stream.asid", "activity_subscriptions.targetType = activity_stream.elementType AND activity_subscriptions.targetID = activity_stream.elementID AND activity_subscriptions.user != activity_stream.actor", "asid = ?", "", ""},
@ -855,3 +532,19 @@ func write_insert_inner_joins(adapter qgen.DB_Adapter) error {
return nil return nil
} }
func writeFile(name string, content string) (err error) {
f, err := os.Create(name)
if err != nil {
return err
}
_, err = f.WriteString(content)
if err != nil {
return err
}
err = f.Sync()
if err != nil {
return err
}
return f.Close()
}

44
query_gen/spitter.go Normal file
View File

@ -0,0 +1,44 @@
package main
import "strings"
import "./lib"
type PrimaryKeySpitter struct {
keys map[string]string
}
func NewPrimaryKeySpitter() *PrimaryKeySpitter {
return &PrimaryKeySpitter{make(map[string]string)}
}
func (spit *PrimaryKeySpitter) Hook(name string, args ...interface{}) error {
if name == "CreateTableStart" {
var found string
for _, key := range args[4].([]qgen.DB_Table_Key) {
if key.Type == "primary" {
expl := strings.Split(key.Columns, ",")
if len(expl) > 1 {
continue
}
found = key.Columns
}
if found != "" {
table := args[0].(string)
spit.keys[table] = found
}
}
}
return nil
}
func (spit *PrimaryKeySpitter) Write() error {
out := `// Generated by Gosora's Query Generator. DO NOT EDIT.
package main
var dbTablePrimaryKeys = map[string]string{
`
for table, key := range spit.keys {
out += "\t\"" + table + "\":\"" + key + "\",\n"
}
return writeFile("./gen_tables.go", out+"}\n")
}

363
query_gen/tables.go Normal file
View File

@ -0,0 +1,363 @@
/* WIP Under Construction */
package main
import "./lib"
func createTables(adapter qgen.DB_Adapter) error {
qgen.Install.CreateTable("users", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"uid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"name", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"password", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"salt", "varchar", 80, false, false, "''"},
qgen.DB_Table_Column{"group", "int", 0, false, false, ""},
qgen.DB_Table_Column{"active", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"is_super_admin", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"createdAt", "createdAt", 0, false, false, ""},
qgen.DB_Table_Column{"lastActiveAt", "datetime", 0, false, false, ""},
qgen.DB_Table_Column{"session", "varchar", 200, false, false, "''"},
qgen.DB_Table_Column{"last_ip", "varchar", 200, false, false, "0.0.0.0.0"},
qgen.DB_Table_Column{"email", "varchar", 200, false, false, "''"},
qgen.DB_Table_Column{"avatar", "varchar", 100, false, false, "''"},
qgen.DB_Table_Column{"message", "text", 0, false, false, "''"},
qgen.DB_Table_Column{"url_prefix", "varchar", 20, false, false, "''"},
qgen.DB_Table_Column{"url_name", "varchar", 100, false, false, "''"},
qgen.DB_Table_Column{"level", "smallint", 0, false, false, "0"},
qgen.DB_Table_Column{"score", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"posts", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"bigposts", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"megaposts", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"topics", "int", 0, false, false, "0"},
//qgen.DB_Table_Column{"penalty_count","int",0,false,false,"0"},
qgen.DB_Table_Column{"temp_group", "int", 0, false, false, "0"}, // For temporary groups, set this to zero when a temporary group isn't in effect
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"uid", "primary"},
qgen.DB_Table_Key{"name", "unique"},
},
)
qgen.Install.CreateTable("users_groups", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"gid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"name", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"permissions", "text", 0, false, false, ""},
qgen.DB_Table_Column{"plugin_perms", "text", 0, false, false, ""},
qgen.DB_Table_Column{"is_mod", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"is_admin", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"is_banned", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"tag", "varchar", 50, false, false, "''"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"gid", "primary"},
},
)
// What should we do about global penalties? Put them on the users table for speed? Or keep them here?
// Should we add IP Penalties? No, that's a stupid idea, just implement IP Bans properly. What about shadowbans?
// TODO: Perm overrides
// TODO: Add a mod-queue and other basic auto-mod features. This is needed for awaiting activation and the mod_queue penalty flag
// TODO: Add a penalty type where a user is stopped from creating plugin_socialgroups social groups
// TODO: Shadow bans. We will probably have a CanShadowBan permission for this, as we *really* don't want people using this lightly.
/*qgen.Install.CreateTable("users_penalties","","",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"uid","int",0,false,false,""},
qgen.DB_Table_Column{"element_id","int",0,false,false,""},
qgen.DB_Table_Column{"element_type","varchar",50,false,false,""}, //forum, profile?, and social_group. Leave blank for global.
qgen.DB_Table_Column{"overrides","text",0,false,false,"{}"},
qgen.DB_Table_Column{"mod_queue","boolean",0,false,false,"0"},
qgen.DB_Table_Column{"shadow_ban","boolean",0,false,false,"0"},
qgen.DB_Table_Column{"no_avatar","boolean",0,false,false,"0"}, // Coming Soon. Should this be a perm override instead?
// Do we *really* need rate-limit penalty types? Are we going to be allowing bots or something?
//qgen.DB_Table_Column{"posts_per_hour","int",0,false,false,"0"},
//qgen.DB_Table_Column{"topics_per_hour","int",0,false,false,"0"},
//qgen.DB_Table_Column{"posts_count","int",0,false,false,"0"},
//qgen.DB_Table_Column{"topic_count","int",0,false,false,"0"},
//qgen.DB_Table_Column{"last_hour","int",0,false,false,"0"}, // UNIX Time, as we don't need to do anything too fancy here. When an hour has elapsed since that time, reset the hourly penalty counters.
qgen.DB_Table_Column{"issued_by","int",0,false,false,""},
qgen.DB_Table_Column{"issued_at","createdAt",0,false,false,""},
qgen.DB_Table_Column{"expires_at","datetime",0,false,false,""},
},
[]qgen.DB_Table_Key{},
)*/
qgen.Install.CreateTable("users_groups_scheduler", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"uid", "int", 0, false, false, ""},
qgen.DB_Table_Column{"set_group", "int", 0, false, false, ""},
qgen.DB_Table_Column{"issued_by", "int", 0, false, false, ""},
qgen.DB_Table_Column{"issued_at", "createdAt", 0, false, false, ""},
qgen.DB_Table_Column{"revert_at", "datetime", 0, false, false, ""},
qgen.DB_Table_Column{"temporary", "boolean", 0, false, false, ""}, // special case for permanent bans to do the necessary bookkeeping, might be removed in the future
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"uid", "primary"},
},
)
qgen.Install.CreateTable("emails", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"email", "varchar", 200, false, false, ""},
qgen.DB_Table_Column{"uid", "int", 0, false, false, ""},
qgen.DB_Table_Column{"validated", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"token", "varchar", 200, false, false, "''"},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("forums", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"fid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"name", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"desc", "varchar", 200, false, false, ""},
qgen.DB_Table_Column{"active", "boolean", 0, false, false, "1"},
qgen.DB_Table_Column{"topicCount", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"preset", "varchar", 100, false, false, "''"},
qgen.DB_Table_Column{"parentID", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"parentType", "varchar", 50, false, false, "''"},
qgen.DB_Table_Column{"lastTopicID", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"lastReplyerID", "int", 0, false, false, "0"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"fid", "primary"},
},
)
qgen.Install.CreateTable("forums_permissions", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"fid", "int", 0, false, false, ""},
qgen.DB_Table_Column{"gid", "int", 0, false, false, ""},
qgen.DB_Table_Column{"preset", "varchar", 100, false, false, "''"},
qgen.DB_Table_Column{"permissions", "text", 0, false, false, ""},
},
[]qgen.DB_Table_Key{
// TODO: Test to see that the compound primary key works
qgen.DB_Table_Key{"fid,gid", "primary"},
},
)
qgen.Install.CreateTable("topics", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"tid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"title", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"parsed_content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"createdAt", "createdAt", 0, false, false, ""},
qgen.DB_Table_Column{"lastReplyAt", "datetime", 0, false, false, ""},
qgen.DB_Table_Column{"lastReplyBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"createdBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"is_closed", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"sticky", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"parentID", "int", 0, false, false, "2"},
qgen.DB_Table_Column{"ipaddress", "varchar", 200, false, false, "0.0.0.0.0"},
qgen.DB_Table_Column{"postCount", "int", 0, false, false, "1"},
qgen.DB_Table_Column{"likeCount", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"words", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"css_class", "varchar", 100, false, false, "''"},
qgen.DB_Table_Column{"data", "varchar", 200, false, false, "''"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"tid", "primary"},
},
)
qgen.Install.CreateTable("replies", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"rid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"tid", "int", 0, false, false, ""},
qgen.DB_Table_Column{"content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"parsed_content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"createdAt", "createdAt", 0, false, false, ""},
qgen.DB_Table_Column{"createdBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"lastEdit", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"lastEditBy", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"lastUpdated", "datetime", 0, false, false, ""},
qgen.DB_Table_Column{"ipaddress", "varchar", 200, false, false, "0.0.0.0.0"},
qgen.DB_Table_Column{"likeCount", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"words", "int", 0, false, false, "1"}, // ? - replies has a default of 1 and topics has 0? why?
qgen.DB_Table_Column{"actionType", "varchar", 20, false, false, "''"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"rid", "primary"},
},
)
qgen.Install.CreateTable("attachments", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"attachID", "int", 0, false, true, ""},
qgen.DB_Table_Column{"sectionID", "int", 0, false, false, "0"},
qgen.DB_Table_Column{"sectionTable", "varchar", 200, false, false, "forums"},
qgen.DB_Table_Column{"originID", "int", 0, false, false, ""},
qgen.DB_Table_Column{"originTable", "varchar", 200, false, false, "replies"},
qgen.DB_Table_Column{"uploadedBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"path", "varchar", 200, false, false, ""},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"attachID", "primary"},
},
)
qgen.Install.CreateTable("revisions", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"index", "int", 0, false, false, ""}, // TODO: Replace this with a proper revision ID x.x
qgen.DB_Table_Column{"content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"contentID", "int", 0, false, false, ""},
qgen.DB_Table_Column{"contentType", "varchar", 100, false, false, "replies"},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("users_replies", "utf8mb4", "utf8mb4_general_ci",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"rid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"uid", "int", 0, false, false, ""},
qgen.DB_Table_Column{"content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"parsed_content", "text", 0, false, false, ""},
qgen.DB_Table_Column{"createdAt", "createdAt", 0, false, false, ""},
qgen.DB_Table_Column{"createdBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"lastEdit", "int", 0, false, false, ""},
qgen.DB_Table_Column{"lastEditBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"ipaddress", "varchar", 200, false, false, "0.0.0.0.0"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"rid", "primary"},
},
)
qgen.Install.CreateTable("likes", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"weight", "tinyint", 0, false, false, "1"},
qgen.DB_Table_Column{"targetItem", "int", 0, false, false, ""},
qgen.DB_Table_Column{"targetType", "varchar", 50, false, false, "replies"},
qgen.DB_Table_Column{"sentBy", "int", 0, false, false, ""},
qgen.DB_Table_Column{"recalc", "tinyint", 0, false, false, "0"},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("activity_stream_matches", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"watcher", "int", 0, false, false, ""},
qgen.DB_Table_Column{"asid", "int", 0, false, false, ""},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("activity_stream", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"asid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"actor", "int", 0, false, false, ""}, /* the one doing the act */
qgen.DB_Table_Column{"targetUser", "int", 0, false, false, ""}, /* the user who created the item the actor is acting on, some items like forums may lack a targetUser field */
qgen.DB_Table_Column{"event", "varchar", 50, false, false, ""}, /* mention, like, reply (as in the act of replying to an item, not the reply item type, you can "reply" to a forum by making a topic in it), friend_invite */
qgen.DB_Table_Column{"elementType", "varchar", 50, false, false, ""}, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
qgen.DB_Table_Column{"elementID", "int", 0, false, false, ""}, /* the ID of the element being acted upon */
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"asid", "primary"},
},
)
qgen.Install.CreateTable("activity_subscriptions", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"user", "int", 0, false, false, ""},
qgen.DB_Table_Column{"targetID", "int", 0, false, false, ""}, /* the ID of the element being acted upon */
qgen.DB_Table_Column{"targetType", "varchar", 50, false, false, ""}, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
qgen.DB_Table_Column{"level", "int", 0, false, false, "0"}, /* 0: Mentions (aka the global default for any post), 1: Replies To You, 2: All Replies*/
},
[]qgen.DB_Table_Key{},
)
/* Due to MySQL's design, we have to drop the unique keys for table settings, plugins, and themes down from 200 to 180 or it will error */
qgen.Install.CreateTable("settings", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"name", "varchar", 180, false, false, ""},
qgen.DB_Table_Column{"content", "varchar", 250, false, false, ""},
qgen.DB_Table_Column{"type", "varchar", 50, false, false, ""},
qgen.DB_Table_Column{"constraints", "varchar", 200, false, false, "''"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"name", "unique"},
},
)
qgen.Install.CreateTable("word_filters", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"wfid", "int", 0, false, true, ""},
qgen.DB_Table_Column{"find", "varchar", 200, false, false, ""},
qgen.DB_Table_Column{"replacement", "varchar", 200, false, false, ""},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"wfid", "primary"},
},
)
qgen.Install.CreateTable("plugins", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"uname", "varchar", 180, false, false, ""},
qgen.DB_Table_Column{"active", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"installed", "boolean", 0, false, false, "0"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"uname", "unique"},
},
)
qgen.Install.CreateTable("themes", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"uname", "varchar", 180, false, false, ""},
qgen.DB_Table_Column{"default", "boolean", 0, false, false, "0"},
},
[]qgen.DB_Table_Key{
qgen.DB_Table_Key{"uname", "unique"},
},
)
qgen.Install.CreateTable("widgets", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"position", "int", 0, false, false, ""},
qgen.DB_Table_Column{"side", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"type", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"active", "boolean", 0, false, false, "0"},
qgen.DB_Table_Column{"location", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"data", "text", 0, false, false, "''"},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("moderation_logs", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"action", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"elementID", "int", 0, false, false, ""},
qgen.DB_Table_Column{"elementType", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"ipaddress", "varchar", 200, false, false, ""},
qgen.DB_Table_Column{"actorID", "int", 0, false, false, ""},
qgen.DB_Table_Column{"doneAt", "datetime", 0, false, false, ""},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("administration_logs", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"action", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"elementID", "int", 0, false, false, ""},
qgen.DB_Table_Column{"elementType", "varchar", 100, false, false, ""},
qgen.DB_Table_Column{"ipaddress", "varchar", 200, false, false, ""},
qgen.DB_Table_Column{"actorID", "int", 0, false, false, ""},
qgen.DB_Table_Column{"doneAt", "datetime", 0, false, false, ""},
},
[]qgen.DB_Table_Key{},
)
qgen.Install.CreateTable("sync", "", "",
[]qgen.DB_Table_Column{
qgen.DB_Table_Column{"last_update", "datetime", 0, false, false, ""},
},
[]qgen.DB_Table_Key{},
)
return nil
}

View File

@ -433,11 +433,7 @@ func routeForums(w http.ResponseWriter, r *http.Request, user User) {
//topic, user := forum.GetLast() //topic, user := forum.GetLast()
//if topic.ID != 0 && user.ID != 0 { //if topic.ID != 0 && user.ID != 0 {
if forum.LastTopic.ID != 0 && forum.LastReplyer.ID != 0 { if forum.LastTopic.ID != 0 && forum.LastReplyer.ID != 0 {
forum.LastTopicTime, err = relativeTimeFromString(forum.LastTopic.LastReplyAt) forum.LastTopicTime = relativeTime(forum.LastTopic.LastReplyAt)
if err != nil {
InternalError(err, w)
return
}
} else { } else {
forum.LastTopicTime = "" forum.LastTopicTime = ""
} }

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [activity_stream];
CREATE TABLE [activity_stream] ( CREATE TABLE [activity_stream] (
[asid] int not null IDENTITY, [asid] int not null IDENTITY,
[actor] int not null, [actor] int not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [activity_stream_matches];
CREATE TABLE [activity_stream_matches] ( CREATE TABLE [activity_stream_matches] (
[watcher] int not null, [watcher] int not null,
[asid] int not null [asid] int not null

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [activity_subscriptions];
CREATE TABLE [activity_subscriptions] ( CREATE TABLE [activity_subscriptions] (
[user] int not null, [user] int not null,
[targetID] int not null, [targetID] int not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [administration_logs];
CREATE TABLE [administration_logs] ( CREATE TABLE [administration_logs] (
[action] nvarchar (100) not null, [action] nvarchar (100) not null,
[elementID] int not null, [elementID] int not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [attachments];
CREATE TABLE [attachments] ( CREATE TABLE [attachments] (
[attachID] int not null IDENTITY, [attachID] int not null IDENTITY,
[sectionID] int DEFAULT 0 not null, [sectionID] int DEFAULT 0 not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [emails];
CREATE TABLE [emails] ( CREATE TABLE [emails] (
[email] nvarchar (200) not null, [email] nvarchar (200) not null,
[uid] int not null, [uid] int not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [forums];
CREATE TABLE [forums] ( CREATE TABLE [forums] (
[fid] int not null IDENTITY, [fid] int not null IDENTITY,
[name] nvarchar (100) not null, [name] nvarchar (100) not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [forums_permissions];
CREATE TABLE [forums_permissions] ( CREATE TABLE [forums_permissions] (
[fid] int not null, [fid] int not null,
[gid] int not null, [gid] int not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [likes];
CREATE TABLE [likes] ( CREATE TABLE [likes] (
[weight] tinyint DEFAULT 1 not null, [weight] tinyint DEFAULT 1 not null,
[targetItem] int not null, [targetItem] int not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [moderation_logs];
CREATE TABLE [moderation_logs] ( CREATE TABLE [moderation_logs] (
[action] nvarchar (100) not null, [action] nvarchar (100) not null,
[elementID] int not null, [elementID] int not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [plugins];
CREATE TABLE [plugins] ( CREATE TABLE [plugins] (
[uname] nvarchar (180) not null, [uname] nvarchar (180) not null,
[active] bit DEFAULT 0 not null, [active] bit DEFAULT 0 not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [replies];
CREATE TABLE [replies] ( CREATE TABLE [replies] (
[rid] int not null IDENTITY, [rid] int not null IDENTITY,
[tid] int not null, [tid] int not null,
@ -6,8 +5,8 @@ CREATE TABLE [replies] (
[parsed_content] nvarchar (MAX) not null, [parsed_content] nvarchar (MAX) not null,
[createdAt] datetime not null, [createdAt] datetime not null,
[createdBy] int not null, [createdBy] int not null,
[lastEdit] int not null, [lastEdit] int DEFAULT 0 not null,
[lastEditBy] int not null, [lastEditBy] int DEFAULT 0 not null,
[lastUpdated] datetime not null, [lastUpdated] datetime not null,
[ipaddress] nvarchar (200) DEFAULT '0.0.0.0.0' not null, [ipaddress] nvarchar (200) DEFAULT '0.0.0.0.0' not null,
[likeCount] int DEFAULT 0 not null, [likeCount] int DEFAULT 0 not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [revisions];
CREATE TABLE [revisions] ( CREATE TABLE [revisions] (
[index] int not null, [index] int not null,
[content] nvarchar (MAX) not null, [content] nvarchar (MAX) not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [settings];
CREATE TABLE [settings] ( CREATE TABLE [settings] (
[name] nvarchar (180) not null, [name] nvarchar (180) not null,
[content] nvarchar (250) not null, [content] nvarchar (250) not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [sync];
CREATE TABLE [sync] ( CREATE TABLE [sync] (
[last_update] datetime not null [last_update] datetime not null
); );

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [themes];
CREATE TABLE [themes] ( CREATE TABLE [themes] (
[uname] nvarchar (180) not null, [uname] nvarchar (180) not null,
[default] bit DEFAULT 0 not null, [default] bit DEFAULT 0 not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [topics];
CREATE TABLE [topics] ( CREATE TABLE [topics] (
[tid] int not null IDENTITY, [tid] int not null IDENTITY,
[title] nvarchar (100) not null, [title] nvarchar (100) not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [users];
CREATE TABLE [users] ( CREATE TABLE [users] (
[uid] int not null IDENTITY, [uid] int not null IDENTITY,
[name] nvarchar (100) not null, [name] nvarchar (100) not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [users_groups];
CREATE TABLE [users_groups] ( CREATE TABLE [users_groups] (
[gid] int not null IDENTITY, [gid] int not null IDENTITY,
[name] nvarchar (100) not null, [name] nvarchar (100) not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [users_groups_scheduler];
CREATE TABLE [users_groups_scheduler] ( CREATE TABLE [users_groups_scheduler] (
[uid] int not null, [uid] int not null,
[set_group] int not null, [set_group] int not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [users_replies];
CREATE TABLE [users_replies] ( CREATE TABLE [users_replies] (
[rid] int not null IDENTITY, [rid] int not null IDENTITY,
[uid] int not null, [uid] int not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [widgets];
CREATE TABLE [widgets] ( CREATE TABLE [widgets] (
[position] int not null, [position] int not null,
[side] nvarchar (100) not null, [side] nvarchar (100) not null,

View File

@ -1,4 +1,3 @@
DROP TABLE IF EXISTS [word_filters];
CREATE TABLE [word_filters] ( CREATE TABLE [word_filters] (
[wfid] int not null IDENTITY, [wfid] int not null IDENTITY,
[find] nvarchar (200) not null, [find] nvarchar (200) not null,

View File

@ -5,8 +5,8 @@ CREATE TABLE `replies` (
`parsed_content` text not null, `parsed_content` text not null,
`createdAt` datetime not null, `createdAt` datetime not null,
`createdBy` int not null, `createdBy` int not null,
`lastEdit` int not null, `lastEdit` int DEFAULT 0 not null,
`lastEditBy` int not null, `lastEditBy` int DEFAULT 0 not null,
`lastUpdated` datetime not null, `lastUpdated` datetime not null,
`ipaddress` varchar(200) DEFAULT '0.0.0.0.0' not null, `ipaddress` varchar(200) DEFAULT '0.0.0.0.0' not null,
`likeCount` int DEFAULT 0 not null, `likeCount` int DEFAULT 0 not null,

View File

@ -5,8 +5,8 @@ CREATE TABLE `replies` (
`parsed_content` text not null, `parsed_content` text not null,
`createdAt` timestamp not null, `createdAt` timestamp not null,
`createdBy` int not null, `createdBy` int not null,
`lastEdit` int not null, `lastEdit` int DEFAULT 0 not null,
`lastEditBy` int not null, `lastEditBy` int DEFAULT 0 not null,
`lastUpdated` timestamp not null, `lastUpdated` timestamp not null,
`ipaddress` varchar (200) DEFAULT '0.0.0.0.0' not null, `ipaddress` varchar (200) DEFAULT '0.0.0.0.0' not null,
`likeCount` int DEFAULT 0 not null, `likeCount` int DEFAULT 0 not null,

View File

@ -6,7 +6,10 @@
*/ */
package main package main
import "time" import (
"log"
"time"
)
var lastSync time.Time var lastSync time.Time
@ -28,12 +31,14 @@ func handleExpiredScheduledGroups() error {
if err != nil { if err != nil {
return err return err
} }
_, err = replaceScheduleGroupStmt.Exec(uid, 0, 0, time.Now(), false) _, err = replaceScheduleGroupStmt.Exec(uid, 0, 0, time.Now(), false, uid)
if err != nil { if err != nil {
log.Print("Unable to replace the scheduled group")
return err return err
} }
_, err = setTempGroupStmt.Exec(0, uid) _, err = setTempGroupStmt.Exec(0, uid)
if err != nil { if err != nil {
log.Print("Unable to reset the tempgroup")
return err return err
} }
if ok { if ok {
@ -54,16 +59,19 @@ func handleServerSync() error {
// TODO: A more granular sync // TODO: A more granular sync
err = fstore.LoadForums() err = fstore.LoadForums()
if err != nil { if err != nil {
log.Print("Unable to reload the forums")
return err return err
} }
// TODO: Resync the groups // TODO: Resync the groups
// TODO: Resync the permissions // TODO: Resync the permissions
err = LoadSettings() err = LoadSettings()
if err != nil { if err != nil {
log.Print("Unable to reload the settings")
return err return err
} }
err = LoadWordFilters() err = LoadWordFilters()
if err != nil { if err != nil {
log.Print("Unable to reload the word filters")
return err return err
} }
} }

View File

@ -110,7 +110,7 @@ func compileTemplates() error {
log.Print("Compiling the templates") log.Print("Compiling the templates")
topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, "Date", "Date", 0, "", "127.0.0.1", 0, 1, "classname", "weird-data", buildProfileURL("fake-user", 62), "Fake User", config.DefaultGroup, "", 0, "", "", "", "", "", 58, false} topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, "Date", time.Now(), "Date", 0, "", "127.0.0.1", 0, 1, "classname", "weird-data", buildProfileURL("fake-user", 62), "Fake User", config.DefaultGroup, "", 0, "", "", "", "", "", 58, false}
var replyList []ReplyUser var replyList []ReplyUser
replyList = append(replyList, ReplyUser{0, 0, "Yo!", "Yo!", 0, "alice", "Alice", config.DefaultGroup, "", 0, 0, "", "", 0, "", "", "", "", 0, "127.0.0.1", false, 1, "", ""}) replyList = append(replyList, ReplyUser{0, 0, "Yo!", "Yo!", 0, "alice", "Alice", config.DefaultGroup, "", 0, 0, "", "", 0, "", "", "", "", 0, "127.0.0.1", false, 1, "", ""})

View File

@ -25,7 +25,8 @@ type Topic struct {
IsClosed bool IsClosed bool
Sticky bool Sticky bool
CreatedAt string CreatedAt string
LastReplyAt string LastReplyAt time.Time
RelativeLastReplyAt string
//LastReplyBy int //LastReplyBy int
ParentID int ParentID int
Status string // Deprecated. Marked for removal. Status string // Deprecated. Marked for removal.
@ -45,7 +46,8 @@ type TopicUser struct {
IsClosed bool IsClosed bool
Sticky bool Sticky bool
CreatedAt string CreatedAt string
LastReplyAt string LastReplyAt time.Time
RelativeLastReplyAt string
//LastReplyBy int //LastReplyBy int
ParentID int ParentID int
Status string // Deprecated. Marked for removal. Status string // Deprecated. Marked for removal.

24
user.go
View File

@ -15,6 +15,9 @@ import (
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
// TODO: Replace any literals with this
var banGroup = 4
var guestUser = User{ID: 0, Link: "#", Group: 6, Perms: GuestPerms} var guestUser = User{ID: 0, Link: "#", Group: 6, Perms: GuestPerms}
//func(real_password string, password string, salt string) (err error) //func(real_password string, password string, salt string) (err error)
@ -59,7 +62,7 @@ type Email struct {
} }
func (user *User) Ban(duration time.Duration, issuedBy int) error { func (user *User) Ban(duration time.Duration, issuedBy int) error {
return user.ScheduleGroupUpdate(4, issuedBy, duration) return user.ScheduleGroupUpdate(banGroup, issuedBy, duration)
} }
func (user *User) Unban() error { func (user *User) Unban() error {
@ -80,7 +83,7 @@ func (user *User) ScheduleGroupUpdate(gid int, issuedBy int, duration time.Durat
} }
revertAt := time.Now().Add(duration) revertAt := time.Now().Add(duration)
_, err := replaceScheduleGroupStmt.Exec(user.ID, gid, issuedBy, revertAt, temporary) _, err := replaceScheduleGroupStmt.Exec(user.ID, gid, issuedBy, revertAt, temporary, user.ID)
if err != nil { if err != nil {
return err return err
} }
@ -94,7 +97,7 @@ func (user *User) ScheduleGroupUpdate(gid int, issuedBy int, duration time.Durat
// TODO: Use a transaction to avoid race conditions // TODO: Use a transaction to avoid race conditions
func (user *User) RevertGroupUpdate() error { func (user *User) RevertGroupUpdate() error {
_, err := replaceScheduleGroupStmt.Exec(user.ID, 0, 0, time.Now(), false) _, err := replaceScheduleGroupStmt.Exec(user.ID, 0, 0, time.Now(), false, user.ID)
if err != nil { if err != nil {
return err return err
} }
@ -121,6 +124,21 @@ func (user *User) Activate() (err error) {
return err return err
} }
// TODO: Write tests for this
// TODO: Delete this user's content too?
// TODO: Expose this to the admin?
func (user *User) Delete() error {
_, err := deleteUserStmt.Exec(user.ID)
if err != nil {
return err
}
ucache, ok := users.(UserCache)
if ok {
ucache.CacheRemove(user.ID)
}
return err
}
func (user *User) ChangeName(username string) (err error) { func (user *User) ChangeName(username string) (err error) {
_, err = setUsernameStmt.Exec(username, user.ID) _, err = setUsernameStmt.Exec(username, user.ID)
ucache, ok := users.(UserCache) ucache, ok := users.(UserCache)

View File

@ -69,7 +69,7 @@ func NewMemoryUserStore(capacity int) *MemoryUserStore {
// Add an admin version of register_stmt with more flexibility? // Add an admin version of register_stmt with more flexibility?
// create_account_stmt, err = db.Prepare("INSERT INTO // create_account_stmt, err = db.Prepare("INSERT INTO
registerStmt, err := qgen.Builder.SimpleInsert("users", "name, email, password, salt, group, is_super_admin, session, active, message", "?,?,?,?,?,0,'',?,''") registerStmt, err := qgen.Builder.SimpleInsert("users", "name, email, password, salt, group, is_super_admin, session, active, message, createdAt, lastActiveAt", "?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP()")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -289,7 +289,11 @@ func (mus *MemoryUserStore) Reload(id int) error {
} }
func (mus *MemoryUserStore) Exists(id int) bool { func (mus *MemoryUserStore) Exists(id int) bool {
return mus.exists.QueryRow(id).Scan(&id) == nil err := mus.exists.QueryRow(id).Scan(&id)
if err != nil && err != ErrNoRows {
LogError(err)
}
return err != ErrNoRows
} }
func (mus *MemoryUserStore) CacheSet(item *User) error { func (mus *MemoryUserStore) CacheSet(item *User) error {
@ -315,8 +319,8 @@ func (mus *MemoryUserStore) CacheAdd(item *User) error {
} }
mus.Lock() mus.Lock()
mus.items[item.ID] = item mus.items[item.ID] = item
mus.length = int64(len(mus.items))
mus.Unlock() mus.Unlock()
atomic.AddInt64(&mus.length, 1)
return nil return nil
} }
@ -325,12 +329,17 @@ func (mus *MemoryUserStore) CacheAddUnsafe(item *User) error {
return ErrStoreCapacityOverflow return ErrStoreCapacityOverflow
} }
mus.items[item.ID] = item mus.items[item.ID] = item
atomic.AddInt64(&mus.length, 1) mus.length = int64(len(mus.items))
return nil return nil
} }
func (mus *MemoryUserStore) CacheRemove(id int) error { func (mus *MemoryUserStore) CacheRemove(id int) error {
mus.Lock() mus.Lock()
_, ok := mus.items[id]
if !ok {
mus.Unlock()
return ErrNoRows
}
delete(mus.items, id) delete(mus.items, id)
mus.Unlock() mus.Unlock()
atomic.AddInt64(&mus.length, -1) atomic.AddInt64(&mus.length, -1)
@ -338,11 +347,16 @@ func (mus *MemoryUserStore) CacheRemove(id int) error {
} }
func (mus *MemoryUserStore) CacheRemoveUnsafe(id int) error { func (mus *MemoryUserStore) CacheRemoveUnsafe(id int) error {
_, ok := mus.items[id]
if !ok {
return ErrNoRows
}
delete(mus.items, id) delete(mus.items, id)
atomic.AddInt64(&mus.length, -1) atomic.AddInt64(&mus.length, -1)
return nil return nil
} }
// TODO: Change active to a bool?
func (mus *MemoryUserStore) Create(username string, password string, email string, group int, active int) (int, error) { func (mus *MemoryUserStore) Create(username string, password string, email string, group int, active int) (int, error) {
// Is this username already taken..? // Is this username already taken..?
err := mus.usernameExists.QueryRow(username).Scan(&username) err := mus.usernameExists.QueryRow(username).Scan(&username)
@ -421,7 +435,7 @@ func NewSQLUserStore() *SQLUserStore {
// Add an admin version of register_stmt with more flexibility? // Add an admin version of register_stmt with more flexibility?
// create_account_stmt, err = db.Prepare("INSERT INTO // create_account_stmt, err = db.Prepare("INSERT INTO
registerStmt, err := qgen.Builder.SimpleInsert("users", "name, email, password, salt, group, is_super_admin, session, active, message", "?,?,?,?,?,0,'',?,''") registerStmt, err := qgen.Builder.SimpleInsert("users", "name, email, password, salt, group, is_super_admin, session, active, message, createdAt, lastActiveAt", "?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP()")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -527,7 +541,11 @@ func (mus *SQLUserStore) BypassGet(id int) (*User, error) {
} }
func (mus *SQLUserStore) Exists(id int) bool { func (mus *SQLUserStore) Exists(id int) bool {
return mus.exists.QueryRow(id).Scan(&id) == nil err := mus.exists.QueryRow(id).Scan(&id)
if err != nil && err != ErrNoRows {
LogError(err)
}
return err != ErrNoRows
} }
func (mus *SQLUserStore) Create(username string, password string, email string, group int, active int) (int, error) { func (mus *SQLUserStore) Create(username string, password string, email string, group int, active int) (int, error) {