From a46bfdef47035e490f5a3976871c2c25362eb4f9 Mon Sep 17 00:00:00 2001 From: kene Date: Sat, 30 Nov 2024 19:32:28 +0100 Subject: [PATCH] feat: admin endpoints for transactions retrieval --- docs/docs.go | 63 +++++++++++++++++++++++++++++++++++++--- docs/swagger.json | 63 +++++++++++++++++++++++++++++++++++++--- docs/swagger.yaml | 44 +++++++++++++++++++++++++--- routes/admin_books.go | 4 +-- routes/admin_payments.go | 52 +++++++++++++++++++++++++++++++++ routes/admin_users.go | 5 ++-- routes/routers.go | 18 +++++++++--- routes/utils.go | 8 +++++ schemas/wallet.go | 21 +++++++++----- 9 files changed, 249 insertions(+), 29 deletions(-) create mode 100644 routes/admin_payments.go diff --git a/docs/docs.go b/docs/docs.go index 0cd5c3f..28e8280 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -36,7 +36,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "Admin" + "Admin | Books" ], "summary": "List Books with Pagination", "parameters": [ @@ -85,7 +85,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "Admin" + "Admin | Books" ], "summary": "List Book Contracts with Pagination", "parameters": [ @@ -131,6 +131,61 @@ const docTemplate = `{ } } }, + "/admin/payments/transactions": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieves a list of current transactions with support for pagination and optional filtering based on username.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Admin | Payments" + ], + "summary": "Latest Transactions with Pagination", + "parameters": [ + { + "type": "string", + "description": "Username to filter by", + "name": "username", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "Current page", + "name": "page", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved list of transactions", + "schema": { + "$ref": "#/definitions/schemas.TransactionsResponseSchema" + } + }, + "400": { + "description": "Invalid query parameters", + "schema": { + "$ref": "#/definitions/utils.ErrorResponse" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/utils.ErrorResponse" + } + } + } + } + }, "/admin/users": { "get": { "security": [ @@ -146,7 +201,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "Admin" + "Admin | Users" ], "summary": "List Users with Pagination", "parameters": [ @@ -206,7 +261,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "Admin" + "Admin | Users" ], "summary": "Update User Role", "parameters": [ diff --git a/docs/swagger.json b/docs/swagger.json index 0e2c7d4..7fcbdc5 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -29,7 +29,7 @@ "application/json" ], "tags": [ - "Admin" + "Admin | Books" ], "summary": "List Books with Pagination", "parameters": [ @@ -78,7 +78,7 @@ "application/json" ], "tags": [ - "Admin" + "Admin | Books" ], "summary": "List Book Contracts with Pagination", "parameters": [ @@ -124,6 +124,61 @@ } } }, + "/admin/payments/transactions": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieves a list of current transactions with support for pagination and optional filtering based on username.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Admin | Payments" + ], + "summary": "Latest Transactions with Pagination", + "parameters": [ + { + "type": "string", + "description": "Username to filter by", + "name": "username", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "Current page", + "name": "page", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved list of transactions", + "schema": { + "$ref": "#/definitions/schemas.TransactionsResponseSchema" + } + }, + "400": { + "description": "Invalid query parameters", + "schema": { + "$ref": "#/definitions/utils.ErrorResponse" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/utils.ErrorResponse" + } + } + } + } + }, "/admin/users": { "get": { "security": [ @@ -139,7 +194,7 @@ "application/json" ], "tags": [ - "Admin" + "Admin | Users" ], "summary": "List Users with Pagination", "parameters": [ @@ -199,7 +254,7 @@ "application/json" ], "tags": [ - "Admin" + "Admin | Users" ], "summary": "Update User Role", "parameters": [ diff --git a/docs/swagger.yaml b/docs/swagger.yaml index ebe5bf1..69b42e2 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1366,7 +1366,7 @@ paths: - BearerAuth: [] summary: List Books with Pagination tags: - - Admin + - Admin | Books /admin/contracts: get: consumes: @@ -1407,7 +1407,43 @@ paths: - BearerAuth: [] summary: List Book Contracts with Pagination tags: - - Admin + - Admin | Books + /admin/payments/transactions: + get: + consumes: + - application/json + description: Retrieves a list of current transactions with support for pagination + and optional filtering based on username. + parameters: + - description: Username to filter by + in: query + name: username + type: string + - default: 1 + description: Current page + in: query + name: page + type: integer + produces: + - application/json + responses: + "200": + description: Successfully retrieved list of transactions + schema: + $ref: '#/definitions/schemas.TransactionsResponseSchema' + "400": + description: Invalid query parameters + schema: + $ref: '#/definitions/utils.ErrorResponse' + "500": + description: Internal server error + schema: + $ref: '#/definitions/utils.ErrorResponse' + security: + - BearerAuth: [] + summary: Latest Transactions with Pagination + tags: + - Admin | Payments /admin/users: get: consumes: @@ -1447,7 +1483,7 @@ paths: - BearerAuth: [] summary: List Users with Pagination tags: - - Admin + - Admin | Users /admin/users/user: put: consumes: @@ -1483,7 +1519,7 @@ paths: - BearerAuth: [] summary: Update User Role tags: - - Admin + - Admin | Users /auth/facebook: post: description: |- diff --git a/routes/admin_books.go b/routes/admin_books.go index b9075e2..7f7cf5a 100644 --- a/routes/admin_books.go +++ b/routes/admin_books.go @@ -10,7 +10,7 @@ import ( // @Summary List Books with Pagination // @Description Retrieves a list of books with support for pagination and optional filtering based on book title. -// @Tags Admin +// @Tags Admin | Books // @Accept json // @Produce json // @Param page query int false "Current Page" default(1) @@ -41,7 +41,7 @@ func (ep Endpoint) AdminGetBooks(c *fiber.Ctx) error { // @Summary List Book Contracts with Pagination // @Description Retrieves a list of book contracts with support for pagination and optional filtering based on contract status. -// @Tags Admin +// @Tags Admin | Books // @Accept json // @Produce json // @Param page query int false "Current Page" default(1) diff --git a/routes/admin_payments.go b/routes/admin_payments.go new file mode 100644 index 0000000..323924f --- /dev/null +++ b/routes/admin_payments.go @@ -0,0 +1,52 @@ +package routes + +import ( + "github.com/LitPad/backend/models" + "github.com/LitPad/backend/schemas" + "github.com/gofiber/fiber/v2" + "github.com/google/uuid" +) + +// @Summary Latest Transactions with Pagination +// @Description Retrieves a list of current transactions with support for pagination and optional filtering based on username. +// @Tags Admin | Payments +// @Accept json +// @Produce json +// @Param username query string false "Username to filter by" +// @Param page query int false "Current page" default(1) +// @Success 200 {object} schemas.TransactionsResponseSchema "Successfully retrieved list of transactions" +// @Failure 400 {object} utils.ErrorResponse "Invalid query parameters" +// @Failure 500 {object} utils.ErrorResponse "Internal server error" +// @Router /admin/payments/transactions [get] +// @Security BearerAuth +func (ep Endpoint) AdminGetTransactions(c *fiber.Ctx) error { + db := ep.DB + username := GetQueryValue(c, "username") + transactions := []models.Transaction{} + query := db + if username != nil { + user := models.User{Username: *username} + db.Take(&user, user) + if user.ID != uuid.Nil { + query = query.Where("user_id = ?", user.ID) + } else { + // Ensure the query empties + query = query.Where("user_id = ?", uuid.Nil) + } + } + + query.Joins("Coin").Joins("SubscriptionPlan").Order("created_at DESC").Find(&transactions) + // Paginate and return transactions + paginatedData, paginatedTransactions, err := PaginateQueryset(transactions, c, 100) + if err != nil { + return c.Status(400).JSON(err) + } + transactions = paginatedTransactions.([]models.Transaction) + response := schemas.TransactionsResponseSchema{ + ResponseSchema: ResponseMessage("Transactions fetched successfully"), + Data: schemas.TransactionsResponseDataSchema{ + PaginatedResponseDataSchema: *paginatedData, + }.Init(transactions), + } + return c.Status(200).JSON(response) +} \ No newline at end of file diff --git a/routes/admin_users.go b/routes/admin_users.go index 64171e3..41f6367 100644 --- a/routes/admin_users.go +++ b/routes/admin_users.go @@ -11,7 +11,7 @@ import ( var truthy = true // @Summary List Users with Pagination // @Description Retrieves a list of user profiles with support for pagination and optional filtering based on user account type. -// @Tags Admin +// @Tags Admin | Users // @Accept json // @Produce json // @Param account_type query string false "Type of user to filter by" Enums(READER, WRITER, ADMIN) @@ -47,7 +47,6 @@ func (ep Endpoint) AdminGetUsers(c *fiber.Ctx) error { return c.Status(400).JSON(err) } users = paginatedUsers.([]models.User) - response := schemas.UserProfilesResponseSchema{ ResponseSchema: ResponseMessage("Profiles fetched successfully"), Data: schemas.UserProfilesResponseDataSchema{ @@ -60,7 +59,7 @@ func (ep Endpoint) AdminGetUsers(c *fiber.Ctx) error { // @Summary Update User Role // @Description Updates the account type of a specified user. -// @Tags Admin +// @Tags Admin | Users // @Accept json // @Produce json // @Param data body schemas.UpdateUserRoleSchema true "User role update data" diff --git a/routes/routers.go b/routes/routers.go index 64d8a04..5bc18b1 100644 --- a/routes/routers.go +++ b/routes/routers.go @@ -107,15 +107,25 @@ func SetupRoutes(app *fiber.App, db *gorm.DB, ws *internetcomputer.WalletService // Internet Computer walletRouter.Get("balance", walletService.GetOnChainBalance) - // Admin Routes (6) + // ADMIN ROUTES (7) adminRouter := api.Group("/admin") + // Admin Users + adminRouter.Put("/", endpoint.AdminMiddleware, endpoint.UpdateProfile) adminRouter.Get("/users", endpoint.AdminMiddleware, endpoint.AdminGetUsers) - adminRouter.Get("/books", endpoint.AdminMiddleware, endpoint.AdminGetBooks) - adminRouter.Get("/waitlist", endpoint.AdminMiddleware, endpoint.AdminGetWaitlist) adminRouter.Put("/users/user", endpoint.AdminMiddleware, endpoint.AdminUpdateUser) - adminRouter.Put("/", endpoint.AdminMiddleware, endpoint.UpdateProfile) + + // Admin Books (2) + adminRouter.Get("/books", endpoint.AdminMiddleware, endpoint.AdminGetBooks) adminRouter.Get("/contracts", endpoint.AdminMiddleware, endpoint.AdminGetBookContracts) + // Admin Waitlist (1) + adminRouter.Get("/waitlist", endpoint.AdminMiddleware, endpoint.AdminGetWaitlist) + + // Admin Payments (1) + adminRouter.Get("/payments/transactions", endpoint.AdminMiddleware, endpoint.AdminGetTransactions) + // -------------------------------------------------------------------------------- + + // Waitlist Routes (1) api.Post("/waitlist", endpoint.AddToWaitlist) // Register Sockets (1) diff --git a/routes/utils.go b/routes/utils.go index 2320ef0..75b2dec 100644 --- a/routes/utils.go +++ b/routes/utils.go @@ -154,3 +154,11 @@ func IsAmongUserType(target string) bool { } return false } + +func GetQueryValue (c *fiber.Ctx, key string) *string { + value := c.Query(key, "") + if value == "" { + return nil + } + return &value +} \ No newline at end of file diff --git a/schemas/wallet.go b/schemas/wallet.go index 30196da..a3723f1 100644 --- a/schemas/wallet.go +++ b/schemas/wallet.go @@ -1,6 +1,8 @@ package schemas import ( + "time" + "github.com/LitPad/backend/models" "github.com/LitPad/backend/models/choices" "github.com/google/uuid" @@ -22,8 +24,8 @@ func (c CoinSchema) Init(coin models.Coin) CoinSchema { type BuyCoinSchema struct { // PaymentType choices.PaymentType `json:"payment_type" validate:"required,payment_type_validator" example:"STRIPE"` // This should be stripe by default - Quantity int `json:"quantity" validate:"required" example:"2"` - CoinID uuid.UUID `json:"coin_id" validate:"required" example:"19e8bd22-fab1-4bb4-ba82-77c41bea6b99"` + Quantity int `json:"quantity" validate:"required" example:"2"` + CoinID uuid.UUID `json:"coin_id" validate:"required" example:"19e8bd22-fab1-4bb4-ba82-77c41bea6b99"` } type TransactionSchema struct { @@ -36,7 +38,9 @@ type TransactionSchema struct { Amount decimal.Decimal `json:"amount" example:"10.35"` AmountTotal decimal.Decimal `json:"amount_total" example:"30.35"` PaymentStatus choices.PaymentStatus `json:"payment_status"` - ClientSecret string `json:"client_secret"` + ClientSecret string `json:"client_secret"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } func (t TransactionSchema) Init(transaction models.Transaction) TransactionSchema { @@ -52,13 +56,14 @@ func (t TransactionSchema) Init(transaction models.Transaction) TransactionSchem t.PaymentPurpose = transaction.PaymentPurpose if t.PaymentPurpose == choices.PP_COINS { t.Amount = transaction.Coin.Price - } else if t.PaymentPurpose == choices.PP_SUB { + } else { t.Amount = transaction.SubscriptionPlan.Amount } t.AmountTotal = t.Amount.Mul(decimal.NewFromInt(int64(transaction.Quantity))) - t.Quantity = transaction.Quantity t.ClientSecret = transaction.ClientSecret + t.CreatedAt = transaction.CreatedAt + t.UpdatedAt = transaction.UpdatedAt return t } @@ -90,8 +95,8 @@ type TransactionsResponseDataSchema struct { func (t TransactionsResponseDataSchema) Init(transactions []models.Transaction) TransactionsResponseDataSchema { // Set Initial Data transactionItems := []TransactionSchema{} - for i := range transactions { - transactionItems = append(transactionItems, TransactionSchema{}.Init(transactions[i])) + for _, transaction := range transactions { + transactionItems = append(transactionItems, TransactionSchema{}.Init(transaction)) } t.Items = transactionItems return t @@ -134,6 +139,6 @@ type SubscriptionPlanResponseSchema struct { } type CreateSubscriptionSchema struct { - SubType choices.SubscriptionTypeChoice `json:"subtype" validate:"required,subscription_type_validator"` + SubType choices.SubscriptionTypeChoice `json:"subtype" validate:"required,subscription_type_validator"` PaymentMethodToken string `json:"payment_method_token" validate:"required"` }