issue reporting service
This commit is contained in:
parent
25230e3fcf
commit
b1c3b73d9c
|
|
@ -36,6 +36,7 @@ import (
|
|||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/currency"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/institutions"
|
||||
issuereporting "github.com/SamuelTariku/FortuneBet-Backend/internal/services/issue_reporting"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/league"
|
||||
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notfication"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||
|
|
@ -218,10 +219,15 @@ func main() {
|
|||
log.Println("Live metrics broadcasted successfully")
|
||||
}
|
||||
|
||||
issueReportingRepo := repository.NewReportedIssueRepository(store)
|
||||
|
||||
issueReportingSvc := issuereporting.New(issueReportingRepo)
|
||||
|
||||
// go httpserver.SetupReportCronJob(reportWorker)
|
||||
|
||||
// Initialize and start HTTP server
|
||||
app := httpserver.NewApp(
|
||||
issueReportingSvc,
|
||||
instSvc,
|
||||
currSvc,
|
||||
cfg.Port,
|
||||
|
|
|
|||
2
db/migrations/000008_issue_reporting.down.sql
Normal file
2
db/migrations/000008_issue_reporting.down.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
DROP TABLE IF EXISTS reported_issues;
|
||||
|
||||
12
db/migrations/000008_issue_reporting.up.sql
Normal file
12
db/migrations/000008_issue_reporting.up.sql
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
CREATE TABLE IF NOT EXISTS reported_issues (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
customer_id BIGINT NOT NULL,
|
||||
subject TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
issue_type TEXT NOT NULL, -- e.g., "deposit", "withdrawal", "bet", "technical"
|
||||
status TEXT NOT NULL DEFAULT 'pending', -- pending, in_progress, resolved, rejected
|
||||
metadata JSONB,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
32
db/query/issue_reporting.sql
Normal file
32
db/query/issue_reporting.sql
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
-- name: CreateReportedIssue :one
|
||||
INSERT INTO reported_issues (
|
||||
customer_id, subject, description, issue_type, metadata
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5
|
||||
)
|
||||
RETURNING *;
|
||||
|
||||
-- name: ListReportedIssues :many
|
||||
SELECT * FROM reported_issues
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $1 OFFSET $2;
|
||||
|
||||
-- name: ListReportedIssuesByCustomer :many
|
||||
SELECT * FROM reported_issues
|
||||
WHERE customer_id = $1
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $2 OFFSET $3;
|
||||
|
||||
-- name: CountReportedIssues :one
|
||||
SELECT COUNT(*) FROM reported_issues;
|
||||
|
||||
-- name: CountReportedIssuesByCustomer :one
|
||||
SELECT COUNT(*) FROM reported_issues WHERE customer_id = $1;
|
||||
|
||||
-- name: UpdateReportedIssueStatus :exec
|
||||
UPDATE reported_issues
|
||||
SET status = $2, updated_at = NOW()
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: DeleteReportedIssue :exec
|
||||
DELETE FROM reported_issues WHERE id = $1;
|
||||
315
docs/docs.go
315
docs/docs.go
|
|
@ -845,6 +845,230 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/issues": {
|
||||
"get": {
|
||||
"description": "Admin endpoint to list all reported issues with pagination",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Issues"
|
||||
],
|
||||
"summary": "Get all reported issues",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Limit",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Offset",
|
||||
"name": "offset",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/domain.ReportedIssue"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Allows a customer to report a new issue related to the betting platform",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Issues"
|
||||
],
|
||||
"summary": "Report an issue",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Issue to report",
|
||||
"name": "issue",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ReportedIssue"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ReportedIssue"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/issues/customer/{customer_id}": {
|
||||
"get": {
|
||||
"description": "Returns all issues reported by a specific customer",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Issues"
|
||||
],
|
||||
"summary": "Get reported issues by a customer",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Customer ID",
|
||||
"name": "customer_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Limit",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Offset",
|
||||
"name": "offset",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/domain.ReportedIssue"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/issues/{issue_id}": {
|
||||
"delete": {
|
||||
"description": "Admin endpoint to delete a reported issue",
|
||||
"tags": [
|
||||
"Issues"
|
||||
],
|
||||
"summary": "Delete a reported issue",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Issue ID",
|
||||
"name": "issue_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/issues/{issue_id}/status": {
|
||||
"patch": {
|
||||
"description": "Admin endpoint to update the status of a reported issue",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Issues"
|
||||
],
|
||||
"summary": "Update issue status",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Issue ID",
|
||||
"name": "issue_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "New issue status (pending, in_progress, resolved, rejected)",
|
||||
"name": "status",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/logs": {
|
||||
"get": {
|
||||
"description": "Fetches the 100 most recent application logs from MongoDB",
|
||||
|
|
@ -1053,6 +1277,33 @@ const docTemplate = `{
|
|||
}
|
||||
},
|
||||
"/api/v1/virtual-game/favorites": {
|
||||
"get": {
|
||||
"description": "Lists the games that the user marked as favorite",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"VirtualGames - Favourites"
|
||||
],
|
||||
"summary": "Get user's favorite games",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/domain.GameRecommendation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Adds a game to the user's favorite games list",
|
||||
"consumes": [
|
||||
|
|
@ -1098,36 +1349,7 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/virtual-games/favorites": {
|
||||
"get": {
|
||||
"description": "Lists the games that the user marked as favorite",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"VirtualGames - Favourites"
|
||||
],
|
||||
"summary": "Get user's favorite games",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/domain.GameRecommendation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/virtual-games/favorites/{gameID}": {
|
||||
"/api/v1/virtual-game/favorites/{gameID}": {
|
||||
"delete": {
|
||||
"description": "Removes a game from the user's favorites",
|
||||
"produces": [
|
||||
|
|
@ -5947,6 +6169,39 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"domain.ReportedIssue": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"customer_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"issue_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"subject": {
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"domain.Response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
|||
|
|
@ -837,6 +837,230 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/issues": {
|
||||
"get": {
|
||||
"description": "Admin endpoint to list all reported issues with pagination",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Issues"
|
||||
],
|
||||
"summary": "Get all reported issues",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Limit",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Offset",
|
||||
"name": "offset",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/domain.ReportedIssue"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Allows a customer to report a new issue related to the betting platform",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Issues"
|
||||
],
|
||||
"summary": "Report an issue",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Issue to report",
|
||||
"name": "issue",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ReportedIssue"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ReportedIssue"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/issues/customer/{customer_id}": {
|
||||
"get": {
|
||||
"description": "Returns all issues reported by a specific customer",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Issues"
|
||||
],
|
||||
"summary": "Get reported issues by a customer",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Customer ID",
|
||||
"name": "customer_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Limit",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Offset",
|
||||
"name": "offset",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/domain.ReportedIssue"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/issues/{issue_id}": {
|
||||
"delete": {
|
||||
"description": "Admin endpoint to delete a reported issue",
|
||||
"tags": [
|
||||
"Issues"
|
||||
],
|
||||
"summary": "Delete a reported issue",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Issue ID",
|
||||
"name": "issue_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/issues/{issue_id}/status": {
|
||||
"patch": {
|
||||
"description": "Admin endpoint to update the status of a reported issue",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Issues"
|
||||
],
|
||||
"summary": "Update issue status",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Issue ID",
|
||||
"name": "issue_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "New issue status (pending, in_progress, resolved, rejected)",
|
||||
"name": "status",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/logs": {
|
||||
"get": {
|
||||
"description": "Fetches the 100 most recent application logs from MongoDB",
|
||||
|
|
@ -1045,6 +1269,33 @@
|
|||
}
|
||||
},
|
||||
"/api/v1/virtual-game/favorites": {
|
||||
"get": {
|
||||
"description": "Lists the games that the user marked as favorite",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"VirtualGames - Favourites"
|
||||
],
|
||||
"summary": "Get user's favorite games",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/domain.GameRecommendation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Adds a game to the user's favorite games list",
|
||||
"consumes": [
|
||||
|
|
@ -1090,36 +1341,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/virtual-games/favorites": {
|
||||
"get": {
|
||||
"description": "Lists the games that the user marked as favorite",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"VirtualGames - Favourites"
|
||||
],
|
||||
"summary": "Get user's favorite games",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/domain.GameRecommendation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/domain.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/virtual-games/favorites/{gameID}": {
|
||||
"/api/v1/virtual-game/favorites/{gameID}": {
|
||||
"delete": {
|
||||
"description": "Removes a game from the user's favorites",
|
||||
"produces": [
|
||||
|
|
@ -5939,6 +6161,39 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"domain.ReportedIssue": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"customer_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"issue_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"subject": {
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"domain.Response": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
|||
|
|
@ -636,6 +636,28 @@ definitions:
|
|||
totalRewardEarned:
|
||||
type: number
|
||||
type: object
|
||||
domain.ReportedIssue:
|
||||
properties:
|
||||
created_at:
|
||||
type: string
|
||||
customer_id:
|
||||
type: integer
|
||||
description:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
issue_type:
|
||||
type: string
|
||||
metadata:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
status:
|
||||
type: string
|
||||
subject:
|
||||
type: string
|
||||
updated_at:
|
||||
type: string
|
||||
type: object
|
||||
domain.Response:
|
||||
properties:
|
||||
data: {}
|
||||
|
|
@ -2140,6 +2162,154 @@ paths:
|
|||
summary: Convert currency
|
||||
tags:
|
||||
- Multi-Currency
|
||||
/api/v1/issues:
|
||||
get:
|
||||
description: Admin endpoint to list all reported issues with pagination
|
||||
parameters:
|
||||
- description: Limit
|
||||
in: query
|
||||
name: limit
|
||||
type: integer
|
||||
- description: Offset
|
||||
in: query
|
||||
name: offset
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/domain.ReportedIssue'
|
||||
type: array
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Get all reported issues
|
||||
tags:
|
||||
- Issues
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Allows a customer to report a new issue related to the betting
|
||||
platform
|
||||
parameters:
|
||||
- description: Issue to report
|
||||
in: body
|
||||
name: issue
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ReportedIssue'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"201":
|
||||
description: Created
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ReportedIssue'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Report an issue
|
||||
tags:
|
||||
- Issues
|
||||
/api/v1/issues/{issue_id}:
|
||||
delete:
|
||||
description: Admin endpoint to delete a reported issue
|
||||
parameters:
|
||||
- description: Issue ID
|
||||
in: path
|
||||
name: issue_id
|
||||
required: true
|
||||
type: integer
|
||||
responses:
|
||||
"204":
|
||||
description: No Content
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Delete a reported issue
|
||||
tags:
|
||||
- Issues
|
||||
/api/v1/issues/{issue_id}/status:
|
||||
patch:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Admin endpoint to update the status of a reported issue
|
||||
parameters:
|
||||
- description: Issue ID
|
||||
in: path
|
||||
name: issue_id
|
||||
required: true
|
||||
type: integer
|
||||
- description: New issue status (pending, in_progress, resolved, rejected)
|
||||
in: body
|
||||
name: status
|
||||
required: true
|
||||
schema:
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
type: object
|
||||
responses:
|
||||
"204":
|
||||
description: No Content
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Update issue status
|
||||
tags:
|
||||
- Issues
|
||||
/api/v1/issues/customer/{customer_id}:
|
||||
get:
|
||||
description: Returns all issues reported by a specific customer
|
||||
parameters:
|
||||
- description: Customer ID
|
||||
in: path
|
||||
name: customer_id
|
||||
required: true
|
||||
type: integer
|
||||
- description: Limit
|
||||
in: query
|
||||
name: limit
|
||||
type: integer
|
||||
- description: Offset
|
||||
in: query
|
||||
name: offset
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/domain.ReportedIssue'
|
||||
type: array
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Get reported issues by a customer
|
||||
tags:
|
||||
- Issues
|
||||
/api/v1/logs:
|
||||
get:
|
||||
description: Fetches the 100 most recent application logs from MongoDB
|
||||
|
|
@ -2274,6 +2444,24 @@ paths:
|
|||
tags:
|
||||
- Reports
|
||||
/api/v1/virtual-game/favorites:
|
||||
get:
|
||||
description: Lists the games that the user marked as favorite
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/domain.GameRecommendation'
|
||||
type: array
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Get user's favorite games
|
||||
tags:
|
||||
- VirtualGames - Favourites
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
|
|
@ -2303,26 +2491,7 @@ paths:
|
|||
summary: Add game to favorites
|
||||
tags:
|
||||
- VirtualGames - Favourites
|
||||
/api/v1/virtual-games/favorites:
|
||||
get:
|
||||
description: Lists the games that the user marked as favorite
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/domain.GameRecommendation'
|
||||
type: array
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/domain.ErrorResponse'
|
||||
summary: Get user's favorite games
|
||||
tags:
|
||||
- VirtualGames - Favourites
|
||||
/api/v1/virtual-games/favorites/{gameID}:
|
||||
/api/v1/virtual-game/favorites/{gameID}:
|
||||
delete:
|
||||
description: Removes a game from the user's favorites
|
||||
parameters:
|
||||
|
|
|
|||
181
gen/db/issue_reporting.sql.go
Normal file
181
gen/db/issue_reporting.sql.go
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.29.0
|
||||
// source: issue_reporting.sql
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const CountReportedIssues = `-- name: CountReportedIssues :one
|
||||
SELECT COUNT(*) FROM reported_issues
|
||||
`
|
||||
|
||||
func (q *Queries) CountReportedIssues(ctx context.Context) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, CountReportedIssues)
|
||||
var count int64
|
||||
err := row.Scan(&count)
|
||||
return count, err
|
||||
}
|
||||
|
||||
const CountReportedIssuesByCustomer = `-- name: CountReportedIssuesByCustomer :one
|
||||
SELECT COUNT(*) FROM reported_issues WHERE customer_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) CountReportedIssuesByCustomer(ctx context.Context, customerID int64) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, CountReportedIssuesByCustomer, customerID)
|
||||
var count int64
|
||||
err := row.Scan(&count)
|
||||
return count, err
|
||||
}
|
||||
|
||||
const CreateReportedIssue = `-- name: CreateReportedIssue :one
|
||||
INSERT INTO reported_issues (
|
||||
customer_id, subject, description, issue_type, metadata
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5
|
||||
)
|
||||
RETURNING id, customer_id, subject, description, issue_type, status, metadata, created_at, updated_at
|
||||
`
|
||||
|
||||
type CreateReportedIssueParams struct {
|
||||
CustomerID int64 `json:"customer_id"`
|
||||
Subject string `json:"subject"`
|
||||
Description string `json:"description"`
|
||||
IssueType string `json:"issue_type"`
|
||||
Metadata []byte `json:"metadata"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateReportedIssue(ctx context.Context, arg CreateReportedIssueParams) (ReportedIssue, error) {
|
||||
row := q.db.QueryRow(ctx, CreateReportedIssue,
|
||||
arg.CustomerID,
|
||||
arg.Subject,
|
||||
arg.Description,
|
||||
arg.IssueType,
|
||||
arg.Metadata,
|
||||
)
|
||||
var i ReportedIssue
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.CustomerID,
|
||||
&i.Subject,
|
||||
&i.Description,
|
||||
&i.IssueType,
|
||||
&i.Status,
|
||||
&i.Metadata,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const DeleteReportedIssue = `-- name: DeleteReportedIssue :exec
|
||||
DELETE FROM reported_issues WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteReportedIssue(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeleteReportedIssue, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const ListReportedIssues = `-- name: ListReportedIssues :many
|
||||
SELECT id, customer_id, subject, description, issue_type, status, metadata, created_at, updated_at FROM reported_issues
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
type ListReportedIssuesParams struct {
|
||||
Limit int32 `json:"limit"`
|
||||
Offset int32 `json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListReportedIssues(ctx context.Context, arg ListReportedIssuesParams) ([]ReportedIssue, error) {
|
||||
rows, err := q.db.Query(ctx, ListReportedIssues, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ReportedIssue
|
||||
for rows.Next() {
|
||||
var i ReportedIssue
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.CustomerID,
|
||||
&i.Subject,
|
||||
&i.Description,
|
||||
&i.IssueType,
|
||||
&i.Status,
|
||||
&i.Metadata,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const ListReportedIssuesByCustomer = `-- name: ListReportedIssuesByCustomer :many
|
||||
SELECT id, customer_id, subject, description, issue_type, status, metadata, created_at, updated_at FROM reported_issues
|
||||
WHERE customer_id = $1
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $2 OFFSET $3
|
||||
`
|
||||
|
||||
type ListReportedIssuesByCustomerParams struct {
|
||||
CustomerID int64 `json:"customer_id"`
|
||||
Limit int32 `json:"limit"`
|
||||
Offset int32 `json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListReportedIssuesByCustomer(ctx context.Context, arg ListReportedIssuesByCustomerParams) ([]ReportedIssue, error) {
|
||||
rows, err := q.db.Query(ctx, ListReportedIssuesByCustomer, arg.CustomerID, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ReportedIssue
|
||||
for rows.Next() {
|
||||
var i ReportedIssue
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.CustomerID,
|
||||
&i.Subject,
|
||||
&i.Description,
|
||||
&i.IssueType,
|
||||
&i.Status,
|
||||
&i.Metadata,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const UpdateReportedIssueStatus = `-- name: UpdateReportedIssueStatus :exec
|
||||
UPDATE reported_issues
|
||||
SET status = $2, updated_at = NOW()
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
type UpdateReportedIssueStatusParams struct {
|
||||
ID int64 `json:"id"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateReportedIssueStatus(ctx context.Context, arg UpdateReportedIssueStatusParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateReportedIssueStatus, arg.ID, arg.Status)
|
||||
return err
|
||||
}
|
||||
|
|
@ -334,6 +334,18 @@ type RefreshToken struct {
|
|||
Revoked bool `json:"revoked"`
|
||||
}
|
||||
|
||||
type ReportedIssue struct {
|
||||
ID int64 `json:"id"`
|
||||
CustomerID int64 `json:"customer_id"`
|
||||
Subject string `json:"subject"`
|
||||
Description string `json:"description"`
|
||||
IssueType string `json:"issue_type"`
|
||||
Status string `json:"status"`
|
||||
Metadata []byte `json:"metadata"`
|
||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
ID int64 `json:"id"`
|
||||
BetOutcomeID int64 `json:"bet_outcome_id"`
|
||||
|
|
|
|||
15
internal/domain/issue_reporting.go
Normal file
15
internal/domain/issue_reporting.go
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type ReportedIssue struct {
|
||||
ID int64 `json:"id"`
|
||||
CustomerID int64 `json:"customer_id"`
|
||||
Subject string `json:"subject"`
|
||||
Description string `json:"description"`
|
||||
IssueType string `json:"issue_type"`
|
||||
Status string `json:"status"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
65
internal/repository/issue_reporting.go
Normal file
65
internal/repository/issue_reporting.go
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
)
|
||||
|
||||
type ReportedIssueRepository interface {
|
||||
CreateReportedIssue(ctx context.Context, arg dbgen.CreateReportedIssueParams) (dbgen.ReportedIssue, error)
|
||||
ListReportedIssues(ctx context.Context, limit, offset int32) ([]dbgen.ReportedIssue, error)
|
||||
ListReportedIssuesByCustomer(ctx context.Context, customerID int64, limit, offset int32) ([]dbgen.ReportedIssue, error)
|
||||
CountReportedIssues(ctx context.Context) (int64, error)
|
||||
CountReportedIssuesByCustomer(ctx context.Context, customerID int64) (int64, error)
|
||||
UpdateReportedIssueStatus(ctx context.Context, id int64, status string) error
|
||||
DeleteReportedIssue(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
type ReportedIssueRepo struct {
|
||||
store *Store
|
||||
}
|
||||
|
||||
func NewReportedIssueRepository(store *Store) ReportedIssueRepository {
|
||||
return &ReportedIssueRepo{store: store}
|
||||
}
|
||||
|
||||
func (s *ReportedIssueRepo) CreateReportedIssue(ctx context.Context, arg dbgen.CreateReportedIssueParams) (dbgen.ReportedIssue, error) {
|
||||
return s.store.queries.CreateReportedIssue(ctx, arg)
|
||||
}
|
||||
|
||||
func (s *ReportedIssueRepo) ListReportedIssues(ctx context.Context, limit, offset int32) ([]dbgen.ReportedIssue, error) {
|
||||
params := dbgen.ListReportedIssuesParams{
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
}
|
||||
return s.store.queries.ListReportedIssues(ctx, params)
|
||||
}
|
||||
|
||||
func (s *ReportedIssueRepo) ListReportedIssuesByCustomer(ctx context.Context, customerID int64, limit, offset int32) ([]dbgen.ReportedIssue, error) {
|
||||
params := dbgen.ListReportedIssuesByCustomerParams{
|
||||
CustomerID: customerID,
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
}
|
||||
return s.store.queries.ListReportedIssuesByCustomer(ctx, params)
|
||||
}
|
||||
|
||||
func (s *ReportedIssueRepo) CountReportedIssues(ctx context.Context) (int64, error) {
|
||||
return s.store.queries.CountReportedIssues(ctx)
|
||||
}
|
||||
|
||||
func (s *ReportedIssueRepo) CountReportedIssuesByCustomer(ctx context.Context, customerID int64) (int64, error) {
|
||||
return s.store.queries.CountReportedIssuesByCustomer(ctx, customerID)
|
||||
}
|
||||
|
||||
func (s *ReportedIssueRepo) UpdateReportedIssueStatus(ctx context.Context, id int64, status string) error {
|
||||
return s.store.queries.UpdateReportedIssueStatus(ctx, dbgen.UpdateReportedIssueStatusParams{
|
||||
ID: id,
|
||||
Status: status,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ReportedIssueRepo) DeleteReportedIssue(ctx context.Context, id int64) error {
|
||||
return s.store.queries.DeleteReportedIssue(ctx, id)
|
||||
}
|
||||
83
internal/services/issue_reporting/service.go
Normal file
83
internal/services/issue_reporting/service.go
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
package issuereporting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
repo repository.ReportedIssueRepository
|
||||
}
|
||||
|
||||
func New(repo repository.ReportedIssueRepository) *Service {
|
||||
return &Service{repo: repo}
|
||||
}
|
||||
|
||||
func (s *Service) CreateReportedIssue(ctx context.Context, issue domain.ReportedIssue) (domain.ReportedIssue, error) {
|
||||
params := dbgen.CreateReportedIssueParams{
|
||||
// Map fields from domain.ReportedIssue to dbgen.CreateReportedIssueParams here.
|
||||
// Example:
|
||||
// Title: issue.Title,
|
||||
// Description: issue.Description,
|
||||
// CustomerID: issue.CustomerID,
|
||||
// Status: issue.Status,
|
||||
// Add other fields as necessary.
|
||||
}
|
||||
dbIssue, err := s.repo.CreateReportedIssue(ctx, params)
|
||||
if err != nil {
|
||||
return domain.ReportedIssue{}, err
|
||||
}
|
||||
// Map dbgen.ReportedIssue to domain.ReportedIssue
|
||||
reportedIssue := domain.ReportedIssue{
|
||||
ID: dbIssue.ID,
|
||||
Subject: dbIssue.Subject,
|
||||
Description: dbIssue.Description,
|
||||
CustomerID: dbIssue.CustomerID,
|
||||
Status: dbIssue.Status,
|
||||
CreatedAt: dbIssue.CreatedAt.Time,
|
||||
UpdatedAt: dbIssue.UpdatedAt.Time,
|
||||
// Add other fields as necessary
|
||||
}
|
||||
return reportedIssue, nil
|
||||
}
|
||||
|
||||
func (s *Service) GetIssuesForCustomer(ctx context.Context, customerID int64, limit, offset int) ([]domain.ReportedIssue, error) {
|
||||
dbIssues, err := s.repo.ListReportedIssuesByCustomer(ctx, customerID, int32(limit), int32(offset))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reportedIssues := make([]domain.ReportedIssue, len(dbIssues))
|
||||
for i, dbIssue := range dbIssues {
|
||||
reportedIssues[i] = domain.ReportedIssue{
|
||||
ID: dbIssue.ID,
|
||||
Subject: dbIssue.Subject,
|
||||
Description: dbIssue.Description,
|
||||
CustomerID: dbIssue.CustomerID,
|
||||
Status: dbIssue.Status,
|
||||
CreatedAt: dbIssue.CreatedAt.Time,
|
||||
UpdatedAt: dbIssue.UpdatedAt.Time,
|
||||
// Add other fields as necessary
|
||||
}
|
||||
}
|
||||
return reportedIssues, nil
|
||||
}
|
||||
|
||||
func (s *Service) GetAllIssues(ctx context.Context, limit, offset int) ([]dbgen.ReportedIssue, error) {
|
||||
return s.repo.ListReportedIssues(ctx, int32(limit), int32(offset))
|
||||
}
|
||||
|
||||
func (s *Service) UpdateIssueStatus(ctx context.Context, issueID int64, status string) error {
|
||||
validStatuses := map[string]bool{"pending": true, "in_progress": true, "resolved": true, "rejected": true}
|
||||
if !validStatuses[status] {
|
||||
return errors.New("invalid status")
|
||||
}
|
||||
return s.repo.UpdateReportedIssueStatus(ctx, issueID, status)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteIssue(ctx context.Context, issueID int64) error {
|
||||
return s.repo.DeleteReportedIssue(ctx, issueID)
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
package issues
|
||||
|
|
@ -1 +0,0 @@
|
|||
package issues
|
||||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/currency"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/institutions"
|
||||
issuereporting "github.com/SamuelTariku/FortuneBet-Backend/internal/services/issue_reporting"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/league"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation"
|
||||
|
|
@ -37,6 +38,7 @@ import (
|
|||
)
|
||||
|
||||
type App struct {
|
||||
issueReportingSvc *issuereporting.Service
|
||||
instSvc *institutions.Service
|
||||
currSvc *currency.Service
|
||||
fiber *fiber.App
|
||||
|
|
@ -70,6 +72,7 @@ type App struct {
|
|||
}
|
||||
|
||||
func NewApp(
|
||||
issueReportingSvc *issuereporting.Service,
|
||||
instSvc *institutions.Service,
|
||||
currSvc *currency.Service,
|
||||
port int, validator *customvalidator.CustomValidator,
|
||||
|
|
@ -113,6 +116,7 @@ func NewApp(
|
|||
}))
|
||||
|
||||
s := &App{
|
||||
issueReportingSvc: issueReportingSvc,
|
||||
instSvc: instSvc,
|
||||
currSvc: currSvc,
|
||||
fiber: app,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/currency"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/institutions"
|
||||
issuereporting "github.com/SamuelTariku/FortuneBet-Backend/internal/services/issue_reporting"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/league"
|
||||
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notfication"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||
|
|
@ -31,6 +32,7 @@ import (
|
|||
)
|
||||
|
||||
type Handler struct {
|
||||
issueReportingSvc *issuereporting.Service
|
||||
instSvc *institutions.Service
|
||||
currSvc *currency.Service
|
||||
logger *slog.Logger
|
||||
|
|
@ -61,6 +63,7 @@ type Handler struct {
|
|||
}
|
||||
|
||||
func New(
|
||||
issueReportingSvc *issuereporting.Service,
|
||||
instSvc *institutions.Service,
|
||||
currSvc *currency.Service,
|
||||
logger *slog.Logger,
|
||||
|
|
@ -90,6 +93,7 @@ func New(
|
|||
mongoLoggerSvc *zap.Logger,
|
||||
) *Handler {
|
||||
return &Handler{
|
||||
issueReportingSvc: issueReportingSvc,
|
||||
instSvc: instSvc,
|
||||
currSvc: currSvc,
|
||||
logger: logger,
|
||||
|
|
|
|||
147
internal/web_server/handlers/issue_reporting.go
Normal file
147
internal/web_server/handlers/issue_reporting.go
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// CreateIssue godoc
|
||||
// @Summary Report an issue
|
||||
// @Description Allows a customer to report a new issue related to the betting platform
|
||||
// @Tags Issues
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param issue body domain.ReportedIssue true "Issue to report"
|
||||
// @Success 201 {object} domain.ReportedIssue
|
||||
// @Failure 400 {object} domain.ErrorResponse
|
||||
// @Failure 500 {object} domain.ErrorResponse
|
||||
// @Router /api/v1/issues [post]
|
||||
func (h *Handler) CreateIssue(c *fiber.Ctx) error {
|
||||
var req domain.ReportedIssue
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||
}
|
||||
|
||||
created, err := h.issueReportingSvc.CreateReportedIssue(c.Context(), req)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusCreated).JSON(created)
|
||||
}
|
||||
|
||||
// GetCustomerIssues godoc
|
||||
// @Summary Get reported issues by a customer
|
||||
// @Description Returns all issues reported by a specific customer
|
||||
// @Tags Issues
|
||||
// @Produce json
|
||||
// @Param customer_id path int true "Customer ID"
|
||||
// @Param limit query int false "Limit"
|
||||
// @Param offset query int false "Offset"
|
||||
// @Success 200 {array} domain.ReportedIssue
|
||||
// @Failure 400 {object} domain.ErrorResponse
|
||||
// @Failure 500 {object} domain.ErrorResponse
|
||||
// @Router /api/v1/issues/customer/{customer_id} [get]
|
||||
func (h *Handler) GetCustomerIssues(c *fiber.Ctx) error {
|
||||
customerID, err := strconv.ParseInt(c.Params("customer_id"), 10, 64)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid customer ID")
|
||||
}
|
||||
|
||||
limit, offset := getPaginationParams(c)
|
||||
|
||||
issues, err := h.issueReportingSvc.GetIssuesForCustomer(c.Context(), customerID, limit, offset)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(issues)
|
||||
}
|
||||
|
||||
// GetAllIssues godoc
|
||||
// @Summary Get all reported issues
|
||||
// @Description Admin endpoint to list all reported issues with pagination
|
||||
// @Tags Issues
|
||||
// @Produce json
|
||||
// @Param limit query int false "Limit"
|
||||
// @Param offset query int false "Offset"
|
||||
// @Success 200 {array} domain.ReportedIssue
|
||||
// @Failure 500 {object} domain.ErrorResponse
|
||||
// @Router /api/v1/issues [get]
|
||||
func (h *Handler) GetAllIssues(c *fiber.Ctx) error {
|
||||
limit, offset := getPaginationParams(c)
|
||||
|
||||
issues, err := h.issueReportingSvc.GetAllIssues(c.Context(), limit, offset)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(issues)
|
||||
}
|
||||
|
||||
// UpdateIssueStatus godoc
|
||||
// @Summary Update issue status
|
||||
// @Description Admin endpoint to update the status of a reported issue
|
||||
// @Tags Issues
|
||||
// @Accept json
|
||||
// @Param issue_id path int true "Issue ID"
|
||||
// @Param status body object{status=string} true "New issue status (pending, in_progress, resolved, rejected)"
|
||||
// @Success 204
|
||||
// @Failure 400 {object} domain.ErrorResponse
|
||||
// @Router /api/v1/issues/{issue_id}/status [patch]
|
||||
func (h *Handler) UpdateIssueStatus(c *fiber.Ctx) error {
|
||||
issueID, err := strconv.ParseInt(c.Params("issue_id"), 10, 64)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid issue ID")
|
||||
}
|
||||
|
||||
var body struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
if err := c.BodyParser(&body); err != nil || body.Status == "" {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid status payload")
|
||||
}
|
||||
|
||||
if err := h.issueReportingSvc.UpdateIssueStatus(c.Context(), issueID, body.Status); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return c.SendStatus(fiber.StatusNoContent)
|
||||
}
|
||||
|
||||
// DeleteIssue godoc
|
||||
// @Summary Delete a reported issue
|
||||
// @Description Admin endpoint to delete a reported issue
|
||||
// @Tags Issues
|
||||
// @Param issue_id path int true "Issue ID"
|
||||
// @Success 204
|
||||
// @Failure 400 {object} domain.ErrorResponse
|
||||
// @Failure 500 {object} domain.ErrorResponse
|
||||
// @Router /api/v1/issues/{issue_id} [delete]
|
||||
func (h *Handler) DeleteIssue(c *fiber.Ctx) error {
|
||||
issueID, err := strconv.ParseInt(c.Params("issue_id"), 10, 64)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid issue ID")
|
||||
}
|
||||
|
||||
if err := h.issueReportingSvc.DeleteIssue(c.Context(), issueID); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return c.SendStatus(fiber.StatusNoContent)
|
||||
}
|
||||
|
||||
func getPaginationParams(c *fiber.Ctx) (limit, offset int) {
|
||||
limit = 20
|
||||
offset = 0
|
||||
|
||||
if l, err := strconv.Atoi(c.Query("limit")); err == nil && l > 0 {
|
||||
limit = l
|
||||
}
|
||||
if o, err := strconv.Atoi(c.Query("offset")); err == nil && o >= 0 {
|
||||
offset = o
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import (
|
|||
|
||||
func (a *App) initAppRoutes() {
|
||||
h := handlers.New(
|
||||
a.issueReportingSvc,
|
||||
a.instSvc,
|
||||
a.currSvc,
|
||||
a.logger,
|
||||
|
|
@ -282,6 +283,13 @@ func (a *App) initAppRoutes() {
|
|||
group.Post("/virtual-game/favorites", a.authMiddleware, h.AddFavorite)
|
||||
group.Delete("/virtual-game/favorites/:gameID", a.authMiddleware, h.RemoveFavorite)
|
||||
group.Get("/virtual-game/favorites", a.authMiddleware, h.ListFavorites)
|
||||
|
||||
//Issue Reporting Routes
|
||||
group.Post("/issues", a.authMiddleware, a.OnlyAdminAndAbove, h.CreateIssue)
|
||||
group.Get("/issues/customer/:customer_id", a.authMiddleware, a.OnlyAdminAndAbove, h.GetCustomerIssues)
|
||||
group.Get("/issues", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllIssues)
|
||||
group.Patch("/issues/:issue_id/status", a.authMiddleware, a.OnlyAdminAndAbove, h.UpdateIssueStatus)
|
||||
group.Delete("/issues/:issue_id", a.authMiddleware, a.OnlyAdminAndAbove, h.DeleteIssue)
|
||||
}
|
||||
|
||||
///user/profile get
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user