search.go
TLDR
This file, search.go
, is part of the Demo Projects project and contains the implementation of search related API endpoints for boards and channels. It includes methods for handling searches of boards, channels, linkable boards, and all boards.
Methods
handleSearchMyChannels
This method handles a GET request to /teams/{teamID}/channels
and returns the user's available channels. It requires authentication and the parameters teamID
(Team ID) and search
(string to filter channels list) are optional.
handleSearchBoards
This method handles a GET request to /teams/{teamID}/boards/search
and returns the boards that match a search term in the specified team. It requires authentication and the parameters teamID
(Team ID), q
(the search term), and field
(the field to search on) are required.
handleSearchLinkableBoards
This method handles a GET request to /teams/{teamID}/boards/search/linkable
and returns the boards that match a search term in the specified team and the user has permission to manage members. It requires authentication and the parameters teamID
(Team ID) and q
(the search term) are required.
handleSearchAllBoards
This method handles a GET request to /boards/search
and returns the boards that match a search term. It requires authentication and the parameter q
(the search term) is required.
Classes
package api
import (
"encoding/json"
"net/http"
"github.com/gorilla/mux"
"github.com/mattermost/focalboard/server/model"
"github.com/mattermost/focalboard/server/services/audit"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
func (a *API) registerSearchRoutes(r *mux.Router) {
r.HandleFunc("/teams/{teamID}/channels", a.sessionRequired(a.handleSearchMyChannels)).Methods("GET")
r.HandleFunc("/teams/{teamID}/boards/search", a.sessionRequired(a.handleSearchBoards)).Methods("GET")
r.HandleFunc("/teams/{teamID}/boards/search/linkable", a.sessionRequired(a.handleSearchLinkableBoards)).Methods("GET")
r.HandleFunc("/boards/search", a.sessionRequired(a.handleSearchAllBoards)).Methods("GET")
}
func (a *API) handleSearchMyChannels(w http.ResponseWriter, r *http.Request) {
// swagger:operation GET /teams/{teamID}/channels searchMyChannels
//
// Returns the user available channels
//
// ---
// produces:
// - application/json
// parameters:
// - name: teamID
// in: path
// description: Team ID
// required: true
// type: string
// - name: search
// in: query
// description: string to filter channels list
// required: false
// type: string
// security:
// - BearerAuth: []
// responses:
// '200':
// description: success
// schema:
// type: array
// items:
// "$ref": "#/definitions/Channel"
// default:
// description: internal error
// schema:
// "$ref": "#/definitions/ErrorResponse"
if !a.MattermostAuth {
a.errorResponse(w, r, model.NewErrNotImplemented("not permitted in standalone mode"))
return
}
query := r.URL.Query()
searchQuery := query.Get("search")
teamID := mux.Vars(r)["teamID"]
userID := getUserID(r)
if !a.permissions.HasPermissionToTeam(userID, teamID, model.PermissionViewTeam) {
a.errorResponse(w, r, model.NewErrPermission("access denied to team"))
return
}
auditRec := a.makeAuditRecord(r, "searchMyChannels", audit.Fail)
defer a.audit.LogRecord(audit.LevelRead, auditRec)
auditRec.AddMeta("teamID", teamID)
channels, err := a.app.SearchUserChannels(teamID, userID, searchQuery)
if err != nil {
a.errorResponse(w, r, err)
return
}
a.logger.Debug("GetUserChannels",
mlog.String("teamID", teamID),
mlog.Int("channelsCount", len(channels)),
)
data, err := json.Marshal(channels)
if err != nil {
a.errorResponse(w, r, err)
return
}
// response
jsonBytesResponse(w, http.StatusOK, data)
auditRec.AddMeta("channelsCount", len(channels))
auditRec.Success()
}
func (a *API) handleSearchBoards(w http.ResponseWriter, r *http.Request) {
// swagger:operation GET /teams/{teamID}/boards/search searchBoards
//
// Returns the boards that match with a search term in the team
//
// ---
// produces:
// - application/json
// parameters:
// - name: teamID
// in: path
// description: Team ID
// required: true
// type: string
// - name: q
// in: query
// description: The search term. Must have at least one character
// required: true
// type: string
// - name: field
// in: query
// description: The field to search on for search term. Can be `title`, `property_name`. Defaults to `title`
// required: false
// type: string
// security:
// - BearerAuth: []
// responses:
// '200':
// description: success
// schema:
// type: array
// items:
// "$ref": "#/definitions/Board"
// default:
// description: internal error
// schema:
// "$ref": "#/definitions/ErrorResponse"
var err error
teamID := mux.Vars(r)["teamID"]
term := r.URL.Query().Get("q")
searchFieldText := r.URL.Query().Get("field")
searchField := model.BoardSearchFieldTitle
if searchFieldText != "" {
searchField, err = model.BoardSearchFieldFromString(searchFieldText)
if err != nil {
a.errorResponse(w, r, model.NewErrBadRequest(err.Error()))
return
}
}
userID := getUserID(r)
if !a.permissions.HasPermissionToTeam(userID, teamID, model.PermissionViewTeam) {
a.errorResponse(w, r, model.NewErrPermission("access denied to team"))
return
}
if len(term) == 0 {
jsonStringResponse(w, http.StatusOK, "[]")
return
}
auditRec := a.makeAuditRecord(r, "searchBoards", audit.Fail)
defer a.audit.LogRecord(audit.LevelRead, auditRec)
auditRec.AddMeta("teamID", teamID)
isGuest, err := a.userIsGuest(userID)
if err != nil {
a.errorResponse(w, r, err)
return
}
// retrieve boards list
boards, err := a.app.SearchBoardsForUser(term, searchField, userID, !isGuest)
if err != nil {
a.errorResponse(w, r, err)
return
}
a.logger.Debug("SearchBoards",
mlog.String("teamID", teamID),
mlog.Int("boardsCount", len(boards)),
)
data, err := json.Marshal(boards)
if err != nil {
a.errorResponse(w, r, err)
return
}
// response
jsonBytesResponse(w, http.StatusOK, data)
auditRec.AddMeta("boardsCount", len(boards))
auditRec.Success()
}
func (a *API) handleSearchLinkableBoards(w http.ResponseWriter, r *http.Request) {
// swagger:operation GET /teams/{teamID}/boards/search/linkable searchLinkableBoards
//
// Returns the boards that match with a search term in the team and the
// user has permission to manage members
//
// ---
// produces:
// - application/json
// parameters:
// - name: teamID
// in: path
// description: Team ID
// required: true
// type: string
// - name: q
// in: query
// description: The search term. Must have at least one character
// required: true
// type: string
// security:
// - BearerAuth: []
// responses:
// '200':
// description: success
// schema:
// type: array
// items:
// "$ref": "#/definitions/Board"
// default:
// description: internal error
// schema:
// "$ref": "#/definitions/ErrorResponse"
if !a.MattermostAuth {
a.errorResponse(w, r, model.NewErrNotImplemented("not permitted in standalone mode"))
return
}
teamID := mux.Vars(r)["teamID"]
term := r.URL.Query().Get("q")
userID := getUserID(r)
if !a.permissions.HasPermissionToTeam(userID, teamID, model.PermissionViewTeam) {
a.errorResponse(w, r, model.NewErrPermission("access denied to team"))
return
}
if len(term) == 0 {
jsonStringResponse(w, http.StatusOK, "[]")
return
}
auditRec := a.makeAuditRecord(r, "searchLinkableBoards", audit.Fail)
defer a.audit.LogRecord(audit.LevelRead, auditRec)
auditRec.AddMeta("teamID", teamID)
// retrieve boards list
boards, err := a.app.SearchBoardsForUserInTeam(teamID, term, userID)
if err != nil {
a.errorResponse(w, r, err)
return
}
linkableBoards := []*model.Board{}
for _, board := range boards {
if a.permissions.HasPermissionToBoard(userID, board.ID, model.PermissionManageBoardRoles) {
linkableBoards = append(linkableBoards, board)
}
}
a.logger.Debug("SearchLinkableBoards",
mlog.String("teamID", teamID),
mlog.Int("boardsCount", len(linkableBoards)),
)
data, err := json.Marshal(linkableBoards)
if err != nil {
a.errorResponse(w, r, err)
return
}
// response
jsonBytesResponse(w, http.StatusOK, data)
auditRec.AddMeta("boardsCount", len(linkableBoards))
auditRec.Success()
}
func (a *API) handleSearchAllBoards(w http.ResponseWriter, r *http.Request) {
// swagger:operation GET /boards/search searchAllBoards
//
// Returns the boards that match with a search term
//
// ---
// produces:
// - application/json
// parameters:
// - name: q
// in: query
// description: The search term. Must have at least one character
// required: true
// type: string
// security:
// - BearerAuth: []
// responses:
// '200':
// description: success
// schema:
// type: array
// items:
// "$ref": "#/definitions/Board"
// default:
// description: internal error
// schema:
// "$ref": "#/definitions/ErrorResponse"
term := r.URL.Query().Get("q")
userID := getUserID(r)
if len(term) == 0 {
jsonStringResponse(w, http.StatusOK, "[]")
return
}
auditRec := a.makeAuditRecord(r, "searchAllBoards", audit.Fail)
defer a.audit.LogRecord(audit.LevelRead, auditRec)
isGuest, err := a.userIsGuest(userID)
if err != nil {
a.errorResponse(w, r, err)
return
}
// retrieve boards list
boards, err := a.app.SearchBoardsForUser(term, model.BoardSearchFieldTitle, userID, !isGuest)
if err != nil {
a.errorResponse(w, r, err)
return
}
a.logger.Debug("SearchAllBoards",
mlog.Int("boardsCount", len(boards)),
)
data, err := json.Marshal(boards)
if err != nil {
a.errorResponse(w, r, err)
return
}
// response
jsonBytesResponse(w, http.StatusOK, data)
auditRec.AddMeta("boardsCount", len(boards))
auditRec.Success()
}