mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2026-02-20 20:15:27 +01:00
@@ -18,7 +18,7 @@ import (
|
|||||||
"github.com/SecurityBrewery/catalyst/storage"
|
"github.com/SecurityBrewery/catalyst/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BackupHandler(catalystStorage *storage.Storage, c *database.Config) http.HandlerFunc {
|
func backupHandler(catalystStorage *storage.Storage, c *database.Config) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Disposition", "attachment; filename=backup.zip")
|
w.Header().Set("Content-Disposition", "attachment; filename=backup.zip")
|
||||||
w.Header().Set("Content-Type", "application/zip")
|
w.Header().Set("Content-Type", "application/zip")
|
||||||
|
|||||||
@@ -190,6 +190,7 @@ func toHTTPErr(err error) error {
|
|||||||
if errors.As(err, &ae) {
|
if errors.As(err, &ae) {
|
||||||
return &api.HTTPError{Status: ae.Code, Internal: err}
|
return &api.HTTPError{Status: ae.Code, Internal: err}
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ func (db *Database) SetReferences(ctx context.Context, id int64, references []*m
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) LinkFiles(ctx context.Context, id int64, files []*model.File) (*model.TicketWithTickets, error) {
|
func (db *Database) AddFile(ctx context.Context, id int64, file *model.File) (*model.TicketWithTickets, error) {
|
||||||
ticketFilterQuery, ticketFilterVars, err := db.Hooks.TicketWriteFilter(ctx)
|
ticketFilterQuery, ticketFilterVars, err := db.Hooks.TicketWriteFilter(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -174,9 +174,9 @@ func (db *Database) LinkFiles(ctx context.Context, id int64, files []*model.File
|
|||||||
|
|
||||||
query := `LET d = DOCUMENT(@@collection, @ID)
|
query := `LET d = DOCUMENT(@@collection, @ID)
|
||||||
` + ticketFilterQuery + `
|
` + ticketFilterQuery + `
|
||||||
UPDATE d WITH { "modified": @now, "files": @files } IN @@collection
|
UPDATE d WITH { "modified": @now, "files": APPEND(NOT_NULL(d.files, []), [@file]) } IN @@collection
|
||||||
RETURN NEW`
|
RETURN NEW`
|
||||||
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{"files": files, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
|
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{"file": file, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
|
||||||
Type: bus.DatabaseEntryUpdated,
|
Type: bus.DatabaseEntryUpdated,
|
||||||
Ids: []driver.DocumentID{
|
Ids: []driver.DocumentID{
|
||||||
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
|
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
|
||||||
|
|||||||
@@ -386,39 +386,6 @@ paths:
|
|||||||
- { id: 8126, created: "2021-10-02T16:04:59.078186Z", modified: "2021-10-02T16:04:59.078186Z", name: "Surfaceintroduce virus detected", owner: "demo", references: [ { href: "http://www.centralworld-class.io/synthesize", name: "university" },{ href: "https://www.futurevirtual.org/supply-chains/markets/sticky/iterate", name: "goal" },{ href: "http://www.chiefsyndicate.io/action-items", name: "unemployment" } ],"schema": "{}", status: "closed", type: "alert" }
|
- { id: 8126, created: "2021-10-02T16:04:59.078186Z", modified: "2021-10-02T16:04:59.078186Z", name: "Surfaceintroduce virus detected", owner: "demo", references: [ { href: "http://www.centralworld-class.io/synthesize", name: "university" },{ href: "https://www.futurevirtual.org/supply-chains/markets/sticky/iterate", name: "goal" },{ href: "http://www.chiefsyndicate.io/action-items", name: "unemployment" } ],"schema": "{}", status: "closed", type: "alert" }
|
||||||
security: [ { roles: [ "ticket:write" ] } ]
|
security: [ { roles: [ "ticket:write" ] } ]
|
||||||
|
|
||||||
/tickets/{id}/files:
|
|
||||||
put:
|
|
||||||
tags: [ "tickets" ]
|
|
||||||
summary: "Link files to an ticket"
|
|
||||||
description: "Link files to an ticket. The files themself will be stored in object storage."
|
|
||||||
operationId: "linkFiles"
|
|
||||||
parameters:
|
|
||||||
- { name: "id", in: "path", description: "Ticket ID", required: true, type: integer, format: "int64", x-example: 8125 }
|
|
||||||
- { name: "files", in: "body", description: "Added files", required: true, schema: { type: array, items: { $ref: "#/definitions/File" } }, x-example: [ { key: myfile, name: "document.doc" } ] }
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: "successful operation"
|
|
||||||
schema: { $ref: "#/definitions/TicketWithTickets" }
|
|
||||||
examples:
|
|
||||||
test:
|
|
||||||
id: 8125
|
|
||||||
created: "2021-10-02T16:04:59.078186Z"
|
|
||||||
modified: "2021-12-12T12:12:12.000000012Z"
|
|
||||||
name: "phishing from selenafadel@von.com detected"
|
|
||||||
owner: "demo"
|
|
||||||
references:
|
|
||||||
- { href: "https://www.seniorleading-edge.name/users/efficient", name: "recovery" }
|
|
||||||
- { href: "http://www.dynamicseamless.com/clicks-and-mortar", name: "force" }
|
|
||||||
- { href: "http://www.leadscalable.biz/envisioneer", name: "fund" }
|
|
||||||
"schema": "{}"
|
|
||||||
status: "closed"
|
|
||||||
type: "alert"
|
|
||||||
files: [ { key: myfile, name: "document.doc" } ]
|
|
||||||
tickets:
|
|
||||||
- { id: 8126, created: "2021-10-02T16:04:59.078186Z", modified: "2021-10-02T16:04:59.078186Z", name: "Surfaceintroduce virus detected", owner: "demo", references: [ { href: "http://www.centralworld-class.io/synthesize", name: "university" },{ href: "https://www.futurevirtual.org/supply-chains/markets/sticky/iterate", name: "goal" },{ href: "http://www.chiefsyndicate.io/action-items", name: "unemployment" } ],"schema": "{}", status: "closed", type: "alert" }
|
|
||||||
|
|
||||||
security: [ { roles: [ "ticket:write" ] } ]
|
|
||||||
|
|
||||||
/tickets/{id}/playbooks:
|
/tickets/{id}/playbooks:
|
||||||
post:
|
post:
|
||||||
tags: [ "tickets" ]
|
tags: [ "tickets" ]
|
||||||
|
|||||||
92
file.go
92
file.go
@@ -1,11 +1,15 @@
|
|||||||
package catalyst
|
package catalyst
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/arangodb/go-driver"
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/service/s3"
|
"github.com/aws/aws-sdk-go/service/s3"
|
||||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||||
@@ -13,11 +17,15 @@ import (
|
|||||||
tusd "github.com/tus/tusd/pkg/handler"
|
tusd "github.com/tus/tusd/pkg/handler"
|
||||||
"github.com/tus/tusd/pkg/s3store"
|
"github.com/tus/tusd/pkg/s3store"
|
||||||
|
|
||||||
|
"github.com/SecurityBrewery/catalyst/bus"
|
||||||
|
"github.com/SecurityBrewery/catalyst/database"
|
||||||
|
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||||
"github.com/SecurityBrewery/catalyst/generated/api"
|
"github.com/SecurityBrewery/catalyst/generated/api"
|
||||||
|
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||||
"github.com/SecurityBrewery/catalyst/storage"
|
"github.com/SecurityBrewery/catalyst/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func upload(client *s3.S3, external string) http.HandlerFunc {
|
func tusdUpload(db *database.Database, bus *bus.Bus, client *s3.S3, external string) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ticketID := chi.URLParam(r, "ticketID")
|
ticketID := chi.URLParam(r, "ticketID")
|
||||||
if ticketID == "" {
|
if ticketID == "" {
|
||||||
@@ -36,14 +44,44 @@ func upload(client *s3.S3, external string) http.HandlerFunc {
|
|||||||
store.UseIn(composer)
|
store.UseIn(composer)
|
||||||
|
|
||||||
handler, err := tusd.NewUnroutedHandler(tusd.Config{
|
handler, err := tusd.NewUnroutedHandler(tusd.Config{
|
||||||
BasePath: external + "/api/files/" + ticketID + "/upload/",
|
BasePath: external + "/api/files/" + ticketID + "/tusd/",
|
||||||
StoreComposer: composer,
|
StoreComposer: composer,
|
||||||
|
NotifyCompleteUploads: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.JSONErrorStatus(w, http.StatusBadRequest, fmt.Errorf("could not create tusd handler: %w", err))
|
api.JSONErrorStatus(w, http.StatusBadRequest, fmt.Errorf("could not create tusd handler: %w", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userID := "unknown"
|
||||||
|
user, ok := busdb.UserFromContext(r.Context())
|
||||||
|
if ok {
|
||||||
|
userID = user.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
event := <-handler.CompleteUploads
|
||||||
|
|
||||||
|
id, err := strconv.ParseInt(ticketID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
file := &model.File{Key: event.Upload.Storage["Key"], Name: event.Upload.MetaData["filename"]}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
doc, err := db.AddFile(ctx, id, file)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bus.PublishRequest(userID, "LinkFiles", []driver.DocumentID{driver.DocumentID(fmt.Sprintf("tickets/%d", doc.ID))})
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodHead:
|
case http.MethodHead:
|
||||||
handler.HeadFile(w, r)
|
handler.HeadFile(w, r)
|
||||||
@@ -54,6 +92,54 @@ func upload(client *s3.S3, external string) http.HandlerFunc {
|
|||||||
default:
|
default:
|
||||||
api.JSONErrorStatus(w, http.StatusInternalServerError, errors.New("unknown method"))
|
api.JSONErrorStatus(w, http.StatusInternalServerError, errors.New("unknown method"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func upload(db *database.Database, client *s3.S3, uploader *s3manager.Uploader) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ticketID := chi.URLParam(r, "ticketID")
|
||||||
|
if ticketID == "" {
|
||||||
|
api.JSONErrorStatus(w, http.StatusBadRequest, errors.New("ticketID not given"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
file, header, err := r.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
api.JSONErrorStatus(w, http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
if err := storage.CreateBucket(client, ticketID); err != nil {
|
||||||
|
api.JSONErrorStatus(w, http.StatusBadRequest, fmt.Errorf("could not create bucket: %w", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = uploader.Upload(&s3manager.UploadInput{
|
||||||
|
Bucket: aws.String("catalyst-" + ticketID),
|
||||||
|
Key: aws.String(header.Filename),
|
||||||
|
Body: file,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
api.JSONErrorStatus(w, http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := strconv.ParseInt(ticketID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
api.JSONErrorStatus(w, http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.AddFile(r.Context(), id, &model.File{
|
||||||
|
Key: header.Filename,
|
||||||
|
Name: header.Filename,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
api.JSONErrorStatus(w, http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ type Service interface {
|
|||||||
RunArtifact(context.Context, int64, string, string) error
|
RunArtifact(context.Context, int64, string, string) error
|
||||||
AddComment(context.Context, int64, *model.CommentForm) (*model.TicketWithTickets, error)
|
AddComment(context.Context, int64, *model.CommentForm) (*model.TicketWithTickets, error)
|
||||||
RemoveComment(context.Context, int64, int) (*model.TicketWithTickets, error)
|
RemoveComment(context.Context, int64, int) (*model.TicketWithTickets, error)
|
||||||
LinkFiles(context.Context, int64, []*model.File) (*model.TicketWithTickets, error)
|
|
||||||
AddTicketPlaybook(context.Context, int64, *model.PlaybookTemplateForm) (*model.TicketWithTickets, error)
|
AddTicketPlaybook(context.Context, int64, *model.PlaybookTemplateForm) (*model.TicketWithTickets, error)
|
||||||
RemoveTicketPlaybook(context.Context, int64, string) (*model.TicketWithTickets, error)
|
RemoveTicketPlaybook(context.Context, int64, string) (*model.TicketWithTickets, error)
|
||||||
SetTask(context.Context, int64, string, string, *model.Task) (*model.TicketWithTickets, error)
|
SetTask(context.Context, int64, string, string, *model.Task) (*model.TicketWithTickets, error)
|
||||||
@@ -139,7 +138,6 @@ func NewServer(service Service, roleAuth func([]string) func(http.Handler) http.
|
|||||||
r.With(roleAuth([]string{"ticket:write"})).Post("/tickets/{id}/artifacts/{name}/run/{automation}", s.runArtifactHandler)
|
r.With(roleAuth([]string{"ticket:write"})).Post("/tickets/{id}/artifacts/{name}/run/{automation}", s.runArtifactHandler)
|
||||||
r.With(roleAuth([]string{"ticket:write"})).Post("/tickets/{id}/comments", s.addCommentHandler)
|
r.With(roleAuth([]string{"ticket:write"})).Post("/tickets/{id}/comments", s.addCommentHandler)
|
||||||
r.With(roleAuth([]string{"ticket:write"})).Delete("/tickets/{id}/comments/{commentID}", s.removeCommentHandler)
|
r.With(roleAuth([]string{"ticket:write"})).Delete("/tickets/{id}/comments/{commentID}", s.removeCommentHandler)
|
||||||
r.With(roleAuth([]string{"ticket:write"})).Put("/tickets/{id}/files", s.linkFilesHandler)
|
|
||||||
r.With(roleAuth([]string{"ticket:write"})).Post("/tickets/{id}/playbooks", s.addTicketPlaybookHandler)
|
r.With(roleAuth([]string{"ticket:write"})).Post("/tickets/{id}/playbooks", s.addTicketPlaybookHandler)
|
||||||
r.With(roleAuth([]string{"ticket:write"})).Delete("/tickets/{id}/playbooks/{playbookID}", s.removeTicketPlaybookHandler)
|
r.With(roleAuth([]string{"ticket:write"})).Delete("/tickets/{id}/playbooks/{playbookID}", s.removeTicketPlaybookHandler)
|
||||||
r.With(roleAuth([]string{"ticket:write"})).Put("/tickets/{id}/playbooks/{playbookID}/task/{taskID}", s.setTaskHandler)
|
r.With(roleAuth([]string{"ticket:write"})).Put("/tickets/{id}/playbooks/{playbookID}/task/{taskID}", s.setTaskHandler)
|
||||||
@@ -642,26 +640,6 @@ func (s *server) removeCommentHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
response(w, result, err)
|
response(w, result, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) linkFilesHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
idP, err := parseURLInt64(r, "id")
|
|
||||||
if err != nil {
|
|
||||||
JSONError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// jl, _ := gojsonschema.NewReaderLoader(r.Body)
|
|
||||||
// []*model.FileSchema.Validate(jl)
|
|
||||||
|
|
||||||
var filesP []*model.File
|
|
||||||
if err := parseBody(r, &filesP); err != nil {
|
|
||||||
JSONError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := s.service.LinkFiles(r.Context(), idP, filesP)
|
|
||||||
response(w, result, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *server) addTicketPlaybookHandler(w http.ResponseWriter, r *http.Request) {
|
func (s *server) addTicketPlaybookHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
idP, err := parseURLInt64(r, "id")
|
idP, err := parseURLInt64(r, "id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -378,15 +378,6 @@ var Tests = []struct {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
Name: "LinkFiles",
|
|
||||||
Args: Args{Method: "Put", URL: "/tickets/8125/files", Data: []interface{}{map[string]interface{}{"key": "myfile", "name": "document.doc"}}},
|
|
||||||
Want: Want{
|
|
||||||
Status: 200,
|
|
||||||
Body: map[string]interface{}{"created": time.Date(2021, time.October, 2, 16, 4, 59, 78186000, time.UTC), "files": []interface{}{map[string]interface{}{"key": "myfile", "name": "document.doc"}}, "id": 8125, "modified": time.Date(2021, time.December, 12, 12, 12, 12, 12, time.UTC), "name": "phishing from selenafadel@von.com detected", "owner": "demo", "references": []interface{}{map[string]interface{}{"href": "https://www.seniorleading-edge.name/users/efficient", "name": "recovery"}, map[string]interface{}{"href": "http://www.dynamicseamless.com/clicks-and-mortar", "name": "force"}, map[string]interface{}{"href": "http://www.leadscalable.biz/envisioneer", "name": "fund"}}, "schema": "{}", "status": "closed", "tickets": []interface{}{map[string]interface{}{"created": time.Date(2021, time.October, 2, 16, 4, 59, 78186000, time.UTC), "id": 8126, "modified": time.Date(2021, time.October, 2, 16, 4, 59, 78186000, time.UTC), "name": "Surfaceintroduce virus detected", "owner": "demo", "references": []interface{}{map[string]interface{}{"href": "http://www.centralworld-class.io/synthesize", "name": "university"}, map[string]interface{}{"href": "https://www.futurevirtual.org/supply-chains/markets/sticky/iterate", "name": "goal"}, map[string]interface{}{"href": "http://www.chiefsyndicate.io/action-items", "name": "unemployment"}}, "schema": "{}", "status": "closed", "type": "alert"}}, "type": "alert"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Name: "AddTicketPlaybook",
|
Name: "AddTicketPlaybook",
|
||||||
Args: Args{Method: "Post", URL: "/tickets/8125/playbooks", Data: map[string]interface{}{"yaml": "name: Simple\ntasks:\n input:\n name: Upload malware if possible\n type: input\n schema:\n title: Malware\n type: object\n properties:\n malware:\n type: string\n title: Select malware\n default: \"\"\n next:\n hash: \"malware != ''\"\n\n hash:\n name: Hash the malware\n type: automation\n automation: hash.sha1\n payload:\n default: \"playbook.tasks['input'].data['malware']\"\n next:\n escalate:\n\n escalate:\n name: Escalate to malware team\n type: task\n"}},
|
Args: Args{Method: "Post", URL: "/tickets/8125/playbooks", Data: map[string]interface{}{"yaml": "name: Simple\ntasks:\n input:\n name: Upload malware if possible\n type: input\n schema:\n title: Malware\n type: object\n properties:\n malware:\n type: string\n title: Select malware\n default: \"\"\n next:\n hash: \"malware != ''\"\n\n hash:\n name: Hash the malware\n type: automation\n automation: hash.sha1\n payload:\n default: \"playbook.tasks['input'].data['malware']\"\n next:\n escalate:\n\n escalate:\n name: Escalate to malware team\n type: task\n"}},
|
||||||
|
|||||||
@@ -3189,101 +3189,6 @@
|
|||||||
"tags" : [ "tickets" ]
|
"tags" : [ "tickets" ]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/tickets/{id}/files" : {
|
|
||||||
"put" : {
|
|
||||||
"description" : "Link files to an ticket. The files themself will be stored in object storage.",
|
|
||||||
"operationId" : "linkFiles",
|
|
||||||
"parameters" : [ {
|
|
||||||
"description" : "Ticket ID",
|
|
||||||
"example" : 8125,
|
|
||||||
"in" : "path",
|
|
||||||
"name" : "id",
|
|
||||||
"required" : true,
|
|
||||||
"schema" : {
|
|
||||||
"format" : "int64",
|
|
||||||
"type" : "integer"
|
|
||||||
}
|
|
||||||
} ],
|
|
||||||
"requestBody" : {
|
|
||||||
"content" : {
|
|
||||||
"application/json" : {
|
|
||||||
"schema" : {
|
|
||||||
"items" : {
|
|
||||||
"$ref" : "#/components/schemas/File"
|
|
||||||
},
|
|
||||||
"type" : "array"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description" : "Added files",
|
|
||||||
"required" : true
|
|
||||||
},
|
|
||||||
"responses" : {
|
|
||||||
"200" : {
|
|
||||||
"content" : {
|
|
||||||
"application/json" : {
|
|
||||||
"schema" : {
|
|
||||||
"$ref" : "#/components/schemas/TicketWithTickets"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"test" : {
|
|
||||||
"example" : {
|
|
||||||
"created" : "2021-10-02T16:04:59.078+0000",
|
|
||||||
"files" : [ {
|
|
||||||
"key" : "myfile",
|
|
||||||
"name" : "document.doc"
|
|
||||||
} ],
|
|
||||||
"id" : 8125,
|
|
||||||
"modified" : "2021-12-12T12:12:12.000+0000",
|
|
||||||
"name" : "phishing from selenafadel@von.com detected",
|
|
||||||
"owner" : "demo",
|
|
||||||
"references" : [ {
|
|
||||||
"href" : "https://www.seniorleading-edge.name/users/efficient",
|
|
||||||
"name" : "recovery"
|
|
||||||
}, {
|
|
||||||
"href" : "http://www.dynamicseamless.com/clicks-and-mortar",
|
|
||||||
"name" : "force"
|
|
||||||
}, {
|
|
||||||
"href" : "http://www.leadscalable.biz/envisioneer",
|
|
||||||
"name" : "fund"
|
|
||||||
} ],
|
|
||||||
"schema" : "{}",
|
|
||||||
"status" : "closed",
|
|
||||||
"tickets" : [ {
|
|
||||||
"created" : "2021-10-02T16:04:59.078+0000",
|
|
||||||
"id" : 8126,
|
|
||||||
"modified" : "2021-10-02T16:04:59.078+0000",
|
|
||||||
"name" : "Surfaceintroduce virus detected",
|
|
||||||
"owner" : "demo",
|
|
||||||
"references" : [ {
|
|
||||||
"href" : "http://www.centralworld-class.io/synthesize",
|
|
||||||
"name" : "university"
|
|
||||||
}, {
|
|
||||||
"href" : "https://www.futurevirtual.org/supply-chains/markets/sticky/iterate",
|
|
||||||
"name" : "goal"
|
|
||||||
}, {
|
|
||||||
"href" : "http://www.chiefsyndicate.io/action-items",
|
|
||||||
"name" : "unemployment"
|
|
||||||
} ],
|
|
||||||
"schema" : "{}",
|
|
||||||
"status" : "closed",
|
|
||||||
"type" : "alert"
|
|
||||||
} ],
|
|
||||||
"type" : "alert"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description" : "successful operation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"security" : [ {
|
|
||||||
"roles" : [ "ticket:write" ]
|
|
||||||
} ],
|
|
||||||
"summary" : "Link files to an ticket",
|
|
||||||
"tags" : [ "tickets" ],
|
|
||||||
"x-codegen-request-body-name" : "files"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/tickets/{id}/playbooks" : {
|
"/tickets/{id}/playbooks" : {
|
||||||
"post" : {
|
"post" : {
|
||||||
"operationId" : "addTicketPlaybook",
|
"operationId" : "addTicketPlaybook",
|
||||||
|
|||||||
@@ -5190,77 +5190,6 @@ paths:
|
|||||||
summary: Remove an comment from an ticket
|
summary: Remove an comment from an ticket
|
||||||
tags:
|
tags:
|
||||||
- tickets
|
- tickets
|
||||||
/tickets/{id}/files:
|
|
||||||
put:
|
|
||||||
description: Link files to an ticket. The files themself will be stored in object
|
|
||||||
storage.
|
|
||||||
operationId: linkFiles
|
|
||||||
parameters:
|
|
||||||
- description: Ticket ID
|
|
||||||
format: int64
|
|
||||||
in: path
|
|
||||||
name: id
|
|
||||||
required: true
|
|
||||||
type: integer
|
|
||||||
x-example: 8125
|
|
||||||
- description: Added files
|
|
||||||
in: body
|
|
||||||
name: files
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/File'
|
|
||||||
type: array
|
|
||||||
x-example:
|
|
||||||
- key: myfile
|
|
||||||
name: document.doc
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: successful operation
|
|
||||||
examples:
|
|
||||||
test:
|
|
||||||
created: 2021-10-02T16:04:59.078186Z
|
|
||||||
files:
|
|
||||||
- key: myfile
|
|
||||||
name: document.doc
|
|
||||||
id: 8125
|
|
||||||
modified: 2021-12-12T12:12:12.000000012Z
|
|
||||||
name: phishing from selenafadel@von.com detected
|
|
||||||
owner: demo
|
|
||||||
references:
|
|
||||||
- href: https://www.seniorleading-edge.name/users/efficient
|
|
||||||
name: recovery
|
|
||||||
- href: http://www.dynamicseamless.com/clicks-and-mortar
|
|
||||||
name: force
|
|
||||||
- href: http://www.leadscalable.biz/envisioneer
|
|
||||||
name: fund
|
|
||||||
schema: '{}'
|
|
||||||
status: closed
|
|
||||||
tickets:
|
|
||||||
- created: 2021-10-02T16:04:59.078186Z
|
|
||||||
id: 8126
|
|
||||||
modified: 2021-10-02T16:04:59.078186Z
|
|
||||||
name: Surfaceintroduce virus detected
|
|
||||||
owner: demo
|
|
||||||
references:
|
|
||||||
- href: http://www.centralworld-class.io/synthesize
|
|
||||||
name: university
|
|
||||||
- href: https://www.futurevirtual.org/supply-chains/markets/sticky/iterate
|
|
||||||
name: goal
|
|
||||||
- href: http://www.chiefsyndicate.io/action-items
|
|
||||||
name: unemployment
|
|
||||||
schema: '{}'
|
|
||||||
status: closed
|
|
||||||
type: alert
|
|
||||||
type: alert
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/TicketWithTickets'
|
|
||||||
security:
|
|
||||||
- roles:
|
|
||||||
- ticket:write
|
|
||||||
summary: Link files to an ticket
|
|
||||||
tags:
|
|
||||||
- tickets
|
|
||||||
/tickets/{id}/playbooks:
|
/tickets/{id}/playbooks:
|
||||||
post:
|
post:
|
||||||
operationId: addTicketPlaybook
|
operationId: addTicketPlaybook
|
||||||
|
|||||||
@@ -2759,101 +2759,6 @@
|
|||||||
"tags" : [ "tickets" ]
|
"tags" : [ "tickets" ]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/tickets/{id}/files" : {
|
|
||||||
"put" : {
|
|
||||||
"description" : "Link files to an ticket. The files themself will be stored in object storage.",
|
|
||||||
"operationId" : "linkFiles",
|
|
||||||
"parameters" : [ {
|
|
||||||
"description" : "Ticket ID",
|
|
||||||
"example" : 8125,
|
|
||||||
"in" : "path",
|
|
||||||
"name" : "id",
|
|
||||||
"required" : true,
|
|
||||||
"schema" : {
|
|
||||||
"format" : "int64",
|
|
||||||
"type" : "integer"
|
|
||||||
}
|
|
||||||
} ],
|
|
||||||
"requestBody" : {
|
|
||||||
"content" : {
|
|
||||||
"application/json" : {
|
|
||||||
"schema" : {
|
|
||||||
"items" : {
|
|
||||||
"$ref" : "#/components/schemas/File"
|
|
||||||
},
|
|
||||||
"type" : "array"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description" : "Added files",
|
|
||||||
"required" : true
|
|
||||||
},
|
|
||||||
"responses" : {
|
|
||||||
"200" : {
|
|
||||||
"content" : {
|
|
||||||
"application/json" : {
|
|
||||||
"schema" : {
|
|
||||||
"$ref" : "#/components/schemas/TicketWithTickets"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"test" : {
|
|
||||||
"example" : {
|
|
||||||
"created" : "2021-10-02T16:04:59.078+0000",
|
|
||||||
"files" : [ {
|
|
||||||
"key" : "myfile",
|
|
||||||
"name" : "document.doc"
|
|
||||||
} ],
|
|
||||||
"id" : 8125,
|
|
||||||
"modified" : "2021-12-12T12:12:12.000+0000",
|
|
||||||
"name" : "phishing from selenafadel@von.com detected",
|
|
||||||
"owner" : "demo",
|
|
||||||
"references" : [ {
|
|
||||||
"href" : "https://www.seniorleading-edge.name/users/efficient",
|
|
||||||
"name" : "recovery"
|
|
||||||
}, {
|
|
||||||
"href" : "http://www.dynamicseamless.com/clicks-and-mortar",
|
|
||||||
"name" : "force"
|
|
||||||
}, {
|
|
||||||
"href" : "http://www.leadscalable.biz/envisioneer",
|
|
||||||
"name" : "fund"
|
|
||||||
} ],
|
|
||||||
"schema" : "{}",
|
|
||||||
"status" : "closed",
|
|
||||||
"tickets" : [ {
|
|
||||||
"created" : "2021-10-02T16:04:59.078+0000",
|
|
||||||
"id" : 8126,
|
|
||||||
"modified" : "2021-10-02T16:04:59.078+0000",
|
|
||||||
"name" : "Surfaceintroduce virus detected",
|
|
||||||
"owner" : "demo",
|
|
||||||
"references" : [ {
|
|
||||||
"href" : "http://www.centralworld-class.io/synthesize",
|
|
||||||
"name" : "university"
|
|
||||||
}, {
|
|
||||||
"href" : "https://www.futurevirtual.org/supply-chains/markets/sticky/iterate",
|
|
||||||
"name" : "goal"
|
|
||||||
}, {
|
|
||||||
"href" : "http://www.chiefsyndicate.io/action-items",
|
|
||||||
"name" : "unemployment"
|
|
||||||
} ],
|
|
||||||
"schema" : "{}",
|
|
||||||
"status" : "closed",
|
|
||||||
"type" : "alert"
|
|
||||||
} ],
|
|
||||||
"type" : "alert"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description" : "successful operation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"security" : [ {
|
|
||||||
"roles" : [ "ticket:write" ]
|
|
||||||
} ],
|
|
||||||
"summary" : "Link files to an ticket",
|
|
||||||
"tags" : [ "tickets" ],
|
|
||||||
"x-codegen-request-body-name" : "files"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/tickets/{id}/playbooks" : {
|
"/tickets/{id}/playbooks" : {
|
||||||
"post" : {
|
"post" : {
|
||||||
"operationId" : "addTicketPlaybook",
|
"operationId" : "addTicketPlaybook",
|
||||||
|
|||||||
@@ -4778,77 +4778,6 @@ paths:
|
|||||||
summary: Remove an comment from an ticket
|
summary: Remove an comment from an ticket
|
||||||
tags:
|
tags:
|
||||||
- tickets
|
- tickets
|
||||||
/tickets/{id}/files:
|
|
||||||
put:
|
|
||||||
description: Link files to an ticket. The files themself will be stored in object
|
|
||||||
storage.
|
|
||||||
operationId: linkFiles
|
|
||||||
parameters:
|
|
||||||
- description: Ticket ID
|
|
||||||
format: int64
|
|
||||||
in: path
|
|
||||||
name: id
|
|
||||||
required: true
|
|
||||||
type: integer
|
|
||||||
x-example: 8125
|
|
||||||
- description: Added files
|
|
||||||
in: body
|
|
||||||
name: files
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/File'
|
|
||||||
type: array
|
|
||||||
x-example:
|
|
||||||
- key: myfile
|
|
||||||
name: document.doc
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: successful operation
|
|
||||||
examples:
|
|
||||||
test:
|
|
||||||
created: 2021-10-02T16:04:59.078186Z
|
|
||||||
files:
|
|
||||||
- key: myfile
|
|
||||||
name: document.doc
|
|
||||||
id: 8125
|
|
||||||
modified: 2021-12-12T12:12:12.000000012Z
|
|
||||||
name: phishing from selenafadel@von.com detected
|
|
||||||
owner: demo
|
|
||||||
references:
|
|
||||||
- href: https://www.seniorleading-edge.name/users/efficient
|
|
||||||
name: recovery
|
|
||||||
- href: http://www.dynamicseamless.com/clicks-and-mortar
|
|
||||||
name: force
|
|
||||||
- href: http://www.leadscalable.biz/envisioneer
|
|
||||||
name: fund
|
|
||||||
schema: '{}'
|
|
||||||
status: closed
|
|
||||||
tickets:
|
|
||||||
- created: 2021-10-02T16:04:59.078186Z
|
|
||||||
id: 8126
|
|
||||||
modified: 2021-10-02T16:04:59.078186Z
|
|
||||||
name: Surfaceintroduce virus detected
|
|
||||||
owner: demo
|
|
||||||
references:
|
|
||||||
- href: http://www.centralworld-class.io/synthesize
|
|
||||||
name: university
|
|
||||||
- href: https://www.futurevirtual.org/supply-chains/markets/sticky/iterate
|
|
||||||
name: goal
|
|
||||||
- href: http://www.chiefsyndicate.io/action-items
|
|
||||||
name: unemployment
|
|
||||||
schema: '{}'
|
|
||||||
status: closed
|
|
||||||
type: alert
|
|
||||||
type: alert
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/TicketWithTickets'
|
|
||||||
security:
|
|
||||||
- roles:
|
|
||||||
- ticket:write
|
|
||||||
summary: Link files to an ticket
|
|
||||||
tags:
|
|
||||||
- tickets
|
|
||||||
/tickets/{id}/playbooks:
|
/tickets/{id}/playbooks:
|
||||||
post:
|
post:
|
||||||
operationId: addTicketPlaybook
|
operationId: addTicketPlaybook
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import (
|
|||||||
"github.com/SecurityBrewery/catalyst/storage"
|
"github.com/SecurityBrewery/catalyst/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RestoreHandler(catalystStorage *storage.Storage, db *database.Database, c *database.Config) http.HandlerFunc {
|
func restoreHandler(catalystStorage *storage.Storage, db *database.Database, c *database.Config) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
uf, header, err := r.FormFile("backup")
|
uf, header, err := r.FormFile("backup")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
15
server.go
15
server.go
@@ -122,13 +122,14 @@ func setupAPI(catalystService *service.Service, catalystStorage *storage.Storage
|
|||||||
allowAll, Authenticate(catalystDatabase, config.Auth), AuthorizeBlockedUser(),
|
allowAll, Authenticate(catalystDatabase, config.Auth), AuthorizeBlockedUser(),
|
||||||
)
|
)
|
||||||
|
|
||||||
apiServer.With(AuthorizeRole([]string{role.FileReadWrite.String()})).Head("/files/:ticketID/upload/:id", upload(catalystStorage.S3(), config.ExternalAddress))
|
apiServer.With(AuthorizeRole([]string{role.FileReadWrite.String()})).Head("/files/{ticketID}/tusd/{id}", tusdUpload(catalystDatabase, bus, catalystStorage.S3(), config.ExternalAddress))
|
||||||
apiServer.With(AuthorizeRole([]string{role.FileReadWrite.String()})).Patch("/files/:ticketID/upload/:id", upload(catalystStorage.S3(), config.ExternalAddress))
|
apiServer.With(AuthorizeRole([]string{role.FileReadWrite.String()})).Patch("/files/{ticketID}/tusd/{id}", tusdUpload(catalystDatabase, bus, catalystStorage.S3(), config.ExternalAddress))
|
||||||
apiServer.With(AuthorizeRole([]string{role.FileReadWrite.String()})).Post("/files/:ticketID/upload", upload(catalystStorage.S3(), config.ExternalAddress))
|
apiServer.With(AuthorizeRole([]string{role.FileReadWrite.String()})).Post("/files/{ticketID}/tusd", tusdUpload(catalystDatabase, bus, catalystStorage.S3(), config.ExternalAddress))
|
||||||
apiServer.With(AuthorizeRole([]string{role.FileReadWrite.String()})).Get("/files/:ticketID/download/:key", download(catalystStorage.Downloader()))
|
apiServer.With(AuthorizeRole([]string{role.FileReadWrite.String()})).Post("/files/{ticketID}/upload", upload(catalystDatabase, catalystStorage.S3(), catalystStorage.Uploader()))
|
||||||
|
apiServer.With(AuthorizeRole([]string{role.FileReadWrite.String()})).Get("/files/{ticketID}/download/{key}", download(catalystStorage.Downloader()))
|
||||||
|
|
||||||
apiServer.With(AuthorizeRole([]string{role.BackupRead.String()})).Get("/backup/create", BackupHandler(catalystStorage, dbConfig))
|
apiServer.With(AuthorizeRole([]string{role.BackupRead.String()})).Get("/backup/create", backupHandler(catalystStorage, dbConfig))
|
||||||
apiServer.With(AuthorizeRole([]string{role.BackupRestore.String()})).Post("/backup/restore", RestoreHandler(catalystStorage, catalystDatabase, dbConfig))
|
apiServer.With(AuthorizeRole([]string{role.BackupRestore.String()})).Post("/backup/restore", restoreHandler(catalystStorage, catalystDatabase, dbConfig))
|
||||||
|
|
||||||
server := chi.NewRouter()
|
server := chi.NewRouter()
|
||||||
server.Use(middleware.RequestID, middleware.RealIP, middleware.Logger, middleware.Recoverer, allowAll)
|
server.Use(middleware.RequestID, middleware.RealIP, middleware.Logger, middleware.Recoverer, allowAll)
|
||||||
@@ -138,7 +139,7 @@ func setupAPI(catalystService *service.Service, catalystStorage *storage.Storage
|
|||||||
server.With(Authenticate(catalystDatabase, config.Auth), AuthorizeBlockedUser()).Handle("/wss", handleWebSocket(bus))
|
server.With(Authenticate(catalystDatabase, config.Auth), AuthorizeBlockedUser()).Handle("/wss", handleWebSocket(bus))
|
||||||
// server.With(Authenticate(catalystDatabase, config.Auth), AuthorizeBlockedUser()).NotFound(static)
|
// server.With(Authenticate(catalystDatabase, config.Auth), AuthorizeBlockedUser()).NotFound(static)
|
||||||
server.NotFound(func(w http.ResponseWriter, r *http.Request) {
|
server.NotFound(func(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Println("not found")
|
log.Println("not found", r.URL.RawPath)
|
||||||
Authenticate(catalystDatabase, config.Auth)(AuthorizeBlockedUser()(http.HandlerFunc(static))).ServeHTTP(w, r)
|
Authenticate(catalystDatabase, config.Auth)(AuthorizeBlockedUser()(http.HandlerFunc(static))).ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -130,11 +130,6 @@ func (s *Service) RemoveComment(ctx context.Context, i int64, i2 int) (doc *mode
|
|||||||
return s.database.RemoveComment(ctx, i, int64(i2))
|
return s.database.RemoveComment(ctx, i, int64(i2))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) LinkFiles(ctx context.Context, i int64, files []*model.File) (doc *model.TicketWithTickets, err error) {
|
|
||||||
defer s.publishRequest(ctx, err, "LinkFiles", ticketWithTicketsID(doc))
|
|
||||||
return s.database.LinkFiles(ctx, i, files)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) AddTicketPlaybook(ctx context.Context, i int64, form *model.PlaybookTemplateForm) (doc *model.TicketWithTickets, err error) {
|
func (s *Service) AddTicketPlaybook(ctx context.Context, i int64, form *model.PlaybookTemplateForm) (doc *model.TicketWithTickets, err error) {
|
||||||
defer s.publishRequest(ctx, err, "AddTicketPlaybook", ticketWithTicketsID(doc))
|
defer s.publishRequest(ctx, err, "AddTicketPlaybook", ticketWithTicketsID(doc))
|
||||||
return s.database.AddTicketPlaybook(ctx, i, form)
|
return s.database.AddTicketPlaybook(ctx, i, form)
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ func createFile(ctx context.Context, server *catalyst.Server) {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := server.DB.LinkFiles(ctx, 8125, []*model.File{{Key: "test.txt", Name: "test.txt"}}); err != nil {
|
if _, err := server.DB.AddFile(ctx, 8125, &model.File{Key: "test.txt", Name: "test.txt"}); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5422,46 +5422,6 @@ export const TicketsApiAxiosParamCreator = function (configuration?: Configurati
|
|||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* Link files to an ticket. The files themself will be stored in object storage.
|
|
||||||
* @summary Link files to an ticket
|
|
||||||
* @param {number} id Ticket ID
|
|
||||||
* @param {Array<any>} files Added files
|
|
||||||
* @param {*} [options] Override http request option.
|
|
||||||
* @throws {RequiredError}
|
|
||||||
*/
|
|
||||||
linkFiles: async (id: number, files: Array<any>, options: any = {}): Promise<RequestArgs> => {
|
|
||||||
// verify required parameter 'id' is not null or undefined
|
|
||||||
assertParamExists('linkFiles', 'id', id)
|
|
||||||
// verify required parameter 'files' is not null or undefined
|
|
||||||
assertParamExists('linkFiles', 'files', files)
|
|
||||||
const localVarPath = `/tickets/{id}/files`
|
|
||||||
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
|
|
||||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
|
||||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
||||||
let baseOptions;
|
|
||||||
if (configuration) {
|
|
||||||
baseOptions = configuration.baseOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options};
|
|
||||||
const localVarHeaderParameter = {} as any;
|
|
||||||
const localVarQueryParameter = {} as any;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
|
||||||
|
|
||||||
setSearchParams(localVarUrlObj, localVarQueryParameter, options.query);
|
|
||||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
|
||||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
|
||||||
localVarRequestOptions.data = serializeDataIfNeeded(files, localVarRequestOptions, configuration)
|
|
||||||
|
|
||||||
return {
|
|
||||||
url: toPathString(localVarUrlObj),
|
|
||||||
options: localVarRequestOptions,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Link an ticket to an ticket
|
* @summary Link an ticket to an ticket
|
||||||
@@ -6141,18 +6101,6 @@ export const TicketsApiFp = function(configuration?: Configuration) {
|
|||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getTicket(id, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.getTicket(id, options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* Link files to an ticket. The files themself will be stored in object storage.
|
|
||||||
* @summary Link files to an ticket
|
|
||||||
* @param {number} id Ticket ID
|
|
||||||
* @param {Array<any>} files Added files
|
|
||||||
* @param {*} [options] Override http request option.
|
|
||||||
* @throws {RequiredError}
|
|
||||||
*/
|
|
||||||
async linkFiles(id: number, files: Array<any>, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<TicketWithTickets>> {
|
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.linkFiles(id, files, options);
|
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Link an ticket to an ticket
|
* @summary Link an ticket to an ticket
|
||||||
@@ -6437,17 +6385,6 @@ export const TicketsApiFactory = function (configuration?: Configuration, basePa
|
|||||||
getTicket(id: number, options?: any): AxiosPromise<TicketWithTickets> {
|
getTicket(id: number, options?: any): AxiosPromise<TicketWithTickets> {
|
||||||
return localVarFp.getTicket(id, options).then((request) => request(axios, basePath));
|
return localVarFp.getTicket(id, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* Link files to an ticket. The files themself will be stored in object storage.
|
|
||||||
* @summary Link files to an ticket
|
|
||||||
* @param {number} id Ticket ID
|
|
||||||
* @param {Array<any>} files Added files
|
|
||||||
* @param {*} [options] Override http request option.
|
|
||||||
* @throws {RequiredError}
|
|
||||||
*/
|
|
||||||
linkFiles(id: number, files: Array<any>, options?: any): AxiosPromise<TicketWithTickets> {
|
|
||||||
return localVarFp.linkFiles(id, files, options).then((request) => request(axios, basePath));
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Link an ticket to an ticket
|
* @summary Link an ticket to an ticket
|
||||||
@@ -6739,19 +6676,6 @@ export class TicketsApi extends BaseAPI {
|
|||||||
return TicketsApiFp(this.configuration).getTicket(id, options).then((request) => request(this.axios, this.basePath));
|
return TicketsApiFp(this.configuration).getTicket(id, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Link files to an ticket. The files themself will be stored in object storage.
|
|
||||||
* @summary Link files to an ticket
|
|
||||||
* @param {number} id Ticket ID
|
|
||||||
* @param {Array<any>} files Added files
|
|
||||||
* @param {*} [options] Override http request option.
|
|
||||||
* @throws {RequiredError}
|
|
||||||
* @memberof TicketsApi
|
|
||||||
*/
|
|
||||||
public linkFiles(id: number, files: Array<any>, options?: any) {
|
|
||||||
return TicketsApiFp(this.configuration).linkFiles(id, files, options).then((request) => request(this.axios, this.basePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Link an ticket to an ticket
|
* @summary Link an ticket to an ticket
|
||||||
|
|||||||
@@ -1425,34 +1425,7 @@ export default Vue.extend({
|
|||||||
setupUppy: function(id: number) {
|
setupUppy: function(id: number) {
|
||||||
let uppy = new Uppy();
|
let uppy = new Uppy();
|
||||||
uppy.use(Tus, {
|
uppy.use(Tus, {
|
||||||
endpoint: location.protocol + '//' + location.hostname + ':'+ location.port + "/api/files/" + id.toString() + "/upload"
|
endpoint: location.protocol + '//' + location.hostname + ':'+ location.port + "/api/files/" + id.toString() + "/tusd"
|
||||||
});
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
uppy.on("upload-success", (file: UppyFile, response: any) => {
|
|
||||||
if (this.ticket !== undefined) {
|
|
||||||
let files: Array<ModelFile> = [];
|
|
||||||
if (this.ticket.files) {
|
|
||||||
files = this.ticket.files;
|
|
||||||
}
|
|
||||||
|
|
||||||
let regex = /\/([^/]*)\+[^/]*$/;
|
|
||||||
let matches = response.uploadURL.match(regex);
|
|
||||||
if (matches.length != 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(matches[1]);
|
|
||||||
files.push({ name: file.name, key: matches[1] });
|
|
||||||
API.linkFiles(id, files)
|
|
||||||
.then(response => {
|
|
||||||
this.$store.dispatch("alertSuccess", { name: "File added" });
|
|
||||||
this.setTicket(response.data);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
this.$store.dispatch("alertError", { name: "File not added", detail: error });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return uppy;
|
return uppy;
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user