From a287ccc3d6eb6ca1570da2ac265eb074da829278 Mon Sep 17 00:00:00 2001 From: Azareal Date: Sat, 27 Jul 2019 09:29:42 +1000 Subject: [PATCH] WIP Conversations templates. WIP Conversations structs. WIP Unbound conversations routes. Shorten more variable names. Eliminate a few characters here and there. Track down widget tick errors more easily. Add the convos_head title phrase. Add the convo_head title phrase. Add the unit phrase. Add the account_menu_messages phrase. Add the convos_head phrase. Add the convo_head phrase. Add the create_convo_head phrase. Add the create_convo_button phrase. Add the profile_send_message phrase. Add the panel_dashboard_disk_unknown phrase. --- common/counters/routes.go | 9 ++- common/menu_store.go | 30 ++++---- common/pages.go | 17 +++++ common/topic_list.go | 15 ++-- common/widget_wol.go | 3 +- common/widgets.go | 19 ++--- langs/english.json | 11 +++ routes/attachments.go | 2 +- routes/convos.go | 148 ++++++++++++++++++++++++++++++++++++ templates/convo.html | 10 +++ templates/convos.html | 17 +++++ templates/create_convo.html | 19 +++++ 12 files changed, 262 insertions(+), 38 deletions(-) create mode 100644 routes/convos.go create mode 100644 templates/convo.html create mode 100644 templates/convos.html create mode 100644 templates/create_convo.html diff --git a/common/counters/routes.go b/common/counters/routes.go index ac55aff8..8f7df60c 100644 --- a/common/counters/routes.go +++ b/common/counters/routes.go @@ -1,8 +1,11 @@ package counters -import "database/sql" -import "github.com/Azareal/Gosora/common" -import "github.com/Azareal/Gosora/query_gen" +import ( + "database/sql" + + "github.com/Azareal/Gosora/common" + qgen "github.com/Azareal/Gosora/query_gen" +) var RouteViewCounter *DefaultRouteViewCounter diff --git a/common/menu_store.go b/common/menu_store.go index 5338e8bf..57e72355 100644 --- a/common/menu_store.go +++ b/common/menu_store.go @@ -23,38 +23,38 @@ func NewDefaultMenuStore() *DefaultMenuStore { } // TODO: Add actual support for multiple menus -func (store *DefaultMenuStore) GetAllMap() (out map[int]*MenuListHolder) { +func (s *DefaultMenuStore) GetAllMap() (out map[int]*MenuListHolder) { out = make(map[int]*MenuListHolder) - for mid, atom := range store.menus { + for mid, atom := range s.menus { out[mid] = atom.Load().(*MenuListHolder) } return out } -func (store *DefaultMenuStore) Get(mid int) (*MenuListHolder, error) { - aStore, ok := store.menus[mid] +func (s *DefaultMenuStore) Get(mid int) (*MenuListHolder, error) { + aStore, ok := s.menus[mid] if ok { return aStore.Load().(*MenuListHolder), nil } return nil, ErrNoRows } -func (store *DefaultMenuStore) Items(mid int) (mlist MenuItemList, err error) { +func (s *DefaultMenuStore) Items(mid int) (mlist MenuItemList, err error) { err = qgen.NewAcc().Select("menu_items").Columns("miid, name, htmlID, cssClass, position, path, aria, tooltip, order, tmplName, guestOnly, memberOnly, staffOnly, adminOnly").Where("mid = " + strconv.Itoa(mid)).Orderby("order ASC").Each(func(rows *sql.Rows) error { - var mitem = MenuItem{MenuID: mid} - err := rows.Scan(&mitem.ID, &mitem.Name, &mitem.HTMLID, &mitem.CSSClass, &mitem.Position, &mitem.Path, &mitem.Aria, &mitem.Tooltip, &mitem.Order, &mitem.TmplName, &mitem.GuestOnly, &mitem.MemberOnly, &mitem.SuperModOnly, &mitem.AdminOnly) + i := MenuItem{MenuID: mid} + err := rows.Scan(&i.ID, &i.Name, &i.HTMLID, &i.CSSClass, &i.Position, &i.Path, &i.Aria, &i.Tooltip, &i.Order, &i.TmplName, &i.GuestOnly, &i.MemberOnly, &i.SuperModOnly, &i.AdminOnly) if err != nil { return err } - store.itemStore.Add(mitem) - mlist = append(mlist, mitem) + s.itemStore.Add(i) + mlist = append(mlist, i) return nil }) return mlist, err } -func (store *DefaultMenuStore) Load(mid int) error { - mlist, err := store.Items(mid) +func (s *DefaultMenuStore) Load(mid int) error { + mlist, err := s.Items(mid) if err != nil { return err } @@ -64,12 +64,12 @@ func (store *DefaultMenuStore) Load(mid int) error { return err } - var aStore = &atomic.Value{} + aStore := &atomic.Value{} aStore.Store(hold) - store.menus[mid] = aStore + s.menus[mid] = aStore return nil } -func (store *DefaultMenuStore) ItemStore() *DefaultMenuItemStore { - return store.itemStore +func (s *DefaultMenuStore) ItemStore() *DefaultMenuItemStore { + return s.itemStore } diff --git a/common/pages.go b/common/pages.go index fe3f57aa..22011f34 100644 --- a/common/pages.go +++ b/common/pages.go @@ -283,6 +283,23 @@ type ResetPage struct { MFA bool } +type ConvoListPage struct { + *Header + Convos []*Conversation + Paginator +} + +type ConvoViewPage struct { + *Header + Posts []*ConversationPost + Paginator +} + +type ConvoCreatePage struct { + *Header + RecpName string +} + /* WIP for dyntmpl */ type Panel struct { *BasePanelPage diff --git a/common/topic_list.go b/common/topic_list.go index cac2b001..0e409915 100644 --- a/common/topic_list.go +++ b/common/topic_list.go @@ -60,10 +60,9 @@ func (tList *DefaultTopicList) Tick() error { } //fmt.Println("building topic list") - var oddLists = make(map[int]*TopicListHolder) - var evenLists = make(map[int]*TopicListHolder) - - var addList = func(gid int, holder *TopicListHolder) { + oddLists := make(map[int]*TopicListHolder) + evenLists := make(map[int]*TopicListHolder) + addList := func(gid int, holder *TopicListHolder) { if gid%2 == 0 { evenLists[gid] = holder } else { @@ -76,15 +75,15 @@ func (tList *DefaultTopicList) Tick() error { return err } - var gidToCanSee = make(map[int]string) - var permTree = make(map[string][]int) // [string(canSee)]canSee + gidToCanSee := make(map[int]string) + permTree := make(map[string][]int) // [string(canSee)]canSee for _, group := range allGroups { // ? - Move the user count check to instance initialisation? Might require more book-keeping, particularly when a user moves into a zero user group if group.UserCount == 0 && group.ID != GuestUser.Group { continue } - var canSee = make([]byte, len(group.CanSee)) + canSee := make([]byte, len(group.CanSee)) for i, item := range group.CanSee { canSee[i] = byte(item) } @@ -96,7 +95,7 @@ func (tList *DefaultTopicList) Tick() error { gidToCanSee[group.ID] = sCanSee } - var canSeeHolders = make(map[string]*TopicListHolder) + canSeeHolders := make(map[string]*TopicListHolder) for name, canSee := range permTree { topicList, forumList, paginator, err := tList.GetListByCanSee(canSee, 1, "", nil) if err != nil { diff --git a/common/widget_wol.go b/common/widget_wol.go index 9ac6b68d..bbb8ef94 100644 --- a/common/widget_wol.go +++ b/common/widget_wol.go @@ -57,8 +57,7 @@ var wolLastUsers []*User func wolTick(widget *Widget) error { w := httptest.NewRecorder() users, ucount := wolGetUsers() - - var inOld = func(id int) bool { + inOld := func(id int) bool { for _, user := range wolLastUsers { if id == user.ID { return true diff --git a/common/widgets.go b/common/widgets.go index f8378ba0..1d40dd9a 100644 --- a/common/widgets.go +++ b/common/widgets.go @@ -11,6 +11,7 @@ import ( "sync/atomic" min "github.com/Azareal/Gosora/common/templates" + "github.com/pkg/errors" ) // TODO: Clean this file up @@ -292,12 +293,12 @@ func releaseWidgets(widgets []*Widget) { // TODO: Use atomics func setDock(dock string, widgets []*Widget) { - var dockHandle = func(dockWidgets []*Widget) { + dockHandle := func(dockWidgets []*Widget) { widgetUpdateMutex.Lock() DebugLog(dock, widgets) releaseWidgets(dockWidgets) } - var dockHandle2 = func(dockWidgets WidgetDock) WidgetDock { + dockHandle2 := func(dockWidgets WidgetDock) WidgetDock { dockHandle(dockWidgets.Items) if dockWidgets.Scheduler == nil { dockWidgets.Scheduler = &WidgetScheduler{} @@ -335,23 +336,23 @@ type WidgetScheduler struct { store atomic.Value } -func (schedule *WidgetScheduler) Add(widget *Widget) { - schedule.widgets = append(schedule.widgets, widget) +func (s *WidgetScheduler) Add(widget *Widget) { + s.widgets = append(s.widgets, widget) } -func (schedule *WidgetScheduler) Store() { - schedule.store.Store(schedule.widgets) +func (s *WidgetScheduler) Store() { + s.store.Store(s.widgets) } -func (schedule *WidgetScheduler) Tick() error { - widgets := schedule.store.Load().([]*Widget) +func (s *WidgetScheduler) Tick() error { + widgets := s.store.Load().([]*Widget) for _, widget := range widgets { if widget.TickFunc == nil { continue } err := widget.TickFunc(widget) if err != nil { - return err + return errors.WithStack(err) } } return nil diff --git a/langs/english.json b/langs/english.json index 84864c14..65a279e4 100644 --- a/langs/english.json +++ b/langs/english.json @@ -143,6 +143,8 @@ "account_logins":"Logins", "account_penalties":"Penalties", "account_level_list":"Level Progress", + "convos_head":"Conversations", + "convo_head":"Conversation", "panel_dashboard":"Control Panel Dashboard", "panel_forums":"Forum Manager", @@ -328,6 +330,7 @@ "TmplPhrases": { "pipe":"|", + "unit":"%.1f%s", "menu_forums":"Forums", "menu_topics":"Topics", @@ -492,6 +495,7 @@ "account_menu_notifications":"Notifications", "account_menu_logins":"Logins", "account_menu_penalties":"Penalties", + "account_menu_messages":"Messages", "account_coming_soon":"Coming Soon", @@ -530,6 +534,11 @@ "account_logins_success":"Successful Login", "account_logins_failure":"Failed Login", + "convos_head":"Conversations", + "convo_head":"Conversation", + "create_convo_head":"Create Conversation", + "create_convo_button":"Create Convo", + "areyousure_head":"Are you sure?", "areyousure_continue":"Continue", @@ -681,6 +690,7 @@ "paginator.next_page_aria":"Go to the next page", "profile_login_for_options":"Login for options", + "profile_send_message":"Send Message", "profile_add_friend":"Add Friend", "profile_unban":"Unban", "profile_ban":"Ban", @@ -768,6 +778,7 @@ "panel_dashboard_memused":"Mem: %.1f%s", "panel_dashboard_memused_desc":"The amount of memory likely being used by this instance", "panel_dashboard_disk":"Disk: %.1f%s", + "panel_dashboard_disk_unknown":"Disk: ??", "panel_dashboard_disk_desc":"The amount of disk space being used by this instance", "panel_dashboard_online": "%d%s online", "panel_dashboard_online_desc":"The number of people who are currently online", diff --git a/routes/attachments.go b/routes/attachments.go index fdc812d5..db85d3c1 100644 --- a/routes/attachments.go +++ b/routes/attachments.go @@ -30,7 +30,7 @@ func init() { func ShowAttachment(w http.ResponseWriter, r *http.Request, user c.User, filename string) c.RouteError { filename = c.Stripslashes(filename) - var ext = filepath.Ext("./attachs/" + filename) + ext := filepath.Ext("./attachs/" + filename) if !c.AllowedFileExts.Contains(strings.TrimPrefix(ext, ".")) { return c.LocalError("Bad extension", w, r, user) } diff --git a/routes/convos.go b/routes/convos.go new file mode 100644 index 00000000..a1781c76 --- /dev/null +++ b/routes/convos.go @@ -0,0 +1,148 @@ +package routes + +import ( + "database/sql" + "net/http" + "strconv" + "strings" + + c "github.com/Azareal/Gosora/common" + "github.com/Azareal/Gosora/common/phrases" +) + +func Convos(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { + accountEditHead("convos", w, r, &user, header) + 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) + if err == sql.ErrNoRows { + return c.NotFound(w, r, header) + } else if err != nil { + return c.InternalError(err, w, r) + } + + pi := c.Account{header, "dashboard", "convos", c.ConvoListPage{header, convos, c.Paginator{pageList, page, lastPage}}} + return renderTemplate("account", w, r, header, pi) +} + +func Convo(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header, scid string) c.RouteError { + accountEditHead("convo", w, r, &user, header) + cid, err := strconv.Atoi(scid) + if err != nil { + return c.LocalError(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user) + } + + convo, err := c.Convos.Get(cid) + if err == sql.ErrNoRows { + return c.NotFound(w, r, header) + } else if err != nil { + return c.InternalError(err, w, r) + } + pcount := convo.PostsCount() + if pcount == 0 { + return c.NotFound(w, r, header) + } + + page, _ := strconv.Atoi(r.FormValue("page")) + offset, page, lastPage := c.PageOffset(pcount, page, c.Config.ItemsPerPage) + pageList := c.Paginate(page, lastPage, 5) + + posts, err := convo.Posts(offset) + // TODO: Report a better error for no posts + if err == sql.ErrNoRows { + return c.NotFound(w, r, header) + } else if err != nil { + return c.InternalError(err, w, r) + } + + pi := c.Account{header, "dashboard", "convo", c.ConvoViewPage{header, posts, c.Paginator{pageList, page, lastPage}}} + return renderTemplate("account", w, r, header, pi) +} + +func ConvosCreate(w http.ResponseWriter, r *http.Request, user c.User, header *c.Header) c.RouteError { + accountEditHead("create_convo", w, r, &user, header) + recpName := "" + pi := c.Account{header, "dashboard", "create_convo", c.ConvoCreatePage{header, recpName}} + return renderTemplate("account", w, r, header, pi) +} + +func ConvosCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + _, ferr := c.SimpleUserCheck(w, r, &user) + if ferr != nil { + return ferr + } + + recps := c.SanitiseSingleLine(r.PostFormValue("recp")) + body := c.PreparseMessage(r.PostFormValue("body")) + rlist := []int{} + max := 10 // max number of recipients that can be added at once + for i, recp := range strings.Split(recps, ",") { + if i >= max { + break + } + + u, err := c.Users.GetByName(recp) + if err == sql.ErrNoRows { + return c.LocalError("One of the recipients doesn't exist", w, r, user) + } else if err != nil { + return c.InternalError(err, w, r) + } + + rlist = append(rlist, u.ID) + } + + cid, err := c.Convos.Create(body, user.ID, rlist) + if err != nil { + return c.InternalError(err, w, r) + } + + http.Redirect(w, r, "/user/convo/"+strconv.Itoa(cid), http.StatusSeeOther) + return nil +} + +/*type ConversationPost struct { + ID int + CID int + Body string + Post string // aes, '' +}*/ + +func ConvosDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, scid string) c.RouteError { + _, ferr := c.SimpleUserCheck(w, r, &user) + if ferr != nil { + return ferr + } + cid, err := strconv.Atoi(scid) + if err != nil { + return c.LocalError(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user) + } + + err = c.Convos.Delete(cid) + if err != nil { + return c.InternalError(err, w, r) + } + + http.Redirect(w, r, "/user/convos/", http.StatusSeeOther) + return nil +} + +func ConvosCreateReplySubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + _, ferr := c.SimpleUserCheck(w, r, &user) + if ferr != nil { + return ferr + } + http.Redirect(w, r, "/user/convo/id", http.StatusSeeOther) + return nil +} + +func ConvosDeleteReplySubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { + _, ferr := c.SimpleUserCheck(w, r, &user) + if ferr != nil { + return ferr + } + http.Redirect(w, r, "/user/convo/id", http.StatusSeeOther) + return nil +} \ No newline at end of file diff --git a/templates/convo.html b/templates/convo.html new file mode 100644 index 00000000..a6b39ef8 --- /dev/null +++ b/templates/convo.html @@ -0,0 +1,10 @@ +
+
+

{{lang "convo_head"}}

+
+
+{{range .Posts}} +
+
{{.Body}}
+
+{{end}} \ No newline at end of file diff --git a/templates/convos.html b/templates/convos.html new file mode 100644 index 00000000..ead11d29 --- /dev/null +++ b/templates/convos.html @@ -0,0 +1,17 @@ +
+
+

{{lang "convos_head"}}

+

Create Convo

+
+
+
+ {{range .Convos}} +
+ + Message + + {{reltime .LastReplyAt}} +
{{end}} +
+
+{{template "paginator.html" . }} \ No newline at end of file diff --git a/templates/create_convo.html b/templates/create_convo.html new file mode 100644 index 00000000..471a0e88 --- /dev/null +++ b/templates/create_convo.html @@ -0,0 +1,19 @@ +
+
+

{{lang "create_convo_head"}}

+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
\ No newline at end of file