landed community results when browsing categories - missing pagination buttons, community activity, proper member counts
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
@@ -139,6 +140,18 @@ func (c *Community) Host() (*User, error) {
|
||||
return AmGetUser(*c.HostUid)
|
||||
}
|
||||
|
||||
// HostQ returns the reference to the community's host, quietly.
|
||||
func (c *Community) HostQ() *User {
|
||||
if c.HostUid == nil {
|
||||
return nil
|
||||
}
|
||||
u, err := AmGetUser(*c.HostUid)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
func (c *Community) LanguageTag() (*language.Tag, error) {
|
||||
if c.Language == nil {
|
||||
return nil, nil
|
||||
@@ -196,6 +209,26 @@ 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 {
|
||||
var rs *sql.Rows
|
||||
var err error
|
||||
if hidden {
|
||||
rs, err = amdb.Query("SELECT COUNT(*) FROM commmember WHERE commid = ?", c.Id)
|
||||
} else {
|
||||
rs, err = amdb.Query("SELECT COUNT(*) FROM commmember WHERE commid = ? AND hidden = 0", c.Id)
|
||||
}
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
if rs.Next() {
|
||||
var rc int
|
||||
rs.Scan(&rc)
|
||||
return rc
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
/* TestPermission is shorthand that tests if a user has a permission with respect to the community.
|
||||
* Parameters:
|
||||
* user - The user to be checked.
|
||||
@@ -620,3 +653,67 @@ func AmCreateCommunity(name string, alias string, hostUid int32, language *strin
|
||||
fmt.Sprintf("name=%s", comm.Name), fmt.Sprintf("alias=%s", comm.Alias))
|
||||
return comm, nil
|
||||
}
|
||||
|
||||
/* AmGetCommunitiesForCategory returns a list of communities for the specified category.
|
||||
* Parameters:
|
||||
* catid - Category ID to search for.
|
||||
* offset - Number of communities to skip at beginning of list.
|
||||
* max - Maximum number of communities to return.
|
||||
* showAll - Include communities that are "hidden in directory."
|
||||
* Returns:
|
||||
* Array of Community pointers representing the return elements.
|
||||
* The total number of communities matching this query (could be greater than max)
|
||||
* Standard Go error status.
|
||||
*/
|
||||
func AmGetCommunitiesForCategory(catid int32, offset int, max int, showAll bool) ([]*Community, int, error) {
|
||||
var rs *sql.Rows
|
||||
var err error
|
||||
if showAll {
|
||||
rs, err = amdb.Query("SELECT COUNT(*) FROM communities WHERE catid = ?", catid)
|
||||
} else {
|
||||
rs, err = amdb.Query("SELECT COUNT(*) FROM communities WHERE catid = ? AND hide_dir = 0", catid)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
if !rs.Next() {
|
||||
return nil, -1, errors.New("internal error getting total match count")
|
||||
}
|
||||
var total int
|
||||
rs.Scan(&total)
|
||||
if total == 0 {
|
||||
return make([]*Community, 0), 0, nil // short-circuit return
|
||||
}
|
||||
if showAll {
|
||||
if offset > 0 {
|
||||
rs, err = amdb.Query("SELECT commid FROM communities WHERE catid = ? ORDER BY commname LIMIT ? OFFSET ?",
|
||||
catid, max, offset)
|
||||
} else {
|
||||
rs, err = amdb.Query("SELECT commid FROM communities WHERE catid = ? ORDER BY commname LIMIT ?", catid, max)
|
||||
}
|
||||
} else {
|
||||
if offset > 0 {
|
||||
rs, err = amdb.Query("SELECT commid FROM communities WHERE catid = ? AND hide_dir = 0 ORDER BY commname LIMIT ? OFFSET ?",
|
||||
catid, max, offset)
|
||||
} else {
|
||||
rs, err = amdb.Query("SELECT commid FROM communities WHERE catid = ? AND hide_dir = 0 ORDER BY commname LIMIT ?", catid, max)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, total, err
|
||||
}
|
||||
rcCap := max
|
||||
if rcCap > 10000 {
|
||||
rcCap = 10000
|
||||
}
|
||||
rc := make([]*Community, 0, rcCap)
|
||||
for rs.Next() {
|
||||
var commid int32
|
||||
rs.Scan(&commid)
|
||||
c, err := AmGetCommunity(commid)
|
||||
if err == nil {
|
||||
rc = append(rc, c)
|
||||
}
|
||||
}
|
||||
return rc, total, nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"git.erbosoft.com/amy/amsterdam/database"
|
||||
@@ -17,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
// loadCategoryInformation loads the current category information to the context.
|
||||
func loadCategoryInformation(ctxt ui.AmContext) error {
|
||||
func loadCategoryInformation(ctxt ui.AmContext, offset int) error {
|
||||
u := ctxt.CurrentUser()
|
||||
catid := int32(-1)
|
||||
p := ctxt.Parameter("catid")
|
||||
@@ -42,7 +43,8 @@ func loadCategoryInformation(ctxt ui.AmContext) error {
|
||||
}
|
||||
ctxt.SetSession("find.catid", catid)
|
||||
ctxt.VarMap().Set("catid", catid)
|
||||
ctxt.VarMap().Set("showHiddenCat", database.AmTestPermission("Global.ShowHiddenCategories", u.BaseLevel))
|
||||
showHidden := database.AmTestPermission("Global.ShowHiddenCategories", u.BaseLevel)
|
||||
ctxt.VarMap().Set("showHiddenCat", showHidden)
|
||||
hier, err := database.AmGetCategoryHierarchy(catid)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -53,7 +55,29 @@ func loadCategoryInformation(ctxt ui.AmContext) error {
|
||||
return err
|
||||
}
|
||||
ctxt.VarMap().Set("catSubs", subs)
|
||||
// TODO: set matching communities as well
|
||||
ctxt.VarMap().Set("displayCats", true)
|
||||
|
||||
if catid > -1 {
|
||||
// search for communities in this category
|
||||
listMax := int(ctxt.Globals().MaxSearchPage)
|
||||
commList, numComm, err := database.AmGetCommunitiesForCategory(catid, offset*listMax, listMax, showHidden)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(commList) == 0 {
|
||||
ctxt.VarMap().Set("resultHeader", "Communities in Category (None)")
|
||||
} else {
|
||||
ctxt.VarMap().Set("resultHeader", fmt.Sprintf("Communities in Category (Displaying %d-%d of %d)",
|
||||
offset*listMax+1, offset*listMax+len(commList), numComm))
|
||||
ctxt.VarMap().Set("resultList", commList)
|
||||
if offset > 0 {
|
||||
ctxt.VarMap().Set("resultShowPrev", true)
|
||||
}
|
||||
if offset*listMax+len(commList) < numComm {
|
||||
ctxt.VarMap().Set("resultShowNext", true)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -79,6 +103,14 @@ func FindPage(ctxt ui.AmContext) (string, any, error) {
|
||||
if mode == "" {
|
||||
mode = "COM"
|
||||
}
|
||||
ofs := 0
|
||||
p = ctxt.Parameter("ofs")
|
||||
if p != "" {
|
||||
v, err := strconv.Atoi(p)
|
||||
if err == nil {
|
||||
ofs = v
|
||||
}
|
||||
}
|
||||
ctxt.SetSession("find.mode", mode)
|
||||
ctxt.VarMap().Set("mode", mode)
|
||||
switch mode {
|
||||
@@ -86,7 +118,7 @@ func FindPage(ctxt ui.AmContext) (string, any, error) {
|
||||
ctxt.VarMap().Set("field", "name")
|
||||
ctxt.VarMap().Set("oper", "st")
|
||||
ctxt.VarMap().Set("term", "")
|
||||
err := loadCategoryInformation(ctxt)
|
||||
err := loadCategoryInformation(ctxt, ofs)
|
||||
if err != nil {
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
<strong>Category:</strong>
|
||||
{{ range i := categories }}
|
||||
{{ if i > 0 }}: {{ end }}
|
||||
<a href="/TODO/find/communities-for-category"
|
||||
<a href="/find?mode=COM&catid={{ .CatId }}"
|
||||
class="text-blue-700 hover:text-blue-900">{{ .Name }}</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
+54
-1
@@ -139,7 +139,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Category Listing -->
|
||||
{{ if mode == "COM" }}
|
||||
{{ if isset(displayCats) }}
|
||||
<div class="max-w-3xl">
|
||||
<hr class="border-gray-400 mb-4">
|
||||
|
||||
@@ -181,4 +181,57 @@
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{ if isset(resultHeader) }}
|
||||
<!-- Search results -->
|
||||
<hr class="border-gray-400 mb-4">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<div class="text-sm text-black font-bold">{{ resultHeader }}</div>
|
||||
</div>
|
||||
{{ if isset(resultList) }}
|
||||
<!-- Results List -->
|
||||
<div class="bg-gray-50 p-6 rounded-lg">
|
||||
<div class="space-y-4">
|
||||
{{ range _, rx := resultList }}
|
||||
{{ if mode == "COM" }}
|
||||
<!-- Community Result -->
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="text-sm pt-0.5 flex-shrink-0">🟣</span>
|
||||
<div class="flex-1">
|
||||
<div class="mb-2">
|
||||
<a href="/comm/{{ rx.Alias }}/profile"
|
||||
class="text-blue-700 hover:text-blue-900 font-bold text-base">{{ rx.Name }}</a>
|
||||
</div>
|
||||
<div class="text-sm text-gray-700 space-y-1">
|
||||
<div>
|
||||
<span class="font-medium">Host:</span>
|
||||
{{ 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) }}
|
||||
{{ if n == 1 }}
|
||||
<span>1 member</span>
|
||||
{{ else }}
|
||||
<span>{{ n }} members</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-medium">Latest activity:</span> [Today, 9:52:48 PM]
|
||||
</div>
|
||||
<div class="italic text-gray-600 mt-2">{{ rx.Synopsis }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ else if mode == "USR" }}
|
||||
TODO: I don't know USR yet
|
||||
{{ else if mode == "CAT" }}
|
||||
TODO: I don't know CAT yet
|
||||
{{ else if mode == "PST" }}
|
||||
TODO: I don't know PST yet
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user