Commit edc8524d authored by Waleed Gadelkareem's avatar Waleed Gadelkareem 🐎
Browse files

add checkout and refund actions

parent bbbfe9c3
package commands
import (
"fmt"
"fmt"
"backend/kernel"
"backend/services"
h "github.com/gadelkareem/go-helpers"
"backend/kernel"
"backend/models"
"backend/services"
h "github.com/gadelkareem/go-helpers"
)
type admin struct {
s *services.UserService
s *services.UserService
}
func NewAdmin(s *services.UserService) kernel.Command {
return &admin{s: s}
return &admin{s: s}
}
func (c *admin) Run(args []string) {
if len(args) > 1 && args[0] == "make-admin" {
c.makeAdmin(args[1])
} else {
c.Help()
}
if len(args) > 1 {
if args[0] == "make-admin" {
c.makeAdmin(args[1])
}
switch args[0] {
case "make-admin":
c.makeAdmin(args[1])
return
case "activate-user":
c.activateUser(args[1])
return
}
} else {
c.Help()
}
}
func (c *admin) makeAdmin(username string) {
err := c.s.MakeAdmin(username)
h.PanicOnError(err)
fmt.Printf("User %s is now an admin\n", username)
err := c.s.MakeAdmin(username)
h.PanicOnError(err)
fmt.Printf("User %s is now an admin\n", username)
}
func (c *admin) activateUser(username string) {
u, err := c.s.FindUser(&models.User{Username: username}, true)
h.PanicOnError(err)
u.Activate()
err = c.s.Save(u)
h.PanicOnError(err)
fmt.Printf("User %s is now an active\n", username)
}
func (c *admin) Help() {
fmt.Printf(`
fmt.Printf(`
Usage: skeleton admin [options] ...
Controls users
......
......@@ -86,7 +86,7 @@ func (c *dev) delUser(username string) {
func (c *dev) Help() {
fmt.Printf(`
Usage: proxycloud dev [options] ...
Usage: skeleton dev [options] ...
Dev commands
......
package controllers
import (
"bytes"
"encoding/json"
"net/http"
"backend/di"
"backend/internal"
"backend/kernel"
"backend/models"
"backend/utils/paginator"
"github.com/astaxie/beego/logs"
"github.com/google/jsonapi"
"bytes"
"encoding/json"
"net/http"
"backend/di"
"backend/internal"
"backend/kernel"
"backend/models"
"backend/utils/paginator"
"github.com/astaxie/beego/logs"
"github.com/google/jsonapi"
)
type (
ApiController struct {
BaseController
}
ApiController struct {
BaseController
}
)
func NewApiController(c *di.Container) ApiController {
return ApiController{BaseController: BaseController{C: c}}
return ApiController{BaseController: BaseController{C: c}}
}
func (c *ApiController) Prepare() {
c.EnableRender = false
c.BaseController.Prepare()
kernel.SetCORS(c.Ctx)
c.setUser()
u := c.Ctx.Request.URL.String()
method := c.Ctx.Request.Method
c.rbac(u, method)
c.rateLimit(u, method)
c.EnableRender = false
c.BaseController.Prepare()
kernel.SetCORS(c.Ctx)
c.setUser()
u := c.Ctx.Request.URL.String()
method := c.Ctx.Request.Method
c.rbac(u, method)
c.rateLimit(u, method)
}
func (c *ApiController) rateLimit(u, method string) {
ip := c.requestIP()
b, err := c.C.RateLimiter.IsRateExceeded(c.user, ip, u, method)
c.handleError(err)
if b {
logs.Error("rate exceeded for %s %s %s", ip, method, c.Ctx.Request.URL)
c.handleError(internal.ErrTooManyRequests)
}
ip := c.requestIP()
b, err := c.C.RateLimiter.IsRateExceeded(c.user, ip, u, method)
c.handleError(err)
if b {
logs.Error("rate exceeded for %s %s %s", ip, method, c.Ctx.Request.URL)
c.handleError(internal.ErrTooManyRequests)
}
}
func (c *ApiController) rbac(u, method string) {
if !c.C.RBAC.CanAccessRoute(c.user, u, method) {
if c.user == nil {
c.handleError(internal.ErrInvalidJWTToken)
}
c.handleError(internal.ErrForbidden)
}
if !c.C.RBAC.CanAccessRoute(c.user, u, method) {
if c.user == nil {
c.handleError(internal.ErrInvalidJWTToken)
}
c.handleError(internal.ErrForbidden)
}
}
func (c *ApiController) parseRequest(m interface{}) {
b := bytes.NewBuffer(c.Ctx.Input.RequestBody)
if err := jsonapi.UnmarshalPayload(b, m); err != nil {
logs.Error("Error parsing request %s err: %s", c.Ctx.Request.URL, err)
c.handleError(internal.ErrInvalidRequest)
}
b := bytes.NewBuffer(c.Ctx.Input.RequestBody)
if err := jsonapi.UnmarshalPayload(b, m); err != nil {
logs.Error("Error parsing request %s err: %s", c.Ctx.Request.URL, err)
c.handleError(internal.ErrInvalidRequest)
}
}
func (c *ApiController) validate(m interface{}) {
v := kernel.Validation()
b, err := v.Valid(m)
if err != nil {
c.handleError(err)
}
if !b {
vErrs := make(map[string]interface{})
for _, e := range v.Errors {
vErrs[e.Key] = e.Error()
}
c.handleError(internal.ValidationErrors(vErrs))
}
return
v := kernel.Validation()
b, err := v.Valid(m)
if err != nil {
c.handleError(err)
}
if !b {
vErrs := make(map[string]interface{})
for _, e := range v.Errors {
vErrs[e.Key] = e.Error()
}
c.handleError(internal.ValidationErrors(vErrs))
}
return
}
func (c *ApiController) parseJSONRequest(m interface{}) {
if err := json.Unmarshal(c.Ctx.Input.RequestBody, m); err != nil {
logs.Error("Error parsing request %s err: %s", c.Ctx.Request.URL, err)
c.handleError(internal.ErrInvalidRequest)
}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, m); err != nil {
logs.Error("Error parsing request %s err: %s", c.Ctx.Request.URL, err)
c.handleError(internal.ErrInvalidRequest)
}
}
func (c *ApiController) jsonMany(p *paginator.Paginator) {
c.Ctx.Output.Header("Content-Type", jsonapi.MediaType)
c.Ctx.Output.SetStatus(http.StatusOK)
for _, m := range p.Models {
if ml, k := m.(models.BaseInterface); k {
ml.Sanitize()
}
}
pl, err := jsonapi.Marshal(p.Models)
c.handleError(err)
py := pl.(*jsonapi.ManyPayload)
py.Links = p.Links()
py.Meta = p.Meta()
b := bytes.NewBuffer(nil)
err = json.NewEncoder(b).Encode(py)
c.handleError(err)
err = c.Ctx.Output.Body(b.Bytes())
c.handleError(err)
c.StopRun()
c.Ctx.Output.Header("Content-Type", jsonapi.MediaType)
c.Ctx.Output.SetStatus(http.StatusOK)
for _, m := range p.Models {
if ml, k := m.(models.BaseInterface); k {
ml.Sanitize()
}
}
pl, err := jsonapi.Marshal(p.Models)
c.handleError(err)
py := pl.(*jsonapi.ManyPayload)
py.Links = p.Links()
py.Meta = p.Meta()
b := bytes.NewBuffer(nil)
err = json.NewEncoder(b).Encode(py)
c.handleError(err)
err = c.Ctx.Output.Body(b.Bytes())
c.handleError(err)
c.StopRun()
}
func (c *ApiController) json(m interface{}) {
c.Ctx.Output.Header("Content-Type", jsonapi.MediaType)
c.Ctx.Output.SetStatus(http.StatusOK)
c.Ctx.Output.Header("Content-Type", jsonapi.MediaType)
c.Ctx.Output.SetStatus(http.StatusOK)
if ml, k := m.(models.BaseInterface); k {
ml.Sanitize()
}
if ml, k := m.(models.BaseInterface); k {
ml.Sanitize()
}
b := bytes.NewBuffer(nil)
err := jsonapi.MarshalPayload(b, m)
c.handleError(err)
b := bytes.NewBuffer(nil)
err := jsonapi.MarshalPayload(b, m)
c.handleError(err)
err = c.Ctx.Output.Body(b.Bytes())
c.handleError(err)
err = c.Ctx.Output.Body(b.Bytes())
c.handleError(err)
c.StopRun()
c.StopRun()
}
func (c *ApiController) handleError(err error) {
if err == nil {
return
}
internalErr, k := err.(internal.Error)
if !k || internalErr == nil {
logs.Error("Error: %s", err)
internalErr = internal.ErrInternalError
}
c.Ctx.Output.Header("Content-Type", jsonapi.MediaType)
c.Ctx.Output.SetStatus(internalErr.Status())
b := bytes.NewBuffer(nil)
e := jsonapi.MarshalErrors(b, []*jsonapi.ErrorObject{internalErr.Object()})
if e != nil {
logs.Error("Error unmarshal errors: %s", e)
}
e = c.Ctx.Output.Body(b.Bytes())
if e != nil {
logs.Error("Error writing body: %s", e)
}
go c.log(internalErr.Status())
c.StopRun()
if err == nil {
return
}
internalErr, k := err.(internal.Error)
if !k || internalErr == nil {
logs.Error("Error: %s", err)
internalErr = internal.ErrInternalError
}
c.Ctx.Output.Header("Content-Type", jsonapi.MediaType)
c.Ctx.Output.SetStatus(internalErr.Status())
b := bytes.NewBuffer(nil)
e := jsonapi.MarshalErrors(b, []*jsonapi.ErrorObject{internalErr.Object()})
if e != nil {
logs.Error("Error unmarshal errors: %s", e)
}
e = c.Ctx.Output.Body(b.Bytes())
if e != nil {
logs.Error("Error writing body: %s", e)
}
go c.log(internalErr.Status())
c.StopRun()
}
func (c *ApiController) SendStatus(s int) {
c.Ctx.ResponseWriter.WriteHeader(s)
go c.log(s)
c.StopRun()
c.Ctx.ResponseWriter.WriteHeader(s)
go c.log(s)
c.StopRun()
}
func (c *ApiController) setUser() {
tk := c.Ctx.Input.Header("Authorization")
if tk == "" {
return
}
p := c.C.JWTService.ParseHeader(tk)
if p == nil {
return
}
var err error
c.user, err = c.C.UserService.UserById(p.UserId)
if err != nil {
logs.Error("Could not find user: %s", err)
}
tk := c.Ctx.Input.Header("Authorization")
if tk == "" {
return
}
p := c.C.JWTService.ParseHeader(tk)
if p == nil {
return
}
var err error
c.user, err = c.C.UserService.UserById(p.UserId)
if err != nil {
logs.Error("Could not find user: %s", err)
}
}
func (c *ApiController) auditLog(l models.Log) {
l.IP = c.requestIP()
l.UserAgent = c.requestUserAgent()
if l.Request == "" {
l.Request = string(c.Ctx.Input.RequestBody)
}
if l.UserID != 0 && c.user != nil && l.UserID != c.user.ID {
l.AdminID = c.user.ID
}
if l.UserID == 0 && c.user != nil {
l.UserID = c.user.ID
}
c.C.AuditLogService.AddAuditLog(l)
l.IP = c.requestIP()
l.UserAgent = c.requestUserAgent()
if l.Request == "" {
l.Request = string(c.Ctx.Input.RequestBody)
}
if l.UserID != 0 && c.user != nil && l.UserID != c.user.ID {
l.AdminID = c.user.ID
}
if l.UserID == 0 && c.user != nil {
l.UserID = c.user.ID
}
c.C.AuditLogService.AddAuditLog(l)
}
func (c *ApiController) paginator(size int) *paginator.Paginator {
page := map[string]int{"size": size, "after": 1}
err := c.Ctx.Input.Bind(&page, "page")
c.logOnError(err)
return paginator.NewPaginator(page, c.readString("sort"), c.readString("filter"), c.Ctx.Input.URI())
page := map[string]int{"size": size, "after": 1}
err := c.Ctx.Input.Bind(&page, "page")
c.logOnError(err)
return paginator.NewPaginator(page, c.readString("sort"), c.readString("filter"), c.Ctx.Input.URI())
}
func (c *ApiController) AssertCustomer(id string) {
if id != c.user.CustomerID {
c.handleError(internal.ErrForbidden)
}
if id != c.user.CustomerID {
c.handleError(internal.ErrForbidden)
}
}
package controllers
import (
"backend/kernel"
"backend/kernel"
)
type AuditLogController struct {
ApiController
ApiController
}
// @router / [get]
func (c *AuditLogController) GetAuditLogs() {
p, err := c.C.AuditLogService.PaginateAuditLogs(c.paginator(kernel.ListLimit))
c.handleError(err)
p, err := c.C.AuditLogService.PaginateAuditLogs(c.paginator(kernel.ListLimit))
c.handleError(err)
c.jsonMany(p)
c.jsonMany(p)
}
package controllers_test
import (
"net/http"
"reflect"
"testing"
"backend/kernel"
"backend/models"
"backend/tests"
"github.com/brianvoe/gofakeit/v6"
"github.com/stretchr/testify/assert"
"net/http"
"reflect"
"testing"
"backend/kernel"
"backend/models"
"backend/tests"
"github.com/brianvoe/gofakeit/v6"
"github.com/stretchr/testify/assert"
)
func TestAuditLogController_GetAuditLogs(t *testing.T) {
l := models.Log{}
gofakeit.Struct(&l)
tests.C.AuditLogService.AddAuditLog(l)
gofakeit.Struct(&l)
tests.C.AuditLogService.AddAuditLog(l)
_, tk := tests.AdminWithToken(t)
w, _ := tests.ApiRequest(&tests.Request{T: t,
Method: http.MethodGet,
URI: "/audit-logs",
AuthToken: tk,
Status: http.StatusOK})
auditLogs, payload := tests.ParseModels(t, reflect.TypeOf(new(models.AuditLog)), w.Body)
assert.NotEmpty(t, auditLogs)
totalAuditLogs, err := tests.C.AuditLogRepository.Count()
tests.FailOnErr(t, err)
count := totalAuditLogs
if totalAuditLogs > kernel.ListLimit {
count = kernel.ListLimit
}
assert.Len(t, auditLogs, count)
assert.NotEmpty(t, auditLogs[0].(*models.AuditLog).ID)
assert.NotEmpty(t, auditLogs[1].(*models.AuditLog).Log.Action)
m := *payload.Meta
assert.Equal(t, totalAuditLogs, int(m["page"].(map[string]interface{})["total"].(float64)))
assert.Equal(t, kernel.ListLimit, int(m["page"].(map[string]interface{})["size"].(float64)))
// test admin access only
_, tk = tests.UserWithToken(true)
w, _ = tests.ApiRequest(&tests.Request{T: t,
Method: http.MethodGet,
URI: "/audit-logs",
AuthToken: tk,
Status: http.StatusForbidden})
l := models.Log{}
gofakeit.Struct(&l)
tests.C.AuditLogService.AddAuditLog(l)
gofakeit.Struct(&l)
tests.C.AuditLogService.AddAuditLog(l)
_, tk := tests.AdminWithToken(t)
w, _ := tests.ApiRequest(&tests.Request{T: t,
Method: http.MethodGet,
URI: "/audit-logs",
AuthToken: tk,
Status: http.StatusOK})
auditLogs, payload := tests.ParseModels(t, reflect.TypeOf(new(models.AuditLog)), w.Body)
assert.NotEmpty(t, auditLogs)
totalAuditLogs, err := tests.C.AuditLogRepository.Count()
tests.FailOnErr(t, err)
count := totalAuditLogs
if totalAuditLogs > kernel.ListLimit {
count = kernel.ListLimit
}
assert.Len(t, auditLogs, count)
assert.NotEmpty(t, auditLogs[0].(*models.AuditLog).ID)
assert.NotEmpty(t, auditLogs[1].(*models.AuditLog).Log.Action)
m := *payload.Meta
assert.Equal(t, totalAuditLogs, int(m["page"].(map[string]interface{})["total"].(float64)))
assert.Equal(t, kernel.ListLimit, int(m["page"].(map[string]interface{})["size"].(float64)))
// test admin access only
_, tk = tests.UserWithToken(true)
w, _ = tests.ApiRequest(&tests.Request{T: t,
Method: http.MethodGet,
URI: "/audit-logs",
AuthToken: tk,
Status: http.StatusForbidden})
}
package controllers
import (
"fmt"
"net/http"
"fmt"
"net/http"
"backend/internal"
"backend/kernel"