mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2025-04-29 14:41:43 +02:00
add api calls for removing tags, initial branch commit
This commit is contained in:
parent
f343fa0071
commit
9bcf7adb67
@ -750,6 +750,122 @@ func (api *RestApi) tagJob(rw http.ResponseWriter, r *http.Request) {
|
||||
json.NewEncoder(rw).Encode(job)
|
||||
}
|
||||
|
||||
// removeTagJob godoc
|
||||
// @summary Removes one or more tags from a job
|
||||
// @tags Job add and modify
|
||||
// @description Removes tag(s) from a job specified by DB ID. Name and Type of Tag(s) must match.
|
||||
// @description Tag Scope is required for matching, options: "global", "admin". Private tags can not be deleted via API.
|
||||
// @description If tagged job is already finished: Tag will be removed from respective archive files.
|
||||
// @accept json
|
||||
// @produce json
|
||||
// @param id path int true "Job Database ID"
|
||||
// @param request body api.TagJobApiRequest true "Array of tag-objects to remove"
|
||||
// @success 200 {object} schema.Job "Updated job resource"
|
||||
// @failure 400 {object} api.ErrorResponse "Bad Request"
|
||||
// @failure 401 {object} api.ErrorResponse "Unauthorized"
|
||||
// @failure 404 {object} api.ErrorResponse "Job or tag does not exist"
|
||||
// @failure 500 {object} api.ErrorResponse "Internal Server Error"
|
||||
// @security ApiKeyAuth
|
||||
// @router /jobs/tag_job/{id} [delete]
|
||||
func (api *RestApi) removeTagJob(rw http.ResponseWriter, r *http.Request) {
|
||||
id, err := strconv.ParseInt(mux.Vars(r)["id"], 10, 64)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
job, err := api.JobRepository.FindById(r.Context(), id)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
job.Tags, err = api.JobRepository.GetTags(repository.GetUserFromContext(r.Context()), &job.ID)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var req TagJobApiRequest
|
||||
if err := decode(r.Body, &req); err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
for _, rtag := range req {
|
||||
// Only Global and Admin Tags
|
||||
if rtag.Scope != "global" && rtag.Scope != "admin" {
|
||||
log.Warnf("Cannot delete private tag for job %d: Skip", job.JobID)
|
||||
continue
|
||||
}
|
||||
|
||||
remainingTags, err := api.JobRepository.RemoveJobTagByRequest(repository.GetUserFromContext(r.Context()), job.ID, rtag.Type, rtag.Name, rtag.Scope)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// remainingTags := job.Tags[:0]
|
||||
// for _, tag := range job.Tags {
|
||||
// if tag.Type != rtag.Type &&
|
||||
// tag.Name != rtag.Name &&
|
||||
// tag.Scope != rtag.Scope {
|
||||
// remainingTags = append(remainingTags, tag)
|
||||
// }
|
||||
// }
|
||||
job.Tags = remainingTags
|
||||
}
|
||||
|
||||
rw.Header().Add("Content-Type", "application/json")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(rw).Encode(job)
|
||||
}
|
||||
|
||||
// removeTags godoc
|
||||
// @summary Removes all tags and job-relations for type:name tuple
|
||||
// @tags Tag remove
|
||||
// @description Removes tags by type and name. Name and Type of Tag(s) must match.
|
||||
// @description Tag Scope is required for matching, options: "global", "admin". Private tags can not be deleted via API.
|
||||
// @description Tag wills be removed from respective archive files.
|
||||
// @accept json
|
||||
// @produce plain
|
||||
// @param request body api.TagJobApiRequest true "Array of tag-objects to remove"
|
||||
// @success 200 {string} string "Success Response"
|
||||
// @failure 400 {object} api.ErrorResponse "Bad Request"
|
||||
// @failure 401 {object} api.ErrorResponse "Unauthorized"
|
||||
// @failure 404 {object} api.ErrorResponse "Job or tag does not exist"
|
||||
// @failure 500 {object} api.ErrorResponse "Internal Server Error"
|
||||
// @security ApiKeyAuth
|
||||
// @router /jobs/tag_job/ [delete]
|
||||
func (api *RestApi) removeTags(rw http.ResponseWriter, r *http.Request) {
|
||||
var req TagJobApiRequest
|
||||
if err := decode(r.Body, &req); err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
targetCount := len(req)
|
||||
currentCount := 0
|
||||
for _, rtag := range req {
|
||||
// Only Global and Admin Tags
|
||||
if rtag.Scope != "global" && rtag.Scope != "admin" {
|
||||
log.Warn("Cannot delete private tag: Skip")
|
||||
continue
|
||||
}
|
||||
|
||||
err := api.JobRepository.RemoveTagByRequest(rtag.Type, rtag.Name, rtag.Scope)
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
} else {
|
||||
currentCount++
|
||||
}
|
||||
}
|
||||
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
rw.Write([]byte(fmt.Sprintf("Deleted Tags from DB: %d of %d", currentCount, targetCount)))
|
||||
}
|
||||
|
||||
// startJob godoc
|
||||
// @summary Adds a new job as "running"
|
||||
// @tags Job add and modify
|
||||
|
@ -45,7 +45,7 @@ func (r *JobRepository) AddTag(user *schema.User, job int64, tag int64) ([]*sche
|
||||
return tags, archive.UpdateTags(j, archiveTags)
|
||||
}
|
||||
|
||||
// Removes a tag from a job
|
||||
// Removes a tag from a job by its ID
|
||||
func (r *JobRepository) RemoveTag(user *schema.User, job, tag int64) ([]*schema.Tag, error) {
|
||||
j, err := r.FindByIdWithUser(user, job)
|
||||
if err != nil {
|
||||
@ -76,6 +76,76 @@ func (r *JobRepository) RemoveTag(user *schema.User, job, tag int64) ([]*schema.
|
||||
return tags, archive.UpdateTags(j, archiveTags)
|
||||
}
|
||||
|
||||
// Removes a tag from a job by tag info
|
||||
func (r *JobRepository) RemoveJobTagByRequest(user *schema.User, job int64, tagType string, tagName string, tagScope string) ([]*schema.Tag, error) {
|
||||
// Get Tag ID to delete
|
||||
tagID, err := r.loadTagIDByInfo(tagName, tagType, tagScope)
|
||||
if err != nil {
|
||||
log.Warn("Error while finding tagId with: %s, %s, %s", tagName, tagType, tagScope)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get Job
|
||||
j, err := r.FindByIdWithUser(user, job)
|
||||
if err != nil {
|
||||
log.Warn("Error while finding job by id")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Handle Delete
|
||||
q := sq.Delete("jobtag").Where("jobtag.job_id = ?", job).Where("jobtag.tag_id = ?", tagID)
|
||||
|
||||
if _, err := q.RunWith(r.stmtCache).Exec(); err != nil {
|
||||
s, _, _ := q.ToSql()
|
||||
log.Errorf("Error removing tag from table 'jobTag' with %s: %v", s, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tags, err := r.GetTags(user, &job)
|
||||
if err != nil {
|
||||
log.Warn("Error while getting tags for job")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
archiveTags, err := r.getArchiveTags(&job)
|
||||
if err != nil {
|
||||
log.Warn("Error while getting tags for job")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tags, archive.UpdateTags(j, archiveTags)
|
||||
}
|
||||
|
||||
// Removes a tag from db by tag info
|
||||
func (r *JobRepository) RemoveTagByRequest(tagType string, tagName string, tagScope string) error {
|
||||
// Get Tag ID to delete
|
||||
tagID, err := r.loadTagIDByInfo(tagName, tagType, tagScope)
|
||||
if err != nil {
|
||||
log.Warn("Error while finding tagId with: %s, %s, %s", tagName, tagType, tagScope)
|
||||
return err
|
||||
}
|
||||
|
||||
// Handle Delete JobTagTable
|
||||
qJobTag := sq.Delete("jobtag").Where("jobtag.tag_id = ?", tagID)
|
||||
|
||||
if _, err := qJobTag.RunWith(r.stmtCache).Exec(); err != nil {
|
||||
s, _, _ := qJobTag.ToSql()
|
||||
log.Errorf("Error removing tag from table 'jobTag' with %s: %v", s, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Handle Delete TagTable
|
||||
qTag := sq.Delete("tag").Where("tag.id = ?", tagID)
|
||||
|
||||
if _, err := qTag.RunWith(r.stmtCache).Exec(); err != nil {
|
||||
s, _, _ := qTag.ToSql()
|
||||
log.Errorf("Error removing tag from table 'tag' with %s: %v", s, err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateTag creates a new tag with the specified type and name and returns its database id.
|
||||
func (r *JobRepository) CreateTag(tagType string, tagName string, tagScope string) (tagId int64, err error) {
|
||||
// Default to "Global" scope if none defined
|
||||
@ -325,3 +395,29 @@ func (r *JobRepository) checkScopeAuth(user *schema.User, operation string, scop
|
||||
return false, fmt.Errorf("error while checking tag operation auth: no user in context")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *JobRepository) loadTagIDByInfo(tagType string, tagName string, tagScope string) (tagID int64, err error) {
|
||||
// Get Tag ID to delete
|
||||
getq := sq.Select("id").From("tag").
|
||||
Where("tag_type = ?", tagType).
|
||||
Where("tag_name = ?", tagName).
|
||||
Where("tag_scope = ?", tagScope)
|
||||
|
||||
rows, err := getq.RunWith(r.stmtCache).Query()
|
||||
if err != nil {
|
||||
s, _, _ := getq.ToSql()
|
||||
log.Errorf("Error get tags for delete with %s: %v", s, err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
dbTags := make([]*schema.Tag, 0)
|
||||
for rows.Next() {
|
||||
dbTag := &schema.Tag{}
|
||||
if err := rows.Scan(&dbTag.ID); err != nil {
|
||||
log.Warn("Error while scanning rows")
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return dbTags[0].ID, nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user