Compare commits

..

10 الالتزامات

المؤلف SHA1 الرسالة التاريخ
884bebed09 edited .gitignore to ignore logs files 2025-10-05 16:53:15 +03:00
7b1edc7deb edited monitor script 2025-10-05 16:50:34 +03:00
814f32ded3 excutables 2025-10-05 16:41:00 +03:00
386932b2c8 edited app.py 2025-10-05 16:39:19 +03:00
5529f66cb5 imported swagger in app.py 2025-10-05 16:38:31 +03:00
d8f12591aa init swagger.py 2025-10-05 16:35:25 +03:00
369ebf8187 added the automated test from adham 2025-10-05 16:33:25 +03:00
1b7e574cf4 added the monitor bash script from seif 2025-10-05 16:31:23 +03:00
c480016be2 mod pyproject.toml 2025-10-05 16:30:47 +03:00
8e3e93a2ea update app.py 2025-10-05 16:24:46 +03:00
6 ملفات معدلة مع 455 إضافات و2 حذوفات

5
.gitignore مباع
عرض الملف

@@ -8,3 +8,8 @@ wheels/
# Virtual environments
.venv
# Log files (generated by the application)
api.log
alerts.log
test_results.log

4
app.py
عرض الملف

@@ -1,6 +1,7 @@
from flask import Flask, request, jsonify
import logging
from datetime import datetime
from swagger import setup_swagger
app = Flask(__name__)
@@ -11,7 +12,6 @@ logging.basicConfig(
format='%(asctime)s - %(levelname)s - %(message)s'
)
# Simple in-memory database (just a list)
products = [
{"id": 1, "name": "Laptop", "price": 5000, "quantity": 10},
{"id": 2, "name": "Mouse", "price": 150, "quantity": 50}
@@ -143,5 +143,7 @@ def get_orders():
logging.info("GET /orders - Fetching all orders")
return jsonify({"orders": orders})
setup_swagger(app)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)

105
monitor.sh Executable file
عرض الملف

@@ -0,0 +1,105 @@
#!/bin/bash
# Configuration
LOG_FILE="api.log"
GHAYMAH_URL="YOUR_GHAYMAH_ENDPOINT_HERE" # Will be provided later
echo "Starting log monitor..."
echo "Watching file: $LOG_FILE"
# Check if log file exists
if [ ! -f "$LOG_FILE" ]; then
echo "Warning: $LOG_FILE not found. Creating it..."
touch "$LOG_FILE"
fi
# Function to get server info
get_server_info() {
# Get IP address - try different methods
if command -v hostname &> /dev/null; then
IP=$(hostname -I | awk '{print $1}')
elif command -v ip &> /dev/null; then
IP=$(ip addr show | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d'/' -f1 | head -n1)
else
IP="127.0.0.1"
fi
# Get CPU usage
if command -v top &> /dev/null; then
CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
else
CPU="N/A"
fi
# Get available RAM
if command -v free &> /dev/null; then
RAM=$(free -h | grep Mem | awk '{print $7}')
else
RAM="N/A"
fi
# Get available disk space
if command -v df &> /dev/null; then
DISK=$(df -h / | tail -1 | awk '{print $4}')
else
DISK="N/A"
fi
echo "$IP|$CPU|$RAM|$DISK"
}
# Function to send alert
send_alert() {
ERROR_MSG=$1
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# Get server metrics
SERVER_INFO=$(get_server_info)
IP=$(echo $SERVER_INFO | cut -d'|' -f1)
CPU=$(echo $SERVER_INFO | cut -d'|' -f2)
RAM=$(echo $SERVER_INFO | cut -d'|' -f3)
DISK=$(echo $SERVER_INFO | cut -d'|' -f4)
# Create JSON payload
JSON_PAYLOAD=$(cat <<EOF
{
"error": "$ERROR_MSG",
"timestamp": "$TIMESTAMP",
"message": "Error detected in API logs",
"server_metrics": {
"ip": "$IP",
"cpu_usage": "${CPU}%",
"ram_available": "$RAM",
"disk_space": "$DISK"
}
}
EOF
)
echo "=========================================="
echo "⚠️ ALERT DETECTED!"
echo "Error: $ERROR_MSG"
echo "Server IP: $IP | CPU: ${CPU}% | RAM: $RAM | Disk: $DISK"
echo "=========================================="
# Send to Ghaymah endpoint
# Uncomment when endpoint URL is provided
# curl -X POST "$GHAYMAH_URL" \
# -H "Content-Type: application/json" \
# -d "$JSON_PAYLOAD"
# For now, just save to alert file
echo "$JSON_PAYLOAD" >> alerts.log
echo "Alert saved to alerts.log"
echo ""
}
# Monitor log file continuously
# Only trigger on actual ERROR lines with 4XX or 5XX codes
tail -f "$LOG_FILE" | while read line
do
# Only check lines that have ERROR level AND contain error codes
if echo "$line" | grep "ERROR" | grep -E "(400|404|500|503|failed|timeout)" > /dev/null; then
send_alert "$line"
fi
done

عرض الملف

@@ -1,7 +1,7 @@
[project]
name = "simple-store"
version = "0.1.0"
description = "Add your description here"
description = "a demo API (e.g., for a store, booking system, or any domain of your choice) with 6-7 documented endpoints, implement logging, monitor errors via a Bash script, and automate API requests."
readme = "README.md"
requires-python = ">=3.13"
dependencies = [

224
swagger.py Normal file
عرض الملف

@@ -0,0 +1,224 @@
from flask import Flask
from flask_swagger_ui import get_swaggerui_blueprint
import json
# Swagger configuration
SWAGGER_URL = '/docs'
API_URL = '/swagger.json'
swagger_ui_blueprint = get_swaggerui_blueprint(
SWAGGER_URL,
API_URL,
config={
'app_name': "My First Store API"
}
)
# Swagger JSON specification
swagger_spec = {
"openapi": "3.0.0",
"info": {
"title": "Simple Store API",
"description": "My first API project - A simple store management system",
"version": "1.0.0"
},
"servers": [
{
"url": "http://localhost:5000",
"description": "Development server"
}
],
"paths": {
"/": {
"get": {
"summary": "Home page",
"description": "Welcome message",
"responses": {
"200": {
"description": "Welcome message",
"content": {
"application/json": {
"example": {"message": "Welcome to my first API!"}
}
}
}
}
}
},
"/products": {
"get": {
"summary": "Get all products",
"description": "Returns a list of all products in the store",
"responses": {
"200": {
"description": "List of products",
"content": {
"application/json": {
"example": {
"products": [
{"id": 1, "name": "Laptop", "price": 5000, "quantity": 10}
]
}
}
}
}
}
},
"post": {
"summary": "Add new product",
"description": "Create a new product in the store",
"requestBody": {
"required": True,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {"type": "string", "example": "Keyboard"},
"price": {"type": "number", "example": 300},
"quantity": {"type": "integer", "example": 20}
},
"required": ["name", "price"]
}
}
}
},
"responses": {
"201": {
"description": "Product created successfully"
},
"400": {
"description": "Missing required fields"
}
}
}
},
"/products/{product_id}": {
"get": {
"summary": "Get single product",
"description": "Get details of a specific product by ID",
"parameters": [
{
"name": "product_id",
"in": "path",
"required": True,
"schema": {"type": "integer"},
"example": 1
}
],
"responses": {
"200": {
"description": "Product details"
},
"404": {
"description": "Product not found"
}
}
},
"put": {
"summary": "Update product",
"description": "Update an existing product",
"parameters": [
{
"name": "product_id",
"in": "path",
"required": True,
"schema": {"type": "integer"}
}
],
"requestBody": {
"required": True,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"price": {"type": "number"},
"quantity": {"type": "integer"}
}
}
}
}
},
"responses": {
"200": {
"description": "Product updated"
},
"404": {
"description": "Product not found"
}
}
},
"delete": {
"summary": "Delete product",
"description": "Remove a product from the store",
"parameters": [
{
"name": "product_id",
"in": "path",
"required": True,
"schema": {"type": "integer"}
}
],
"responses": {
"200": {
"description": "Product deleted"
},
"404": {
"description": "Product not found"
}
}
}
},
"/orders": {
"get": {
"summary": "Get all orders",
"description": "Returns a list of all orders",
"responses": {
"200": {
"description": "List of orders"
}
}
},
"post": {
"summary": "Create order",
"description": "Place a new order for a product",
"requestBody": {
"required": True,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"product_id": {"type": "integer", "example": 1},
"quantity": {"type": "integer", "example": 2}
},
"required": ["product_id", "quantity"]
}
}
}
},
"responses": {
"201": {
"description": "Order created successfully"
},
"400": {
"description": "Invalid order data or not enough stock"
},
"404": {
"description": "Product not found"
}
}
}
}
}
}
def setup_swagger(app):
"""Add Swagger UI to Flask app"""
app.register_blueprint(swagger_ui_blueprint, url_prefix=SWAGGER_URL)
@app.route('/swagger.json')
def swagger_json():
return swagger_spec

117
test_api.sh Executable file
عرض الملف

@@ -0,0 +1,117 @@
#!/bin/bash
# Configuration
API_URL="http://localhost:5000"
LOG_FILE="test_results.log"
# Clear previous log
> "$LOG_FILE"
echo "Starting API tests..."
echo "Results will be saved to: $LOG_FILE"
echo "========================================"
# Function to log results
log_result() {
echo "$1" | tee -a "$LOG_FILE"
}
# Test 1: Home page
log_result ""
log_result "Test 1: GET / (Home page)"
log_result "----------------------------"
curl -s -X GET "$API_URL/" | tee -a "$LOG_FILE"
log_result ""
sleep 1
# Test 2: Get all products
log_result ""
log_result "Test 2: GET /products (All products)"
log_result "----------------------------"
curl -s -X GET "$API_URL/products" | tee -a "$LOG_FILE"
log_result ""
sleep 1
# Test 3: Get single product
log_result ""
log_result "Test 3: GET /products/1 (Single product)"
log_result "----------------------------"
curl -s -X GET "$API_URL/products/1" | tee -a "$LOG_FILE"
log_result ""
sleep 1
# Test 4: Add new product
log_result ""
log_result "Test 4: POST /products (Add new product)"
log_result "----------------------------"
curl -s -X POST "$API_URL/products" \
-H "Content-Type: application/json" \
-d '{
"name": "Keyboard",
"price": 300,
"quantity": 20
}' | tee -a "$LOG_FILE"
log_result ""
sleep 1
# Test 5: Update product
log_result ""
log_result "Test 5: PUT /products/1 (Update product)"
log_result "----------------------------"
curl -s -X PUT "$API_URL/products/1" \
-H "Content-Type: application/json" \
-d '{
"price": 4500,
"quantity": 15
}' | tee -a "$LOG_FILE"
log_result ""
sleep 1
# Test 6: Create order
log_result ""
log_result "Test 6: POST /orders (Create order)"
log_result "----------------------------"
curl -s -X POST "$API_URL/orders" \
-H "Content-Type: application/json" \
-d '{
"product_id": 2,
"quantity": 5
}' | tee -a "$LOG_FILE"
log_result ""
sleep 1
# Test 7: Get all orders
log_result ""
log_result "Test 7: GET /orders (All orders)"
log_result "----------------------------"
curl -s -X GET "$API_URL/orders" | tee -a "$LOG_FILE"
log_result ""
sleep 1
# Test 8: Delete product
log_result ""
log_result "Test 8: DELETE /products/2 (Delete product)"
log_result "----------------------------"
curl -s -X DELETE "$API_URL/products/2" | tee -a "$LOG_FILE"
log_result ""
sleep 1
# Test 9: Try to get deleted product (should fail)
log_result ""
log_result "Test 9: GET /products/2 (Should return 404)"
log_result "----------------------------"
curl -s -X GET "$API_URL/products/2" | tee -a "$LOG_FILE"
log_result ""
log_result ""
log_result "========================================"
log_result "All tests completed!"
log_result "Check $LOG_FILE for full results"