479 lines
29 KiB
Python
479 lines
29 KiB
Python
from datetime import datetime
|
|
from sqlalchemy import Boolean, DateTime, ForeignKey, Index, Integer, JSON, String, Text, UniqueConstraint
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
from .database import Base
|
|
|
|
|
|
class Category(Base):
|
|
__tablename__ = "categories"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(100), unique=True, index=True)
|
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
image_path: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
|
|
assets: Mapped[list["Asset"]] = relationship(back_populates="category")
|
|
visible_fields: Mapped[list["CategoryField"]] = relationship(
|
|
back_populates="category", cascade="all, delete-orphan", order_by="CategoryField.sort_order"
|
|
)
|
|
|
|
|
|
class FieldDefinition(Base):
|
|
__tablename__ = "field_definitions"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
field_name: Mapped[str] = mapped_column(String(80), unique=True, index=True)
|
|
label: Mapped[str] = mapped_column(String(120))
|
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
data_type: Mapped[str] = mapped_column(String(30), default="short_text")
|
|
readonly: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
is_system: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
translation_key: Mapped[str | None] = mapped_column(String(180), nullable=True)
|
|
searchable: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
filterable: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
chart_enabled: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
excel_import: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
excel_export: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
bulk_edit: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
is_default: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
list_width: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
sort_order: Mapped[int] = mapped_column(Integer, default=0)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
category_links: Mapped[list["CategoryField"]] = relationship(back_populates="definition", cascade="all, delete-orphan")
|
|
values: Mapped[list["AssetFieldValue"]] = relationship(back_populates="definition", cascade="all, delete-orphan")
|
|
|
|
|
|
class CategoryField(Base):
|
|
__tablename__ = "category_fields"
|
|
__table_args__ = (UniqueConstraint("category_id", "field_name"),)
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
category_id: Mapped[int] = mapped_column(ForeignKey("categories.id", ondelete="CASCADE"))
|
|
field_name: Mapped[str] = mapped_column(String(80))
|
|
label: Mapped[str] = mapped_column(String(100))
|
|
field_definition_id: Mapped[int | None] = mapped_column(ForeignKey("field_definitions.id", ondelete="CASCADE"), nullable=True, index=True)
|
|
active: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
required: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
show_in_list: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
readonly: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
sort_order: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
category: Mapped[Category] = relationship(back_populates="visible_fields")
|
|
definition: Mapped[FieldDefinition | None] = relationship(back_populates="category_links")
|
|
|
|
@property
|
|
def effective_label(self) -> str:
|
|
return self.definition.label if self.definition else self.label
|
|
|
|
@property
|
|
def effective_readonly(self) -> bool:
|
|
return bool(self.definition.readonly) if self.definition else bool(getattr(self, "readonly", False))
|
|
|
|
|
|
class Asset(Base):
|
|
__tablename__ = "assets"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
category_id: Mapped[int] = mapped_column(ForeignKey("categories.id"), index=True)
|
|
asset_tag: Mapped[str | None] = mapped_column(String(100), unique=True, nullable=True, index=True)
|
|
name: Mapped[str] = mapped_column(String(150), index=True)
|
|
manufacturer: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
model: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
serial_number: Mapped[str | None] = mapped_column(String(150), nullable=True, index=True)
|
|
status: Mapped[str | None] = mapped_column(String(60), nullable=True)
|
|
assigned_to: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
assigned_on: Mapped[str | None] = mapped_column(String(20), nullable=True)
|
|
location: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
room_number: Mapped[str | None] = mapped_column(String(80), nullable=True, index=True)
|
|
parent_asset_id: Mapped[int | None] = mapped_column(ForeignKey("assets.id", ondelete="SET NULL"), nullable=True, index=True)
|
|
department: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
purchase_date: Mapped[str | None] = mapped_column(String(20), nullable=True)
|
|
warranty_until: Mapped[str | None] = mapped_column(String(20), nullable=True)
|
|
notes: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
image_path: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
|
|
hostname: Mapped[str | None] = mapped_column(String(150), nullable=True, index=True)
|
|
operating_system: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
os_patch_level: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
mac_address: Mapped[str | None] = mapped_column(String(50), nullable=True)
|
|
ip_address: Mapped[str | None] = mapped_column(String(50), nullable=True)
|
|
cpu: Mapped[str | None] = mapped_column(String(200), nullable=True)
|
|
memory_gb: Mapped[str | None] = mapped_column(String(40), nullable=True)
|
|
storage_gb: Mapped[str | None] = mapped_column(String(40), nullable=True)
|
|
storage_details: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
gpu_name: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
tpm_version: Mapped[str | None] = mapped_column(String(50), nullable=True)
|
|
memory_details: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
antivirus: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
mesh_group: Mapped[str | None] = mapped_column(String(180), nullable=True)
|
|
mesh_mtype: Mapped[int | None] = mapped_column(Integer, nullable=True, index=True)
|
|
|
|
mesh_node_id: Mapped[str | None] = mapped_column(String(180), unique=True, nullable=True, index=True)
|
|
mesh_last_sync: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
mesh_last_seen: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
mesh_online: Mapped[bool | None] = mapped_column(Boolean, nullable=True, index=True)
|
|
mesh_online_state: Mapped[str] = mapped_column(String(20), default="unknown", index=True)
|
|
mesh_presence_updated_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
mesh_last_online_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
mesh_presence_source: Mapped[str | None] = mapped_column(String(40), nullable=True)
|
|
mesh_sync_status: Mapped[str | None] = mapped_column(String(30), nullable=True, index=True)
|
|
mesh_sync_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
mesh_conflicts: Mapped[dict] = mapped_column(JSON, default=dict)
|
|
mesh_source_data: Mapped[dict] = mapped_column(JSON, default=dict)
|
|
mesh_hardware_data: Mapped[dict] = mapped_column(JSON, default=dict)
|
|
mesh_software_data: Mapped[list | dict] = mapped_column(JSON, default=list)
|
|
mesh_inventory_updated_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
extra_data: Mapped[dict] = mapped_column(JSON, default=dict)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
category: Mapped[Category] = relationship(back_populates="assets")
|
|
parent_asset: Mapped["Asset | None"] = relationship("Asset", remote_side="Asset.id", back_populates="child_assets", foreign_keys=[parent_asset_id])
|
|
child_assets: Mapped[list["Asset"]] = relationship("Asset", back_populates="parent_asset", foreign_keys=[parent_asset_id])
|
|
|
|
|
|
class AssetFieldValue(Base):
|
|
__tablename__ = "asset_field_values"
|
|
__table_args__ = (UniqueConstraint("asset_id", "field_definition_id"),)
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
asset_id: Mapped[int] = mapped_column(ForeignKey("assets.id", ondelete="CASCADE"), index=True)
|
|
field_definition_id: Mapped[int] = mapped_column(ForeignKey("field_definitions.id", ondelete="CASCADE"), index=True)
|
|
value_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
value_number: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
|
value_boolean: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
|
|
value_date: Mapped[str | None] = mapped_column(String(20), nullable=True)
|
|
value_datetime: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
value_json: Mapped[dict | list | None] = mapped_column(JSON, nullable=True)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
asset: Mapped[Asset] = relationship()
|
|
definition: Mapped[FieldDefinition] = relationship(back_populates="values")
|
|
|
|
|
|
class MeshFieldMapping(Base):
|
|
__tablename__ = "mesh_field_mappings"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
source_path: Mapped[str] = mapped_column(String(255), index=True)
|
|
target_field_name: Mapped[str] = mapped_column(String(80), index=True)
|
|
transform: Mapped[str] = mapped_column(String(40), default="raw")
|
|
multi_value_mode: Mapped[str] = mapped_column(String(30), default="first")
|
|
separator: Mapped[str] = mapped_column(String(20), default="\n")
|
|
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
priority: Mapped[int] = mapped_column(Integer, default=0)
|
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
update_rule: Mapped[str] = mapped_column(String(30), default="fill_empty")
|
|
is_system: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
|
|
|
|
class AssetHistory(Base):
|
|
__tablename__ = "asset_history"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
asset_id: Mapped[int] = mapped_column(ForeignKey("assets.id", ondelete="CASCADE"), index=True)
|
|
changed_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, index=True)
|
|
source: Mapped[str] = mapped_column(String(50), default="manual")
|
|
changed_by: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
changes: Mapped[dict] = mapped_column(JSON, default=dict)
|
|
|
|
|
|
class StatusOption(Base):
|
|
__tablename__ = "status_options"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(60), unique=True, index=True)
|
|
sort_order: Mapped[int] = mapped_column(Integer, default=0)
|
|
active: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
use_for_issue: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
use_for_return: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
|
|
|
|
class SyncRun(Base):
|
|
__tablename__ = "sync_runs"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
source: Mapped[str] = mapped_column(String(50), default="meshcentral")
|
|
started_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
finished_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
status: Mapped[str] = mapped_column(String(30), default="running")
|
|
devices_found: Mapped[int] = mapped_column(Integer, default=0)
|
|
created_count: Mapped[int] = mapped_column(Integer, default=0)
|
|
updated_count: Mapped[int] = mapped_column(Integer, default=0)
|
|
conflict_count: Mapped[int] = mapped_column(Integer, default=0)
|
|
error_count: Mapped[int] = mapped_column(Integer, default=0)
|
|
message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
class ChartDefinition(Base):
|
|
__tablename__ = "chart_definitions"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(150), unique=True, index=True)
|
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
chart_type: Mapped[str] = mapped_column(String(30), default="bar")
|
|
group_field: Mapped[str] = mapped_column(String(80), default="category")
|
|
stack_field: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
|
dashboard_visible: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
show_empty: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
max_items: Mapped[int] = mapped_column(Integer, default=12)
|
|
sort_mode: Mapped[str] = mapped_column(String(30), default="count_desc")
|
|
value_mode: Mapped[str] = mapped_column(String(30), default="raw")
|
|
value_mappings: Mapped[list] = mapped_column(JSON, default=list)
|
|
excluded_statuses: Mapped[list] = mapped_column(JSON, default=list)
|
|
is_system: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
created_by: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
|
|
class Language(Base):
|
|
__tablename__ = "languages"
|
|
|
|
code: Mapped[str] = mapped_column(String(10), primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(80))
|
|
native_name: Mapped[str] = mapped_column(String(80))
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
is_default: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
sort_order: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
|
|
class Translation(Base):
|
|
__tablename__ = "translations"
|
|
__table_args__ = (UniqueConstraint("translation_key", "language_code"),)
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
translation_key: Mapped[str] = mapped_column(String(180), index=True)
|
|
language_code: Mapped[str] = mapped_column(ForeignKey("languages.code", ondelete="CASCADE"), index=True)
|
|
text_value: Mapped[str] = mapped_column(Text)
|
|
description: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
|
|
class User(Base):
|
|
__tablename__ = "users"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
username: Mapped[str] = mapped_column(String(120), unique=True, index=True)
|
|
display_name: Mapped[str | None] = mapped_column(String(180), nullable=True)
|
|
email: Mapped[str | None] = mapped_column(String(180), nullable=True)
|
|
password_hash: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
auth_source: Mapped[str] = mapped_column(String(30), default="local")
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
is_admin: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
is_protected: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
allowed_mesh_groups: Mapped[list] = mapped_column(JSON, default=list)
|
|
asset_access_scopes: Mapped[list] = mapped_column(JSON, default=list)
|
|
profile_department: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
profile_location: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
language_code: Mapped[str] = mapped_column(String(10), default="en")
|
|
persist_browser_state: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
toast_position: Mapped[str] = mapped_column(String(30), default="top-right")
|
|
toast_duration_seconds: Mapped[int] = mapped_column(Integer, default=6)
|
|
theme_mode: Mapped[str] = mapped_column(String(20), default="light")
|
|
last_login: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
|
|
class JobDefinition(Base):
|
|
__tablename__ = "job_definitions"
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(180), unique=True, index=True)
|
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
job_kind: Mapped[str] = mapped_column(String(30), default="script", index=True)
|
|
configuration: Mapped[dict] = mapped_column(JSON, default=dict)
|
|
system_key: Mapped[str | None] = mapped_column(String(120), unique=True, nullable=True, index=True)
|
|
platform: Mapped[str] = mapped_column(String(30), default="windows", index=True)
|
|
interpreter: Mapped[str] = mapped_column(String(30), default="powershell")
|
|
source_type: Mapped[str] = mapped_column(String(30), default="inline")
|
|
source_path: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
inline_script: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
arguments: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
timeout_seconds: Mapped[int] = mapped_column(Integer, default=300)
|
|
success_codes: Mapped[str] = mapped_column(String(120), default="0")
|
|
enabled: Mapped[bool] = mapped_column(Boolean, default=True, index=True)
|
|
is_system: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
revision: Mapped[int] = mapped_column(Integer, default=1)
|
|
created_by: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
updated_by: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
revisions: Mapped[list["JobDefinitionRevision"]] = relationship(back_populates="definition", cascade="all, delete-orphan", order_by="JobDefinitionRevision.revision.desc()")
|
|
parameters: Mapped[list["JobDefinitionParameter"]] = relationship(back_populates="definition", cascade="all, delete-orphan", order_by="JobDefinitionParameter.sort_order")
|
|
|
|
|
|
class JobDefinitionParameter(Base):
|
|
__tablename__ = "job_definition_parameters"
|
|
__table_args__ = (UniqueConstraint("definition_id", "parameter_key", name="uq_job_definition_parameter_key"),)
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
definition_id: Mapped[int] = mapped_column(ForeignKey("job_definitions.id", ondelete="CASCADE"), index=True)
|
|
parameter_key: Mapped[str] = mapped_column(String(80))
|
|
label: Mapped[str] = mapped_column(String(140))
|
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
data_type: Mapped[str] = mapped_column(String(30), default="text")
|
|
default_value: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
required: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
sort_order: Mapped[int] = mapped_column(Integer, default=0)
|
|
definition: Mapped["JobDefinition"] = relationship(back_populates="parameters")
|
|
|
|
|
|
class JobDefinitionAssetParameter(Base):
|
|
__tablename__ = "job_definition_asset_parameters"
|
|
__table_args__ = (UniqueConstraint("definition_parameter_id", "asset_id", name="uq_job_definition_asset_parameter"),)
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
definition_parameter_id: Mapped[int] = mapped_column(ForeignKey("job_definition_parameters.id", ondelete="CASCADE"), index=True)
|
|
asset_id: Mapped[int] = mapped_column(ForeignKey("assets.id", ondelete="CASCADE"), index=True)
|
|
value_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
updated_by: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
parameter: Mapped["JobDefinitionParameter"] = relationship()
|
|
asset: Mapped["Asset"] = relationship()
|
|
|
|
|
|
class JobDefinitionRevision(Base):
|
|
__tablename__ = "job_definition_revisions"
|
|
__table_args__ = (UniqueConstraint("definition_id", "revision", name="uq_job_definition_revision"),)
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
definition_id: Mapped[int] = mapped_column(ForeignKey("job_definitions.id", ondelete="CASCADE"), index=True)
|
|
revision: Mapped[int] = mapped_column(Integer)
|
|
snapshot: Mapped[dict] = mapped_column(JSON, default=dict)
|
|
changed_by: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
definition: Mapped["JobDefinition"] = relationship(back_populates="revisions")
|
|
|
|
|
|
class SoftwarePackage(Base):
|
|
__tablename__ = "software_packages"
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(180), unique=True, index=True)
|
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
package_type: Mapped[str] = mapped_column(String(40), default="command")
|
|
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
is_system: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
command_windows: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
command_linux: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
command_macos: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
command_android: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
callback_timeout_minutes: Mapped[int] = mapped_column(Integer, default=30)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
parameters: Mapped[list["SoftwarePackageParameter"]] = relationship(back_populates="package", cascade="all, delete-orphan", order_by="SoftwarePackageParameter.sort_order")
|
|
jobs: Mapped[list["SoftwareJob"]] = relationship(back_populates="package")
|
|
|
|
|
|
class SoftwarePackageParameter(Base):
|
|
__tablename__ = "software_package_parameters"
|
|
__table_args__ = (UniqueConstraint("package_id", "name"),)
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
package_id: Mapped[int] = mapped_column(ForeignKey("software_packages.id", ondelete="CASCADE"), index=True)
|
|
name: Mapped[str] = mapped_column(String(80))
|
|
label: Mapped[str] = mapped_column(String(120))
|
|
data_type: Mapped[str] = mapped_column(String(30), default="text")
|
|
required: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
secret: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
default_value: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
validation_regex: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
sort_order: Mapped[int] = mapped_column(Integer, default=0)
|
|
package: Mapped[SoftwarePackage] = relationship(back_populates="parameters")
|
|
|
|
|
|
class SoftwareJob(Base):
|
|
__tablename__ = "software_jobs"
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
asset_id: Mapped[int] = mapped_column(ForeignKey("assets.id", ondelete="CASCADE"), index=True)
|
|
package_id: Mapped[int] = mapped_column(ForeignKey("software_packages.id"), index=True)
|
|
status: Mapped[str] = mapped_column(String(30), default="created", index=True)
|
|
job_type: Mapped[str] = mapped_column(String(50), default="software_inventory", index=True)
|
|
action: Mapped[str] = mapped_column(String(30), default="run", index=True)
|
|
priority: Mapped[int] = mapped_column(Integer, default=100, index=True)
|
|
platform: Mapped[str] = mapped_column(String(30), default="unknown")
|
|
parameters: Mapped[dict] = mapped_column(JSON, default=dict)
|
|
result_data: Mapped[dict] = mapped_column(JSON, default=dict)
|
|
attempt_count: Mapped[int] = mapped_column(Integer, default=0)
|
|
max_attempts: Mapped[int] = mapped_column(Integer, default=1)
|
|
scheduled_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, index=True)
|
|
callback_token_hash: Mapped[str] = mapped_column(String(64), index=True)
|
|
callback_expires_at: Mapped[datetime] = mapped_column(DateTime)
|
|
callback_completed_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
command_preview: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
resolved_script: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
meshctrl_stdout: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
meshctrl_stderr: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
exit_code: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
log_text: Mapped[str] = mapped_column(Text, default="")
|
|
created_by: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, index=True)
|
|
sent_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
finished_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
asset: Mapped[Asset] = relationship()
|
|
package: Mapped[SoftwarePackage] = relationship(back_populates="jobs")
|
|
events: Mapped[list["JobEvent"]] = relationship(back_populates="job", cascade="all, delete-orphan", order_by="JobEvent.created_at")
|
|
|
|
|
|
class AssetJobState(Base):
|
|
__tablename__ = "asset_job_states"
|
|
__table_args__ = (
|
|
UniqueConstraint("asset_id", "state_key", name="uq_asset_job_state_asset_key"),
|
|
Index("ix_asset_job_states_key_status", "state_key", "last_status"),
|
|
Index("ix_asset_job_states_key_success", "state_key", "last_success_at"),
|
|
Index("ix_asset_job_states_asset_key", "asset_id", "state_key"),
|
|
)
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
asset_id: Mapped[int] = mapped_column(ForeignKey("assets.id", ondelete="CASCADE"), index=True)
|
|
state_key: Mapped[str] = mapped_column(String(120), index=True)
|
|
job_type: Mapped[str] = mapped_column(String(50), index=True)
|
|
job_definition_id: Mapped[int | None] = mapped_column(Integer, nullable=True, index=True)
|
|
definition_revision: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
last_success_revision: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
last_job_id: Mapped[int | None] = mapped_column(ForeignKey("software_jobs.id", ondelete="SET NULL"), nullable=True, index=True)
|
|
last_status: Mapped[str] = mapped_column(String(30), default="created", index=True)
|
|
last_status_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, index=True)
|
|
last_created_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
last_sent_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
last_started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
last_completed_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
last_success_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, index=True)
|
|
execution_count: Mapped[int] = mapped_column(Integer, default=0)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
asset: Mapped[Asset] = relationship()
|
|
last_job: Mapped[SoftwareJob | None] = relationship()
|
|
|
|
|
|
class JobEvent(Base):
|
|
__tablename__ = "job_events"
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
job_id: Mapped[int] = mapped_column(ForeignKey("software_jobs.id", ondelete="CASCADE"), index=True)
|
|
attempt: Mapped[int] = mapped_column(Integer, default=0)
|
|
event_type: Mapped[str] = mapped_column(String(40), default="status", index=True)
|
|
status: Mapped[str | None] = mapped_column(String(30), nullable=True, index=True)
|
|
message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
created_by: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, index=True)
|
|
job: Mapped["SoftwareJob"] = relationship(back_populates="events")
|
|
|
|
|
|
class InstalledSoftware(Base):
|
|
__tablename__ = "installed_software"
|
|
__table_args__ = (UniqueConstraint("asset_id", "name", "version", "publisher", "architecture", name="uq_installed_software_identity"),)
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
asset_id: Mapped[int] = mapped_column(ForeignKey("assets.id", ondelete="CASCADE"), index=True)
|
|
name: Mapped[str] = mapped_column(String(300), index=True)
|
|
version: Mapped[str] = mapped_column(String(160), default="")
|
|
publisher: Mapped[str] = mapped_column(String(220), default="")
|
|
architecture: Mapped[str] = mapped_column(String(40), default="")
|
|
platform: Mapped[str] = mapped_column(String(40), default="unknown", index=True)
|
|
install_date: Mapped[str | None] = mapped_column(String(40), nullable=True)
|
|
source: Mapped[str] = mapped_column(String(50), default="meshcentral-inventory")
|
|
first_seen_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
last_seen_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, index=True)
|
|
asset: Mapped[Asset] = relationship()
|