babybuddy / babybuddy

A :baby: buddy to help caregivers track sleep, feedings, diaper changes, tummy time and more to learn about and predict baby's needs without (as much) guess work.
http://docs.baby-buddy.net/
BSD 2-Clause "Simplified" License
2.12k stars 262 forks source link

Feature request: store auth user in core models so you can see who did what #900

Open skjdghsdjgsdj opened 2 days ago

skjdghsdjgsdj commented 2 days ago

I poked around in the SQLite database for how Baby Buddy stores some of its data. Here's an example of a typical model (feedings):

CREATE TABLE IF NOT EXISTS "core_feeding" (
    "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
    "end" datetime NOT NULL,
    "duration" bigint NULL,
    "type" varchar(255) NOT NULL,
    "method" varchar(255) NOT NULL,
    "amount" real NULL,
    "child_id" integer NOT NULL REFERENCES "core_child" ("id") DEFERRABLE INITIALLY DEFERRED,
    "notes" text NULL,
    "start" datetime NOT NULL
);

I noticed that there's no reference to who recorded the feeding. In general, it looks like Baby Buddy uses the auth users for authentication/authorization only but then doesn't record the effective user ID for activities.

Here's the auth_user table:

CREATE TABLE IF NOT EXISTS "auth_user" (
    "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
    "password" varchar(128) NOT NULL,
    "last_login" datetime NULL,
    "is_superuser" bool NOT NULL,
    "username" varchar(150) NOT NULL UNIQUE,
    "last_name" varchar(150) NOT NULL,
    "email" varchar(254) NOT NULL,
    "is_staff" bool NOT NULL,
    "is_active" bool NOT NULL,
    "date_joined" datetime NOT NULL,
    "first_name" varchar(150) NOT NULL
);

Guessing at the SQLite syntax, I suggest adding a column like this to the core models:

"auth_user_id" integer NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED

I made it nullable for backwards compatibility, but that column would store who recorded, in this example, the feeding.

Use case? My Baby Buddy instance has multiple users:

It would be great if we can go back through the data and see which things we did vs. our care provider. If you want to start domestic issues, you could also use the data to say "I changed the baby's last poop diaper, see?"

I know barely anything about Django, but I would presume there's a base model from which the other core models extend, and that behavior could be built into that model and inherit to all the others?

Logically, what could then follow is surfacing that information in the UI, but the data has to be there first.

cdubz commented 1 day ago

Yeah, no reason we can't do this and it should be very straightforward just starting with the user association.

cdubz commented 1 day ago

@skjdghsdjgsdj thinking about this use case a little --

It would be great if we can go back through the data and see which things we did vs. our care provider. If you want to start domestic issues, you could also use the data to say "I changed the baby's last poop diaper, see?"

What about using something even more robust like django-auditlog? It kind of "feels" like overkill, but ultimately it is a simpler and perhaps more flexible and useful implementation than just associating the auth user.

I got to thinking about this when considering what to do for adds v.s. updates. E.g., should we have created_by and updated_by instead of just auth_user? Is that more of less useful? What does auth_user really tell us? Etc. etc.

skjdghsdjgsdj commented 1 day ago

The audit log does seem powerful. I don't know enough of Django to know if it's best practice to use a module like that vs. storing the data yourself. But, storing created_by and updated_by is indeed better and less ambiguous than just an auth_user.

The only scenario that I'm mixed on is timers. If person A starts the timer and person B stopped it, is that a separate created and modified? Or did person A ultimately create the timer?

cdubz commented 1 day ago

The only scenario that I'm mixed on is timers. If person A starts the timer and person B stopped it, is that a separate created and modified? Or did person A ultimately create the timer?

Yeah I ran in to that as well. Part of why I ended up thinking about this. I’m gonna poke around with django-audit first.