Mostly a mid-way technical commit to make reading diffs easier on me.

Split the relativeTime function into relativeTime and relativeTimeFromString.
Refactored the installer.
Made a lot of progress with PgSQL and MSSQL support, mostly MSSQL.
Made a lot of progress on the automated testing suite.
Added eqcss to the file extension list.
..depressed..
Fixed various bugs here and there.
gen_mysql.go is now properly excluded when the pgsql or mssql build tag is passed.
The BBCode plugin is now always initialised prior to it's test.
We've begun transitioning towards deserializing database times directly into time.Times rather than doing it every time on the spot.
Added more dev flags.
The tests now make use of a test database rather than the production database.
This commit is contained in:
Azareal 2017-10-14 08:39:22 +01:00
parent a09630c0dc
commit fdb6304e32
107 changed files with 2881 additions and 619 deletions

28
.eslintrc.json Normal file
View File

@ -0,0 +1,28 @@
{
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"node": false
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module"
},
"rules": {
"no-const-assign": "warn",
"no-this-before-super": "warn",
"no-undef": "warn",
"no-unreachable": "warn",
"no-unused-vars": "warn",
"constructor-super": "warn",
"valid-typeof": "warn"
},
"globals": {
"$": true,
"session": true,
"siteURL": true
}
}

View File

@ -107,6 +107,10 @@ go get -u gopkg.in/sourcemap.v1
go get -u github.com/robertkrimen/otto go get -u github.com/robertkrimen/otto
go get -u github.com/lib/pq
go get -u github.com/denisenkom/go-mssqldb
go generate go generate
@ -127,6 +131,8 @@ install.exe
gosora.exe gosora.exe
``` ```
I'm looking into minimising the number of go gets for the advanced build and to maybe remove the platform and database engine specific dependencies if possible for those who don't need them.
# How do I install plugins? # How do I install plugins?
@ -176,16 +182,26 @@ More images in the /images/ folder. Beware though, some of them are *really* out
* github.com/gorilla/websocket Needed for Gosora's Optional WebSockets Module. * github.com/gorilla/websocket Needed for Gosora's Optional WebSockets Module.
* github.com/robertkrimen/otto Needed for the upcoming JS plugin type.
* gopkg.in/sourcemap.v1 Dependency for Otto.
* github.com/lib/pq For interfacing with PostgreSQL. You will be able to pick this instead of MariaDB soon.
* ithub.com/denisenkom/go-mssqldb For interfacing with MSSQL. You will be able to pick this instead of MSSQL soon.
# Bundled Plugins # Bundled Plugins
There are several plugins which are bundled with the software by default. These cover various common tasks which aren't common enough to clutter the core with or which have competing implementation methods (E.g. plugin_markdown vs plugin_bbcode for post mark-up). There are several plugins which are bundled with the software by default. These cover various common tasks which aren't common enough to clutter the core with or which have competing implementation methods (E.g. plugin_markdown vs plugin_bbcode for post mark-up).
* Hello World / Skeleton - Example plugins for helping you learn how to develop plugins. * Hey There / Skeleton / Hey There (JS Version) - Example plugins for helping you learn how to develop plugins.
* BBCode - A plugin in early development for converting BBCode Tags into HTML. * BBCode - A plugin in early development for converting BBCode Tags into HTML.
* Markdown - An extremely simple plugin for converting Markdown into HTML. * Markdown - An extremely simple plugin for converting Markdown into HTML.
* Social Groups - A WIP plugin which lets users create their own little discussion areas which they can administrate / moderate on their own.
# Developers # Developers
There are a few things you'll need to know before running the more developer oriented features like the tests or the benchmarks. There are a few things you'll need to know before running the more developer oriented features like the tests or the benchmarks.

View File

@ -11,6 +11,8 @@ var dbAdapter string
// ErrNoRows is an alias of sql.ErrNoRows, just in case we end up with non-database/sql datastores // ErrNoRows is an alias of sql.ErrNoRows, just in case we end up with non-database/sql datastores
var ErrNoRows = sql.ErrNoRows var ErrNoRows = sql.ErrNoRows
var _initDatabase func() error
func initDatabase() (err error) { func initDatabase() (err error) {
// Engine specific code // Engine specific code
err = _initDatabase() err = _initDatabase()

962
gen_mssql.go Normal file
View File

@ -0,0 +1,962 @@
// +build mssql
// This file was generated by Gosora's Query Generator. Please try to avoid modifying this file, as it might change at any time.
package main
import "log"
import "database/sql"
// nolint
var getUserStmt *sql.Stmt
var getReplyStmt *sql.Stmt
var getUserReplyStmt *sql.Stmt
var getPasswordStmt *sql.Stmt
var getSettingsStmt *sql.Stmt
var getSettingStmt *sql.Stmt
var getFullSettingStmt *sql.Stmt
var getFullSettingsStmt *sql.Stmt
var getGroupsStmt *sql.Stmt
var getForumsStmt *sql.Stmt
var getForumsPermissionsStmt *sql.Stmt
var getPluginsStmt *sql.Stmt
var getThemesStmt *sql.Stmt
var getWidgetsStmt *sql.Stmt
var isPluginActiveStmt *sql.Stmt
var getUsersStmt *sql.Stmt
var getUsersOffsetStmt *sql.Stmt
var getWordFiltersStmt *sql.Stmt
var isThemeDefaultStmt *sql.Stmt
var getModlogsStmt *sql.Stmt
var getModlogsOffsetStmt *sql.Stmt
var getReplyTIDStmt *sql.Stmt
var getTopicFIDStmt *sql.Stmt
var getUserReplyUIDStmt *sql.Stmt
var hasLikedTopicStmt *sql.Stmt
var hasLikedReplyStmt *sql.Stmt
var getUserNameStmt *sql.Stmt
var getEmailsByUserStmt *sql.Stmt
var getTopicBasicStmt *sql.Stmt
var getActivityEntryStmt *sql.Stmt
var forumEntryExistsStmt *sql.Stmt
var groupEntryExistsStmt *sql.Stmt
var getForumTopicsOffsetStmt *sql.Stmt
var getExpiredScheduledGroupsStmt *sql.Stmt
var getSyncStmt *sql.Stmt
var getAttachmentStmt *sql.Stmt
var getTopicRepliesOffsetStmt *sql.Stmt
var getTopicListStmt *sql.Stmt
var getTopicUserStmt *sql.Stmt
var getTopicByReplyStmt *sql.Stmt
var getTopicRepliesStmt *sql.Stmt
var getForumTopicsStmt *sql.Stmt
var getProfileRepliesStmt *sql.Stmt
var getWatchersStmt *sql.Stmt
var createTopicStmt *sql.Stmt
var createReportStmt *sql.Stmt
var createReplyStmt *sql.Stmt
var createActionReplyStmt *sql.Stmt
var createLikeStmt *sql.Stmt
var addActivityStmt *sql.Stmt
var notifyOneStmt *sql.Stmt
var addEmailStmt *sql.Stmt
var createProfileReplyStmt *sql.Stmt
var addSubscriptionStmt *sql.Stmt
var createForumStmt *sql.Stmt
var addForumPermsToForumStmt *sql.Stmt
var addPluginStmt *sql.Stmt
var addThemeStmt *sql.Stmt
var createGroupStmt *sql.Stmt
var addModlogEntryStmt *sql.Stmt
var addAdminlogEntryStmt *sql.Stmt
var addAttachmentStmt *sql.Stmt
var createWordFilterStmt *sql.Stmt
var addForumPermsToGroupStmt *sql.Stmt
var replaceScheduleGroupStmt *sql.Stmt
var addRepliesToTopicStmt *sql.Stmt
var removeRepliesFromTopicStmt *sql.Stmt
var addTopicsToForumStmt *sql.Stmt
var removeTopicsFromForumStmt *sql.Stmt
var updateForumCacheStmt *sql.Stmt
var addLikesToTopicStmt *sql.Stmt
var addLikesToReplyStmt *sql.Stmt
var editTopicStmt *sql.Stmt
var editReplyStmt *sql.Stmt
var stickTopicStmt *sql.Stmt
var unstickTopicStmt *sql.Stmt
var lockTopicStmt *sql.Stmt
var unlockTopicStmt *sql.Stmt
var updateLastIPStmt *sql.Stmt
var updateSessionStmt *sql.Stmt
var setPasswordStmt *sql.Stmt
var setAvatarStmt *sql.Stmt
var setUsernameStmt *sql.Stmt
var changeGroupStmt *sql.Stmt
var activateUserStmt *sql.Stmt
var updateUserLevelStmt *sql.Stmt
var incrementUserScoreStmt *sql.Stmt
var incrementUserPostsStmt *sql.Stmt
var incrementUserBigpostsStmt *sql.Stmt
var incrementUserMegapostsStmt *sql.Stmt
var incrementUserTopicsStmt *sql.Stmt
var editProfileReplyStmt *sql.Stmt
var updateForumStmt *sql.Stmt
var updateSettingStmt *sql.Stmt
var updatePluginStmt *sql.Stmt
var updatePluginInstallStmt *sql.Stmt
var updateThemeStmt *sql.Stmt
var updateUserStmt *sql.Stmt
var updateGroupPermsStmt *sql.Stmt
var updateGroupRankStmt *sql.Stmt
var updateGroupStmt *sql.Stmt
var updateEmailStmt *sql.Stmt
var verifyEmailStmt *sql.Stmt
var setTempGroupStmt *sql.Stmt
var updateWordFilterStmt *sql.Stmt
var bumpSyncStmt *sql.Stmt
var deleteReplyStmt *sql.Stmt
var deleteProfileReplyStmt *sql.Stmt
var deleteForumPermsByForumStmt *sql.Stmt
var deleteActivityStreamMatchStmt *sql.Stmt
var deleteWordFilterStmt *sql.Stmt
var reportExistsStmt *sql.Stmt
var groupCountStmt *sql.Stmt
var modlogCountStmt *sql.Stmt
var addForumPermsToForumAdminsStmt *sql.Stmt
var addForumPermsToForumStaffStmt *sql.Stmt
var addForumPermsToForumMembersStmt *sql.Stmt
var notifyWatchersStmt *sql.Stmt
// nolint
func _gen_mssql() (err error) {
if dev.DebugMode {
log.Print("Building the generated statements")
}
log.Print("Preparing getUser statement.")
getUserStmt, err = db.Prepare("SELECT [name],[group],[is_super_admin],[avatar],[message],[url_prefix],[url_name],[level] FROM [users] WHERE [uid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [name],[group],[is_super_admin],[avatar],[message],[url_prefix],[url_name],[level] FROM [users] WHERE [uid] = ?1")
return err
}
log.Print("Preparing getReply statement.")
getReplyStmt, err = db.Prepare("SELECT [tid],[content],[createdBy],[createdAt],[lastEdit],[lastEditBy],[ipaddress],[likeCount] FROM [replies] WHERE [rid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [tid],[content],[createdBy],[createdAt],[lastEdit],[lastEditBy],[ipaddress],[likeCount] FROM [replies] WHERE [rid] = ?1")
return err
}
log.Print("Preparing getUserReply statement.")
getUserReplyStmt, err = db.Prepare("SELECT [uid],[content],[createdBy],[createdAt],[lastEdit],[lastEditBy],[ipaddress] FROM [users_replies] WHERE [rid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [uid],[content],[createdBy],[createdAt],[lastEdit],[lastEditBy],[ipaddress] FROM [users_replies] WHERE [rid] = ?1")
return err
}
log.Print("Preparing getPassword statement.")
getPasswordStmt, err = db.Prepare("SELECT [password],[salt] FROM [users] WHERE [uid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [password],[salt] FROM [users] WHERE [uid] = ?1")
return err
}
log.Print("Preparing getSettings statement.")
getSettingsStmt, err = db.Prepare("SELECT [name],[content],[type] FROM [settings]")
if err != nil {
log.Print("Bad Query: ","SELECT [name],[content],[type] FROM [settings]")
return err
}
log.Print("Preparing getSetting statement.")
getSettingStmt, err = db.Prepare("SELECT [content],[type] FROM [settings] WHERE [name] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [content],[type] FROM [settings] WHERE [name] = ?1")
return err
}
log.Print("Preparing getFullSetting statement.")
getFullSettingStmt, err = db.Prepare("SELECT [name],[type],[constraints] FROM [settings] WHERE [name] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [name],[type],[constraints] FROM [settings] WHERE [name] = ?1")
return err
}
log.Print("Preparing getFullSettings statement.")
getFullSettingsStmt, err = db.Prepare("SELECT [name],[content],[type],[constraints] FROM [settings]")
if err != nil {
log.Print("Bad Query: ","SELECT [name],[content],[type],[constraints] FROM [settings]")
return err
}
log.Print("Preparing getGroups statement.")
getGroupsStmt, err = db.Prepare("SELECT [gid],[name],[permissions],[plugin_perms],[is_mod],[is_admin],[is_banned],[tag] FROM [users_groups]")
if err != nil {
log.Print("Bad Query: ","SELECT [gid],[name],[permissions],[plugin_perms],[is_mod],[is_admin],[is_banned],[tag] FROM [users_groups]")
return err
}
log.Print("Preparing getForums statement.")
getForumsStmt, err = db.Prepare("SELECT [fid],[name],[desc],[active],[preset],[parentID],[parentType],[topicCount],[lastTopicID],[lastReplyerID] FROM [forums] ORDER BY fid ASC")
if err != nil {
log.Print("Bad Query: ","SELECT [fid],[name],[desc],[active],[preset],[parentID],[parentType],[topicCount],[lastTopicID],[lastReplyerID] FROM [forums] ORDER BY fid ASC")
return err
}
log.Print("Preparing getForumsPermissions statement.")
getForumsPermissionsStmt, err = db.Prepare("SELECT [gid],[fid],[permissions] FROM [forums_permissions] ORDER BY gid ASC,fid ASC")
if err != nil {
log.Print("Bad Query: ","SELECT [gid],[fid],[permissions] FROM [forums_permissions] ORDER BY gid ASC,fid ASC")
return err
}
log.Print("Preparing getPlugins statement.")
getPluginsStmt, err = db.Prepare("SELECT [uname],[active],[installed] FROM [plugins]")
if err != nil {
log.Print("Bad Query: ","SELECT [uname],[active],[installed] FROM [plugins]")
return err
}
log.Print("Preparing getThemes statement.")
getThemesStmt, err = db.Prepare("SELECT [uname],[default] FROM [themes]")
if err != nil {
log.Print("Bad Query: ","SELECT [uname],[default] FROM [themes]")
return err
}
log.Print("Preparing getWidgets statement.")
getWidgetsStmt, err = db.Prepare("SELECT [position],[side],[type],[active],[location],[data] FROM [widgets] ORDER BY position ASC")
if err != nil {
log.Print("Bad Query: ","SELECT [position],[side],[type],[active],[location],[data] FROM [widgets] ORDER BY position ASC")
return err
}
log.Print("Preparing isPluginActive statement.")
isPluginActiveStmt, err = db.Prepare("SELECT [active] FROM [plugins] WHERE [uname] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [active] FROM [plugins] WHERE [uname] = ?1")
return err
}
log.Print("Preparing getUsers statement.")
getUsersStmt, err = db.Prepare("SELECT [uid],[name],[group],[active],[is_super_admin],[avatar] FROM [users]")
if err != nil {
log.Print("Bad Query: ","SELECT [uid],[name],[group],[active],[is_super_admin],[avatar] FROM [users]")
return err
}
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")
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")
return err
}
log.Print("Preparing getWordFilters statement.")
getWordFiltersStmt, err = db.Prepare("SELECT [wfid],[find],[replacement] FROM [word_filters]")
if err != nil {
log.Print("Bad Query: ","SELECT [wfid],[find],[replacement] FROM [word_filters]")
return err
}
log.Print("Preparing isThemeDefault statement.")
isThemeDefaultStmt, err = db.Prepare("SELECT [default] FROM [themes] WHERE [uname] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [default] FROM [themes] WHERE [uname] = ?1")
return err
}
log.Print("Preparing getModlogs statement.")
getModlogsStmt, err = db.Prepare("SELECT [action],[elementID],[elementType],[ipaddress],[actorID],[doneAt] FROM [moderation_logs]")
if err != nil {
log.Print("Bad Query: ","SELECT [action],[elementID],[elementType],[ipaddress],[actorID],[doneAt] FROM [moderation_logs]")
return err
}
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")
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")
return err
}
log.Print("Preparing getReplyTID statement.")
getReplyTIDStmt, err = db.Prepare("SELECT [tid] FROM [replies] WHERE [rid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [tid] FROM [replies] WHERE [rid] = ?1")
return err
}
log.Print("Preparing getTopicFID statement.")
getTopicFIDStmt, err = db.Prepare("SELECT [parentID] FROM [topics] WHERE [tid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [parentID] FROM [topics] WHERE [tid] = ?1")
return err
}
log.Print("Preparing getUserReplyUID statement.")
getUserReplyUIDStmt, err = db.Prepare("SELECT [uid] FROM [users_replies] WHERE [rid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [uid] FROM [users_replies] WHERE [rid] = ?1")
return err
}
log.Print("Preparing hasLikedTopic statement.")
hasLikedTopicStmt, err = db.Prepare("SELECT [targetItem] FROM [likes] WHERE [sentBy] = ?1 AND [targetItem] = ?2 AND [targetType] = 'topics'")
if err != nil {
log.Print("Bad Query: ","SELECT [targetItem] FROM [likes] WHERE [sentBy] = ?1 AND [targetItem] = ?2 AND [targetType] = 'topics'")
return err
}
log.Print("Preparing hasLikedReply statement.")
hasLikedReplyStmt, err = db.Prepare("SELECT [targetItem] FROM [likes] WHERE [sentBy] = ?1 AND [targetItem] = ?2 AND [targetType] = 'replies'")
if err != nil {
log.Print("Bad Query: ","SELECT [targetItem] FROM [likes] WHERE [sentBy] = ?1 AND [targetItem] = ?2 AND [targetType] = 'replies'")
return err
}
log.Print("Preparing getUserName statement.")
getUserNameStmt, err = db.Prepare("SELECT [name] FROM [users] WHERE [uid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [name] FROM [users] WHERE [uid] = ?1")
return err
}
log.Print("Preparing getEmailsByUser statement.")
getEmailsByUserStmt, err = db.Prepare("SELECT [email],[validated],[token] FROM [emails] WHERE [uid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [email],[validated],[token] FROM [emails] WHERE [uid] = ?1")
return err
}
log.Print("Preparing getTopicBasic statement.")
getTopicBasicStmt, err = db.Prepare("SELECT [title],[content] FROM [topics] WHERE [tid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [title],[content] FROM [topics] WHERE [tid] = ?1")
return err
}
log.Print("Preparing getActivityEntry statement.")
getActivityEntryStmt, err = db.Prepare("SELECT [actor],[targetUser],[event],[elementType],[elementID] FROM [activity_stream] WHERE [asid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [actor],[targetUser],[event],[elementType],[elementID] FROM [activity_stream] WHERE [asid] = ?1")
return err
}
log.Print("Preparing forumEntryExists statement.")
forumEntryExistsStmt, err = db.Prepare("SELECT [fid] FROM [forums] WHERE [name] = '' ORDER BY fid ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY")
if err != nil {
log.Print("Bad Query: ","SELECT [fid] FROM [forums] WHERE [name] = '' ORDER BY fid ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY")
return err
}
log.Print("Preparing groupEntryExists statement.")
groupEntryExistsStmt, err = db.Prepare("SELECT [gid] FROM [users_groups] WHERE [name] = '' ORDER BY gid ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY")
if err != nil {
log.Print("Bad Query: ","SELECT [gid] FROM [users_groups] WHERE [name] = '' ORDER BY gid ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY")
return err
}
log.Print("Preparing getForumTopicsOffset statement.")
getForumTopicsOffsetStmt, err = db.Prepare("SELECT [tid],[title],[content],[createdBy],[is_closed],[sticky],[createdAt],[lastReplyAt],[lastReplyBy],[parentID],[postCount],[likeCount] FROM [topics] WHERE [parentID] = ?1 ORDER BY sticky DESC,lastReplyAt DESC,createdBy DESC OFFSET ?2 ROWS FETCH NEXT ?3 ROWS ONLY")
if err != nil {
log.Print("Bad Query: ","SELECT [tid],[title],[content],[createdBy],[is_closed],[sticky],[createdAt],[lastReplyAt],[lastReplyBy],[parentID],[postCount],[likeCount] FROM [topics] WHERE [parentID] = ?1 ORDER BY sticky DESC,lastReplyAt DESC,createdBy DESC OFFSET ?2 ROWS FETCH NEXT ?3 ROWS ONLY")
return err
}
log.Print("Preparing getExpiredScheduledGroups statement.")
getExpiredScheduledGroupsStmt, err = db.Prepare("SELECT [uid] FROM [users_groups_scheduler] WHERE GETUTCDATE() > [revert_at] AND [temporary] = 1")
if err != nil {
log.Print("Bad Query: ","SELECT [uid] FROM [users_groups_scheduler] WHERE GETUTCDATE() > [revert_at] AND [temporary] = 1")
return err
}
log.Print("Preparing getSync statement.")
getSyncStmt, err = db.Prepare("SELECT [last_update] FROM [sync]")
if err != nil {
log.Print("Bad Query: ","SELECT [last_update] FROM [sync]")
return err
}
log.Print("Preparing getAttachment statement.")
getAttachmentStmt, err = db.Prepare("SELECT [sectionID],[sectionTable],[originID],[originTable],[uploadedBy],[path] FROM [attachments] WHERE [path] = ?1 AND [sectionID] = ?2 AND [sectionTable] = ?3")
if err != nil {
log.Print("Bad Query: ","SELECT [sectionID],[sectionTable],[originID],[originTable],[uploadedBy],[path] FROM [attachments] WHERE [path] = ?1 AND [sectionID] = ?2 AND [sectionTable] = ?3")
return err
}
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")
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")
return err
}
log.Print("Preparing getTopicList statement.")
getTopicListStmt, err = db.Prepare("SELECT [topics].[tid],[topics].[title],[topics].[content],[topics].[createdBy],[topics].[is_closed],[topics].[sticky],[topics].[createdAt],[topics].[parentID],[users].[name],[users].[avatar] FROM [topics] LEFT JOIN [users] ON [topics].[createdBy] = [users].[uid] ORDER BY topics.sticky DESC,topics.lastReplyAt DESC,topics.createdBy DESC")
if err != nil {
log.Print("Bad Query: ","SELECT [topics].[tid],[topics].[title],[topics].[content],[topics].[createdBy],[topics].[is_closed],[topics].[sticky],[topics].[createdAt],[topics].[parentID],[users].[name],[users].[avatar] FROM [topics] LEFT JOIN [users] ON [topics].[createdBy] = [users].[uid] ORDER BY topics.sticky DESC,topics.lastReplyAt DESC,topics.createdBy DESC")
return err
}
log.Print("Preparing getTopicUser statement.")
getTopicUserStmt, err = db.Prepare("SELECT [topics].[title],[topics].[content],[topics].[createdBy],[topics].[createdAt],[topics].[is_closed],[topics].[sticky],[topics].[parentID],[topics].[ipaddress],[topics].[postCount],[topics].[likeCount],[users].[name],[users].[avatar],[users].[group],[users].[url_prefix],[users].[url_name],[users].[level] FROM [topics] LEFT JOIN [users] ON [topics].[createdBy] = [users].[uid] WHERE [tid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [topics].[title],[topics].[content],[topics].[createdBy],[topics].[createdAt],[topics].[is_closed],[topics].[sticky],[topics].[parentID],[topics].[ipaddress],[topics].[postCount],[topics].[likeCount],[users].[name],[users].[avatar],[users].[group],[users].[url_prefix],[users].[url_name],[users].[level] FROM [topics] LEFT JOIN [users] ON [topics].[createdBy] = [users].[uid] WHERE [tid] = ?1")
return err
}
log.Print("Preparing getTopicByReply statement.")
getTopicByReplyStmt, err = db.Prepare("SELECT [topics].[tid],[topics].[title],[topics].[content],[topics].[createdBy],[topics].[createdAt],[topics].[is_closed],[topics].[sticky],[topics].[parentID],[topics].[ipaddress],[topics].[postCount],[topics].[likeCount],[topics].[data] FROM [replies] LEFT JOIN [topics] ON [replies].[tid] = [topics].[tid] WHERE [rid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [topics].[tid],[topics].[title],[topics].[content],[topics].[createdBy],[topics].[createdAt],[topics].[is_closed],[topics].[sticky],[topics].[parentID],[topics].[ipaddress],[topics].[postCount],[topics].[likeCount],[topics].[data] FROM [replies] LEFT JOIN [topics] ON [replies].[tid] = [topics].[tid] WHERE [rid] = ?1")
return err
}
log.Print("Preparing getTopicReplies statement.")
getTopicRepliesStmt, 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] FROM [replies] LEFT JOIN [users] ON [replies].[createdBy] = [users].[uid] WHERE [tid] = ?1")
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] FROM [replies] LEFT JOIN [users] ON [replies].[createdBy] = [users].[uid] WHERE [tid] = ?1")
return err
}
log.Print("Preparing getForumTopics statement.")
getForumTopicsStmt, err = db.Prepare("SELECT [topics].[tid],[topics].[title],[topics].[content],[topics].[createdBy],[topics].[is_closed],[topics].[sticky],[topics].[createdAt],[topics].[lastReplyAt],[topics].[parentID],[users].[name],[users].[avatar] FROM [topics] LEFT JOIN [users] ON [topics].[createdBy] = [users].[uid] WHERE [topics].[parentID] = ?1 ORDER BY topics.sticky DESC,topics.lastReplyAt DESC,topics.createdBy DESC")
if err != nil {
log.Print("Bad Query: ","SELECT [topics].[tid],[topics].[title],[topics].[content],[topics].[createdBy],[topics].[is_closed],[topics].[sticky],[topics].[createdAt],[topics].[lastReplyAt],[topics].[parentID],[users].[name],[users].[avatar] FROM [topics] LEFT JOIN [users] ON [topics].[createdBy] = [users].[uid] WHERE [topics].[parentID] = ?1 ORDER BY topics.sticky DESC,topics.lastReplyAt DESC,topics.createdBy DESC")
return err
}
log.Print("Preparing getProfileReplies statement.")
getProfileRepliesStmt, err = db.Prepare("SELECT [users_replies].[rid],[users_replies].[content],[users_replies].[createdBy],[users_replies].[createdAt],[users_replies].[lastEdit],[users_replies].[lastEditBy],[users].[avatar],[users].[name],[users].[group] FROM [users_replies] LEFT JOIN [users] ON [users_replies].[createdBy] = [users].[uid] WHERE [users_replies].[uid] = ?1")
if err != nil {
log.Print("Bad Query: ","SELECT [users_replies].[rid],[users_replies].[content],[users_replies].[createdBy],[users_replies].[createdAt],[users_replies].[lastEdit],[users_replies].[lastEditBy],[users].[avatar],[users].[name],[users].[group] FROM [users_replies] LEFT JOIN [users] ON [users_replies].[createdBy] = [users].[uid] WHERE [users_replies].[uid] = ?1")
return err
}
log.Print("Preparing getWatchers statement.")
getWatchersStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing createTopic statement.")
createTopicStmt, err = db.Prepare("INSERT INTO [topics] ([parentID],[title],[content],[parsed_content],[createdAt],[lastReplyAt],[lastReplyBy],[ipaddress],[words],[createdBy]) VALUES (?,?,?,?,GETUTCDATE(),GETUTCDATE(),?,?,?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [topics] ([parentID],[title],[content],[parsed_content],[createdAt],[lastReplyAt],[lastReplyBy],[ipaddress],[words],[createdBy]) VALUES (?,?,?,?,GETUTCDATE(),GETUTCDATE(),?,?,?,?)")
return err
}
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')")
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')")
return err
}
log.Print("Preparing createReply statement.")
createReplyStmt, err = db.Prepare("INSERT INTO [replies] ([tid],[content],[parsed_content],[createdAt],[ipaddress],[words],[createdBy]) VALUES (?,?,?,GETUTCDATE(),?,?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [replies] ([tid],[content],[parsed_content],[createdAt],[ipaddress],[words],[createdBy]) VALUES (?,?,?,GETUTCDATE(),?,?,?)")
return err
}
log.Print("Preparing createActionReply statement.")
createActionReplyStmt, err = db.Prepare("INSERT INTO [replies] ([tid],[actionType],[ipaddress],[createdBy]) VALUES (?,?,?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [replies] ([tid],[actionType],[ipaddress],[createdBy]) VALUES (?,?,?,?)")
return err
}
log.Print("Preparing createLike statement.")
createLikeStmt, err = db.Prepare("INSERT INTO [likes] ([weight],[targetItem],[targetType],[sentBy]) VALUES (?,?,?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [likes] ([weight],[targetItem],[targetType],[sentBy]) VALUES (?,?,?,?)")
return err
}
log.Print("Preparing addActivity statement.")
addActivityStmt, err = db.Prepare("INSERT INTO [activity_stream] ([actor],[targetUser],[event],[elementType],[elementID]) VALUES (?,?,?,?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [activity_stream] ([actor],[targetUser],[event],[elementType],[elementID]) VALUES (?,?,?,?,?)")
return err
}
log.Print("Preparing notifyOne statement.")
notifyOneStmt, err = db.Prepare("INSERT INTO [activity_stream_matches] ([watcher],[asid]) VALUES (?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [activity_stream_matches] ([watcher],[asid]) VALUES (?,?)")
return err
}
log.Print("Preparing addEmail statement.")
addEmailStmt, err = db.Prepare("INSERT INTO [emails] ([email],[uid],[validated],[token]) VALUES (?,?,?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [emails] ([email],[uid],[validated],[token]) VALUES (?,?,?,?)")
return err
}
log.Print("Preparing createProfileReply statement.")
createProfileReplyStmt, err = db.Prepare("INSERT INTO [users_replies] ([uid],[content],[parsed_content],[createdAt],[createdBy],[ipaddress]) VALUES (?,?,?,GETUTCDATE(),?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [users_replies] ([uid],[content],[parsed_content],[createdAt],[createdBy],[ipaddress]) VALUES (?,?,?,GETUTCDATE(),?,?)")
return err
}
log.Print("Preparing addSubscription statement.")
addSubscriptionStmt, err = db.Prepare("INSERT INTO [activity_subscriptions] ([user],[targetID],[targetType],[level]) VALUES (?,?,?,2)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [activity_subscriptions] ([user],[targetID],[targetType],[level]) VALUES (?,?,?,2)")
return err
}
log.Print("Preparing createForum statement.")
createForumStmt, err = db.Prepare("INSERT INTO [forums] ([name],[desc],[active],[preset]) VALUES (?,?,?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [forums] ([name],[desc],[active],[preset]) VALUES (?,?,?,?)")
return err
}
log.Print("Preparing addForumPermsToForum statement.")
addForumPermsToForumStmt, err = db.Prepare("INSERT INTO [forums_permissions] ([gid],[fid],[preset],[permissions]) VALUES (?,?,?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [forums_permissions] ([gid],[fid],[preset],[permissions]) VALUES (?,?,?,?)")
return err
}
log.Print("Preparing addPlugin statement.")
addPluginStmt, err = db.Prepare("INSERT INTO [plugins] ([uname],[active],[installed]) VALUES (?,?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [plugins] ([uname],[active],[installed]) VALUES (?,?,?)")
return err
}
log.Print("Preparing addTheme statement.")
addThemeStmt, err = db.Prepare("INSERT INTO [themes] ([uname],[default]) VALUES (?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [themes] ([uname],[default]) VALUES (?,?)")
return err
}
log.Print("Preparing createGroup statement.")
createGroupStmt, err = db.Prepare("INSERT INTO [users_groups] ([name],[tag],[is_admin],[is_mod],[is_banned],[permissions]) VALUES (?,?,?,?,?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [users_groups] ([name],[tag],[is_admin],[is_mod],[is_banned],[permissions]) VALUES (?,?,?,?,?,?)")
return err
}
log.Print("Preparing addModlogEntry statement.")
addModlogEntryStmt, err = db.Prepare("INSERT INTO [moderation_logs] ([action],[elementID],[elementType],[ipaddress],[actorID],[doneAt]) VALUES (?,?,?,?,?,GETUTCDATE())")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [moderation_logs] ([action],[elementID],[elementType],[ipaddress],[actorID],[doneAt]) VALUES (?,?,?,?,?,GETUTCDATE())")
return err
}
log.Print("Preparing addAdminlogEntry statement.")
addAdminlogEntryStmt, err = db.Prepare("INSERT INTO [administration_logs] ([action],[elementID],[elementType],[ipaddress],[actorID],[doneAt]) VALUES (?,?,?,?,?,GETUTCDATE())")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [administration_logs] ([action],[elementID],[elementType],[ipaddress],[actorID],[doneAt]) VALUES (?,?,?,?,?,GETUTCDATE())")
return err
}
log.Print("Preparing addAttachment statement.")
addAttachmentStmt, err = db.Prepare("INSERT INTO [attachments] ([sectionID],[sectionTable],[originID],[originTable],[uploadedBy],[path]) VALUES (?,?,?,?,?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [attachments] ([sectionID],[sectionTable],[originID],[originTable],[uploadedBy],[path]) VALUES (?,?,?,?,?,?)")
return err
}
log.Print("Preparing createWordFilter statement.")
createWordFilterStmt, err = db.Prepare("INSERT INTO [word_filters] ([find],[replacement]) VALUES (?,?)")
if err != nil {
log.Print("Bad Query: ","INSERT INTO [word_filters] ([find],[replacement]) VALUES (?,?)")
return err
}
log.Print("Preparing addForumPermsToGroup statement.")
addForumPermsToGroupStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing replaceScheduleGroup statement.")
replaceScheduleGroupStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing addRepliesToTopic statement.")
addRepliesToTopicStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing removeRepliesFromTopic statement.")
removeRepliesFromTopicStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing addTopicsToForum statement.")
addTopicsToForumStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing removeTopicsFromForum statement.")
removeTopicsFromForumStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updateForumCache statement.")
updateForumCacheStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing addLikesToTopic statement.")
addLikesToTopicStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing addLikesToReply statement.")
addLikesToReplyStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing editTopic statement.")
editTopicStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing editReply statement.")
editReplyStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing stickTopic statement.")
stickTopicStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing unstickTopic statement.")
unstickTopicStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing lockTopic statement.")
lockTopicStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing unlockTopic statement.")
unlockTopicStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updateLastIP statement.")
updateLastIPStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updateSession statement.")
updateSessionStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing setPassword statement.")
setPasswordStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing setAvatar statement.")
setAvatarStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing setUsername statement.")
setUsernameStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing changeGroup statement.")
changeGroupStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing activateUser statement.")
activateUserStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updateUserLevel statement.")
updateUserLevelStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing incrementUserScore statement.")
incrementUserScoreStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing incrementUserPosts statement.")
incrementUserPostsStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing incrementUserBigposts statement.")
incrementUserBigpostsStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing incrementUserMegaposts statement.")
incrementUserMegapostsStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing incrementUserTopics statement.")
incrementUserTopicsStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing editProfileReply statement.")
editProfileReplyStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updateForum statement.")
updateForumStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updateSetting statement.")
updateSettingStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updatePlugin statement.")
updatePluginStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updatePluginInstall statement.")
updatePluginInstallStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updateTheme statement.")
updateThemeStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updateUser statement.")
updateUserStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updateGroupPerms statement.")
updateGroupPermsStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updateGroupRank statement.")
updateGroupRankStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updateGroup statement.")
updateGroupStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updateEmail statement.")
updateEmailStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing verifyEmail statement.")
verifyEmailStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing setTempGroup statement.")
setTempGroupStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing updateWordFilter statement.")
updateWordFilterStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing bumpSync statement.")
bumpSyncStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing deleteReply statement.")
deleteReplyStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing deleteProfileReply statement.")
deleteProfileReplyStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing deleteForumPermsByForum statement.")
deleteForumPermsByForumStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing deleteActivityStreamMatch statement.")
deleteActivityStreamMatchStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing deleteWordFilter statement.")
deleteWordFilterStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing reportExists statement.")
reportExistsStmt, err = db.Prepare("SELECT COUNT(*) AS [count] FROM [topics] WHERE [data] = ? AND [data] != '' AND [parentID] = 1")
if err != nil {
log.Print("Bad Query: ","SELECT COUNT(*) AS [count] FROM [topics] WHERE [data] = ? AND [data] != '' AND [parentID] = 1")
return err
}
log.Print("Preparing groupCount statement.")
groupCountStmt, err = db.Prepare("SELECT COUNT(*) AS [count] FROM [users_groups]")
if err != nil {
log.Print("Bad Query: ","SELECT COUNT(*) AS [count] FROM [users_groups]")
return err
}
log.Print("Preparing modlogCount statement.")
modlogCountStmt, err = db.Prepare("SELECT COUNT(*) AS [count] FROM [moderation_logs]")
if err != nil {
log.Print("Bad Query: ","SELECT COUNT(*) AS [count] FROM [moderation_logs]")
return err
}
log.Print("Preparing addForumPermsToForumAdmins statement.")
addForumPermsToForumAdminsStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing addForumPermsToForumStaff statement.")
addForumPermsToForumStaffStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing addForumPermsToForumMembers statement.")
addForumPermsToForumMembersStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
log.Print("Preparing notifyWatchers statement.")
notifyWatchersStmt, err = db.Prepare("")
if err != nil {
log.Print("Bad Query: ","")
return err
}
return nil
}

View File

@ -1,4 +1,4 @@
// +build !pgsql !sqlite !mssql // +build !pgsql, !sqlite, !mssql
/* This file was generated by Gosora's Query Generator. Please try to avoid modifying this file, as it might change at any time. */ /* This file was generated by Gosora's Query Generator. Please try to avoid modifying this file, as it might change at any time. */
@ -350,7 +350,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 `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` = ? LIMIT ?,?")
if err != nil { if err != nil {
return err return err
} }

View File

@ -3,6 +3,7 @@ package main
import ( import (
//"os" //"os"
"bytes" "bytes"
"errors"
"log" "log"
"strconv" "strconv"
"strings" "strings"
@ -12,24 +13,57 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"time" "time"
"./install/install"
//"runtime/pprof" //"runtime/pprof"
//_ "github.com/go-sql-driver/mysql" //_ "github.com/go-sql-driver/mysql"
//"github.com/erikstmartin/go-testdb" //"github.com/erikstmartin/go-testdb"
//"github.com/husobee/vestigo" //"github.com/husobee/vestigo"
) )
var dbTest *sql.DB //var dbTest *sql.DB
var dbProd *sql.DB var dbProd *sql.DB
var gloinited bool var gloinited bool
func gloinit() error { func gloinit() (err error) {
dev.DebugMode = false dev.DebugMode = false
//nogrouplog = true //nogrouplog = true
startTime = time.Now() startTime = time.Now()
processConfig()
err := initThemes() err = processConfig()
if err != nil {
return err
}
err = initThemes()
if err != nil {
return err
}
switchToTestDB()
adap, ok := install.Lookup(dbAdapter)
if !ok {
return errors.New("We couldn't find the adapter '" + dbAdapter + "'")
}
adap.SetConfig(dbConfig.Host, dbConfig.Username, dbConfig.Password, dbConfig.Dbname, dbConfig.Port)
err = adap.InitDatabase()
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
} }

View File

@ -4,6 +4,9 @@ go get -u github.com/go-sql-driver/mysql
echo "Installing the PostgreSQL Driver" echo "Installing the PostgreSQL Driver"
go get -u github.com/lib/pq go get -u github.com/lib/pq
echo "Installing the MSSQL Driver"
go get -u github.com/denisenkom/go-mssqldb
echo "Installing bcrypt" echo "Installing bcrypt"
go get -u golang.org/x/crypto/bcrypt go get -u golang.org/x/crypto/bcrypt
@ -16,9 +19,10 @@ go get -u github.com/gorilla/websocket
echo "Installing Sourcemap (dependency for OttoJS)" echo "Installing Sourcemap (dependency for OttoJS)"
go get -u gopkg.in/sourcemap.v1 go get -u gopkg.in/sourcemap.v1
echo "Install OttoJS" echo "Installing OttoJS"
go get -u github.com/robertkrimen/otto go get -u github.com/robertkrimen/otto
echo "Building the installer" echo "Building the installer"
cd ./install cd ./install
go generate go generate

View File

@ -15,6 +15,13 @@ if %errorlevel% neq 0 (
exit /b %errorlevel% exit /b %errorlevel%
) )
echo Installing the MSSQL Driver
go get -u github.com/denisenkom/go-mssqldb
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
echo Installing the bcrypt library echo Installing the bcrypt library
go get -u golang.org/x/crypto/bcrypt go get -u golang.org/x/crypto/bcrypt
if %errorlevel% neq 0 ( if %errorlevel% neq 0 (
@ -64,6 +71,7 @@ if %errorlevel% neq 0 (
exit /b %errorlevel% exit /b %errorlevel%
) )
echo Building the installer echo Building the installer
go generate go generate
go build ./install go build ./install

View File

@ -8,27 +8,17 @@ package main
import ( import (
"bufio" "bufio"
"database/sql" "errors"
"fmt" "fmt"
"os" "os"
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"../query_gen/lib" "./install"
) )
const saltLength int = 32
var db *sql.DB
var scanner *bufio.Scanner var scanner *bufio.Scanner
var dbAdapter = "mysql"
var dbHost string
var dbUsername string
var dbPassword string
var dbName string
var dbPort string
var siteShortName string var siteShortName string
var siteName string var siteName string
var siteURL string var siteURL string
@ -43,13 +33,8 @@ var defaultSiteName = "Site Name"
var defaultsiteURL = "localhost" var defaultsiteURL = "localhost"
var defaultServerPort = "80" // 8080's a good one, if you're testing and don't want it to clash with port 80 var defaultServerPort = "80" // 8080's a good one, if you're testing and don't want it to clash with port 80
// func() error, removing type to satisfy lint
var initDatabase = _initMysql
var tableDefs = _tableDefsMysql
var initialData = _initialDataMysql
func main() { func main() {
// Capture panics rather than immediately closing the window on Windows // Capture panics instead of closing the window at a superhuman speed before the user can read the message on Windows
defer func() { defer func() {
r := recover() r := recover()
if r != nil { if r != nil {
@ -63,15 +48,15 @@ func main() {
scanner = bufio.NewScanner(os.Stdin) scanner = bufio.NewScanner(os.Stdin)
fmt.Println("Welcome to Gosora's Installer") fmt.Println("Welcome to Gosora's Installer")
fmt.Println("We're going to take you through a few steps to help you get started :)") fmt.Println("We're going to take you through a few steps to help you get started :)")
if !getDatabaseDetails() { adap, ok := handleDatabaseDetails()
if !ok {
err := scanner.Err() err := scanner.Err()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} else { } else {
fmt.Println("Something went wrong!") err = errors.New("Something went wrong!")
} }
fmt.Println("Aborting installation...") abortError(err)
pressAnyKey()
return return
} }
@ -80,73 +65,36 @@ func main() {
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} else { } else {
fmt.Println("Something went wrong!") err = errors.New("Something went wrong!")
} }
fmt.Println("Aborting installation...") abortError(err)
pressAnyKey()
return return
} }
err := initDatabase() err := adap.InitDatabase()
if err != nil { if err != nil {
fmt.Println(err) abortError(err)
fmt.Println("Aborting installation...")
pressAnyKey()
return return
} }
err = tableDefs() err = adap.TableDefs()
if err != nil { if err != nil {
fmt.Println(err) abortError(err)
fmt.Println("Aborting installation...")
pressAnyKey()
return return
} }
hashedPassword, salt, err := BcryptGeneratePassword("password") err = adap.CreateAdmin()
if err != nil { if err != nil {
fmt.Println(err) abortError(err)
fmt.Println("Aborting installation...")
pressAnyKey()
return return
} }
// Build the admin user query err = adap.InitialData()
adminUserStmt, err := qgen.Builder.SimpleInsert("users", "name, password, salt, email, group, is_super_admin, active, createdAt, lastActiveAt, message, last_ip", "'Admin',?,?,'admin@localhost',1,1,1,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'','127.0.0.1'")
if err != nil { if err != nil {
fmt.Println(err) abortError(err)
fmt.Println("Aborting installation...")
pressAnyKey()
return return
} }
// Run the admin user query
_, err = adminUserStmt.Exec(hashedPassword, salt)
if err != nil {
fmt.Println(err)
fmt.Println("Aborting installation...")
pressAnyKey()
return
}
err = initialData()
if err != nil {
fmt.Println(err)
fmt.Println("Aborting installation...")
pressAnyKey()
return
}
if dbAdapter == "mysql" {
err = _mysqlSeedDatabase()
if err != nil {
fmt.Println(err)
fmt.Println("Aborting installation...")
pressAnyKey()
return
}
}
configContents := []byte(`package main configContents := []byte(`package main
func init() { func init() {
@ -164,11 +112,18 @@ func init() {
site.Language = "english" site.Language = "english"
// Database details // Database details
dbConfig.Host = "` + dbHost + `" dbConfig.Host = "` + adap.DbHost() + `"
dbConfig.Username = "` + dbUsername + `" dbConfig.Username = "` + adap.DbUsername() + `"
dbConfig.Password = "` + dbPassword + `" dbConfig.Password = "` + adap.DbPassword() + `"
dbConfig.Dbname = "` + dbName + `" dbConfig.Dbname = "` + adap.DbName() + `"
dbConfig.Port = "` + dbPort + `" // You probably won't need to change this dbConfig.Port = "` + adap.DbPort() + `" // You probably won't need to change this
// Test Database details
dbConfig.TestHost = ""
dbConfig.TestUsername = ""
dbConfig.TestPassword = ""
dbConfig.TestDbname = "" // The name of the test database, leave blank to disable. DON'T USE YOUR PRODUCTION DATABASE FOR THIS. LEAVE BLANK IF YOU DON'T KNOW WHAT THIS MEANS.
dbConfig.TestPort = ""
// Limiters // Limiters
config.MaxRequestSize = 5 * megabyte config.MaxRequestSize = 5 * megabyte
@ -202,24 +157,21 @@ func init() {
//dev.SuperDebug = true //dev.SuperDebug = true
//dev.TemplateDebug = true //dev.TemplateDebug = true
//dev.Profiling = true //dev.Profiling = true
//dev.TestDB = true
} }
`) `)
fmt.Println("Opening the configuration file") fmt.Println("Opening the configuration file")
configFile, err := os.Create("./config.go") configFile, err := os.Create("./config.go")
if err != nil { if err != nil {
fmt.Println(err) abortError(err)
fmt.Println("Aborting installation...")
pressAnyKey()
return return
} }
fmt.Println("Writing to the configuration file...") fmt.Println("Writing to the configuration file...")
_, err = configFile.Write(configContents) _, err = configFile.Write(configContents)
if err != nil { if err != nil {
fmt.Println(err) abortError(err)
fmt.Println("Aborting installation...")
pressAnyKey()
return return
} }
@ -232,21 +184,39 @@ func init() {
pressAnyKey() pressAnyKey()
} }
func getDatabaseDetails() bool { func abortError(err error) {
fmt.Println("Which database driver do you wish to use? mysql, mysql, or mysql? Default: mysql") fmt.Println(err)
fmt.Println("Aborting installation...")
pressAnyKey()
}
func handleDatabaseDetails() (adap install.InstallAdapter, ok bool) {
var dbHost string
var dbUsername string
var dbPassword string
var dbName string
var dbPort string
for {
fmt.Println("Which database adapter do you wish to use? mysql, mysql, or mysql? Default: mysql")
if !scanner.Scan() { if !scanner.Scan() {
return false return nil, false
} }
dbAdapter = scanner.Text() dbAdapter := scanner.Text()
if dbAdapter == "" { if dbAdapter == "" {
dbAdapter = defaultAdapter dbAdapter = defaultAdapter
} }
dbAdapter = setDBAdapter(dbAdapter) adap, ok = install.Lookup(dbAdapter)
if ok {
break
}
fmt.Println("That adapter doesn't exist")
}
fmt.Println("Set database adapter to " + dbAdapter) fmt.Println("Set database adapter to " + dbAdapter)
fmt.Println("Database Host? Default: " + defaultHost) fmt.Println("Database Host? Default: " + defaultHost)
if !scanner.Scan() { if !scanner.Scan() {
return false return nil, false
} }
dbHost = scanner.Text() dbHost = scanner.Text()
if dbHost == "" { if dbHost == "" {
@ -256,7 +226,7 @@ func getDatabaseDetails() bool {
fmt.Println("Database Username? Default: " + defaultUsername) fmt.Println("Database Username? Default: " + defaultUsername)
if !scanner.Scan() { if !scanner.Scan() {
return false return nil, false
} }
dbUsername = scanner.Text() dbUsername = scanner.Text()
if dbUsername == "" { if dbUsername == "" {
@ -266,7 +236,7 @@ func getDatabaseDetails() bool {
fmt.Println("Database Password? Default: ''") fmt.Println("Database Password? Default: ''")
if !scanner.Scan() { if !scanner.Scan() {
return false return nil, false
} }
dbPassword = scanner.Text() dbPassword = scanner.Text()
if len(dbPassword) == 0 { if len(dbPassword) == 0 {
@ -278,14 +248,16 @@ func getDatabaseDetails() bool {
fmt.Println("Database Name? Pick a name you like or one provided to you. Default: " + defaultDbname) fmt.Println("Database Name? Pick a name you like or one provided to you. Default: " + defaultDbname)
if !scanner.Scan() { if !scanner.Scan() {
return false return nil, false
} }
dbName = scanner.Text() dbName = scanner.Text()
if dbName == "" { if dbName == "" {
dbName = defaultDbname dbName = defaultDbname
} }
fmt.Println("Set database name to " + dbName) fmt.Println("Set database name to " + dbName)
return true
adap.SetConfig(dbHost, dbUsername, dbPassword, dbName, adap.DefaultPort())
return adap, true
} }
func getSiteDetails() bool { func getSiteDetails() bool {
@ -338,16 +310,6 @@ func getSiteDetails() bool {
return true return true
} }
func setDBAdapter(name string) string {
switch name {
//case "wip-pgsql":
// set_pgsql_adapter()
// return "wip-pgsql"
}
_setMysqlAdapter()
return "mysql"
}
func obfuscatePassword(password string) (out string) { func obfuscatePassword(password string) (out string) {
for i := 0; i < len(password); i++ { for i := 0; i < len(password); i++ {
out += "*" out += "*"

View File

@ -0,0 +1,45 @@
package install
import (
"../../query_gen/lib"
)
var adapters = make(map[string]InstallAdapter)
type InstallAdapter interface {
Name() string
DefaultPort() string
SetConfig(dbHost string, dbUsername string, dbPassword string, dbName string, dbPort string)
InitDatabase() error
TableDefs() error
InitialData() error
CreateAdmin() error
DBHost() string
DBUsername() string
DBPassword() string
DBName() string
DBPort() string
}
func Lookup(name string) (InstallAdapter, bool) {
adap, ok := adapters[name]
return adap, ok
}
func createAdmin() error {
hashedPassword, salt, err := BcryptGeneratePassword("password")
if err != nil {
return err
}
// Build the admin user query
adminUserStmt, err := qgen.Builder.SimpleInsert("users", "name, password, salt, email, group, is_super_admin, active, createdAt, lastActiveAt, message, last_ip", "'Admin',?,?,'admin@localhost',1,1,1,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'','127.0.0.1'")
if err != nil {
return err
}
// Run the admin user query
_, err = adminUserStmt.Exec(hashedPassword, salt)
return err
}

173
install/install/mssql.go Normal file
View File

@ -0,0 +1,173 @@
/*
*
* Gosora MSSQL Interface
* Under heavy development
* Copyright Azareal 2017 - 2018
*
*/
package install
import (
"bytes"
"database/sql"
"fmt"
"io/ioutil"
"log"
"net/url"
"path/filepath"
"strconv"
"strings"
"../../query_gen/lib"
_ "github.com/denisenkom/go-mssqldb"
)
func init() {
adapters["mssql"] = &MssqlInstaller{dbHost: ""}
}
type MssqlInstaller struct {
db *sql.DB
dbHost string
dbUsername string
dbPassword string
dbName string
dbInstance string
dbPort string
}
func (ins *MssqlInstaller) SetConfig(dbHost string, dbUsername string, dbPassword string, dbName string, dbPort string) {
ins.dbHost = dbHost
ins.dbUsername = dbUsername
ins.dbPassword = dbPassword
ins.dbName = dbName
ins.dbInstance = "" // You can't set this from the installer right now, it allows you to connect to a named instance instead of a port
ins.dbPort = dbPort
}
func (ins *MssqlInstaller) Name() string {
return "mssql"
}
func (ins *MssqlInstaller) DefaultPort() string {
return "1433"
}
func (ins *MssqlInstaller) InitDatabase() (err error) {
query := url.Values{}
query.Add("database", ins.dbName)
u := &url.URL{
Scheme: "sqlserver",
User: url.UserPassword(ins.dbUsername, ins.dbPassword),
Host: ins.dbHost + ":" + ins.dbPort,
Path: ins.dbInstance,
RawQuery: query.Encode(),
}
log.Print("u.String() ", u.String())
db, err := sql.Open("mssql", u.String())
if err != nil {
return err
}
// Make sure that the connection is alive..
err = db.Ping()
if err != nil {
return err
}
fmt.Println("Successfully connected to the database")
// TODO: Create the database, if it doesn't exist
// Ready the query builder
qgen.Builder.SetConn(db)
err = qgen.Builder.SetAdapter("mssql")
if err != nil {
return err
}
ins.db = db
return nil
}
func (ins *MssqlInstaller) TableDefs() (err error) {
//fmt.Println("Creating the tables")
files, _ := ioutil.ReadDir("./schema/mssql/")
for _, f := range files {
if !strings.HasPrefix(f.Name(), "query_") {
continue
}
var table, ext string
table = strings.TrimPrefix(f.Name(), "query_")
ext = filepath.Ext(table)
if ext != ".sql" {
continue
}
table = strings.TrimSuffix(table, ext)
fmt.Println("Creating table '" + table + "'")
data, err := ioutil.ReadFile("./schema/mssql/" + f.Name())
if err != nil {
return err
}
data = bytes.TrimSpace(data)
_, err = ins.db.Exec(string(data))
if err != nil {
fmt.Println("Failed query:", string(data))
return err
}
}
//fmt.Println("Finished creating the tables")
return nil
}
func (ins *MssqlInstaller) InitialData() (err error) {
//fmt.Println("Seeding the tables")
data, err := ioutil.ReadFile("./schema/mssql/inserts.sql")
if err != nil {
return err
}
data = bytes.TrimSpace(data)
statements := bytes.Split(data, []byte(";"))
for key, statement := range statements {
if len(statement) == 0 {
continue
}
fmt.Println("Executing query #" + strconv.Itoa(key) + " " + string(statement))
_, err = ins.db.Exec(string(statement))
if err != nil {
return err
}
}
//fmt.Println("Finished inserting the database data")
return nil
}
func (ins *MssqlInstaller) CreateAdmin() error {
return createAdmin()
}
func (ins *MssqlInstaller) DBHost() string {
return ins.dbHost
}
func (ins *MssqlInstaller) DBUsername() string {
return ins.dbUsername
}
func (ins *MssqlInstaller) DBPassword() string {
return ins.dbPassword
}
func (ins *MssqlInstaller) DBName() string {
return ins.dbName
}
func (ins *MssqlInstaller) DBPort() string {
return ins.dbPort
}

View File

@ -4,7 +4,7 @@
* Copyright Azareal 2017 - 2018 * Copyright Azareal 2017 - 2018
* *
*/ */
package main package install
import ( import (
"bytes" "bytes"
@ -15,25 +15,47 @@ import (
"strconv" "strconv"
"strings" "strings"
"../query_gen/lib" "../../query_gen/lib"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
) )
//var dbCollation string = "utf8mb4_general_ci" //var dbCollation string = "utf8mb4_general_ci"
func _setMysqlAdapter() { func init() {
dbPort = "3306" adapters["mysql"] = &MysqlInstaller{dbHost: ""}
initDatabase = _initMysql
tableDefs = _tableDefsMysql
initialData = _initialDataMysql
} }
func _initMysql() (err error) { type MysqlInstaller struct {
_dbPassword := dbPassword db *sql.DB
dbHost string
dbUsername string
dbPassword string
dbName string
dbPort string
}
func (ins *MysqlInstaller) SetConfig(dbHost string, dbUsername string, dbPassword string, dbName string, dbPort string) {
ins.dbHost = dbHost
ins.dbUsername = dbUsername
ins.dbPassword = dbPassword
ins.dbName = dbName
ins.dbPort = dbPort
}
func (ins *MysqlInstaller) Name() string {
return "mysql"
}
func (ins *MysqlInstaller) DefaultPort() string {
return "3306"
}
func (ins *MysqlInstaller) InitDatabase() (err error) {
_dbPassword := ins.dbPassword
if _dbPassword != "" { if _dbPassword != "" {
_dbPassword = ":" + _dbPassword _dbPassword = ":" + _dbPassword
} }
db, err = sql.Open("mysql", dbUsername+_dbPassword+"@tcp("+dbHost+":"+dbPort+")/") db, err := sql.Open("mysql", ins.dbUsername+_dbPassword+"@tcp("+ins.dbHost+":"+ins.dbPort+")/")
if err != nil { if err != nil {
return err return err
} }
@ -46,22 +68,22 @@ func _initMysql() (err error) {
fmt.Println("Successfully connected to the database") fmt.Println("Successfully connected to the database")
var waste string var waste string
err = db.QueryRow("SHOW DATABASES LIKE '" + dbName + "'").Scan(&waste) err = db.QueryRow("SHOW DATABASES LIKE '" + ins.dbName + "'").Scan(&waste)
if err != nil && err != sql.ErrNoRows { if err != nil && err != sql.ErrNoRows {
return err return err
} }
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
fmt.Println("Unable to find the database. Attempting to create it") fmt.Println("Unable to find the database. Attempting to create it")
_, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + dbName) _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + ins.dbName)
if err != nil { if err != nil {
return err return err
} }
fmt.Println("The database was successfully created") fmt.Println("The database was successfully created")
} }
fmt.Println("Switching to database " + dbName) fmt.Println("Switching to database " + ins.dbName)
_, err = db.Exec("USE " + dbName) _, err = db.Exec("USE " + ins.dbName)
if err != nil { if err != nil {
return err return err
} }
@ -73,10 +95,11 @@ func _initMysql() (err error) {
return err return err
} }
ins.db = db
return nil return nil
} }
func _tableDefsMysql() error { func (ins *MysqlInstaller) TableDefs() error {
//fmt.Println("Creating the tables") //fmt.Println("Creating the tables")
files, _ := ioutil.ReadDir("./schema/mysql/") files, _ := ioutil.ReadDir("./schema/mysql/")
for _, f := range files { for _, f := range files {
@ -99,7 +122,7 @@ func _tableDefsMysql() error {
} }
data = bytes.TrimSpace(data) data = bytes.TrimSpace(data)
_, err = db.Exec(string(data)) _, err = ins.db.Exec(string(data))
if err != nil { if err != nil {
fmt.Println("Failed query:", string(data)) fmt.Println("Failed query:", string(data))
return err return err
@ -113,47 +136,51 @@ func _tableDefsMysql() error {
/* TODO: Implement the html-attribute setting type before deploying this */ /* TODO: Implement the html-attribute setting type before deploying this */
/*INSERT INTO settings(`name`,`content`,`type`) VALUES ('meta_desc','','html-attribute');*/ /*INSERT INTO settings(`name`,`content`,`type`) VALUES ('meta_desc','','html-attribute');*/
func _initialDataMysql() error { func (ins *MysqlInstaller) InitialData() error {
return nil // Coming Soon //fmt.Println("Seeding the tables")
/*fmt.Println("Seeding the tables")
data, err := ioutil.ReadFile("./schema/mysql/inserts.sql") data, err := ioutil.ReadFile("./schema/mysql/inserts.sql")
if err != nil { if err != nil {
return err return err
} }
data = bytes.TrimSpace(data) data = bytes.TrimSpace(data)
fmt.Println("Executing query",string(data)) statements := bytes.Split(data, []byte(";"))
_, err = db.Exec(string(data))
if err != nil {
return err
}
//fmt.Println("Finished inserting the database data")
return nil*/
}
func _mysqlSeedDatabase() error {
fmt.Println("Opening the database seed file")
sqlContents, err := ioutil.ReadFile("./mysql.sql")
if err != nil {
return err
}
fmt.Println("Preparing installation queries")
sqlContents = bytes.TrimSpace(sqlContents)
statements := bytes.Split(sqlContents, []byte(";"))
for key, statement := range statements { for key, statement := range statements {
if len(statement) == 0 { if len(statement) == 0 {
continue continue
} }
fmt.Println("Executing query #" + strconv.Itoa(key) + " " + string(statement)) fmt.Println("Executing query #" + strconv.Itoa(key) + " " + string(statement))
_, err = db.Exec(string(statement)) _, err = ins.db.Exec(string(statement))
if err != nil { if err != nil {
return err return err
} }
} }
fmt.Println("Finished inserting the database data")
//fmt.Println("Finished inserting the database data")
return nil return nil
} }
func (ins *MysqlInstaller) CreateAdmin() error {
return createAdmin()
}
func (ins *MysqlInstaller) DBHost() string {
return ins.dbHost
}
func (ins *MysqlInstaller) DBUsername() string {
return ins.dbUsername
}
func (ins *MysqlInstaller) DBPassword() string {
return ins.dbPassword
}
func (ins *MysqlInstaller) DBName() string {
return ins.dbName
}
func (ins *MysqlInstaller) DBPort() string {
return ins.dbPort
}

117
install/install/pgsql.go Normal file
View File

@ -0,0 +1,117 @@
/*
*
* Gosora PostgreSQL Interface
* Under heavy development
* Copyright Azareal 2017 - 2018
*
*/
package install
import (
"database/sql"
"errors"
"fmt"
"strings"
"../../query_gen/lib"
_ "github.com/go-sql-driver/mysql"
)
// We don't need SSL to run an installer... Do we?
var dbSslmode = "disable"
func init() {
adapters["pgsql"] = &PgsqlInstaller{dbHost: ""}
}
type PgsqlInstaller struct {
db *sql.DB
dbHost string
dbUsername string
dbPassword string
dbName string
dbPort string
}
func (ins *PgsqlInstaller) SetConfig(dbHost string, dbUsername string, dbPassword string, dbName string, dbPort string) {
ins.dbHost = dbHost
ins.dbUsername = dbUsername
ins.dbPassword = dbPassword
ins.dbName = dbName
ins.dbPort = dbPort
}
func (ins *PgsqlInstaller) Name() string {
return "pgsql"
}
func (ins *PgsqlInstaller) DefaultPort() string {
return "5432"
}
func (ins *PgsqlInstaller) InitDatabase() (err error) {
_dbPassword := ins.dbPassword
if _dbPassword != "" {
_dbPassword = " password=" + pgEscapeBit(_dbPassword)
}
db, err := sql.Open("postgres", "host='"+pgEscapeBit(ins.dbHost)+"' port='"+pgEscapeBit(ins.dbPort)+"' user='"+pgEscapeBit(ins.dbUsername)+"' dbname='"+pgEscapeBit(ins.dbName)+"'"+_dbPassword+" sslmode='"+dbSslmode+"'")
if err != nil {
return err
}
// Make sure that the connection is alive..
err = db.Ping()
if err != nil {
return err
}
fmt.Println("Successfully connected to the database")
// TODO: Create the database, if it doesn't exist
// Ready the query builder
qgen.Builder.SetConn(db)
err = qgen.Builder.SetAdapter("pgsql")
if err != nil {
return err
}
ins.db = db
return nil
}
func (ins *PgsqlInstaller) TableDefs() (err error) {
return errors.New("TableDefs() not implemented")
}
func (ins *PgsqlInstaller) InitialData() (err error) {
return errors.New("InitialData() not implemented")
}
func (ins *PgsqlInstaller) CreateAdmin() error {
return createAdmin()
}
func (ins *PgsqlInstaller) DBHost() string {
return ins.dbHost
}
func (ins *PgsqlInstaller) DBUsername() string {
return ins.dbUsername
}
func (ins *PgsqlInstaller) DBPassword() string {
return ins.dbPassword
}
func (ins *PgsqlInstaller) DBName() string {
return ins.dbName
}
func (ins *PgsqlInstaller) DBPort() string {
return ins.dbPort
}
func pgEscapeBit(bit string) string {
// TODO: Write a custom parser, so that backslashes work properly in the sql.Open string. Do something similar for the database driver, if possible?
return strings.Replace(bit, "'", "\\'", -1)
}

View File

@ -1,9 +1,11 @@
package main package install
import "encoding/base64" import "encoding/base64"
import "crypto/rand" import "crypto/rand"
import "golang.org/x/crypto/bcrypt" import "golang.org/x/crypto/bcrypt"
const saltLength int = 32
// Generate a cryptographically secure set of random bytes.. // Generate a cryptographically secure set of random bytes..
func GenerateSafeString(length int) (string, error) { func GenerateSafeString(length int) (string, error) {
rb := make([]byte, length) rb := make([]byte, length)

View File

@ -1,42 +0,0 @@
/*
*
* Gosora PostgreSQL Interface
* Under heavy development
* Copyright Azareal 2017 - 2018
*
*/
package main
import "fmt"
import "strings"
import "database/sql"
import _ "github.com/go-sql-driver/mysql"
// We don't need SSL to run an installer... Do we?
var dbSslmode = "disable"
func _setPgsqlAdapter() {
dbPort = "5432"
initDatabase = _initPgsql
}
func _initPgsql() (err error) {
_dbPassword := dbPassword
if _dbPassword != "" {
_dbPassword = " password=" + _pgEscapeBit(_dbPassword)
}
db, err = sql.Open("postgres", "host='"+_pgEscapeBit(dbHost)+"' port='"+_pgEscapeBit(dbPort)+"' user='"+_pgEscapeBit(dbUsername)+"' dbname='"+_pgEscapeBit(dbName)+"'"+_dbPassword+" sslmode='"+dbSslmode+"'")
if err != nil {
return err
}
fmt.Println("Successfully connected to the database")
// TODO: Create the database, if it doesn't exist
return nil
}
func _pgEscapeBit(bit string) string {
// TODO: Write a custom parser, so that backslashes work properly in the sql.Open string. Do something similar for the database driver, if possible?
return strings.Replace(bit, "'", "\\'", -1)
}

View File

@ -46,7 +46,7 @@ type StringList []string
var allowedFileExts = StringList{ var allowedFileExts = StringList{
"png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp", "apng", // images "png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp", "apng", // images
"txt", "xml", "json", "yaml", "toml", "ini", "md", "html", "rtf", "js", "py", "rb", "css", "scss", "less", "java", "ts", "cs", "c", "cc", "cpp", "cxx", "C", "c++", "h", "hh", "hpp", "hxx", "h++", "rs", "rlib", "htaccess", "gitignore", // text "txt", "xml", "json", "yaml", "toml", "ini", "md", "html", "rtf", "js", "py", "rb", "css", "scss", "less", "eqcss", "java", "ts", "cs", "c", "cc", "cpp", "cxx", "C", "c++", "h", "hh", "hpp", "hxx", "h++", "rs", "rlib", "htaccess", "gitignore", // text
"mp3", "mp4", "avi", "wmv", "webm", // video "mp3", "mp4", "avi", "wmv", "webm", // video
@ -92,7 +92,10 @@ func main() {
startTime = time.Now() startTime = time.Now()
log.Print("Processing configuration data") log.Print("Processing configuration data")
processConfig() err = processConfig()
if err != nil {
log.Fatal(err)
}
err = initThemes() err = initThemes()
if err != nil { if err != nil {

View File

@ -4,7 +4,6 @@ import (
//"log" //"log"
//"fmt" //"fmt"
"html" "html"
"log"
"net" "net"
"net/http" "net/http"
"strconv" "strconv"
@ -48,8 +47,6 @@ func routeEditTopic(w http.ResponseWriter, r *http.Request, user User) {
topicName := r.PostFormValue("topic_name") topicName := r.PostFormValue("topic_name")
topicContent := html.EscapeString(r.PostFormValue("topic_content")) topicContent := html.EscapeString(r.PostFormValue("topic_content"))
log.Print("topicContent ", topicContent)
err = topic.Update(topicName, topicContent) err = topic.Update(topicName, topicContent)
if err != nil { if err != nil {
InternalErrorJSQ(err, w, r, isJs) InternalErrorJSQ(err, w, r, isJs)

84
mssql.go Normal file
View File

@ -0,0 +1,84 @@
// +build mssql
/*
*
* Gosora MSSQL Interface
* Copyright Azareal 2016 - 2018
*
*/
package main
//import "time"
import (
"database/sql"
"net/url"
"./query_gen/lib"
_ "github.com/denisenkom/go-mssqldb"
)
var dbInstance string = ""
var getActivityFeedByWatcherStmt *sql.Stmt
var getActivityCountByWatcherStmt *sql.Stmt
var todaysPostCountStmt *sql.Stmt
var todaysTopicCountStmt *sql.Stmt
var todaysReportCountStmt *sql.Stmt
var todaysNewUserCountStmt *sql.Stmt
var findUsersByIPUsersStmt *sql.Stmt
var findUsersByIPTopicsStmt *sql.Stmt
var findUsersByIPRepliesStmt *sql.Stmt
func init() {
dbAdapter = "mssql"
_initDatabase = initMSSQL
}
func initMSSQL() (err error) {
// TODO: Move this bit to the query gen lib
query := url.Values{}
query.Add("database", dbConfig.Dbname)
u := &url.URL{
Scheme: "sqlserver",
User: url.UserPassword(dbConfig.Username, dbConfig.Password),
Host: dbConfig.Host + ":" + dbConfig.Port,
Path: dbInstance,
RawQuery: query.Encode(),
}
db, err = sql.Open("mssql", u.String())
if err != nil {
return err
}
// Make sure that the connection is alive
err = db.Ping()
if err != nil {
return err
}
// TODO: Fetch the database version
// Set the number of max open connections
db.SetMaxOpenConns(64)
db.SetMaxIdleConns(32)
// Only hold connections open for five seconds to avoid accumulating a large number of stale connections
//db.SetConnMaxLifetime(5 * time.Second)
// Build the generated prepared statements, we are going to slowly move the queries over to the query generator rather than writing them all by hand, this'll make it easier for us to implement database adapters for other databases like PostgreSQL, MSSQL, SQlite, etc.
err = _gen_mssql()
if err != nil {
return err
}
// Ready the query builder
qgen.Builder.SetConn(db)
err = qgen.Builder.SetAdapter("mssql")
if err != nil {
return err
}
// TODO: Add the custom queries
return nil
}

View File

@ -1,4 +1,4 @@
// +build !pgsql !sqlite !mssql // +build !pgsql, !sqlite, !mssql
/* /*
* *
@ -28,16 +28,18 @@ var findUsersByIPRepliesStmt *sql.Stmt
func init() { func init() {
dbAdapter = "mysql" dbAdapter = "mysql"
_initDatabase = initMySQL
} }
func _initDatabase() (err error) { func initMySQL() (err error) {
var _dbpassword string var _dbpassword string
if dbConfig.Password != "" { if dbConfig.Password != "" {
_dbpassword = ":" + dbConfig.Password _dbpassword = ":" + dbConfig.Password
} }
// TODO: Move this bit to the query gen lib
// Open the database connection // Open the database connection
db, err = sql.Open("mysql", dbConfig.Username+_dbpassword+"@tcp("+dbConfig.Host+":"+dbConfig.Port+")/"+dbConfig.Dbname+"?collation="+dbCollation) db, err = sql.Open("mysql", dbConfig.Username+_dbpassword+"@tcp("+dbConfig.Host+":"+dbConfig.Port+")/"+dbConfig.Dbname+"?collation="+dbCollation+"&parseTime=true")
if err != nil { if err != nil {
return err return err
} }

269
mysql.sql
View File

@ -1,269 +0,0 @@
CREATE TABLE `users_groups`(
`gid` int not null AUTO_INCREMENT,
`name` varchar(100) not null,
`permissions` text not null,
`plugin_perms` text not null,
`is_mod` tinyint DEFAULT 0 not null,
`is_admin` tinyint DEFAULT 0 not null,
`is_banned` tinyint DEFAULT 0 not null,
`tag` varchar(50) DEFAULT '' not null,
primary key(`gid`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
CREATE TABLE `emails`(
`email` varchar(200) not null,
`uid` int not null,
`validated` tinyint DEFAULT 0 not null,
`token` varchar(200) DEFAULT '' not null
);
CREATE TABLE `forums`(
`fid` int not null AUTO_INCREMENT,
`name` varchar(100) not null,
`desc` varchar(200) not null,
`active` tinyint DEFAULT 1 not null,
`topicCount` int DEFAULT 0 not null,
`preset` varchar(100) DEFAULT '' not null,
`parentID` int DEFAULT 0 not null, /* TODO: Add support for subforums */
`parentType` varchar(50) DEFAULT '' not null,
`lastTopicID` int DEFAULT 0 not null,
`lastReplyerID` int DEFAULT 0 not null,
primary key(`fid`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
CREATE TABLE `forums_permissions`(
`fid` int not null,
`gid` int not null,
`preset` varchar(100) DEFAULT '' not null,
`permissions` text not null,
primary key(fid, gid)
);
CREATE TABLE `topics`(
`tid` int not null AUTO_INCREMENT,
`title` varchar(100) not null,
`content` text not null,
`parsed_content` text not null,
`createdAt` datetime not null,
`lastReplyAt` datetime not null,
`lastReplyBy` int not null,
`createdBy` int not null,
`is_closed` tinyint DEFAULT 0 not null,
`sticky` tinyint DEFAULT 0 not null,
`parentID` int DEFAULT 2 not null,
`ipaddress` varchar(200) DEFAULT '0.0.0.0.0' not null,
`postCount` int DEFAULT 1 not null,
`likeCount` int DEFAULT 0 not null,
`words` int DEFAULT 0 not null,
`css_class` varchar(100) DEFAULT '' not null,
`data` varchar(200) DEFAULT '' not null,
primary key(`tid`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
CREATE TABLE `replies`(
`rid` int not null AUTO_INCREMENT,
`tid` int not null,
`content` text not null,
`parsed_content` text not null,
`createdAt` datetime not null,
`createdBy` int not null,
`lastEdit` int not null,
`lastEditBy` int not null, /* Do we need this? */
/*`editIndex` int not null,*/ /* For append edits, e.g. auto-merges? Is this enough for this feature? */
`lastUpdated` datetime not null,
`ipaddress` varchar(200) DEFAULT '0.0.0.0.0' not null,
`likeCount` int DEFAULT 0 not null,
`words` int DEFAULT 1 not null,
`actionType` varchar(20) DEFAULT '' not null,
primary key(`rid`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
CREATE TABLE `attachments`(
`attachID` int not null AUTO_INCREMENT,
`sectionID` int DEFAULT 0 not null, /* section ID */
`sectionTable` varchar(200) DEFAULT 'forums' not null, /* section table */
`originID` int not null,
`originTable` varchar(200) DEFAULT 'replies' not null,
`uploadedBy` int not null,
`path` varchar(200) not null,
primary key(`attachID`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
CREATE TABLE `revisions`(
`index` int not null,
`content` text not null,
`contentID` int not null,
`contentType` varchar(100) DEFAULT 'replies' not null
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
CREATE TABLE `users_replies`(
`rid` int not null AUTO_INCREMENT,
`uid` int not null,
`content` text not null,
`parsed_content` text not null,
`createdAt` datetime not null,
`createdBy` int not null,
`lastEdit` int not null,
`lastEditBy` int not null,
`ipaddress` varchar(200) DEFAULT '0.0.0.0.0' not null,
primary key(`rid`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
CREATE TABLE `likes`(
`weight` tinyint DEFAULT 1 not null,
/*`type` tinyint not null, /* Regular Post: 1, Big Post: 2, Mega Post: 3, etc.*/
`targetItem` int not null,
`targetType` varchar(50) DEFAULT 'replies' not null,
`sentBy` int not null,
`recalc` tinyint DEFAULT 0 not null
);
CREATE TABLE `activity_stream_matches`(
`watcher` int not null,
`asid` int not null
);
CREATE TABLE `activity_stream`(
`asid` int not null AUTO_INCREMENT,
`actor` int not null, /* the one doing the act */
`targetUser` int not null, /* the user who created the item the actor is acting on, some items like forums may lack a targetUser field */
`event` varchar(50) not null, /* 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 */
`elementType` varchar(50) not null, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
`elementID` int not null, /* the ID of the element being acted upon */
primary key(`asid`)
);
CREATE TABLE `activity_subscriptions`(
`user` int not null,
`targetID` int not null, /* the ID of the element being acted upon */
`targetType` varchar(50) not null, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
`level` tinyint DEFAULT 0 not null /* 0: Mentions (aka the global default for any post), 1: Replies To You, 2: All Replies*/
);
/* 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 */
CREATE TABLE `settings`(
`name` varchar(180) not null,
`content` varchar(250) not null,
`type` varchar(50) not null,
`constraints` varchar(200) DEFAULT '' not null,
unique(`name`)
);
CREATE TABLE `plugins`(
`uname` varchar(180) not null,
`active` tinyint DEFAULT 0 not null,
`installed` tinyint DEFAULT 0 not null,
unique(`uname`)
);
CREATE TABLE `themes`(
`uname` varchar(180) not null,
`default` tinyint DEFAULT 0 not null,
unique(`uname`)
);
CREATE TABLE `widgets`(
`position` int not null,
`side` varchar(100) not null,
`type` varchar(100) not null,
`active` tinyint(1) DEFAULT 0 not null,
`location` varchar(100) not null,
`data` text DEFAULT '' not null
);
CREATE TABLE `moderation_logs`(
`action` varchar(100) not null,
`elementID` int not null,
`elementType` varchar(100) not null,
`ipaddress` varchar(200) not null,
`actorID` int not null,
`doneAt` datetime not null
);
CREATE TABLE `administration_logs`(
`action` varchar(100) not null,
`elementID` int not null,
`elementType` varchar(100) not null,
`ipaddress` varchar(200) not null,
`actorID` int not null,
`doneAt` datetime not null
);
INSERT INTO sync(`last_update`) VALUES (UTC_TIMESTAMP());
INSERT INTO settings(`name`,`content`,`type`) VALUES ('url_tags','1','bool');
INSERT INTO settings(`name`,`content`,`type`,`constraints`) VALUES ('activation_type','1','list','1-3');
INSERT INTO settings(`name`,`content`,`type`) VALUES ('bigpost_min_words','250','int');
INSERT INTO settings(`name`,`content`,`type`) VALUES ('megapost_min_words','1000','int');
INSERT INTO themes(`uname`,`default`) VALUES ('tempra-simple',1);
INSERT INTO emails(`email`,`uid`,`validated`) VALUES ('admin@localhost',1,1);
/*
The Permissions:
Global Permissions:
BanUsers
ActivateUsers
EditUser
EditUserEmail
EditUserPassword
EditUserGroup
EditUserGroupSuperMod
EditUserGroupAdmin
EditGroup
EditGroupLocalPerms
EditGroupGlobalPerms
EditGroupSuperMod
EditGroupAdmin
ManageForums
EditSettings
ManageThemes
ManagePlugins
ViewAdminLogs
ViewIPs
Non-staff Global Permissions:
UploadFiles
Forum Permissions:
ViewTopic
LikeItem
CreateTopic
EditTopic
DeleteTopic
CreateReply
EditReply
DeleteReply
PinTopic
CloseTopic
*/
INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"UploadFiles":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}','{}',1,1,"Admin");
INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`,`is_mod`,`tag`) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"UploadFiles":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}','{}',1,"Mod");
INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`) VALUES ('Member','{"UploadFiles":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}','{}');
INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`,`is_banned`) VALUES ('Banned','{"ViewTopic":true}','{}',1);
INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`) VALUES ('Awaiting Activation','{"ViewTopic":true}','{}');
INSERT INTO users_groups(`name`,`permissions`,`plugin_perms`,`tag`) VALUES ('Not Loggedin','{"ViewTopic":true}','{}','Guest');
INSERT INTO forums(`name`,`active`) VALUES ('Reports',0);
INSERT INTO forums(`name`,`lastTopicID`,`lastReplyerID`) VALUES ("General",1,1);
INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (1,1,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"PinTopic":true,"CloseTopic":true}');
INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (2,1,'{"ViewTopic":true,"CreateReply":true,"CloseTopic":true}');
INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (3,1,'{}');
INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (4,1,'{}');
INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (5,1,'{}');
INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (6,1,'{}');
INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (1,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true,"EditTopic":true,"DeleteTopic":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}');
INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (2,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true,"EditTopic":true,"DeleteTopic":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}');
INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (3,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true}');
INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (4,2,'{"ViewTopic":true}');
INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (5,2,'{"ViewTopic":true}');
INSERT INTO forums_permissions(`gid`,`fid`,`permissions`) VALUES (6,2,'{"ViewTopic":true}');
INSERT INTO topics(`title`,`content`,`createdAt`,`lastReplyAt`,`lastReplyBy`,`createdBy`,`parentID`)
VALUES ('Test Topic','A topic automatically generated by the software.',UTC_TIMESTAMP(),UTC_TIMESTAMP(),1,1,2);
INSERT INTO replies(`tid`,`content`,`createdAt`,`createdBy`,`lastEdit`,`lastEditBy`)
VALUES (1,'Reply 1',UTC_TIMESTAMP(),1,0,0);

View File

@ -5,6 +5,7 @@
package main package main
import "strings" import "strings"
//import "time" //import "time"
import "database/sql" import "database/sql"
import _ "github.com/lib/pq" import _ "github.com/lib/pq"
@ -21,15 +22,17 @@ var todays_newuser_count_stmt *sql.Stmt
func init() { func init() {
db_adapter = "pgsql" db_adapter = "pgsql"
_initDatabase = initPgsql
} }
func _init_database() (err error) { func initPgsql() (err error) {
// TODO: Investigate connect_timeout to see what it does exactly and whether it's relevant to us // TODO: Investigate connect_timeout to see what it does exactly and whether it's relevant to us
var _dbpassword string var _dbpassword string
if(dbpassword != ""){ if dbpassword != "" {
_dbpassword = " password='" + _escape_bit(db_config.Password) + "'" _dbpassword = " password='" + _escape_bit(db_config.Password) + "'"
} }
db, err = sql.Open("postgres", "host='" + _escape_bit(db_config.Host) + "' port='" + _escape_bit(db_config.Port) + "' user='" + _escape_bit(db_config.Username) + "' dbname='" + _escape_bit(config.Dbname) + "'" + _dbpassword + " sslmode='" + db_sslmode + "'") // TODO: Move this bit to the query gen lib
db, err = sql.Open("postgres", "host='"+_escape_bit(db_config.Host)+"' port='"+_escape_bit(db_config.Port)+"' user='"+_escape_bit(db_config.Username)+"' dbname='"+_escape_bit(config.Dbname)+"'"+_dbpassword+" sslmode='"+db_sslmode+"'")
if err != nil { if err != nil {
return err return err
} }
@ -69,5 +72,5 @@ func _init_database() (err error) {
func _escape_bit(bit string) string { func _escape_bit(bit string) string {
// TODO: Write a custom parser, so that backslashes work properly in the sql.Open string. Do something similar for the database driver, if possible? // TODO: Write a custom parser, so that backslashes work properly in the sql.Open string. Do something similar for the database driver, if possible?
return strings.Replace(bit,"'","\\'",-1) return strings.Replace(bit, "'", "\\'", -1)
} }

View File

@ -388,20 +388,18 @@ func bbcodeFullParse(msg string) string {
} }
} }
} }
//log.Print(string(outbytes)) //log.Print("Outbytes:",`"`+string(outbytes)+`"`)
if lastTag != i { if lastTag != i {
outbytes = append(outbytes, msgbytes[lastTag:]...) outbytes = append(outbytes, msgbytes[lastTag:]...)
//log.Print("Outbytes:",`"`+string(outbytes)+`"`)
//log.Print("----")
} }
if len(outbytes) != 0 { if len(outbytes) != 0 {
//log.Print("BBCode Post:",`"`+string(outbytes[0:len(outbytes) - 10])+`"`) //log.Print("BBCode Post:",`"`+string(outbytes[0:len(outbytes) - 10])+`"`)
//log.Print("----")
msg = string(outbytes[0 : len(outbytes)-10]) msg = string(outbytes[0 : len(outbytes)-10])
} else { } else {
msg = string(msgbytes[0 : len(msgbytes)-10]) msg = string(msgbytes[0 : len(msgbytes)-10])
} }
//log.Print("----")
//msg = bbcode_url.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$1$2//$3</i>") //msg = bbcode_url.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$1$2//$3</i>")
msg = bbcodeURLLabel.ReplaceAllString(msg, "<a href='$1$2//$3' rel='nofollow'>$4</i>") msg = bbcodeURLLabel.ReplaceAllString(msg, "<a href='$1$2//$3' rel='nofollow'>$4</i>")

View File

@ -478,7 +478,7 @@ func socialgroupsMemberList(w http.ResponseWriter, r *http.Request, user User) {
} else { } else {
sgMember.User.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(sgMember.User.ID), 1) sgMember.User.Avatar = strings.Replace(config.Noavatar, "{id}", strconv.Itoa(sgMember.User.ID), 1)
} }
sgMember.JoinedAt, _ = relativeTime(sgMember.JoinedAt) sgMember.JoinedAt, _ = relativeTimeFromString(sgMember.JoinedAt)
if sgItem.Owner == sgMember.User.ID { if sgItem.Owner == sgMember.User.ID {
sgMember.RankString = "Owner" sgMember.RankString = "Owner"
} else { } else {

View File

@ -16,6 +16,11 @@ func addMEPair(msgList []MEPair, msg string, expects string) []MEPair {
func TestBBCodeRender(t *testing.T) { func TestBBCodeRender(t *testing.T) {
//t.Skip() //t.Skip()
err := initBbcode()
if err != nil {
t.Fatal(err)
}
var res string var res string
var msgList []MEPair var msgList []MEPair
msgList = addMEPair(msgList, "hi", "hi") msgList = addMEPair(msgList, "hi", "hi")
@ -54,8 +59,8 @@ func TestBBCodeRender(t *testing.T) {
} }
} }
var msg, expects string var msg string
var err error var expects string
msg = "[rand][/rand]" msg = "[rand][/rand]"
expects = "<span style='color: red;'>[Invalid Number]</span>[rand][/rand]" expects = "<span style='color: red;'>[Invalid Number]</span>[rand][/rand]"

View File

@ -26,11 +26,13 @@ func (install *installer) SetAdapter(name string) error {
return err return err
} }
install.adapter = adap install.adapter = adap
install.instructions = []DB_Install_Instruction{}
return nil return nil
} }
func (install *installer) SetAdapterInstance(adapter DB_Adapter) { func (install *installer) SetAdapterInstance(adapter DB_Adapter) {
install.adapter = adapter install.adapter = adapter
install.instructions = []DB_Install_Instruction{}
} }
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 {
@ -42,6 +44,15 @@ func (install *installer) CreateTable(table string, charset string, collation st
return nil return nil
} }
func (install *installer) SimpleInsert(table string, columns string, fields string) error {
res, err := install.adapter.SimpleInsert("_installer", table, columns, fields)
if err != nil {
return err
}
install.instructions = append(install.instructions, DB_Install_Instruction{table, res, "insert"})
return nil
}
func (install *installer) Write() error { func (install *installer) Write() error {
var inserts string var inserts string
// We can't escape backticks, so we have to dump it out a file at a time // We can't escape backticks, so we have to dump it out a file at a time
@ -52,7 +63,7 @@ func (install *installer) Write() error {
return err return err
} }
} else { } else {
inserts += instr.Contents + "\n" inserts += instr.Contents + ";\n"
} }
} }
return writeFile("./schema/"+install.adapter.GetName()+"/inserts.sql", inserts) return writeFile("./schema/"+install.adapter.GetName()+"/inserts.sql", inserts)

View File

@ -134,6 +134,13 @@ func (adapter *Mysql_Adapter) SimpleInsert(name string, table string, columns st
querystr += ") VALUES (" querystr += ") VALUES ("
for _, field := range processFields(fields) { for _, field := range processFields(fields) {
nameLen := len(field.Name)
if field.Name[0] == '"' && field.Name[nameLen-1] == '"' && nameLen >= 3 {
field.Name = "'" + field.Name[1:nameLen-1] + "'"
}
if field.Name[0] == '\'' && field.Name[nameLen-1] == '\'' && nameLen >= 3 {
field.Name = "'" + strings.Replace(field.Name[1:nameLen-1], "'", "''", -1) + "'"
}
querystr += field.Name + "," querystr += field.Name + ","
} }
querystr = querystr[0 : len(querystr)-1] querystr = querystr[0 : len(querystr)-1]
@ -330,6 +337,7 @@ func (adapter *Mysql_Adapter) SimpleSelect(name string, table string, columns st
if len(orderby) != 0 { if len(orderby) != 0 {
querystr += " ORDER BY " querystr += " ORDER BY "
for _, column := range processOrderby(orderby) { for _, column := range processOrderby(orderby) {
// TODO: We might want to escape this column
querystr += column.Column + " " + strings.ToUpper(column.Order) + "," querystr += column.Column + " " + strings.ToUpper(column.Order) + ","
} }
querystr = querystr[0 : len(querystr)-1] querystr = querystr[0 : len(querystr)-1]
@ -778,12 +786,12 @@ func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where strin
var querystr = "SELECT COUNT(*) AS `count` FROM `" + table + "`" var querystr = "SELECT COUNT(*) AS `count` FROM `" + table + "`"
// Add support for BETWEEN x.x // TODO: Add support for BETWEEN x.x
if len(where) != 0 { if len(where) != 0 {
querystr += " WHERE" querystr += " WHERE"
//fmt.Println("SimpleCount:",name) //fmt.Println("SimpleCount:",name)
//fmt.Println("where:",where) //fmt.Println("where:",where)
//fmt.Println("_process_where:",_process_where(where)) //fmt.Println("processWhere:",processWhere(where))
for _, loc := range processWhere(where) { for _, loc := range processWhere(where) {
for _, token := range loc.Expr { for _, token := range loc.Expr {
switch token.Type { switch token.Type {
@ -814,6 +822,9 @@ func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where strin
func (adapter *Mysql_Adapter) Write() error { func (adapter *Mysql_Adapter) Write() error {
var stmts, body string var stmts, body string
for _, name := range adapter.BufferOrder { for _, name := range adapter.BufferOrder {
if name[0] == '_' {
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 :( // TODO: Add support for create-table? Table creation might be a little complex for Go to do outside a SQL file :(
if stmt.Type != "create-table" { if stmt.Type != "create-table" {
@ -828,7 +839,7 @@ func (adapter *Mysql_Adapter) Write() error {
} }
} }
out := `// +build !pgsql !sqlite !mssql out := `// +build !pgsql, !sqlite, !mssql
/* This file was generated by Gosora's Query Generator. Please try to avoid modifying this file, as it might change at any time. */ /* This file was generated by Gosora's Query Generator. Please try to avoid modifying this file, as it might change at any time. */

View File

@ -304,6 +304,9 @@ func (adapter *Pgsql_Adapter) SimpleCount(name string, table string, where strin
func (adapter *Pgsql_Adapter) Write() error { func (adapter *Pgsql_Adapter) Write() error {
var stmts, body string var stmts, body string
for _, name := range adapter.BufferOrder { for _, name := range adapter.BufferOrder {
if name[0] == '_' {
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 :( // TODO: Add support for create-table? Table creation might be a little complex for Go to do outside a SQL file :(
if stmt.Type != "create-table" { if stmt.Type != "create-table" {

View File

@ -6,8 +6,7 @@ import "errors"
var DB_Registry []DB_Adapter var DB_Registry []DB_Adapter
var No_Adapter = errors.New("This adapter doesn't exist") var No_Adapter = errors.New("This adapter doesn't exist")
type DB_Table_Column struct type DB_Table_Column struct {
{
Name string Name string
Type string Type string
Size int Size int
@ -16,14 +15,12 @@ type DB_Table_Column struct
Default string Default string
} }
type DB_Table_Key struct type DB_Table_Key struct {
{
Columns string Columns string
Type string Type string
} }
type DB_Select struct type DB_Select struct {
{
Table string Table string
Columns string Columns string
Where string Where string
@ -31,8 +28,7 @@ type DB_Select struct
Limit string Limit string
} }
type DB_Join struct type DB_Join struct {
{
Table1 string Table1 string
Table2 string Table2 string
Columns string Columns string
@ -42,34 +38,29 @@ type DB_Join struct
Limit string Limit string
} }
type DB_Insert struct type DB_Insert struct {
{
Table string Table string
Columns string Columns string
Fields string Fields string
} }
type DB_Column struct type DB_Column struct {
{
Table string Table string
Left string // Could be a function or a column, so I'm naming this Left Left string // Could be a function or a column, so I'm naming this Left
Alias string // aka AS Blah, if it's present Alias string // aka AS Blah, if it's present
Type string // function or column Type string // function or column
} }
type DB_Field struct type DB_Field struct {
{
Name string Name string
Type string Type string
} }
type DB_Where struct type DB_Where struct {
{
Expr []DB_Token // Simple expressions, the innards of functions are opaque for now. Expr []DB_Token // Simple expressions, the innards of functions are opaque for now.
} }
type DB_Joiner struct type DB_Joiner struct {
{
LeftTable string LeftTable string
LeftColumn string LeftColumn string
RightTable string RightTable string
@ -77,8 +68,7 @@ type DB_Joiner struct
Operator string Operator string
} }
type DB_Order struct type DB_Order struct {
{
Column string Column string
Order string Order string
} }
@ -98,8 +88,7 @@ type DB_Limit struct {
MaxCount string // ? or int MaxCount string // ? or int
} }
type DB_Stmt struct type DB_Stmt struct {
{
Contents string Contents string
Type string // create-table, insert, update, delete Type string // create-table, insert, update, delete
} }
@ -114,11 +103,11 @@ type DB_Adapter interface {
Purge(name string, table string) (string, error) Purge(name string, table string) (string, error)
SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error)
SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error)
SimpleInnerJoin(string,string,string,string,string,string,string,string) (string, error) SimpleInnerJoin(string, string, string, string, string, string, string, string) (string, error)
SimpleInsertSelect(string,DB_Insert,DB_Select) (string,error) SimpleInsertSelect(string, DB_Insert, DB_Select) (string, error)
SimpleInsertLeftJoin(string,DB_Insert,DB_Join) (string,error) SimpleInsertLeftJoin(string, DB_Insert, DB_Join) (string, error)
SimpleInsertInnerJoin(string,DB_Insert,DB_Join) (string,error) SimpleInsertInnerJoin(string, DB_Insert, DB_Join) (string, error)
SimpleCount(string,string,string,string) (string, error) SimpleCount(string, string, string, string) (string, error)
Write() error Write() error
// TODO: Add a simple query builder // TODO: Add a simple query builder

View File

@ -120,6 +120,22 @@ func create_tables(adapter qgen.DB_Adapter) error {
}, },
) )
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? // 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? // Should we add IP Penalties? No, that's a stupid idea, just implement IP Bans properly. What about shadowbans?
// TODO: Perm overrides // TODO: Perm overrides
@ -166,6 +182,191 @@ func create_tables(adapter qgen.DB_Adapter) error {
}, },
) )
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.Install.CreateTable("word_filters", "", "",
[]qgen.DB_Table_Column{ []qgen.DB_Table_Column{
qgen.DB_Table_Column{"wfid", "int", 0, false, true, ""}, qgen.DB_Table_Column{"wfid", "int", 0, false, true, ""},
@ -177,6 +378,63 @@ func create_tables(adapter qgen.DB_Adapter) error {
}, },
) )
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.Install.CreateTable("sync", "", "",
[]qgen.DB_Table_Column{ []qgen.DB_Table_Column{
qgen.DB_Table_Column{"last_update", "datetime", 0, false, false, ""}, qgen.DB_Table_Column{"last_update", "datetime", 0, false, false, ""},
@ -189,6 +447,103 @@ func create_tables(adapter qgen.DB_Adapter) error {
// nolint // nolint
func seed_tables(adapter qgen.DB_Adapter) error { func seed_tables(adapter qgen.DB_Adapter) error {
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, constraints", "'activation_type','1','list','1-3'")
qgen.Install.SimpleInsert("settings", "name, content, type", "'bigpost_min_words','250','int'")
qgen.Install.SimpleInsert("settings", "name, content, type", "'megapost_min_words','1000','int'")
qgen.Install.SimpleInsert("themes", "uname, default", "'tempra-simple',1")
qgen.Install.SimpleInsert("emails", "email, uid, validated", "'admin@localhost',1,1") // ? - Use a different default email or let the admin input it during installation?
/*
The Permissions:
Global Permissions:
BanUsers
ActivateUsers
EditUser
EditUserEmail
EditUserPassword
EditUserGroup
EditUserGroupSuperMod
EditUserGroupAdmin
EditGroup
EditGroupLocalPerms
EditGroupGlobalPerms
EditGroupSuperMod
EditGroupAdmin
ManageForums
EditSettings
ManageThemes
ManagePlugins
ViewAdminLogs
ViewIPs
Non-staff Global Permissions:
UploadFiles
Forum Permissions:
ViewTopic
LikeItem
CreateTopic
EditTopic
DeleteTopic
CreateReply
EditReply
DeleteReply
PinTopic
CloseTopic
*/
qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms, is_mod, is_admin, tag", `'Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"UploadFiles":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}','{}',1,1,"Admin"`)
qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms, is_mod, tag", `'Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"UploadFiles":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}','{}',1,"Mod"`)
qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms", `'Member','{"UploadFiles":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}','{}'`)
qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms, is_banned", `'Banned','{"ViewTopic":true}','{}',1`)
qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms", `'Awaiting Activation','{"ViewTopic":true}','{}'`)
qgen.Install.SimpleInsert("users_groups", "name, permissions, plugin_perms, tag", `'Not Loggedin','{"ViewTopic":true}','{}','Guest'`)
//
// TODO: Stop processFields() from stripping the spaces in the descriptions in the next commit
qgen.Install.SimpleInsert("forums", "name, active, desc", "'Reports',0,'All the reports go here'")
qgen.Install.SimpleInsert("forums", "name, lastTopicID, lastReplyerID, desc", "'General',1,1,'A place for general discussions which don't fit elsewhere'")
//
qgen.Install.SimpleInsert("forums_permissions", "gid, fid, permissions", `1,1,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"PinTopic":true,"CloseTopic":true}'`)
qgen.Install.SimpleInsert("forums_permissions", "gid, fid, permissions", `2,1,'{"ViewTopic":true,"CreateReply":true,"CloseTopic":true}'`)
qgen.Install.SimpleInsert("forums_permissions", "gid, fid, permissions", "3,1,'{}'")
qgen.Install.SimpleInsert("forums_permissions", "gid, fid, permissions", "4,1,'{}'")
qgen.Install.SimpleInsert("forums_permissions", "gid, fid, permissions", "5,1,'{}'")
qgen.Install.SimpleInsert("forums_permissions", "gid, fid, permissions", "6,1,'{}'")
//
qgen.Install.SimpleInsert("forums_permissions", "gid, fid, permissions", `1,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true,"EditTopic":true,"DeleteTopic":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}'`)
qgen.Install.SimpleInsert("forums_permissions", "gid, fid, permissions", `2,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true,"EditTopic":true,"DeleteTopic":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}'`)
qgen.Install.SimpleInsert("forums_permissions", "gid, fid, permissions", `3,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true}'`)
qgen.Install.SimpleInsert("forums_permissions", "gid, fid, permissions", `4,2,'{"ViewTopic":true}'`)
qgen.Install.SimpleInsert("forums_permissions", "gid, fid, permissions", `5,2,'{"ViewTopic":true}'`)
qgen.Install.SimpleInsert("forums_permissions", "gid, fid, permissions", `6,2,'{"ViewTopic":true}'`)
//
qgen.Install.SimpleInsert("topics", "title, content, parsed_content, createdAt, lastReplyAt, lastReplyBy, createdBy, parentID", "'Test Topic','A topic automatically generated by the software.','A topic automatically generated by the software.',UTC_TIMESTAMP(),UTC_TIMESTAMP(),1,1,2")
qgen.Install.SimpleInsert("replies", "tid, content, parsed_content, createdAt, createdBy, lastUpdated, lastEdit, lastEditBy", "1,'A reply!','A reply!',UTC_TIMESTAMP(),1,UTC_TIMESTAMP(),0,0")
return nil return nil
} }
@ -276,7 +631,7 @@ func write_selects(adapter qgen.DB_Adapter) error {
// nolint // nolint
func write_left_joins(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", "tid = ?", "", "?,?") 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", "")
@ -302,25 +657,25 @@ func write_inner_joins(adapter qgen.DB_Adapter) error {
// nolint // nolint
func write_inserts(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, 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, ipaddress, words, createdBy", "?,?,?,UTC_TIMESTAMP(),?,?,?")
adapter.SimpleInsert("createActionReply", "replies", "tid,actionType,ipaddress,createdBy", "?,?,?,?") adapter.SimpleInsert("createActionReply", "replies", "tid, actionType, ipaddress, createdBy", "?,?,?,?")
adapter.SimpleInsert("createLike", "likes", "weight, targetItem, targetType, sentBy", "?,?,?,?") adapter.SimpleInsert("createLike", "likes", "weight, targetItem, targetType, sentBy", "?,?,?,?")
adapter.SimpleInsert("addActivity", "activity_stream", "actor,targetUser,event,elementType,elementID", "?,?,?,?,?") adapter.SimpleInsert("addActivity", "activity_stream", "actor, targetUser, event, elementType, elementID", "?,?,?,?,?")
adapter.SimpleInsert("notifyOne", "activity_stream_matches", "watcher,asid", "?,?") adapter.SimpleInsert("notifyOne", "activity_stream_matches", "watcher, asid", "?,?")
adapter.SimpleInsert("addEmail", "emails", "email, uid, validated, token", "?,?,?,?") adapter.SimpleInsert("addEmail", "emails", "email, uid, validated, token", "?,?,?,?")
adapter.SimpleInsert("createProfileReply", "users_replies", "uid, content, parsed_content, createdAt, createdBy, ipaddress", "?,?,?,UTC_TIMESTAMP(),?,?") adapter.SimpleInsert("createProfileReply", "users_replies", "uid, content, parsed_content, createdAt, createdBy, ipaddress", "?,?,?,UTC_TIMESTAMP(),?,?")
adapter.SimpleInsert("addSubscription", "activity_subscriptions", "user,targetID,targetType,level", "?,?,?,2") adapter.SimpleInsert("addSubscription", "activity_subscriptions", "user, targetID, targetType, level", "?,?,?,2")
adapter.SimpleInsert("createForum", "forums", "name, desc, active, preset", "?,?,?,?") adapter.SimpleInsert("createForum", "forums", "name, desc, active, preset", "?,?,?,?")
@ -328,7 +683,7 @@ func write_inserts(adapter qgen.DB_Adapter) error {
adapter.SimpleInsert("addPlugin", "plugins", "uname, active, installed", "?,?,?") adapter.SimpleInsert("addPlugin", "plugins", "uname, active, installed", "?,?,?")
adapter.SimpleInsert("addTheme", "themes", "uname,default", "?,?") adapter.SimpleInsert("addTheme", "themes", "uname, default", "?,?")
adapter.SimpleInsert("createGroup", "users_groups", "name, tag, is_admin, is_mod, is_banned, permissions", "?,?,?,?,?,?") adapter.SimpleInsert("createGroup", "users_groups", "name, tag, is_admin, is_mod, is_banned, permissions", "?,?,?,?,?,?")
@ -345,7 +700,7 @@ func write_inserts(adapter qgen.DB_Adapter) error {
// nolint // nolint
func write_replaces(adapter qgen.DB_Adapter) error { func write_replaces(adapter qgen.DB_Adapter) error {
adapter.SimpleReplace("addForumPermsToGroup", "forums_permissions", "gid,fid,preset,permissions", "?,?,?,?") 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(),?,?") adapter.SimpleReplace("replaceScheduleGroup", "users_groups_scheduler", "uid, set_group, issued_by, issued_at, revert_at, temporary", "?,?,?,UTC_TIMESTAMP(),?,?")
@ -469,17 +824,17 @@ func write_simple_counts(adapter qgen.DB_Adapter) error {
// nolint // nolint
func write_insert_selects(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", "", ""},
) )
adapter.SimpleInsertSelect("addForumPermsToForumStaff", adapter.SimpleInsertSelect("addForumPermsToForumStaff",
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 = 0 AND is_mod = 1", "", ""}, qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 1", "", ""},
) )
adapter.SimpleInsertSelect("addForumPermsToForumMembers", adapter.SimpleInsertSelect("addForumPermsToForumMembers",
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 = 0 AND is_mod = 0 AND is_banned = 0", "", ""}, qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 0 AND is_banned = 0", "", ""},
) )

View File

@ -235,14 +235,11 @@ func routeTopics(w http.ResponseWriter, r *http.Request, user User) {
//topicItem.ForumLink = "" //topicItem.ForumLink = ""
} }
/*topicItem.CreatedAt, err = relativeTime(topicItem.CreatedAt) /*topicItem.CreatedAt, err = relativeTimeFromString(topicItem.CreatedAt)
if err != nil { if err != nil {
replyItem.CreatedAt = "" replyItem.CreatedAt = ""
}*/ }*/
topicItem.LastReplyAt, err = relativeTime(topicItem.LastReplyAt) topicItem.RelativeLastReplyAt = relativeTime(topicItem.LastReplyAt)
if err != nil {
InternalError(err, w)
}
if vhooks["topics_topic_row_assign"] != nil { if vhooks["topics_topic_row_assign"] != nil {
runVhook("topics_topic_row_assign", &topicItem, &forum) runVhook("topics_topic_row_assign", &topicItem, &forum)
@ -354,10 +351,7 @@ func routeForum(w http.ResponseWriter, r *http.Request, user User, sfid string)
} }
topicItem.Link = buildTopicURL(nameToSlug(topicItem.Title), topicItem.ID) topicItem.Link = buildTopicURL(nameToSlug(topicItem.Title), topicItem.ID)
topicItem.LastReplyAt, err = relativeTime(topicItem.LastReplyAt) topicItem.RelativeLastReplyAt = relativeTime(topicItem.LastReplyAt)
if err != nil {
InternalError(err, w)
}
if vhooks["forum_trow_assign"] != nil { if vhooks["forum_trow_assign"] != nil {
runVhook("forum_trow_assign", &topicItem, &forum) runVhook("forum_trow_assign", &topicItem, &forum)
@ -439,7 +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 = relativeTime(forum.LastTopic.LastReplyAt) forum.LastTopicTime, err = relativeTimeFromString(forum.LastTopic.LastReplyAt)
if err != nil { if err != nil {
InternalError(err, w) InternalError(err, w)
return return
@ -539,7 +533,7 @@ func routeTopicID(w http.ResponseWriter, r *http.Request, user User) {
} }
}*/ }*/
topic.CreatedAt, err = relativeTime(topic.CreatedAt) topic.CreatedAt, err = relativeTimeFromString(topic.CreatedAt)
if err != nil { if err != nil {
topic.CreatedAt = "" topic.CreatedAt = ""
} }
@ -624,7 +618,7 @@ func routeTopicID(w http.ResponseWriter, r *http.Request, user User) {
} }
}*/ }*/
replyItem.CreatedAt, err = relativeTime(replyItem.CreatedAt) replyItem.CreatedAt, err = relativeTimeFromString(replyItem.CreatedAt)
if err != nil { if err != nil {
replyItem.CreatedAt = "" replyItem.CreatedAt = ""
} }

36
run_mssql.bat Normal file
View File

@ -0,0 +1,36 @@
@echo off
echo Generating the dynamic code
go generate
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
echo Building the router generator
go build ./router_gen
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
echo Running the router generator
router_gen.exe
echo Building the query generator
go build ./query_gen
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
echo Running the query generator
query_gen.exe
echo Building the executable
go build -o gosora.exe -tags mssql
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
echo Running Gosora
gosora.exe
pause

29
schema/mssql/inserts.sql Normal file
View File

@ -0,0 +1,29 @@
INSERT INTO [sync] ([last_update]) VALUES (GETUTCDATE());
INSERT INTO [settings] ([name],[content],[type]) VALUES ('url_tags','1','bool');
INSERT INTO [settings] ([name],[content],[type],[constraints]) VALUES ('activation_type','1','list','1-3');
INSERT INTO [settings] ([name],[content],[type]) VALUES ('bigpost_min_words','250','int');
INSERT INTO [settings] ([name],[content],[type]) VALUES ('megapost_min_words','1000','int');
INSERT INTO [themes] ([uname],[default]) VALUES ('tempra-simple',1);
INSERT INTO [emails] ([email],[uid],[validated]) VALUES ('admin@localhost',1,1);
INSERT INTO [users_groups] ([name],[permissions],[plugin_perms],[is_mod],[is_admin],[tag]) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"UploadFiles":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}','{}',1,1,'Admin');
INSERT INTO [users_groups] ([name],[permissions],[plugin_perms],[is_mod],[tag]) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"UploadFiles":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}','{}',1,'Mod');
INSERT INTO [users_groups] ([name],[permissions],[plugin_perms]) VALUES ('Member','{"UploadFiles":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}','{}');
INSERT INTO [users_groups] ([name],[permissions],[plugin_perms],[is_banned]) VALUES ('Banned','{"ViewTopic":true}','{}',1);
INSERT INTO [users_groups] ([name],[permissions],[plugin_perms]) VALUES ('AwaitingActivation','{"ViewTopic":true}','{}');
INSERT INTO [users_groups] ([name],[permissions],[plugin_perms],[tag]) VALUES ('NotLoggedin','{"ViewTopic":true}','{}','Guest');
INSERT INTO [forums] ([name],[active],[desc]) VALUES ('Reports',0,'Allthereportsgohere');
INSERT INTO [forums] ([name],[lastTopicID],[lastReplyerID],[desc]) VALUES ('General',1,1,'Aplaceforgeneraldiscussionswhichdon''tfitelsewhere');
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (1,1,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"PinTopic":true,"CloseTopic":true}');
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (2,1,'{"ViewTopic":true,"CreateReply":true,"CloseTopic":true}');
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (3,1,'{}');
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (4,1,'{}');
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (5,1,'{}');
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (6,1,'{}');
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (1,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true,"EditTopic":true,"DeleteTopic":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}');
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (2,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true,"EditTopic":true,"DeleteTopic":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}');
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (3,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true}');
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (4,2,'{"ViewTopic":true}');
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (5,2,'{"ViewTopic":true}');
INSERT INTO [forums_permissions] ([gid],[fid],[permissions]) VALUES (6,2,'{"ViewTopic":true}');
INSERT INTO [topics] ([title],[content],[parsed_content],[createdAt],[lastReplyAt],[lastReplyBy],[createdBy],[parentID]) VALUES ('TestTopic','Atopicautomaticallygeneratedbythesoftware.','Atopicautomaticallygeneratedbythesoftware.',GETUTCDATE(),GETUTCDATE(),1,1,2);
INSERT INTO [replies] ([tid],[content],[parsed_content],[createdAt],[createdBy],[lastUpdated],[lastEdit],[lastEditBy]) VALUES (1,'Areply!','Areply!',GETUTCDATE(),1,GETUTCDATE(),0,0);

View File

@ -0,0 +1,10 @@
DROP TABLE IF EXISTS [activity_stream];
CREATE TABLE [activity_stream] (
[asid] int not null IDENTITY,
[actor] int not null,
[targetUser] int not null,
[event] nvarchar (50) not null,
[elementType] nvarchar (50) not null,
[elementID] int not null,
primary key([asid])
);

View File

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

View File

@ -0,0 +1,7 @@
DROP TABLE IF EXISTS [activity_subscriptions];
CREATE TABLE [activity_subscriptions] (
[user] int not null,
[targetID] int not null,
[targetType] nvarchar (50) not null,
[level] int DEFAULT 0 not null
);

View File

@ -0,0 +1,9 @@
DROP TABLE IF EXISTS [administration_logs];
CREATE TABLE [administration_logs] (
[action] nvarchar (100) not null,
[elementID] int not null,
[elementType] nvarchar (100) not null,
[ipaddress] nvarchar (200) not null,
[actorID] int not null,
[doneAt] datetime not null
);

View File

@ -0,0 +1,11 @@
DROP TABLE IF EXISTS [attachments];
CREATE TABLE [attachments] (
[attachID] int not null IDENTITY,
[sectionID] int DEFAULT 0 not null,
[sectionTable] nvarchar (200) DEFAULT 'forums' not null,
[originID] int not null,
[originTable] nvarchar (200) DEFAULT 'replies' not null,
[uploadedBy] int not null,
[path] nvarchar (200) not null,
primary key([attachID])
);

View File

@ -0,0 +1,7 @@
DROP TABLE IF EXISTS [emails];
CREATE TABLE [emails] (
[email] nvarchar (200) not null,
[uid] int not null,
[validated] bit DEFAULT 0 not null,
[token] nvarchar (200) DEFAULT '' not null
);

View File

@ -0,0 +1,14 @@
DROP TABLE IF EXISTS [forums];
CREATE TABLE [forums] (
[fid] int not null IDENTITY,
[name] nvarchar (100) not null,
[desc] nvarchar (200) not null,
[active] bit DEFAULT 1 not null,
[topicCount] int DEFAULT 0 not null,
[preset] nvarchar (100) DEFAULT '' not null,
[parentID] int DEFAULT 0 not null,
[parentType] nvarchar (50) DEFAULT '' not null,
[lastTopicID] int DEFAULT 0 not null,
[lastReplyerID] int DEFAULT 0 not null,
primary key([fid])
);

View File

@ -0,0 +1,8 @@
DROP TABLE IF EXISTS [forums_permissions];
CREATE TABLE [forums_permissions] (
[fid] int not null,
[gid] int not null,
[preset] nvarchar (100) DEFAULT '' not null,
[permissions] nvarchar (MAX) not null,
primary key([fid],[gid])
);

View File

@ -0,0 +1,8 @@
DROP TABLE IF EXISTS [likes];
CREATE TABLE [likes] (
[weight] tinyint DEFAULT 1 not null,
[targetItem] int not null,
[targetType] nvarchar (50) DEFAULT 'replies' not null,
[sentBy] int not null,
[recalc] tinyint DEFAULT 0 not null
);

View File

@ -0,0 +1,9 @@
DROP TABLE IF EXISTS [moderation_logs];
CREATE TABLE [moderation_logs] (
[action] nvarchar (100) not null,
[elementID] int not null,
[elementType] nvarchar (100) not null,
[ipaddress] nvarchar (200) not null,
[actorID] int not null,
[doneAt] datetime not null
);

View File

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

View File

@ -0,0 +1,17 @@
DROP TABLE IF EXISTS [replies];
CREATE TABLE [replies] (
[rid] int not null IDENTITY,
[tid] int not null,
[content] nvarchar (MAX) not null,
[parsed_content] nvarchar (MAX) not null,
[createdAt] datetime not null,
[createdBy] int not null,
[lastEdit] int not null,
[lastEditBy] int not null,
[lastUpdated] datetime not null,
[ipaddress] nvarchar (200) DEFAULT '0.0.0.0.0' not null,
[likeCount] int DEFAULT 0 not null,
[words] int DEFAULT 1 not null,
[actionType] nvarchar (20) DEFAULT '' not null,
primary key([rid])
);

View File

@ -0,0 +1,7 @@
DROP TABLE IF EXISTS [revisions];
CREATE TABLE [revisions] (
[index] int not null,
[content] nvarchar (MAX) not null,
[contentID] int not null,
[contentType] nvarchar (100) DEFAULT 'replies' not null
);

View File

@ -0,0 +1,8 @@
DROP TABLE IF EXISTS [settings];
CREATE TABLE [settings] (
[name] nvarchar (180) not null,
[content] nvarchar (250) not null,
[type] nvarchar (50) not null,
[constraints] nvarchar (200) DEFAULT '' not null,
unique([name])
);

View File

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

View File

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

View File

@ -0,0 +1,21 @@
DROP TABLE IF EXISTS [topics];
CREATE TABLE [topics] (
[tid] int not null IDENTITY,
[title] nvarchar (100) not null,
[content] nvarchar (MAX) not null,
[parsed_content] nvarchar (MAX) not null,
[createdAt] datetime not null,
[lastReplyAt] datetime not null,
[lastReplyBy] int not null,
[createdBy] int not null,
[is_closed] bit DEFAULT 0 not null,
[sticky] bit DEFAULT 0 not null,
[parentID] int DEFAULT 2 not null,
[ipaddress] nvarchar (200) DEFAULT '0.0.0.0.0' not null,
[postCount] int DEFAULT 1 not null,
[likeCount] int DEFAULT 0 not null,
[words] int DEFAULT 0 not null,
[css_class] nvarchar (100) DEFAULT '' not null,
[data] nvarchar (200) DEFAULT '' not null,
primary key([tid])
);

View File

@ -0,0 +1,28 @@
DROP TABLE IF EXISTS [users];
CREATE TABLE [users] (
[uid] int not null IDENTITY,
[name] nvarchar (100) not null,
[password] nvarchar (100) not null,
[salt] nvarchar (80) DEFAULT '' not null,
[group] int not null,
[active] bit DEFAULT 0 not null,
[is_super_admin] bit DEFAULT 0 not null,
[createdAt] datetime not null,
[lastActiveAt] datetime not null,
[session] nvarchar (200) DEFAULT '' not null,
[last_ip] nvarchar (200) DEFAULT '0.0.0.0.0' not null,
[email] nvarchar (200) DEFAULT '' not null,
[avatar] nvarchar (100) DEFAULT '' not null,
[message] nvarchar (MAX) DEFAULT '' not null,
[url_prefix] nvarchar (20) DEFAULT '' not null,
[url_name] nvarchar (100) DEFAULT '' not null,
[level] smallint DEFAULT 0 not null,
[score] int DEFAULT 0 not null,
[posts] int DEFAULT 0 not null,
[bigposts] int DEFAULT 0 not null,
[megaposts] int DEFAULT 0 not null,
[topics] int DEFAULT 0 not null,
[temp_group] int DEFAULT 0 not null,
primary key([uid]),
unique([name])
);

View File

@ -0,0 +1,12 @@
DROP TABLE IF EXISTS [users_groups];
CREATE TABLE [users_groups] (
[gid] int not null IDENTITY,
[name] nvarchar (100) not null,
[permissions] nvarchar (MAX) not null,
[plugin_perms] nvarchar (MAX) not null,
[is_mod] bit DEFAULT 0 not null,
[is_admin] bit DEFAULT 0 not null,
[is_banned] bit DEFAULT 0 not null,
[tag] nvarchar (50) DEFAULT '' not null,
primary key([gid])
);

View File

@ -0,0 +1,10 @@
DROP TABLE IF EXISTS [users_groups_scheduler];
CREATE TABLE [users_groups_scheduler] (
[uid] int not null,
[set_group] int not null,
[issued_by] int not null,
[issued_at] datetime not null,
[revert_at] datetime not null,
[temporary] bit not null,
primary key([uid])
);

View File

@ -0,0 +1,13 @@
DROP TABLE IF EXISTS [users_replies];
CREATE TABLE [users_replies] (
[rid] int not null IDENTITY,
[uid] int not null,
[content] nvarchar (MAX) not null,
[parsed_content] nvarchar (MAX) not null,
[createdAt] datetime not null,
[createdBy] int not null,
[lastEdit] int not null,
[lastEditBy] int not null,
[ipaddress] nvarchar (200) DEFAULT '0.0.0.0.0' not null,
primary key([rid])
);

View File

@ -0,0 +1,9 @@
DROP TABLE IF EXISTS [widgets];
CREATE TABLE [widgets] (
[position] int not null,
[side] nvarchar (100) not null,
[type] nvarchar (100) not null,
[active] bit DEFAULT 0 not null,
[location] nvarchar (100) not null,
[data] nvarchar (MAX) DEFAULT '' not null
);

View File

@ -0,0 +1,7 @@
DROP TABLE IF EXISTS [word_filters];
CREATE TABLE [word_filters] (
[wfid] int not null IDENTITY,
[find] nvarchar (200) not null,
[replacement] nvarchar (200) not null,
primary key([wfid])
);

View File

@ -0,0 +1,29 @@
INSERT INTO `sync`(`last_update`) VALUES (UTC_TIMESTAMP());
INSERT INTO `settings`(`name`,`content`,`type`) VALUES ('url_tags','1','bool');
INSERT INTO `settings`(`name`,`content`,`type`,`constraints`) VALUES ('activation_type','1','list','1-3');
INSERT INTO `settings`(`name`,`content`,`type`) VALUES ('bigpost_min_words','250','int');
INSERT INTO `settings`(`name`,`content`,`type`) VALUES ('megapost_min_words','1000','int');
INSERT INTO `themes`(`uname`,`default`) VALUES ('tempra-simple',1);
INSERT INTO `emails`(`email`,`uid`,`validated`) VALUES ('admin@localhost',1,1);
INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{"BanUsers":true,"ActivateUsers":true,"EditUser":true,"EditUserEmail":true,"EditUserPassword":true,"EditUserGroup":true,"EditUserGroupSuperMod":true,"EditUserGroupAdmin":false,"EditGroup":true,"EditGroupLocalPerms":true,"EditGroupGlobalPerms":true,"EditGroupSuperMod":true,"EditGroupAdmin":false,"ManageForums":true,"EditSettings":true,"ManageThemes":true,"ManagePlugins":true,"ViewAdminLogs":true,"ViewIPs":true,"UploadFiles":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}','{}',1,1,'Admin');
INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`,`is_mod`,`tag`) VALUES ('Moderator','{"BanUsers":true,"ActivateUsers":false,"EditUser":true,"EditUserEmail":false,"EditUserGroup":true,"ViewIPs":true,"UploadFiles":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"EditTopic":true,"DeleteTopic":true,"CreateReply":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}','{}',1,'Mod');
INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`) VALUES ('Member','{"UploadFiles":true,"ViewTopic":true,"LikeItem":true,"CreateTopic":true,"CreateReply":true}','{}');
INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`,`is_banned`) VALUES ('Banned','{"ViewTopic":true}','{}',1);
INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`) VALUES ('AwaitingActivation','{"ViewTopic":true}','{}');
INSERT INTO `users_groups`(`name`,`permissions`,`plugin_perms`,`tag`) VALUES ('NotLoggedin','{"ViewTopic":true}','{}','Guest');
INSERT INTO `forums`(`name`,`active`,`desc`) VALUES ('Reports',0,'Allthereportsgohere');
INSERT INTO `forums`(`name`,`lastTopicID`,`lastReplyerID`,`desc`) VALUES ('General',1,1,'Aplaceforgeneraldiscussionswhichdon''tfitelsewhere');
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (1,1,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"PinTopic":true,"CloseTopic":true}');
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (2,1,'{"ViewTopic":true,"CreateReply":true,"CloseTopic":true}');
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (3,1,'{}');
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (4,1,'{}');
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (5,1,'{}');
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (6,1,'{}');
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (1,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true,"EditTopic":true,"DeleteTopic":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}');
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (2,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true,"EditTopic":true,"DeleteTopic":true,"EditReply":true,"DeleteReply":true,"PinTopic":true,"CloseTopic":true}');
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (3,2,'{"ViewTopic":true,"CreateReply":true,"CreateTopic":true,"LikeItem":true}');
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (4,2,'{"ViewTopic":true}');
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (5,2,'{"ViewTopic":true}');
INSERT INTO `forums_permissions`(`gid`,`fid`,`permissions`) VALUES (6,2,'{"ViewTopic":true}');
INSERT INTO `topics`(`title`,`content`,`parsed_content`,`createdAt`,`lastReplyAt`,`lastReplyBy`,`createdBy`,`parentID`) VALUES ('TestTopic','Atopicautomaticallygeneratedbythesoftware.','Atopicautomaticallygeneratedbythesoftware.',UTC_TIMESTAMP(),UTC_TIMESTAMP(),1,1,2);
INSERT INTO `replies`(`tid`,`content`,`parsed_content`,`createdAt`,`createdBy`,`lastUpdated`,`lastEdit`,`lastEditBy`) VALUES (1,'Areply!','Areply!',UTC_TIMESTAMP(),1,UTC_TIMESTAMP(),0,0);

View File

@ -0,0 +1,9 @@
CREATE TABLE `activity_stream` (
`asid` int not null AUTO_INCREMENT,
`actor` int not null,
`targetUser` int not null,
`event` varchar(50) not null,
`elementType` varchar(50) not null,
`elementID` int not null,
primary key(`asid`)
);

View File

@ -0,0 +1,4 @@
CREATE TABLE `activity_stream_matches` (
`watcher` int not null,
`asid` int not null
);

View File

@ -0,0 +1,6 @@
CREATE TABLE `activity_subscriptions` (
`user` int not null,
`targetID` int not null,
`targetType` varchar(50) not null,
`level` int DEFAULT 0 not null
);

View File

@ -0,0 +1,8 @@
CREATE TABLE `administration_logs` (
`action` varchar(100) not null,
`elementID` int not null,
`elementType` varchar(100) not null,
`ipaddress` varchar(200) not null,
`actorID` int not null,
`doneAt` datetime not null
);

View File

@ -0,0 +1,10 @@
CREATE TABLE `attachments` (
`attachID` int not null AUTO_INCREMENT,
`sectionID` int DEFAULT 0 not null,
`sectionTable` varchar(200) DEFAULT 'forums' not null,
`originID` int not null,
`originTable` varchar(200) DEFAULT 'replies' not null,
`uploadedBy` int not null,
`path` varchar(200) not null,
primary key(`attachID`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;

View File

@ -0,0 +1,6 @@
CREATE TABLE `emails` (
`email` varchar(200) not null,
`uid` int not null,
`validated` boolean DEFAULT 0 not null,
`token` varchar(200) DEFAULT '' not null
);

View File

@ -0,0 +1,13 @@
CREATE TABLE `forums` (
`fid` int not null AUTO_INCREMENT,
`name` varchar(100) not null,
`desc` varchar(200) not null,
`active` boolean DEFAULT 1 not null,
`topicCount` int DEFAULT 0 not null,
`preset` varchar(100) DEFAULT '' not null,
`parentID` int DEFAULT 0 not null,
`parentType` varchar(50) DEFAULT '' not null,
`lastTopicID` int DEFAULT 0 not null,
`lastReplyerID` int DEFAULT 0 not null,
primary key(`fid`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;

View File

@ -0,0 +1,7 @@
CREATE TABLE `forums_permissions` (
`fid` int not null,
`gid` int not null,
`preset` varchar(100) DEFAULT '' not null,
`permissions` text not null,
primary key(`fid`,`gid`)
);

View File

@ -0,0 +1,7 @@
CREATE TABLE `likes` (
`weight` tinyint DEFAULT 1 not null,
`targetItem` int not null,
`targetType` varchar(50) DEFAULT 'replies' not null,
`sentBy` int not null,
`recalc` tinyint DEFAULT 0 not null
);

View File

@ -0,0 +1,8 @@
CREATE TABLE `moderation_logs` (
`action` varchar(100) not null,
`elementID` int not null,
`elementType` varchar(100) not null,
`ipaddress` varchar(200) not null,
`actorID` int not null,
`doneAt` datetime not null
);

View File

@ -0,0 +1,6 @@
CREATE TABLE `plugins` (
`uname` varchar(180) not null,
`active` boolean DEFAULT 0 not null,
`installed` boolean DEFAULT 0 not null,
unique(`uname`)
);

View File

@ -0,0 +1,16 @@
CREATE TABLE `replies` (
`rid` int not null AUTO_INCREMENT,
`tid` int not null,
`content` text not null,
`parsed_content` text not null,
`createdAt` datetime not null,
`createdBy` int not null,
`lastEdit` int not null,
`lastEditBy` int not null,
`lastUpdated` datetime not null,
`ipaddress` varchar(200) DEFAULT '0.0.0.0.0' not null,
`likeCount` int DEFAULT 0 not null,
`words` int DEFAULT 1 not null,
`actionType` varchar(20) DEFAULT '' not null,
primary key(`rid`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;

View File

@ -0,0 +1,6 @@
CREATE TABLE `revisions` (
`index` int not null,
`content` text not null,
`contentID` int not null,
`contentType` varchar(100) DEFAULT 'replies' not null
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;

View File

@ -0,0 +1,7 @@
CREATE TABLE `settings` (
`name` varchar(180) not null,
`content` varchar(250) not null,
`type` varchar(50) not null,
`constraints` varchar(200) DEFAULT '' not null,
unique(`name`)
);

View File

@ -0,0 +1,5 @@
CREATE TABLE `themes` (
`uname` varchar(180) not null,
`default` boolean DEFAULT 0 not null,
unique(`uname`)
);

View File

@ -0,0 +1,20 @@
CREATE TABLE `topics` (
`tid` int not null AUTO_INCREMENT,
`title` varchar(100) not null,
`content` text not null,
`parsed_content` text not null,
`createdAt` datetime not null,
`lastReplyAt` datetime not null,
`lastReplyBy` int not null,
`createdBy` int not null,
`is_closed` boolean DEFAULT 0 not null,
`sticky` boolean DEFAULT 0 not null,
`parentID` int DEFAULT 2 not null,
`ipaddress` varchar(200) DEFAULT '0.0.0.0.0' not null,
`postCount` int DEFAULT 1 not null,
`likeCount` int DEFAULT 0 not null,
`words` int DEFAULT 0 not null,
`css_class` varchar(100) DEFAULT '' not null,
`data` varchar(200) DEFAULT '' not null,
primary key(`tid`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;

View File

@ -0,0 +1,11 @@
CREATE TABLE `users_groups` (
`gid` int not null AUTO_INCREMENT,
`name` varchar(100) not null,
`permissions` text not null,
`plugin_perms` text not null,
`is_mod` boolean DEFAULT 0 not null,
`is_admin` boolean DEFAULT 0 not null,
`is_banned` boolean DEFAULT 0 not null,
`tag` varchar(50) DEFAULT '' not null,
primary key(`gid`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;

View File

@ -0,0 +1,12 @@
CREATE TABLE `users_replies` (
`rid` int not null AUTO_INCREMENT,
`uid` int not null,
`content` text not null,
`parsed_content` text not null,
`createdAt` datetime not null,
`createdBy` int not null,
`lastEdit` int not null,
`lastEditBy` int not null,
`ipaddress` varchar(200) DEFAULT '0.0.0.0.0' not null,
primary key(`rid`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;

View File

@ -0,0 +1,8 @@
CREATE TABLE `widgets` (
`position` int not null,
`side` varchar(100) not null,
`type` varchar(100) not null,
`active` boolean DEFAULT 0 not null,
`location` varchar(100) not null,
`data` text not null
);

View File

@ -0,0 +1,29 @@
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;

View File

@ -0,0 +1,9 @@
CREATE TABLE `activity_stream` (
`asid` serial not null,
`actor` int not null,
`targetUser` int not null,
`event` varchar (50) not null,
`elementType` varchar (50) not null,
`elementID` int not null,
primary key(`asid`)
);

View File

@ -0,0 +1,4 @@
CREATE TABLE `activity_stream_matches` (
`watcher` int not null,
`asid` int not null
);

View File

@ -0,0 +1,6 @@
CREATE TABLE `activity_subscriptions` (
`user` int not null,
`targetID` int not null,
`targetType` varchar (50) not null,
`level` int DEFAULT 0 not null
);

View File

@ -0,0 +1,8 @@
CREATE TABLE `administration_logs` (
`action` varchar (100) not null,
`elementID` int not null,
`elementType` varchar (100) not null,
`ipaddress` varchar (200) not null,
`actorID` int not null,
`doneAt` timestamp not null
);

View File

@ -0,0 +1,10 @@
CREATE TABLE `attachments` (
`attachID` serial not null,
`sectionID` int DEFAULT 0 not null,
`sectionTable` varchar (200) DEFAULT 'forums' not null,
`originID` int not null,
`originTable` varchar (200) DEFAULT 'replies' not null,
`uploadedBy` int not null,
`path` varchar (200) not null,
primary key(`attachID`)
);

View File

@ -0,0 +1,6 @@
CREATE TABLE `emails` (
`email` varchar (200) not null,
`uid` int not null,
`validated` boolean DEFAULT 0 not null,
`token` varchar (200) DEFAULT '' not null
);

View File

@ -0,0 +1,13 @@
CREATE TABLE `forums` (
`fid` serial not null,
`name` varchar (100) not null,
`desc` varchar (200) not null,
`active` boolean DEFAULT 1 not null,
`topicCount` int DEFAULT 0 not null,
`preset` varchar (100) DEFAULT '' not null,
`parentID` int DEFAULT 0 not null,
`parentType` varchar (50) DEFAULT '' not null,
`lastTopicID` int DEFAULT 0 not null,
`lastReplyerID` int DEFAULT 0 not null,
primary key(`fid`)
);

View File

@ -0,0 +1,7 @@
CREATE TABLE `forums_permissions` (
`fid` int not null,
`gid` int not null,
`preset` varchar (100) DEFAULT '' not null,
`permissions` text not null,
primary key(`fid`,`gid`)
);

View File

@ -0,0 +1,7 @@
CREATE TABLE `likes` (
`weight` tinyint DEFAULT 1 not null,
`targetItem` int not null,
`targetType` varchar (50) DEFAULT 'replies' not null,
`sentBy` int not null,
`recalc` tinyint DEFAULT 0 not null
);

View File

@ -0,0 +1,8 @@
CREATE TABLE `moderation_logs` (
`action` varchar (100) not null,
`elementID` int not null,
`elementType` varchar (100) not null,
`ipaddress` varchar (200) not null,
`actorID` int not null,
`doneAt` timestamp not null
);

View File

@ -0,0 +1,6 @@
CREATE TABLE `plugins` (
`uname` varchar (180) not null,
`active` boolean DEFAULT 0 not null,
`installed` boolean DEFAULT 0 not null,
unique(`uname`)
);

View File

@ -0,0 +1,16 @@
CREATE TABLE `replies` (
`rid` serial not null,
`tid` int not null,
`content` text not null,
`parsed_content` text not null,
`createdAt` timestamp not null,
`createdBy` int not null,
`lastEdit` int not null,
`lastEditBy` int not null,
`lastUpdated` timestamp not null,
`ipaddress` varchar (200) DEFAULT '0.0.0.0.0' not null,
`likeCount` int DEFAULT 0 not null,
`words` int DEFAULT 1 not null,
`actionType` varchar (20) DEFAULT '' not null,
primary key(`rid`)
);

View File

@ -0,0 +1,6 @@
CREATE TABLE `revisions` (
`index` int not null,
`content` text not null,
`contentID` int not null,
`contentType` varchar (100) DEFAULT 'replies' not null
);

View File

@ -0,0 +1,7 @@
CREATE TABLE `settings` (
`name` varchar (180) not null,
`content` varchar (250) not null,
`type` varchar (50) not null,
`constraints` varchar (200) DEFAULT '' not null,
unique(`name`)
);

View File

@ -0,0 +1,5 @@
CREATE TABLE `themes` (
`uname` varchar (180) not null,
`default` boolean DEFAULT 0 not null,
unique(`uname`)
);

View File

@ -0,0 +1,20 @@
CREATE TABLE `topics` (
`tid` serial not null,
`title` varchar (100) not null,
`content` text not null,
`parsed_content` text not null,
`createdAt` timestamp not null,
`lastReplyAt` timestamp not null,
`lastReplyBy` int not null,
`createdBy` int not null,
`is_closed` boolean DEFAULT 0 not null,
`sticky` boolean DEFAULT 0 not null,
`parentID` int DEFAULT 2 not null,
`ipaddress` varchar (200) DEFAULT '0.0.0.0.0' not null,
`postCount` int DEFAULT 1 not null,
`likeCount` int DEFAULT 0 not null,
`words` int DEFAULT 0 not null,
`css_class` varchar (100) DEFAULT '' not null,
`data` varchar (200) DEFAULT '' not null,
primary key(`tid`)
);

View File

@ -0,0 +1,11 @@
CREATE TABLE `users_groups` (
`gid` serial not null,
`name` varchar (100) not null,
`permissions` text not null,
`plugin_perms` text not null,
`is_mod` boolean DEFAULT 0 not null,
`is_admin` boolean DEFAULT 0 not null,
`is_banned` boolean DEFAULT 0 not null,
`tag` varchar (50) DEFAULT '' not null,
primary key(`gid`)
);

View File

@ -0,0 +1,12 @@
CREATE TABLE `users_replies` (
`rid` serial not null,
`uid` int not null,
`content` text not null,
`parsed_content` text not null,
`createdAt` timestamp not null,
`createdBy` int not null,
`lastEdit` int not null,
`lastEditBy` int not null,
`ipaddress` varchar (200) DEFAULT '0.0.0.0.0' not null,
primary key(`rid`)
);

View File

@ -0,0 +1,8 @@
CREATE TABLE `widgets` (
`position` int not null,
`side` varchar (100) not null,
`type` varchar (100) not null,
`active` boolean DEFAULT 0 not null,
`location` varchar (100) not null,
`data` text DEFAULT '' not null
);

27
site.go
View File

@ -24,11 +24,19 @@ type Site struct {
} }
type DBConfig struct { type DBConfig struct {
// Production database
Host string Host string
Username string Username string
Password string Password string
Dbname string Dbname string
Port string Port string
// Test database. Split this into a separate variable?
TestHost string
TestUsername string
TestPassword string
TestDbname string
TestPort string
} }
type Config struct { type Config struct {
@ -62,9 +70,10 @@ type DevConfig struct {
SuperDebug bool SuperDebug bool
TemplateDebug bool TemplateDebug bool
Profiling bool Profiling bool
TestDB bool
} }
func processConfig() { func processConfig() error {
config.Noavatar = strings.Replace(config.Noavatar, "{site_url}", site.URL, -1) config.Noavatar = strings.Replace(config.Noavatar, "{site_url}", site.URL, -1)
if site.Port != "80" && site.Port != "443" { if site.Port != "80" && site.Port != "443" {
site.URL = strings.TrimSuffix(site.URL, "/") site.URL = strings.TrimSuffix(site.URL, "/")
@ -72,6 +81,14 @@ func processConfig() {
site.URL = strings.TrimSuffix(site.URL, ":") site.URL = strings.TrimSuffix(site.URL, ":")
site.URL = site.URL + ":" + site.Port site.URL = site.URL + ":" + site.Port
} }
// We need this in here rather than verifyConfig as switchToTestDB() currently overwrites the values it verifies
if dbConfig.TestDbname == dbConfig.Dbname {
return errors.New("Your test database can't have the same name as your production database")
}
if dev.TestDB {
switchToTestDB()
}
return nil
} }
func verifyConfig() error { func verifyConfig() error {
@ -80,3 +97,11 @@ func verifyConfig() error {
} }
return nil return nil
} }
func switchToTestDB() {
dbConfig.Host = dbConfig.TestHost
dbConfig.Username = dbConfig.TestUsername
dbConfig.Password = dbConfig.TestPassword
dbConfig.Dbname = dbConfig.TestDbname
dbConfig.Port = dbConfig.TestPort
}

View File

@ -45,13 +45,7 @@ func handleExpiredScheduledGroups() error {
func handleServerSync() error { func handleServerSync() error {
var lastUpdate time.Time var lastUpdate time.Time
var lastUpdateStr string err := getSyncStmt.QueryRow().Scan(&lastUpdate)
err := getSyncStmt.QueryRow().Scan(&lastUpdateStr)
if err != nil {
return err
}
lastUpdate, err = time.Parse("2006-01-02 15:04:05", lastUpdateStr)
if err != nil { if err != nil {
return err return err
} }

View File

@ -173,7 +173,7 @@ w.Write([]byte(item.LastUser.Link))
w.Write(forum_43) w.Write(forum_43)
w.Write([]byte(item.LastUser.Name)) w.Write([]byte(item.LastUser.Name))
w.Write(forum_44) w.Write(forum_44)
w.Write([]byte(item.LastReplyAt)) w.Write([]byte(item.RelativeLastReplyAt))
w.Write(forum_45) w.Write(forum_45)
} }
} else { } else {

View File

@ -1,8 +1,11 @@
package main package main
import "log" import (
import "html/template" "html/template"
import "net/http" "log"
"net/http"
"time"
)
var templates = template.New("") var templates = template.New("")
@ -148,7 +151,7 @@ func compileTemplates() error {
} }
var topicsList []*TopicsRow var topicsList []*TopicsRow
topicsList = append(topicsList, &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, "Date", "Date", user3.ID, 1, "", "127.0.0.1", 0, 1, "classname", "", &user2, "", 0, &user3, "General", "/forum/general.2"}) topicsList = append(topicsList, &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, "Date", time.Now(), "Date", user3.ID, 1, "", "127.0.0.1", 0, 1, "classname", "", &user2, "", 0, &user3, "General", "/forum/general.2"})
topicsPage := TopicsPage{"Topic List", user, headerVars, topicsList, forumList, config.DefaultForum} topicsPage := TopicsPage{"Topic List", user, headerVars, topicsList, forumList, config.DefaultForum}
topicsTmpl, err := c.compileTemplate("topics.html", "templates/", "TopicsPage", topicsPage, varList) topicsTmpl, err := c.compileTemplate("topics.html", "templates/", "TopicsPage", topicsPage, varList)
if err != nil { if err != nil {

View File

@ -173,7 +173,7 @@ w.Write([]byte(item.LastUser.Link))
w.Write(topics_42) w.Write(topics_42)
w.Write([]byte(item.LastUser.Name)) w.Write([]byte(item.LastUser.Name))
w.Write(topics_43) w.Write(topics_43)
w.Write([]byte(item.LastReplyAt)) w.Write([]byte(item.RelativeLastReplyAt))
w.Write(topics_44) w.Write(topics_44)
} }
} else { } else {

Some files were not shown because too many files have changed in this diff Show More