Compare commits
5 Commits
c31eb2f3df
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| e58ba1b8d1 | |||
| 4ffc601723 | |||
| d6321e775a | |||
| de9b544afb | |||
| 19291b7f61 |
@@ -1771,7 +1771,7 @@ const docTemplate = `{
|
|||||||
},
|
},
|
||||||
"/health": {
|
"/health": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Check the API health status along with database connectivity details",
|
"description": "Check the API health status along with database connectivity and SMTP service details",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1768,7 +1768,7 @@
|
|||||||
},
|
},
|
||||||
"/health": {
|
"/health": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Check the API health status along with database connectivity details",
|
"description": "Check the API health status along with database connectivity and SMTP service details",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1387,7 +1387,8 @@ paths:
|
|||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: Check the API health status along with database connectivity details
|
description: Check the API health status along with database connectivity and
|
||||||
|
SMTP service details
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package integration
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -63,13 +62,33 @@ func TestIntegration_Router_FullMiddlewareChain(t *testing.T) {
|
|||||||
t.Run("DBMonitoring_Active", func(t *testing.T) {
|
t.Run("DBMonitoring_Active", func(t *testing.T) {
|
||||||
request := makeGetRequest(t, router, "/health")
|
request := makeGetRequest(t, router, "/health")
|
||||||
|
|
||||||
var response map[string]any
|
response := assertJSONResponse(t, request, http.StatusOK)
|
||||||
if err := json.NewDecoder(request.Body).Decode(&response); err == nil {
|
if response == nil {
|
||||||
if data, ok := response["data"].(map[string]any); ok {
|
return
|
||||||
if _, exists := data["database_stats"]; !exists {
|
}
|
||||||
t.Error("Expected database_stats in health response")
|
|
||||||
}
|
data, ok := getDataFromResponse(response)
|
||||||
}
|
if !ok {
|
||||||
|
t.Fatal("Expected data to be a map")
|
||||||
|
}
|
||||||
|
|
||||||
|
services, ok := data["services"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Expected services in health response")
|
||||||
|
}
|
||||||
|
|
||||||
|
databaseService, ok := services["database"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Expected database service in health response")
|
||||||
|
}
|
||||||
|
|
||||||
|
details, ok := databaseService["details"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Expected database details in health response")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, exists := details["stats"]; !exists {
|
||||||
|
t.Error("Expected database stats in health response")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -26,12 +26,7 @@ func NewCORSConfig() *CORSConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch env {
|
switch env {
|
||||||
case "production":
|
case "production", "staging":
|
||||||
if origins := os.Getenv("CORS_ALLOWED_ORIGINS"); origins == "" {
|
|
||||||
config.AllowedOrigins = []string{}
|
|
||||||
}
|
|
||||||
config.AllowCredentials = true
|
|
||||||
case "staging":
|
|
||||||
if origins := os.Getenv("CORS_ALLOWED_ORIGINS"); origins == "" {
|
if origins := os.Getenv("CORS_ALLOWED_ORIGINS"); origins == "" {
|
||||||
config.AllowedOrigins = []string{}
|
config.AllowedOrigins = []string{}
|
||||||
}
|
}
|
||||||
@@ -53,82 +48,66 @@ func NewCORSConfig() *CORSConfig {
|
|||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkOrigin(origin string, allowedOrigins []string) (allowed bool, hasWildcard bool) {
|
||||||
|
for _, allowedOrigin := range allowedOrigins {
|
||||||
|
if allowedOrigin == "*" {
|
||||||
|
hasWildcard = true
|
||||||
|
allowed = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if allowedOrigin == origin {
|
||||||
|
allowed = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func setCORSHeaders(w http.ResponseWriter, origin string, hasWildcard bool, config *CORSConfig) {
|
||||||
|
if hasWildcard && !config.AllowCredentials {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
} else {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.AllowCredentials && !hasWildcard {
|
||||||
|
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func CORSWithConfig(config *CORSConfig) func(http.Handler) http.Handler {
|
func CORSWithConfig(config *CORSConfig) func(http.Handler) http.Handler {
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
origin := r.Header.Get("Origin")
|
origin := r.Header.Get("Origin")
|
||||||
|
|
||||||
if r.Method == "OPTIONS" {
|
if origin == "" {
|
||||||
if origin != "" {
|
if r.Method == "OPTIONS" {
|
||||||
allowed := false
|
w.WriteHeader(http.StatusOK)
|
||||||
hasWildcard := false
|
return
|
||||||
for _, allowedOrigin := range config.AllowedOrigins {
|
|
||||||
if allowedOrigin == "*" {
|
|
||||||
hasWildcard = true
|
|
||||||
allowed = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if allowedOrigin == origin {
|
|
||||||
allowed = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !allowed {
|
|
||||||
http.Error(w, "Origin not allowed", http.StatusForbidden)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasWildcard && !config.AllowCredentials {
|
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
||||||
} else {
|
|
||||||
w.Header().Set("Access-Control-Allow-Origin", origin)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Access-Control-Allow-Methods", strings.Join(config.AllowedMethods, ", "))
|
|
||||||
w.Header().Set("Access-Control-Allow-Headers", strings.Join(config.AllowedHeaders, ", "))
|
|
||||||
w.Header().Set("Access-Control-Max-Age", fmt.Sprintf("%d", config.MaxAge))
|
|
||||||
|
|
||||||
if config.AllowCredentials && !hasWildcard {
|
|
||||||
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
allowed, hasWildcard := checkOrigin(origin, config.AllowedOrigins)
|
||||||
|
|
||||||
|
if !allowed {
|
||||||
|
http.Error(w, "Origin not allowed", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Method == "OPTIONS" {
|
||||||
|
setCORSHeaders(w, origin, hasWildcard, config)
|
||||||
|
|
||||||
|
w.Header().Set("Access-Control-Allow-Methods", strings.Join(config.AllowedMethods, ", "))
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", strings.Join(config.AllowedHeaders, ", "))
|
||||||
|
w.Header().Set("Access-Control-Max-Age", fmt.Sprintf("%d", config.MaxAge))
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if origin != "" {
|
setCORSHeaders(w, origin, hasWildcard, config)
|
||||||
allowed := false
|
|
||||||
hasWildcard := false
|
|
||||||
for _, allowedOrigin := range config.AllowedOrigins {
|
|
||||||
if allowedOrigin == "*" {
|
|
||||||
hasWildcard = true
|
|
||||||
allowed = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if allowedOrigin == origin {
|
|
||||||
allowed = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !allowed {
|
|
||||||
http.Error(w, "Origin not allowed", http.StatusForbidden)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasWildcard && !config.AllowCredentials {
|
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
||||||
} else {
|
|
||||||
w.Header().Set("Access-Control-Allow-Origin", origin)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.AllowCredentials && !hasWildcard {
|
|
||||||
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# screenshot
|
||||||
|
|
||||||
In this folder, you will find screenshots of the app.
|
In this folder, you will find screenshots of the app.
|
||||||
|
|
||||||
Two kinds of screenshot here:
|
Two kinds of screenshot here:
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ if [ "$EUID" -ne 0 ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
read -s "Do you want to install PostgreSQL 18? [y/N] " INSTALL_PG
|
read -rp "Do you want to install PostgreSQL 18? [y/N] " INSTALL_PG
|
||||||
if [ "$INSTALL_PG" != "y" ]; then
|
if [ "$INSTALL_PG" != "y" ]; then
|
||||||
echo "PostgreSQL 18 will not be installed"
|
echo "PostgreSQL 18 will not be installed"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
read -s -p "Enter password for PostgreSQL user 'goyco': " GOYCO_PWD
|
read -rsp "Enter password for PostgreSQL user 'goyco': " GOYCO_PWD
|
||||||
echo
|
echo
|
||||||
|
|
||||||
apt-get update
|
apt-get update
|
||||||
|
|||||||
Reference in New Issue
Block a user