patched up community display in find.jet
This commit is contained in:
@@ -239,6 +239,9 @@ func EditCommunityProfile(ctxt ui.AmContext) (string, any, error) {
|
|||||||
flags.Set(database.CommunityFlagPicturesInPosts, dlg.Field("pic_in_post").IsChecked())
|
flags.Set(database.CommunityFlagPicturesInPosts, dlg.Field("pic_in_post").IsChecked())
|
||||||
err = comm.SaveFlags(flags)
|
err = comm.SaveFlags(flags)
|
||||||
}
|
}
|
||||||
|
if err == nil {
|
||||||
|
err = comm.TouchUpdate()
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctxt.ClearCommunityContext()
|
ctxt.ClearCommunityContext()
|
||||||
return dlg.RenderError(ctxt, err.Error())
|
return dlg.RenderError(ctxt, err.Error())
|
||||||
@@ -321,6 +324,9 @@ func EditCommunityLogo(ctxt ui.AmContext) (string, any, error) {
|
|||||||
photourl := fmt.Sprintf("/img/store/%d", img.ImgId)
|
photourl := fmt.Sprintf("/img/store/%d", img.ImgId)
|
||||||
ci.PhotoURL = &photourl
|
ci.PhotoURL = &photourl
|
||||||
_, err = ci.Save()
|
_, err = ci.Save()
|
||||||
|
if err == nil {
|
||||||
|
err = comm.TouchUpdate()
|
||||||
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return "redirect", "/comm/" + comm.Alias + "/admin/profile", nil
|
return "redirect", "/comm/" + comm.Alias + "/admin/profile", nil
|
||||||
}
|
}
|
||||||
@@ -457,6 +463,9 @@ func CreateCommunity(ctxt ui.AmContext) (string, any, error) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
err = comm.SetContactID(ci.ContactId)
|
err = comm.SetContactID(ci.ContactId)
|
||||||
}
|
}
|
||||||
|
if err == nil {
|
||||||
|
err = comm.TouchUpdate()
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return dlg.RenderError(ctxt, err.Error())
|
return dlg.RenderError(ctxt, err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-6
@@ -209,8 +209,8 @@ func (c *Community) Membership(u *User) (bool, bool, uint16, error) {
|
|||||||
return false, false, uint16(0), err
|
return false, false, uint16(0), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MemberCountQ returns the number of members in the community, quietly.
|
// MemberCount returns the number of members in the community, quietly.
|
||||||
func (c *Community) MemberCountQ(hidden bool) int {
|
func (c *Community) MemberCount(hidden bool) (int, error) {
|
||||||
var rs *sql.Rows
|
var rs *sql.Rows
|
||||||
var err error
|
var err error
|
||||||
if hidden {
|
if hidden {
|
||||||
@@ -219,14 +219,14 @@ func (c *Community) MemberCountQ(hidden bool) int {
|
|||||||
rs, err = amdb.Query("SELECT COUNT(*) FROM commmember WHERE commid = ? AND hidden = 0", c.Id)
|
rs, err = amdb.Query("SELECT COUNT(*) FROM commmember WHERE commid = ? AND hidden = 0", c.Id)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1
|
return -1, err
|
||||||
}
|
}
|
||||||
if rs.Next() {
|
if rs.Next() {
|
||||||
var rc int
|
var rc int
|
||||||
rs.Scan(&rc)
|
rs.Scan(&rc)
|
||||||
return rc
|
return rc, nil
|
||||||
}
|
}
|
||||||
return -1
|
return -1, errors.New("internal error reading member count")
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TestPermission is shorthand that tests if a user has a permission with respect to the community.
|
/* TestPermission is shorthand that tests if a user has a permission with respect to the community.
|
||||||
@@ -254,7 +254,7 @@ func (c *Community) TestPermission(perm string, level uint16) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PermissionLevel returns trhe permission level for a permission name.
|
// PermissionLevel returns the permission level for a permission name.
|
||||||
func (c *Community) PermissionLevel(perm string) uint16 {
|
func (c *Community) PermissionLevel(perm string) uint16 {
|
||||||
switch perm {
|
switch perm {
|
||||||
case "Community.Read":
|
case "Community.Read":
|
||||||
@@ -348,6 +348,41 @@ func (c *Community) SetContactID(cid int32) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Touch updates the last access time of the community.
|
||||||
|
func (c *Community) Touch() error {
|
||||||
|
c.Mutex.Lock()
|
||||||
|
defer c.Mutex.Unlock()
|
||||||
|
_, err := amdb.Exec("UPDATE communities SET lastaccess = NOW() WHERE commid = ?", c.Id)
|
||||||
|
if err == nil {
|
||||||
|
rs, err := amdb.Query("SELECT lastaccess FROM communities WHERE commid = ?", c.Id)
|
||||||
|
if err == nil {
|
||||||
|
rs.Next()
|
||||||
|
var na time.Time
|
||||||
|
rs.Scan(&na)
|
||||||
|
c.LastAccess = &na
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TouchUpdate updates the last access and last update times of the community.
|
||||||
|
func (c *Community) TouchUpdate() error {
|
||||||
|
c.Mutex.Lock()
|
||||||
|
defer c.Mutex.Unlock()
|
||||||
|
_, err := amdb.Exec("UPDATE communities SET lastaccess = NOW(), lastupdate = NOW() WHERE commid = ?", c.Id)
|
||||||
|
if err == nil {
|
||||||
|
rs, err := amdb.Query("SELECT lastaccess, lastupdate FROM communities WHERE commid = ?", c.Id)
|
||||||
|
if err != nil {
|
||||||
|
rs.Next()
|
||||||
|
var na, nu time.Time
|
||||||
|
rs.Scan(&na, &nu)
|
||||||
|
c.LastAccess = &na
|
||||||
|
c.LastUpdate = &nu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
/* AmGetCommunity returns a reference to the specified community.
|
/* AmGetCommunity returns a reference to the specified community.
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* id - The ID of the community.
|
* id - The ID of the community.
|
||||||
|
|||||||
@@ -284,6 +284,9 @@ func (c *amContext) SubRender(name string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
err = view.Execute(buf, c.VarMap(), c)
|
err = view.Execute(buf, c.VarMap(), c)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("template \"%s\" failed subrender exec: %v", name, err)
|
||||||
|
}
|
||||||
return buf.Bytes(), err
|
return buf.Bytes(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+40
-5
@@ -107,6 +107,35 @@ func extractCommunityLogo(a jet.Arguments) reflect.Value {
|
|||||||
return reflect.ValueOf(rc)
|
return reflect.ValueOf(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func displayActivity(a jet.Arguments) reflect.Value {
|
||||||
|
timeval := a.Get(0).Convert(reflect.TypeFor[*time.Time]()).Interface().(*time.Time)
|
||||||
|
ctxt := a.Get(1).Convert(reflect.TypeFor[AmContext]()).Interface().(AmContext)
|
||||||
|
prefs, err := ctxt.CurrentUser().Prefs()
|
||||||
|
if err == nil {
|
||||||
|
return reflect.ValueOf(util.AmActivityString(timeval, prefs.Localizer()))
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(fmt.Sprintf("<<%v>>", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func displayMemberCount(a jet.Arguments) reflect.Value {
|
||||||
|
showHidden := false
|
||||||
|
comm := a.Get(0).Convert(reflect.TypeFor[*database.Community]()).Interface().(*database.Community)
|
||||||
|
ctxt := a.Get(1).Convert(reflect.TypeFor[AmContext]()).Interface().(AmContext)
|
||||||
|
level := ctxt.CurrentUser().BaseLevel
|
||||||
|
mbr, _, clevel, err := comm.Membership(ctxt.CurrentUser())
|
||||||
|
if err == nil {
|
||||||
|
if mbr && clevel > level {
|
||||||
|
level = clevel
|
||||||
|
}
|
||||||
|
showHidden = comm.TestPermission("Community.ShowHiddenMembers", level)
|
||||||
|
}
|
||||||
|
count, err := comm.MemberCount(showHidden)
|
||||||
|
if err != nil {
|
||||||
|
return reflect.ValueOf(-1)
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(count)
|
||||||
|
}
|
||||||
|
|
||||||
// SetupTemplates is called to set up the template renderer after the configuration is loaded.
|
// SetupTemplates is called to set up the template renderer after the configuration is loaded.
|
||||||
func SetupTemplates() {
|
func SetupTemplates() {
|
||||||
views = jet.NewSet(
|
views = jet.NewSet(
|
||||||
@@ -122,17 +151,19 @@ func SetupTemplates() {
|
|||||||
views.AddGlobalFunc("MakeIntRange", makeIntRange)
|
views.AddGlobalFunc("MakeIntRange", makeIntRange)
|
||||||
views.AddGlobalFunc("MakeYearRange", makeYearRange)
|
views.AddGlobalFunc("MakeYearRange", makeYearRange)
|
||||||
views.AddGlobalFunc("ExtractCommunityLogo", extractCommunityLogo)
|
views.AddGlobalFunc("ExtractCommunityLogo", extractCommunityLogo)
|
||||||
|
views.AddGlobalFunc("DisplayActivity", displayActivity)
|
||||||
|
views.AddGlobalFunc("DisplayMemberCount", displayMemberCount)
|
||||||
|
|
||||||
views.AddGlobalFunc("GetCountryList", func(a jet.Arguments) reflect.Value {
|
views.AddGlobalFunc("GetCountryList", func(jet.Arguments) reflect.Value {
|
||||||
return reflect.ValueOf(util.AmCountryList())
|
return reflect.ValueOf(util.AmCountryList())
|
||||||
})
|
})
|
||||||
views.AddGlobalFunc("GetLanguageList", func(a jet.Arguments) reflect.Value {
|
views.AddGlobalFunc("GetLanguageList", func(jet.Arguments) reflect.Value {
|
||||||
return reflect.ValueOf(util.AmLanguageList())
|
return reflect.ValueOf(util.AmLanguageList())
|
||||||
})
|
})
|
||||||
views.AddGlobalFunc("GetTimeZoneList", func(a jet.Arguments) reflect.Value {
|
views.AddGlobalFunc("GetTimeZoneList", func(jet.Arguments) reflect.Value {
|
||||||
return reflect.ValueOf(util.AmTimeZoneList())
|
return reflect.ValueOf(util.AmTimeZoneList())
|
||||||
})
|
})
|
||||||
views.AddGlobalFunc("GetMonthList", func(a jet.Arguments) reflect.Value {
|
views.AddGlobalFunc("GetMonthList", func(jet.Arguments) reflect.Value {
|
||||||
return reflect.ValueOf(util.AmMonthList())
|
return reflect.ValueOf(util.AmMonthList())
|
||||||
})
|
})
|
||||||
views.AddGlobalFunc("AmMenu", func(a jet.Arguments) reflect.Value {
|
views.AddGlobalFunc("AmMenu", func(a jet.Arguments) reflect.Value {
|
||||||
@@ -173,5 +204,9 @@ func (r *TemplateRenderer) Render(w io.Writer, name string, data any, c echo.Con
|
|||||||
if amctxt != nil {
|
if amctxt != nil {
|
||||||
vmap = amctxt.VarMap()
|
vmap = amctxt.VarMap()
|
||||||
}
|
}
|
||||||
return view.Execute(w, vmap, data)
|
err = view.Execute(w, vmap, data)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Template \"%s\" failed exec: %v", name, err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -208,7 +208,7 @@
|
|||||||
{{ h := rx.HostQ() }}
|
{{ h := rx.HostQ() }}
|
||||||
<a href="/user/{{ h.Username }}" class="text-blue-700 hover:text-blue-900">{{ h.Username }}</a>
|
<a href="/user/{{ h.Username }}" class="text-blue-700 hover:text-blue-900">{{ h.Username }}</a>
|
||||||
<span class="mx-2">-</span>
|
<span class="mx-2">-</span>
|
||||||
{{ n := rx.MemberCountQ(false) }}
|
{{ n := DisplayMemberCount(rx, .) }}
|
||||||
{{ if n == 1 }}
|
{{ if n == 1 }}
|
||||||
<span>1 member</span>
|
<span>1 member</span>
|
||||||
{{ else }}
|
{{ else }}
|
||||||
@@ -216,7 +216,7 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="font-medium">Latest activity:</span> [Today, 9:52:48 PM]
|
<span class="font-medium">Latest activity:</span> {{ DisplayActivity(rx.LastAccess, .)}}
|
||||||
</div>
|
</div>
|
||||||
<div class="italic text-gray-600 mt-2">{{ rx.Synopsis }}</div>
|
<div class="italic text-gray-600 mt-2">{{ rx.Synopsis }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,10 +11,12 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/klauspost/lctime"
|
||||||
"github.com/tkuchiki/go-timezone"
|
"github.com/tkuchiki/go-timezone"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -51,6 +53,48 @@ func AmMonthList() []string {
|
|||||||
return rc
|
return rc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* AmActivityString generates a string to represent the activity based on the given timestamp
|
||||||
|
* and the current time.
|
||||||
|
* Parameters:
|
||||||
|
* timeval - The time value representing the last point of activity.
|
||||||
|
* loc - The localizer used to format the time.
|
||||||
|
* Returns:
|
||||||
|
* The string activity equivalent.
|
||||||
|
*/
|
||||||
|
func AmActivityString(timeval *time.Time, loc lctime.Localizer) string {
|
||||||
|
if timeval == nil {
|
||||||
|
return "Never"
|
||||||
|
}
|
||||||
|
now := time.Now().In(timeval.Location())
|
||||||
|
day := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||||
|
if timeval.Compare(day) == 1 {
|
||||||
|
return "Today, " + loc.Strftime("%X", *timeval)
|
||||||
|
}
|
||||||
|
day = time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, now.Location())
|
||||||
|
if timeval.Compare(day) == 1 {
|
||||||
|
return "Yesterday, " + loc.Strftime("%X", *timeval)
|
||||||
|
}
|
||||||
|
duration := now.Sub(*timeval)
|
||||||
|
days := duration.Hours() / 24.0
|
||||||
|
day = time.Date(now.Year(), now.Month()-1, now.Day(), 0, 0, 0, 0, now.Location())
|
||||||
|
if timeval.Compare(day) == 1 {
|
||||||
|
return fmt.Sprintf("%d days ago", int(days))
|
||||||
|
}
|
||||||
|
day = time.Date(now.Year()-1, now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||||
|
if timeval.Compare(day) == 1 {
|
||||||
|
nm := int(days / 30.0)
|
||||||
|
if nm == 1 {
|
||||||
|
return "1 month ago"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d months ago", nm)
|
||||||
|
}
|
||||||
|
ny := int(days / 365.25)
|
||||||
|
if ny == 1 {
|
||||||
|
return "1 year ago"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d years ago", ny)
|
||||||
|
}
|
||||||
|
|
||||||
// init preloads the time zone list.
|
// init preloads the time zone list.
|
||||||
func init() {
|
func init() {
|
||||||
go AmTimeZoneList()
|
go AmTimeZoneList()
|
||||||
|
|||||||
Reference in New Issue
Block a user