openwork-agent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +436 -0
- package/package.json +78 -0
- package/src/core/TechDetector.js +351 -0
- package/src/generators/ProjectGenerator.js +1241 -0
- package/src/generators/ProjectGeneratorExtensions.js +14 -0
- package/src/generators/TemplateMethods.js +402 -0
- package/src/generators/index.js +5 -0
- package/src/index.js +152 -0
- package/src/main.js +8 -0
- package/src/templates/common/README.md.hbs +358 -0
- package/src/templates/docker/index.js +518 -0
- package/src/templates/docker.js +58 -0
- package/src/templates/go/basic/api/routes/user.go.hbs +138 -0
- package/src/templates/go/basic/config/config.go.hbs +54 -0
- package/src/templates/go/basic/go.mod.hbs +8 -0
- package/src/templates/go/basic/main.go.hbs +70 -0
- package/src/templates/go/basic/models/user.go.hbs +69 -0
- package/src/templates/go/basic/services/user_service.go.hbs +173 -0
- package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/controller/UserController.java.hbs +91 -0
- package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/dto/ApiResponse.java.hbs +40 -0
- package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/model/User.java.hbs +102 -0
- package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/repository/UserRepository.java.hbs +20 -0
- package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/service/UserService.java.hbs +65 -0
- package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/{{pascalCase projectName}}Application.java.hbs +16 -0
- package/src/templates/node/basic/src/config/database.ts.hbs +18 -0
- package/src/templates/node/basic/src/controllers/UserController.ts.hbs +98 -0
- package/src/templates/node/basic/src/index.ts.hbs +45 -0
- package/src/templates/node/basic/src/middleware/errorHandler.ts.hbs +33 -0
- package/src/templates/node/basic/src/routes/index.ts.hbs +42 -0
- package/src/templates/node/basic/src/types/index.ts.hbs +18 -0
- package/src/templates/python/basic/config/database.py.hbs +36 -0
- package/src/templates/python/basic/main.py.hbs +58 -0
- package/src/templates/python/basic/middleware/error_handler.py.hbs +41 -0
- package/src/templates/python/basic/models/user.py.hbs +40 -0
- package/src/templates/python/basic/routes/__init__.py.hbs +12 -0
- package/src/templates/python/basic/routes/users.py.hbs +64 -0
- package/src/templates/rust/basic/Cargo.toml.hbs +39 -0
- package/src/templates/rust/basic/src/config/database.rs.hbs +27 -0
- package/src/templates/rust/basic/src/handlers/user.rs.hbs +130 -0
- package/src/templates/rust/basic/src/handlers/user_routes.rs.hbs +15 -0
- package/src/templates/rust/basic/src/main.rs.hbs +53 -0
- package/src/templates/rust/basic/src/models/mod.rs.hbs +79 -0
- package/src/templates/rust/basic/src/schema.rs.hbs +10 -0
- package/src/utils/FileManager.js +186 -0
- package/src/utils/Templates.js +231 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package com.{{snakeCase projectName}}.{{projectName}};
|
|
2
|
+
|
|
3
|
+
import org.springframework.boot.SpringApplication;
|
|
4
|
+
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
5
|
+
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
|
6
|
+
|
|
7
|
+
@SpringBootApplication
|
|
8
|
+
@EnableMongoRepositories
|
|
9
|
+
public class {{pascalCase projectName}}Application {
|
|
10
|
+
|
|
11
|
+
public static void main(String[] args) {
|
|
12
|
+
SpringApplication.run({{pascalCase projectName}}Application.class, args);
|
|
13
|
+
System.out.println("🚀 " + "{{pascalCase projectName}}" + " application started successfully!");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import mongoose from 'mongoose';
|
|
2
|
+
|
|
3
|
+
export async function connectDatabase(): Promise<void> {
|
|
4
|
+
const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/{{projectName}}';
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
await mongoose.connect(mongoUri);
|
|
8
|
+
console.log('✅ Connected to MongoDB');
|
|
9
|
+
} catch (error) {
|
|
10
|
+
console.error('❌ MongoDB connection error:', error);
|
|
11
|
+
throw error;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const disconnectDatabase = (): void => {
|
|
16
|
+
mongoose.connection.close();
|
|
17
|
+
console.log('🔌 Disconnected from MongoDB');
|
|
18
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Request, Response } from 'express';
|
|
2
|
+
|
|
3
|
+
export class UserController {
|
|
4
|
+
async getUsers(req: Request, res: Response) {
|
|
5
|
+
try {
|
|
6
|
+
// TODO: Implement user retrieval logic
|
|
7
|
+
const users = [];
|
|
8
|
+
res.json({
|
|
9
|
+
success: true,
|
|
10
|
+
data: users
|
|
11
|
+
});
|
|
12
|
+
} catch (error) {
|
|
13
|
+
res.status(500).json({
|
|
14
|
+
success: false,
|
|
15
|
+
message: 'Failed to fetch users'
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async getUser(req: Request, res: Response) {
|
|
21
|
+
try {
|
|
22
|
+
const { id } = req.params;
|
|
23
|
+
// TODO: Implement user retrieval by ID
|
|
24
|
+
const user = null;
|
|
25
|
+
|
|
26
|
+
if (!user) {
|
|
27
|
+
return res.status(404).json({
|
|
28
|
+
success: false,
|
|
29
|
+
message: 'User not found'
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
res.json({
|
|
34
|
+
success: true,
|
|
35
|
+
data: user
|
|
36
|
+
});
|
|
37
|
+
} catch (error) {
|
|
38
|
+
res.status(500).json({
|
|
39
|
+
success: false,
|
|
40
|
+
message: 'Failed to fetch user'
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async createUser(req: Request, res: Response) {
|
|
46
|
+
try {
|
|
47
|
+
const userData = req.body;
|
|
48
|
+
// TODO: Implement user creation logic
|
|
49
|
+
const newUser = { id: 1, ...userData };
|
|
50
|
+
|
|
51
|
+
res.status(201).json({
|
|
52
|
+
success: true,
|
|
53
|
+
data: newUser
|
|
54
|
+
});
|
|
55
|
+
} catch (error) {
|
|
56
|
+
res.status(500).json({
|
|
57
|
+
success: false,
|
|
58
|
+
message: 'Failed to create user'
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async updateUser(req: Request, res: Response) {
|
|
64
|
+
try {
|
|
65
|
+
const { id } = req.params;
|
|
66
|
+
const userData = req.body;
|
|
67
|
+
// TODO: Implement user update logic
|
|
68
|
+
const updatedUser = { id, ...userData };
|
|
69
|
+
|
|
70
|
+
res.json({
|
|
71
|
+
success: true,
|
|
72
|
+
data: updatedUser
|
|
73
|
+
});
|
|
74
|
+
} catch (error) {
|
|
75
|
+
res.status(500).json({
|
|
76
|
+
success: false,
|
|
77
|
+
message: 'Failed to update user'
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async deleteUser(req: Request, res: Response) {
|
|
83
|
+
try {
|
|
84
|
+
const { id } = req.params;
|
|
85
|
+
// TODO: Implement user deletion logic
|
|
86
|
+
|
|
87
|
+
res.json({
|
|
88
|
+
success: true,
|
|
89
|
+
message: 'User deleted successfully'
|
|
90
|
+
});
|
|
91
|
+
} catch (error) {
|
|
92
|
+
res.status(500).json({
|
|
93
|
+
success: false,
|
|
94
|
+
message: 'Failed to delete user'
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import cors from 'cors';
|
|
3
|
+
import helmet from 'helmet';
|
|
4
|
+
import dotenv from 'dotenv';
|
|
5
|
+
|
|
6
|
+
import { connectDatabase } from './config/database';
|
|
7
|
+
import { errorHandler } from './middleware/errorHandler';
|
|
8
|
+
import routes from './routes';
|
|
9
|
+
|
|
10
|
+
dotenv.config();
|
|
11
|
+
|
|
12
|
+
const app = express();
|
|
13
|
+
const PORT = process.env.PORT || 3000;
|
|
14
|
+
|
|
15
|
+
// Middleware
|
|
16
|
+
app.use(helmet());
|
|
17
|
+
app.use(cors());
|
|
18
|
+
app.use(express.json());
|
|
19
|
+
app.use(express.urlencoded({ extended: true }));
|
|
20
|
+
|
|
21
|
+
// Routes
|
|
22
|
+
app.use('/api', routes);
|
|
23
|
+
|
|
24
|
+
// Health check
|
|
25
|
+
app.get('/health', (req, res) => {
|
|
26
|
+
res.json({ status: 'OK', timestamp: new Date().toISOString() });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Error handling
|
|
30
|
+
app.use(errorHandler);
|
|
31
|
+
|
|
32
|
+
// Database connection and server start
|
|
33
|
+
async function startServer() {
|
|
34
|
+
try {
|
|
35
|
+
await connectDatabase();
|
|
36
|
+
app.listen(PORT, () => {
|
|
37
|
+
console.log(`🚀 Server running on port ${PORT}`);
|
|
38
|
+
});
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error('Failed to start server:', error);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
startServer();
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from 'express';
|
|
2
|
+
|
|
3
|
+
export interface ApiError extends Error {
|
|
4
|
+
statusCode?: number;
|
|
5
|
+
isOperational?: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const createError = (message: string, statusCode: number): ApiError => {
|
|
9
|
+
const error = new Error(message) as ApiError;
|
|
10
|
+
error.statusCode = statusCode;
|
|
11
|
+
error.isOperational = true;
|
|
12
|
+
return error;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const errorHandler = (
|
|
16
|
+
error: ApiError,
|
|
17
|
+
req: Request,
|
|
18
|
+
res: Response,
|
|
19
|
+
next: NextFunction
|
|
20
|
+
): void => {
|
|
21
|
+
const statusCode = error.statusCode || 500;
|
|
22
|
+
const message = error.message || 'Internal Server Error';
|
|
23
|
+
|
|
24
|
+
console.error('Error:', error);
|
|
25
|
+
|
|
26
|
+
res.status(statusCode).json({
|
|
27
|
+
success: false,
|
|
28
|
+
error: {
|
|
29
|
+
message,
|
|
30
|
+
...(process.env.NODE_ENV === 'development' && { stack: error.stack })
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { UserController } from '../controllers/UserController';
|
|
3
|
+
|
|
4
|
+
const router = Router();
|
|
5
|
+
const userController = new UserController();
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @route GET /api/users
|
|
9
|
+
* @desc Get all users
|
|
10
|
+
* @access Public
|
|
11
|
+
*/
|
|
12
|
+
router.get('/users', userController.getUsers);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @route GET /api/users/:id
|
|
16
|
+
* @desc Get user by ID
|
|
17
|
+
* @access Public
|
|
18
|
+
*/
|
|
19
|
+
router.get('/users/:id', userController.getUser);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @route POST /api/users
|
|
23
|
+
* @desc Create a new user
|
|
24
|
+
* @access Public
|
|
25
|
+
*/
|
|
26
|
+
router.post('/users', userController.createUser);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @route PUT /api/users/:id
|
|
30
|
+
* @desc Update user by ID
|
|
31
|
+
* @access Public
|
|
32
|
+
*/
|
|
33
|
+
router.put('/users/:id', userController.updateUser);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @route DELETE /api/users/:id
|
|
37
|
+
* @desc Delete user by ID
|
|
38
|
+
* @access Public
|
|
39
|
+
*/
|
|
40
|
+
router.delete('/users/:id', userController.deleteUser);
|
|
41
|
+
|
|
42
|
+
export default router;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface User {
|
|
2
|
+
_id?: string;
|
|
3
|
+
name: string;
|
|
4
|
+
email: string;
|
|
5
|
+
age?: number;
|
|
6
|
+
createdAt?: Date;
|
|
7
|
+
updatedAt?: Date;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ApiResponse<T = any> {
|
|
11
|
+
success: boolean;
|
|
12
|
+
data?: T;
|
|
13
|
+
message?: string;
|
|
14
|
+
error?: {
|
|
15
|
+
message: string;
|
|
16
|
+
stack?: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from motor.motor_asyncio import AsyncIOMotorClient
|
|
2
|
+
from pymongo.errors import ConnectionFailure
|
|
3
|
+
import os
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
client: Optional[AsyncIOMotorClient] = None
|
|
7
|
+
database = None
|
|
8
|
+
|
|
9
|
+
async def connect_database():
|
|
10
|
+
"""Connect to MongoDB database"""
|
|
11
|
+
global client, database
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
mongo_uri = os.getenv("MONGODB_URI", "mongodb://localhost:27017/{{projectName}}")
|
|
15
|
+
client = AsyncIOMotorClient(mongo_uri)
|
|
16
|
+
|
|
17
|
+
# Test the connection
|
|
18
|
+
await client.admin.command('ping')
|
|
19
|
+
|
|
20
|
+
database = client[os.getenv("DB_NAME", "{{projectName}}")]
|
|
21
|
+
print("✅ Connected to MongoDB")
|
|
22
|
+
|
|
23
|
+
except ConnectionFailure as e:
|
|
24
|
+
print(f"❌ MongoDB connection error: {e}")
|
|
25
|
+
raise
|
|
26
|
+
|
|
27
|
+
async def disconnect_database():
|
|
28
|
+
"""Disconnect from MongoDB"""
|
|
29
|
+
global client
|
|
30
|
+
if client:
|
|
31
|
+
client.close()
|
|
32
|
+
print("🔌 Disconnected from MongoDB")
|
|
33
|
+
|
|
34
|
+
async def get_database():
|
|
35
|
+
"""Get database instance"""
|
|
36
|
+
return database
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from fastapi import FastAPI, HTTPException
|
|
2
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
3
|
+
from fastapi.responses import JSONResponse
|
|
4
|
+
import uvicorn
|
|
5
|
+
import os
|
|
6
|
+
from dotenv import load_dotenv
|
|
7
|
+
|
|
8
|
+
from config.database import connect_database
|
|
9
|
+
from routes import api_router
|
|
10
|
+
from middleware.error_handler import global_exception_handler
|
|
11
|
+
|
|
12
|
+
load_dotenv()
|
|
13
|
+
|
|
14
|
+
app = FastAPI(
|
|
15
|
+
title="{{pascalCase projectName}} API",
|
|
16
|
+
description="{{description}}",
|
|
17
|
+
version="1.0.0"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# CORS middleware
|
|
21
|
+
app.add_middleware(
|
|
22
|
+
CORSMiddleware,
|
|
23
|
+
allow_origins=["*"],
|
|
24
|
+
allow_credentials=True,
|
|
25
|
+
allow_methods=["*"],
|
|
26
|
+
allow_headers=["*"],
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# Global exception handler
|
|
30
|
+
app.exception_handler(Exception)(global_exception_handler)
|
|
31
|
+
|
|
32
|
+
# Include routes
|
|
33
|
+
app.include_router(api_router, prefix="/api")
|
|
34
|
+
|
|
35
|
+
@app.get("/health")
|
|
36
|
+
async def health_check():
|
|
37
|
+
return {
|
|
38
|
+
"status": "OK",
|
|
39
|
+
"timestamp": "2024-01-01T00:00:00Z"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@app.on_event("startup")
|
|
43
|
+
async def startup_event():
|
|
44
|
+
await connect_database()
|
|
45
|
+
print("🚀 Server started successfully")
|
|
46
|
+
|
|
47
|
+
@app.on_event("shutdown")
|
|
48
|
+
async def shutdown_event():
|
|
49
|
+
print("🔌 Server shutting down")
|
|
50
|
+
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
port = int(os.getenv("PORT", 8000))
|
|
53
|
+
uvicorn.run(
|
|
54
|
+
"main:app",
|
|
55
|
+
host="0.0.0.0",
|
|
56
|
+
port=port,
|
|
57
|
+
reload=True
|
|
58
|
+
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from fastapi import Request, HTTPException
|
|
2
|
+
from fastapi.responses import JSONResponse
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
async def global_exception_handler(request: Request, exc: Exception):
|
|
8
|
+
"""Global exception handler for FastAPI"""
|
|
9
|
+
|
|
10
|
+
logger.error(f"Unhandled exception: {str(exc)}")
|
|
11
|
+
|
|
12
|
+
return JSONResponse(
|
|
13
|
+
status_code=500,
|
|
14
|
+
content={
|
|
15
|
+
"success": False,
|
|
16
|
+
"error": {
|
|
17
|
+
"message": "Internal server error",
|
|
18
|
+
"type": type(exc).__name__
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
class APIException(Exception):
|
|
24
|
+
"""Custom API exception"""
|
|
25
|
+
def __init__(self, message: str, status_code: int = 400):
|
|
26
|
+
self.message = message
|
|
27
|
+
self.status_code = status_code
|
|
28
|
+
super().__init__(self.message)
|
|
29
|
+
|
|
30
|
+
async def api_exception_handler(request: Request, exc: APIException):
|
|
31
|
+
"""Handler for custom API exceptions"""
|
|
32
|
+
|
|
33
|
+
return JSONResponse(
|
|
34
|
+
status_code=exc.status_code,
|
|
35
|
+
content={
|
|
36
|
+
"success": False,
|
|
37
|
+
"error": {
|
|
38
|
+
"message": exc.message
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from pydantic import BaseModel, EmailStr
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from bson import ObjectId
|
|
5
|
+
|
|
6
|
+
class PyObjectId(ObjectId):
|
|
7
|
+
"""Custom ObjectId class for Pydantic"""
|
|
8
|
+
@classmethod
|
|
9
|
+
def __get_validators__(cls):
|
|
10
|
+
yield cls.validate
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
def validate(cls, v):
|
|
14
|
+
if not ObjectId.is_valid(v):
|
|
15
|
+
raise ValueError("Invalid objectid")
|
|
16
|
+
return ObjectId(v)
|
|
17
|
+
|
|
18
|
+
class UserBase(BaseModel):
|
|
19
|
+
name: str
|
|
20
|
+
email: EmailStr
|
|
21
|
+
age: Optional[int] = None
|
|
22
|
+
|
|
23
|
+
class UserCreate(UserBase):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
class UserUpdate(BaseModel):
|
|
27
|
+
name: Optional[str] = None
|
|
28
|
+
email: Optional[EmailStr] = None
|
|
29
|
+
age: Optional[int] = None
|
|
30
|
+
|
|
31
|
+
class User(UserBase):
|
|
32
|
+
id: Optional[PyObjectId] = None
|
|
33
|
+
created_at: Optional[datetime] = None
|
|
34
|
+
updated_at: Optional[datetime] = None
|
|
35
|
+
|
|
36
|
+
class Config:
|
|
37
|
+
arbitrary_types_allowed = True
|
|
38
|
+
json_encoders = {
|
|
39
|
+
ObjectId: str
|
|
40
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from fastapi import APIRouter
|
|
2
|
+
from routes import users
|
|
3
|
+
|
|
4
|
+
api_router = APIRouter()
|
|
5
|
+
|
|
6
|
+
api_router.include_router(users.router)
|
|
7
|
+
|
|
8
|
+
@app.get("/")
|
|
9
|
+
async def root():
|
|
10
|
+
return {"message": "{{pascalCase projectName}} API is running"}
|
|
11
|
+
|
|
12
|
+
__all__ = ["api_router"]
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from fastapi import APIRouter, HTTPException, Depends
|
|
2
|
+
from typing import List, Optional
|
|
3
|
+
from models.user import User, UserCreate, UserUpdate
|
|
4
|
+
from services.user_service import UserService
|
|
5
|
+
|
|
6
|
+
router = APIRouter()
|
|
7
|
+
user_service = UserService()
|
|
8
|
+
|
|
9
|
+
@router.get("/users", response_model=List[User])
|
|
10
|
+
async def get_users():
|
|
11
|
+
"""Get all users"""
|
|
12
|
+
try:
|
|
13
|
+
users = await user_service.get_all_users()
|
|
14
|
+
return users
|
|
15
|
+
except Exception as e:
|
|
16
|
+
raise HTTPException(status_code=500, detail="Failed to fetch users")
|
|
17
|
+
|
|
18
|
+
@router.get("/users/{user_id}", response_model=User)
|
|
19
|
+
async def get_user(user_id: str):
|
|
20
|
+
"""Get user by ID"""
|
|
21
|
+
try:
|
|
22
|
+
user = await user_service.get_user_by_id(user_id)
|
|
23
|
+
if not user:
|
|
24
|
+
raise HTTPException(status_code=404, detail="User not found")
|
|
25
|
+
return user
|
|
26
|
+
except HTTPException:
|
|
27
|
+
raise
|
|
28
|
+
except Exception as e:
|
|
29
|
+
raise HTTPException(status_code=500, detail="Failed to fetch user")
|
|
30
|
+
|
|
31
|
+
@router.post("/users", response_model=User, status_code=201)
|
|
32
|
+
async def create_user(user_data: UserCreate):
|
|
33
|
+
"""Create a new user"""
|
|
34
|
+
try:
|
|
35
|
+
user = await user_service.create_user(user_data)
|
|
36
|
+
return user
|
|
37
|
+
except Exception as e:
|
|
38
|
+
raise HTTPException(status_code=500, detail="Failed to create user")
|
|
39
|
+
|
|
40
|
+
@router.put("/users/{user_id}", response_model=User)
|
|
41
|
+
async def update_user(user_id: str, user_data: UserUpdate):
|
|
42
|
+
"""Update user by ID"""
|
|
43
|
+
try:
|
|
44
|
+
user = await user_service.update_user(user_id, user_data)
|
|
45
|
+
if not user:
|
|
46
|
+
raise HTTPException(status_code=404, detail="User not found")
|
|
47
|
+
return user
|
|
48
|
+
except HTTPException:
|
|
49
|
+
raise
|
|
50
|
+
except Exception as e:
|
|
51
|
+
raise HTTPException(status_code=500, detail="Failed to update user")
|
|
52
|
+
|
|
53
|
+
@router.delete("/users/{user_id}")
|
|
54
|
+
async def delete_user(user_id: str):
|
|
55
|
+
"""Delete user by ID"""
|
|
56
|
+
try:
|
|
57
|
+
success = await user_service.delete_user(user_id)
|
|
58
|
+
if not success:
|
|
59
|
+
raise HTTPException(status_code=404, detail="User not found")
|
|
60
|
+
return {"success": True, "message": "User deleted successfully"}
|
|
61
|
+
except HTTPException:
|
|
62
|
+
raise
|
|
63
|
+
except Exception as e:
|
|
64
|
+
raise HTTPException(status_code=500, detail="Failed to delete user")
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "{{projectName}}"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
authors = ["{{author}}"]
|
|
6
|
+
description = "{{description}}"
|
|
7
|
+
|
|
8
|
+
[dependencies]
|
|
9
|
+
# Web framework
|
|
10
|
+
actix-web = "4.4"
|
|
11
|
+
actix-cors = "0.7"
|
|
12
|
+
|
|
13
|
+
# Database
|
|
14
|
+
diesel = { version = "2.1", features = ["postgres", "uuid", "chrono", "r2d2"] }
|
|
15
|
+
diesel_migrations = "2.1"
|
|
16
|
+
|
|
17
|
+
# Serialization
|
|
18
|
+
serde = { version = "1.0", features = ["derive"] }
|
|
19
|
+
serde_json = "1.0"
|
|
20
|
+
|
|
21
|
+
# UUID
|
|
22
|
+
uuid = { version = "1.5", features = ["v4", "serde"] }
|
|
23
|
+
|
|
24
|
+
# Date/Time
|
|
25
|
+
chrono = { version = "0.4", features = ["serde"] }
|
|
26
|
+
|
|
27
|
+
# Environment
|
|
28
|
+
dotenv = "0.15"
|
|
29
|
+
|
|
30
|
+
# Logging
|
|
31
|
+
log = "0.4"
|
|
32
|
+
env_logger = "0.10"
|
|
33
|
+
|
|
34
|
+
# Async
|
|
35
|
+
tokio = { version = "1.32", features = ["full"] }
|
|
36
|
+
|
|
37
|
+
# Error handling
|
|
38
|
+
anyhow = "1.0"
|
|
39
|
+
thiserror = "1.0"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
use diesel::prelude::*;
|
|
2
|
+
use diesel::r2d2::{self, ConnectionManager};
|
|
3
|
+
use std::env;
|
|
4
|
+
|
|
5
|
+
pub type DbPool = r2d2::Pool<ConnectionManager<PgConnection>>;
|
|
6
|
+
|
|
7
|
+
pub fn establish_connection() -> DbPool {
|
|
8
|
+
dotenv::dotenv().ok();
|
|
9
|
+
|
|
10
|
+
let database_url = env::var("DATABASE_URL")
|
|
11
|
+
.expect("DATABASE_URL must be set");
|
|
12
|
+
|
|
13
|
+
let manager = ConnectionManager::<PgConnection>::new(database_url);
|
|
14
|
+
r2d2::Pool::builder()
|
|
15
|
+
.build(manager)
|
|
16
|
+
.expect("Failed to create pool.")
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
pub fn run_migrations(pool: &DbPool) {
|
|
20
|
+
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
|
|
21
|
+
|
|
22
|
+
const MIGRATIONS: EmbeddedMigrations = embed_migrations!();
|
|
23
|
+
|
|
24
|
+
let mut conn = pool.get().expect("Failed to get connection");
|
|
25
|
+
conn.run_pending_migrations(MIGRATIONS)
|
|
26
|
+
.expect("Failed to run migrations");
|
|
27
|
+
}
|