Files
TimeTracker/app/models/user_client.py
T
Dries Peeters ae9ee9dec1 feat: add subcontractor role with assigned clients (scope-restricted access)
- Add user_clients table and UserClient model for many-to-many user-client assignment
- Add 'subcontractor' system role; users with this role see only assigned clients and their projects
- User helpers: is_scope_restricted, get_allowed_client_ids(), get_allowed_project_ids()
- Admin user form: assign clients when role is Subcontractor (multi-select, JS toggle)
- Scope filtering: clients, projects, time entries, reports, invoices, timer, API v1
- Direct access to out-of-scope client/project returns 403 (web and API)
- Migration 127_add_user_clients_table; scope_filter utility and ProjectService scope_client_ids
- Docs: SUBCONTRACTOR_ROLE.md, ADVANCED_PERMISSIONS.md, RBAC, CLIENT_PORTAL, README, CHANGELOG

Addresses GitHub Discussion #476 (user with limited clients/projects).
2026-02-16 07:12:57 +01:00

21 lines
843 B
Python

"""User-Client association for subcontractor scope (restrict user to assigned clients)."""
from datetime import datetime
from app import db
class UserClient(db.Model):
"""Association: user is allowed to see this client (subcontractor scope)."""
__tablename__ = "user_clients"
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
client_id = db.Column(db.Integer, db.ForeignKey("clients.id", ondelete="CASCADE"), nullable=False, index=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
__table_args__ = (db.UniqueConstraint("user_id", "client_id", name="uq_user_client"),)
def __repr__(self):
return f"<UserClient user_id={self.user_id} client_id={self.client_id}>"