gosora/common/user_store.go

478 lines
16 KiB
Go
Raw Normal View History

package common
Added support for HTTP/2 Push. The themes are still going to be a little broken for a while, but here's the progress I've made. Renamed the topics_trow_assign hook to topics_topic_row_assign. Added more debug code to the generated router. Added a robots.txt file. Gosora now responds to favicon.ico requests with a 404 rather than the topic list. Fixed the tests and some of the benchmarks. Changed the default UserCacheCapacity from 100 to 120. Changed the default TopicCacheCapacity from 100 to 200. Added the last replyer to the topics list and the forum pages. Added the BulkCascadeGetMap method to the UserStore. Refactored the topics list and forum page to load the users with a call to the UserStore rather than via a join. WebSockets now work on SSL. Fixed a race condition when the user permissions are initialised at the start of a request. Fixed a race condition when the user permissions for the OP of a topic are initialised. The rows.Close() calls are deferred once more, so that we can catch problems with recover() Improved support for struct pointers in the template compiler. Added a pin emoji to pinned topics to make them stand-out on the Shadow theme, we have some other ideas in mind for this, but I'd like to get Shadow fully functional for this commit. Fixed a bug an issue with Chrome not detecting XHTML style closes on <form>s. Fixed a visual issue with `color` not being set for textarea elements for the Shadow theme. Fixed a function which wasn't getting renamed for PGSQL. Added seven new UserStore tests.
2017-08-06 15:22:18 +00:00
import (
2022-02-21 03:32:53 +00:00
"database/sql"
"errors"
"strconv"
Added support for HTTP/2 Push. The themes are still going to be a little broken for a while, but here's the progress I've made. Renamed the topics_trow_assign hook to topics_topic_row_assign. Added more debug code to the generated router. Added a robots.txt file. Gosora now responds to favicon.ico requests with a 404 rather than the topic list. Fixed the tests and some of the benchmarks. Changed the default UserCacheCapacity from 100 to 120. Changed the default TopicCacheCapacity from 100 to 200. Added the last replyer to the topics list and the forum pages. Added the BulkCascadeGetMap method to the UserStore. Refactored the topics list and forum page to load the users with a call to the UserStore rather than via a join. WebSockets now work on SSL. Fixed a race condition when the user permissions are initialised at the start of a request. Fixed a race condition when the user permissions for the OP of a topic are initialised. The rows.Close() calls are deferred once more, so that we can catch problems with recover() Improved support for struct pointers in the template compiler. Added a pin emoji to pinned topics to make them stand-out on the Shadow theme, we have some other ideas in mind for this, but I'd like to get Shadow fully functional for this commit. Fixed a bug an issue with Chrome not detecting XHTML style closes on <form>s. Fixed a visual issue with `color` not being set for textarea elements for the Shadow theme. Fixed a function which wasn't getting renamed for PGSQL. Added seven new UserStore tests.
2017-08-06 15:22:18 +00:00
2022-02-21 03:32:53 +00:00
qgen "github.com/Azareal/Gosora/query_gen"
"golang.org/x/crypto/bcrypt"
Added support for HTTP/2 Push. The themes are still going to be a little broken for a while, but here's the progress I've made. Renamed the topics_trow_assign hook to topics_topic_row_assign. Added more debug code to the generated router. Added a robots.txt file. Gosora now responds to favicon.ico requests with a 404 rather than the topic list. Fixed the tests and some of the benchmarks. Changed the default UserCacheCapacity from 100 to 120. Changed the default TopicCacheCapacity from 100 to 200. Added the last replyer to the topics list and the forum pages. Added the BulkCascadeGetMap method to the UserStore. Refactored the topics list and forum page to load the users with a call to the UserStore rather than via a join. WebSockets now work on SSL. Fixed a race condition when the user permissions are initialised at the start of a request. Fixed a race condition when the user permissions for the OP of a topic are initialised. The rows.Close() calls are deferred once more, so that we can catch problems with recover() Improved support for struct pointers in the template compiler. Added a pin emoji to pinned topics to make them stand-out on the Shadow theme, we have some other ideas in mind for this, but I'd like to get Shadow fully functional for this commit. Fixed a bug an issue with Chrome not detecting XHTML style closes on <form>s. Fixed a visual issue with `color` not being set for textarea elements for the Shadow theme. Fixed a function which wasn't getting renamed for PGSQL. Added seven new UserStore tests.
2017-08-06 15:22:18 +00:00
)
// TODO: Add the watchdog goroutine
// TODO: Add some sort of update method
var Users UserStore
var ErrAccountExists = errors.New("this username is already in use")
var ErrLongUsername = errors.New("this username is too long")
var ErrSomeUsersNotFound = errors.New("Unable to find some users")
type UserStore interface {
2022-02-21 03:32:53 +00:00
DirtyGet(id int) *User
Get(id int) (*User, error)
Getn(id int) *User
GetByName(name string) (*User, error)
BulkGetByName(names []string) (list []*User, err error)
RawBulkGetByNameForConvo(f func(int, string, int, bool, int, int) error, names []string) error
Exists(id int) bool
SearchOffset(name, email string, gid, offset, perPage int) (users []*User, err error)
GetOffset(offset, perPage int) ([]*User, error)
Each(f func(*User) error) error
//BulkGet(ids []int) ([]*User, error)
BulkGetMap(ids []int) (map[int]*User, error)
BypassGet(id int) (*User, error)
ClearLastIPs() error
Create(name, password, email string, group int, active bool) (int, error)
Reload(id int) error
Count() int
CountSearch(name, email string, gid int) int
SetCache(cache UserCache)
GetCache() UserCache
}
Added the AboutSegment feature, you can see this in use on Cosora, it's a little raw right now, but I'm planning to polish it in the next commit. Refactored the code to use switches instead of if blocks in some places. Refactored the Dashboard to make it easier to add icons to it like I did with Cosora. You can now use maps in transpiled templates. Made progress on Cosora's footer. Swapped out the ThemeName property in the HeaderVars struct for a more general and flexible Theme property. Added the colstack CSS class to make it easier to style the layouts for the Control Panel and profile. Renamed the FStore variable to Forums. Renamed the Fpstore variable to FPStore. Renamed the Gstore variable to Groups. Split the MemoryTopicStore into DefaultTopicStore and MemoryTopicCache. Split the MemoryUserStore into DefaultUserStore and MemoryUserCache. Removed the NullUserStore, SQLUserStore, and SQLTopicStore. Added the NullTopicCache and NullUserCache. Moved the Reload method out of the TopicCache interface and into the TopicStore one. Moved the Reload method out of the UserCache interface and into the UserStore one. Added the SetCache and GetCache methods to the TopicStore and UserStore. Added the BypassGetAll method to the WordFilterMap type. Renamed routePanelSetting to routePanelSettingEdit. Renamed routePanelSettingEdit to routePanelSettingEditSubmit. Moved the page titles into the english language pack. Split main() into main and afterDBInit to avoid code duplication in general_test.go Added the ReqIsJson method so that we don't have to sniff the headers every time. Added the LogStore interface. Added the SQLModLogStore and the SQLAdminLogStore. Refactored the phrase system to use getPhrasePlaceholder instead of hard-coding the string to return in a bunch of functions. Removed a redundant rank check. Added the GuildStore to plugin_guilds. Added the about_segment_title and about_segment_body settings. Refactored the setting system to use predefined errors to make it easier for an upstream caller to filter out sensitive error messages as opposed to safe errors. Added the BypassGetAll method to the SettingMap type. Added the Update method to the SettingMap type. BulkGet is now exposed via the MemoryUserCache. Refactored more logs in the template transpiler to reduce the amount of indentation. Refactored the tests to take up fewer lines. Further improved the Cosora theme's colours, padding, and profiles. Added styling for the Control Panel Dashboard to the Cosora Theme. Reduced the amount of code duplication in the installer query generator and opened the door to certain types of auto-migrations. Refactored the Control Panel Dashboard to reduce the amount of code duplication. Refactored the modlog route to reduce the amount of code duplication and string concatenation.
2017-11-23 05:37:08 +00:00
type DefaultUserStore struct {
2022-02-21 03:32:53 +00:00
cache UserCache
Added the AboutSegment feature, you can see this in use on Cosora, it's a little raw right now, but I'm planning to polish it in the next commit. Refactored the code to use switches instead of if blocks in some places. Refactored the Dashboard to make it easier to add icons to it like I did with Cosora. You can now use maps in transpiled templates. Made progress on Cosora's footer. Swapped out the ThemeName property in the HeaderVars struct for a more general and flexible Theme property. Added the colstack CSS class to make it easier to style the layouts for the Control Panel and profile. Renamed the FStore variable to Forums. Renamed the Fpstore variable to FPStore. Renamed the Gstore variable to Groups. Split the MemoryTopicStore into DefaultTopicStore and MemoryTopicCache. Split the MemoryUserStore into DefaultUserStore and MemoryUserCache. Removed the NullUserStore, SQLUserStore, and SQLTopicStore. Added the NullTopicCache and NullUserCache. Moved the Reload method out of the TopicCache interface and into the TopicStore one. Moved the Reload method out of the UserCache interface and into the UserStore one. Added the SetCache and GetCache methods to the TopicStore and UserStore. Added the BypassGetAll method to the WordFilterMap type. Renamed routePanelSetting to routePanelSettingEdit. Renamed routePanelSettingEdit to routePanelSettingEditSubmit. Moved the page titles into the english language pack. Split main() into main and afterDBInit to avoid code duplication in general_test.go Added the ReqIsJson method so that we don't have to sniff the headers every time. Added the LogStore interface. Added the SQLModLogStore and the SQLAdminLogStore. Refactored the phrase system to use getPhrasePlaceholder instead of hard-coding the string to return in a bunch of functions. Removed a redundant rank check. Added the GuildStore to plugin_guilds. Added the about_segment_title and about_segment_body settings. Refactored the setting system to use predefined errors to make it easier for an upstream caller to filter out sensitive error messages as opposed to safe errors. Added the BypassGetAll method to the SettingMap type. Added the Update method to the SettingMap type. BulkGet is now exposed via the MemoryUserCache. Refactored more logs in the template transpiler to reduce the amount of indentation. Refactored the tests to take up fewer lines. Further improved the Cosora theme's colours, padding, and profiles. Added styling for the Control Panel Dashboard to the Cosora Theme. Reduced the amount of code duplication in the installer query generator and opened the door to certain types of auto-migrations. Refactored the Control Panel Dashboard to reduce the amount of code duplication. Refactored the modlog route to reduce the amount of code duplication and string concatenation.
2017-11-23 05:37:08 +00:00
2022-02-21 03:32:53 +00:00
get *sql.Stmt
getByName *sql.Stmt
searchOffset *sql.Stmt
getOffset *sql.Stmt
getAll *sql.Stmt
exists *sql.Stmt
register *sql.Stmt
nameExists *sql.Stmt
2022-02-21 03:32:53 +00:00
count *sql.Stmt
countSearch *sql.Stmt
2022-02-21 03:32:53 +00:00
clearIPs *sql.Stmt
}
Added the AboutSegment feature, you can see this in use on Cosora, it's a little raw right now, but I'm planning to polish it in the next commit. Refactored the code to use switches instead of if blocks in some places. Refactored the Dashboard to make it easier to add icons to it like I did with Cosora. You can now use maps in transpiled templates. Made progress on Cosora's footer. Swapped out the ThemeName property in the HeaderVars struct for a more general and flexible Theme property. Added the colstack CSS class to make it easier to style the layouts for the Control Panel and profile. Renamed the FStore variable to Forums. Renamed the Fpstore variable to FPStore. Renamed the Gstore variable to Groups. Split the MemoryTopicStore into DefaultTopicStore and MemoryTopicCache. Split the MemoryUserStore into DefaultUserStore and MemoryUserCache. Removed the NullUserStore, SQLUserStore, and SQLTopicStore. Added the NullTopicCache and NullUserCache. Moved the Reload method out of the TopicCache interface and into the TopicStore one. Moved the Reload method out of the UserCache interface and into the UserStore one. Added the SetCache and GetCache methods to the TopicStore and UserStore. Added the BypassGetAll method to the WordFilterMap type. Renamed routePanelSetting to routePanelSettingEdit. Renamed routePanelSettingEdit to routePanelSettingEditSubmit. Moved the page titles into the english language pack. Split main() into main and afterDBInit to avoid code duplication in general_test.go Added the ReqIsJson method so that we don't have to sniff the headers every time. Added the LogStore interface. Added the SQLModLogStore and the SQLAdminLogStore. Refactored the phrase system to use getPhrasePlaceholder instead of hard-coding the string to return in a bunch of functions. Removed a redundant rank check. Added the GuildStore to plugin_guilds. Added the about_segment_title and about_segment_body settings. Refactored the setting system to use predefined errors to make it easier for an upstream caller to filter out sensitive error messages as opposed to safe errors. Added the BypassGetAll method to the SettingMap type. Added the Update method to the SettingMap type. BulkGet is now exposed via the MemoryUserCache. Refactored more logs in the template transpiler to reduce the amount of indentation. Refactored the tests to take up fewer lines. Further improved the Cosora theme's colours, padding, and profiles. Added styling for the Control Panel Dashboard to the Cosora Theme. Reduced the amount of code duplication in the installer query generator and opened the door to certain types of auto-migrations. Refactored the Control Panel Dashboard to reduce the amount of code duplication. Refactored the modlog route to reduce the amount of code duplication and string concatenation.
2017-11-23 05:37:08 +00:00
// NewDefaultUserStore gives you a new instance of DefaultUserStore
func NewDefaultUserStore(cache UserCache) (*DefaultUserStore, error) {
2022-02-21 03:32:53 +00:00
acc := qgen.NewAcc()
if cache == nil {
cache = NewNullUserCache()
}
u := "users"
allCols := "uid,name,group,active,is_super_admin,session,email,avatar,message,level,score,posts,liked,last_ip,temp_group,createdAt,enable_embeds,profile_comments,who_can_convo"
// TODO: Add an admin version of registerStmt with more flexibility?
return &DefaultUserStore{
cache: cache,
get: acc.Select(u).Columns("name,group,active,is_super_admin,session,email,avatar,message,level,score,posts,liked,last_ip,temp_group,createdAt,enable_embeds,profile_comments,who_can_convo").Where("uid=?").Prepare(),
getByName: acc.Select(u).Columns(allCols).Where("name=?").Prepare(),
searchOffset: acc.Select(u).Columns(allCols).Where("(name=? OR ?='') AND (email=? OR ?='') AND (group=? OR ?=0)").Orderby("uid ASC").Limit("?,?").Prepare(),
getOffset: acc.Select(u).Columns(allCols).Orderby("uid ASC").Limit("?,?").Prepare(),
getAll: acc.Select(u).Columns(allCols).Prepare(),
exists: acc.Exists(u, "uid").Prepare(),
register: acc.Insert(u).Columns("name,email,password,salt,group,is_super_admin,session,active,message,createdAt,lastActiveAt,lastLiked,oldestItemLikedCreatedAt").Fields("?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP()").Prepare(), // TODO: Implement user_count on users_groups here
nameExists: acc.Exists(u, "name").Prepare(),
count: acc.Count(u).Prepare(),
countSearch: acc.Count(u).Where("(name=? OR ?='') AND (email=? OR ?='') AND (group=? OR ?=0)").Prepare(),
clearIPs: acc.Update(u).Set("last_ip=''").Where("last_ip!=''").Prepare(),
}, acc.FirstError()
}
func (s *DefaultUserStore) DirtyGet(id int) *User {
2022-02-21 03:32:53 +00:00
user, err := s.Get(id)
if err == nil {
return user
}
/*if s.OutOfBounds(id) {
return BlankUser()
}*/
return BlankUser()
}
func (s *DefaultUserStore) scanUser(r *sql.Row, u *User) (embeds int, err error) {
2022-02-21 03:32:53 +00:00
e := r.Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage)
return embeds, e
}
Added the AboutSegment feature, you can see this in use on Cosora, it's a little raw right now, but I'm planning to polish it in the next commit. Refactored the code to use switches instead of if blocks in some places. Refactored the Dashboard to make it easier to add icons to it like I did with Cosora. You can now use maps in transpiled templates. Made progress on Cosora's footer. Swapped out the ThemeName property in the HeaderVars struct for a more general and flexible Theme property. Added the colstack CSS class to make it easier to style the layouts for the Control Panel and profile. Renamed the FStore variable to Forums. Renamed the Fpstore variable to FPStore. Renamed the Gstore variable to Groups. Split the MemoryTopicStore into DefaultTopicStore and MemoryTopicCache. Split the MemoryUserStore into DefaultUserStore and MemoryUserCache. Removed the NullUserStore, SQLUserStore, and SQLTopicStore. Added the NullTopicCache and NullUserCache. Moved the Reload method out of the TopicCache interface and into the TopicStore one. Moved the Reload method out of the UserCache interface and into the UserStore one. Added the SetCache and GetCache methods to the TopicStore and UserStore. Added the BypassGetAll method to the WordFilterMap type. Renamed routePanelSetting to routePanelSettingEdit. Renamed routePanelSettingEdit to routePanelSettingEditSubmit. Moved the page titles into the english language pack. Split main() into main and afterDBInit to avoid code duplication in general_test.go Added the ReqIsJson method so that we don't have to sniff the headers every time. Added the LogStore interface. Added the SQLModLogStore and the SQLAdminLogStore. Refactored the phrase system to use getPhrasePlaceholder instead of hard-coding the string to return in a bunch of functions. Removed a redundant rank check. Added the GuildStore to plugin_guilds. Added the about_segment_title and about_segment_body settings. Refactored the setting system to use predefined errors to make it easier for an upstream caller to filter out sensitive error messages as opposed to safe errors. Added the BypassGetAll method to the SettingMap type. Added the Update method to the SettingMap type. BulkGet is now exposed via the MemoryUserCache. Refactored more logs in the template transpiler to reduce the amount of indentation. Refactored the tests to take up fewer lines. Further improved the Cosora theme's colours, padding, and profiles. Added styling for the Control Panel Dashboard to the Cosora Theme. Reduced the amount of code duplication in the installer query generator and opened the door to certain types of auto-migrations. Refactored the Control Panel Dashboard to reduce the amount of code duplication. Refactored the modlog route to reduce the amount of code duplication and string concatenation.
2017-11-23 05:37:08 +00:00
// TODO: Log weird cache errors? Not just here but in every *Cache?
func (s *DefaultUserStore) Get(id int) (*User, error) {
2022-02-21 03:32:53 +00:00
u, err := s.cache.Get(id)
if err == nil {
//log.Print("cached user")
//log.Print(string(debug.Stack()))
//log.Println("")
return u, nil
}
//log.Print("uncached user")
u = &User{ID: id, Loggedin: true}
embeds, err := s.scanUser(s.get.QueryRow(id), u)
if err == nil {
if embeds != -1 {
u.ParseSettings = DefaultParseSettings.CopyPtr()
u.ParseSettings.NoEmbed = embeds == 0
}
u.Init()
s.cache.Set(u)
}
return u, err
}
func (s *DefaultUserStore) Getn(id int) *User {
2022-02-21 03:32:53 +00:00
u := s.cache.Getn(id)
if u != nil {
return u
}
u = &User{ID: id, Loggedin: true}
embeds, err := s.scanUser(s.get.QueryRow(id), u)
if err != nil {
return nil
}
if embeds != -1 {
u.ParseSettings = DefaultParseSettings.CopyPtr()
u.ParseSettings.NoEmbed = embeds == 0
}
u.Init()
s.cache.Set(u)
return u
}
// TODO: Log weird cache errors? Not just here but in every *Cache?
// ! This bypasses the cache, use frugally
func (s *DefaultUserStore) GetByName(name string) (*User, error) {
2022-02-21 03:32:53 +00:00
u := &User{Loggedin: true}
var embeds int
err := s.getByName.QueryRow(name).Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage)
if err != nil {
return nil, err
}
if embeds != -1 {
u.ParseSettings = DefaultParseSettings.CopyPtr()
u.ParseSettings.NoEmbed = embeds == 0
}
u.Init()
s.cache.Set(u)
return u, nil
}
// TODO: Optimise the query to avoid preparing it on the spot? Maybe, use knowledge of the most common IN() parameter counts?
// ! This bypasses the cache, use frugally
func (s *DefaultUserStore) BulkGetByName(names []string) (list []*User, err error) {
2022-02-21 03:32:53 +00:00
if len(names) == 0 {
return list, nil
} else if len(names) == 1 {
user, err := s.GetByName(names[0])
if err != nil {
return list, err
}
return []*User{user}, nil
}
idList, q := inqbuildstr(names)
rows, err := qgen.NewAcc().Select("users").Columns("uid,name,group,active,is_super_admin,session,email,avatar,message,level,score,posts,liked,last_ip,temp_group,createdAt,enable_embeds,profile_comments,who_can_convo").Where("name IN(" + q + ")").Query(idList...)
if err != nil {
return list, err
}
defer rows.Close()
var embeds int
for rows.Next() {
u := &User{Loggedin: true}
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage)
if err != nil {
return list, err
}
if embeds != -1 {
u.ParseSettings = DefaultParseSettings.CopyPtr()
u.ParseSettings.NoEmbed = embeds == 0
}
u.Init()
s.cache.Set(u)
list = append(list, u)
}
if err = rows.Err(); err != nil {
return list, err
}
// Did we miss any users?
if len(names) > len(list) {
return list, ErrSomeUsersNotFound
}
return list, err
}
// Special case function for efficiency
func (s *DefaultUserStore) RawBulkGetByNameForConvo(f func(int, string, int, bool, int, int) error, names []string) error {
2022-02-21 03:32:53 +00:00
idList, q := inqbuildstr(names)
rows, e := qgen.NewAcc().Select("users").Columns("uid,name,group,is_super_admin,temp_group,who_can_convo").Where("name IN(" + q + ")").Query(idList...)
if e != nil {
return e
}
defer rows.Close()
for rows.Next() {
var name string
var id, group, temp_group, who_can_convo int
var super_admin bool
if e = rows.Scan(&id, &name, &group, &super_admin, &temp_group, &who_can_convo); e != nil {
return e
}
if e = f(id, name, group, super_admin, temp_group, who_can_convo); e != nil {
return e
}
}
return rows.Err()
}
UNSTABLE: Began work on the Nox Theme. Removed the Tempra Cursive Theme. You can now do bulk moderation actions with Shadow. Added: Argon2 as a dependency. The EmailStore. The ReportStore. The Copy method to *Setting. The AddColumn method to the query builder and adapters. The textarea setting type. More logging to better debug issues. The GetOffset method to the UserStore. Removed: Sortable from Code Climate's Analysis. MemberCheck and memberCheck as they're obsolete now. The obsolete url_tags setting. The BcryptGeneratePasswordNoSalt function. Some redundant fields from some of the page structs. Revamped: The Control Panel Setting List and Editor. Refactored: The password hashing logic to make it more amenable to multiple hashing algorithms. The email portion of the Account Manager. The Control Panel User List. The report system. simplePanelUserCheck and simpleUserCheck to remove the duplicated logic as the two do the exact same thing. Fixed: Missing slugs in the profile links in the User Manager. A few template initialisers potentially reducing the number of odd template edge cases. Some problems with the footer. Custom selection colour not applying to images on Shadow. The avatars of the bottom row of the topic list on Conflux leaking out. Other: Moved the startTime variable into package common and exported it. Moved the password hashing logic from user.go to auth.go Split common/themes.go into common/theme.go and common/theme_list.go Replaced the SettingLabels phrase category with the more generic SettingPhrases category. Moved a load of routes, including panel ones into the routes and panel packages. Hid the notifications link from the Account Menu. Moved more inline CSS into the CSS files and made things a little more flexible here and there. Continued work on PgSQL, still a ways away. Guests now have a default avatar like everyone else. Tweaked some of the font sizes on Cosora to make the text look a little nicer. Partially implemented the theme dock override logic. Partially implemented a "symlink" like feature for theme directories. ... And a bunch of other things I might have missed. You will need to run this update script / patcher for this commit. Warning: This is an "unstable commit", therefore some things may be a little less stable than I'd like. For instance, the Shadow Theme is a little broken in this commit.
2018-05-27 09:36:35 +00:00
// TODO: Optimise this, so we don't wind up hitting the database every-time for small gaps
// TODO: Make this a little more consistent with DefaultGroupStore's GetRange method
func (s *DefaultUserStore) GetOffset(offset, perPage int) (users []*User, err error) {
2022-02-21 03:32:53 +00:00
rows, err := s.getOffset.Query(offset, perPage)
if err != nil {
return users, err
}
defer rows.Close()
var embeds int
for rows.Next() {
u := &User{Loggedin: true}
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage)
if err != nil {
return nil, err
}
if embeds != -1 {
u.ParseSettings = DefaultParseSettings.CopyPtr()
u.ParseSettings.NoEmbed = embeds == 0
}
u.Init()
s.cache.Set(u)
users = append(users, u)
}
return users, rows.Err()
UNSTABLE: Began work on the Nox Theme. Removed the Tempra Cursive Theme. You can now do bulk moderation actions with Shadow. Added: Argon2 as a dependency. The EmailStore. The ReportStore. The Copy method to *Setting. The AddColumn method to the query builder and adapters. The textarea setting type. More logging to better debug issues. The GetOffset method to the UserStore. Removed: Sortable from Code Climate's Analysis. MemberCheck and memberCheck as they're obsolete now. The obsolete url_tags setting. The BcryptGeneratePasswordNoSalt function. Some redundant fields from some of the page structs. Revamped: The Control Panel Setting List and Editor. Refactored: The password hashing logic to make it more amenable to multiple hashing algorithms. The email portion of the Account Manager. The Control Panel User List. The report system. simplePanelUserCheck and simpleUserCheck to remove the duplicated logic as the two do the exact same thing. Fixed: Missing slugs in the profile links in the User Manager. A few template initialisers potentially reducing the number of odd template edge cases. Some problems with the footer. Custom selection colour not applying to images on Shadow. The avatars of the bottom row of the topic list on Conflux leaking out. Other: Moved the startTime variable into package common and exported it. Moved the password hashing logic from user.go to auth.go Split common/themes.go into common/theme.go and common/theme_list.go Replaced the SettingLabels phrase category with the more generic SettingPhrases category. Moved a load of routes, including panel ones into the routes and panel packages. Hid the notifications link from the Account Menu. Moved more inline CSS into the CSS files and made things a little more flexible here and there. Continued work on PgSQL, still a ways away. Guests now have a default avatar like everyone else. Tweaked some of the font sizes on Cosora to make the text look a little nicer. Partially implemented the theme dock override logic. Partially implemented a "symlink" like feature for theme directories. ... And a bunch of other things I might have missed. You will need to run this update script / patcher for this commit. Warning: This is an "unstable commit", therefore some things may be a little less stable than I'd like. For instance, the Shadow Theme is a little broken in this commit.
2018-05-27 09:36:35 +00:00
}
func (s *DefaultUserStore) SearchOffset(name, email string, gid, offset, perPage int) (users []*User, err error) {
2022-02-21 03:32:53 +00:00
rows, err := s.searchOffset.Query(name, name, email, email, gid, gid, offset, perPage)
if err != nil {
return users, err
}
defer rows.Close()
var embeds int
for rows.Next() {
u := &User{Loggedin: true}
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage)
if err != nil {
return nil, err
}
if embeds != -1 {
u.ParseSettings = DefaultParseSettings.CopyPtr()
u.ParseSettings.NoEmbed = embeds == 0
}
u.Init()
s.cache.Set(u)
users = append(users, u)
}
return users, rows.Err()
}
func (s *DefaultUserStore) Each(f func(*User) error) error {
2022-02-21 03:32:53 +00:00
rows, e := s.getAll.Query()
if e != nil {
return e
}
defer rows.Close()
var embeds int
for rows.Next() {
u := new(User)
if e := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage); e != nil {
return e
}
if embeds != -1 {
u.ParseSettings = DefaultParseSettings.CopyPtr()
u.ParseSettings.NoEmbed = embeds == 0
}
u.Init()
if e := f(u); e != nil {
return e
}
}
return rows.Err()
}
UNSTABLE: Began work on the Nox Theme. Removed the Tempra Cursive Theme. You can now do bulk moderation actions with Shadow. Added: Argon2 as a dependency. The EmailStore. The ReportStore. The Copy method to *Setting. The AddColumn method to the query builder and adapters. The textarea setting type. More logging to better debug issues. The GetOffset method to the UserStore. Removed: Sortable from Code Climate's Analysis. MemberCheck and memberCheck as they're obsolete now. The obsolete url_tags setting. The BcryptGeneratePasswordNoSalt function. Some redundant fields from some of the page structs. Revamped: The Control Panel Setting List and Editor. Refactored: The password hashing logic to make it more amenable to multiple hashing algorithms. The email portion of the Account Manager. The Control Panel User List. The report system. simplePanelUserCheck and simpleUserCheck to remove the duplicated logic as the two do the exact same thing. Fixed: Missing slugs in the profile links in the User Manager. A few template initialisers potentially reducing the number of odd template edge cases. Some problems with the footer. Custom selection colour not applying to images on Shadow. The avatars of the bottom row of the topic list on Conflux leaking out. Other: Moved the startTime variable into package common and exported it. Moved the password hashing logic from user.go to auth.go Split common/themes.go into common/theme.go and common/theme_list.go Replaced the SettingLabels phrase category with the more generic SettingPhrases category. Moved a load of routes, including panel ones into the routes and panel packages. Hid the notifications link from the Account Menu. Moved more inline CSS into the CSS files and made things a little more flexible here and there. Continued work on PgSQL, still a ways away. Guests now have a default avatar like everyone else. Tweaked some of the font sizes on Cosora to make the text look a little nicer. Partially implemented the theme dock override logic. Partially implemented a "symlink" like feature for theme directories. ... And a bunch of other things I might have missed. You will need to run this update script / patcher for this commit. Warning: This is an "unstable commit", therefore some things may be a little less stable than I'd like. For instance, the Shadow Theme is a little broken in this commit.
2018-05-27 09:36:35 +00:00
// TODO: Optimise the query to avoid preparing it on the spot? Maybe, use knowledge of the most common IN() parameter counts?
// TODO: ID of 0 should always error?
func (s *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err error) {
2022-02-21 03:32:53 +00:00
idCount := len(ids)
list = make(map[int]*User)
if idCount == 0 {
return list, nil
}
var stillHere []int
sliceList := s.cache.BulkGet(ids)
if len(sliceList) > 0 {
for i, sliceItem := range sliceList {
if sliceItem != nil {
list[sliceItem.ID] = sliceItem
} else {
stillHere = append(stillHere, ids[i])
}
}
ids = stillHere
}
// If every user is in the cache, then return immediately
if len(ids) == 0 {
return list, nil
} else if len(ids) == 1 {
user, err := s.Get(ids[0])
if err != nil {
return list, err
}
list[user.ID] = user
return list, nil
}
idList, q := inqbuild(ids)
rows, err := qgen.NewAcc().Select("users").Columns("uid,name,group,active,is_super_admin,session,email,avatar,message,level,score,posts,liked,last_ip,temp_group,createdAt,enable_embeds,profile_comments,who_can_convo").Where("uid IN(" + q + ")").Query(idList...)
if err != nil {
return list, err
}
defer rows.Close()
var embeds int
for rows.Next() {
u := &User{Loggedin: true}
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &u.CreatedAt, &embeds, &u.Privacy.ShowComments, &u.Privacy.AllowMessage)
if err != nil {
return list, err
}
if embeds != -1 {
u.ParseSettings = DefaultParseSettings.CopyPtr()
u.ParseSettings.NoEmbed = embeds == 0
}
u.Init()
s.cache.Set(u)
list[u.ID] = u
}
if err = rows.Err(); err != nil {
return list, err
}
// Did we miss any users?
if idCount > len(list) {
var sidList string
for _, id := range ids {
_, ok := list[id]
if !ok {
sidList += strconv.Itoa(id) + ","
}
}
if sidList != "" {
sidList = sidList[0 : len(sidList)-1]
err = errors.New("Unable to find users with the following IDs: " + sidList)
}
}
return list, err
Added support for HTTP/2 Push. The themes are still going to be a little broken for a while, but here's the progress I've made. Renamed the topics_trow_assign hook to topics_topic_row_assign. Added more debug code to the generated router. Added a robots.txt file. Gosora now responds to favicon.ico requests with a 404 rather than the topic list. Fixed the tests and some of the benchmarks. Changed the default UserCacheCapacity from 100 to 120. Changed the default TopicCacheCapacity from 100 to 200. Added the last replyer to the topics list and the forum pages. Added the BulkCascadeGetMap method to the UserStore. Refactored the topics list and forum page to load the users with a call to the UserStore rather than via a join. WebSockets now work on SSL. Fixed a race condition when the user permissions are initialised at the start of a request. Fixed a race condition when the user permissions for the OP of a topic are initialised. The rows.Close() calls are deferred once more, so that we can catch problems with recover() Improved support for struct pointers in the template compiler. Added a pin emoji to pinned topics to make them stand-out on the Shadow theme, we have some other ideas in mind for this, but I'd like to get Shadow fully functional for this commit. Fixed a bug an issue with Chrome not detecting XHTML style closes on <form>s. Fixed a visual issue with `color` not being set for textarea elements for the Shadow theme. Fixed a function which wasn't getting renamed for PGSQL. Added seven new UserStore tests.
2017-08-06 15:22:18 +00:00
}
func (s *DefaultUserStore) BypassGet(id int) (*User, error) {
2022-02-21 03:32:53 +00:00
u := &User{ID: id, Loggedin: true}
embeds, err := s.scanUser(s.get.QueryRow(id), u)
if err == nil {
if embeds != -1 {
u.ParseSettings = DefaultParseSettings.CopyPtr()
u.ParseSettings.NoEmbed = embeds == 0
}
u.Init()
}
return u, err
}
func (s *DefaultUserStore) Reload(id int) error {
2022-02-21 03:32:53 +00:00
u, err := s.BypassGet(id)
if err != nil {
s.cache.Remove(id)
return err
}
_ = s.cache.Set(u)
TopicListThaw.Thaw()
return nil
}
func (s *DefaultUserStore) Exists(id int) bool {
2022-02-21 03:32:53 +00:00
err := s.exists.QueryRow(id).Scan(&id)
if err != nil && err != ErrNoRows {
LogError(err)
}
return err != ErrNoRows
}
func (s *DefaultUserStore) ClearLastIPs() error {
2022-02-21 03:32:53 +00:00
_, e := s.clearIPs.Exec()
return e
}
// TODO: Change active to a bool?
// TODO: Use unique keys for the usernames
func (s *DefaultUserStore) Create(name, password, email string, group int, active bool) (int, error) {
2022-02-21 03:32:53 +00:00
// TODO: Strip spaces?
// ? This number might be a little screwy with Unicode, but it's the only consistent thing we have, as Unicode characters can be any number of bytes in theory?
if len(name) > Config.MaxUsernameLength {
return 0, ErrLongUsername
}
// Is this name already taken..?
err := s.nameExists.QueryRow(name).Scan(&name)
if err != ErrNoRows {
return 0, ErrAccountExists
}
salt, err := GenerateSafeString(SaltLength)
if err != nil {
return 0, err
}
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password+salt), bcrypt.DefaultCost)
if err != nil {
return 0, err
}
res, err := s.register.Exec(name, email, string(hashedPassword), salt, group, active)
if err != nil {
return 0, err
}
lastID, err := res.LastInsertId()
return int(lastID), err
}
// Count returns the total number of users registered on the forums
func (s *DefaultUserStore) Count() (count int) {
2022-02-21 03:32:53 +00:00
return Countf(s.count)
}
func (s *DefaultUserStore) CountSearch(name, email string, gid int) (count int) {
2022-02-21 03:32:53 +00:00
return Countf(s.countSearch, name, name, email, email, gid, gid)
}
func (s *DefaultUserStore) SetCache(cache UserCache) {
2022-02-21 03:32:53 +00:00
s.cache = cache
}
Added the AboutSegment feature, you can see this in use on Cosora, it's a little raw right now, but I'm planning to polish it in the next commit. Refactored the code to use switches instead of if blocks in some places. Refactored the Dashboard to make it easier to add icons to it like I did with Cosora. You can now use maps in transpiled templates. Made progress on Cosora's footer. Swapped out the ThemeName property in the HeaderVars struct for a more general and flexible Theme property. Added the colstack CSS class to make it easier to style the layouts for the Control Panel and profile. Renamed the FStore variable to Forums. Renamed the Fpstore variable to FPStore. Renamed the Gstore variable to Groups. Split the MemoryTopicStore into DefaultTopicStore and MemoryTopicCache. Split the MemoryUserStore into DefaultUserStore and MemoryUserCache. Removed the NullUserStore, SQLUserStore, and SQLTopicStore. Added the NullTopicCache and NullUserCache. Moved the Reload method out of the TopicCache interface and into the TopicStore one. Moved the Reload method out of the UserCache interface and into the UserStore one. Added the SetCache and GetCache methods to the TopicStore and UserStore. Added the BypassGetAll method to the WordFilterMap type. Renamed routePanelSetting to routePanelSettingEdit. Renamed routePanelSettingEdit to routePanelSettingEditSubmit. Moved the page titles into the english language pack. Split main() into main and afterDBInit to avoid code duplication in general_test.go Added the ReqIsJson method so that we don't have to sniff the headers every time. Added the LogStore interface. Added the SQLModLogStore and the SQLAdminLogStore. Refactored the phrase system to use getPhrasePlaceholder instead of hard-coding the string to return in a bunch of functions. Removed a redundant rank check. Added the GuildStore to plugin_guilds. Added the about_segment_title and about_segment_body settings. Refactored the setting system to use predefined errors to make it easier for an upstream caller to filter out sensitive error messages as opposed to safe errors. Added the BypassGetAll method to the SettingMap type. Added the Update method to the SettingMap type. BulkGet is now exposed via the MemoryUserCache. Refactored more logs in the template transpiler to reduce the amount of indentation. Refactored the tests to take up fewer lines. Further improved the Cosora theme's colours, padding, and profiles. Added styling for the Control Panel Dashboard to the Cosora Theme. Reduced the amount of code duplication in the installer query generator and opened the door to certain types of auto-migrations. Refactored the Control Panel Dashboard to reduce the amount of code duplication. Refactored the modlog route to reduce the amount of code duplication and string concatenation.
2017-11-23 05:37:08 +00:00
// TODO: We're temporarily doing this so that you can do ucache != nil in getTopicUser. Refactor it.
func (s *DefaultUserStore) GetCache() UserCache {
2022-02-21 03:32:53 +00:00
_, ok := s.cache.(*NullUserCache)
if ok {
return nil
}
return s.cache
}