Compare commits
3 Commits
1338447524
...
a170085b89
| Author | SHA1 | Date | |
|---|---|---|---|
| a170085b89 | |||
| 78989eb9f8 | |||
| 22d5773c7c |
165
docs/docs.go
165
docs/docs.go
@@ -14,8 +14,8 @@ const docTemplate = `{
|
||||
"email": "sandro@cazzaniga.fr"
|
||||
},
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
"url": "https://opensource.org/licenses/MIT"
|
||||
"name": "GPLv3",
|
||||
"url": "https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
},
|
||||
"version": "{{.Version}}"
|
||||
},
|
||||
@@ -24,7 +24,7 @@ const docTemplate = `{
|
||||
"paths": {
|
||||
"/api": {
|
||||
"get": {
|
||||
"description": "Get information about the API endpoints and version",
|
||||
"description": "Retrieve API metadata, available endpoints, authentication details, and response formats",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -45,7 +45,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/account": {
|
||||
"/api/auth/account": {
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
@@ -91,7 +91,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/account/confirm": {
|
||||
"/api/auth/account/confirm": {
|
||||
"post": {
|
||||
"description": "Confirm account deletion using the provided token",
|
||||
"consumes": [
|
||||
@@ -143,7 +143,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/confirm": {
|
||||
"/api/auth/confirm": {
|
||||
"get": {
|
||||
"description": "Confirm user email with verification token",
|
||||
"consumes": [
|
||||
@@ -187,7 +187,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/email": {
|
||||
"/api/auth/email": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
@@ -256,7 +256,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/forgot-password": {
|
||||
"/api/auth/forgot-password": {
|
||||
"post": {
|
||||
"description": "Send a password reset email using a username or email",
|
||||
"consumes": [
|
||||
@@ -296,7 +296,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/login": {
|
||||
"/api/auth/login": {
|
||||
"post": {
|
||||
"description": "Authenticate user with username and password",
|
||||
"consumes": [
|
||||
@@ -354,7 +354,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/logout": {
|
||||
"/api/auth/logout": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
@@ -388,7 +388,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/me": {
|
||||
"/api/auth/me": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -428,7 +428,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/password": {
|
||||
"/api/auth/password": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
@@ -485,7 +485,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/refresh": {
|
||||
"/api/auth/refresh": {
|
||||
"post": {
|
||||
"description": "Use a refresh token to get a new access token. This endpoint allows clients to obtain a new access token using a valid refresh token without requiring user credentials.",
|
||||
"consumes": [
|
||||
@@ -543,7 +543,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/register": {
|
||||
"/api/auth/register": {
|
||||
"post": {
|
||||
"description": "Register a new user with username, email and password",
|
||||
"consumes": [
|
||||
@@ -595,7 +595,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/resend-verification": {
|
||||
"/api/auth/resend-verification": {
|
||||
"post": {
|
||||
"description": "Send a new verification email to the provided address",
|
||||
"consumes": [
|
||||
@@ -665,7 +665,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/reset-password": {
|
||||
"/api/auth/reset-password": {
|
||||
"post": {
|
||||
"description": "Reset a user's password using a reset token",
|
||||
"consumes": [
|
||||
@@ -711,7 +711,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/revoke": {
|
||||
"/api/auth/revoke": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
@@ -768,7 +768,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/revoke-all": {
|
||||
"/api/auth/revoke-all": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
@@ -808,7 +808,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/username": {
|
||||
"/api/auth/username": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
@@ -871,55 +871,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/health": {
|
||||
"get": {
|
||||
"description": "Check if the API is healthy with comprehensive database monitoring",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"api"
|
||||
],
|
||||
"summary": "Health check",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Health check successful",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/metrics": {
|
||||
"get": {
|
||||
"description": "Get application metrics including post stats, user stats, vote stats, and database performance metrics",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"api"
|
||||
],
|
||||
"summary": "Get metrics",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Application metrics with vote statistics and database monitoring",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/posts": {
|
||||
"/api/posts": {
|
||||
"get": {
|
||||
"description": "Get a list of posts with pagination. Posts include vote statistics (up_votes, down_votes, score) and current user's vote status.",
|
||||
"consumes": [
|
||||
@@ -1037,7 +989,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/posts/search": {
|
||||
"/api/posts/search": {
|
||||
"get": {
|
||||
"description": "Search posts by title or content keywords. Results include vote statistics and current user's vote status.",
|
||||
"consumes": [
|
||||
@@ -1094,7 +1046,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/posts/title": {
|
||||
"/api/posts/title": {
|
||||
"get": {
|
||||
"description": "Fetch the HTML title for the provided URL",
|
||||
"consumes": [
|
||||
@@ -1144,7 +1096,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/posts/{id}": {
|
||||
"/api/posts/{id}": {
|
||||
"get": {
|
||||
"description": "Get a post by ID with vote statistics and current user's vote status",
|
||||
"consumes": [
|
||||
@@ -1333,7 +1285,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/posts/{id}/vote": {
|
||||
"/api/posts/{id}/vote": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -1515,7 +1467,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/posts/{id}/votes": {
|
||||
"/api/posts/{id}/votes": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -1570,7 +1522,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users": {
|
||||
"/api/users": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -1687,7 +1639,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/{id}": {
|
||||
"/api/users/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -1748,7 +1700,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/{id}/posts": {
|
||||
"/api/users/{id}/posts": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -1816,6 +1768,52 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/health": {
|
||||
"get": {
|
||||
"description": "Check the API health status along with database connectivity details",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"api"
|
||||
],
|
||||
"summary": "Health check",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Health check successful",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.CommonResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/metrics": {
|
||||
"get": {
|
||||
"description": "Retrieve application metrics including aggregate counts and database performance data",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"api"
|
||||
],
|
||||
"summary": "Get metrics",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Application metrics retrieved successfully",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.CommonResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
@@ -1906,6 +1904,21 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.CommonResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {},
|
||||
"error": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"success": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.ConfirmAccountDeletionRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"schemes": ["http"],
|
||||
"schemes": [
|
||||
"http"
|
||||
],
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "Goyco is a Y Combinator-style news aggregation platform API.",
|
||||
@@ -9,8 +11,8 @@
|
||||
"email": "sandro@cazzaniga.fr"
|
||||
},
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
"url": "https://opensource.org/licenses/MIT"
|
||||
"name": "GPLv3",
|
||||
"url": "https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
},
|
||||
"version": "0.1.0"
|
||||
},
|
||||
@@ -19,10 +21,16 @@
|
||||
"paths": {
|
||||
"/api": {
|
||||
"get": {
|
||||
"description": "Get information about the API endpoints and version",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["api"],
|
||||
"description": "Retrieve API metadata, available endpoints, authentication details, and response formats",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"api"
|
||||
],
|
||||
"summary": "Get API information",
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -34,7 +42,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/account": {
|
||||
"/api/auth/account": {
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
@@ -42,9 +50,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Initiate the deletion process for the authenticated user's account",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Request account deletion",
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -74,12 +88,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/account/confirm": {
|
||||
"/api/auth/account/confirm": {
|
||||
"post": {
|
||||
"description": "Confirm account deletion using the provided token",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Confirm account deletion",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -120,12 +140,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/confirm": {
|
||||
"/api/auth/confirm": {
|
||||
"get": {
|
||||
"description": "Confirm user email with verification token",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Confirm email address",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -158,7 +184,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/email": {
|
||||
"/api/auth/email": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
@@ -166,9 +192,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Update the authenticated user's email address",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Update email address",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -221,12 +253,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/forgot-password": {
|
||||
"/api/auth/forgot-password": {
|
||||
"post": {
|
||||
"description": "Send a password reset email using a username or email",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Request a password reset",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -255,12 +293,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/login": {
|
||||
"/api/auth/login": {
|
||||
"post": {
|
||||
"description": "Authenticate user with username and password",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Login user",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -307,7 +351,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/logout": {
|
||||
"/api/auth/logout": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
@@ -315,9 +359,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Logout the authenticated user and invalidate their session",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Logout user",
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -335,7 +385,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/me": {
|
||||
"/api/auth/me": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -343,9 +393,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Retrieve the authenticated user's profile information",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Get current user profile",
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -369,7 +425,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/password": {
|
||||
"/api/auth/password": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
@@ -377,9 +433,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Update the authenticated user's password",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Update password",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -420,12 +482,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/refresh": {
|
||||
"/api/auth/refresh": {
|
||||
"post": {
|
||||
"description": "Use a refresh token to get a new access token. This endpoint allows clients to obtain a new access token using a valid refresh token without requiring user credentials.",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Refresh access token",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -472,12 +540,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/register": {
|
||||
"/api/auth/register": {
|
||||
"post": {
|
||||
"description": "Register a new user with username, email and password",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Register a new user",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -518,12 +592,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/resend-verification": {
|
||||
"/api/auth/resend-verification": {
|
||||
"post": {
|
||||
"description": "Send a new verification email to the provided address",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Resend verification email",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -582,12 +662,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/reset-password": {
|
||||
"/api/auth/reset-password": {
|
||||
"post": {
|
||||
"description": "Reset a user's password using a reset token",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Reset password",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -622,7 +708,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/revoke": {
|
||||
"/api/auth/revoke": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
@@ -630,9 +716,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Revoke a specific refresh token. This endpoint allows authenticated users to invalidate a specific refresh token, preventing its future use.",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Revoke refresh token",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -673,7 +765,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/revoke-all": {
|
||||
"/api/auth/revoke-all": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
@@ -681,9 +773,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Revoke all refresh tokens for the authenticated user. This endpoint allows users to invalidate all their refresh tokens at once, effectively logging them out from all devices.",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Revoke all user tokens",
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -707,7 +805,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/username": {
|
||||
"/api/auth/username": {
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
@@ -715,9 +813,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Update the authenticated user's username",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["auth"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"summary": "Update username",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -764,48 +868,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/health": {
|
||||
"get": {
|
||||
"description": "Check if the API is healthy with comprehensive database monitoring",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["api"],
|
||||
"summary": "Health check",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Health check successful",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/metrics": {
|
||||
"get": {
|
||||
"description": "Get application metrics including post stats, user stats, vote stats, and database performance metrics",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["api"],
|
||||
"summary": "Get metrics",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Application metrics with vote statistics and database monitoring",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/posts": {
|
||||
"/api/posts": {
|
||||
"get": {
|
||||
"description": "Get a list of posts with pagination. Posts include vote statistics (up_votes, down_votes, score) and current user's vote status.",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["posts"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"posts"
|
||||
],
|
||||
"summary": "Get posts",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -851,9 +925,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Create a new post with URL and optional title",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["posts"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"posts"
|
||||
],
|
||||
"summary": "Create a new post",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -906,12 +986,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/posts/search": {
|
||||
"/api/posts/search": {
|
||||
"get": {
|
||||
"description": "Search posts by title or content keywords. Results include vote statistics and current user's vote status.",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["posts"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"posts"
|
||||
],
|
||||
"summary": "Search posts",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -957,12 +1043,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/posts/title": {
|
||||
"/api/posts/title": {
|
||||
"get": {
|
||||
"description": "Fetch the HTML title for the provided URL",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["posts"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"posts"
|
||||
],
|
||||
"summary": "Fetch title from URL",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -1001,12 +1093,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/posts/{id}": {
|
||||
"/api/posts/{id}": {
|
||||
"get": {
|
||||
"description": "Get a post by ID with vote statistics and current user's vote status",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["posts"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"posts"
|
||||
],
|
||||
"summary": "Get a single post",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -1051,9 +1149,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Update the title and content of a post owned by the authenticated user",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["posts"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"posts"
|
||||
],
|
||||
"summary": "Update a post",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -1119,9 +1223,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Delete a post owned by the authenticated user",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["posts"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"posts"
|
||||
],
|
||||
"summary": "Delete a post",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -1172,7 +1282,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/posts/{id}/vote": {
|
||||
"/api/posts/{id}/vote": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -1180,9 +1290,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Retrieve the current user's vote for a specific post. Requires authentication and returns the vote type if it exists.\n\n**Response:**\n- If vote exists: Returns vote details with contextual metadata (including `is_anonymous`)\n- If no vote: Returns success with null vote data and metadata",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["votes"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"votes"
|
||||
],
|
||||
"summary": "Get current user's vote",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -1227,9 +1343,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Vote on a post (upvote, downvote, or remove vote). Authentication is required; the vote is performed on behalf of the current user.\n\n**Vote Types:**\n- `up`: Upvote the post\n- `down`: Downvote the post\n- `none`: Remove existing vote\n\n**Response includes:**\n- Updated post vote counts (up_votes, down_votes, score)\n- Success message",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["votes"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"votes"
|
||||
],
|
||||
"summary": "Cast a vote on a post",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -1289,9 +1411,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Remove a vote from a post for the authenticated user. This is equivalent to casting a vote with type 'none'.",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["votes"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"votes"
|
||||
],
|
||||
"summary": "Remove a vote",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -1336,7 +1464,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/posts/{id}/votes": {
|
||||
"/api/posts/{id}/votes": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -1344,9 +1472,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Retrieve all votes for a specific post. Returns all votes in a single format.\n\n**Authentication Required:** Yes (Bearer token)\n\n**Response includes:**\n- Array of all votes\n- Total vote count\n- Each vote includes type and unauthenticated status",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["votes"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"votes"
|
||||
],
|
||||
"summary": "Get post votes",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -1385,7 +1519,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users": {
|
||||
"/api/users": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -1393,9 +1527,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Retrieve a paginated list of users",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["users"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"users"
|
||||
],
|
||||
"summary": "List users",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -1441,9 +1581,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Create a new user account",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["users"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"users"
|
||||
],
|
||||
"summary": "Create user",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -1490,7 +1636,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/{id}": {
|
||||
"/api/users/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -1498,9 +1644,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Retrieve a specific user by ID",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["users"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"users"
|
||||
],
|
||||
"summary": "Get user",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -1545,7 +1697,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/{id}/posts": {
|
||||
"/api/users/{id}/posts": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -1553,9 +1705,15 @@
|
||||
}
|
||||
],
|
||||
"description": "Retrieve posts created by a specific user",
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["users"],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"users"
|
||||
],
|
||||
"summary": "Get user posts",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -1607,6 +1765,52 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/health": {
|
||||
"get": {
|
||||
"description": "Check the API health status along with database connectivity details",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"api"
|
||||
],
|
||||
"summary": "Health check",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Health check successful",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.CommonResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/metrics": {
|
||||
"get": {
|
||||
"description": "Retrieve application metrics including aggregate counts and database performance data",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"api"
|
||||
],
|
||||
"summary": "Get metrics",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Application metrics retrieved successfully",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handlers.CommonResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
@@ -1697,6 +1901,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.CommonResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {},
|
||||
"error": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"success": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.ConfirmAccountDeletionRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1758,7 +1977,9 @@
|
||||
},
|
||||
"handlers.RefreshTokenRequest": {
|
||||
"type": "object",
|
||||
"required": ["refresh_token"],
|
||||
"required": [
|
||||
"refresh_token"
|
||||
],
|
||||
"properties": {
|
||||
"refresh_token": {
|
||||
"type": "string",
|
||||
@@ -1801,7 +2022,9 @@
|
||||
},
|
||||
"handlers.RevokeTokenRequest": {
|
||||
"type": "object",
|
||||
"required": ["refresh_token"],
|
||||
"required": [
|
||||
"refresh_token"
|
||||
],
|
||||
"properties": {
|
||||
"refresh_token": {
|
||||
"type": "string",
|
||||
@@ -1868,7 +2091,11 @@
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["up", "down", "none"],
|
||||
"enum": [
|
||||
"up",
|
||||
"down",
|
||||
"none"
|
||||
],
|
||||
"example": "up"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -60,6 +60,13 @@ func NewAPIHandlerWithMonitoring(config *config.Config, postRepo repositories.Po
|
||||
|
||||
type APIInfo = CommonResponse
|
||||
|
||||
// @Summary Get API information
|
||||
// @Description Retrieve API metadata, available endpoints, authentication details, and response formats
|
||||
// @Tags api
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} APIInfo "API information retrieved successfully"
|
||||
// @Router /api [get]
|
||||
func (h *APIHandler) GetAPIInfo(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/api" {
|
||||
http.NotFound(w, r)
|
||||
@@ -127,6 +134,13 @@ func (h *APIHandler) GetAPIInfo(w http.ResponseWriter, r *http.Request) {
|
||||
SendSuccessResponse(w, "API information retrieved successfully", apiInfo)
|
||||
}
|
||||
|
||||
// @Summary Health check
|
||||
// @Description Check the API health status along with database connectivity details
|
||||
// @Tags api
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} CommonResponse "Health check successful"
|
||||
// @Router /health [get]
|
||||
func (h *APIHandler) GetHealth(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if h.healthChecker != nil {
|
||||
@@ -151,6 +165,13 @@ func (h *APIHandler) GetHealth(w http.ResponseWriter, r *http.Request) {
|
||||
SendSuccessResponse(w, "Health check successful", health)
|
||||
}
|
||||
|
||||
// @Summary Get metrics
|
||||
// @Description Retrieve application metrics including aggregate counts and database performance data
|
||||
// @Tags api
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} CommonResponse "Application metrics retrieved successfully"
|
||||
// @Router /metrics [get]
|
||||
func (h *APIHandler) GetMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
postCount, err := h.postRepo.Count()
|
||||
|
||||
@@ -138,7 +138,7 @@ func NewAuthHandler(authService AuthServiceInterface, userRepo repositories.User
|
||||
// @Failure 401 {object} AuthResponse "Invalid credentials"
|
||||
// @Failure 403 {object} AuthResponse "Account is locked"
|
||||
// @Failure 500 {object} AuthResponse "Internal server error"
|
||||
// @Router /auth/login [post]
|
||||
// @Router /api/auth/login [post]
|
||||
func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Username string `json:"username"`
|
||||
@@ -180,7 +180,7 @@ func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 400 {object} AuthResponse "Invalid request data or validation failed"
|
||||
// @Failure 409 {object} AuthResponse "Username or email already exists"
|
||||
// @Failure 500 {object} AuthResponse "Internal server error"
|
||||
// @Router /auth/register [post]
|
||||
// @Router /api/auth/register [post]
|
||||
func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Username string `json:"username"`
|
||||
@@ -256,7 +256,7 @@ func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) {
|
||||
// @Success 200 {object} AuthResponse "Email confirmed successfully"
|
||||
// @Failure 400 {object} AuthResponse "Invalid or missing token"
|
||||
// @Failure 500 {object} AuthResponse "Internal server error"
|
||||
// @Router /auth/confirm [get]
|
||||
// @Router /api/auth/confirm [get]
|
||||
func (h *AuthHandler) ConfirmEmail(w http.ResponseWriter, r *http.Request) {
|
||||
token := strings.TrimSpace(r.URL.Query().Get("token"))
|
||||
if token == "" {
|
||||
@@ -288,7 +288,7 @@ func (h *AuthHandler) ConfirmEmail(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 429 {object} AuthResponse
|
||||
// @Failure 503 {object} AuthResponse
|
||||
// @Failure 500 {object} AuthResponse
|
||||
// @Router /auth/resend-verification [post]
|
||||
// @Router /api/auth/resend-verification [post]
|
||||
func (h *AuthHandler) ResendVerificationEmail(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Email string `json:"email"`
|
||||
@@ -337,7 +337,7 @@ func (h *AuthHandler) ResendVerificationEmail(w http.ResponseWriter, r *http.Req
|
||||
// @Success 200 {object} AuthResponse "User profile retrieved successfully"
|
||||
// @Failure 401 {object} AuthResponse "Authentication required"
|
||||
// @Failure 404 {object} AuthResponse "User not found"
|
||||
// @Router /auth/me [get]
|
||||
// @Router /api/auth/me [get]
|
||||
func (h *AuthHandler) Me(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := RequireAuth(w, r)
|
||||
if !ok {
|
||||
@@ -362,7 +362,7 @@ func (h *AuthHandler) Me(w http.ResponseWriter, r *http.Request) {
|
||||
// @Param request body ForgotPasswordRequest true "Username or email"
|
||||
// @Success 200 {object} AuthResponse "Password reset email sent if account exists"
|
||||
// @Failure 400 {object} AuthResponse "Invalid request data"
|
||||
// @Router /auth/forgot-password [post]
|
||||
// @Router /api/auth/forgot-password [post]
|
||||
func (h *AuthHandler) RequestPasswordReset(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
UsernameOrEmail string `json:"username_or_email"`
|
||||
@@ -393,7 +393,7 @@ func (h *AuthHandler) RequestPasswordReset(w http.ResponseWriter, r *http.Reques
|
||||
// @Success 200 {object} AuthResponse "Password reset successfully"
|
||||
// @Failure 400 {object} AuthResponse "Invalid or expired token, or validation failed"
|
||||
// @Failure 500 {object} AuthResponse "Internal server error"
|
||||
// @Router /auth/reset-password [post]
|
||||
// @Router /api/auth/reset-password [post]
|
||||
func (h *AuthHandler) ResetPassword(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Token string `json:"token"`
|
||||
@@ -450,7 +450,7 @@ func (h *AuthHandler) ResetPassword(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 409 {object} AuthResponse
|
||||
// @Failure 503 {object} AuthResponse
|
||||
// @Failure 500 {object} AuthResponse
|
||||
// @Router /auth/email [put]
|
||||
// @Router /api/auth/email [put]
|
||||
func (h *AuthHandler) UpdateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := RequireAuth(w, r)
|
||||
if !ok {
|
||||
@@ -504,7 +504,7 @@ func (h *AuthHandler) UpdateEmail(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 401 {object} AuthResponse
|
||||
// @Failure 409 {object} AuthResponse
|
||||
// @Failure 500 {object} AuthResponse
|
||||
// @Router /auth/username [put]
|
||||
// @Router /api/auth/username [put]
|
||||
func (h *AuthHandler) UpdateUsername(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := RequireAuth(w, r)
|
||||
if !ok {
|
||||
@@ -553,7 +553,7 @@ func (h *AuthHandler) UpdateUsername(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 400 {object} AuthResponse
|
||||
// @Failure 401 {object} AuthResponse
|
||||
// @Failure 500 {object} AuthResponse
|
||||
// @Router /auth/password [put]
|
||||
// @Router /api/auth/password [put]
|
||||
func (h *AuthHandler) UpdatePassword(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := RequireAuth(w, r)
|
||||
if !ok {
|
||||
@@ -608,7 +608,7 @@ func (h *AuthHandler) UpdatePassword(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 401 {object} AuthResponse "Authentication required"
|
||||
// @Failure 503 {object} AuthResponse "Email delivery unavailable"
|
||||
// @Failure 500 {object} AuthResponse "Internal server error"
|
||||
// @Router /auth/account [delete]
|
||||
// @Router /api/auth/account [delete]
|
||||
func (h *AuthHandler) DeleteAccount(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := RequireAuth(w, r)
|
||||
if !ok {
|
||||
@@ -638,7 +638,7 @@ func (h *AuthHandler) DeleteAccount(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 400 {object} AuthResponse "Invalid or expired token"
|
||||
// @Failure 503 {object} AuthResponse "Email delivery unavailable"
|
||||
// @Failure 500 {object} AuthResponse "Internal server error"
|
||||
// @Router /auth/account/confirm [post]
|
||||
// @Router /api/auth/account/confirm [post]
|
||||
func (h *AuthHandler) ConfirmAccountDeletion(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Token string `json:"token"`
|
||||
@@ -684,7 +684,7 @@ func (h *AuthHandler) ConfirmAccountDeletion(w http.ResponseWriter, r *http.Requ
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} AuthResponse "Logged out successfully"
|
||||
// @Failure 401 {object} AuthResponse "Authentication required"
|
||||
// @Router /auth/logout [post]
|
||||
// @Router /api/auth/logout [post]
|
||||
func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) {
|
||||
SendSuccessResponse(w, "Logged out successfully", nil)
|
||||
}
|
||||
@@ -700,7 +700,7 @@ func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 401 {object} AuthResponse "Invalid or expired refresh token"
|
||||
// @Failure 403 {object} AuthResponse "Account is locked"
|
||||
// @Failure 500 {object} AuthResponse "Internal server error"
|
||||
// @Router /auth/refresh [post]
|
||||
// @Router /api/auth/refresh [post]
|
||||
func (h *AuthHandler) RefreshToken(w http.ResponseWriter, r *http.Request) {
|
||||
var req RefreshTokenRequest
|
||||
|
||||
@@ -732,7 +732,7 @@ func (h *AuthHandler) RefreshToken(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 400 {object} AuthResponse "Invalid request body or missing refresh token"
|
||||
// @Failure 401 {object} AuthResponse "Invalid or expired access token"
|
||||
// @Failure 500 {object} AuthResponse "Internal server error"
|
||||
// @Router /auth/revoke [post]
|
||||
// @Router /api/auth/revoke [post]
|
||||
func (h *AuthHandler) RevokeToken(w http.ResponseWriter, r *http.Request) {
|
||||
var req RevokeTokenRequest
|
||||
|
||||
@@ -763,7 +763,7 @@ func (h *AuthHandler) RevokeToken(w http.ResponseWriter, r *http.Request) {
|
||||
// @Success 200 {object} AuthResponse "All tokens revoked successfully"
|
||||
// @Failure 401 {object} AuthResponse "Invalid or expired access token"
|
||||
// @Failure 500 {object} AuthResponse "Internal server error"
|
||||
// @Router /auth/revoke-all [post]
|
||||
// @Router /api/auth/revoke-all [post]
|
||||
func (h *AuthHandler) RevokeAllTokens(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := RequireAuth(w, r)
|
||||
if !ok {
|
||||
|
||||
@@ -51,7 +51,7 @@ type UpdatePostRequest struct {
|
||||
// @Success 200 {object} PostResponse "Posts retrieved successfully with vote statistics"
|
||||
// @Failure 400 {object} PostResponse "Invalid pagination parameters"
|
||||
// @Failure 500 {object} PostResponse "Internal server error"
|
||||
// @Router /posts [get]
|
||||
// @Router /api/posts [get]
|
||||
func (h *PostHandler) GetPosts(w http.ResponseWriter, r *http.Request) {
|
||||
limit, offset := parsePagination(r)
|
||||
|
||||
@@ -87,7 +87,7 @@ func (h *PostHandler) GetPosts(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 400 {object} PostResponse "Invalid post ID"
|
||||
// @Failure 404 {object} PostResponse "Post not found"
|
||||
// @Failure 500 {object} PostResponse "Internal server error"
|
||||
// @Router /posts/{id} [get]
|
||||
// @Router /api/posts/{id} [get]
|
||||
func (h *PostHandler) GetPost(w http.ResponseWriter, r *http.Request) {
|
||||
postID, ok := ParseUintParam(w, r, "id", "Post")
|
||||
if !ok {
|
||||
@@ -118,7 +118,7 @@ func (h *PostHandler) GetPost(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 409 {object} PostResponse "URL already submitted"
|
||||
// @Failure 502 {object} PostResponse "Failed to fetch title from URL"
|
||||
// @Failure 500 {object} PostResponse "Internal server error"
|
||||
// @Router /posts [post]
|
||||
// @Router /api/posts [post]
|
||||
func (h *PostHandler) CreatePost(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Title string `json:"title"`
|
||||
@@ -218,7 +218,7 @@ func (h *PostHandler) CreatePost(w http.ResponseWriter, r *http.Request) {
|
||||
// @Success 200 {object} PostResponse "Search results with vote statistics"
|
||||
// @Failure 400 {object} PostResponse "Invalid search parameters"
|
||||
// @Failure 500 {object} PostResponse "Internal server error"
|
||||
// @Router /posts/search [get]
|
||||
// @Router /api/posts/search [get]
|
||||
func (h *PostHandler) SearchPosts(w http.ResponseWriter, r *http.Request) {
|
||||
query := strings.TrimSpace(r.URL.Query().Get("q"))
|
||||
limit, offset := parsePagination(r)
|
||||
@@ -264,7 +264,7 @@ func (h *PostHandler) SearchPosts(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 403 {object} PostResponse "Not authorized to update this post"
|
||||
// @Failure 404 {object} PostResponse "Post not found"
|
||||
// @Failure 500 {object} PostResponse "Internal server error"
|
||||
// @Router /posts/{id} [put]
|
||||
// @Router /api/posts/{id} [put]
|
||||
func (h *PostHandler) UpdatePost(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := RequireAuth(w, r)
|
||||
if !ok {
|
||||
@@ -343,7 +343,7 @@ func (h *PostHandler) UpdatePost(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 403 {object} PostResponse "Not authorized to delete this post"
|
||||
// @Failure 404 {object} PostResponse "Post not found"
|
||||
// @Failure 500 {object} PostResponse "Internal server error"
|
||||
// @Router /posts/{id} [delete]
|
||||
// @Router /api/posts/{id} [delete]
|
||||
func (h *PostHandler) DeletePost(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := RequireAuth(w, r)
|
||||
if !ok {
|
||||
@@ -388,7 +388,7 @@ func (h *PostHandler) DeletePost(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 400 {object} PostResponse "Invalid URL or URL parameter missing"
|
||||
// @Failure 501 {object} PostResponse "Title fetching is not available"
|
||||
// @Failure 502 {object} PostResponse "Failed to fetch title from URL"
|
||||
// @Router /posts/title [get]
|
||||
// @Router /api/posts/title [get]
|
||||
func (h *PostHandler) FetchTitleFromURL(w http.ResponseWriter, r *http.Request) {
|
||||
if h.titleFetcher == nil {
|
||||
SendErrorResponse(w, "Title fetching is not available", http.StatusNotImplemented)
|
||||
|
||||
@@ -36,7 +36,7 @@ type UserResponse = CommonResponse
|
||||
// @Success 200 {object} UserResponse "Users retrieved successfully"
|
||||
// @Failure 401 {object} UserResponse "Authentication required"
|
||||
// @Failure 500 {object} UserResponse "Internal server error"
|
||||
// @Router /users [get]
|
||||
// @Router /api/users [get]
|
||||
func (h *UserHandler) GetUsers(w http.ResponseWriter, r *http.Request) {
|
||||
limit, offset := parsePagination(r)
|
||||
|
||||
@@ -68,7 +68,7 @@ func (h *UserHandler) GetUsers(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 401 {object} UserResponse "Authentication required"
|
||||
// @Failure 404 {object} UserResponse "User not found"
|
||||
// @Failure 500 {object} UserResponse "Internal server error"
|
||||
// @Router /users/{id} [get]
|
||||
// @Router /api/users/{id} [get]
|
||||
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := ParseUintParam(w, r, "id", "User")
|
||||
if !ok {
|
||||
@@ -97,7 +97,7 @@ func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 401 {object} UserResponse "Authentication required"
|
||||
// @Failure 409 {object} UserResponse "Username or email already exists"
|
||||
// @Failure 500 {object} UserResponse "Internal server error"
|
||||
// @Router /users [post]
|
||||
// @Router /api/users [post]
|
||||
func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Username string `json:"username"`
|
||||
@@ -155,7 +155,7 @@ func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 400 {object} UserResponse "Invalid user ID or pagination parameters"
|
||||
// @Failure 401 {object} UserResponse "Authentication required"
|
||||
// @Failure 500 {object} UserResponse "Internal server error"
|
||||
// @Router /users/{id}/posts [get]
|
||||
// @Router /api/users/{id}/posts [get]
|
||||
func (h *UserHandler) GetUserPosts(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := ParseUintParam(w, r, "id", "User")
|
||||
if !ok {
|
||||
|
||||
@@ -70,7 +70,7 @@ type VoteResponse = CommonResponse
|
||||
// @Failure 500 {object} VoteResponse "Internal server error"
|
||||
// @Example 200 {"success": true, "message": "Vote cast successfully", "data": {"post_id": 1, "type": "up", "up_votes": 5, "down_votes": 2, "score": 3, "is_anonymous": false}}
|
||||
// @Example 400 {"success": false, "error": "Invalid vote type. Must be 'up', 'down', or 'none'"}
|
||||
// @Router /posts/{id}/vote [post]
|
||||
// @Router /api/posts/{id}/vote [post]
|
||||
func (h *VoteHandler) CastVote(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := RequireAuth(w, r)
|
||||
if !ok {
|
||||
@@ -140,7 +140,7 @@ func (h *VoteHandler) CastVote(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 400 {object} VoteResponse "Invalid post ID"
|
||||
// @Failure 404 {object} VoteResponse "Post not found"
|
||||
// @Failure 500 {object} VoteResponse "Internal server error"
|
||||
// @Router /posts/{id}/vote [delete]
|
||||
// @Router /api/posts/{id}/vote [delete]
|
||||
func (h *VoteHandler) RemoveVote(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := RequireAuth(w, r)
|
||||
if !ok {
|
||||
@@ -198,7 +198,7 @@ func (h *VoteHandler) RemoveVote(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 500 {object} VoteResponse "Internal server error"
|
||||
// @Example 200 {"success": true, "message": "Vote retrieved successfully", "data": {"has_vote": true, "vote": {"type": "up", "user_id": 123}, "is_anonymous": false}}
|
||||
// @Example 200 {"success": true, "message": "No vote found", "data": {"has_vote": false, "vote": null, "is_anonymous": false}}
|
||||
// @Router /posts/{id}/vote [get]
|
||||
// @Router /api/posts/{id}/vote [get]
|
||||
func (h *VoteHandler) GetUserVote(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := RequireAuth(w, r)
|
||||
if !ok {
|
||||
@@ -253,7 +253,7 @@ func (h *VoteHandler) GetUserVote(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 401 {object} VoteResponse "Authentication required"
|
||||
// @Failure 500 {object} VoteResponse "Internal server error"
|
||||
// @Example 200 {"success": true, "message": "Votes retrieved successfully", "data": {"votes": [{"type": "up", "user_id": 123}, {"type": "down", "vote_hash": "abc123"}], "count": 2}}
|
||||
// @Router /posts/{id}/votes [get]
|
||||
// @Router /api/posts/{id}/votes [get]
|
||||
func (h *VoteHandler) GetPostVotes(w http.ResponseWriter, r *http.Request) {
|
||||
postID, ok := ParseUintParam(w, r, "id", "Post")
|
||||
if !ok {
|
||||
|
||||
Reference in New Issue
Block a user