Move pagination to helper function and implement filters+search in contacts
This commit is contained in:
parent
581d11c98d
commit
b3c309743b
5 changed files with 470 additions and 61 deletions
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.readonly.ch/bouzoure/pop-camarades/helpers"
|
||||
|
|
@ -45,26 +46,374 @@ func Contacts(c *fiber.Ctx) error {
|
|||
return err
|
||||
}
|
||||
|
||||
var people []models.Person
|
||||
result := db.Order(
|
||||
"last_name collate nocase asc, first_name collate nocase asc",
|
||||
).Preload("Section").Find(
|
||||
&people, "is_contact = ? AND section_id IN ?", true, allowedSections,
|
||||
)
|
||||
filterSection := c.Query("se")
|
||||
filterArchive := c.Query("a")
|
||||
filterSearch := c.Query("s")
|
||||
|
||||
if result.Error != nil && !errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
sqlFilterSections := allowedSections
|
||||
sqlFilterAppend := "IS NULL"
|
||||
if filterArchive == "1" {
|
||||
sqlFilterAppend = "IS NOT NULL"
|
||||
sqlFilterSections = allowedSectionsArchived
|
||||
}
|
||||
|
||||
var filterSectionUint uint
|
||||
if len(filterSection) > 0 {
|
||||
filterSectionUint64, err := strconv.ParseUint(filterSection, 10, 0)
|
||||
if err == nil {
|
||||
for _, s := range sqlFilterSections {
|
||||
if s == uint(filterSectionUint64) {
|
||||
filterSectionUint = uint(filterSectionUint64)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if filterSectionUint > 0 {
|
||||
sqlFilterAppend = fmt.Sprintf(
|
||||
"%s AND section_id = %d",
|
||||
sqlFilterAppend,
|
||||
filterSectionUint,
|
||||
)
|
||||
}
|
||||
|
||||
var sqlFilterSearch string
|
||||
if len(filterSearch) > 0 {
|
||||
sqlFilterSearch = fmt.Sprintf(
|
||||
"%%%s%%", filterSearch,
|
||||
)
|
||||
}
|
||||
|
||||
var count int64
|
||||
if len(filterSearch) > 0 {
|
||||
db.Model(&models.Person{}).Where(
|
||||
fmt.Sprintf(
|
||||
"is_contact = ? AND section_id IN ? AND (first_name LIKE ? OR last_name LIKE ?) AND deleted_at %s",
|
||||
sqlFilterAppend,
|
||||
),
|
||||
true, allowedSections, sqlFilterSearch, sqlFilterSearch,
|
||||
).Count(&count)
|
||||
} else {
|
||||
db.Model(&models.Person{}).Where(
|
||||
fmt.Sprintf(
|
||||
"is_contact = ? AND section_id IN ? AND deleted_at %s",
|
||||
sqlFilterAppend,
|
||||
),
|
||||
true, allowedSections,
|
||||
).Count(&count)
|
||||
}
|
||||
|
||||
page, _ := strconv.Atoi(c.Query("p"))
|
||||
pagination := helpers.Paginate(50, int(count), page)
|
||||
|
||||
var people []models.Person
|
||||
if len(filterSearch) > 0 {
|
||||
result := db.Unscoped().Offset(
|
||||
pagination.Offset,
|
||||
).Limit(
|
||||
pagination.PageSize,
|
||||
).Order(
|
||||
"last_name collate nocase asc, first_name collate nocase asc",
|
||||
).Preload(
|
||||
"Section",
|
||||
).Find(
|
||||
&people,
|
||||
fmt.Sprintf(
|
||||
"is_contact = ? AND section_id IN ? AND (first_name LIKE ? OR last_name LIKE ?) AND deleted_at %s",
|
||||
sqlFilterAppend,
|
||||
),
|
||||
true, sqlFilterSections, sqlFilterSearch, sqlFilterSearch,
|
||||
)
|
||||
|
||||
if result.Error != nil && !errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
result := db.Unscoped().Offset(
|
||||
pagination.Offset,
|
||||
).Limit(
|
||||
pagination.PageSize,
|
||||
).Order(
|
||||
"last_name collate nocase asc, first_name collate nocase asc",
|
||||
).Preload(
|
||||
"Section",
|
||||
).Find(
|
||||
&people,
|
||||
fmt.Sprintf(
|
||||
"is_contact = ? AND section_id IN ? AND deleted_at %s",
|
||||
sqlFilterAppend,
|
||||
),
|
||||
true, sqlFilterSections,
|
||||
)
|
||||
|
||||
if result.Error != nil && !errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var sections []models.Section
|
||||
db.Order(
|
||||
"name collate nocase asc",
|
||||
).Find(
|
||||
§ions, sqlFilterSections,
|
||||
)
|
||||
|
||||
return c.Render("people", fiber.Map{
|
||||
"PageTitle": "Contacts",
|
||||
"MembersPage": false,
|
||||
"People": people,
|
||||
"Pagination": pagination,
|
||||
"PermShow": permShow,
|
||||
"PermShowArchived": permShowArchived,
|
||||
"Sections": sections,
|
||||
"FilterArchive": filterArchive,
|
||||
"FilterSection": filterSectionUint,
|
||||
"FilterSearch": filterSearch,
|
||||
})
|
||||
}
|
||||
|
||||
func ContactsExport(c *fiber.Ctx) error {
|
||||
userid, err := helpers.GetSessionUserId(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
allowedSections, err := helpers.PermissionsGetSections(
|
||||
userid, "show_contact",
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
allowedSectionsArchived, err := helpers.PermissionsGetSections(
|
||||
userid, "show_archived_contact",
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
permShow := (len(allowedSections) > 0)
|
||||
permShowArchived := (len(allowedSectionsArchived) > 0)
|
||||
|
||||
if !permShow && !permShowArchived {
|
||||
return fiber.NewError(fiber.StatusForbidden, "Forbidden")
|
||||
}
|
||||
|
||||
db, err := helpers.GetDatabase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filterSection := c.Query("se")
|
||||
filterArchive := c.Query("a")
|
||||
filterSearch := c.Query("s")
|
||||
|
||||
sqlFilterSections := allowedSections
|
||||
sqlFilterAppend := "IS NULL"
|
||||
if filterArchive == "1" {
|
||||
sqlFilterAppend = "IS NOT NULL"
|
||||
sqlFilterSections = allowedSectionsArchived
|
||||
}
|
||||
|
||||
var filterSectionUint uint
|
||||
if len(filterSection) > 0 {
|
||||
filterSectionUint64, err := strconv.ParseUint(filterSection, 10, 0)
|
||||
if err == nil {
|
||||
for _, s := range sqlFilterSections {
|
||||
if s == uint(filterSectionUint64) {
|
||||
filterSectionUint = uint(filterSectionUint64)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if filterSectionUint > 0 {
|
||||
sqlFilterAppend = fmt.Sprintf(
|
||||
"%s AND section_id = %d",
|
||||
sqlFilterAppend,
|
||||
filterSectionUint,
|
||||
)
|
||||
}
|
||||
|
||||
var sqlFilterSearch string
|
||||
if len(filterSearch) > 0 {
|
||||
sqlFilterSearch = fmt.Sprintf(
|
||||
"%%%s%%", filterSearch,
|
||||
)
|
||||
}
|
||||
|
||||
var people []models.Person
|
||||
if len(filterSearch) > 0 {
|
||||
result := db.Unscoped().Order(
|
||||
"last_name collate nocase asc, first_name collate nocase asc",
|
||||
).Preload("Section").Find(
|
||||
&people,
|
||||
fmt.Sprintf(
|
||||
"is_contact = ? AND section_id IN ? AND (first_name LIKE ? OR last_name LIKE ?) AND deleted_at %s",
|
||||
sqlFilterAppend,
|
||||
),
|
||||
true, sqlFilterSections, sqlFilterSearch, sqlFilterSearch,
|
||||
)
|
||||
|
||||
if result.Error != nil && !errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
result := db.Unscoped().Order(
|
||||
"last_name collate nocase asc, first_name collate nocase asc",
|
||||
).Preload("Section").Find(
|
||||
&people,
|
||||
fmt.Sprintf(
|
||||
"is_contact = ? AND section_id IN ? AND deleted_at %s",
|
||||
sqlFilterAppend,
|
||||
),
|
||||
true, sqlFilterSections,
|
||||
)
|
||||
|
||||
if result.Error != nil && !errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var fields []models.Field
|
||||
db.Order("name collate nocase asc").Preload(
|
||||
"List",
|
||||
).Find(
|
||||
&fields, "person_type = ?", "contact",
|
||||
)
|
||||
|
||||
var fieldValues []models.FieldValue
|
||||
db.Preload("ListItem").Find(&fieldValues)
|
||||
|
||||
c.Set("Content-Type", "text/csv")
|
||||
c.Set("Content-Disposition", fmt.Sprintf(
|
||||
"attachment;filename=contacts_%s.csv",
|
||||
time.Now().Format(time.RFC3339),
|
||||
))
|
||||
|
||||
csvFields := []string{
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
"phone",
|
||||
"mobile",
|
||||
"address1",
|
||||
"address2",
|
||||
"postal_code",
|
||||
"city",
|
||||
"section_id",
|
||||
"section_name",
|
||||
}
|
||||
|
||||
for _, field := range fields {
|
||||
csvFields = append(csvFields, field.Name)
|
||||
}
|
||||
|
||||
for key, csvField := range csvFields {
|
||||
csvField = strings.ReplaceAll(csvField, "\r", "")
|
||||
csvField = strings.ReplaceAll(csvField, "\n", " ")
|
||||
csvField = strings.ReplaceAll(csvField, ",", "_")
|
||||
csvField = strings.ReplaceAll(csvField, ";", "_")
|
||||
|
||||
if key+1 == len(csvFields) {
|
||||
c.Writef("\"%s\"\n", csvField)
|
||||
} else {
|
||||
c.Writef("\"%s\";", csvField)
|
||||
}
|
||||
}
|
||||
|
||||
for _, person := range people {
|
||||
c.Writef("\"%s\";", person.FirstName)
|
||||
c.Writef("\"%s\";", person.LastName)
|
||||
c.Writef("\"%s\";", person.Email)
|
||||
c.Writef("\"%s\";", person.Phone)
|
||||
c.Writef("\"%s\";", person.Mobile)
|
||||
c.Writef("\"%s\";", person.Address1)
|
||||
c.Writef("\"%s\";", person.Address2)
|
||||
c.Writef("\"%s\";", person.PostalCode)
|
||||
c.Writef("\"%s\";", person.City)
|
||||
c.Writef("\"%d\";", person.SectionID)
|
||||
|
||||
if len(fields) > 0 {
|
||||
c.Writef("\"%s\";", person.Section.Name)
|
||||
} else {
|
||||
c.Writef("\"%s\"\n", person.Section.Name)
|
||||
}
|
||||
|
||||
for key, field := range fields {
|
||||
endLine := ";"
|
||||
if key+1 == len(fields) {
|
||||
endLine = "\n"
|
||||
}
|
||||
|
||||
countMulti := 0
|
||||
found := false
|
||||
for _, value := range fieldValues {
|
||||
if value.FieldID == field.ID && value.PersonID == person.ID {
|
||||
found = true
|
||||
|
||||
if field.FieldType == "text" || field.FieldType == "longtext" {
|
||||
|
||||
text := value.ValueString.String
|
||||
text = strings.ReplaceAll(text, "\r", "")
|
||||
text = strings.ReplaceAll(text, "\n", " ")
|
||||
text = strings.ReplaceAll(text, ",", "_")
|
||||
text = strings.ReplaceAll(text, ";", "_")
|
||||
|
||||
c.Writef("\"%s\"%s", text, endLine)
|
||||
|
||||
} else if field.FieldType == "number" {
|
||||
|
||||
if value.ValueInt.Valid {
|
||||
c.Writef("\"%d\"%s", value.ValueInt.Int64, endLine)
|
||||
} else {
|
||||
c.Writef("\"\"%s", endLine)
|
||||
}
|
||||
|
||||
} else if field.FieldType == "date" {
|
||||
|
||||
if value.ValueDate.Valid {
|
||||
date := value.ValueDate.Time.Format("2006-01-02")
|
||||
c.Writef("\"%s\"%s", date, endLine)
|
||||
} else {
|
||||
c.Writef("\"\"%s", endLine)
|
||||
}
|
||||
|
||||
} else if field.FieldType == "list" {
|
||||
|
||||
if field.List.Multi {
|
||||
|
||||
if countMulti == 0 {
|
||||
c.Writef("\"")
|
||||
} else {
|
||||
c.Writef(",")
|
||||
}
|
||||
|
||||
c.Writef("%s", value.ListItem.Value)
|
||||
countMulti++
|
||||
|
||||
} else {
|
||||
c.Writef("\"%s\"%s", value.ListItem.Value, endLine)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if countMulti > 0 {
|
||||
c.Writef("\"%s", endLine)
|
||||
}
|
||||
|
||||
if !found {
|
||||
c.Writef("\"\"%s", endLine)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ContactShow(c *fiber.Ctx) error {
|
||||
id := c.Params("id")
|
||||
|
||||
|
|
@ -78,14 +427,14 @@ func ContactShow(c *fiber.Ctx) error {
|
|||
&person, "id = ? AND is_contact", id, true,
|
||||
)
|
||||
|
||||
if result.RowsAffected < 1 {
|
||||
return fiber.NewError(fiber.StatusNotFound, "Not found")
|
||||
}
|
||||
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected < 1 {
|
||||
return fiber.NewError(fiber.StatusNotFound, "Not found")
|
||||
}
|
||||
|
||||
userid, err := helpers.GetSessionUserId(c)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue