diff --git a/cypress/e2e/03_features.cy.ts b/cypress/e2e/03_features.cy.ts index dd2c66424..10e56a834 100644 --- a/cypress/e2e/03_features.cy.ts +++ b/cypress/e2e/03_features.cy.ts @@ -1,11 +1,11 @@ -import { User, HostName, Workspaces, Repositories, Features } from '../support/objects/objects'; +import { User, HostName, Features } from '../support/objects/objects'; describe('Create Features for Workspace', () => { it('passes', () => { cy.upsertlogin(User).then(value => { - for(let i = 0; i <= 2; i++) { + for (let i = 0; i <= 2; i++) { cy.request({ method: 'POST', url: `${HostName}/features`, @@ -25,7 +25,7 @@ describe('Create Features for Workspace', () => { describe('Modify name for Feature', () => { it('passes', () => { cy.upsertlogin(User).then(value => { - for(let i = 0; i <= 2; i++) { + for (let i = 0; i <= 2; i++) { cy.request({ method: 'POST', url: `${HostName}/features`, @@ -48,7 +48,7 @@ describe('Modify name for Feature', () => { describe('Modify brief for Feature', () => { it('passes', () => { cy.upsertlogin(User).then(value => { - for(let i = 0; i <= 2; i++) { + for (let i = 0; i <= 2; i++) { cy.request({ method: 'POST', url: `${HostName}/features`, @@ -71,7 +71,7 @@ describe('Modify brief for Feature', () => { describe('Modify requirements for Feature', () => { it('passes', () => { cy.upsertlogin(User).then(value => { - for(let i = 0; i <= 2; i++) { + for (let i = 0; i <= 2; i++) { cy.request({ method: 'POST', url: `${HostName}/features`, @@ -94,7 +94,7 @@ describe('Modify requirements for Feature', () => { describe('Modify architecture for Feature', () => { it('passes', () => { cy.upsertlogin(User).then(value => { - for(let i = 0; i <= 2; i++) { + for (let i = 0; i <= 2; i++) { cy.request({ method: 'POST', url: `${HostName}/features`, @@ -121,17 +121,18 @@ describe('Get Features for Workspace', () => { cy.request({ method: 'GET', url: `${HostName}/features/forworkspace/` + Features[0].workspace_uuid, - headers: { 'x-jwt': `${ value }` }, - body: {} + headers: { 'x-jwt': `${value}` }, + body: {} }).then((resp) => { - expect(resp.status).to.eq(200) - for(let i = 0; i <= 2; i++) { - expect(resp.body[i]).to.have.property('name', Features[i].name.trim() + " _addtext") - expect(resp.body[i]).to.have.property('brief', Features[i].brief.trim() + " _addtext") - expect(resp.body[i]).to.have.property('requirements', Features[i].requirements.trim() + " _addtext") - expect(resp.body[i]).to.have.property('architecture', Features[i].architecture.trim() + " _addtext") + expect(resp.status).to.eq(200); + const body = resp.body.reverse(); + for (let i = 0; i <= 2; i++) { + expect(body[i]).to.have.property('name', Features[i].name.trim() + " _addtext") + expect(body[i]).to.have.property('brief', Features[i].brief.trim() + " _addtext") + expect(body[i]).to.have.property('requirements', Features[i].requirements.trim() + " _addtext") + expect(body[i]).to.have.property('architecture', Features[i].architecture.trim() + " _addtext") } - }) + }); }) }) }) @@ -139,12 +140,12 @@ describe('Get Features for Workspace', () => { describe('Get Feature by uuid', () => { it('passes', () => { cy.upsertlogin(User).then(value => { - for(let i = 0; i <= 2; i++) { + for (let i = 0; i <= 2; i++) { cy.request({ method: 'GET', url: `${HostName}/features/` + Features[i].uuid, - headers: { 'x-jwt': `${ value }` }, - body: {} + headers: { 'x-jwt': `${value}` }, + body: {} }).then((resp) => { expect(resp.status).to.eq(200) expect(resp.body).to.have.property('name', Features[i].name.trim() + " _addtext") diff --git a/cypress/e2e/04_user_stories.cy.ts b/cypress/e2e/04_user_stories.cy.ts new file mode 100644 index 000000000..3bca14d24 --- /dev/null +++ b/cypress/e2e/04_user_stories.cy.ts @@ -0,0 +1,117 @@ +import { User, HostName, UserStories } from '../support/objects/objects'; + +describe('Create user stories for Feature', () => { + it('passes', () => { + cy.upsertlogin(User).then(value => { + for (let i = 0; i <= 5; i++) { + cy.request({ + method: 'POST', + url: `${HostName}/features/story`, + headers: { 'x-jwt': `${value}` }, + body: UserStories[i] + }).its('body').then(body => { + expect(body).to.have.property('uuid').and.equal(UserStories[i].uuid.trim()); + expect(body).to.have.property('feature_uuid').and.equal(UserStories[i].feature_uuid.trim()); + expect(body).to.have.property('description').and.equal(UserStories[i].description.trim()); + expect(body).to.have.property('priority').and.equal(UserStories[i].priority); + }); + } + }) + }) +}) + +describe('Modify user story description', () => { + it('passes', () => { + cy.upsertlogin(User).then(value => { + for (let i = 0; i <= 5; i++) { + cy.request({ + method: 'POST', + url: `${HostName}/features/story`, + headers: { 'x-jwt': `${value}` }, + body: { + uuid: UserStories[i].uuid, + description: UserStories[i].description + "_addtext" + } + }).its('body').then(body => { + expect(body).to.have.property('uuid').and.equal(UserStories[i].uuid.trim()); + expect(body).to.have.property('feature_uuid').and.equal(UserStories[i].feature_uuid.trim()); + expect(body).to.have.property('description').and.equal(UserStories[i].description.trim() + " _addtext"); + expect(body).to.have.property('priority').and.equal(UserStories[i].priority); + }); + } + }) + }) +}) + +describe('Get user stories for feature', () => { + it('passes', () => { + cy.upsertlogin(User).then(value => { + cy.request({ + method: 'GET', + url: `${HostName}/features/${UserStories[0].feature_uuid}/story`, + headers: { 'x-jwt': `${value}` }, + body: {} + }).then((resp) => { + expect(resp.status).to.eq(200) + for (let i = 0; i <= 5; i++) { + expect(resp.body[i]).to.have.property('uuid').and.equal(UserStories[i].uuid.trim()); + expect(resp.body[i]).to.have.property('feature_uuid').and.equal(UserStories[i].feature_uuid.trim()); + expect(resp.body[i]).to.have.property('description').and.equal(UserStories[i].description.trim() + " _addtext"); + expect(resp.body[i]).to.have.property('priority').and.equal(UserStories[i].priority); + } + }) + }) + }) +}) + +describe('Get story by uuid', () => { + it('passes', () => { + cy.upsertlogin(User).then(value => { + for (let i = 0; i <= 5; i++) { + cy.request({ + method: 'GET', + url: `${HostName}/features/${UserStories[0].feature_uuid}/story/${UserStories[i].uuid}`, + headers: { 'x-jwt': `${value}` }, + body: {} + }).then((resp) => { + expect(resp.status).to.eq(200); + expect(resp.body).to.have.property('uuid').and.equal(UserStories[i].uuid.trim()); + expect(resp.body).to.have.property('feature_uuid').and.equal(UserStories[i].feature_uuid.trim()); + expect(resp.body).to.have.property('description').and.equal(UserStories[i].description.trim() + " _addtext"); + expect(resp.body).to.have.property('priority').and.equal(UserStories[i].priority); + }); + } + }); + }); +}); + +describe('Delete story by uuid', () => { + it('passes', () => { + cy.upsertlogin(User).then(value => { + cy.request({ + method: 'DELETE', + url: `${HostName}/features/${UserStories[0].feature_uuid}/story/${UserStories[0].uuid}`, + headers: { 'x-jwt': `${value}` }, + body: {} + }).then((resp) => { + expect(resp.status).to.eq(200) + }) + }) + }) +}) + +describe('Check delete by uuid', () => { + it('passes', () => { + cy.upsertlogin(User).then(value => { + cy.request({ + method: 'DELETE', + url: `${HostName}/features/${UserStories[0].feature_uuid}/story/${UserStories[0].uuid}`, + headers: { 'x-jwt': `${value}` }, + body: {}, + failOnStatusCode: false + }).then((resp) => { + expect(resp.status).to.eq(404); + }) + }) + }) +}) diff --git a/cypress/e2e/06_phases.cy.ts b/cypress/e2e/05_phases.cy.ts similarity index 100% rename from cypress/e2e/06_phases.cy.ts rename to cypress/e2e/05_phases.cy.ts diff --git a/cypress/e2e/06_phases.cy.js b/cypress/e2e/06_phases.cy.js deleted file mode 100644 index d74b0bbf2..000000000 --- a/cypress/e2e/06_phases.cy.js +++ /dev/null @@ -1,116 +0,0 @@ -import { User, HostName, UserStories, Phases } from '../support/objects/objects'; - -describe('Create Phases for Feature', () => { - it('passes', () => { - cy.upsertlogin(User).then(value => { - for(let i = 0; i <= 2; i++) { - cy.request({ - method: 'POST', - url: `${HostName}/features/phase`, - headers: { 'x-jwt': `${value}` }, - body: Phases[i] - }).its('body').then(body => { - expect(body).to.have.property('uuid').and.equal(Phases[i].uuid.trim()); - expect(body).to.have.property('feature_uuid').and.equal(Phases[i].feature_uuid.trim()); - expect(body).to.have.property('name').and.equal(Phases[i].name.trim()); - expect(body).to.have.property('priority').and.equal(Phases[i].priority); - }); - } - }) - }) -}) - -describe('Modify phases name', () => { - it('passes', () => { - cy.upsertlogin(User).then(value => { - for(let i = 0; i <= 2; i++) { - cy.request({ - method: 'POST', - url: `${HostName}/features/phase`, - headers: { 'x-jwt': `${value}` }, - body: { - uuid: Phases[i].uuid, - name: Phases[i].name + "_addtext" - } - }).its('body').then(body => { - expect(body).to.have.property('uuid').and.equal(Phases[i].uuid.trim()); - expect(body).to.have.property('feature_uuid').and.equal(Phases[i].feature_uuid.trim()); - expect(body).to.have.property('name').and.equal(Phases[i].name.trim() + "_addtext"); - expect(body).to.have.property('priority').and.equal(Phases[i].priority); - }); - } - }) - }) -}) - -describe('Get phases for feature', () => { - it('passes', () => { - cy.upsertlogin(User).then(value => { - cy.request({ - method: 'GET', - url: `${HostName}/features/${Phases[0].feature_uuid}/phase`, - headers: { 'x-jwt': `${ value }` }, - body: {} - }).then((resp) => { - expect(resp.status).to.eq(200) - for(let i = 0; i <= 2; i++) { - expect(resp.body[i]).to.have.property('uuid').and.equal(Phases[i].uuid.trim()); - expect(resp.body[i]).to.have.property('feature_uuid').and.equal(Phases[i].feature_uuid.trim()); - expect(resp.body[i]).to.have.property('name').and.equal(Phases[i].name.trim() + "_addtext"); - expect(resp.body[i]).to.have.property('priority').and.equal(Phases[i].priority); - } - }) - }) - }) -}) - -describe('Get phase by uuid', () => { - it('passes', () => { - cy.upsertlogin(User).then(value => { - for(let i = 0; i <= 2; i++) { - cy.request({ - method: 'GET', - url: `${HostName}/features/${Phases[0].feature_uuid}/phase/${Phases[i].uuid}`, - headers: { 'x-jwt': `${ value }` }, - body: {} - }).then((resp) => { - expect(resp.status).to.eq(200) - expect(resp.body[i]).to.have.property('uuid').and.equal(Phases[i].uuid.trim()); - expect(resp.body[i]).to.have.property('feature_uuid').and.equal(Phases[i].feature_uuid.trim()); - expect(resp.body[i]).to.have.property('name').and.equal(Phases[i].name.trim() + "_addtext"); - expect(resp.body[i]).to.have.property('priority').and.equal(Phases[i].priority); - }) - } - }) - }) -}) - -describe('Delete phase by uuid', () => { - it('passes', () => { - cy.upsertlogin(User).then(value => { - cy.request({ - method: 'DELETE', - url: `${HostName}/features/${Phases[0].feature_uuid}/phase/${Phases[0].uuid}`, - headers: { 'x-jwt': `${ value }` }, - body: {} - }).then((resp) => { - expect(resp.status).to.eq(200) - }) - }) - }) -}) - -describe('Check delete by uuid', () => { - it('passes', () => { - cy.upsertlogin(User).then(value => { - cy.request({ - method: 'GET', - url: `${HostName}/features/${Phases[0].feature_uuid}/phase/${Phases[0].uuid}`, - headers: { 'x-jwt': `${ value }` }, - body: {} - }).then((resp) => { - expect(resp.status).to.eq(404); - }) - }) - }) -}) diff --git a/cypress/support/objects/objects.ts b/cypress/support/objects/objects.ts index 9e4910605..973ab70fe 100644 --- a/cypress/support/objects/objects.ts +++ b/cypress/support/objects/objects.ts @@ -129,12 +129,12 @@ export const Features = [ ]; export const UserStories = [ - { uuid: 'com1lh0n1e49ug76noig', feature_uuid: 'com1kson1e49th88dbg0', description: ' As a {PM} I want to {make providers \"hive ready\"}, so I can {leverage the hive process ' }, - { uuid: 'com1lk8n1e49uqfe3l40', feature_uuid: 'com1kson1e49th88dbg0', description: ' As a {PM} I want to {CRUD Features}, so I can {use the system to manage my features} ' }, - { uuid: 'com1ln8n1e49v4159gug', feature_uuid: 'com1kson1e49th88dbg0', description: ' As a {PM} I want to {follow best practices}, so I can {make more valuable features} ' }, - { uuid: 'com1lqgn1e49vevhs9k0', feature_uuid: 'com1kson1e49th88dbg0', description: ' As a {PM} I want to {save the architecture of the feature}, so I can {share it with people} ' }, - { uuid: 'com1lt8n1e49voquoq90', feature_uuid: 'com1kson1e49th88dbg0', description: ' As a {PM} I want to {create phases}, so I can {divide the work in several deliverable stages} ' }, - { uuid: 'com1m08n1e4a02r6j0pg', feature_uuid: 'com1kson1e49th88dbg0', description: ' As a {PM} I want to {assign bounties to features}, so I can {group bounties together} ' }, + { uuid: 'com1lh0n1e49ug76noig', feature_uuid: 'com1kson1e49th88dbg0', description: ' As a {PM} I want to {make providers \"hive ready\"}, so I can {leverage the hive process ', priority: 0 }, + { uuid: 'com1lk8n1e49uqfe3l40', feature_uuid: 'com1kson1e49th88dbg0', description: ' As a {PM} I want to {CRUD Features}, so I can {use the system to manage my features} ', priority: 1 }, + { uuid: 'com1ln8n1e49v4159gug', feature_uuid: 'com1kson1e49th88dbg0', description: ' As a {PM} I want to {follow best practices}, so I can {make more valuable features} ', priority: 2 }, + { uuid: 'com1lqgn1e49vevhs9k0', feature_uuid: 'com1kson1e49th88dbg0', description: ' As a {PM} I want to {save the architecture of the feature}, so I can {share it with people} ', priority: 3 }, + { uuid: 'com1lt8n1e49voquoq90', feature_uuid: 'com1kson1e49th88dbg0', description: ' As a {PM} I want to {create phases}, so I can {divide the work in several deliverable stages} ', priority: 4 }, + { uuid: 'com1m08n1e4a02r6j0pg', feature_uuid: 'com1kson1e49th88dbg0', description: ' As a {PM} I want to {assign bounties to features}, so I can {group bounties together} ', priority: 5 }, ]; export const Phases = [ diff --git a/db/config.go b/db/config.go index b7ab4fa20..d54c162ca 100644 --- a/db/config.go +++ b/db/config.go @@ -70,6 +70,7 @@ func InitDB() { db.AutoMigrate(&WorkspaceRepositories{}) db.AutoMigrate(&WorkspaceFeatures{}) db.AutoMigrate(&FeaturePhase{}) + db.AutoMigrate(&FeatureStory{}) DB.MigrateTablesWithOrgUuid() DB.MigrateOrganizationToWorkspace() diff --git a/db/features.go b/db/features.go index 1372674f1..3d4f585a0 100644 --- a/db/features.go +++ b/db/features.go @@ -67,6 +67,8 @@ func (db database) CreateOrEditFeature(m WorkspaceFeatures) (WorkspaceFeatures, db.db.Create(&m) } + db.db.Model(&WorkspaceFeatures{}).Where("uuid = ?", m.Uuid).Find(&m) + return m, nil } @@ -115,3 +117,54 @@ func (db database) DeleteFeaturePhase(featureUuid, phaseUuid string) error { } return nil } + +func (db database) CreateOrEditFeatureStory(story FeatureStory) (FeatureStory, error) { + story.Description = strings.TrimSpace(story.Description) + + now := time.Now() + story.Updated = &now + + existingStory := FeatureStory{} + result := db.db.Model(&FeatureStory{}).Where("uuid = ?", story.Uuid).First(&existingStory) + + if result.RowsAffected == 0 { + story.Created = &now + db.db.Create(&story) + } else { + db.db.Model(&FeatureStory{}).Where("uuid = ?", story.Uuid).Updates(story) + } + + db.db.Model(&FeatureStory{}).Where("uuid = ?", story.Uuid).Find(&story) + + return story, nil +} + +func (db database) GetFeatureStoriesByFeatureUuid(featureUuid string) ([]FeatureStory, error) { + var stories []FeatureStory + result := db.db.Where("feature_uuid = ?", featureUuid).Find(&stories) + if result.Error != nil { + return nil, result.Error + } + + for i := range stories { + stories[i].Description = strings.TrimSpace(stories[i].Description) + } + return stories, nil +} + +func (db database) GetFeatureStoryByUuid(featureUuid, storyUuid string) (FeatureStory, error) { + story := FeatureStory{} + result := db.db.Model(&FeatureStory{}).Where("feature_uuid = ? AND uuid = ?", featureUuid, storyUuid).First(&story) + if result.RowsAffected == 0 { + return story, errors.New("no story found") + } + return story, nil +} + +func (db database) DeleteFeatureStoryByUuid(featureUuid, storyUuid string) error { + result := db.db.Where("feature_uuid = ? AND uuid = ?", featureUuid, storyUuid).Delete(&FeatureStory{}) + if result.RowsAffected == 0 { + return errors.New("no story found to delete") + } + return nil +} diff --git a/db/interface.go b/db/interface.go index 1643e352c..4b4585b99 100644 --- a/db/interface.go +++ b/db/interface.go @@ -150,4 +150,8 @@ type Database interface { GetPhasesByFeatureUuid(featureUuid string) []FeaturePhase GetFeaturePhaseByUuid(featureUuid, phaseUuid string) (FeaturePhase, error) DeleteFeaturePhase(featureUuid, phaseUuid string) error + CreateOrEditFeatureStory(story FeatureStory) (FeatureStory, error) + GetFeatureStoriesByFeatureUuid(featureUuid string) ([]FeatureStory, error) + GetFeatureStoryByUuid(featureUuid, storyUuid string) (FeatureStory, error) + DeleteFeatureStoryByUuid(featureUuid, storyUuid string) error } diff --git a/db/structs.go b/db/structs.go index 020b5e4b8..6988a5511 100644 --- a/db/structs.go +++ b/db/structs.go @@ -679,6 +679,18 @@ type BudgetHistory struct { PaymentType PaymentType `json:"payment_type"` } +type FeatureStory struct { + ID uint `json:"id"` + Uuid string `json:"uuid"` + FeatureUuid string `json:"feature_uuid"` + Description string `json:"description"` + Priority int `json:"priority"` + Created *time.Time `json:"created"` + Updated *time.Time `json:"updated"` + CreatedBy string `json:"created_by"` + UpdatedBy string `json:"updated_by"` +} + type BudgetHistoryData struct { BudgetHistory SenderName string `json:"sender_name"` diff --git a/handlers/features.go b/handlers/features.go index 1e2096623..7dd7b4fe2 100644 --- a/handlers/features.go +++ b/handlers/features.go @@ -3,12 +3,13 @@ package handlers import ( "encoding/json" "fmt" + "io" + "net/http" + "github.com/go-chi/chi" "github.com/rs/xid" "github.com/stakwork/sphinx-tribes/auth" "github.com/stakwork/sphinx-tribes/db" - "io" - "net/http" ) type featureHandler struct { @@ -193,3 +194,84 @@ func (oh *featureHandler) DeleteFeaturePhase(w http.ResponseWriter, r *http.Requ w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{"message": "Phase deleted successfully"}) } + +func (oh *featureHandler) CreateOrEditStory(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + pubKeyFromAuth, _ := ctx.Value(auth.ContextKey).(string) + if pubKeyFromAuth == "" { + fmt.Println("no pubkey from auth") + w.WriteHeader(http.StatusUnauthorized) + return + } + + newStory := db.FeatureStory{} + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&newStory) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + fmt.Fprintf(w, "Error decoding request body: %v", err) + return + } + + if newStory.Uuid == "" { + newStory.Uuid = xid.New().String() + } + + existingStory, _ := oh.db.GetFeatureStoryByUuid(newStory.FeatureUuid, newStory.Uuid) + + if existingStory.CreatedBy == "" { + newStory.CreatedBy = pubKeyFromAuth + } + + newStory.UpdatedBy = pubKeyFromAuth + + story, err := oh.db.CreateOrEditFeatureStory(newStory) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "Error creating feature story: %v", err) + return + } + + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(story) +} + +func (oh *featureHandler) GetStoriesByFeatureUuid(w http.ResponseWriter, r *http.Request) { + featureUuid := chi.URLParam(r, "feature_uuid") + stories, err := oh.db.GetFeatureStoriesByFeatureUuid(featureUuid) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(stories) +} + +func (oh *featureHandler) GetStoryByUuid(w http.ResponseWriter, r *http.Request) { + featureUuid := chi.URLParam(r, "feature_uuid") + storyUuid := chi.URLParam(r, "story_uuid") + + story, err := oh.db.GetFeatureStoryByUuid(featureUuid, storyUuid) + if err != nil { + w.WriteHeader(http.StatusNotFound) + return + } + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(story) +} +func (oh *featureHandler) DeleteStory(w http.ResponseWriter, r *http.Request) { + featureUuid := chi.URLParam(r, "feature_uuid") + storyUuid := chi.URLParam(r, "story_uuid") + + err := oh.db.DeleteFeatureStoryByUuid(featureUuid, storyUuid) + if err != nil { + w.WriteHeader(http.StatusNotFound) + json.NewEncoder(w).Encode(map[string]string{"error": err.Error()}) + return + } + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string]string{"message": "Story deleted successfully"}) +} diff --git a/mocks/Database.go b/mocks/Database.go index 92bbc00de..3028b31a2 100644 --- a/mocks/Database.go +++ b/mocks/Database.go @@ -986,6 +986,118 @@ func (_c *Database_CreateOrEditFeature_Call) RunAndReturn(run func(db.WorkspaceF return _c } +// CreateOrEditFeaturePhase provides a mock function with given fields: phase +func (_m *Database) CreateOrEditFeaturePhase(phase db.FeaturePhase) (db.FeaturePhase, error) { + ret := _m.Called(phase) + + if len(ret) == 0 { + panic("no return value specified for CreateOrEditFeaturePhase") + } + + var r0 db.FeaturePhase + var r1 error + if rf, ok := ret.Get(0).(func(db.FeaturePhase) (db.FeaturePhase, error)); ok { + return rf(phase) + } + if rf, ok := ret.Get(0).(func(db.FeaturePhase) db.FeaturePhase); ok { + r0 = rf(phase) + } else { + r0 = ret.Get(0).(db.FeaturePhase) + } + + if rf, ok := ret.Get(1).(func(db.FeaturePhase) error); ok { + r1 = rf(phase) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Database_CreateOrEditFeaturePhase_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateOrEditFeaturePhase' +type Database_CreateOrEditFeaturePhase_Call struct { + *mock.Call +} + +// CreateOrEditFeaturePhase is a helper method to define mock.On call +// - phase db.FeaturePhase +func (_e *Database_Expecter) CreateOrEditFeaturePhase(phase interface{}) *Database_CreateOrEditFeaturePhase_Call { + return &Database_CreateOrEditFeaturePhase_Call{Call: _e.mock.On("CreateOrEditFeaturePhase", phase)} +} + +func (_c *Database_CreateOrEditFeaturePhase_Call) Run(run func(phase db.FeaturePhase)) *Database_CreateOrEditFeaturePhase_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(db.FeaturePhase)) + }) + return _c +} + +func (_c *Database_CreateOrEditFeaturePhase_Call) Return(_a0 db.FeaturePhase, _a1 error) *Database_CreateOrEditFeaturePhase_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Database_CreateOrEditFeaturePhase_Call) RunAndReturn(run func(db.FeaturePhase) (db.FeaturePhase, error)) *Database_CreateOrEditFeaturePhase_Call { + _c.Call.Return(run) + return _c +} + +// CreateOrEditFeatureStory provides a mock function with given fields: story +func (_m *Database) CreateOrEditFeatureStory(story db.FeatureStory) (db.FeatureStory, error) { + ret := _m.Called(story) + + if len(ret) == 0 { + panic("no return value specified for CreateOrEditFeatureStory") + } + + var r0 db.FeatureStory + var r1 error + if rf, ok := ret.Get(0).(func(db.FeatureStory) (db.FeatureStory, error)); ok { + return rf(story) + } + if rf, ok := ret.Get(0).(func(db.FeatureStory) db.FeatureStory); ok { + r0 = rf(story) + } else { + r0 = ret.Get(0).(db.FeatureStory) + } + + if rf, ok := ret.Get(1).(func(db.FeatureStory) error); ok { + r1 = rf(story) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Database_CreateOrEditFeatureStory_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateOrEditFeatureStory' +type Database_CreateOrEditFeatureStory_Call struct { + *mock.Call +} + +// CreateOrEditFeatureStory is a helper method to define mock.On call +// - story db.FeatureStory +func (_e *Database_Expecter) CreateOrEditFeatureStory(story interface{}) *Database_CreateOrEditFeatureStory_Call { + return &Database_CreateOrEditFeatureStory_Call{Call: _e.mock.On("CreateOrEditFeatureStory", story)} +} + +func (_c *Database_CreateOrEditFeatureStory_Call) Run(run func(story db.FeatureStory)) *Database_CreateOrEditFeatureStory_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(db.FeatureStory)) + }) + return _c +} + +func (_c *Database_CreateOrEditFeatureStory_Call) Return(_a0 db.FeatureStory, _a1 error) *Database_CreateOrEditFeatureStory_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Database_CreateOrEditFeatureStory_Call) RunAndReturn(run func(db.FeatureStory) (db.FeatureStory, error)) *Database_CreateOrEditFeatureStory_Call { + _c.Call.Return(run) + return _c +} + // CreateOrEditPerson provides a mock function with given fields: m func (_m *Database) CreateOrEditPerson(m db.Person) (db.Person, error) { ret := _m.Called(m) @@ -1455,6 +1567,100 @@ func (_c *Database_DeleteBounty_Call) RunAndReturn(run func(string, string) (db. return _c } +// DeleteFeaturePhase provides a mock function with given fields: featureUuid, phaseUuid +func (_m *Database) DeleteFeaturePhase(featureUuid string, phaseUuid string) error { + ret := _m.Called(featureUuid, phaseUuid) + + if len(ret) == 0 { + panic("no return value specified for DeleteFeaturePhase") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string, string) error); ok { + r0 = rf(featureUuid, phaseUuid) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Database_DeleteFeaturePhase_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteFeaturePhase' +type Database_DeleteFeaturePhase_Call struct { + *mock.Call +} + +// DeleteFeaturePhase is a helper method to define mock.On call +// - featureUuid string +// - phaseUuid string +func (_e *Database_Expecter) DeleteFeaturePhase(featureUuid interface{}, phaseUuid interface{}) *Database_DeleteFeaturePhase_Call { + return &Database_DeleteFeaturePhase_Call{Call: _e.mock.On("DeleteFeaturePhase", featureUuid, phaseUuid)} +} + +func (_c *Database_DeleteFeaturePhase_Call) Run(run func(featureUuid string, phaseUuid string)) *Database_DeleteFeaturePhase_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *Database_DeleteFeaturePhase_Call) Return(_a0 error) *Database_DeleteFeaturePhase_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Database_DeleteFeaturePhase_Call) RunAndReturn(run func(string, string) error) *Database_DeleteFeaturePhase_Call { + _c.Call.Return(run) + return _c +} + +// DeleteFeatureStoryByUuid provides a mock function with given fields: featureUuid, storyUuid +func (_m *Database) DeleteFeatureStoryByUuid(featureUuid string, storyUuid string) error { + ret := _m.Called(featureUuid, storyUuid) + + if len(ret) == 0 { + panic("no return value specified for DeleteFeatureStoryByUuid") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string, string) error); ok { + r0 = rf(featureUuid, storyUuid) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Database_DeleteFeatureStoryByUuid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteFeatureStoryByUuid' +type Database_DeleteFeatureStoryByUuid_Call struct { + *mock.Call +} + +// DeleteFeatureStoryByUuid is a helper method to define mock.On call +// - featureUuid string +// - storyUuid string +func (_e *Database_Expecter) DeleteFeatureStoryByUuid(featureUuid interface{}, storyUuid interface{}) *Database_DeleteFeatureStoryByUuid_Call { + return &Database_DeleteFeatureStoryByUuid_Call{Call: _e.mock.On("DeleteFeatureStoryByUuid", featureUuid, storyUuid)} +} + +func (_c *Database_DeleteFeatureStoryByUuid_Call) Run(run func(featureUuid string, storyUuid string)) *Database_DeleteFeatureStoryByUuid_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *Database_DeleteFeatureStoryByUuid_Call) Return(_a0 error) *Database_DeleteFeatureStoryByUuid_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Database_DeleteFeatureStoryByUuid_Call) RunAndReturn(run func(string, string) error) *Database_DeleteFeatureStoryByUuid_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) @@ -2681,6 +2887,178 @@ func (_c *Database_GetFeatureByUuid_Call) RunAndReturn(run func(string) db.Works return _c } +// GetFeaturePhaseByUuid provides a mock function with given fields: featureUuid, phaseUuid +func (_m *Database) GetFeaturePhaseByUuid(featureUuid string, phaseUuid string) (db.FeaturePhase, error) { + ret := _m.Called(featureUuid, phaseUuid) + + if len(ret) == 0 { + panic("no return value specified for GetFeaturePhaseByUuid") + } + + var r0 db.FeaturePhase + var r1 error + if rf, ok := ret.Get(0).(func(string, string) (db.FeaturePhase, error)); ok { + return rf(featureUuid, phaseUuid) + } + if rf, ok := ret.Get(0).(func(string, string) db.FeaturePhase); ok { + r0 = rf(featureUuid, phaseUuid) + } else { + r0 = ret.Get(0).(db.FeaturePhase) + } + + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(featureUuid, phaseUuid) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Database_GetFeaturePhaseByUuid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFeaturePhaseByUuid' +type Database_GetFeaturePhaseByUuid_Call struct { + *mock.Call +} + +// GetFeaturePhaseByUuid is a helper method to define mock.On call +// - featureUuid string +// - phaseUuid string +func (_e *Database_Expecter) GetFeaturePhaseByUuid(featureUuid interface{}, phaseUuid interface{}) *Database_GetFeaturePhaseByUuid_Call { + return &Database_GetFeaturePhaseByUuid_Call{Call: _e.mock.On("GetFeaturePhaseByUuid", featureUuid, phaseUuid)} +} + +func (_c *Database_GetFeaturePhaseByUuid_Call) Run(run func(featureUuid string, phaseUuid string)) *Database_GetFeaturePhaseByUuid_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *Database_GetFeaturePhaseByUuid_Call) Return(_a0 db.FeaturePhase, _a1 error) *Database_GetFeaturePhaseByUuid_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Database_GetFeaturePhaseByUuid_Call) RunAndReturn(run func(string, string) (db.FeaturePhase, error)) *Database_GetFeaturePhaseByUuid_Call { + _c.Call.Return(run) + return _c +} + +// GetFeatureStoriesByFeatureUuid provides a mock function with given fields: featureUuid +func (_m *Database) GetFeatureStoriesByFeatureUuid(featureUuid string) ([]db.FeatureStory, error) { + ret := _m.Called(featureUuid) + + if len(ret) == 0 { + panic("no return value specified for GetFeatureStoriesByFeatureUuid") + } + + var r0 []db.FeatureStory + var r1 error + if rf, ok := ret.Get(0).(func(string) ([]db.FeatureStory, error)); ok { + return rf(featureUuid) + } + if rf, ok := ret.Get(0).(func(string) []db.FeatureStory); ok { + r0 = rf(featureUuid) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]db.FeatureStory) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(featureUuid) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Database_GetFeatureStoriesByFeatureUuid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFeatureStoriesByFeatureUuid' +type Database_GetFeatureStoriesByFeatureUuid_Call struct { + *mock.Call +} + +// GetFeatureStoriesByFeatureUuid is a helper method to define mock.On call +// - featureUuid string +func (_e *Database_Expecter) GetFeatureStoriesByFeatureUuid(featureUuid interface{}) *Database_GetFeatureStoriesByFeatureUuid_Call { + return &Database_GetFeatureStoriesByFeatureUuid_Call{Call: _e.mock.On("GetFeatureStoriesByFeatureUuid", featureUuid)} +} + +func (_c *Database_GetFeatureStoriesByFeatureUuid_Call) Run(run func(featureUuid string)) *Database_GetFeatureStoriesByFeatureUuid_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *Database_GetFeatureStoriesByFeatureUuid_Call) Return(_a0 []db.FeatureStory, _a1 error) *Database_GetFeatureStoriesByFeatureUuid_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Database_GetFeatureStoriesByFeatureUuid_Call) RunAndReturn(run func(string) ([]db.FeatureStory, error)) *Database_GetFeatureStoriesByFeatureUuid_Call { + _c.Call.Return(run) + return _c +} + +// GetFeatureStoryByUuid provides a mock function with given fields: featureUuid, storyUuid +func (_m *Database) GetFeatureStoryByUuid(featureUuid string, storyUuid string) (db.FeatureStory, error) { + ret := _m.Called(featureUuid, storyUuid) + + if len(ret) == 0 { + panic("no return value specified for GetFeatureStoryByUuid") + } + + var r0 db.FeatureStory + var r1 error + if rf, ok := ret.Get(0).(func(string, string) (db.FeatureStory, error)); ok { + return rf(featureUuid, storyUuid) + } + if rf, ok := ret.Get(0).(func(string, string) db.FeatureStory); ok { + r0 = rf(featureUuid, storyUuid) + } else { + r0 = ret.Get(0).(db.FeatureStory) + } + + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(featureUuid, storyUuid) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Database_GetFeatureStoryByUuid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFeatureStoryByUuid' +type Database_GetFeatureStoryByUuid_Call struct { + *mock.Call +} + +// GetFeatureStoryByUuid is a helper method to define mock.On call +// - featureUuid string +// - storyUuid string +func (_e *Database_Expecter) GetFeatureStoryByUuid(featureUuid interface{}, storyUuid interface{}) *Database_GetFeatureStoryByUuid_Call { + return &Database_GetFeatureStoryByUuid_Call{Call: _e.mock.On("GetFeatureStoryByUuid", featureUuid, storyUuid)} +} + +func (_c *Database_GetFeatureStoryByUuid_Call) Run(run func(featureUuid string, storyUuid string)) *Database_GetFeatureStoryByUuid_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *Database_GetFeatureStoryByUuid_Call) Return(_a0 db.FeatureStory, _a1 error) *Database_GetFeatureStoryByUuid_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Database_GetFeatureStoryByUuid_Call) RunAndReturn(run func(string, string) (db.FeatureStory, error)) *Database_GetFeatureStoryByUuid_Call { + _c.Call.Return(run) + return _c +} + // GetFeaturesByWorkspaceUuid provides a mock function with given fields: uuid, r func (_m *Database) GetFeaturesByWorkspaceUuid(uuid string, r *http.Request) []db.WorkspaceFeatures { ret := _m.Called(uuid, r) @@ -3858,6 +4236,54 @@ func (_c *Database_GetPersonByUuid_Call) RunAndReturn(run func(string) db.Person return _c } +// GetPhasesByFeatureUuid provides a mock function with given fields: featureUuid +func (_m *Database) GetPhasesByFeatureUuid(featureUuid string) []db.FeaturePhase { + ret := _m.Called(featureUuid) + + if len(ret) == 0 { + panic("no return value specified for GetPhasesByFeatureUuid") + } + + var r0 []db.FeaturePhase + if rf, ok := ret.Get(0).(func(string) []db.FeaturePhase); ok { + r0 = rf(featureUuid) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]db.FeaturePhase) + } + } + + return r0 +} + +// Database_GetPhasesByFeatureUuid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPhasesByFeatureUuid' +type Database_GetPhasesByFeatureUuid_Call struct { + *mock.Call +} + +// GetPhasesByFeatureUuid is a helper method to define mock.On call +// - featureUuid string +func (_e *Database_Expecter) GetPhasesByFeatureUuid(featureUuid interface{}) *Database_GetPhasesByFeatureUuid_Call { + return &Database_GetPhasesByFeatureUuid_Call{Call: _e.mock.On("GetPhasesByFeatureUuid", featureUuid)} +} + +func (_c *Database_GetPhasesByFeatureUuid_Call) Run(run func(featureUuid string)) *Database_GetPhasesByFeatureUuid_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *Database_GetPhasesByFeatureUuid_Call) Return(_a0 []db.FeaturePhase) *Database_GetPhasesByFeatureUuid_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Database_GetPhasesByFeatureUuid_Call) RunAndReturn(run func(string) []db.FeaturePhase) *Database_GetPhasesByFeatureUuid_Call { + _c.Call.Return(run) + return _c +} + // GetPreviousBountyByCreated provides a mock function with given fields: r func (_m *Database) GetPreviousBountyByCreated(r *http.Request) (uint, error) { ret := _m.Called(r) @@ -6811,75 +7237,3 @@ func NewDatabase(t interface { return mock } - -// CreateOrEditFeaturePhase provides a mock function with given fields: phase -func (_m *Database) CreateOrEditFeaturePhase(phase db.FeaturePhase) (db.FeaturePhase, error) { - ret := _m.Called(phase) - - var r0 db.FeaturePhase - var r1 error - if rf, ok := ret.Get(0).(func(db.FeaturePhase) db.FeaturePhase); ok { - r0 = rf(phase) - } else { - r0 = ret.Get(0).(db.FeaturePhase) - } - - if rf, ok := ret.Get(1).(func(db.FeaturePhase) error); ok { - r1 = rf(phase) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetPhasesByFeatureUuid provides a mock function with given fields: featureUuid -func (_m *Database) GetPhasesByFeatureUuid(featureUuid string) []db.FeaturePhase { - ret := _m.Called(featureUuid) - - var r0 []db.FeaturePhase - if rf, ok := ret.Get(0).(func(string) []db.FeaturePhase); ok { - r0 = rf(featureUuid) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]db.FeaturePhase) - } - } - - return r0 -} - -// GetFeaturePhaseByUuid provides a mock function with given fields: featureUuid, phaseUuid -func (_m *Database) GetFeaturePhaseByUuid(featureUuid, phaseUuid string) (db.FeaturePhase, error) { - ret := _m.Called(featureUuid, phaseUuid) - - var r0 db.FeaturePhase - var r1 error - if rf, ok := ret.Get(0).(func(string, string) db.FeaturePhase); ok { - r0 = rf(featureUuid, phaseUuid) - } else { - r0 = ret.Get(0).(db.FeaturePhase) - } - - if rf, ok := ret.Get(1).(func(string, string) error); ok { - r1 = rf(featureUuid, phaseUuid) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DeleteFeaturePhase provides a mock function with given fields: featureUuid, phaseUuid -func (_m *Database) DeleteFeaturePhase(featureUuid string, phaseUuid string) error { - ret := _m.Called(featureUuid, phaseUuid) - - var r1 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r1 = rf(featureUuid, phaseUuid) - } else { - r1 = ret.Error(0) - } - - return r1 -} diff --git a/routes/features.go b/routes/features.go index 405b7ce60..e43bb1b3b 100644 --- a/routes/features.go +++ b/routes/features.go @@ -23,6 +23,10 @@ func FeatureRoutes() chi.Router { r.Get("/{feature_uuid}/phase/{phase_uuid}", featureHandlers.GetFeaturePhaseByUUID) r.Delete("/{feature_uuid}/phase/{phase_uuid}", featureHandlers.DeleteFeaturePhase) + r.Post("/story", featureHandlers.CreateOrEditStory) + r.Get("/{feature_uuid}/story", featureHandlers.GetStoriesByFeatureUuid) + r.Get("/{feature_uuid}/story/{story_uuid}", featureHandlers.GetStoryByUuid) + r.Delete("/{feature_uuid}/story/{story_uuid}", featureHandlers.DeleteStory) }) return r }