diff --git a/common/conversations.go b/common/conversations.go index 6ca4c968..18e9a4ce 100644 --- a/common/conversations.go +++ b/common/conversations.go @@ -3,8 +3,9 @@ package common import ( "errors" "time" + //"log" - //"strconv" + "strconv" "database/sql" qgen "github.com/Azareal/Gosora/query_gen" @@ -20,7 +21,7 @@ type ConvoStmts struct { edit *sql.Stmt create *sql.Stmt delete *sql.Stmt - has *sql.Stmt + has *sql.Stmt editPost *sql.Stmt createPost *sql.Stmt @@ -37,7 +38,7 @@ func init() { countPosts: acc.Count("conversations_posts").Where("cid = ?").Prepare(), edit: acc.Update("conversations").Set("lastReplyBy = ?, lastReplyAt = ?").Where("cid = ?").Prepare(), create: acc.Insert("conversations").Columns("createdAt, lastReplyAt").Fields("UTC_TIMESTAMP(),UTC_TIMESTAMP()").Prepare(), - has: acc.Count("conversations_participants").Where("uid = ? AND cid = ?").Prepare(), + has: acc.Count("conversations_participants").Where("uid = ? AND cid = ?").Prepare(), editPost: acc.Update("conversations_posts").Set("body = ?, post = ?").Where("pid = ?").Prepare(), createPost: acc.Insert("conversations_posts").Columns("cid, body, post, createdBy").Fields("?,?,?,?").Prepare(), @@ -130,9 +131,15 @@ func (co *Conversation) Create() (int, error) { return int(lastID), err } +type ConversationExtra struct { + *Conversation + Users []*User +} + type ConversationStore interface { Get(id int) (*Conversation, error) GetUser(uid int, offset int) (cos []*Conversation, err error) + GetUserExtra(uid int, offset int) (cos []*ConversationExtra, err error) GetUserCount(uid int) (count int) Delete(id int) error Count() (count int) @@ -140,35 +147,35 @@ type ConversationStore interface { } type DefaultConversationStore struct { - get *sql.Stmt - getUser *sql.Stmt - getUserCount *sql.Stmt - delete *sql.Stmt - deletePosts *sql.Stmt + get *sql.Stmt + getUser *sql.Stmt + getUserCount *sql.Stmt + delete *sql.Stmt + deletePosts *sql.Stmt deleteParticipants *sql.Stmt - create *sql.Stmt - addParticipant *sql.Stmt - count *sql.Stmt + create *sql.Stmt + addParticipant *sql.Stmt + count *sql.Stmt } func NewDefaultConversationStore(acc *qgen.Accumulator) (*DefaultConversationStore, error) { return &DefaultConversationStore{ - get: acc.Select("conversations").Columns("createdBy, createdAt, lastReplyBy, lastReplyAt").Where("cid = ?").Prepare(), - getUser: acc.SimpleInnerJoin("conversations_participants AS cp", "conversations AS c", "cp.cid, c.createdBy, c.createdAt, c.lastReplyBy, c.lastReplyAt", "cp.cid = c.cid", "cp.uid = ?", "c.lastReplyAt DESC, c.createdAt DESC, c.cid DESC", "?,?"), - getUserCount: acc.Count("conversations_participants").Where("uid = ?").Prepare(), - delete: acc.Delete("conversations").Where("cid = ?").Prepare(), - deletePosts: acc.Delete("conversations_posts").Where("cid = ?").Prepare(), - deleteParticipants: acc.Delete("conversations_participants").Where("cid = ?").Prepare(), - create: acc.Insert("conversations").Columns("createdBy, createdAt, lastReplyAt").Fields("?,UTC_TIMESTAMP(),UTC_TIMESTAMP()").Prepare(), - addParticipant: acc.Insert("conversations_participants").Columns("uid, cid").Fields("?,?").Prepare(), - count: acc.Count("conversations").Prepare(), + get: acc.Select("conversations").Columns("createdBy, createdAt, lastReplyBy, lastReplyAt").Where("cid = ?").Prepare(), + getUser: acc.SimpleInnerJoin("conversations_participants AS cp", "conversations AS c", "cp.cid, c.createdBy, c.createdAt, c.lastReplyBy, c.lastReplyAt", "cp.cid = c.cid", "cp.uid = ?", "c.lastReplyAt DESC, c.createdAt DESC, c.cid DESC", "?,?"), + getUserCount: acc.Count("conversations_participants").Where("uid = ?").Prepare(), + delete: acc.Delete("conversations").Where("cid = ?").Prepare(), + deletePosts: acc.Delete("conversations_posts").Where("cid = ?").Prepare(), + deleteParticipants: acc.Delete("conversations_participants").Where("cid = ?").Prepare(), + create: acc.Insert("conversations").Columns("createdBy, createdAt, lastReplyAt").Fields("?,UTC_TIMESTAMP(),UTC_TIMESTAMP()").Prepare(), + addParticipant: acc.Insert("conversations_participants").Columns("uid, cid").Fields("?,?").Prepare(), + count: acc.Count("conversations").Prepare(), }, acc.FirstError() } func (s *DefaultConversationStore) Get(id int) (*Conversation, error) { - convo := &Conversation{ID: id} - err := s.get.QueryRow(id).Scan(&convo.CreatedBy, &convo.CreatedAt, &convo.LastReplyBy, &convo.LastReplyAt) - return convo, err + co := &Conversation{ID: id} + err := s.get.QueryRow(id).Scan(&co.CreatedBy, &co.CreatedAt, &co.LastReplyBy, &co.LastReplyAt) + return co, err } func (s *DefaultConversationStore) GetUser(uid int, offset int) (cos []*Conversation, err error) { @@ -190,6 +197,109 @@ func (s *DefaultConversationStore) GetUser(uid int, offset int) (cos []*Conversa return cos, rows.Err() } +func (s *DefaultConversationStore) GetUserExtra(uid int, offset int) (cos []*ConversationExtra, err error) { + raw, err := s.GetUser(uid, offset) + if err != nil { + return nil, err + } + //log.Printf("raw: %+v\n", raw) + + if len(raw) == 0 { + //log.Println("r0") + return nil, sql.ErrNoRows + } + if len(raw) == 1 { + //log.Print("r0b2") + uids, err := raw[0].Uids() + if err != nil { + return nil, err + } + //log.Println("r1b2") + umap, err := Users.BulkGetMap(uids) + if err != nil { + return nil, err + } + //log.Println("r2b2") + users := make([]*User,len(umap)) + var i int + for _, user := range umap { + users[i] = user + i++ + } + return []*ConversationExtra{&ConversationExtra{raw[0],users}}, nil + } + //log.Println("1") + + cmap := make(map[int]*ConversationExtra,len(raw)) + for _, co := range raw { + cmap[co.ID] = &ConversationExtra{co,nil} + } + + // TODO: Add a function for the q stuff + var q string + idList := make([]interface{},len(raw)) + for i, co := range raw { + idList[i] = strconv.Itoa(co.ID) + q += "?," + } + q = q[0 : len(q)-1] + + rows, err := qgen.NewAcc().Select("conversations_participants").Columns("uid,cid").Where("cid IN(" + q + ")").Query(idList...) + if err != nil { + return nil, err + } + defer rows.Close() + //log.Println("2") + + idmap := make(map[int][]int) // cid: []uid + puidmap := make(map[int]struct{}) + for rows.Next() { + var uid, cid int + err := rows.Scan(&uid, &cid) + if err != nil { + return nil, err + } + idmap[cid] = append(idmap[cid],uid) + puidmap[uid] = struct{}{} + } + err = rows.Err() + if err != nil { + return nil, err + } + //log.Println("3") + //log.Printf("idmap: %+v\n", idmap) + //log.Printf("puidmap: %+v\n",puidmap) + + puids := make([]int,len(puidmap)) + var i int + for puid, _ := range puidmap { + puids[i] = puid + i++ + } + umap, err := Users.BulkGetMap(puids) + if err != nil { + return nil, err + } + //log.Println("4") + //log.Printf("umap: %+v\n", umap) + for cid, uids := range idmap { + co := cmap[cid] + for _, uid := range uids { + co.Users = append(co.Users,umap[uid]) + } + //log.Printf("co.Conversation: %+v\n", co.Conversation) + //log.Printf("co.Users: %+v\n", co.Users) + cmap[cid] = co + } + //log.Printf("cmap: %+v\n", cmap) + for _, ra := range raw { + cos = append(cos,cmap[ra.ID]) + } + //log.Printf("cos: %+v\n", cos) + + return cos, rows.Err() +} + func (s *DefaultConversationStore) GetUserCount(uid int) (count int) { err := s.getUserCount.QueryRow(uid).Scan(&count) if err != nil { @@ -225,10 +335,7 @@ func (s *DefaultConversationStore) Create(content string, createdBy int, partici return 0, err } - post := &ConversationPost{} - post.CID = int(lastID) - post.Body = content - post.CreatedBy = createdBy + post := &ConversationPost{CID: int(lastID), Body: content, CreatedBy: createdBy} _, err = post.Create() if err != nil { return 0, err diff --git a/common/forum_perms_store.go b/common/forum_perms_store.go index 3ddccbba..a5522427 100644 --- a/common/forum_perms_store.go +++ b/common/forum_perms_store.go @@ -81,7 +81,7 @@ func (s *MemoryForumPermsStore) Reload(fid int) error { } defer rows.Close() - var forumPerms = make(map[int]*ForumPerms) + forumPerms := make(map[int]*ForumPerms) for rows.Next() { var gid int var perms []byte diff --git a/common/pages.go b/common/pages.go index d2c8184a..24e07c1c 100644 --- a/common/pages.go +++ b/common/pages.go @@ -265,7 +265,7 @@ type ResetPage struct { type ConvoListPage struct { *Header - Convos []*Conversation + Convos []*ConversationExtra Paginator } diff --git a/common/poll_store.go b/common/poll_store.go index ce0e535b..263a2f01 100644 --- a/common/poll_store.go +++ b/common/poll_store.go @@ -145,15 +145,15 @@ func (s *DefaultPollStore) BulkGetMap(ids []int) (list map[int]*Poll, err error) } // TODO: Add a function for the qlist stuff - var qlist string + var q string idList := make([]interface{},len(ids)) for i, id := range ids { idList[i] = strconv.Itoa(id) - qlist += "?," + q += "?," } - qlist = qlist[0 : len(qlist)-1] + q = q[0 : len(q)-1] - rows, err := qgen.NewAcc().Select("polls").Columns("pollID, parentID, parentTable, type, options, votes").Where("pollID IN(" + qlist + ")").Query(idList...) + rows, err := qgen.NewAcc().Select("polls").Columns("pollID,parentID,parentTable,type,options,votes").Where("pollID IN(" + q + ")").Query(idList...) if err != nil { return list, err } diff --git a/common/topic_store.go b/common/topic_store.go index 0c7e5079..1e9d781f 100644 --- a/common/topic_store.go +++ b/common/topic_store.go @@ -16,7 +16,6 @@ import ( ) // TODO: Add the watchdog goroutine -// TODO: Add BulkGetMap // TODO: Add some sort of update method // ? - Should we add stick, lock, unstick, and unlock methods? These might be better on the Topics not the TopicStore var Topics TopicStore @@ -104,7 +103,7 @@ func (s *DefaultTopicStore) BypassGet(id int) (*Topic, error) { // TODO: Avoid duplicating much of this logic from user_store.go func (s *DefaultTopicStore) BulkGetMap(ids []int) (list map[int]*Topic, err error) { - var idCount = len(ids) + idCount := len(ids) list = make(map[int]*Topic) if idCount == 0 { return list, nil @@ -136,15 +135,15 @@ func (s *DefaultTopicStore) BulkGetMap(ids []int) (list map[int]*Topic, err erro } // TODO: Add a function for the qlist stuff - var qlist string + var q string idList := make([]interface{},len(ids)) for i, id := range ids { idList[i] = strconv.Itoa(id) - qlist += "?," + q += "?," } - qlist = qlist[0 : len(qlist)-1] + q = q[0 : len(q)-1] - rows, err := qgen.NewAcc().Select("topics").Columns("tid, title, content, createdBy, createdAt, lastReplyBy, lastReplyAt, lastReplyID, is_closed, sticky, parentID, ipaddress, views, postCount, likeCount, attachCount, poll, data").Where("tid IN(" + qlist + ")").Query(idList...) + rows, err := qgen.NewAcc().Select("topics").Columns("tid,title,content,createdBy,createdAt,lastReplyBy,lastReplyAt,lastReplyID,is_closed,sticky,parentID,ipaddress,views,postCount,likeCount,attachCount,poll,data").Where("tid IN(" + q + ")").Query(idList...) if err != nil { return list, err } diff --git a/common/user_store.go b/common/user_store.go index d2eb9ade..b0b9b714 100644 --- a/common/user_store.go +++ b/common/user_store.go @@ -63,78 +63,67 @@ func NewDefaultUserStore(cache UserCache) (*DefaultUserStore, error) { }, acc.FirstError() } -func (mus *DefaultUserStore) DirtyGet(id int) *User { - user, err := mus.cache.Get(id) +func (s *DefaultUserStore) DirtyGet(id int) *User { + user, err := s.Get(id) if err == nil { return user } - /*if mus.OutOfBounds(id) { + /*if s.OutOfBounds(id) { return BlankUser() }*/ - - user = &User{ID: id, Loggedin: true} - err = mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.RawAvatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Liked, &user.LastIP, &user.TempGroup) - - user.Init() - if err == nil { - mus.cache.Set(user) - return user - } return BlankUser() } // TODO: Log weird cache errors? Not just here but in every *Cache? -func (mus *DefaultUserStore) Get(id int) (*User, error) { - user, err := mus.cache.Get(id) +func (s *DefaultUserStore) Get(id int) (*User, error) { + u, err := s.cache.Get(id) if err == nil { //log.Print("cached user") //log.Print(string(debug.Stack())) //log.Println("") - return user, nil + return u, nil } //log.Print("uncached user") - user = &User{ID: id, Loggedin: true} - err = mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.RawAvatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Liked, &user.LastIP, &user.TempGroup) - - user.Init() + u = &User{ID: id, Loggedin: true} + err = s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score,&u.Liked, &u.LastIP, &u.TempGroup) if err == nil { - mus.cache.Set(user) + u.Init() + s.cache.Set(u) } - return user, err + return u, err } // TODO: Log weird cache errors? Not just here but in every *Cache? // ! This bypasses the cache, use frugally -func (mus *DefaultUserStore) GetByName(name string) (*User, error) { - user := &User{Loggedin: true} - err := mus.getByName.QueryRow(name).Scan(&user.ID, &user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.RawAvatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Liked, &user.LastIP, &user.TempGroup) - - user.Init() +func (s *DefaultUserStore) GetByName(name string) (*User, error) { + u := &User{Loggedin: true} + 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.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Liked, &u.LastIP, &u.TempGroup) if err == nil { - mus.cache.Set(user) + u.Init() + s.cache.Set(u) } - return user, err + return u, err } // 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 (store *DefaultUserStore) GetOffset(offset int, perPage int) (users []*User, err error) { - rows, err := store.getOffset.Query(offset, perPage) +func (s *DefaultUserStore) GetOffset(offset int, perPage int) (users []*User, err error) { + rows, err := s.getOffset.Query(offset, perPage) if err != nil { return users, err } defer rows.Close() for rows.Next() { - user := &User{Loggedin: true} - err := rows.Scan(&user.ID, &user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.RawAvatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Liked, &user.LastIP, &user.TempGroup) + 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.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Liked, &u.LastIP, &u.TempGroup) if err != nil { return nil, err } - user.Init() - store.cache.Set(user) - users = append(users, user) + u.Init() + s.cache.Set(u) + users = append(users, u) } return users, rows.Err() } @@ -142,7 +131,7 @@ func (store *DefaultUserStore) GetOffset(offset int, perPage int) (users []*User // 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) { - var idCount = len(ids) + idCount := len(ids) list = make(map[int]*User) if idCount == 0 { return list, nil @@ -173,16 +162,16 @@ func (s *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err error) return list, nil } - // TODO: Add a function for the qlist stuff - var qlist string + // TODO: Add a function for the q stuff + var q string idList := make([]interface{},len(ids)) for i, id := range ids { idList[i] = strconv.Itoa(id) - qlist += "?," + q += "?," } - qlist = qlist[0 : len(qlist)-1] + q = q[0 : len(q)-1] - rows, err := qgen.NewAcc().Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, liked, last_ip, temp_group").Where("uid IN(" + qlist + ")").Query(idList...) + rows, err := qgen.NewAcc().Select("users").Columns("uid,name,group,active,is_super_admin,session,email,avatar,message,url_prefix,url_name,level,score,liked,last_ip,temp_group").Where("uid IN(" + q + ")").Query(idList...) if err != nil { return list, err } @@ -221,29 +210,28 @@ func (s *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err error) return list, err } -func (mus *DefaultUserStore) BypassGet(id int) (*User, error) { - user := &User{ID: id, Loggedin: true} - err := mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.RawAvatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Liked, &user.LastIP, &user.TempGroup) - - user.Init() - return user, err +func (s *DefaultUserStore) BypassGet(id int) (*User, error) { + u := &User{ID: id, Loggedin: true} + err := s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Liked, &u.LastIP, &u.TempGroup) + u.Init() + return u, err } -func (mus *DefaultUserStore) Reload(id int) error { - user := &User{ID: id, Loggedin: true} - err := mus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Active, &user.IsSuperAdmin, &user.Session, &user.Email, &user.RawAvatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Liked, &user.LastIP, &user.TempGroup) +func (s *DefaultUserStore) Reload(id int) error { + u := &User{ID: id, Loggedin: true} + err := s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Liked, &u.LastIP, &u.TempGroup) if err != nil { - mus.cache.Remove(id) + s.cache.Remove(id) return err } - user.Init() - _ = mus.cache.Set(user) + u.Init() + _ = s.cache.Set(u) TopicListThaw.Thaw() return nil } -func (mus *DefaultUserStore) Exists(id int) bool { - err := mus.exists.QueryRow(id).Scan(&id) +func (s *DefaultUserStore) Exists(id int) bool { + err := s.exists.QueryRow(id).Scan(&id) if err != nil && err != ErrNoRows { LogError(err) } @@ -252,7 +240,7 @@ func (mus *DefaultUserStore) Exists(id int) bool { // TODO: Change active to a bool? // TODO: Use unique keys for the usernames -func (mus *DefaultUserStore) Create(username string, password string, email string, group int, active bool) (int, error) { +func (s *DefaultUserStore) Create(username string, password string, email string, group int, active bool) (int, error) { // 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? @@ -261,7 +249,7 @@ func (mus *DefaultUserStore) Create(username string, password string, email stri } // Is this username already taken..? - err := mus.usernameExists.QueryRow(username).Scan(&username) + err := s.usernameExists.QueryRow(username).Scan(&username) if err != ErrNoRows { return 0, ErrAccountExists } @@ -274,7 +262,7 @@ func (mus *DefaultUserStore) Create(username string, password string, email stri return 0, err } - res, err := mus.register.Exec(username, email, string(hashedPassword), salt, group, active) + res, err := s.register.Exec(username, email, string(hashedPassword), salt, group, active) if err != nil { return 0, err } diff --git a/common/widget_store.go b/common/widget_store.go index 36fd3900..cd239de0 100644 --- a/common/widget_store.go +++ b/common/widget_store.go @@ -16,24 +16,24 @@ func NewDefaultWidgetStore() *DefaultWidgetStore { return &DefaultWidgetStore{widgets: make(map[int]*Widget)} } -func (widgets *DefaultWidgetStore) Get(id int) (*Widget, error) { - widgets.RLock() - defer widgets.RUnlock() - widget, ok := widgets.widgets[id] +func (w *DefaultWidgetStore) Get(id int) (*Widget, error) { + w.RLock() + defer w.RUnlock() + widget, ok := w.widgets[id] if !ok { return widget, sql.ErrNoRows } return widget, nil } -func (widgets *DefaultWidgetStore) set(widget *Widget) { - widgets.Lock() - defer widgets.Unlock() - widgets.widgets[widget.ID] = widget +func (w *DefaultWidgetStore) set(widget *Widget) { + w.Lock() + defer w.Unlock() + w.widgets[widget.ID] = widget } -func (widgets *DefaultWidgetStore) delete(id int) { - widgets.Lock() - defer widgets.Unlock() - delete(widgets.widgets, id) +func (w *DefaultWidgetStore) delete(id int) { + w.Lock() + defer w.Unlock() + delete(w.widgets, id) } diff --git a/langs/english.json b/langs/english.json index 102a33e6..48bc824d 100644 --- a/langs/english.json +++ b/langs/english.json @@ -538,6 +538,7 @@ "convos_head":"Conversations", "convo_head":"Conversation", + "convo_users":"Participants", "create_convo_head":"Create Conversation", "create_convo_button":"Create Convo", diff --git a/query_gen/acc_builders.go b/query_gen/acc_builders.go index b70e8e91..37876b14 100644 --- a/query_gen/acc_builders.go +++ b/query_gen/acc_builders.go @@ -100,12 +100,12 @@ func (b *accUpdateBuilder) Prepare() *sql.Stmt { return b.build.prepare(b.build.adapter.SimpleUpdate(b.up)) } -func (u *accUpdateBuilder) Exec(args ...interface{}) (res sql.Result, err error) { - query, err := u.build.adapter.SimpleUpdate(u.up) +func (b *accUpdateBuilder) Exec(args ...interface{}) (res sql.Result, err error) { + query, err := b.build.adapter.SimpleUpdate(b.up) if err != nil { return res, err } - return u.build.exec(query, args...) + return b.build.exec(query, args...) } type AccSelectBuilder struct { @@ -145,7 +145,8 @@ func (b *AccSelectBuilder) In(column string, inList []int) *AccSelectBuilder { return b } - var where = column + " IN(" + // TODO: Optimise this + where := column + " IN(" for _, item := range inList { where += strconv.Itoa(item) + "," } @@ -158,6 +159,29 @@ func (b *AccSelectBuilder) In(column string, inList []int) *AccSelectBuilder { return b } +// TODO: Don't implement the SQL at the accumulator level but the adapter level +func (b *AccSelectBuilder) InPQuery(column string, inList []int) (*sql.Rows, error) { + if len(inList) == 0 { + return nil, sql.ErrNoRows + } + // TODO: Optimise this + where := column + " IN(" + + idList := make([]interface{},len(inList)) + for i, id := range inList { + idList[i] = strconv.Itoa(id) + where += "?," + } + where = where[0 : len(where)-1] + ")" + + if b.where != "" { + where += " AND " + b.where + } + + b.where = where + return b.Query(idList...) +} + func (b *AccSelectBuilder) InQ(column string, subBuilder *AccSelectBuilder) *AccSelectBuilder { b.inChain = subBuilder b.inColumn = column diff --git a/routes/convos.go b/routes/convos.go index bcb528d5..360ae476 100644 --- a/routes/convos.go +++ b/routes/convos.go @@ -2,10 +2,11 @@ package routes import ( "database/sql" + "errors" "net/http" "strconv" "strings" - "errors" + //"log" c "github.com/Azareal/Gosora/common" p "github.com/Azareal/Gosora/common/phrases" @@ -13,13 +14,15 @@ import ( func Convos(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { accountEditHead("convos", w, r, &user, header) + header.AddSheet(header.Theme.Name + "/convo.css") header.AddNotice("convo_dev") ccount := c.Convos.GetUserCount(user.ID) page, _ := strconv.Atoi(r.FormValue("page")) offset, page, lastPage := c.PageOffset(ccount, page, c.Config.ItemsPerPage) pageList := c.Paginate(page, lastPage, 5) - convos, err := c.Convos.GetUser(user.ID, offset) + convos, err := c.Convos.GetUserExtra(user.ID, offset) + //log.Printf("convos: %+v\n", convos) if err == sql.ErrNoRows { return c.NotFound(w, r, header) } else if err != nil { @@ -74,7 +77,7 @@ func Convo(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header } else if err != nil { return c.InternalError(err, w, r) } - users := make([]*c.User,len(umap)) + users := make([]*c.User, len(umap)) i := 0 for _, user := range umap { users[i] = user diff --git a/templates/convo.html b/templates/convo.html index 54a39954..fcec6396 100644 --- a/templates/convo.html +++ b/templates/convo.html @@ -5,11 +5,11 @@
-
Participants: 
+
{{lang "convo_users"}}: 
{{range .Users}} {{end}}
-
{{template "convo_row.html" .}}
+
{{template "convo_row.html" .}}
{{if not .CurrentUser.IsBanned}}
diff --git a/templates/convos.html b/templates/convos.html index 45fd71bb..4011981f 100644 --- a/templates/convos.html +++ b/templates/convos.html @@ -8,7 +8,7 @@ {{range .Convos}}
- Message + {{range .Users}}{{.Name}} {{end}} {{reltime .LastReplyAt}}
{{end}} diff --git a/themes/nox/public/convo.css b/themes/nox/public/convo.css index 4db58d48..7dc83876 100644 --- a/themes/nox/public/convo.css +++ b/themes/nox/public/convo.css @@ -1,3 +1,7 @@ +.convos_item_user:not(:last-child):after { + content: ","; +} + .parti { margin-bottom: 8px; }