Files
IT_asset_management/app/models/user.py

97 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from datetime import datetime
from app.extensions import db
class User(db.Model):
"""
Tracked employees / users of IT assets.
Privacy / GDPR masking:
When a user leaves the company, an admin can mask the record.
All PII fields are cleared and replaced with a reference to the
permanent windows_id so asset history is preserved without
exposing personal data during audits.
"""
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
# Permanent, non-PII identifier — used as the anchor for history after masking
windows_id = db.Column(db.String(50), unique=True, nullable=False, index=True)
# PII fields — nulled out when masked
first_name = db.Column(db.String(100), nullable=True)
last_name = db.Column(db.String(100), nullable=True)
email = db.Column(db.String(200), nullable=True)
phone = db.Column(db.String(50), nullable=True)
# Non-PII organisational data — retained after masking
department = db.Column(db.String(100), nullable=True)
job_title = db.Column(db.String(100), nullable=True)
location = db.Column(db.String(100), nullable=True)
manager_windows_id = db.Column(db.String(50), nullable=True)
# Status
is_active = db.Column(db.Boolean, default=True) # employed / active in company
is_masked = db.Column(db.Boolean, default=False) # PII erased
masked_at = db.Column(db.DateTime, nullable=True)
masked_by_id = db.Column(db.Integer, db.ForeignKey('admin_users.id'), nullable=True)
# Import metadata
import_source = db.Column(db.String(20), default='manual') # manual | ldap | csv
ldap_dn = db.Column(db.String(500), nullable=True) # AD Distinguished Name
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# Relationships
assignments = db.relationship(
'Assignment', foreign_keys='Assignment.user_id',
backref='user', lazy='dynamic', cascade='all, delete-orphan'
)
paperwork_docs = db.relationship(
'Paperwork', foreign_keys='Paperwork.user_id',
backref='user', lazy='dynamic', cascade='all, delete-orphan'
)
masked_by = db.relationship('AdminUser', foreign_keys=[masked_by_id])
# ------------------------------------------------------------------
# Display helpers
# ------------------------------------------------------------------
@property
def display_name(self):
if self.is_masked:
return f'[MASKED WID: {self.windows_id}]'
parts = [self.first_name, self.last_name]
full = ' '.join(p for p in parts if p)
return full or self.windows_id
@property
def display_email(self):
return '[MASKED]' if self.is_masked else (self.email or '')
@property
def display_phone(self):
return '[MASKED]' if self.is_masked else (self.phone or '')
@property
def current_assets(self):
"""Returns active assignments."""
return self.assignments.filter_by(is_active=True).all()
def mask(self, admin_user_id):
"""Erase PII while preserving the record for asset-history purposes."""
self.first_name = None
self.last_name = None
self.email = None
self.phone = None
self.is_active = False
self.is_masked = True
self.masked_at = datetime.utcnow()
self.masked_by_id = admin_user_id
def __repr__(self):
return f'<User wid={self.windows_id} masked={self.is_masked}>'