Add /search endpoint which redirects to user/job

This commit is contained in:
Lou Knauer 2022-02-09 15:03:12 +01:00
parent 0ca7dbb4f1
commit 27fd3c4e5a
4 changed files with 77 additions and 3 deletions

View File

@ -266,6 +266,11 @@ func (api *RestApi) stopJob(rw http.ResponseWriter, r *http.Request) {
job, err = api.JobRepository.FindById(id) job, err = api.JobRepository.FindById(id)
} else { } else {
if req.JobId == nil || req.Cluster == nil || req.StartTime == nil {
http.Error(rw, "'jobId', 'cluster' and 'startTime' are required", http.StatusBadRequest)
return
}
job, err = api.JobRepository.Find(*req.JobId, *req.Cluster, *req.StartTime) job, err = api.JobRepository.Find(*req.JobId, *req.Cluster, *req.StartTime)
} }

View File

@ -65,6 +65,12 @@ const JOBS_DB_SCHEMA string = `
FOREIGN KEY (tag_id) REFERENCES tag (id) ON DELETE CASCADE); FOREIGN KEY (tag_id) REFERENCES tag (id) ON DELETE CASCADE);
` `
const JOBS_DB_INDEXES string = `
CREATE INDEX job_by_user ON job (user);
CREATE INDEX job_by_starttime ON job (start_time);
CREATE INDEX job_by_job_id ON job (job_id);
`
// Delete the tables "job", "tag" and "jobtag" from the database and // Delete the tables "job", "tag" and "jobtag" from the database and
// repopulate them using the jobs found in `archive`. // repopulate them using the jobs found in `archive`.
func initDB(db *sqlx.DB, archive string) error { func initDB(db *sqlx.DB, archive string) error {
@ -178,9 +184,7 @@ func initDB(db *sqlx.DB, archive string) error {
// Create indexes after inserts so that they do not // Create indexes after inserts so that they do not
// need to be continually updated. // need to be continually updated.
if _, err := db.Exec(` if _, err := db.Exec(JOBS_DB_INDEXES); err != nil {
CREATE INDEX job_by_user ON job (user);
CREATE INDEX job_by_starttime ON job (start_time);`); err != nil {
return err return err
} }

View File

@ -1,6 +1,12 @@
package repository package repository
import ( import (
"context"
"database/sql"
"errors"
"strconv"
"github.com/ClusterCockpit/cc-backend/auth"
"github.com/ClusterCockpit/cc-backend/log" "github.com/ClusterCockpit/cc-backend/log"
"github.com/ClusterCockpit/cc-backend/schema" "github.com/ClusterCockpit/cc-backend/schema"
sq "github.com/Masterminds/squirrel" sq "github.com/Masterminds/squirrel"
@ -141,3 +147,38 @@ func (r *JobRepository) TagId(tagType string, tagName string) (tagId int64, exis
} }
return return
} }
var ErrNotFound = errors.New("no such job or user")
// FindJobOrUser returns a job database ID or a username if a job or user machtes the search term.
// As 0 is a valid job id, check if username is "" instead in order to check what machted.
// If nothing matches the search, `ErrNotFound` is returned.
func (r *JobRepository) FindJobOrUser(ctx context.Context, searchterm string) (job int64, username string, err error) {
user := auth.GetUser(ctx)
if id, err := strconv.Atoi(searchterm); err == nil {
qb := sq.Select("job.id").From("job").Where("job.job_id = ?", id)
if user != nil && !user.HasRole(auth.RoleAdmin) {
qb = qb.Where("job.user = ?", user.Username)
}
err := qb.RunWith(r.DB).QueryRow().Scan(&job)
if err != nil && err != sql.ErrNoRows {
return 0, "", err
} else if err == nil {
return job, "", nil
}
}
if user == nil || user.HasRole(auth.RoleAdmin) {
err := sq.Select("job.user").Distinct().From("job").
Where("job.user = ?", searchterm).
RunWith(r.DB).QueryRow().Scan(&username)
if err != nil && err != sql.ErrNoRows {
return 0, "", err
} else if err == nil {
return 0, username, nil
}
}
return 0, "", ErrNotFound
}

View File

@ -10,6 +10,7 @@ import (
"io" "io"
"net" "net"
"net/http" "net/http"
"net/url"
"os" "os"
"os/signal" "os/signal"
"strings" "strings"
@ -375,6 +376,29 @@ func main() {
}) })
}) })
secured.HandleFunc("/search", func(rw http.ResponseWriter, r *http.Request) {
if search := r.URL.Query().Get("searchId"); search != "" {
job, username, err := api.JobRepository.FindJobOrUser(r.Context(), search)
if err == repository.ErrNotFound {
http.Redirect(rw, r, "/monitoring/jobs/?jobId="+url.QueryEscape(search), http.StatusTemporaryRedirect)
return
} else if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
if username != "" {
http.Redirect(rw, r, "/monitoring/user/"+username, http.StatusTemporaryRedirect)
return
} else {
http.Redirect(rw, r, fmt.Sprintf("/monitoring/job/%d", job), http.StatusTemporaryRedirect)
return
}
} else {
http.Error(rw, "'searchId' query parameter missing", http.StatusBadRequest)
}
})
setupRoutes(secured, routes) setupRoutes(secured, routes)
api.MountRoutes(secured) api.MountRoutes(secured)