diff --git a/pkg/controller/admin/feedback.go b/pkg/controller/admin/feedback.go index 1820ea1..2767c0a 100644 --- a/pkg/controller/admin/feedback.go +++ b/pkg/controller/admin/feedback.go @@ -14,6 +14,13 @@ import ( // Feedback controller (/admin/feedback) func Feedback() http.HandlerFunc { tmpl := templates.Must("admin/feedback.html") + + // Whitelist for ordering options. + var sortWhitelist = []string{ + "created_at desc", + "created_at asc", + } + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Query params. var ( @@ -23,8 +30,26 @@ func Feedback() http.HandlerFunc { profile = r.FormValue("profile") == "true" // visit associated user profile verdict = r.FormValue("verdict") fb *models.Feedback + + // Search filters. + searchQuery = r.FormValue("q") + search = models.ParseSearchString(searchQuery) + subject = r.FormValue("subject") + sort = r.FormValue("sort") + sortOK bool ) + // Sort options. + for _, v := range sortWhitelist { + if sort == v { + sortOK = true + break + } + } + if !sortOK { + sort = sortWhitelist[0] + } + currentUser, err := session.CurrentUser(r) if err != nil { session.FlashError(w, r, "Couldn't get your current user: %s", err) @@ -149,10 +174,10 @@ func Feedback() http.HandlerFunc { pager := &models.Pagination{ Page: 1, PerPage: config.PageSizeAdminFeedback, - Sort: "updated_at desc", + Sort: sort, } pager.ParsePage(r) - page, err := models.PaginateFeedback(acknowledged, intent, pager) + page, err := models.PaginateFeedback(acknowledged, intent, subject, search, pager) if err != nil { session.FlashError(w, r, "Couldn't load feedback from DB: %s", err) } @@ -170,6 +195,12 @@ func Feedback() http.HandlerFunc { } var vars = map[string]interface{}{ + // Filter settings. + "DistinctSubjects": models.DistinctFeedbackSubjects(), + "SearchTerm": searchQuery, + "Subject": subject, + "Sort": sort, + "Intent": intent, "Acknowledged": acknowledged, "Feedback": page, diff --git a/pkg/models/feedback.go b/pkg/models/feedback.go index 94a001d..9e7c28c 100644 --- a/pkg/models/feedback.go +++ b/pkg/models/feedback.go @@ -1,6 +1,7 @@ package models import ( + "sort" "strings" "time" @@ -45,7 +46,7 @@ func CountUnreadFeedback() int64 { } // PaginateFeedback -func PaginateFeedback(acknowledged bool, intent string, pager *Pagination) ([]*Feedback, error) { +func PaginateFeedback(acknowledged bool, intent, subject string, search *Search, pager *Pagination) ([]*Feedback, error) { var ( fb = []*Feedback{} wheres = []string{} @@ -60,6 +61,23 @@ func PaginateFeedback(acknowledged bool, intent string, pager *Pagination) ([]*F placeholders = append(placeholders, intent) } + if subject != "" { + wheres = append(wheres, "subject = ?") + placeholders = append(placeholders, subject) + } + + // Search terms. + for _, term := range search.Includes { + var ilike = "%" + strings.ToLower(term) + "%" + wheres = append(wheres, "message ILIKE ?") + placeholders = append(placeholders, ilike) + } + for _, term := range search.Excludes { + var ilike = "%" + strings.ToLower(term) + "%" + wheres = append(wheres, "message NOT ILIKE ?") + placeholders = append(placeholders, ilike) + } + query := DB.Where( strings.Join(wheres, " AND "), placeholders..., @@ -91,9 +109,10 @@ func PaginateFeedbackAboutUser(user *User, pager *Pagination) ([]*Feedback, erro wheres = append(wheres, ` (table_name = 'users' AND table_id = ?) OR - (table_name = 'photos' AND table_id IN ?) + (table_name = 'photos' AND table_id IN ?) OR + message LIKE ? `) - placeholders = append(placeholders, user.ID, photoIDs) + placeholders = append(placeholders, user.ID, photoIDs, user.Username) query := DB.Where( strings.Join(wheres, " AND "), @@ -111,6 +130,22 @@ func PaginateFeedbackAboutUser(user *User, pager *Pagination) ([]*Feedback, erro return fb, result.Error } +// DistinctFeedbackSubjects returns the distinct subjects on feedback & reports. +func DistinctFeedbackSubjects() []string { + var results = []string{} + query := DB.Model(&Feedback{}). + Select("DISTINCT feedbacks.subject"). + Group("feedbacks.subject"). + Find(&results) + if query.Error != nil { + log.Error("DistinctFeedbackSubjects: %s", query.Error) + return nil + } + + sort.Strings(results) + return results +} + // CreateFeedback saves a new Feedback row to the DB. func CreateFeedback(fb *Feedback) error { result := DB.Create(fb) diff --git a/web/templates/admin/feedback.html b/web/templates/admin/feedback.html index 62ba733..ce2ae4e 100644 --- a/web/templates/admin/feedback.html +++ b/web/templates/admin/feedback.html @@ -23,13 +23,13 @@
@@ -38,16 +38,93 @@
+ +
+
+ + + +
+ +
+
+ +
+
+ + +

+ Tip: you can "quote exact phrases" and + -exclude words (or + -"exclude phrases") from your search. +

+
+
+ +
+
+ +
+ +
+
+
+ +
+
+ +
+ +
+
+
+ +
+ + Reset + +
+
+
+
+ +
+ +
+ {{SimplePager .Pager}}