Upload 80 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- polisage.db +0 -0
- src/__init__.py +0 -0
- src/__pycache__/__init__.cpython-310.pyc +0 -0
- src/__pycache__/__init__.cpython-311.pyc +0 -0
- src/__pycache__/decorators.cpython-310.pyc +0 -0
- src/__pycache__/decorators.cpython-311.pyc +0 -0
- src/__pycache__/extensions.cpython-310.pyc +0 -0
- src/__pycache__/extensions.cpython-311.pyc +0 -0
- src/__pycache__/main.cpython-310.pyc +0 -0
- src/__pycache__/main.cpython-311.pyc +0 -0
- src/create_sample_users.py +45 -0
- src/decorators.py +15 -0
- src/extensions.py +7 -0
- src/main.py +99 -0
- src/models/__pycache__/amendment.cpython-310.pyc +0 -0
- src/models/__pycache__/amendment.cpython-311.pyc +0 -0
- src/models/__pycache__/analysis.cpython-310.pyc +0 -0
- src/models/__pycache__/analysis.cpython-311.pyc +0 -0
- src/models/__pycache__/cross_reference.cpython-310.pyc +0 -0
- src/models/__pycache__/cross_reference.cpython-311.pyc +0 -0
- src/models/__pycache__/draft.cpython-310.pyc +0 -0
- src/models/__pycache__/draft.cpython-311.pyc +0 -0
- src/models/__pycache__/legislation.cpython-310.pyc +0 -0
- src/models/__pycache__/legislation.cpython-311.pyc +0 -0
- src/models/__pycache__/monitoring.cpython-310.pyc +0 -0
- src/models/__pycache__/monitoring.cpython-311.pyc +0 -0
- src/models/__pycache__/recommendation.cpython-310.pyc +0 -0
- src/models/__pycache__/recommendation.cpython-311.pyc +0 -0
- src/models/__pycache__/user.cpython-310.pyc +0 -0
- src/models/__pycache__/user.cpython-311.pyc +0 -0
- src/models/amendment.py +17 -0
- src/models/analysis.py +22 -0
- src/models/cross_reference.py +18 -0
- src/models/draft.py +18 -0
- src/models/legislation.py +28 -0
- src/models/monitoring.py +37 -0
- src/models/recommendation.py +17 -0
- src/models/user.py +27 -0
- src/routes/__pycache__/amendment.cpython-310.pyc +0 -0
- src/routes/__pycache__/amendment.cpython-311.pyc +0 -0
- src/routes/__pycache__/analysis.cpython-310.pyc +0 -0
- src/routes/__pycache__/analysis.cpython-311.pyc +0 -0
- src/routes/__pycache__/auth.cpython-310.pyc +0 -0
- src/routes/__pycache__/auth.cpython-311.pyc +0 -0
- src/routes/__pycache__/drafting.cpython-310.pyc +0 -0
- src/routes/__pycache__/drafting.cpython-311.pyc +0 -0
- src/routes/__pycache__/monitoring.cpython-310.pyc +0 -0
- src/routes/__pycache__/monitoring.cpython-311.pyc +0 -0
- src/routes/__pycache__/recommendation.cpython-310.pyc +0 -0
- 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
|
|