yasserrmd commited on
Commit
0a40ab8
·
verified ·
1 Parent(s): 8121c32

Upload 80 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. polisage.db +0 -0
  2. src/__init__.py +0 -0
  3. src/__pycache__/__init__.cpython-310.pyc +0 -0
  4. src/__pycache__/__init__.cpython-311.pyc +0 -0
  5. src/__pycache__/decorators.cpython-310.pyc +0 -0
  6. src/__pycache__/decorators.cpython-311.pyc +0 -0
  7. src/__pycache__/extensions.cpython-310.pyc +0 -0
  8. src/__pycache__/extensions.cpython-311.pyc +0 -0
  9. src/__pycache__/main.cpython-310.pyc +0 -0
  10. src/__pycache__/main.cpython-311.pyc +0 -0
  11. src/create_sample_users.py +45 -0
  12. src/decorators.py +15 -0
  13. src/extensions.py +7 -0
  14. src/main.py +99 -0
  15. src/models/__pycache__/amendment.cpython-310.pyc +0 -0
  16. src/models/__pycache__/amendment.cpython-311.pyc +0 -0
  17. src/models/__pycache__/analysis.cpython-310.pyc +0 -0
  18. src/models/__pycache__/analysis.cpython-311.pyc +0 -0
  19. src/models/__pycache__/cross_reference.cpython-310.pyc +0 -0
  20. src/models/__pycache__/cross_reference.cpython-311.pyc +0 -0
  21. src/models/__pycache__/draft.cpython-310.pyc +0 -0
  22. src/models/__pycache__/draft.cpython-311.pyc +0 -0
  23. src/models/__pycache__/legislation.cpython-310.pyc +0 -0
  24. src/models/__pycache__/legislation.cpython-311.pyc +0 -0
  25. src/models/__pycache__/monitoring.cpython-310.pyc +0 -0
  26. src/models/__pycache__/monitoring.cpython-311.pyc +0 -0
  27. src/models/__pycache__/recommendation.cpython-310.pyc +0 -0
  28. src/models/__pycache__/recommendation.cpython-311.pyc +0 -0
  29. src/models/__pycache__/user.cpython-310.pyc +0 -0
  30. src/models/__pycache__/user.cpython-311.pyc +0 -0
  31. src/models/amendment.py +17 -0
  32. src/models/analysis.py +22 -0
  33. src/models/cross_reference.py +18 -0
  34. src/models/draft.py +18 -0
  35. src/models/legislation.py +28 -0
  36. src/models/monitoring.py +37 -0
  37. src/models/recommendation.py +17 -0
  38. src/models/user.py +27 -0
  39. src/routes/__pycache__/amendment.cpython-310.pyc +0 -0
  40. src/routes/__pycache__/amendment.cpython-311.pyc +0 -0
  41. src/routes/__pycache__/analysis.cpython-310.pyc +0 -0
  42. src/routes/__pycache__/analysis.cpython-311.pyc +0 -0
  43. src/routes/__pycache__/auth.cpython-310.pyc +0 -0
  44. src/routes/__pycache__/auth.cpython-311.pyc +0 -0
  45. src/routes/__pycache__/drafting.cpython-310.pyc +0 -0
  46. src/routes/__pycache__/drafting.cpython-311.pyc +0 -0
  47. src/routes/__pycache__/monitoring.cpython-310.pyc +0 -0
  48. src/routes/__pycache__/monitoring.cpython-311.pyc +0 -0
  49. src/routes/__pycache__/recommendation.cpython-310.pyc +0 -0
  50. src/routes/__pycache__/recommendation.cpython-311.pyc +0 -0
polisage.db ADDED
Binary file (77.8 kB). View file
 
src/__init__.py ADDED
File without changes
src/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (134 Bytes). View file
 
src/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (150 Bytes). View file
 
src/__pycache__/decorators.cpython-310.pyc ADDED
Binary file (788 Bytes). View file
 
src/__pycache__/decorators.cpython-311.pyc ADDED
Binary file (1.13 kB). View file
 
src/__pycache__/extensions.cpython-310.pyc ADDED
Binary file (261 Bytes). View file
 
src/__pycache__/extensions.cpython-311.pyc ADDED
Binary file (351 Bytes). View file
 
src/__pycache__/main.cpython-310.pyc ADDED
Binary file (3.16 kB). View file
 
src/__pycache__/main.cpython-311.pyc ADDED
Binary file (6.27 kB). View file
 
src/create_sample_users.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # src/create_sample_users.py
2
+ import sys
3
+ import os
4
+
5
+ # Add project root to sys.path to allow imports from src
6
+ sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
7
+
8
+ from src.main import app, db
9
+ from src.models.user import User
10
+
11
+ def create_users():
12
+ """Creates sample users in the database."""
13
+ with app.app_context():
14
+ print("Creating sample users...")
15
+
16
+ # Check if users already exist
17
+ admin_user = User.query.filter_by(username="admin").first()
18
+ analyst_user = User.query.filter_by(username="analyst").first()
19
+
20
+ if not admin_user:
21
+ admin = User(username="admin", full_name="Admin User", role="Administrator")
22
+ admin.set_password("password123") # Use a more secure password in production
23
+ db.session.add(admin)
24
+ print("Created admin user (password: password123)")
25
+ else:
26
+ print("Admin user already exists.")
27
+
28
+ if not analyst_user:
29
+ analyst = User(username="analyst", full_name="Legal Analyst", role="Analyst")
30
+ analyst.set_password("testpass") # Use a more secure password in production
31
+ db.session.add(analyst)
32
+ print("Created analyst user (password: testpass)")
33
+ else:
34
+ print("Analyst user already exists.")
35
+
36
+ try:
37
+ db.session.commit()
38
+ print("Users committed to database.")
39
+ except Exception as e:
40
+ db.session.rollback()
41
+ print(f"Error creating users: {e}")
42
+
43
+ if __name__ == "__main__":
44
+ create_users()
45
+
src/decorators.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # src/decorators.py
2
+ from functools import wraps
3
+ from flask import session, flash, redirect, url_for, request
4
+
5
+ def login_required(f):
6
+ """Decorator to ensure user is logged in before accessing a route."""
7
+ @wraps(f)
8
+ def decorated_function(*args, **kwargs):
9
+ if 'user_id' not in session:
10
+ flash('Please log in to access this page.', 'warning')
11
+ # Store the intended destination to redirect after login
12
+ return redirect(url_for('auth.login', next=request.url))
13
+ return f(*args, **kwargs)
14
+ return decorated_function
15
+
src/extensions.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # src/extensions.py
2
+ from flask_sqlalchemy import SQLAlchemy
3
+ from flask_migrate import Migrate
4
+
5
+ db = SQLAlchemy()
6
+ migrate = Migrate()
7
+
src/main.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ import re # Import re for nl2br filter
4
+ # DON'T CHANGE THIS !!!
5
+ sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
6
+
7
+ from flask import Flask, redirect, url_for, session, request, flash, render_template # Added render_template
8
+ from jinja2 import pass_eval_context # Use pass_eval_context
9
+ from markupsafe import Markup, escape # Import Markup and escape from markupsafe
10
+ from src.extensions import db, migrate # Import from extensions
11
+ from src.decorators import login_required # Import from decorators
12
+
13
+ # --- Custom Jinja Filter ---
14
+ _paragraph_re = re.compile(r'\r\n|\r|\n')
15
+
16
+ @pass_eval_context
17
+ def nl2br(eval_ctx, value):
18
+ """Converts newlines into <p> and <br />s."""
19
+ # Ensure value is treated as string before splitting
20
+ value_str = str(escape(value))
21
+ result = u'\n\n'.join(u'<p>%s</p>' % p.replace('\n', Markup('<br />\n'))
22
+ for p in _paragraph_re.split(value_str))
23
+ if eval_ctx.autoescape:
24
+ result = Markup(result)
25
+ return result
26
+
27
+ def create_app():
28
+ """Application Factory Pattern"""
29
+ app = Flask(__name__,
30
+ static_folder=os.path.join(os.path.dirname(__file__), 'static'),
31
+ template_folder=os.path.join(os.path.dirname(__file__), 'templates'))
32
+
33
+ # --- Configuration ---
34
+ app.config['SECRET_KEY'] = os.urandom(24)
35
+ basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) # Base directory is polisage_app
36
+ app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'polisage.db')
37
+ app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
38
+
39
+ # --- Initialize Extensions ---
40
+ db.init_app(app)
41
+ migrate.init_app(app, db)
42
+
43
+ # --- Register Custom Filters ---
44
+ app.jinja_env.filters['nl2br'] = nl2br
45
+
46
+ # --- Import and Register Blueprints ---
47
+ # Import blueprints inside the factory function to avoid circular imports
48
+ from src.routes.auth import auth_bp
49
+ from src.routes.drafting import drafting_bp
50
+ from src.routes.amendment import amendment_bp
51
+ from src.routes.monitoring import monitoring_bp
52
+ from src.routes.analysis import analysis_bp
53
+ from src.routes.recommendation import recommendation_bp
54
+ # Import dashboard blueprint later if created
55
+ # from src.routes.dashboard import dashboard_bp
56
+
57
+ app.register_blueprint(auth_bp)
58
+ app.register_blueprint(drafting_bp)
59
+ app.register_blueprint(amendment_bp)
60
+ app.register_blueprint(monitoring_bp)
61
+ app.register_blueprint(analysis_bp)
62
+ app.register_blueprint(recommendation_bp)
63
+ # app.register_blueprint(dashboard_bp)
64
+
65
+ # --- Import Models (Needed for Flask-Migrate context) ---
66
+ # Although models are used within routes/extensions, importing them here
67
+ # ensures they are known to Flask-Migrate when running commands.
68
+ with app.app_context():
69
+ from src.models import user, legislation, draft, amendment, monitoring, analysis, recommendation, cross_reference
70
+
71
+ # --- Basic Routes ---
72
+ @app.route('/')
73
+ @login_required
74
+ def index():
75
+ # Redirect to a default page, e.g., drafts list or a future dashboard
76
+ return redirect(url_for('drafting.list_drafts'))
77
+
78
+ # Add a simple dashboard route placeholder
79
+ @app.route('/dashboard')
80
+ @login_required
81
+ def dashboard():
82
+ # Placeholder for a real dashboard
83
+ username = session.get('username', 'Guest')
84
+ # Query some basic stats later
85
+ draft_count = draft.Draft.query.count()
86
+ analysis_count = analysis.ImpactAnalysis.query.count()
87
+ rec_count = recommendation.Recommendation.query.count()
88
+ return render_template('dashboard.html', username=username, draft_count=draft_count, analysis_count=analysis_count, rec_count=rec_count)
89
+
90
+ return app
91
+
92
+ # Create the app instance using the factory
93
+ app = create_app()
94
+
95
+ # --- Main Execution (for running with 'python src/main.py') ---
96
+ if __name__ == '__main__':
97
+ # Note: Recommended to run using 'flask run' after setting FLASK_APP=src.main:app
98
+ app.run(host='0.0.0.0', port=5000, debug=True)
99
+
src/models/__pycache__/amendment.cpython-310.pyc ADDED
Binary file (1.01 kB). View file
 
src/models/__pycache__/amendment.cpython-311.pyc ADDED
Binary file (1.76 kB). View file
 
src/models/__pycache__/analysis.cpython-310.pyc ADDED
Binary file (1.02 kB). View file
 
src/models/__pycache__/analysis.cpython-311.pyc ADDED
Binary file (1.75 kB). View file
 
src/models/__pycache__/cross_reference.cpython-310.pyc ADDED
Binary file (1.07 kB). View file
 
src/models/__pycache__/cross_reference.cpython-311.pyc ADDED
Binary file (1.78 kB). View file
 
src/models/__pycache__/draft.cpython-310.pyc ADDED
Binary file (996 Bytes). View file
 
src/models/__pycache__/draft.cpython-311.pyc ADDED
Binary file (1.79 kB). View file
 
src/models/__pycache__/legislation.cpython-310.pyc ADDED
Binary file (1.51 kB). View file
 
src/models/__pycache__/legislation.cpython-311.pyc ADDED
Binary file (2.64 kB). View file
 
src/models/__pycache__/monitoring.cpython-310.pyc ADDED
Binary file (1.8 kB). View file
 
src/models/__pycache__/monitoring.cpython-311.pyc ADDED
Binary file (3.19 kB). View file
 
src/models/__pycache__/recommendation.cpython-310.pyc ADDED
Binary file (1.02 kB). View file
 
src/models/__pycache__/recommendation.cpython-311.pyc ADDED
Binary file (1.72 kB). View file
 
src/models/__pycache__/user.cpython-310.pyc ADDED
Binary file (1.38 kB). View file
 
src/models/__pycache__/user.cpython-311.pyc ADDED
Binary file (2.25 kB). View file
 
src/models/amendment.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.extensions import db
2
+ import datetime
3
+
4
+ class Amendment(db.Model):
5
+ __tablename__ = 'amendments'
6
+ id = db.Column(db.Integer, primary_key=True)
7
+ legislation_id = db.Column(db.Integer, db.ForeignKey('legislation.id'), nullable=False)
8
+ proposed_changes = db.Column(db.Text, nullable=False)
9
+ rationale = db.Column(db.Text)
10
+ status = db.Column(db.String, default='Proposed') # e.g., 'Proposed', 'Review', 'Approved', 'Rejected'
11
+ author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
12
+ created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
13
+ last_updated = db.Column(db.DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
14
+
15
+ def __repr__(self):
16
+ return f'<Amendment {self.id} for Legislation {self.legislation_id}>'
17
+
src/models/analysis.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.extensions import db
2
+ import datetime
3
+
4
+ class ImpactAnalysis(db.Model):
5
+ __tablename__ = 'impact_analyses'
6
+ id = db.Column(db.Integer, primary_key=True)
7
+ # Using polymorphic association for document_id might be better, but for simplicity:
8
+ document_id = db.Column(db.Integer, nullable=False) # Can be legislation_id, draft_id, or amendment_id
9
+ document_type = db.Column(db.String, nullable=False) # 'Legislation', 'Draft', 'Amendment'
10
+ analysis_type = db.Column(db.String, nullable=False) # e.g., 'Societal', 'Economic', 'Environmental'
11
+ predicted_impact = db.Column(db.Text)
12
+ confidence_score = db.Column(db.Float)
13
+ rationale = db.Column(db.Text)
14
+ generated_by_user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
15
+ generated_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
16
+
17
+ # Add __table_args__ for potential index or constraints if needed later
18
+ # Example: db.Index('idx_doc_type_id', 'document_type', 'document_id')
19
+
20
+ def __repr__(self):
21
+ return f'<ImpactAnalysis {self.id} for {self.document_type} {self.document_id}>'
22
+
src/models/cross_reference.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.extensions import db
2
+ import datetime
3
+
4
+ class CrossReference(db.Model):
5
+ __tablename__ = 'cross_references'
6
+ id = db.Column(db.Integer, primary_key=True)
7
+ source_legislation_id = db.Column(db.Integer, db.ForeignKey('legislation.id'), nullable=False)
8
+ target_legislation_id = db.Column(db.Integer, db.ForeignKey('legislation.id'), nullable=False)
9
+ relationship_type = db.Column(db.String, nullable=False) # e.g., 'Cites', 'Amends', 'Conflicts With', 'Related To'
10
+ details = db.Column(db.Text) # Optional: Specific section or context
11
+ identified_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
12
+
13
+ # Prevent duplicate references
14
+ __table_args__ = (db.UniqueConstraint('source_legislation_id', 'target_legislation_id', 'relationship_type', name='_source_target_rel_uc'),)
15
+
16
+ def __repr__(self):
17
+ return f'<CrossRef {self.id}: {self.source_legislation_id} {self.relationship_type} {self.target_legislation_id}>'
18
+
src/models/draft.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.extensions import db
2
+ import datetime
3
+
4
+ class Draft(db.Model):
5
+ __tablename__ = 'drafts'
6
+ id = db.Column(db.Integer, primary_key=True)
7
+ title = db.Column(db.String, nullable=False)
8
+ content = db.Column(db.Text)
9
+ policy_intent = db.Column(db.Text)
10
+ status = db.Column(db.String, default='Draft') # e.g., 'Draft', 'Review', 'Approved', 'Rejected'
11
+ author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
12
+ related_legislation_id = db.Column(db.Integer, db.ForeignKey('legislation.id')) # Optional
13
+ created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
14
+ last_updated = db.Column(db.DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
15
+
16
+ def __repr__(self):
17
+ return f'<Draft {self.id}: {self.title[:50]}>'
18
+
src/models/legislation.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.extensions import db
2
+ import datetime
3
+
4
+ class Legislation(db.Model):
5
+ __tablename__ = 'legislation'
6
+ id = db.Column(db.Integer, primary_key=True)
7
+ title = db.Column(db.String, nullable=False)
8
+ full_text = db.Column(db.Text)
9
+ jurisdiction = db.Column(db.String) # e.g., 'Federal', 'State - CA'
10
+ type = db.Column(db.String) # e.g., 'Statute', 'Regulation', 'Policy'
11
+ status = db.Column(db.String, default='Active') # e.g., 'Active', 'Repealed', 'Amended'
12
+ effective_date = db.Column(db.Date)
13
+ enactment_date = db.Column(db.Date)
14
+ source_url = db.Column(db.String)
15
+ last_updated = db.Column(db.DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
16
+ created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
17
+
18
+ # Relationships
19
+ drafts = db.relationship('Draft', backref='related_legislation', lazy=True)
20
+ amendments = db.relationship('Amendment', backref='legislation', lazy=True)
21
+ monitored_events = db.relationship('MonitoredEvent', backref='related_legislation', lazy=True)
22
+ recommendations = db.relationship('Recommendation', backref='related_legislation', lazy=True)
23
+ source_cross_references = db.relationship('CrossReference', foreign_keys='CrossReference.source_legislation_id', backref='source_legislation', lazy=True)
24
+ target_cross_references = db.relationship('CrossReference', foreign_keys='CrossReference.target_legislation_id', backref='target_legislation', lazy=True)
25
+
26
+ def __repr__(self):
27
+ return f'<Legislation {self.id}: {self.title[:50]}>'
28
+
src/models/monitoring.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.extensions import db
2
+ import datetime
3
+
4
+ class MonitoringSource(db.Model):
5
+ __tablename__ = 'monitoring_sources'
6
+ id = db.Column(db.Integer, primary_key=True)
7
+ name = db.Column(db.String, nullable=False)
8
+ url = db.Column(db.String, unique=True, nullable=False)
9
+ type = db.Column(db.String, nullable=False) # e.g., 'Official Gazette', 'Court Website', 'News Feed', 'RSS'
10
+ frequency_minutes = db.Column(db.Integer, default=1440) # Default: daily
11
+ last_checked = db.Column(db.DateTime)
12
+ is_active = db.Column(db.Boolean, default=True)
13
+ created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
14
+
15
+ # Relationship
16
+ events = db.relationship('MonitoredEvent', backref='source', lazy=True)
17
+
18
+ def __repr__(self):
19
+ return f'<MonitoringSource {self.id}: {self.name}>'
20
+
21
+ class MonitoredEvent(db.Model):
22
+ __tablename__ = 'monitored_events'
23
+ id = db.Column(db.Integer, primary_key=True)
24
+ source_id = db.Column(db.Integer, db.ForeignKey('monitoring_sources.id'), nullable=False)
25
+ detected_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
26
+ event_summary = db.Column(db.Text, nullable=False)
27
+ event_details = db.Column(db.Text)
28
+ relevance_score = db.Column(db.Float) # Estimated relevance (e.g., 0.0 to 1.0)
29
+ related_legislation_id = db.Column(db.Integer, db.ForeignKey('legislation.id')) # Optional
30
+ status = db.Column(db.String, default='New') # e.g., 'New', 'Reviewed', 'Actioned'
31
+
32
+ # Relationship
33
+ recommendations = db.relationship('Recommendation', backref='source_event', lazy=True)
34
+
35
+ def __repr__(self):
36
+ return f'<MonitoredEvent {self.id} from Source {self.source_id}>'
37
+
src/models/recommendation.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.extensions import db
2
+ import datetime
3
+
4
+ class Recommendation(db.Model):
5
+ __tablename__ = 'recommendations'
6
+ id = db.Column(db.Integer, primary_key=True)
7
+ related_legislation_id = db.Column(db.Integer, db.ForeignKey('legislation.id')) # Optional
8
+ recommendation_type = db.Column(db.String, nullable=False) # e.g., 'Update', 'Consolidate', 'Remove', 'New'
9
+ recommendation_text = db.Column(db.Text, nullable=False)
10
+ rationale = db.Column(db.Text)
11
+ source_event_id = db.Column(db.Integer, db.ForeignKey('monitored_events.id')) # Optional
12
+ status = db.Column(db.String, default='New') # e.g., 'New', 'Reviewed', 'Implemented', 'Rejected'
13
+ generated_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
14
+
15
+ def __repr__(self):
16
+ return f'<Recommendation {self.id}: {self.recommendation_type}>'
17
+
src/models/user.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.extensions import db
2
+ from werkzeug.security import generate_password_hash, check_password_hash
3
+ import datetime
4
+
5
+ class User(db.Model):
6
+ __tablename__ = 'users'
7
+ id = db.Column(db.Integer, primary_key=True)
8
+ username = db.Column(db.String(80), unique=True, nullable=False)
9
+ password_hash = db.Column(db.String(128), nullable=False)
10
+ full_name = db.Column(db.String(120))
11
+ role = db.Column(db.String(80)) # e.g., 'Legal Director', 'Analyst'
12
+ created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
13
+
14
+ # Relationships (examples, adjust as needed)
15
+ drafts = db.relationship('Draft', backref='author', lazy=True)
16
+ amendments = db.relationship('Amendment', backref='author', lazy=True)
17
+ analyses = db.relationship('ImpactAnalysis', backref='generator', lazy=True)
18
+
19
+ def set_password(self, password):
20
+ self.password_hash = generate_password_hash(password)
21
+
22
+ def check_password(self, password):
23
+ return check_password_hash(self.password_hash, password)
24
+
25
+ def __repr__(self):
26
+ return f'<User {self.username}>'
27
+
src/routes/__pycache__/amendment.cpython-310.pyc ADDED
Binary file (2.31 kB). View file
 
src/routes/__pycache__/amendment.cpython-311.pyc ADDED
Binary file (4.5 kB). View file
 
src/routes/__pycache__/analysis.cpython-310.pyc ADDED
Binary file (3.83 kB). View file
 
src/routes/__pycache__/analysis.cpython-311.pyc ADDED
Binary file (8.35 kB). View file
 
src/routes/__pycache__/auth.cpython-310.pyc ADDED
Binary file (1.36 kB). View file
 
src/routes/__pycache__/auth.cpython-311.pyc ADDED
Binary file (2.63 kB). View file
 
src/routes/__pycache__/drafting.cpython-310.pyc ADDED
Binary file (2.74 kB). View file
 
src/routes/__pycache__/drafting.cpython-311.pyc ADDED
Binary file (5.49 kB). View file
 
src/routes/__pycache__/monitoring.cpython-310.pyc ADDED
Binary file (3.09 kB). View file
 
src/routes/__pycache__/monitoring.cpython-311.pyc ADDED
Binary file (5.54 kB). View file
 
src/routes/__pycache__/recommendation.cpython-310.pyc ADDED
Binary file (2.61 kB). View file
 
src/routes/__pycache__/recommendation.cpython-311.pyc ADDED
Binary file (4.49 kB). View file