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())
|
||||
err = comm.SaveFlags(flags)
|
||||
}
|
||||
if err == nil {
|
||||
err = comm.TouchUpdate()
|
||||
}
|
||||
if err != nil {
|
||||
ctxt.ClearCommunityContext()
|
||||
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)
|
||||
ci.PhotoURL = &photourl
|
||||
_, err = ci.Save()
|
||||
if err == nil {
|
||||
err = comm.TouchUpdate()
|
||||
}
|
||||
if err == nil {
|
||||
return "redirect", "/comm/" + comm.Alias + "/admin/profile", nil
|
||||
}
|
||||
@@ -457,6 +463,9 @@ func CreateCommunity(ctxt ui.AmContext) (string, any, error) {
|
||||
if err == nil {
|
||||
err = comm.SetContactID(ci.ContactId)
|
||||
}
|
||||
if err == nil {
|
||||
err = comm.TouchUpdate()
|
||||
}
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
// MemberCountQ returns the number of members in the community, quietly.
|
||||
func (c *Community) MemberCountQ(hidden bool) int {
|
||||
// MemberCount returns the number of members in the community, quietly.
|
||||
func (c *Community) MemberCount(hidden bool) (int, error) {
|
||||
var rs *sql.Rows
|
||||
var err error
|
||||
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)
|
||||
}
|
||||
if err != nil {
|
||||
return -1
|
||||
return -1, err
|
||||
}
|
||||
if rs.Next() {
|
||||
var rc int
|
||||
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.
|
||||
@@ -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 {
|
||||
switch perm {
|
||||
case "Community.Read":
|
||||
@@ -348,6 +348,41 @@ func (c *Community) SetContactID(cid int32) error {
|
||||
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.
|
||||
* Parameters:
|
||||
* id - The ID of the community.
|
||||
|
||||
@@ -284,6 +284,9 @@ func (c *amContext) SubRender(name string) ([]byte, error) {
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
err = view.Execute(buf, c.VarMap(), c)
|
||||
if err != nil {
|
||||
log.Errorf("template \"%s\" failed subrender exec: %v", name, err)
|
||||
}
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
|
||||
+40
-5
@@ -107,6 +107,35 @@ func extractCommunityLogo(a jet.Arguments) reflect.Value {
|
||||
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.
|
||||
func SetupTemplates() {
|
||||
views = jet.NewSet(
|
||||
@@ -122,17 +151,19 @@ func SetupTemplates() {
|
||||
views.AddGlobalFunc("MakeIntRange", makeIntRange)
|
||||
views.AddGlobalFunc("MakeYearRange", makeYearRange)
|
||||
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())
|
||||
})
|
||||
views.AddGlobalFunc("GetLanguageList", func(a jet.Arguments) reflect.Value {
|
||||
views.AddGlobalFunc("GetLanguageList", func(jet.Arguments) reflect.Value {
|
||||
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())
|
||||
})
|
||||
views.AddGlobalFunc("GetMonthList", func(a jet.Arguments) reflect.Value {
|
||||
views.AddGlobalFunc("GetMonthList", func(jet.Arguments) reflect.Value {
|
||||
return reflect.ValueOf(util.AmMonthList())
|
||||
})
|
||||
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 {
|
||||
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() }}
|
||||
<a href="/user/{{ h.Username }}" class="text-blue-700 hover:text-blue-900">{{ h.Username }}</a>
|
||||
<span class="mx-2">-</span>
|
||||
{{ n := rx.MemberCountQ(false) }}
|
||||
{{ n := DisplayMemberCount(rx, .) }}
|
||||
{{ if n == 1 }}
|
||||
<span>1 member</span>
|
||||
{{ else }}
|
||||
@@ -216,7 +216,7 @@
|
||||
{{ end }}
|
||||
</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 class="italic text-gray-600 mt-2">{{ rx.Synopsis }}</div>
|
||||
</div>
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/klauspost/lctime"
|
||||
"github.com/tkuchiki/go-timezone"
|
||||
)
|
||||
|
||||
@@ -51,6 +53,48 @@ func AmMonthList() []string {
|
||||
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.
|
||||
func init() {
|
||||
go AmTimeZoneList()
|
||||
|
||||
Reference in New Issue
Block a user