1+ from flask import Flask , request , jsonify
2+ from flask_restful import Resource , Api
3+ from flask_sqlalchemy import SQLAlchemy
4+ import json
5+ import os
6+
7+ app = Flask (__name__ )
8+ api = Api (app )
9+
10+ # Configure SQLite database
11+ basedir = os .path .abspath (os .path .dirname (__file__ ))
12+ app .config ['SQLALCHEMY_DATABASE_URI' ] = f'sqlite:///{ os .path .join (basedir , "projects.db" )} '
13+ app .config ['SQLALCHEMY_TRACK_MODIFICATIONS' ] = False
14+
15+ db = SQLAlchemy (app )
16+
17+ # Models
18+ class Project (db .Model ):
19+ id = db .Column (db .Integer , primary_key = True )
20+ name = db .Column (db .String (100 ), nullable = False , unique = True )
21+ description = db .Column (db .Text )
22+ modules = db .relationship ('Module' , backref = 'project' , lazy = True , cascade = 'all, delete-orphan' )
23+
24+ def to_dict (self ):
25+ return {
26+ 'id' : self .id ,
27+ 'name' : self .name ,
28+ 'description' : self .description ,
29+ 'module_count' : len (self .modules )
30+ }
31+
32+ class Module (db .Model ):
33+ id = db .Column (db .Integer , primary_key = True )
34+ name = db .Column (db .String (100 ), nullable = False )
35+ project_id = db .Column (db .Integer , db .ForeignKey ('project.id' ), nullable = False )
36+ json_content = db .Column (db .Text , nullable = False )
37+
38+ __table_args__ = (db .UniqueConstraint ('name' , 'project_id' , name = '_module_project_uc' ),)
39+
40+ def to_dict (self ):
41+ return {
42+ 'id' : self .id ,
43+ 'name' : self .name ,
44+ 'project_id' : self .project_id ,
45+ 'json_content' : json .loads (self .json_content ) if self .json_content else {}
46+ }
47+
48+ # Resources
49+ class ProjectListResource (Resource ):
50+ def get (self ):
51+ """Get list of all projects"""
52+ projects = Project .query .all ()
53+ return {'projects' : [project .to_dict () for project in projects ]}
54+
55+ def post (self ):
56+ """Create a new project"""
57+ data = request .get_json ()
58+ if not data or 'name' not in data :
59+ return {'error' : 'Project name is required' }, 400
60+
61+ # Check if project already exists
62+ existing_project = Project .query .filter_by (name = data ['name' ]).first ()
63+ if existing_project :
64+ return {'error' : 'Project with this name already exists' }, 409
65+
66+ project = Project (
67+ name = data ['name' ],
68+ description = data .get ('description' , '' )
69+ )
70+
71+ try :
72+ db .session .add (project )
73+ db .session .commit ()
74+ return project .to_dict (), 201
75+ except Exception as e :
76+ db .session .rollback ()
77+ return {'error' : 'Failed to create project' }, 500
78+
79+ class ProjectResource (Resource ):
80+ def get (self , project_id ):
81+ """Get a specific project with its modules"""
82+ project = Project .query .get_or_404 (project_id )
83+ project_dict = project .to_dict ()
84+ project_dict ['modules' ] = [
85+ {
86+ 'id' : module .id ,
87+ 'name' : module .name
88+ } for module in project .modules
89+ ]
90+ return project_dict
91+
92+ def put (self , project_id ):
93+ """Update a project"""
94+ project = Project .query .get_or_404 (project_id )
95+ data = request .get_json ()
96+
97+ if not data :
98+ return {'error' : 'No data provided' }, 400
99+
100+ if 'name' in data :
101+ # Check if another project has this name
102+ existing = Project .query .filter (Project .name == data ['name' ], Project .id != project_id ).first ()
103+ if existing :
104+ return {'error' : 'Project with this name already exists' }, 409
105+ project .name = data ['name' ]
106+
107+ if 'description' in data :
108+ project .description = data ['description' ]
109+
110+ try :
111+ db .session .commit ()
112+ return project .to_dict ()
113+ except Exception as e :
114+ db .session .rollback ()
115+ return {'error' : 'Failed to update project' }, 500
116+
117+ def delete (self , project_id ):
118+ """Delete a project and all its modules"""
119+ project = Project .query .get_or_404 (project_id )
120+
121+ try :
122+ db .session .delete (project )
123+ db .session .commit ()
124+ return {'message' : 'Project deleted successfully' }
125+ except Exception as e :
126+ db .session .rollback ()
127+ return {'error' : 'Failed to delete project' }, 500
128+
129+ class ModuleListResource (Resource ):
130+ def get (self , project_id ):
131+ """Get all modules for a project"""
132+ project = Project .query .get_or_404 (project_id )
133+ modules = Module .query .filter_by (project_id = project_id ).all ()
134+ return {
135+ 'project' : project .to_dict (),
136+ 'modules' : [module .to_dict () for module in modules ]
137+ }
138+
139+ def post (self , project_id ):
140+ """Create a new module in a project"""
141+ project = Project .query .get_or_404 (project_id )
142+ data = request .get_json ()
143+
144+ if not data or 'name' not in data :
145+ return {'error' : 'Module name is required' }, 400
146+
147+ if 'json_content' not in data :
148+ return {'error' : 'JSON content is required' }, 400
149+
150+ # Check if module already exists in this project
151+ existing_module = Module .query .filter_by (name = data ['name' ], project_id = project_id ).first ()
152+ if existing_module :
153+ return {'error' : 'Module with this name already exists in this project' }, 409
154+
155+ # Validate JSON content
156+ try :
157+ json_content = json .dumps (data ['json_content' ])
158+ except (TypeError , ValueError ):
159+ return {'error' : 'Invalid JSON content' }, 400
160+
161+ module = Module (
162+ name = data ['name' ],
163+ project_id = project_id ,
164+ json_content = json_content
165+ )
166+
167+ try :
168+ db .session .add (module )
169+ db .session .commit ()
170+ return module .to_dict (), 201
171+ except Exception as e :
172+ db .session .rollback ()
173+ return {'error' : 'Failed to create module' }, 500
174+
175+ class ModuleResource (Resource ):
176+ def get (self , project_id , module_id ):
177+ """Get a specific module"""
178+ module = Module .query .filter_by (id = module_id , project_id = project_id ).first_or_404 ()
179+ return module .to_dict ()
180+
181+ def put (self , project_id , module_id ):
182+ """Update a module's content"""
183+ module = Module .query .filter_by (id = module_id , project_id = project_id ).first_or_404 ()
184+ data = request .get_json ()
185+
186+ if not data :
187+ return {'error' : 'No data provided' }, 400
188+
189+ if 'name' in data :
190+ # Check if another module in this project has this name
191+ existing = Module .query .filter (
192+ Module .name == data ['name' ],
193+ Module .project_id == project_id ,
194+ Module .id != module_id
195+ ).first ()
196+ if existing :
197+ return {'error' : 'Module with this name already exists in this project' }, 409
198+ module .name = data ['name' ]
199+
200+ if 'json_content' in data :
201+ try :
202+ json_content = json .dumps (data ['json_content' ])
203+ module .json_content = json_content
204+ except (TypeError , ValueError ):
205+ return {'error' : 'Invalid JSON content' }, 400
206+
207+ try :
208+ db .session .commit ()
209+ return module .to_dict ()
210+ except Exception as e :
211+ db .session .rollback ()
212+ return {'error' : 'Failed to update module' }, 500
213+
214+ def delete (self , project_id , module_id ):
215+ """Delete a module"""
216+ module = Module .query .filter_by (id = module_id , project_id = project_id ).first_or_404 ()
217+
218+ try :
219+ db .session .delete (module )
220+ db .session .commit ()
221+ return {'message' : 'Module deleted successfully' }
222+ except Exception as e :
223+ db .session .rollback ()
224+ return {'error' : 'Failed to delete module' }, 500
225+
226+ # Register API routes
227+ api .add_resource (ProjectListResource , '/projects' )
228+ api .add_resource (ProjectResource , '/projects/<int:project_id>' )
229+ api .add_resource (ModuleListResource , '/projects/<int:project_id>/modules' )
230+ api .add_resource (ModuleResource , '/projects/<int:project_id>/modules/<int:module_id>' )
231+
232+ @app .route ('/' )
233+ def index ():
234+ return jsonify ({
235+ 'message' : 'Project and Module Management API' ,
236+ 'endpoints' : {
237+ 'projects' : '/projects' ,
238+ 'specific_project' : '/projects/<project_id>' ,
239+ 'project_modules' : '/projects/<project_id>/modules' ,
240+ 'specific_module' : '/projects/<project_id>/modules/<module_id>'
241+ }
242+ })
243+
244+ if __name__ == '__main__' :
245+ with app .app_context ():
246+ db .create_all ()
247+ app .run (debug = True , port = 5001 )
0 commit comments