mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2024-12-25 12:59:06 +01:00
Move /search code to routerConfig, add simple docs for searchbar
This commit is contained in:
parent
1873c6a87d
commit
641affbbdf
@ -13,7 +13,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -297,66 +296,7 @@ func main() {
|
|||||||
|
|
||||||
// Send a searchId and then reply with a redirect to a user, or directly send query to job table for jobid and project.
|
// Send a searchId and then reply with a redirect to a user, or directly send query to job table for jobid and project.
|
||||||
secured.HandleFunc("/search", func(rw http.ResponseWriter, r *http.Request) {
|
secured.HandleFunc("/search", func(rw http.ResponseWriter, r *http.Request) {
|
||||||
if search := r.URL.Query().Get("searchId"); search != "" {
|
routerConfig.HandleSearchBar(rw, r, api)
|
||||||
splitSearch := strings.Split(search, ":")
|
|
||||||
|
|
||||||
if (len(splitSearch) == 2) {
|
|
||||||
switch strings.Trim(splitSearch[0], " ") {
|
|
||||||
case "jobId":
|
|
||||||
http.Redirect(rw, r, "/monitoring/jobs/?jobId="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusTemporaryRedirect) // All Users: Redirect to Tablequery
|
|
||||||
return
|
|
||||||
case "jobName":
|
|
||||||
http.Redirect(rw, r, "/monitoring/jobs/?jobName="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusTemporaryRedirect) // All Users: Redirect to Tablequery
|
|
||||||
return
|
|
||||||
case "projectId":
|
|
||||||
project, _ := api.JobRepository.FindProject(r.Context(), strings.Trim(splitSearch[1], " ")) // Restricted: projectId
|
|
||||||
if project != "" {
|
|
||||||
http.Redirect(rw, r, "/monitoring/jobs/?projectMatch=eq&project="+url.QueryEscape(project), http.StatusTemporaryRedirect)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
http.Redirect(rw, r, "/monitoring/jobs/?jobId=NotFound", http.StatusTemporaryRedirect) // Workaround to display correctly empty table
|
|
||||||
}
|
|
||||||
case "username":
|
|
||||||
username, _ := api.JobRepository.FindUser(r.Context(), strings.Trim(splitSearch[1], " ")) // Restricted: username
|
|
||||||
if username != "" {
|
|
||||||
http.Redirect(rw, r, "/monitoring/user/"+username, http.StatusTemporaryRedirect)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
http.Redirect(rw, r, "/monitoring/jobs/?jobId=NotFound", http.StatusTemporaryRedirect) // Workaround to display correctly empty table
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
http.Error(rw, "'searchId' type parameter unknown", http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (len(splitSearch) == 1) {
|
|
||||||
jobname, username, project, err := api.JobRepository.FindJobnameOrUserOrProject(r.Context(), strings.Trim(search, " ")) // Determine Access within
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if username != "" {
|
|
||||||
http.Redirect(rw, r, "/monitoring/user/"+username, http.StatusTemporaryRedirect) // User: Redirect to user page
|
|
||||||
return
|
|
||||||
} else if (project != "") {
|
|
||||||
http.Redirect(rw, r, "/monitoring/jobs/?projectMatch=eq&project="+url.QueryEscape(strings.Trim(search, " ")), http.StatusTemporaryRedirect) // projectId (equal)
|
|
||||||
return
|
|
||||||
} else if (jobname != "") {
|
|
||||||
http.Redirect(rw, r, "/monitoring/jobs/?jobName="+url.QueryEscape(strings.Trim(search, " ")), http.StatusTemporaryRedirect) // JobName (contains)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
http.Redirect(rw, r, "/monitoring/jobs/?jobId="+url.QueryEscape(strings.Trim(search, " ")), http.StatusTemporaryRedirect) // No Result: Probably jobId
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
http.Error(rw, "'searchId' query parameter malformed", http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
http.Redirect(rw, r, "/monitoring/jobs/?", http.StatusTemporaryRedirect)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Mount all /monitoring/... and /api/... routes.
|
// Mount all /monitoring/... and /api/... routes.
|
||||||
|
24
docs/searchbar.md
Normal file
24
docs/searchbar.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
## Docs for ClusterCockpit Searchbar
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
* Searchtags are implemented as `type:<query>` search-string
|
||||||
|
* Types `jobId, jobName, projectId, username` for roles `admin` and `support`
|
||||||
|
* Types `jobId, jobName` for role `user`
|
||||||
|
* Examples:
|
||||||
|
* `jobName:myJob12`
|
||||||
|
* `jobId:123456`
|
||||||
|
* `username:abcd100`
|
||||||
|
* If no searchTag used: Best guess search with the following hierarchy
|
||||||
|
* `jobId -> username -> projectId -> jobName`
|
||||||
|
* Simple HTML Error if ...
|
||||||
|
* Best guess search fails -> 'Not Found'
|
||||||
|
* Query `type` is unknown
|
||||||
|
* More than two colons in string -> 'malformed'
|
||||||
|
* Spaces trimmed (both for searchTag and queryString)
|
||||||
|
* ` job12` == `job12`
|
||||||
|
* `projectID : abcd ` == `projectId:abcd`
|
||||||
|
* jobId-Query now redirects to table
|
||||||
|
* Allows multiple jobs from different systems, but with identical job-id to be found
|
||||||
|
* jobName-Query works with a part of the jobName-String (e.g. jobName:myjob for jobName myjob_cluster1)
|
||||||
|
* JobName GQL Query is resolved as matching the query as a part of the whole metaData-JSON in the SQL DB.
|
@ -13,6 +13,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ClusterCockpit/cc-backend/internal/auth"
|
"github.com/ClusterCockpit/cc-backend/internal/auth"
|
||||||
|
"github.com/ClusterCockpit/cc-backend/internal/api"
|
||||||
"github.com/ClusterCockpit/cc-backend/internal/graph"
|
"github.com/ClusterCockpit/cc-backend/internal/graph"
|
||||||
"github.com/ClusterCockpit/cc-backend/internal/graph/model"
|
"github.com/ClusterCockpit/cc-backend/internal/graph/model"
|
||||||
"github.com/ClusterCockpit/cc-backend/internal/repository"
|
"github.com/ClusterCockpit/cc-backend/internal/repository"
|
||||||
@ -297,3 +298,66 @@ func SetupRoutes(router *mux.Router, version string, hash string, buildTime stri
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HandleSearchBar(rw http.ResponseWriter, r *http.Request, api *api.RestApi) {
|
||||||
|
if search := r.URL.Query().Get("searchId"); search != "" {
|
||||||
|
splitSearch := strings.Split(search, ":")
|
||||||
|
|
||||||
|
if (len(splitSearch) == 2) {
|
||||||
|
switch strings.Trim(splitSearch[0], " ") {
|
||||||
|
case "jobId":
|
||||||
|
http.Redirect(rw, r, "/monitoring/jobs/?jobId="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusTemporaryRedirect) // All Users: Redirect to Tablequery
|
||||||
|
return
|
||||||
|
case "jobName":
|
||||||
|
http.Redirect(rw, r, "/monitoring/jobs/?jobName="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusTemporaryRedirect) // All Users: Redirect to Tablequery
|
||||||
|
return
|
||||||
|
case "projectId":
|
||||||
|
project, _ := api.JobRepository.FindProject(r.Context(), strings.Trim(splitSearch[1], " ")) // Restricted: projectId
|
||||||
|
if project != "" {
|
||||||
|
http.Redirect(rw, r, "/monitoring/jobs/?projectMatch=eq&project="+url.QueryEscape(project), http.StatusTemporaryRedirect)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
http.Redirect(rw, r, "/monitoring/jobs/?jobId=NotFound", http.StatusTemporaryRedirect) // Workaround to display correctly empty table
|
||||||
|
}
|
||||||
|
case "username":
|
||||||
|
username, _ := api.JobRepository.FindUser(r.Context(), strings.Trim(splitSearch[1], " ")) // Restricted: username
|
||||||
|
if username != "" {
|
||||||
|
http.Redirect(rw, r, "/monitoring/user/"+username, http.StatusTemporaryRedirect)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
http.Redirect(rw, r, "/monitoring/jobs/?jobId=NotFound", http.StatusTemporaryRedirect) // Workaround to display correctly empty table
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
http.Error(rw, "'searchId' type parameter unknown", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (len(splitSearch) == 1) {
|
||||||
|
jobname, username, project, err := api.JobRepository.FindJobnameOrUserOrProject(r.Context(), strings.Trim(search, " ")) // Determine Access within
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if username != "" {
|
||||||
|
http.Redirect(rw, r, "/monitoring/user/"+username, http.StatusTemporaryRedirect) // User: Redirect to user page
|
||||||
|
return
|
||||||
|
} else if (project != "") {
|
||||||
|
http.Redirect(rw, r, "/monitoring/jobs/?projectMatch=eq&project="+url.QueryEscape(strings.Trim(search, " ")), http.StatusTemporaryRedirect) // projectId (equal)
|
||||||
|
return
|
||||||
|
} else if (jobname != "") {
|
||||||
|
http.Redirect(rw, r, "/monitoring/jobs/?jobName="+url.QueryEscape(strings.Trim(search, " ")), http.StatusTemporaryRedirect) // JobName (contains)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
http.Redirect(rw, r, "/monitoring/jobs/?jobId="+url.QueryEscape(strings.Trim(search, " ")), http.StatusTemporaryRedirect) // No Result: Probably jobId
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
http.Error(rw, "'searchId' query parameter malformed", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
http.Redirect(rw, r, "/monitoring/jobs/?", http.StatusTemporaryRedirect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user