diff --git a/cypress/e2e/03_features.cy.ts b/cypress/e2e/03_features.cy.ts new file mode 100644 index 000000000..dd2c66424 --- /dev/null +++ b/cypress/e2e/03_features.cy.ts @@ -0,0 +1,158 @@ +import { User, HostName, Workspaces, Repositories, Features } from '../support/objects/objects'; + + + +describe('Create Features for Workspace', () => { + it('passes', () => { + cy.upsertlogin(User).then(value => { + for(let i = 0; i <= 2; i++) { + cy.request({ + method: 'POST', + url: `${HostName}/features`, + headers: { 'x-jwt': `${value}` }, + body: Features[i] + }).its('body').then(body => { + expect(body).to.have.property('name').and.equal(Features[i].name.trim()); + expect(body).to.have.property('brief').and.equal(Features[i].brief.trim()); + expect(body).to.have.property('requirements').and.equal(Features[i].requirements.trim()); + expect(body).to.have.property('architecture').and.equal(Features[i].architecture.trim()); + }); + } + }) + }) +}) + +describe('Modify name for Feature', () => { + it('passes', () => { + cy.upsertlogin(User).then(value => { + for(let i = 0; i <= 2; i++) { + cy.request({ + method: 'POST', + url: `${HostName}/features`, + headers: { 'x-jwt': `${value}` }, + body: { + uuid: Features[i].uuid, + name: Features[i].name + "_addtext" + } + }).its('body').then(body => { + expect(body).to.have.property('name').and.equal(Features[i].name.trim() + " _addtext"); + expect(body).to.have.property('brief').and.equal(Features[i].brief.trim()); + expect(body).to.have.property('requirements').and.equal(Features[i].requirements.trim()); + expect(body).to.have.property('architecture').and.equal(Features[i].architecture.trim()); + }); + } + }) + }) +}) + +describe('Modify brief for Feature', () => { + it('passes', () => { + cy.upsertlogin(User).then(value => { + for(let i = 0; i <= 2; i++) { + cy.request({ + method: 'POST', + url: `${HostName}/features`, + headers: { 'x-jwt': `${value}` }, + body: { + uuid: Features[i].uuid, + brief: Features[i].brief + "_addtext" + } + }).its('body').then(body => { + expect(body).to.have.property('name').and.equal(Features[i].name.trim() + " _addtext"); + expect(body).to.have.property('brief').and.equal(Features[i].brief.trim() + " _addtext"); + expect(body).to.have.property('requirements').and.equal(Features[i].requirements.trim()); + expect(body).to.have.property('architecture').and.equal(Features[i].architecture.trim()); + }); + } + }) + }) +}) + +describe('Modify requirements for Feature', () => { + it('passes', () => { + cy.upsertlogin(User).then(value => { + for(let i = 0; i <= 2; i++) { + cy.request({ + method: 'POST', + url: `${HostName}/features`, + headers: { 'x-jwt': `${value}` }, + body: { + uuid: Features[i].uuid, + requirements: Features[i].requirements + "_addtext" + } + }).its('body').then(body => { + expect(body).to.have.property('name').and.equal(Features[i].name.trim() + " _addtext"); + expect(body).to.have.property('brief').and.equal(Features[i].brief.trim() + " _addtext"); + expect(body).to.have.property('requirements').and.equal(Features[i].requirements.trim() + " _addtext"); + expect(body).to.have.property('architecture').and.equal(Features[i].architecture.trim()); + }); + } + }) + }) +}) + +describe('Modify architecture for Feature', () => { + it('passes', () => { + cy.upsertlogin(User).then(value => { + for(let i = 0; i <= 2; i++) { + cy.request({ + method: 'POST', + url: `${HostName}/features`, + headers: { 'x-jwt': `${value}` }, + body: { + uuid: Features[i].uuid, + architecture: Features[i].architecture + "_addtext" + } + }).its('body').then(body => { + expect(body).to.have.property('name').and.equal(Features[i].name.trim() + " _addtext"); + expect(body).to.have.property('brief').and.equal(Features[i].brief.trim() + " _addtext"); + expect(body).to.have.property('requirements').and.equal(Features[i].requirements.trim() + " _addtext"); + expect(body).to.have.property('architecture').and.equal(Features[i].architecture.trim() + " _addtext"); + }); + } + }) + }) +}) + + +describe('Get Features for Workspace', () => { + it('passes', () => { + cy.upsertlogin(User).then(value => { + cy.request({ + method: 'GET', + url: `${HostName}/features/forworkspace/` + Features[0].workspace_uuid, + 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") + } + }) + }) + }) +}) + +describe('Get Feature by uuid', () => { + it('passes', () => { + cy.upsertlogin(User).then(value => { + for(let i = 0; i <= 2; i++) { + cy.request({ + method: 'GET', + url: `${HostName}/features/` + Features[i].uuid, + 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") + expect(resp.body).to.have.property('brief', Features[i].brief.trim() + " _addtext") + expect(resp.body).to.have.property('requirements', Features[i].requirements.trim() + " _addtext") + expect(resp.body).to.have.property('architecture', Features[i].architecture.trim() + " _addtext") + }) + } + }) + }) +}) diff --git a/cypress/support/objects/objects.ts b/cypress/support/objects/objects.ts index e1a2f7328..9c1908ca8 100644 --- a/cypress/support/objects/objects.ts +++ b/cypress/support/objects/objects.ts @@ -74,7 +74,7 @@ export const Features = [ { uuid: 'com1kson1e49th88dbg0', workspace_uuid: 'cohob00n1e4808utqel0', - name: 'Hive Process', + name: ' Hive Process ', priority: 1, brief: ' To follow a set of best practices in product development.
' + 'Dividing complex features into small
steps makes it easier to ' + @@ -100,7 +100,7 @@ export const Features = [ ' the base from which every technical decition relays on.
' + 'We are going to leverage AI to help the PM write better definitions.
' + 'The fields that would benefit form AI assistance are: mission, tactics, ' + - 'feature brief and feature user stories', + 'feature brief and feature user stories ', requirements: ' Create a new page for a conversation format between the PM and the LLM
' + 'Rely as much as possible on stakwork workflows
' + 'Have history of previous definitions ', @@ -110,7 +110,7 @@ export const Features = [ 'Front

', }, { - uuid: 'com1l5on1e49tucv350g', + uuid: 'com1l5on1e49tucv350h', workspace_uuid: 'cohob00n1e4808utqel0', name: ' AI Assited relation between text fields ', priority: 2, @@ -118,9 +118,9 @@ export const Features = [ 'feature brief, user stories, requirements and architecture should have some ' + 'relation between each other.
' + 'One way to do that is to leverage an LLM ' + 'to discern the parts of the defintion that have a connection to other definitions.
' + - 'The UI will need to show the user how each definition is related to other defintions.', + 'The UI will need to show the user how each definition is related to other defintions. ', requirements: 'Create a new process after a Feature text has changed. It should use the LLM to ' + - 'determine de relationship between parts of the text.', + 'determine de relationship between parts of the text. ', architecture: 'Describe the architecture of the feature with the following sections:' + '

Wireframes

Visual Schematics

Object Definition

' + 'DB Schema Changes

UX

CI/CD

Changes

Endpoints

' + diff --git a/db/config.go b/db/config.go index 547ca97a1..3ffc2c3a1 100644 --- a/db/config.go +++ b/db/config.go @@ -68,6 +68,7 @@ func InitDB() { db.AutoMigrate(&BountyRoles{}) db.AutoMigrate(&UserInvoiceData{}) db.AutoMigrate(&WorkspaceRepositories{}) + db.AutoMigrate(&WorkspaceFeatures{}) DB.MigrateTablesWithOrgUuid() DB.MigrateOrganizationToWorkspace() @@ -178,6 +179,8 @@ func (db database) MigrateTablesWithOrgUuid() { if !db.db.Migrator().HasTable("bounty") { if !db.db.Migrator().HasColumn(Bounty{}, "workspace_uuid") { db.db.AutoMigrate(&Bounty{}) + } else { + db.db.AutoMigrate(&NewBounty{}) } } if !db.db.Migrator().HasTable("budget_histories") { @@ -188,16 +191,22 @@ func (db database) MigrateTablesWithOrgUuid() { if !db.db.Migrator().HasTable("payment_histories") { if !db.db.Migrator().HasColumn(PaymentHistory{}, "workspace_uuid") { db.db.AutoMigrate(&PaymentHistory{}) + } else { + db.db.AutoMigrate(&NewPaymentHistory{}) } } if !db.db.Migrator().HasTable("invoice_list") { if !db.db.Migrator().HasColumn(InvoiceList{}, "workspace_uuid") { db.db.AutoMigrate(&InvoiceList{}) + } else { + db.db.AutoMigrate(&NewInvoiceList{}) } } if !db.db.Migrator().HasTable("bounty_budgets") { if !db.db.Migrator().HasColumn(BountyBudget{}, "workspace_uuid") { db.db.AutoMigrate(&BountyBudget{}) + } else { + db.db.AutoMigrate(&NewBountyBudget{}) } } if !db.db.Migrator().HasTable("workspace_user_roles") { diff --git a/db/db.go b/db/db.go index d2af69fb5..ed1fd7e18 100644 --- a/db/db.go +++ b/db/db.go @@ -1142,7 +1142,7 @@ func (db database) GetAllBounties(r *http.Request) []NewBounty { languageArray := strings.Split(languages, ",") languageLength := len(languageArray) - if workspaceUuid != "" && orgUuid != "" { + if workspaceUuid == "" && orgUuid != "" { workspaceUuid = orgUuid } diff --git a/db/features.go b/db/features.go new file mode 100644 index 000000000..c978124be --- /dev/null +++ b/db/features.go @@ -0,0 +1,41 @@ +package db + +import ( + "strings" + "time" +) + +func (db database) GetFeaturesByWorkspaceUuid(uuid string) []WorkspaceFeatures { + ms := []WorkspaceFeatures{} + + db.db.Model(&WorkspaceFeatures{}).Where("workspace_uuid = ?", uuid).Order("Created").Find(&ms) + + return ms +} + +func (db database) GetFeatureByUuid(uuid string) WorkspaceFeatures { + ms := WorkspaceFeatures{} + + db.db.Model(&WorkspaceFeatures{}).Where("uuid = ?", uuid).Find(&ms) + + return ms +} + +func (db database) CreateOrEditFeature(m WorkspaceFeatures) (WorkspaceFeatures, error) { + m.Name = strings.TrimSpace(m.Name) + m.Brief = strings.TrimSpace(m.Brief) + m.Requirements = strings.TrimSpace(m.Requirements) + m.Architecture = strings.TrimSpace(m.Architecture) + + now := time.Now() + m.Updated = &now + + if db.db.Model(&m).Where("uuid = ?", m.Uuid).Updates(&m).RowsAffected == 0 { + m.Created = &now + db.db.Create(&m) + } + + db.db.Model(&WorkspaceFeatures{}).Where("uuid = ?", m.Uuid).Find(&m) + + return m, nil +} diff --git a/db/interface.go b/db/interface.go index 691c737dd..a5c27c430 100644 --- a/db/interface.go +++ b/db/interface.go @@ -122,18 +122,19 @@ type Database interface { DeleteAllUsersFromWorkspace(uuid string) error GetFilterStatusCount() FilterStattuCount UserHasManageBountyRoles(pubKeyFromAuth string, uuid string) bool - BountiesPaidPercentage(r PaymentDateRange) uint - TotalSatsPosted(r PaymentDateRange) uint - TotalSatsPaid(r PaymentDateRange) uint - SatsPaidPercentage(r PaymentDateRange) uint - AveragePaidTime(r PaymentDateRange) uint - AverageCompletedTime(r PaymentDateRange) uint - TotalBountiesPosted(r PaymentDateRange) int64 - TotalPaidBounties(r PaymentDateRange) int64 - NewHuntersPaid(r PaymentDateRange) int64 - TotalHuntersPaid(r PaymentDateRange) int64 + BountiesPaidPercentage(r PaymentDateRange, workspace string) uint + TotalSatsPosted(r PaymentDateRange, workspace string) uint + TotalSatsPaid(r PaymentDateRange, workspace string) uint + SatsPaidPercentage(r PaymentDateRange, workspace string) uint + AveragePaidTime(r PaymentDateRange, workspace string) uint + AverageCompletedTime(r PaymentDateRange, workspace string) uint + TotalBountiesPosted(r PaymentDateRange, workspace string) int64 + TotalPaidBounties(r PaymentDateRange, workspace string) int64 + TotalAssignedBounties(r PaymentDateRange, workspace string) int64 + NewHuntersPaid(r PaymentDateRange, workspace string) int64 + TotalHuntersPaid(r PaymentDateRange, workspace string) int64 GetPersonByPubkey(pubkey string) Person - GetBountiesByDateRange(r PaymentDateRange, re *http.Request) []Bounty + GetBountiesByDateRange(r PaymentDateRange, re *http.Request) []NewBounty GetBountiesByDateRangeCount(r PaymentDateRange, re *http.Request) int64 GetBountiesProviders(r PaymentDateRange, re *http.Request) []Person PersonUniqueNameFromName(name string) (string, error) @@ -141,4 +142,7 @@ type Database interface { UserHasAccess(pubKeyFromAuth string, uuid string, role string) bool CreateWorkspaceRepository(m WorkspaceRepositories) (WorkspaceRepositories, error) GetWorkspaceRepositorByWorkspaceUuid(uuid string) []WorkspaceRepositories + CreateOrEditFeature(m WorkspaceFeatures) (WorkspaceFeatures, error) + GetFeaturesByWorkspaceUuid(uuid string) []WorkspaceFeatures + GetFeatureByUuid(uuid string) WorkspaceFeatures } diff --git a/db/metrics.go b/db/metrics.go index 1a1f0e870..0fd676c2b 100644 --- a/db/metrics.go +++ b/db/metrics.go @@ -23,27 +23,45 @@ func (db database) TotalWorkspacesByDateRange(r PaymentDateRange) int64 { return count } -func (db database) TotalPaymentsByDateRange(r PaymentDateRange) uint { +func (db database) TotalPaymentsByDateRange(r PaymentDateRange, workspace string) uint { var sum uint - db.db.Model(&PaymentHistory{}).Where("payment_type = ?", r.PaymentType).Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate).Select("SUM(amount)").Row().Scan(&sum) + query := db.db.Model(&NewPaymentHistory{}).Where("payment_type = ?", r.PaymentType).Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate) + + if workspace != "" { + query.Where("workspace_uuid", workspace) + } + + query.Select("SUM(amount)").Row().Scan(&sum) return sum } -func (db database) TotalSatsPosted(r PaymentDateRange) uint { +func (db database) TotalSatsPosted(r PaymentDateRange, workspace string) uint { var sum uint - db.db.Model(&Bounty{}).Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate).Select("SUM(price)").Row().Scan(&sum) + query := db.db.Model(&NewBounty{}).Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate) + + if workspace != "" { + query.Where("workspace_uuid", workspace) + } + + query.Select("SUM(price)").Row().Scan(&sum) return sum } -func (db database) TotalSatsPaid(r PaymentDateRange) uint { +func (db database) TotalSatsPaid(r PaymentDateRange, workspace string) uint { var sum uint - db.db.Model(&Bounty{}).Where("paid = ?", true).Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate).Select("SUM(price)").Row().Scan(&sum) + query := db.db.Model(&NewBounty{}).Where("paid = ?", true).Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate) + + if workspace != "" { + query.Where("workspace_uuid", workspace) + } + + query.Select("SUM(price)").Row().Scan(&sum) return sum } -func (db database) SatsPaidPercentage(r PaymentDateRange) uint { - satsPosted := DB.TotalSatsPosted(r) - satsPaid := DB.TotalSatsPaid(r) +func (db database) SatsPaidPercentage(r PaymentDateRange, workspace string) uint { + satsPosted := DB.TotalSatsPosted(r, workspace) + satsPaid := DB.TotalSatsPaid(r, workspace) if satsPaid != 0 && satsPosted != 0 { value := (satsPaid * 100) / satsPosted paidPercentage := math.Round(float64(value)) @@ -52,43 +70,81 @@ func (db database) SatsPaidPercentage(r PaymentDateRange) uint { return 0 } -func (db database) TotalPaidBounties(r PaymentDateRange) int64 { +func (db database) TotalPaidBounties(r PaymentDateRange, workspace string) int64 { + var count int64 + query := db.db.Model(&NewBounty{}).Where("paid = ?", true).Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate) + + if workspace != "" { + query.Where("workspace_uuid", workspace) + } + + query.Count(&count) + return count +} + +func (db database) TotalAssignedBounties(r PaymentDateRange, workspace string) int64 { var count int64 - db.db.Model(&Bounty{}).Where("paid = ?", true).Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate).Count(&count) + query := db.db.Model(&NewBounty{}).Where("assignee != ''").Where("paid = ?", false).Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate) + + if workspace != "" { + query.Where("workspace_uuid", workspace) + } + + query.Count(&count) return count } -func (db database) TotalHuntersPaid(r PaymentDateRange) int64 { +func (db database) TotalHuntersPaid(r PaymentDateRange, workspace string) int64 { var count int64 query := fmt.Sprintf(`SELECT COUNT(DISTINCT assignee) FROM bounty WHERE assignee !='' AND paid=true AND created >= %s AND created <= %s`, r.StartDate, r.EndDate) - db.db.Raw(query).Count(&count) + var workspaceQuery string + if workspace != "" { + workspaceQuery = fmt.Sprintf("AND workspace_uuid = '%s'", workspace) + } + + allQuery := query + " " + workspaceQuery + db.db.Raw(allQuery).Count(&count) return count } -func (db database) NewHuntersPaid(r PaymentDateRange) int64 { +func (db database) NewHuntersPaid(r PaymentDateRange, workspace string) int64 { var count int64 - db.db.Model(&Bounty{}). + + query := db.db.Model(&NewBounty{}). Select("DISTINCT assignee"). Where("paid = true"). - Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate). - Not("assignee IN (?)", db.db.Model(&Bounty{}). - Select("assignee"). - Where("paid = true"). - Where("created < ?", r.StartDate), - ).Count(&count) + Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate) + + if workspace != "" { + query.Where("workspace_uuid", workspace) + } + + query.Not("assignee IN (?)", db.db.Model(&NewBounty{}). + Select("assignee"). + Where("paid = true"). + Where("created < ?", r.StartDate), + ) + + query.Count(&count) return count } -func (db database) TotalBountiesPosted(r PaymentDateRange) int64 { +func (db database) TotalBountiesPosted(r PaymentDateRange, workspace string) int64 { var count int64 - db.db.Model(&Bounty{}).Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate).Count(&count) + query := db.db.Model(&Bounty{}).Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate) + + if workspace != "" { + query.Where("workspace_uuid", workspace) + } + + query.Count(&count) return count } -func (db database) BountiesPaidPercentage(r PaymentDateRange) uint { - bountiesPosted := DB.TotalBountiesPosted(r) - bountiesPaid := DB.TotalPaidBounties(r) +func (db database) BountiesPaidPercentage(r PaymentDateRange, workspace string) uint { + bountiesPosted := DB.TotalBountiesPosted(r, workspace) + bountiesPaid := DB.TotalPaidBounties(r, workspace) if bountiesPaid != 0 && bountiesPosted != 0 { value := bountiesPaid * 100 / bountiesPosted paidPercentage := math.Round(float64(value)) @@ -97,23 +153,31 @@ func (db database) BountiesPaidPercentage(r PaymentDateRange) uint { return 0 } -func (db database) PaidDifference(r PaymentDateRange) []DateDifference { +func (db database) PaidDifference(r PaymentDateRange, workspace string) []DateDifference { ms := []DateDifference{} - db.db.Raw(`SELECT EXTRACT(EPOCH FROM (paid_date - TO_TIMESTAMP(created))) as diff FROM public.bounty WHERE paid_date IS NOT NULL AND created >= '` + r.StartDate + `' AND created <= '` + r.EndDate + `' `).Find(&ms) + query := fmt.Sprintf("SELECT EXTRACT(EPOCH FROM (paid_date - TO_TIMESTAMP(created))) as diff FROM public.bounty WHERE paid_date IS NOT NULL AND created >= %s AND created <= %s", r.StartDate, r.EndDate) + + var workspaceQuery string + if workspace != "" { + workspaceQuery = fmt.Sprintf("AND workspace_uuid = '%s'", workspace) + } + + allQuery := query + " " + workspaceQuery + db.db.Raw(allQuery).Find(&ms) return ms } -func (db database) PaidDifferenceCount(r PaymentDateRange) int64 { +func (db database) PaidDifferenceCount(r PaymentDateRange, workspace string) int64 { var count int64 - list := db.PaidDifference(r) + list := db.PaidDifference(r, workspace) count = int64(len(list)) return count } -func (db database) AveragePaidTime(r PaymentDateRange) uint { - paidList := DB.PaidDifference(r) - paidCount := DB.PaidDifferenceCount(r) +func (db database) AveragePaidTime(r PaymentDateRange, workspace string) uint { + paidList := DB.PaidDifference(r, workspace) + paidCount := DB.PaidDifferenceCount(r, workspace) var paidSum uint for _, diff := range paidList { paidSum = uint(math.Round(diff.Diff)) @@ -121,23 +185,31 @@ func (db database) AveragePaidTime(r PaymentDateRange) uint { return CalculateAverageDays(paidCount, paidSum) } -func (db database) CompletedDifference(r PaymentDateRange) []DateDifference { +func (db database) CompletedDifference(r PaymentDateRange, workspace string) []DateDifference { ms := []DateDifference{} - db.db.Raw(`SELECT EXTRACT(EPOCH FROM (completion_date - TO_TIMESTAMP(created))) as diff FROM public.bounty WHERE completion_date IS NOT NULL AND created >= '` + r.StartDate + `' AND created <= '` + r.EndDate + `' `).Find(&ms) + query := fmt.Sprintf("SELECT EXTRACT(EPOCH FROM (completion_date - TO_TIMESTAMP(created))) as diff FROM public.bounty WHERE completion_date IS NOT NULL AND created >= %s AND created <= %s", r.StartDate, r.EndDate) + + var workspaceQuery string + if workspace != "" { + workspaceQuery = fmt.Sprintf("AND workspace_uuid = '%s'", workspace) + } + + allQuery := query + " " + workspaceQuery + db.db.Raw(allQuery).Find(&ms) return ms } -func (db database) CompletedDifferenceCount(r PaymentDateRange) int64 { +func (db database) CompletedDifferenceCount(r PaymentDateRange, workspace string) int64 { var count int64 - list := db.CompletedDifference(r) + list := db.CompletedDifference(r, workspace) count = int64(len(list)) return count } -func (db database) AverageCompletedTime(r PaymentDateRange) uint { - paidList := DB.CompletedDifference(r) - paidCount := DB.CompletedDifferenceCount(r) +func (db database) AverageCompletedTime(r PaymentDateRange, workspace string) uint { + paidList := DB.CompletedDifference(r, workspace) + paidCount := DB.CompletedDifferenceCount(r, workspace) var paidSum uint for _, diff := range paidList { paidSum = uint(math.Round(diff.Diff)) @@ -155,16 +227,18 @@ func CalculateAverageDays(paidCount int64, paidSum uint) uint { return 0 } -func (db database) GetBountiesByDateRange(r PaymentDateRange, re *http.Request) []Bounty { +func (db database) GetBountiesByDateRange(r PaymentDateRange, re *http.Request) []NewBounty { offset, limit, sortBy, direction, _ := utils.GetPaginationParams(re) keys := re.URL.Query() open := keys.Get("Open") assingned := keys.Get("Assigned") paid := keys.Get("Paid") providers := keys.Get("provider") + workspace := keys.Get("workspace") orderQuery := "" limitQuery := "" + workspaceQuery := "" var statusConditions []string @@ -190,9 +264,12 @@ func (db database) GetBountiesByDateRange(r PaymentDateRange, re *http.Request) } else { orderQuery = " ORDER BY " + sortBy + "" + "DESC" } - if limit > 0 { + if limit > 1 { limitQuery = fmt.Sprintf("LIMIT %d OFFSET %d", limit, offset) } + if workspace != "" { + workspaceQuery = fmt.Sprintf("AND workspace_uuid = '%s'", workspace) + } providerCondition := "" if len(providers) > 0 { @@ -201,10 +278,11 @@ func (db database) GetBountiesByDateRange(r PaymentDateRange, re *http.Request) } query := `SELECT * FROM public.bounty WHERE created >= '` + r.StartDate + `' AND created <= '` + r.EndDate + `'` + providerCondition - allQuery := query + " " + statusQuery + " " + orderQuery + " " + limitQuery + allQuery := query + " " + workspaceQuery + " " + statusQuery + " " + orderQuery + " " + limitQuery - b := []Bounty{} + b := []NewBounty{} db.db.Raw(allQuery).Find(&b) + return b } @@ -214,6 +292,7 @@ func (db database) GetBountiesByDateRangeCount(r PaymentDateRange, re *http.Requ assingned := keys.Get("Assigned") paid := keys.Get("Paid") providers := keys.Get("provider") + workspace := keys.Get("workspace") var statusConditions []string @@ -239,11 +318,15 @@ func (db database) GetBountiesByDateRangeCount(r PaymentDateRange, re *http.Requ providerSlice := strings.Split(providers, ",") providerCondition = " AND owner_id IN ('" + strings.Join(providerSlice, "','") + "')" } + var workspaceQuery string + if workspace != "" { + workspaceQuery = fmt.Sprintf("AND workspace_uuid = '%s'", workspace) + } var count int64 query := `SELECT COUNT(*) FROM public.bounty WHERE created >= '` + r.StartDate + `' AND created <= '` + r.EndDate + `'` + providerCondition - allQuery := query + " " + statusQuery + allQuery := query + " " + workspaceQuery + " " + statusQuery db.db.Raw(allQuery).Scan(&count) return count } diff --git a/db/structs.go b/db/structs.go index c4aba003e..adf07ed70 100644 --- a/db/structs.go +++ b/db/structs.go @@ -429,38 +429,42 @@ type BountyOwners struct { } type BountyData struct { - Bounty + NewBounty BountyId uint `json:"bounty_id"` BountyCreated int64 `json:"bounty_created"` BountyUpdated *time.Time `json:"bounty_updated"` BountyDescription string `json:"bounty_description"` Person - AssigneeAlias string `json:"assignee_alias"` - AssigneeId uint `json:"assignee_id"` - AssigneeImg string `json:"assignee_img"` - AssigneeCreated *time.Time `json:"assignee_created"` - AssigneeUpdated *time.Time `json:"assignee_updated"` - AssigneeDescription string `json:"assignee_description"` - AssigneeRouteHint string `json:"assignee_route_hint"` - BountyOwnerId uint `json:"bounty_owner_id"` - OwnerUuid string `json:"owner_uuid"` - OwnerKey string `json:"owner_key"` - OwnerAlias string `json:"owner_alias"` - OwnerUniqueName string `json:"owner_unique_name"` - OwnerDescription string `json:"owner_description"` - OwnerTags pq.StringArray `gorm:"type:text[]" json:"owner_tags" null` - OwnerImg string `json:"owner_img"` - OwnerCreated *time.Time `json:"owner_created"` - OwnerUpdated *time.Time `json:"owner_updated"` - OwnerLastLogin int64 `json:"owner_last_login"` - OwnerRouteHint string `json:"owner_route_hint"` - OwnerContactKey string `json:"owner_contact_key"` - OwnerPriceToMeet int64 `json:"owner_price_to_meet"` - OwnerTwitterConfirmed bool `json:"owner_twitter_confirmed"` - OrganizationName string `json:"organization_name"` - OrganizationImg string `json:"organization_img"` - WorkspaceUuid string `json:"organization_uuid"` - WorkspaceDescription string `json:"description"` + AssigneeAlias string `json:"assignee_alias"` + AssigneeId uint `json:"assignee_id"` + AssigneeImg string `json:"assignee_img"` + AssigneeCreated *time.Time `json:"assignee_created"` + AssigneeUpdated *time.Time `json:"assignee_updated"` + AssigneeDescription string `json:"assignee_description"` + AssigneeRouteHint string `json:"assignee_route_hint"` + BountyOwnerId uint `json:"bounty_owner_id"` + OwnerUuid string `json:"owner_uuid"` + OwnerKey string `json:"owner_key"` + OwnerAlias string `json:"owner_alias"` + OwnerUniqueName string `json:"owner_unique_name"` + OwnerDescription string `json:"owner_description"` + OwnerTags pq.StringArray `gorm:"type:text[]" json:"owner_tags" null` + OwnerImg string `json:"owner_img"` + OwnerCreated *time.Time `json:"owner_created"` + OwnerUpdated *time.Time `json:"owner_updated"` + OwnerLastLogin int64 `json:"owner_last_login"` + OwnerRouteHint string `json:"owner_route_hint"` + OwnerContactKey string `json:"owner_contact_key"` + OwnerPriceToMeet int64 `json:"owner_price_to_meet"` + OwnerTwitterConfirmed bool `json:"owner_twitter_confirmed"` + OrganizationName string `json:"organization_name"` + OrganizationImg string `json:"organization_img"` + OrganizationUuid string `json:"organization_uuid"` + OrganizationDescription string `json:"description"` + WorkspaceName string `json:"workspace_name"` + WorkspaceImg string `json:"workspace_img"` + WorkspaceUuid string `json:"workspace_uuid"` + WorkspaceDescription string `json:"workspace_description"` } type BountyResponse struct { @@ -559,6 +563,20 @@ type WorkspaceRepositories struct { UpdatedBy string `json:"updated_by"` } +type WorkspaceFeatures struct { + ID uint `json:"id"` + Uuid string `json:"uuid"` + WorkspaceUuid string `json:"workspace_uuid"` + Name string `json:"name"` + Brief string `json:"brief"` + Requirements string `json:"requirements"` + Architecture string `json:"architecture"` + Created *time.Time `json:"created"` + Updated *time.Time `json:"updated"` + CreatedBy string `json:"created_by"` + UpdatedBy string `json:"updated_by"` +} + type BountyRoles struct { Name string `json:"name"` } @@ -599,15 +617,18 @@ type NewBountyBudget struct { } type StatusBudget struct { - OrgUuid string `json:"org_uuid"` - WorkspaceUuid string `json:"workspace_uuid"` - CurrentBudget uint `json:"current_budget"` - OpenBudget uint `json:"open_budget"` - OpenCount int64 `json:"open_count"` - AssignedBudget uint `json:"assigned_budget"` - AssignedCount int64 `json:"assigned_count"` - CompletedBudget uint `json:"completed_budget"` - CompletedCount int64 `json:"completed_count"` + OrgUuid string `json:"org_uuid"` + WorkspaceUuid string `json:"workspace_uuid"` + CurrentBudget uint `json:"current_budget"` + OpenBudget uint `json:"open_budget"` + OpenCount int64 `json:"open_count"` + OpenDifference int `json:"open_difference"` + AssignedBudget uint `json:"assigned_budget"` + AssignedCount int64 `json:"assigned_count"` + AssignedDifference int `json:"assigned_difference"` + CompletedBudget uint `json:"completed_budget"` + CompletedCount int64 `json:"completed_count"` + CompletedDifference int `json:"completed_difference"` } type BudgetInvoiceRequest struct { @@ -811,6 +832,7 @@ type DateDifference struct { type BountyMetrics struct { BountiesPosted int64 `json:"bounties_posted"` BountiesPaid int64 `json:"bounties_paid"` + BountiesAssigned int64 `json:"bounties_assigned"` BountiesPaidPercentage uint `json:"bounties_paid_average"` SatsPosted uint `json:"sats_posted"` SatsPaid uint `json:"sats_paid"` diff --git a/db/workspaces.go b/db/workspaces.go index 406be7d01..0087d9b6e 100644 --- a/db/workspaces.go +++ b/db/workspaces.go @@ -14,8 +14,13 @@ func (db database) GetWorkspaces(r *http.Request) []Workspace { ms := []Workspace{} offset, limit, sortBy, direction, search := utils.GetPaginationParams(r) - // return if like owner_alias, unique_name, or equals pubkey - db.db.Offset(offset).Limit(limit).Order(sortBy+" "+direction+" ").Where("LOWER(name) LIKE ?", "%"+search+"%").Where("deleted != ?", false).Find(&ms) + query := db.db.Model(&ms).Where("LOWER(name) LIKE ?", "%"+search+"%").Where("deleted != ?", true) + + if limit > 1 { + query.Offset(offset).Limit(limit).Order(sortBy + " " + direction + " ") + } + + query.Find(&ms) return ms } @@ -186,28 +191,37 @@ func (db database) GetWorkspaceStatusBudget(workspace_uuid string) StatusBudget var openCount int64 db.db.Model(&Bounty{}).Where("assignee = '' ").Where("paid != true").Count(&openCount) + var openDifference int = int(orgBudget.TotalBudget - openBudget) + var assignedBudget uint db.db.Model(&Bounty{}).Where("assignee != '' ").Where("paid != true").Select("SUM(price)").Row().Scan(&assignedBudget) var assignedCount int64 db.db.Model(&Bounty{}).Where("assignee != '' ").Where("paid != true").Count(&assignedCount) + var assignedDifference int = int(orgBudget.TotalBudget - assignedBudget) + var completedBudget uint db.db.Model(&Bounty{}).Where("completed = true ").Where("paid != true").Select("SUM(price)").Row().Scan(&completedBudget) var completedCount int64 db.db.Model(&Bounty{}).Where("completed = true ").Where("paid != true").Count(&completedCount) + var completedDifference int = int(orgBudget.TotalBudget - completedBudget) + statusBudget := StatusBudget{ - OrgUuid: workspace_uuid, - WorkspaceUuid: workspace_uuid, - CurrentBudget: orgBudget.TotalBudget, - OpenBudget: openBudget, - OpenCount: openCount, - AssignedBudget: assignedBudget, - AssignedCount: assignedCount, - CompletedBudget: completedBudget, - CompletedCount: completedCount, + OrgUuid: workspace_uuid, + WorkspaceUuid: workspace_uuid, + CurrentBudget: orgBudget.TotalBudget, + OpenBudget: openBudget, + OpenCount: openCount, + OpenDifference: openDifference, + AssignedBudget: assignedBudget, + AssignedCount: assignedCount, + AssignedDifference: assignedDifference, + CompletedBudget: completedBudget, + CompletedCount: completedCount, + CompletedDifference: completedDifference, } return statusBudget diff --git a/handlers/features.go b/handlers/features.go new file mode 100644 index 000000000..9c4f9cd68 --- /dev/null +++ b/handlers/features.go @@ -0,0 +1,95 @@ +package handlers + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/go-chi/chi" + "github.com/stakwork/sphinx-tribes/auth" + "github.com/stakwork/sphinx-tribes/db" +) + +type featureHandler struct { + db db.Database +} + +func NewFeatureHandler(database db.Database) *featureHandler { + return &featureHandler{ + db: database, + } +} + +func (oh *featureHandler) CreateOrEditFeatures(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 + } + + features := db.WorkspaceFeatures{} + body, _ := io.ReadAll(r.Body) + r.Body.Close() + err := json.Unmarshal(body, &features) + + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusNotAcceptable) + return + } + + features.CreatedBy = pubKeyFromAuth + + // Validate struct data + err = db.Validate.Struct(features) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + msg := fmt.Sprintf("Error: did not pass validation test : %s", err) + json.NewEncoder(w).Encode(msg) + return + } + + p, err := oh.db.CreateOrEditFeature(features) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(p) +} + +func (oh *featureHandler) GetFeaturesByWorkspaceUuid(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 + } + + uuid := chi.URLParam(r, "uuid") + workspaceFeatures := oh.db.GetFeaturesByWorkspaceUuid(uuid) + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(workspaceFeatures) +} + +func (oh *featureHandler) GetFeatureByUuid(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 + } + + uuid := chi.URLParam(r, "uuid") + workspaceFeature := oh.db.GetFeatureByUuid(uuid) + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(workspaceFeature) +} diff --git a/handlers/metrics.go b/handlers/metrics.go index 2a0140cb5..27f1378b7 100644 --- a/handlers/metrics.go +++ b/handlers/metrics.go @@ -33,6 +33,8 @@ func NewMetricHandler(db db.Database) *metricHandler { func PaymentMetrics(w http.ResponseWriter, r *http.Request) { ctx := r.Context() pubKeyFromAuth, _ := ctx.Value(auth.ContextKey).(string) + keys := r.URL.Query() + workspace := keys.Get("workspace") if pubKeyFromAuth == "" { fmt.Println("no pubkey from auth") @@ -51,7 +53,7 @@ func PaymentMetrics(w http.ResponseWriter, r *http.Request) { return } - sumAmount := db.DB.TotalPaymentsByDateRange(request) + sumAmount := db.DB.TotalPaymentsByDateRange(request, workspace) w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(sumAmount) @@ -114,6 +116,8 @@ func PeopleMetrics(w http.ResponseWriter, r *http.Request) { func (mh *metricHandler) BountyMetrics(w http.ResponseWriter, r *http.Request) { ctx := r.Context() pubKeyFromAuth, _ := ctx.Value(auth.ContextKey).(string) + keys := r.URL.Query() + workspace := keys.Get("workspace") if pubKeyFromAuth == "" { fmt.Println("no pubkey from auth") @@ -146,20 +150,22 @@ func (mh *metricHandler) BountyMetrics(w http.ResponseWriter, r *http.Request) { } } - totalBountiesPosted := mh.db.TotalBountiesPosted(request) - totalBountiesPaid := mh.db.TotalPaidBounties(request) - bountiesPaidPercentage := mh.db.BountiesPaidPercentage(request) - totalSatsPosted := mh.db.TotalSatsPosted(request) - totalSatsPaid := mh.db.TotalSatsPaid(request) - satsPaidPercentage := mh.db.SatsPaidPercentage(request) - avgPaidDays := mh.db.AveragePaidTime(request) - avgCompletedDays := mh.db.AverageCompletedTime(request) - uniqueHuntersPaid := mh.db.TotalHuntersPaid(request) - newHuntersPaid := mh.db.NewHuntersPaid(request) + totalBountiesPosted := mh.db.TotalBountiesPosted(request, workspace) + totalBountiesPaid := mh.db.TotalPaidBounties(request, workspace) + totalBountiesAssigned := mh.db.TotalAssignedBounties(request, workspace) + bountiesPaidPercentage := mh.db.BountiesPaidPercentage(request, workspace) + totalSatsPosted := mh.db.TotalSatsPosted(request, workspace) + totalSatsPaid := mh.db.TotalSatsPaid(request, workspace) + satsPaidPercentage := mh.db.SatsPaidPercentage(request, workspace) + avgPaidDays := mh.db.AveragePaidTime(request, workspace) + avgCompletedDays := mh.db.AverageCompletedTime(request, workspace) + uniqueHuntersPaid := mh.db.TotalHuntersPaid(request, workspace) + newHuntersPaid := mh.db.NewHuntersPaid(request, workspace) bountyMetrics := db.BountyMetrics{ BountiesPosted: totalBountiesPosted, BountiesPaid: totalBountiesPaid, + BountiesAssigned: totalBountiesAssigned, BountiesPaidPercentage: bountiesPaidPercentage, SatsPosted: totalSatsPosted, SatsPaid: totalSatsPaid, @@ -300,46 +306,65 @@ func MetricsCsv(w http.ResponseWriter, r *http.Request) { } } -func (mh *metricHandler) GetMetricsBountiesData(metricBounties []db.Bounty) []db.BountyData { +func GetAdminWorkspaces(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 + } + + workspaces := db.DB.GetWorkspaces(r) + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(workspaces) +} + +func (mh *metricHandler) GetMetricsBountiesData(metricBounties []db.NewBounty) []db.BountyData { var metricBountiesData []db.BountyData for _, bounty := range metricBounties { bountyOwner := mh.db.GetPersonByPubkey(bounty.OwnerID) bountyAssignee := mh.db.GetPersonByPubkey(bounty.Assignee) - organization := mh.db.GetWorkspaceByUuid(bounty.OrgUuid) + workspace := mh.db.GetWorkspaceByUuid(bounty.WorkspaceUuid) bountyData := db.BountyData{ - Bounty: bounty, - BountyId: bounty.ID, - Person: bountyOwner, - BountyCreated: bounty.Created, - BountyDescription: bounty.Description, - BountyUpdated: bounty.Updated, - AssigneeId: bountyAssignee.ID, - AssigneeImg: bountyAssignee.Img, - AssigneeAlias: bountyAssignee.OwnerAlias, - AssigneeDescription: bountyAssignee.Description, - AssigneeRouteHint: bountyAssignee.OwnerRouteHint, - BountyOwnerId: bountyOwner.ID, - OwnerUuid: bountyOwner.Uuid, - OwnerDescription: bountyOwner.Description, - OwnerUniqueName: bountyOwner.UniqueName, - OwnerImg: bountyOwner.Img, - OrganizationName: organization.Name, - OrganizationImg: organization.Img, - WorkspaceUuid: organization.Uuid, - WorkspaceDescription: organization.Description, + NewBounty: bounty, + BountyId: bounty.ID, + Person: bountyOwner, + BountyCreated: bounty.Created, + BountyDescription: bounty.Description, + BountyUpdated: bounty.Updated, + AssigneeId: bountyAssignee.ID, + AssigneeImg: bountyAssignee.Img, + AssigneeAlias: bountyAssignee.OwnerAlias, + AssigneeDescription: bountyAssignee.Description, + AssigneeRouteHint: bountyAssignee.OwnerRouteHint, + BountyOwnerId: bountyOwner.ID, + OwnerUuid: bountyOwner.Uuid, + OwnerDescription: bountyOwner.Description, + OwnerUniqueName: bountyOwner.UniqueName, + OwnerImg: bountyOwner.Img, + OrganizationName: workspace.Name, + OrganizationImg: workspace.Img, + OrganizationUuid: workspace.Uuid, + OrganizationDescription: workspace.Description, + WorkspaceName: workspace.Name, + WorkspaceImg: workspace.Img, + WorkspaceUuid: workspace.Uuid, + WorkspaceDescription: workspace.Description, } metricBountiesData = append(metricBountiesData, bountyData) } return metricBountiesData } -func getMetricsBountyCsv(metricBounties []db.Bounty) []db.MetricsBountyCsv { +func getMetricsBountyCsv(metricBounties []db.NewBounty) []db.MetricsBountyCsv { var metricBountiesCsv []db.MetricsBountyCsv for _, bounty := range metricBounties { bountyOwner := db.DB.GetPersonByPubkey(bounty.OwnerID) bountyAssignee := db.DB.GetPersonByPubkey(bounty.Assignee) - organization := db.DB.GetWorkspaceByUuid(bounty.OrgUuid) + workspace := db.DB.GetWorkspaceByUuid(bounty.WorkspaceUuid) bountyLink := fmt.Sprintf("https://community.sphinx.chat/bounty/%d", bounty.ID) bountyStatus := "Open" @@ -353,7 +378,7 @@ func getMetricsBountyCsv(metricBounties []db.Bounty) []db.MetricsBountyCsv { tm := time.Unix(bounty.Created, 0) bountyCsv := db.MetricsBountyCsv{ DatePosted: &tm, - Organization: organization.Name, + Organization: workspace.Name, BountyAmount: bounty.Price, Provider: bountyOwner.OwnerAlias, Hunter: bountyAssignee.OwnerAlias, diff --git a/handlers/metrics_test.go b/handlers/metrics_test.go index 38695f8ac..d278831a4 100644 --- a/handlers/metrics_test.go +++ b/handlers/metrics_test.go @@ -58,30 +58,34 @@ func TestBountyMetrics(t *testing.T) { db.RedisError = errors.New("redis not initialized") rr := httptest.NewRecorder() handler := http.HandlerFunc(mh.BountyMetrics) + workspace := "test-workspace" + dateRange := db.PaymentDateRange{ StartDate: "1111", EndDate: "2222", } body, _ := json.Marshal(dateRange) - req, err := http.NewRequestWithContext(ctx, http.MethodPost, "/bounty_stats", bytes.NewReader(body)) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, "/bounty_stats?workspace="+workspace, bytes.NewReader(body)) if err != nil { t.Fatal(err) } - mockDb.On("TotalBountiesPosted", dateRange).Return(int64(1)).Once() - mockDb.On("TotalPaidBounties", dateRange).Return(int64(1)).Once() - mockDb.On("BountiesPaidPercentage", dateRange).Return(uint(1)).Once() - mockDb.On("TotalSatsPosted", dateRange).Return(uint(1)).Once() - mockDb.On("TotalSatsPaid", dateRange).Return(uint(1)).Once() - mockDb.On("SatsPaidPercentage", dateRange).Return(uint(1)).Once() - mockDb.On("AveragePaidTime", dateRange).Return(uint(1)).Once() - mockDb.On("AverageCompletedTime", dateRange).Return(uint(1)).Once() - mockDb.On("TotalHuntersPaid", dateRange).Return(int64(1)).Once() - mockDb.On("NewHuntersPaid", dateRange).Return(int64(1)).Once() + mockDb.On("TotalBountiesPosted", dateRange, workspace).Return(int64(1)).Once() + mockDb.On("TotalPaidBounties", dateRange, workspace).Return(int64(1)).Once() + mockDb.On("TotalAssignedBounties", dateRange, workspace).Return(int64(2)).Once() + mockDb.On("BountiesPaidPercentage", dateRange, workspace).Return(uint(1)).Once() + mockDb.On("TotalSatsPosted", dateRange, workspace).Return(uint(1)).Once() + mockDb.On("TotalSatsPaid", dateRange, workspace).Return(uint(1)).Once() + mockDb.On("SatsPaidPercentage", dateRange, workspace).Return(uint(1)).Once() + mockDb.On("AveragePaidTime", dateRange, workspace).Return(uint(1)).Once() + mockDb.On("AverageCompletedTime", dateRange, workspace).Return(uint(1)).Once() + mockDb.On("TotalHuntersPaid", dateRange, workspace).Return(int64(1)).Once() + mockDb.On("NewHuntersPaid", dateRange, workspace).Return(int64(1)).Once() handler.ServeHTTP(rr, req) expectedMetricRes := db.BountyMetrics{ BountiesPosted: 1, BountiesPaid: 1, + BountiesAssigned: 2, BountiesPaidPercentage: 1, SatsPosted: 1, SatsPaid: 1, @@ -148,7 +152,7 @@ func TestMetricsBounties(t *testing.T) { t.Fatal(err) } - bounties := []db.Bounty{ + bounties := []db.NewBounty{ { ID: 1, OwnerID: "owner-1", @@ -194,7 +198,7 @@ func TestMetricsBounties(t *testing.T) { req.URL.RawQuery = "provider=provider1,provider2" // Mock bounties data for multiple providers - bounties := []db.Bounty{ + bounties := []db.NewBounty{ { ID: 1, OwnerID: "provider1", diff --git a/mocks/Database.go b/mocks/Database.go index aeff38189..06093fbe1 100644 --- a/mocks/Database.go +++ b/mocks/Database.go @@ -311,17 +311,17 @@ func (_c *Database_AddUserInvoiceData_Call) RunAndReturn(run func(db.UserInvoice return _c } -// AverageCompletedTime provides a mock function with given fields: r -func (_m *Database) AverageCompletedTime(r db.PaymentDateRange) uint { - ret := _m.Called(r) +// AverageCompletedTime provides a mock function with given fields: r, workspace +func (_m *Database) AverageCompletedTime(r db.PaymentDateRange, workspace string) uint { + ret := _m.Called(r, workspace) if len(ret) == 0 { panic("no return value specified for AverageCompletedTime") } var r0 uint - if rf, ok := ret.Get(0).(func(db.PaymentDateRange) uint); ok { - r0 = rf(r) + if rf, ok := ret.Get(0).(func(db.PaymentDateRange, string) uint); ok { + r0 = rf(r, workspace) } else { r0 = ret.Get(0).(uint) } @@ -336,13 +336,14 @@ type Database_AverageCompletedTime_Call struct { // AverageCompletedTime is a helper method to define mock.On call // - r db.PaymentDateRange -func (_e *Database_Expecter) AverageCompletedTime(r interface{}) *Database_AverageCompletedTime_Call { - return &Database_AverageCompletedTime_Call{Call: _e.mock.On("AverageCompletedTime", r)} +// - workspace string +func (_e *Database_Expecter) AverageCompletedTime(r interface{}, workspace interface{}) *Database_AverageCompletedTime_Call { + return &Database_AverageCompletedTime_Call{Call: _e.mock.On("AverageCompletedTime", r, workspace)} } -func (_c *Database_AverageCompletedTime_Call) Run(run func(r db.PaymentDateRange)) *Database_AverageCompletedTime_Call { +func (_c *Database_AverageCompletedTime_Call) Run(run func(r db.PaymentDateRange, workspace string)) *Database_AverageCompletedTime_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(db.PaymentDateRange)) + run(args[0].(db.PaymentDateRange), args[1].(string)) }) return _c } @@ -352,22 +353,22 @@ func (_c *Database_AverageCompletedTime_Call) Return(_a0 uint) *Database_Average return _c } -func (_c *Database_AverageCompletedTime_Call) RunAndReturn(run func(db.PaymentDateRange) uint) *Database_AverageCompletedTime_Call { +func (_c *Database_AverageCompletedTime_Call) RunAndReturn(run func(db.PaymentDateRange, string) uint) *Database_AverageCompletedTime_Call { _c.Call.Return(run) return _c } -// AveragePaidTime provides a mock function with given fields: r -func (_m *Database) AveragePaidTime(r db.PaymentDateRange) uint { - ret := _m.Called(r) +// AveragePaidTime provides a mock function with given fields: r, workspace +func (_m *Database) AveragePaidTime(r db.PaymentDateRange, workspace string) uint { + ret := _m.Called(r, workspace) if len(ret) == 0 { panic("no return value specified for AveragePaidTime") } var r0 uint - if rf, ok := ret.Get(0).(func(db.PaymentDateRange) uint); ok { - r0 = rf(r) + if rf, ok := ret.Get(0).(func(db.PaymentDateRange, string) uint); ok { + r0 = rf(r, workspace) } else { r0 = ret.Get(0).(uint) } @@ -382,13 +383,14 @@ type Database_AveragePaidTime_Call struct { // AveragePaidTime is a helper method to define mock.On call // - r db.PaymentDateRange -func (_e *Database_Expecter) AveragePaidTime(r interface{}) *Database_AveragePaidTime_Call { - return &Database_AveragePaidTime_Call{Call: _e.mock.On("AveragePaidTime", r)} +// - workspace string +func (_e *Database_Expecter) AveragePaidTime(r interface{}, workspace interface{}) *Database_AveragePaidTime_Call { + return &Database_AveragePaidTime_Call{Call: _e.mock.On("AveragePaidTime", r, workspace)} } -func (_c *Database_AveragePaidTime_Call) Run(run func(r db.PaymentDateRange)) *Database_AveragePaidTime_Call { +func (_c *Database_AveragePaidTime_Call) Run(run func(r db.PaymentDateRange, workspace string)) *Database_AveragePaidTime_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(db.PaymentDateRange)) + run(args[0].(db.PaymentDateRange), args[1].(string)) }) return _c } @@ -398,22 +400,22 @@ func (_c *Database_AveragePaidTime_Call) Return(_a0 uint) *Database_AveragePaidT return _c } -func (_c *Database_AveragePaidTime_Call) RunAndReturn(run func(db.PaymentDateRange) uint) *Database_AveragePaidTime_Call { +func (_c *Database_AveragePaidTime_Call) RunAndReturn(run func(db.PaymentDateRange, string) uint) *Database_AveragePaidTime_Call { _c.Call.Return(run) return _c } -// BountiesPaidPercentage provides a mock function with given fields: r -func (_m *Database) BountiesPaidPercentage(r db.PaymentDateRange) uint { - ret := _m.Called(r) +// BountiesPaidPercentage provides a mock function with given fields: r, workspace +func (_m *Database) BountiesPaidPercentage(r db.PaymentDateRange, workspace string) uint { + ret := _m.Called(r, workspace) if len(ret) == 0 { panic("no return value specified for BountiesPaidPercentage") } var r0 uint - if rf, ok := ret.Get(0).(func(db.PaymentDateRange) uint); ok { - r0 = rf(r) + if rf, ok := ret.Get(0).(func(db.PaymentDateRange, string) uint); ok { + r0 = rf(r, workspace) } else { r0 = ret.Get(0).(uint) } @@ -428,13 +430,14 @@ type Database_BountiesPaidPercentage_Call struct { // BountiesPaidPercentage is a helper method to define mock.On call // - r db.PaymentDateRange -func (_e *Database_Expecter) BountiesPaidPercentage(r interface{}) *Database_BountiesPaidPercentage_Call { - return &Database_BountiesPaidPercentage_Call{Call: _e.mock.On("BountiesPaidPercentage", r)} +// - workspace string +func (_e *Database_Expecter) BountiesPaidPercentage(r interface{}, workspace interface{}) *Database_BountiesPaidPercentage_Call { + return &Database_BountiesPaidPercentage_Call{Call: _e.mock.On("BountiesPaidPercentage", r, workspace)} } -func (_c *Database_BountiesPaidPercentage_Call) Run(run func(r db.PaymentDateRange)) *Database_BountiesPaidPercentage_Call { +func (_c *Database_BountiesPaidPercentage_Call) Run(run func(r db.PaymentDateRange, workspace string)) *Database_BountiesPaidPercentage_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(db.PaymentDateRange)) + run(args[0].(db.PaymentDateRange), args[1].(string)) }) return _c } @@ -444,7 +447,7 @@ func (_c *Database_BountiesPaidPercentage_Call) Return(_a0 uint) *Database_Bount return _c } -func (_c *Database_BountiesPaidPercentage_Call) RunAndReturn(run func(db.PaymentDateRange) uint) *Database_BountiesPaidPercentage_Call { +func (_c *Database_BountiesPaidPercentage_Call) RunAndReturn(run func(db.PaymentDateRange, string) uint) *Database_BountiesPaidPercentage_Call { _c.Call.Return(run) return _c } @@ -927,6 +930,62 @@ func (_c *Database_CreateOrEditBounty_Call) RunAndReturn(run func(db.NewBounty) return _c } +// CreateOrEditFeature provides a mock function with given fields: m +func (_m *Database) CreateOrEditFeature(m db.WorkspaceFeatures) (db.WorkspaceFeatures, error) { + ret := _m.Called(m) + + if len(ret) == 0 { + panic("no return value specified for CreateOrEditFeature") + } + + var r0 db.WorkspaceFeatures + var r1 error + if rf, ok := ret.Get(0).(func(db.WorkspaceFeatures) (db.WorkspaceFeatures, error)); ok { + return rf(m) + } + if rf, ok := ret.Get(0).(func(db.WorkspaceFeatures) db.WorkspaceFeatures); ok { + r0 = rf(m) + } else { + r0 = ret.Get(0).(db.WorkspaceFeatures) + } + + if rf, ok := ret.Get(1).(func(db.WorkspaceFeatures) error); ok { + r1 = rf(m) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Database_CreateOrEditFeature_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateOrEditFeature' +type Database_CreateOrEditFeature_Call struct { + *mock.Call +} + +// CreateOrEditFeature is a helper method to define mock.On call +// - m db.WorkspaceFeatures +func (_e *Database_Expecter) CreateOrEditFeature(m interface{}) *Database_CreateOrEditFeature_Call { + return &Database_CreateOrEditFeature_Call{Call: _e.mock.On("CreateOrEditFeature", m)} +} + +func (_c *Database_CreateOrEditFeature_Call) Run(run func(m db.WorkspaceFeatures)) *Database_CreateOrEditFeature_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(db.WorkspaceFeatures)) + }) + return _c +} + +func (_c *Database_CreateOrEditFeature_Call) Return(_a0 db.WorkspaceFeatures, _a1 error) *Database_CreateOrEditFeature_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Database_CreateOrEditFeature_Call) RunAndReturn(run func(db.WorkspaceFeatures) (db.WorkspaceFeatures, error)) *Database_CreateOrEditFeature_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) @@ -1831,19 +1890,19 @@ func (_c *Database_GetBotsByOwner_Call) RunAndReturn(run func(string) []db.Bot) } // GetBountiesByDateRange provides a mock function with given fields: r, re -func (_m *Database) GetBountiesByDateRange(r db.PaymentDateRange, re *http.Request) []db.Bounty { +func (_m *Database) GetBountiesByDateRange(r db.PaymentDateRange, re *http.Request) []db.NewBounty { ret := _m.Called(r, re) if len(ret) == 0 { panic("no return value specified for GetBountiesByDateRange") } - var r0 []db.Bounty - if rf, ok := ret.Get(0).(func(db.PaymentDateRange, *http.Request) []db.Bounty); ok { + var r0 []db.NewBounty + if rf, ok := ret.Get(0).(func(db.PaymentDateRange, *http.Request) []db.NewBounty); ok { r0 = rf(r, re) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]db.Bounty) + r0 = ret.Get(0).([]db.NewBounty) } } @@ -1869,12 +1928,12 @@ func (_c *Database_GetBountiesByDateRange_Call) Run(run func(r db.PaymentDateRan return _c } -func (_c *Database_GetBountiesByDateRange_Call) Return(_a0 []db.Bounty) *Database_GetBountiesByDateRange_Call { +func (_c *Database_GetBountiesByDateRange_Call) Return(_a0 []db.NewBounty) *Database_GetBountiesByDateRange_Call { _c.Call.Return(_a0) return _c } -func (_c *Database_GetBountiesByDateRange_Call) RunAndReturn(run func(db.PaymentDateRange, *http.Request) []db.Bounty) *Database_GetBountiesByDateRange_Call { +func (_c *Database_GetBountiesByDateRange_Call) RunAndReturn(run func(db.PaymentDateRange, *http.Request) []db.NewBounty) *Database_GetBountiesByDateRange_Call { _c.Call.Return(run) return _c } @@ -2576,6 +2635,100 @@ func (_c *Database_GetCreatedBounties_Call) RunAndReturn(run func(*http.Request) return _c } +// GetFeatureByUuid provides a mock function with given fields: uuid +func (_m *Database) GetFeatureByUuid(uuid string) db.WorkspaceFeatures { + ret := _m.Called(uuid) + + if len(ret) == 0 { + panic("no return value specified for GetFeatureByUuid") + } + + var r0 db.WorkspaceFeatures + if rf, ok := ret.Get(0).(func(string) db.WorkspaceFeatures); ok { + r0 = rf(uuid) + } else { + r0 = ret.Get(0).(db.WorkspaceFeatures) + } + + return r0 +} + +// Database_GetFeatureByUuid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFeatureByUuid' +type Database_GetFeatureByUuid_Call struct { + *mock.Call +} + +// GetFeatureByUuid is a helper method to define mock.On call +// - uuid string +func (_e *Database_Expecter) GetFeatureByUuid(uuid interface{}) *Database_GetFeatureByUuid_Call { + return &Database_GetFeatureByUuid_Call{Call: _e.mock.On("GetFeatureByUuid", uuid)} +} + +func (_c *Database_GetFeatureByUuid_Call) Run(run func(uuid string)) *Database_GetFeatureByUuid_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *Database_GetFeatureByUuid_Call) Return(_a0 db.WorkspaceFeatures) *Database_GetFeatureByUuid_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Database_GetFeatureByUuid_Call) RunAndReturn(run func(string) db.WorkspaceFeatures) *Database_GetFeatureByUuid_Call { + _c.Call.Return(run) + return _c +} + +// GetFeaturesByWorkspaceUuid provides a mock function with given fields: uuid +func (_m *Database) GetFeaturesByWorkspaceUuid(uuid string) []db.WorkspaceFeatures { + ret := _m.Called(uuid) + + if len(ret) == 0 { + panic("no return value specified for GetFeaturesByWorkspaceUuid") + } + + var r0 []db.WorkspaceFeatures + if rf, ok := ret.Get(0).(func(string) []db.WorkspaceFeatures); ok { + r0 = rf(uuid) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]db.WorkspaceFeatures) + } + } + + return r0 +} + +// Database_GetFeaturesByWorkspaceUuid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFeaturesByWorkspaceUuid' +type Database_GetFeaturesByWorkspaceUuid_Call struct { + *mock.Call +} + +// GetFeaturesByWorkspaceUuid is a helper method to define mock.On call +// - uuid string +func (_e *Database_Expecter) GetFeaturesByWorkspaceUuid(uuid interface{}) *Database_GetFeaturesByWorkspaceUuid_Call { + return &Database_GetFeaturesByWorkspaceUuid_Call{Call: _e.mock.On("GetFeaturesByWorkspaceUuid", uuid)} +} + +func (_c *Database_GetFeaturesByWorkspaceUuid_Call) Run(run func(uuid string)) *Database_GetFeaturesByWorkspaceUuid_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *Database_GetFeaturesByWorkspaceUuid_Call) Return(_a0 []db.WorkspaceFeatures) *Database_GetFeaturesByWorkspaceUuid_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Database_GetFeaturesByWorkspaceUuid_Call) RunAndReturn(run func(string) []db.WorkspaceFeatures) *Database_GetFeaturesByWorkspaceUuid_Call { + _c.Call.Return(run) + return _c +} + // GetFilterStatusCount provides a mock function with given fields: func (_m *Database) GetFilterStatusCount() db.FilterStattuCount { ret := _m.Called() @@ -5139,17 +5292,17 @@ func (_c *Database_GetWorkspacesCount_Call) RunAndReturn(run func() int64) *Data return _c } -// NewHuntersPaid provides a mock function with given fields: r -func (_m *Database) NewHuntersPaid(r db.PaymentDateRange) int64 { - ret := _m.Called(r) +// NewHuntersPaid provides a mock function with given fields: r, workspace +func (_m *Database) NewHuntersPaid(r db.PaymentDateRange, workspace string) int64 { + ret := _m.Called(r, workspace) if len(ret) == 0 { panic("no return value specified for NewHuntersPaid") } var r0 int64 - if rf, ok := ret.Get(0).(func(db.PaymentDateRange) int64); ok { - r0 = rf(r) + if rf, ok := ret.Get(0).(func(db.PaymentDateRange, string) int64); ok { + r0 = rf(r, workspace) } else { r0 = ret.Get(0).(int64) } @@ -5164,13 +5317,14 @@ type Database_NewHuntersPaid_Call struct { // NewHuntersPaid is a helper method to define mock.On call // - r db.PaymentDateRange -func (_e *Database_Expecter) NewHuntersPaid(r interface{}) *Database_NewHuntersPaid_Call { - return &Database_NewHuntersPaid_Call{Call: _e.mock.On("NewHuntersPaid", r)} +// - workspace string +func (_e *Database_Expecter) NewHuntersPaid(r interface{}, workspace interface{}) *Database_NewHuntersPaid_Call { + return &Database_NewHuntersPaid_Call{Call: _e.mock.On("NewHuntersPaid", r, workspace)} } -func (_c *Database_NewHuntersPaid_Call) Run(run func(r db.PaymentDateRange)) *Database_NewHuntersPaid_Call { +func (_c *Database_NewHuntersPaid_Call) Run(run func(r db.PaymentDateRange, workspace string)) *Database_NewHuntersPaid_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(db.PaymentDateRange)) + run(args[0].(db.PaymentDateRange), args[1].(string)) }) return _c } @@ -5180,7 +5334,7 @@ func (_c *Database_NewHuntersPaid_Call) Return(_a0 int64) *Database_NewHuntersPa return _c } -func (_c *Database_NewHuntersPaid_Call) RunAndReturn(run func(db.PaymentDateRange) int64) *Database_NewHuntersPaid_Call { +func (_c *Database_NewHuntersPaid_Call) RunAndReturn(run func(db.PaymentDateRange, string) int64) *Database_NewHuntersPaid_Call { _c.Call.Return(run) return _c } @@ -5274,17 +5428,17 @@ func (_c *Database_ProcessAlerts_Call) RunAndReturn(run func(db.Person)) *Databa return _c } -// SatsPaidPercentage provides a mock function with given fields: r -func (_m *Database) SatsPaidPercentage(r db.PaymentDateRange) uint { - ret := _m.Called(r) +// SatsPaidPercentage provides a mock function with given fields: r, workspace +func (_m *Database) SatsPaidPercentage(r db.PaymentDateRange, workspace string) uint { + ret := _m.Called(r, workspace) if len(ret) == 0 { panic("no return value specified for SatsPaidPercentage") } var r0 uint - if rf, ok := ret.Get(0).(func(db.PaymentDateRange) uint); ok { - r0 = rf(r) + if rf, ok := ret.Get(0).(func(db.PaymentDateRange, string) uint); ok { + r0 = rf(r, workspace) } else { r0 = ret.Get(0).(uint) } @@ -5299,13 +5453,14 @@ type Database_SatsPaidPercentage_Call struct { // SatsPaidPercentage is a helper method to define mock.On call // - r db.PaymentDateRange -func (_e *Database_Expecter) SatsPaidPercentage(r interface{}) *Database_SatsPaidPercentage_Call { - return &Database_SatsPaidPercentage_Call{Call: _e.mock.On("SatsPaidPercentage", r)} +// - workspace string +func (_e *Database_Expecter) SatsPaidPercentage(r interface{}, workspace interface{}) *Database_SatsPaidPercentage_Call { + return &Database_SatsPaidPercentage_Call{Call: _e.mock.On("SatsPaidPercentage", r, workspace)} } -func (_c *Database_SatsPaidPercentage_Call) Run(run func(r db.PaymentDateRange)) *Database_SatsPaidPercentage_Call { +func (_c *Database_SatsPaidPercentage_Call) Run(run func(r db.PaymentDateRange, workspace string)) *Database_SatsPaidPercentage_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(db.PaymentDateRange)) + run(args[0].(db.PaymentDateRange), args[1].(string)) }) return _c } @@ -5315,7 +5470,7 @@ func (_c *Database_SatsPaidPercentage_Call) Return(_a0 uint) *Database_SatsPaidP return _c } -func (_c *Database_SatsPaidPercentage_Call) RunAndReturn(run func(db.PaymentDateRange) uint) *Database_SatsPaidPercentage_Call { +func (_c *Database_SatsPaidPercentage_Call) RunAndReturn(run func(db.PaymentDateRange, string) uint) *Database_SatsPaidPercentage_Call { _c.Call.Return(run) return _c } @@ -5468,17 +5623,64 @@ func (_c *Database_SearchTribes_Call) RunAndReturn(run func(string) []db.Tribe) return _c } -// TotalBountiesPosted provides a mock function with given fields: r -func (_m *Database) TotalBountiesPosted(r db.PaymentDateRange) int64 { - ret := _m.Called(r) +// TotalAssignedBounties provides a mock function with given fields: r, workspace +func (_m *Database) TotalAssignedBounties(r db.PaymentDateRange, workspace string) int64 { + ret := _m.Called(r, workspace) + + if len(ret) == 0 { + panic("no return value specified for TotalAssignedBounties") + } + + var r0 int64 + if rf, ok := ret.Get(0).(func(db.PaymentDateRange, string) int64); ok { + r0 = rf(r, workspace) + } else { + r0 = ret.Get(0).(int64) + } + + return r0 +} + +// Database_TotalAssignedBounties_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TotalAssignedBounties' +type Database_TotalAssignedBounties_Call struct { + *mock.Call +} + +// TotalAssignedBounties is a helper method to define mock.On call +// - r db.PaymentDateRange +// - workspace string +func (_e *Database_Expecter) TotalAssignedBounties(r interface{}, workspace interface{}) *Database_TotalAssignedBounties_Call { + return &Database_TotalAssignedBounties_Call{Call: _e.mock.On("TotalAssignedBounties", r, workspace)} +} + +func (_c *Database_TotalAssignedBounties_Call) Run(run func(r db.PaymentDateRange, workspace string)) *Database_TotalAssignedBounties_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(db.PaymentDateRange), args[1].(string)) + }) + return _c +} + +func (_c *Database_TotalAssignedBounties_Call) Return(_a0 int64) *Database_TotalAssignedBounties_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Database_TotalAssignedBounties_Call) RunAndReturn(run func(db.PaymentDateRange, string) int64) *Database_TotalAssignedBounties_Call { + _c.Call.Return(run) + return _c +} + +// TotalBountiesPosted provides a mock function with given fields: r, workspace +func (_m *Database) TotalBountiesPosted(r db.PaymentDateRange, workspace string) int64 { + ret := _m.Called(r, workspace) if len(ret) == 0 { panic("no return value specified for TotalBountiesPosted") } var r0 int64 - if rf, ok := ret.Get(0).(func(db.PaymentDateRange) int64); ok { - r0 = rf(r) + if rf, ok := ret.Get(0).(func(db.PaymentDateRange, string) int64); ok { + r0 = rf(r, workspace) } else { r0 = ret.Get(0).(int64) } @@ -5493,13 +5695,14 @@ type Database_TotalBountiesPosted_Call struct { // TotalBountiesPosted is a helper method to define mock.On call // - r db.PaymentDateRange -func (_e *Database_Expecter) TotalBountiesPosted(r interface{}) *Database_TotalBountiesPosted_Call { - return &Database_TotalBountiesPosted_Call{Call: _e.mock.On("TotalBountiesPosted", r)} +// - workspace string +func (_e *Database_Expecter) TotalBountiesPosted(r interface{}, workspace interface{}) *Database_TotalBountiesPosted_Call { + return &Database_TotalBountiesPosted_Call{Call: _e.mock.On("TotalBountiesPosted", r, workspace)} } -func (_c *Database_TotalBountiesPosted_Call) Run(run func(r db.PaymentDateRange)) *Database_TotalBountiesPosted_Call { +func (_c *Database_TotalBountiesPosted_Call) Run(run func(r db.PaymentDateRange, workspace string)) *Database_TotalBountiesPosted_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(db.PaymentDateRange)) + run(args[0].(db.PaymentDateRange), args[1].(string)) }) return _c } @@ -5509,22 +5712,22 @@ func (_c *Database_TotalBountiesPosted_Call) Return(_a0 int64) *Database_TotalBo return _c } -func (_c *Database_TotalBountiesPosted_Call) RunAndReturn(run func(db.PaymentDateRange) int64) *Database_TotalBountiesPosted_Call { +func (_c *Database_TotalBountiesPosted_Call) RunAndReturn(run func(db.PaymentDateRange, string) int64) *Database_TotalBountiesPosted_Call { _c.Call.Return(run) return _c } -// TotalHuntersPaid provides a mock function with given fields: r -func (_m *Database) TotalHuntersPaid(r db.PaymentDateRange) int64 { - ret := _m.Called(r) +// TotalHuntersPaid provides a mock function with given fields: r, workspace +func (_m *Database) TotalHuntersPaid(r db.PaymentDateRange, workspace string) int64 { + ret := _m.Called(r, workspace) if len(ret) == 0 { panic("no return value specified for TotalHuntersPaid") } var r0 int64 - if rf, ok := ret.Get(0).(func(db.PaymentDateRange) int64); ok { - r0 = rf(r) + if rf, ok := ret.Get(0).(func(db.PaymentDateRange, string) int64); ok { + r0 = rf(r, workspace) } else { r0 = ret.Get(0).(int64) } @@ -5539,13 +5742,14 @@ type Database_TotalHuntersPaid_Call struct { // TotalHuntersPaid is a helper method to define mock.On call // - r db.PaymentDateRange -func (_e *Database_Expecter) TotalHuntersPaid(r interface{}) *Database_TotalHuntersPaid_Call { - return &Database_TotalHuntersPaid_Call{Call: _e.mock.On("TotalHuntersPaid", r)} +// - workspace string +func (_e *Database_Expecter) TotalHuntersPaid(r interface{}, workspace interface{}) *Database_TotalHuntersPaid_Call { + return &Database_TotalHuntersPaid_Call{Call: _e.mock.On("TotalHuntersPaid", r, workspace)} } -func (_c *Database_TotalHuntersPaid_Call) Run(run func(r db.PaymentDateRange)) *Database_TotalHuntersPaid_Call { +func (_c *Database_TotalHuntersPaid_Call) Run(run func(r db.PaymentDateRange, workspace string)) *Database_TotalHuntersPaid_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(db.PaymentDateRange)) + run(args[0].(db.PaymentDateRange), args[1].(string)) }) return _c } @@ -5555,22 +5759,22 @@ func (_c *Database_TotalHuntersPaid_Call) Return(_a0 int64) *Database_TotalHunte return _c } -func (_c *Database_TotalHuntersPaid_Call) RunAndReturn(run func(db.PaymentDateRange) int64) *Database_TotalHuntersPaid_Call { +func (_c *Database_TotalHuntersPaid_Call) RunAndReturn(run func(db.PaymentDateRange, string) int64) *Database_TotalHuntersPaid_Call { _c.Call.Return(run) return _c } -// TotalPaidBounties provides a mock function with given fields: r -func (_m *Database) TotalPaidBounties(r db.PaymentDateRange) int64 { - ret := _m.Called(r) +// TotalPaidBounties provides a mock function with given fields: r, workspace +func (_m *Database) TotalPaidBounties(r db.PaymentDateRange, workspace string) int64 { + ret := _m.Called(r, workspace) if len(ret) == 0 { panic("no return value specified for TotalPaidBounties") } var r0 int64 - if rf, ok := ret.Get(0).(func(db.PaymentDateRange) int64); ok { - r0 = rf(r) + if rf, ok := ret.Get(0).(func(db.PaymentDateRange, string) int64); ok { + r0 = rf(r, workspace) } else { r0 = ret.Get(0).(int64) } @@ -5585,13 +5789,14 @@ type Database_TotalPaidBounties_Call struct { // TotalPaidBounties is a helper method to define mock.On call // - r db.PaymentDateRange -func (_e *Database_Expecter) TotalPaidBounties(r interface{}) *Database_TotalPaidBounties_Call { - return &Database_TotalPaidBounties_Call{Call: _e.mock.On("TotalPaidBounties", r)} +// - workspace string +func (_e *Database_Expecter) TotalPaidBounties(r interface{}, workspace interface{}) *Database_TotalPaidBounties_Call { + return &Database_TotalPaidBounties_Call{Call: _e.mock.On("TotalPaidBounties", r, workspace)} } -func (_c *Database_TotalPaidBounties_Call) Run(run func(r db.PaymentDateRange)) *Database_TotalPaidBounties_Call { +func (_c *Database_TotalPaidBounties_Call) Run(run func(r db.PaymentDateRange, workspace string)) *Database_TotalPaidBounties_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(db.PaymentDateRange)) + run(args[0].(db.PaymentDateRange), args[1].(string)) }) return _c } @@ -5601,22 +5806,22 @@ func (_c *Database_TotalPaidBounties_Call) Return(_a0 int64) *Database_TotalPaid return _c } -func (_c *Database_TotalPaidBounties_Call) RunAndReturn(run func(db.PaymentDateRange) int64) *Database_TotalPaidBounties_Call { +func (_c *Database_TotalPaidBounties_Call) RunAndReturn(run func(db.PaymentDateRange, string) int64) *Database_TotalPaidBounties_Call { _c.Call.Return(run) return _c } -// TotalSatsPaid provides a mock function with given fields: r -func (_m *Database) TotalSatsPaid(r db.PaymentDateRange) uint { - ret := _m.Called(r) +// TotalSatsPaid provides a mock function with given fields: r, workspace +func (_m *Database) TotalSatsPaid(r db.PaymentDateRange, workspace string) uint { + ret := _m.Called(r, workspace) if len(ret) == 0 { panic("no return value specified for TotalSatsPaid") } var r0 uint - if rf, ok := ret.Get(0).(func(db.PaymentDateRange) uint); ok { - r0 = rf(r) + if rf, ok := ret.Get(0).(func(db.PaymentDateRange, string) uint); ok { + r0 = rf(r, workspace) } else { r0 = ret.Get(0).(uint) } @@ -5631,13 +5836,14 @@ type Database_TotalSatsPaid_Call struct { // TotalSatsPaid is a helper method to define mock.On call // - r db.PaymentDateRange -func (_e *Database_Expecter) TotalSatsPaid(r interface{}) *Database_TotalSatsPaid_Call { - return &Database_TotalSatsPaid_Call{Call: _e.mock.On("TotalSatsPaid", r)} +// - workspace string +func (_e *Database_Expecter) TotalSatsPaid(r interface{}, workspace interface{}) *Database_TotalSatsPaid_Call { + return &Database_TotalSatsPaid_Call{Call: _e.mock.On("TotalSatsPaid", r, workspace)} } -func (_c *Database_TotalSatsPaid_Call) Run(run func(r db.PaymentDateRange)) *Database_TotalSatsPaid_Call { +func (_c *Database_TotalSatsPaid_Call) Run(run func(r db.PaymentDateRange, workspace string)) *Database_TotalSatsPaid_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(db.PaymentDateRange)) + run(args[0].(db.PaymentDateRange), args[1].(string)) }) return _c } @@ -5647,22 +5853,22 @@ func (_c *Database_TotalSatsPaid_Call) Return(_a0 uint) *Database_TotalSatsPaid_ return _c } -func (_c *Database_TotalSatsPaid_Call) RunAndReturn(run func(db.PaymentDateRange) uint) *Database_TotalSatsPaid_Call { +func (_c *Database_TotalSatsPaid_Call) RunAndReturn(run func(db.PaymentDateRange, string) uint) *Database_TotalSatsPaid_Call { _c.Call.Return(run) return _c } -// TotalSatsPosted provides a mock function with given fields: r -func (_m *Database) TotalSatsPosted(r db.PaymentDateRange) uint { - ret := _m.Called(r) +// TotalSatsPosted provides a mock function with given fields: r, workspace +func (_m *Database) TotalSatsPosted(r db.PaymentDateRange, workspace string) uint { + ret := _m.Called(r, workspace) if len(ret) == 0 { panic("no return value specified for TotalSatsPosted") } var r0 uint - if rf, ok := ret.Get(0).(func(db.PaymentDateRange) uint); ok { - r0 = rf(r) + if rf, ok := ret.Get(0).(func(db.PaymentDateRange, string) uint); ok { + r0 = rf(r, workspace) } else { r0 = ret.Get(0).(uint) } @@ -5677,13 +5883,14 @@ type Database_TotalSatsPosted_Call struct { // TotalSatsPosted is a helper method to define mock.On call // - r db.PaymentDateRange -func (_e *Database_Expecter) TotalSatsPosted(r interface{}) *Database_TotalSatsPosted_Call { - return &Database_TotalSatsPosted_Call{Call: _e.mock.On("TotalSatsPosted", r)} +// - workspace string +func (_e *Database_Expecter) TotalSatsPosted(r interface{}, workspace interface{}) *Database_TotalSatsPosted_Call { + return &Database_TotalSatsPosted_Call{Call: _e.mock.On("TotalSatsPosted", r, workspace)} } -func (_c *Database_TotalSatsPosted_Call) Run(run func(r db.PaymentDateRange)) *Database_TotalSatsPosted_Call { +func (_c *Database_TotalSatsPosted_Call) Run(run func(r db.PaymentDateRange, workspace string)) *Database_TotalSatsPosted_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(db.PaymentDateRange)) + run(args[0].(db.PaymentDateRange), args[1].(string)) }) return _c } @@ -5693,7 +5900,7 @@ func (_c *Database_TotalSatsPosted_Call) Return(_a0 uint) *Database_TotalSatsPos return _c } -func (_c *Database_TotalSatsPosted_Call) RunAndReturn(run func(db.PaymentDateRange) uint) *Database_TotalSatsPosted_Call { +func (_c *Database_TotalSatsPosted_Call) RunAndReturn(run func(db.PaymentDateRange, string) uint) *Database_TotalSatsPosted_Call { _c.Call.Return(run) return _c } diff --git a/routes/features.go b/routes/features.go new file mode 100644 index 000000000..0b2449399 --- /dev/null +++ b/routes/features.go @@ -0,0 +1,21 @@ +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 FeatureRoutes() chi.Router { + r := chi.NewRouter() + featureHandlers := handlers.NewFeatureHandler(db.DB) + r.Group(func(r chi.Router) { + r.Use(auth.PubKeyContext) + + r.Post("/", featureHandlers.CreateOrEditFeatures) + r.Get("/forworkspace/{uuid}", featureHandlers.GetFeaturesByWorkspaceUuid) + r.Get("/{uuid}", featureHandlers.GetFeatureByUuid) + }) + return r +} diff --git a/routes/index.go b/routes/index.go index 98dc0c162..22090938c 100644 --- a/routes/index.go +++ b/routes/index.go @@ -36,6 +36,7 @@ func NewRouter() *http.Server { r.Mount("/gobounties", BountyRoutes()) r.Mount("/workspaces", WorkspaceRoutes()) r.Mount("/metrics", MetricsRoutes()) + r.Mount("/features", FeatureRoutes()) r.Group(func(r chi.Router) { r.Get("/tribe_by_feed", tribeHandlers.GetFirstTribeByFeed) diff --git a/routes/metrics.go b/routes/metrics.go index e24a1386d..19065e175 100644 --- a/routes/metrics.go +++ b/routes/metrics.go @@ -13,6 +13,8 @@ func MetricsRoutes() chi.Router { r.Group(func(r chi.Router) { r.Use(auth.PubKeyContextSuperAdmin) + r.Get("/workspaces", handlers.GetAdminWorkspaces) + r.Post("/payment", handlers.PaymentMetrics) r.Post("/people", handlers.PeopleMetrics) r.Post("/organization", handlers.WorkspacetMetrics)