1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
webvirtcloud/logs/migrations/0004_audit_fields.py
catborise 8c0fbff8f7 feat(logs): admin changes and logins are recorded on the Logs page
The Logs page shows who added, changed or deleted a compute, from web
or API, and every login, failed login, lockout and logout, with the
client address and a Result column (Done, Failed, Unknown for older
rows). A failed change is recorded with its reason and the error still
reaches the user; a refused one is recorded too.

- logs.audit.write saves each row in its own savepoint and never
  raises, so a log write cannot break or undo the action it records.
  The audit() context manager writes one row when the change ends.
- Logs gains success and ip; user, host and instance are wider and
  date is indexed. The page orders by date then id.
- A compute edit names the changed fields; an edit that changes
  nothing writes no row, and an empty password field is no change.
- A compute's VMs leaving the panel get a system row each: owners
  kept on the Removed VMs page, moved to another compute, restored,
  left without owners, or the removed record expired.
- Job rows carry the result. A job's log entry that cannot be
  computed is logged and skipped instead of rolling back the finish
  (test_service.py changes this on purpose).
- Logins are recorded by signal receivers; CustomLoginView is removed
  and the plain LoginView is used. A wrong OTP code is a failed login,
  counted by django-axes toward the lockout.

Panel records and host-side objects follow in the next layers.
2026-10-23 10:30:48 +03:00

48 lines
1.4 KiB
Python

# Generated by Django 5.2.18 on 2026-10-22 13:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('logs', '0003_logs_host'),
]
operations = [
migrations.AddField(
model_name='logs',
name='ip',
field=models.GenericIPAddressField(null=True, verbose_name='IP address'),
),
migrations.AddField(
model_name='logs',
name='success',
field=models.BooleanField(null=True, verbose_name='success'),
),
migrations.AlterField(
model_name='logs',
name='date',
field=models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='date'),
),
migrations.AlterField(
model_name='logs',
name='host',
field=models.CharField(default='-', max_length=255, verbose_name='host'),
),
migrations.AlterField(
model_name='logs',
name='instance',
field=models.CharField(max_length=120, verbose_name='instance'),
),
migrations.AlterField(
model_name='logs',
name='message',
field=models.TextField(verbose_name='message'),
),
migrations.AlterField(
model_name='logs',
name='user',
field=models.CharField(max_length=150, verbose_name='user'),
),
]