add operator issue reports for endpoint agent
Operators had no way to flag a problem PC from the tray. This adds a report path: the tray captures a reason, free-text note, and optional screenshot and the agent uploads it on the collector token to a new operatorreports table linked to the asset. Ships the endpoints 0009 migration so the table exists before the code queries it; the running DB had drifted behind the code and returned HTTP 500 on upload.
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
"""Operator issue reports (tray screenshot + free-text notes).
|
||||
|
||||
Adds operatorreports: one row per operator-submitted issue report for a PC
|
||||
asset. The screenshot bytes live on disk under the instance uploads dir; this
|
||||
table holds only metadata plus the stored file name so the image can be served
|
||||
back and purged on retention. Reports are transient - a retention window
|
||||
(default 7 days) purges old rows and their files - so this is a rolling
|
||||
operator-signal feed, not a permanent record.
|
||||
|
||||
Idempotent: creation checks the live schema first so a db.create_all() site
|
||||
(which already built the table) re-runs clean on strict MySQL 8.
|
||||
"""
|
||||
from alembic import op
|
||||
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'endpoints0009opreports'
|
||||
down_revision = 'endpoints0008drift'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def _has_table(table_name):
|
||||
from sqlalchemy import inspect
|
||||
|
||||
return inspect(op.get_bind()).has_table(table_name)
|
||||
|
||||
|
||||
def upgrade():
|
||||
if _has_table('operatorreports'):
|
||||
return
|
||||
|
||||
op.create_table(
|
||||
'operatorreports',
|
||||
sa.Column('operatorreportid', sa.Integer(), nullable=False),
|
||||
sa.Column('assetid', sa.Integer(), nullable=False),
|
||||
sa.Column('reason', sa.String(length=128), nullable=False,
|
||||
server_default='Other (free text)'),
|
||||
sa.Column('details', sa.Text(), nullable=True),
|
||||
sa.Column('imagefilename', sa.String(length=255), nullable=True),
|
||||
sa.Column('imagemimetype', sa.String(length=64), nullable=True),
|
||||
sa.Column('imagebytesize', sa.Integer(), nullable=True),
|
||||
sa.Column('reportedhostname', sa.String(length=255), nullable=True),
|
||||
sa.Column('createdat', sa.DateTime(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('operatorreportid'),
|
||||
sa.ForeignKeyConstraint(
|
||||
['assetid'], ['assets.assetid'],
|
||||
name='fk_operatorreports_asset', ondelete='CASCADE'),
|
||||
)
|
||||
op.create_index('idx_operatorreports_asset', 'operatorreports', ['assetid'])
|
||||
op.create_index('idx_operatorreports_createdat', 'operatorreports',
|
||||
['createdat'])
|
||||
|
||||
|
||||
def downgrade():
|
||||
if not _has_table('operatorreports'):
|
||||
return
|
||||
|
||||
op.drop_index('idx_operatorreports_createdat', table_name='operatorreports')
|
||||
op.drop_index('idx_operatorreports_asset', table_name='operatorreports')
|
||||
op.drop_table('operatorreports')
|
||||
Reference in New Issue
Block a user