mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2024-12-26 13:29:05 +01:00
Add /search endpoint which redirects to user/job
This commit is contained in:
parent
0ca7dbb4f1
commit
27fd3c4e5a
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
init-db.go
10
init-db.go
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
24
server.go
24
server.go
@ -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)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user