diff --git a/db/db.go b/db/db.go index 95adbf7bf..50392ae08 100644 --- a/db/db.go +++ b/db/db.go @@ -1711,6 +1711,12 @@ func (db database) AddInvoice(invoice NewInvoiceList) NewInvoiceList { return invoice } +func (db database) DeleteInvoice(payment_request string) NewInvoiceList { + ms := NewInvoiceList{} + db.db.Model(&NewInvoiceList{}).Where("payment_request = ?", payment_request).Delete(&ms) + return ms +} + func (db database) AddUserInvoiceData(userData UserInvoiceData) UserInvoiceData { db.db.Create(&userData) return userData diff --git a/db/interface.go b/db/interface.go index 17349ebe7..5862ea6c6 100644 --- a/db/interface.go +++ b/db/interface.go @@ -114,6 +114,7 @@ type Database interface { GetWorkspaceInvoicesCount(workspace_uuid string) int64 UpdateInvoice(payment_request string) NewInvoiceList AddInvoice(invoice NewInvoiceList) NewInvoiceList + DeleteInvoice(payment_request string) NewInvoiceList AddUserInvoiceData(userData UserInvoiceData) UserInvoiceData GetUserInvoiceData(payment_request string) UserInvoiceData DeleteUserInvoiceData(payment_request string) UserInvoiceData diff --git a/db/structs.go b/db/structs.go index 1383c3fa9..b906611be 100644 --- a/db/structs.go +++ b/db/structs.go @@ -503,6 +503,7 @@ type Organization struct { Mission string `json:"mission"` Tactics string `json:"tactics"` SchematicUrl string `json:"schematic_url"` + SchematicImg string `json:"schematic_img"` } type Workspace struct { diff --git a/handlers/bounty.go b/handlers/bounty.go index d0dc996a8..f1880abd5 100644 --- a/handlers/bounty.go +++ b/handlers/bounty.go @@ -895,11 +895,6 @@ func (h *bountyHandler) PollInvoice(w http.ResponseWriter, r *http.Request) { req.Header.Set("Content-Type", "application/json") res, _ := h.httpClient.Do(req) - if err != nil { - log.Printf("[bounty] Request Failed: %s", err) - return - } - defer res.Body.Close() body, _ := io.ReadAll(res.Body) @@ -909,11 +904,15 @@ func (h *bountyHandler) PollInvoice(w http.ResponseWriter, r *http.Request) { keysendRes := db.KeysendSuccess{} err = json.Unmarshal(body, &keysendRes) - bounty, err := h.db.GetBountyByCreated(uint(invData.Created)) + if err != nil { + w.WriteHeader(http.StatusForbidden) + json.NewEncoder(w).Encode("Could not decode keysend response") + return + } + bounty, err := h.db.GetBountyByCreated(uint(invData.Created)) if err == nil { now := time.Now() - bounty.Paid = true bounty.PaidDate = &now bounty.Completed = true @@ -925,13 +924,19 @@ func (h *bountyHandler) PollInvoice(w http.ResponseWriter, r *http.Request) { // Unmarshal result keysendError := db.KeysendError{} err = json.Unmarshal(body, &keysendError) - log.Printf("[bounty] Keysend Payment to %s Failed, with Error: %s", invData.UserPubkey, keysendError.Error) + log.Printf("[bounty] Keysend Payment to %s Failed, with Error: %s", invData.UserPubkey, err) } } // Update the invoice status h.db.UpdateInvoice(paymentRequest) } - + } else { + // Cheeck if time has expired + isInvoiceExpired := utils.GetInvoiceExpired(paymentRequest) + // If the invoice has expired and it is not paid delete from the DB + if isInvoiceExpired { + h.db.DeleteInvoice(paymentRequest) + } } w.WriteHeader(http.StatusOK) diff --git a/handlers/workspaces.go b/handlers/workspaces.go index 184ec2bed..e625aec72 100644 --- a/handlers/workspaces.go +++ b/handlers/workspaces.go @@ -652,9 +652,8 @@ func (oh *workspaceHandler) PollBudgetInvoices(w http.ResponseWriter, r *http.Re return } - orgInvoices := oh.db.GetWorkspaceInvoices(uuid) - - for _, inv := range orgInvoices { + workInvoices := oh.db.GetWorkspaceInvoices(uuid) + for _, inv := range workInvoices { invoiceRes, invoiceErr := oh.getLightningInvoice(inv.PaymentRequest) if invoiceErr.Error != "" { @@ -669,6 +668,13 @@ func (oh *workspaceHandler) PollBudgetInvoices(w http.ResponseWriter, r *http.Re // Update the invoice status oh.db.UpdateInvoice(inv.PaymentRequest) } + } else { + // Cheeck if time has expired + isInvoiceExpired := utils.GetInvoiceExpired(inv.PaymentRequest) + // If the invoice has expired and it is not paid delete from the DB + if isInvoiceExpired { + oh.db.DeleteInvoice(inv.PaymentRequest) + } } } diff --git a/mocks/Database.go b/mocks/Database.go index 8bc8365e2..20fba238a 100644 --- a/mocks/Database.go +++ b/mocks/Database.go @@ -1707,6 +1707,52 @@ func (_c *Database_DeleteFeatureStoryByUuid_Call) RunAndReturn(run func(string, return _c } +// DeleteInvoice provides a mock function with given fields: payment_request +func (_m *Database) DeleteInvoice(payment_request string) db.NewInvoiceList { + ret := _m.Called(payment_request) + + if len(ret) == 0 { + panic("no return value specified for DeleteInvoice") + } + + var r0 db.NewInvoiceList + if rf, ok := ret.Get(0).(func(string) db.NewInvoiceList); ok { + r0 = rf(payment_request) + } else { + r0 = ret.Get(0).(db.NewInvoiceList) + } + + return r0 +} + +// Database_DeleteInvoice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteInvoice' +type Database_DeleteInvoice_Call struct { + *mock.Call +} + +// DeleteInvoice is a helper method to define mock.On call +// - payment_request string +func (_e *Database_Expecter) DeleteInvoice(payment_request interface{}) *Database_DeleteInvoice_Call { + return &Database_DeleteInvoice_Call{Call: _e.mock.On("DeleteInvoice", payment_request)} +} + +func (_c *Database_DeleteInvoice_Call) Run(run func(payment_request string)) *Database_DeleteInvoice_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *Database_DeleteInvoice_Call) Return(_a0 db.NewInvoiceList) *Database_DeleteInvoice_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Database_DeleteInvoice_Call) RunAndReturn(run func(string) db.NewInvoiceList) *Database_DeleteInvoice_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) diff --git a/utils/helpers.go b/utils/helpers.go index 189b10ea4..e6a826ae2 100644 --- a/utils/helpers.go +++ b/utils/helpers.go @@ -54,6 +54,23 @@ func GetInvoiceAmount(paymentRequest string) uint { return amount } +func GetInvoiceExpired(paymentRequest string) bool { + decodedInvoice, err := decodepay.Decodepay(paymentRequest) + if err != nil { + fmt.Println("Could not Decode Invoice", err) + return false + } + + timeInUnix := time.Now().Unix() + expiryDate := decodedInvoice.CreatedAt + decodedInvoice.Expiry + + if timeInUnix > int64(expiryDate) { + return true + } else { + return false + } +} + func GetDateDaysDifference(createdDate int64, paidDate *time.Time) int64 { firstDate := time.Unix(createdDate, 0) difference := paidDate.Sub(*&firstDate) diff --git a/utils/helpers_test.go b/utils/helpers_test.go index 046dc7d9d..6fdaa9c31 100644 --- a/utils/helpers_test.go +++ b/utils/helpers_test.go @@ -72,3 +72,9 @@ func TestGetInvoiceAmount(t *testing.T) { amount2 := GetInvoiceAmount(invalidInvoice) assert.Equal(t, uint(0), amount2) } + +func TestGetInvoiceExpired(t *testing.T) { + expiredInvoice := "lnbcrt100u1pnr5gtzpp5r7ew6nzqd9y9w5ktsspftnckxdn3te0y04n9mw7c6hkkrznh4pgsdqhgf6kgem9wssyjmnkda5kxegcqzpgxqyz5vqsp5mc09mpl4l3rllnfl3y902yxa29flke8r4ertqswdcrk766z5nq4q9qyyssq7wteenxtwlxatsd8dqdncqnn6u23jmcpe0d7ne6dcpafwlx9ckr3dp6y4p7sl4j3pq6l93g6vc4w8z04ry9yzwjv6cggm06eecad9psp9dh6u5" + isInvoiceExpired := GetInvoiceExpired(expiredInvoice) + assert.Equal(t, true, isInvoiceExpired) +}