diff --git a/db/interface.go b/db/interface.go index cb4b6cf06..62509bcda 100644 --- a/db/interface.go +++ b/db/interface.go @@ -194,4 +194,8 @@ type Database interface { DeleteProcessingMapByKey(processType, processKey string) error DeleteProcessingMap(id uint) error ProcessReversePayments(paymentId uint) error + CreateOrEditTicket(ticket *Tickets) (Tickets, error) + GetTicket(uuid string) (Tickets, error) + UpdateTicket(ticket Tickets) (Tickets, error) + DeleteTicket(uuid string) error } diff --git a/db/structs.go b/db/structs.go index 4a2b2bb3d..300758092 100644 --- a/db/structs.go +++ b/db/structs.go @@ -7,6 +7,7 @@ import ( "errors" "time" + "github.com/google/uuid" "github.com/gorilla/websocket" "github.com/lib/pq" "gorm.io/gorm" @@ -952,7 +953,7 @@ const ( ) type Tickets struct { - UUID string `gorm:"primaryKey;type:uuid;default:gen_random_uuid()"` + UUID uuid.UUID `gorm:"primaryKey;type:uuid;default:gen_random_uuid()"` FeatureUUID string `gorm:"type:uuid;not null;index:composite_index" json:"feature_uuid" validate:"required"` Features WorkspaceFeatures `gorm:"foreignKey:FeatureUUID;references:Uuid"` PhaseUUID string `gorm:"type:uuid;not null;index:phase_index" json:"phase_uuid" validate:"required"` diff --git a/db/tickets.go b/db/tickets.go index d5e97b838..2d0375483 100644 --- a/db/tickets.go +++ b/db/tickets.go @@ -4,11 +4,14 @@ import ( "errors" "fmt" "time" + + "github.com/google/uuid" + "gorm.io/gorm" ) func (db database) CreateOrEditTicket(ticket *Tickets) (Tickets, error) { - if ticket.UUID == "" || ticket.FeatureUUID == "" || ticket.PhaseUUID == "" || ticket.Name == "" { + if ticket.UUID == uuid.Nil || ticket.FeatureUUID == "" || ticket.PhaseUUID == "" || ticket.Name == "" { return Tickets{}, errors.New("required fields are missing") } @@ -43,8 +46,57 @@ func (db database) GetTicket(uuid string) (Tickets, error) { } if results.RowsAffected == 0 { - return Tickets{}, fmt.Errorf("failed to get ticket: %w", results.Error) + return Tickets{}, fmt.Errorf("ticket not found") } return ticket, nil } + +func (db database) UpdateTicket(ticket Tickets) (Tickets, error) { + if ticket.UUID == uuid.Nil { + return Tickets{}, errors.New("ticket UUID is required") + } + + if ticket.FeatureUUID == "" || ticket.PhaseUUID == "" || ticket.Name == "" { + return Tickets{}, errors.New("feature_uuid, phase_uuid, and name are required") + } + + var existingTicket Tickets + result := db.db.Where("uuid = ?", ticket.UUID).First(&existingTicket) + + now := time.Now() + ticket.UpdatedAt = now + + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + ticket.CreatedAt = now + if err := db.db.Create(&ticket).Error; err != nil { + return Tickets{}, fmt.Errorf("failed to create ticket: %w", err) + } + return ticket, nil + } + return Tickets{}, fmt.Errorf("database error: %w", result.Error) + } + + if err := db.db.Model(&existingTicket).Updates(ticket).Error; err != nil { + return Tickets{}, fmt.Errorf("failed to update ticket: %w", err) + } + + var updatedTicket Tickets + if err := db.db.Where("uuid = ?", ticket.UUID).First(&updatedTicket).Error; err != nil { + return Tickets{}, fmt.Errorf("failed to fetch updated ticket: %w", err) + } + + return updatedTicket, nil +} + +func (db database) DeleteTicket(uuid string) error { + result := db.db.Where("uuid = ?", uuid).Delete(&Tickets{}) + if result.Error != nil { + return fmt.Errorf("failed to delete ticket: %w", result.Error) + } + if result.RowsAffected == 0 { + return errors.New("ticket not found") + } + return nil +} diff --git a/db/tickets_test.go b/db/tickets_test.go index 30e912b93..90e9aaa73 100644 --- a/db/tickets_test.go +++ b/db/tickets_test.go @@ -56,7 +56,7 @@ func TestCreateOrEditTicket(t *testing.T) { } ticket := Tickets{ - UUID: uuid.New().String(), + UUID: uuid.New(), FeatureUUID: workspaceFeatures.Uuid, PhaseUUID: featurePhase.Uuid, Name: "test ticket", @@ -79,7 +79,7 @@ func TestCreateOrEditTicket(t *testing.T) { // test that an error is returned if the required fields are missing t.Run("test that an error is returned if the required fields are missing", func(t *testing.T) { ticket := Tickets{ - UUID: uuid.New().String(), + UUID: uuid.New(), FeatureUUID: "", PhaseUUID: "", Name: "test ticket", @@ -96,7 +96,7 @@ func TestCreateOrEditTicket(t *testing.T) { // test that an error is thrown if the FeatureUUID, and PhaseUUID does not exists t.Run("test that an error is returned if the required fields are missing", func(t *testing.T) { ticket := Tickets{ - UUID: uuid.New().String(), + UUID: uuid.New(), FeatureUUID: "testfeatureuuid", PhaseUUID: "testphaseuuid", Name: "test ticket", @@ -180,7 +180,7 @@ func TestGetTicket(t *testing.T) { TestDB.CreateOrEditFeaturePhase(featurePhase) ticket := Tickets{ - UUID: uuid.New().String(), + UUID: uuid.New(), FeatureUUID: workspaceFeatures.Uuid, PhaseUUID: featurePhase.Uuid, Name: "test get ticket", @@ -201,7 +201,7 @@ func TestGetTicket(t *testing.T) { // should return a ticket if it exists t.Run("should return a ticket if it exists", func(t *testing.T) { - result, err := TestDB.GetTicket(ticket.UUID) + result, err := TestDB.GetTicket(ticket.UUID.String()) if err != nil { t.Errorf("expected no error but got %v", err) } diff --git a/db/workflow_db.go b/db/workflow.go similarity index 100% rename from db/workflow_db.go rename to db/workflow.go diff --git a/handlers/ticket.go b/handlers/ticket.go new file mode 100644 index 000000000..64ade8ea2 --- /dev/null +++ b/handlers/ticket.go @@ -0,0 +1,108 @@ +package handlers + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/go-chi/chi" + "github.com/google/uuid" + "github.com/stakwork/sphinx-tribes/db" +) + +type ticketHandler struct { + db db.Database +} + +func NewTicketHandler(database db.Database) *ticketHandler { + return &ticketHandler{ + db: database, + } +} + +func (th *ticketHandler) GetTicket(w http.ResponseWriter, r *http.Request) { + uuid := chi.URLParam(r, "uuid") + if uuid == "" { + http.Error(w, "UUID is required", http.StatusBadRequest) + return + } + + ticket, err := th.db.GetTicket(uuid) + if err != nil { + if err.Error() == "ticket not found" { + http.Error(w, "Ticket not found", http.StatusNotFound) + return + } + http.Error(w, fmt.Sprintf("Failed to get ticket: %v", err), http.StatusInternalServerError) + return + } + + respondWithJSON(w, http.StatusOK, ticket) +} + +func (th *ticketHandler) UpdateTicket(w http.ResponseWriter, r *http.Request) { + uuidStr := chi.URLParam(r, "uuid") + if uuidStr == "" { + http.Error(w, "UUID is required", http.StatusBadRequest) + return + } + + ticketUUID, err := uuid.Parse(uuidStr) + if err != nil { + http.Error(w, "Invalid UUID format", http.StatusBadRequest) + return + } + + body, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "Error reading request body", http.StatusBadRequest) + return + } + + var ticket db.Tickets + if err := json.Unmarshal(body, &ticket); err != nil { + http.Error(w, "Error parsing request body", http.StatusBadRequest) + return + } + + ticket.UUID = ticketUUID + + updatedTicket, err := th.db.UpdateTicket(ticket) + if err != nil { + if err.Error() == "feature_uuid, phase_uuid, and name are required" { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + http.Error(w, fmt.Sprintf("Failed to update ticket: %v", err), http.StatusInternalServerError) + return + } + + respondWithJSON(w, http.StatusOK, updatedTicket) +} + +func (th *ticketHandler) DeleteTicket(w http.ResponseWriter, r *http.Request) { + uuid := chi.URLParam(r, "uuid") + if uuid == "" { + http.Error(w, "UUID is required", http.StatusBadRequest) + return + } + + err := th.db.DeleteTicket(uuid) + if err != nil { + if err.Error() == "ticket not found" { + http.Error(w, "Ticket not found", http.StatusNotFound) + return + } + http.Error(w, fmt.Sprintf("Failed to delete ticket: %v", err), http.StatusInternalServerError) + return + } + + respondWithJSON(w, http.StatusOK, map[string]string{"status": "success"}) +} + +func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + json.NewEncoder(w).Encode(payload) +} diff --git a/handlers/ticket_test.go b/handlers/ticket_test.go new file mode 100644 index 000000000..e4d83d656 --- /dev/null +++ b/handlers/ticket_test.go @@ -0,0 +1,388 @@ +package handlers + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/go-chi/chi" + "github.com/google/uuid" + "github.com/stakwork/sphinx-tribes/db" + "github.com/stretchr/testify/assert" +) + +func TestGetTicket(t *testing.T) { + teardownSuite := SetupSuite(t) + defer teardownSuite(t) + + tHandler := NewTicketHandler(db.TestDB) + + person := db.Person{ + Uuid: uuid.New().String(), + OwnerAlias: "test-alias", + UniqueName: "test-unique-name", + OwnerPubKey: "test-pubkey", + PriceToMeet: 0, + Description: "test-description", + } + db.TestDB.CreateOrEditPerson(person) + + workspace := db.Workspace{ + Uuid: uuid.New().String(), + Name: "test-workspace" + uuid.New().String(), + OwnerPubKey: person.OwnerPubKey, + Github: "https://github.com/test", + Website: "https://www.testwebsite.com", + Description: "test-description", + } + db.TestDB.CreateOrEditWorkspace(workspace) + + feature := db.WorkspaceFeatures{ + Uuid: uuid.New().String(), + WorkspaceUuid: workspace.Uuid, + Name: "test-feature", + Url: "https://github.com/test-feature", + Priority: 0, + } + db.TestDB.CreateOrEditFeature(feature) + + featurePhase := db.FeaturePhase{ + Uuid: uuid.New().String(), + FeatureUuid: feature.Uuid, + Name: "test-phase", + Priority: 0, + } + db.TestDB.CreateOrEditFeaturePhase(featurePhase) + + ticket := db.Tickets{ + UUID: uuid.New(), + FeatureUUID: feature.Uuid, + PhaseUUID: featurePhase.Uuid, + Name: "Test Ticket", + Sequence: 1, + Description: "Test Description", + Status: db.DraftTicket, + } + createdTicket, _ := db.TestDB.UpdateTicket(ticket) + + t.Run("should return 400 if UUID is empty", func(t *testing.T) { + rr := httptest.NewRecorder() + handler := http.HandlerFunc(tHandler.GetTicket) + + req, err := http.NewRequest(http.MethodGet, "/tickets/", nil) + if err != nil { + t.Fatal(err) + } + + handler.ServeHTTP(rr, req) + assert.Equal(t, http.StatusBadRequest, rr.Code) + }) + + t.Run("should return 404 if ticket doesn't exist", func(t *testing.T) { + rr := httptest.NewRecorder() + handler := http.HandlerFunc(tHandler.GetTicket) + + nonExistentUUID := uuid.New() + rctx := chi.NewRouteContext() + rctx.URLParams.Add("uuid", nonExistentUUID.String()) + req, err := http.NewRequest(http.MethodGet, "/tickets/"+nonExistentUUID.String(), nil) + if err != nil { + t.Fatal(err) + } + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + + handler.ServeHTTP(rr, req) + assert.Equal(t, http.StatusNotFound, rr.Code) + }) + + t.Run("should return ticket if exists", func(t *testing.T) { + rr := httptest.NewRecorder() + handler := http.HandlerFunc(tHandler.GetTicket) + + rctx := chi.NewRouteContext() + rctx.URLParams.Add("uuid", createdTicket.UUID.String()) + req, err := http.NewRequest(http.MethodGet, "/tickets/"+createdTicket.UUID.String(), nil) + if err != nil { + t.Fatal(err) + } + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code) + + var returnedTicket db.Tickets + err = json.Unmarshal(rr.Body.Bytes(), &returnedTicket) + assert.NoError(t, err) + assert.Equal(t, createdTicket.Name, returnedTicket.Name) + assert.Equal(t, createdTicket.Description, returnedTicket.Description) + assert.Equal(t, createdTicket.Status, returnedTicket.Status) + assert.Equal(t, createdTicket.FeatureUUID, returnedTicket.FeatureUUID) + assert.Equal(t, createdTicket.PhaseUUID, returnedTicket.PhaseUUID) + }) +} + +func TestUpdateTicket(t *testing.T) { + teardownSuite := SetupSuite(t) + defer teardownSuite(t) + + tHandler := NewTicketHandler(db.TestDB) + + person := db.Person{ + Uuid: uuid.New().String(), + OwnerAlias: "test-alias", + UniqueName: "test-unique-name", + OwnerPubKey: "test-pubkey", + PriceToMeet: 0, + Description: "test-description", + } + db.TestDB.CreateOrEditPerson(person) + + workspace := db.Workspace{ + Uuid: uuid.New().String(), + Name: "test-workspace" + uuid.New().String(), + OwnerPubKey: person.OwnerPubKey, + Github: "https://github.com/test", + Website: "https://www.testwebsite.com", + Description: "test-description", + } + db.TestDB.CreateOrEditWorkspace(workspace) + + feature := db.WorkspaceFeatures{ + Uuid: uuid.New().String(), + WorkspaceUuid: workspace.Uuid, + Name: "test-feature", + Url: "https://github.com/test-feature", + Priority: 0, + } + db.TestDB.CreateOrEditFeature(feature) + + featurePhase := db.FeaturePhase{ + Uuid: uuid.New().String(), + FeatureUuid: feature.Uuid, + Name: "test-phase", + Priority: 0, + } + db.TestDB.CreateOrEditFeaturePhase(featurePhase) + + ticket := db.Tickets{ + UUID: uuid.New(), + FeatureUUID: feature.Uuid, + PhaseUUID: featurePhase.Uuid, + Name: "Test Ticket", + Sequence: 1, + Description: "Test Description", + Status: db.DraftTicket, + } + createdTicket, _ := db.TestDB.UpdateTicket(ticket) + + t.Run("should return 400 if UUID is empty", func(t *testing.T) { + rr := httptest.NewRecorder() + handler := http.HandlerFunc(tHandler.UpdateTicket) + + req, err := http.NewRequest(http.MethodPut, "/tickets/", nil) + if err != nil { + t.Fatal(err) + } + + handler.ServeHTTP(rr, req) + assert.Equal(t, http.StatusBadRequest, rr.Code) + }) + + t.Run("should return 400 if UUID is invalid", func(t *testing.T) { + rr := httptest.NewRecorder() + handler := http.HandlerFunc(tHandler.UpdateTicket) + + rctx := chi.NewRouteContext() + rctx.URLParams.Add("uuid", "invalid-uuid") + req, err := http.NewRequest(http.MethodPut, "/tickets/invalid-uuid", bytes.NewReader([]byte("{}"))) + if err != nil { + t.Fatal(err) + } + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + + handler.ServeHTTP(rr, req) + assert.Equal(t, http.StatusBadRequest, rr.Code) + }) + + t.Run("should return 400 if body is not valid json", func(t *testing.T) { + rr := httptest.NewRecorder() + handler := http.HandlerFunc(tHandler.UpdateTicket) + + invalidJson := []byte(`{"key": "value"`) + rctx := chi.NewRouteContext() + rctx.URLParams.Add("uuid", createdTicket.UUID.String()) + req, err := http.NewRequest(http.MethodPut, "/tickets/"+createdTicket.UUID.String(), bytes.NewReader(invalidJson)) + if err != nil { + t.Fatal(err) + } + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + + handler.ServeHTTP(rr, req) + assert.Equal(t, http.StatusBadRequest, rr.Code) + }) + + t.Run("should return 400 if required fields are missing", func(t *testing.T) { + rr := httptest.NewRecorder() + handler := http.HandlerFunc(tHandler.UpdateTicket) + + invalidTicket := db.Tickets{ + UUID: uuid.New(), + // Missing required fields + } + + requestBody, _ := json.Marshal(invalidTicket) + rctx := chi.NewRouteContext() + rctx.URLParams.Add("uuid", invalidTicket.UUID.String()) + req, err := http.NewRequest(http.MethodPut, "/tickets/"+invalidTicket.UUID.String(), bytes.NewReader(requestBody)) + if err != nil { + t.Fatal(err) + } + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + + handler.ServeHTTP(rr, req) + assert.Equal(t, http.StatusBadRequest, rr.Code) + }) + + t.Run("should update ticket successfully", func(t *testing.T) { + rr := httptest.NewRecorder() + handler := http.HandlerFunc(tHandler.UpdateTicket) + + updatedTicket := createdTicket + updatedTicket.Name = "Updated Test Ticket" + updatedTicket.Description = "Updated Description" + updatedTicket.Status = db.CompletedTicket + + requestBody, _ := json.Marshal(updatedTicket) + rctx := chi.NewRouteContext() + rctx.URLParams.Add("uuid", createdTicket.UUID.String()) + req, err := http.NewRequest(http.MethodPut, "/tickets/"+createdTicket.UUID.String(), bytes.NewReader(requestBody)) + if err != nil { + t.Fatal(err) + } + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code) + + var returnedTicket db.Tickets + err = json.Unmarshal(rr.Body.Bytes(), &returnedTicket) + assert.NoError(t, err) + assert.Equal(t, updatedTicket.Name, returnedTicket.Name) + assert.Equal(t, updatedTicket.Description, returnedTicket.Description) + assert.Equal(t, updatedTicket.Status, returnedTicket.Status) + assert.Equal(t, updatedTicket.FeatureUUID, returnedTicket.FeatureUUID) + assert.Equal(t, updatedTicket.PhaseUUID, returnedTicket.PhaseUUID) + }) +} + +func TestDeleteTicket(t *testing.T) { + teardownSuite := SetupSuite(t) + defer teardownSuite(t) + + tHandler := NewTicketHandler(db.TestDB) + + person := db.Person{ + Uuid: uuid.New().String(), + OwnerAlias: "test-alias", + UniqueName: "test-unique-name", + OwnerPubKey: "test-pubkey", + PriceToMeet: 0, + Description: "test-description", + } + db.TestDB.CreateOrEditPerson(person) + + workspace := db.Workspace{ + Uuid: uuid.New().String(), + Name: "test-workspace" + uuid.New().String(), + OwnerPubKey: person.OwnerPubKey, + Github: "https://github.com/test", + Website: "https://www.testwebsite.com", + Description: "test-description", + } + db.TestDB.CreateOrEditWorkspace(workspace) + + feature := db.WorkspaceFeatures{ + Uuid: uuid.New().String(), + WorkspaceUuid: workspace.Uuid, + Name: "test-feature", + Url: "https://github.com/test-feature", + Priority: 0, + } + db.TestDB.CreateOrEditFeature(feature) + + featurePhase := db.FeaturePhase{ + Uuid: uuid.New().String(), + FeatureUuid: feature.Uuid, + Name: "test-phase", + Priority: 0, + } + db.TestDB.CreateOrEditFeaturePhase(featurePhase) + + ticket := db.Tickets{ + UUID: uuid.New(), + FeatureUUID: feature.Uuid, + PhaseUUID: featurePhase.Uuid, + Name: "Test Ticket", + Sequence: 1, + Description: "Test Description", + Status: db.DraftTicket, + } + createdTicket, _ := db.TestDB.UpdateTicket(ticket) + + t.Run("should return 400 if UUID is empty", func(t *testing.T) { + rr := httptest.NewRecorder() + handler := http.HandlerFunc(tHandler.DeleteTicket) + + req, err := http.NewRequest(http.MethodDelete, "/tickets/", nil) + if err != nil { + t.Fatal(err) + } + + handler.ServeHTTP(rr, req) + assert.Equal(t, http.StatusBadRequest, rr.Code) + }) + + t.Run("should return 404 if ticket doesn't exist", func(t *testing.T) { + rr := httptest.NewRecorder() + handler := http.HandlerFunc(tHandler.DeleteTicket) + + nonExistentUUID := uuid.New() + rctx := chi.NewRouteContext() + rctx.URLParams.Add("uuid", nonExistentUUID.String()) + req, err := http.NewRequest(http.MethodDelete, "/tickets/"+nonExistentUUID.String(), nil) + if err != nil { + t.Fatal(err) + } + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + + handler.ServeHTTP(rr, req) + assert.Equal(t, http.StatusNotFound, rr.Code) + }) + + t.Run("should delete ticket successfully", func(t *testing.T) { + rr := httptest.NewRecorder() + handler := http.HandlerFunc(tHandler.DeleteTicket) + + rctx := chi.NewRouteContext() + rctx.URLParams.Add("uuid", createdTicket.UUID.String()) + req, err := http.NewRequest(http.MethodDelete, "/tickets/"+createdTicket.UUID.String(), nil) + if err != nil { + t.Fatal(err) + } + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code) + + // Verify ticket was deleted + _, err = db.TestDB.GetTicket(createdTicket.UUID.String()) + assert.Error(t, err) + assert.Equal(t, "ticket not found", err.Error()) + }) +} diff --git a/mocks/Database.go b/mocks/Database.go index 0f9b36ccf..94be903ce 100644 --- a/mocks/Database.go +++ b/mocks/Database.go @@ -1154,6 +1154,62 @@ func (_c *Database_CreateOrEditPerson_Call) RunAndReturn(run func(db.Person) (db return _c } +// CreateOrEditTicket provides a mock function with given fields: ticket +func (_m *Database) CreateOrEditTicket(ticket *db.Tickets) (db.Tickets, error) { + ret := _m.Called(ticket) + + if len(ret) == 0 { + panic("no return value specified for CreateOrEditTicket") + } + + var r0 db.Tickets + var r1 error + if rf, ok := ret.Get(0).(func(*db.Tickets) (db.Tickets, error)); ok { + return rf(ticket) + } + if rf, ok := ret.Get(0).(func(*db.Tickets) db.Tickets); ok { + r0 = rf(ticket) + } else { + r0 = ret.Get(0).(db.Tickets) + } + + if rf, ok := ret.Get(1).(func(*db.Tickets) error); ok { + r1 = rf(ticket) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Database_CreateOrEditTicket_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateOrEditTicket' +type Database_CreateOrEditTicket_Call struct { + *mock.Call +} + +// CreateOrEditTicket is a helper method to define mock.On call +// - ticket *db.Tickets +func (_e *Database_Expecter) CreateOrEditTicket(ticket interface{}) *Database_CreateOrEditTicket_Call { + return &Database_CreateOrEditTicket_Call{Call: _e.mock.On("CreateOrEditTicket", ticket)} +} + +func (_c *Database_CreateOrEditTicket_Call) Run(run func(ticket *db.Tickets)) *Database_CreateOrEditTicket_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*db.Tickets)) + }) + return _c +} + +func (_c *Database_CreateOrEditTicket_Call) Return(_a0 db.Tickets, _a1 error) *Database_CreateOrEditTicket_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Database_CreateOrEditTicket_Call) RunAndReturn(run func(*db.Tickets) (db.Tickets, error)) *Database_CreateOrEditTicket_Call { + _c.Call.Return(run) + return _c +} + // CreateOrEditTribe provides a mock function with given fields: m func (_m *Database) CreateOrEditTribe(m db.Tribe) (db.Tribe, error) { ret := _m.Called(m) @@ -1891,6 +1947,99 @@ func (_c *Database_DeleteProcessingMap_Call) RunAndReturn(run func(uint) error) return _c } +// DeleteProcessingMapByKey provides a mock function with given fields: processType, processKey +func (_m *Database) DeleteProcessingMapByKey(processType string, processKey string) error { + ret := _m.Called(processType, processKey) + + if len(ret) == 0 { + panic("no return value specified for DeleteProcessingMapByKey") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string, string) error); ok { + r0 = rf(processType, processKey) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Database_DeleteProcessingMapByKey_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteProcessingMapByKey' +type Database_DeleteProcessingMapByKey_Call struct { + *mock.Call +} + +// DeleteProcessingMapByKey is a helper method to define mock.On call +// - processType string +// - processKey string +func (_e *Database_Expecter) DeleteProcessingMapByKey(processType interface{}, processKey interface{}) *Database_DeleteProcessingMapByKey_Call { + return &Database_DeleteProcessingMapByKey_Call{Call: _e.mock.On("DeleteProcessingMapByKey", processType, processKey)} +} + +func (_c *Database_DeleteProcessingMapByKey_Call) Run(run func(processType string, processKey string)) *Database_DeleteProcessingMapByKey_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *Database_DeleteProcessingMapByKey_Call) Return(_a0 error) *Database_DeleteProcessingMapByKey_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Database_DeleteProcessingMapByKey_Call) RunAndReturn(run func(string, string) error) *Database_DeleteProcessingMapByKey_Call { + _c.Call.Return(run) + return _c +} + +// DeleteTicket provides a mock function with given fields: uuid +func (_m *Database) DeleteTicket(uuid string) error { + ret := _m.Called(uuid) + + if len(ret) == 0 { + panic("no return value specified for DeleteTicket") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(uuid) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Database_DeleteTicket_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteTicket' +type Database_DeleteTicket_Call struct { + *mock.Call +} + +// DeleteTicket is a helper method to define mock.On call +// - uuid string +func (_e *Database_Expecter) DeleteTicket(uuid interface{}) *Database_DeleteTicket_Call { + return &Database_DeleteTicket_Call{Call: _e.mock.On("DeleteTicket", uuid)} +} + +func (_c *Database_DeleteTicket_Call) Run(run func(uuid string)) *Database_DeleteTicket_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *Database_DeleteTicket_Call) Return(_a0 error) *Database_DeleteTicket_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Database_DeleteTicket_Call) RunAndReturn(run func(string) error) *Database_DeleteTicket_Call { + _c.Call.Return(run) + return _c +} + // DeleteUserInvoiceData provides a mock function with given fields: payment_request func (_m *Database) DeleteUserInvoiceData(payment_request string) db.UserInvoiceData { ret := _m.Called(payment_request) @@ -5384,6 +5533,62 @@ func (_c *Database_GetSumOfWithdrawal_Call) RunAndReturn(run func(string) uint) return _c } +// GetTicket provides a mock function with given fields: uuid +func (_m *Database) GetTicket(uuid string) (db.Tickets, error) { + ret := _m.Called(uuid) + + if len(ret) == 0 { + panic("no return value specified for GetTicket") + } + + var r0 db.Tickets + var r1 error + if rf, ok := ret.Get(0).(func(string) (db.Tickets, error)); ok { + return rf(uuid) + } + if rf, ok := ret.Get(0).(func(string) db.Tickets); ok { + r0 = rf(uuid) + } else { + r0 = ret.Get(0).(db.Tickets) + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(uuid) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Database_GetTicket_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTicket' +type Database_GetTicket_Call struct { + *mock.Call +} + +// GetTicket is a helper method to define mock.On call +// - uuid string +func (_e *Database_Expecter) GetTicket(uuid interface{}) *Database_GetTicket_Call { + return &Database_GetTicket_Call{Call: _e.mock.On("GetTicket", uuid)} +} + +func (_c *Database_GetTicket_Call) Run(run func(uuid string)) *Database_GetTicket_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *Database_GetTicket_Call) Return(_a0 db.Tickets, _a1 error) *Database_GetTicket_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Database_GetTicket_Call) RunAndReturn(run func(string) (db.Tickets, error)) *Database_GetTicket_Call { + _c.Call.Return(run) + return _c +} + // GetTribe provides a mock function with given fields: uuid func (_m *Database) GetTribe(uuid string) db.Tribe { ret := _m.Called(uuid) @@ -8735,6 +8940,62 @@ func (_c *Database_UpdateProcessingMap_Call) RunAndReturn(run func(*db.WfProcess return _c } +// UpdateTicket provides a mock function with given fields: ticket +func (_m *Database) UpdateTicket(ticket db.Tickets) (db.Tickets, error) { + ret := _m.Called(ticket) + + if len(ret) == 0 { + panic("no return value specified for UpdateTicket") + } + + var r0 db.Tickets + var r1 error + if rf, ok := ret.Get(0).(func(db.Tickets) (db.Tickets, error)); ok { + return rf(ticket) + } + if rf, ok := ret.Get(0).(func(db.Tickets) db.Tickets); ok { + r0 = rf(ticket) + } else { + r0 = ret.Get(0).(db.Tickets) + } + + if rf, ok := ret.Get(1).(func(db.Tickets) error); ok { + r1 = rf(ticket) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Database_UpdateTicket_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateTicket' +type Database_UpdateTicket_Call struct { + *mock.Call +} + +// UpdateTicket is a helper method to define mock.On call +// - ticket db.Tickets +func (_e *Database_Expecter) UpdateTicket(ticket interface{}) *Database_UpdateTicket_Call { + return &Database_UpdateTicket_Call{Call: _e.mock.On("UpdateTicket", ticket)} +} + +func (_c *Database_UpdateTicket_Call) Run(run func(ticket db.Tickets)) *Database_UpdateTicket_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(db.Tickets)) + }) + return _c +} + +func (_c *Database_UpdateTicket_Call) Return(_a0 db.Tickets, _a1 error) *Database_UpdateTicket_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Database_UpdateTicket_Call) RunAndReturn(run func(db.Tickets) (db.Tickets, error)) *Database_UpdateTicket_Call { + _c.Call.Return(run) + return _c +} + // UpdateTribe provides a mock function with given fields: uuid, u func (_m *Database) UpdateTribe(uuid string, u map[string]interface{}) bool { ret := _m.Called(uuid, u) @@ -8922,14 +9183,14 @@ type Database_UpdateWorkflowRequestStatusAndResponse_Call struct { // UpdateWorkflowRequestStatusAndResponse is a helper method to define mock.On call // - requestID string // - status db.WfRequestStatus -// - responseData db.JSONB +// - responseData db.PropertyMap func (_e *Database_Expecter) UpdateWorkflowRequestStatusAndResponse(requestID interface{}, status interface{}, responseData interface{}) *Database_UpdateWorkflowRequestStatusAndResponse_Call { return &Database_UpdateWorkflowRequestStatusAndResponse_Call{Call: _e.mock.On("UpdateWorkflowRequestStatusAndResponse", requestID, status, responseData)} } -func (_c *Database_UpdateWorkflowRequestStatusAndResponse_Call) Run(run func(requestID string, status db.WfRequestStatus, responseData db.JSONB)) *Database_UpdateWorkflowRequestStatusAndResponse_Call { +func (_c *Database_UpdateWorkflowRequestStatusAndResponse_Call) Run(run func(requestID string, status db.WfRequestStatus, responseData db.PropertyMap)) *Database_UpdateWorkflowRequestStatusAndResponse_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(db.WfRequestStatus), args[2].(db.JSONB)) + run(args[0].(string), args[1].(db.WfRequestStatus), args[2].(db.PropertyMap)) }) return _c } @@ -8939,7 +9200,7 @@ func (_c *Database_UpdateWorkflowRequestStatusAndResponse_Call) Return(_a0 error return _c } -func (_c *Database_UpdateWorkflowRequestStatusAndResponse_Call) RunAndReturn(run func(string, db.WfRequestStatus, db.JSONB) error) *Database_UpdateWorkflowRequestStatusAndResponse_Call { +func (_c *Database_UpdateWorkflowRequestStatusAndResponse_Call) RunAndReturn(run func(string, db.WfRequestStatus, db.PropertyMap) error) *Database_UpdateWorkflowRequestStatusAndResponse_Call { _c.Call.Return(run) return _c } @@ -8990,45 +9251,6 @@ func (_c *Database_UpdateWorkspaceBudget_Call) RunAndReturn(run func(db.NewBount return _c } -// DeleteProcessingMapByKey provides a mock function with given fields: processType, processKey -func (_m *Database) DeleteProcessingMapByKey(processType string, processKey string) error { - ret := _m.Called(processType, processKey) - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(processType, processKey) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -type Database_DeleteProcessingMapByKey_Call struct { - *mock.Call -} - -func (_e *Database_Expecter) DeleteProcessingMapByKey(processType interface{}, processKey interface{}) *Database_DeleteProcessingMapByKey_Call { - return &Database_DeleteProcessingMapByKey_Call{Call: _e.mock.On("DeleteProcessingMapByKey", processType, processKey)} -} - -func (_c *Database_DeleteProcessingMapByKey_Call) Run(run func(processType string, processKey string)) *Database_DeleteProcessingMapByKey_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *Database_DeleteProcessingMapByKey_Call) Return(_a0 error) *Database_DeleteProcessingMapByKey_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *Database_DeleteProcessingMapByKey_Call) RunAndReturn(run func(string, string) error) *Database_DeleteProcessingMapByKey_Call { - _c.Call.Return(run) - return _c -} - // UpdateWorkspaceForDeletion provides a mock function with given fields: uuid func (_m *Database) UpdateWorkspaceForDeletion(uuid string) error { ret := _m.Called(uuid) diff --git a/routes/index.go b/routes/index.go index fab5a9783..53837a90b 100644 --- a/routes/index.go +++ b/routes/index.go @@ -38,6 +38,7 @@ func NewRouter() *http.Server { r.Mount("/metrics", MetricsRoutes()) r.Mount("/features", FeatureRoutes()) r.Mount("/workflows", WorkflowRoutes()) + r.Mount("/bounty/ticket", TicketRoutes()) r.Group(func(r chi.Router) { r.Get("/tribe_by_feed", tribeHandlers.GetFirstTribeByFeed) diff --git a/routes/ticket_routes.go b/routes/ticket_routes.go new file mode 100644 index 000000000..0fee7bef4 --- /dev/null +++ b/routes/ticket_routes.go @@ -0,0 +1,23 @@ +package routes + +import ( + "github.com/go-chi/chi" + "github.com/stakwork/sphinx-tribes/auth" + "github.com/stakwork/sphinx-tribes/db" + "github.com/stakwork/sphinx-tribes/handlers" +) + +func TicketRoutes() chi.Router { + r := chi.NewRouter() + ticketHandler := handlers.NewTicketHandler(db.DB) + + r.Group(func(r chi.Router) { + r.Use(auth.PubKeyContext) + + r.Get("/{uuid}", ticketHandler.GetTicket) + r.Put("/{uuid}", ticketHandler.UpdateTicket) + r.Delete("/{uuid}", ticketHandler.DeleteTicket) + }) + + return r +}