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.
This commit is contained in:
parent
597240233f
commit
a287ccc3d6
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
}
|
||||
|
148
routes/convos.go
Normal file
148
routes/convos.go
Normal file
@ -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
|
||||
}
|
10
templates/convo.html
Normal file
10
templates/convo.html
Normal file
@ -0,0 +1,10 @@
|
||||
<div class="colstack_item colstack_head rowhead">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "convo_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
{{range .Posts}}
|
||||
<div class="colstack_item">
|
||||
<div class="rowitem">{{.Body}}</div>
|
||||
</div>
|
||||
{{end}}
|
17
templates/convos.html
Normal file
17
templates/convos.html
Normal file
@ -0,0 +1,17 @@
|
||||
<div class="colstack_item colstack_head rowhead">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "convos_head"}}</h1>
|
||||
<h2>Create Convo</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colstack_item">
|
||||
{{range .Convos}}
|
||||
<div class="rowitem">
|
||||
<span class="to_left">
|
||||
<a href="/user/convo/{{.ID}}">Message</a>
|
||||
</span>
|
||||
<span title="{{abstime .LastReplyAt}}" class="to_right">{{reltime .LastReplyAt}}</span>
|
||||
</div>{{end}}
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
{{template "paginator.html" . }}
|
19
templates/create_convo.html
Normal file
19
templates/create_convo.html
Normal file
@ -0,0 +1,19 @@
|
||||
<div class="colstack_item colstack_head rowhead">
|
||||
<div class="rowitem">
|
||||
<h1>{{lang "create_convo_head"}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="colstack_item the_form">
|
||||
<form action="/user/convos/create/submit/?session={{.CurrentUser.Session}}" method="post">
|
||||
<div class="formrow real_first_child">
|
||||
<div class="formitem formlabel"><a>Recipient/s</a></div>
|
||||
<div class="formitem"><input name="recp" type="text"{{if .RecpName}} value="{{.RecpName}}"{{end}} /></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem"><textarea name="body"></textarea></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">{{lang "create_convo_button"}}</button></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user