diff --git a/client-v3/src/components/config/ConfigUsers.vue b/client-v3/src/components/config/ConfigUsers.vue index 62b3fa83..0b1b10c9 100644 --- a/client-v3/src/components/config/ConfigUsers.vue +++ b/client-v3/src/components/config/ConfigUsers.vue @@ -10,6 +10,9 @@ + @@ -105,6 +108,7 @@ const selectedUser = ref<{ id: number; username: string } | null>(null); const userFields = [ 'username', + 'created_on', 'last_login', 'last_seen', { key: 'is_admin', label: 'User Type' }, diff --git a/client-v3/src/types/api/user.ts b/client-v3/src/types/api/user.ts index e37f8f3b..bdb8d311 100644 --- a/client-v3/src/types/api/user.ts +++ b/client-v3/src/types/api/user.ts @@ -2,6 +2,7 @@ export interface User { id: number; username: string | null; is_admin: boolean | null; + created_on: string | null; last_login: string | null; last_seen: string | null; requires_password_change: boolean; diff --git a/client/src/types/api/user.ts b/client/src/types/api/user.ts index 98e204a2..d0ee6261 100644 --- a/client/src/types/api/user.ts +++ b/client/src/types/api/user.ts @@ -2,6 +2,7 @@ export interface User { id: number; username: string | null; is_admin: boolean | null; + created_on: string | null; last_login: string | null; last_seen: string | null; requires_password_change: boolean; diff --git a/client/src/vue_components/config/ConfigUsers.vue b/client/src/vue_components/config/ConfigUsers.vue index c045c580..3edb0e1a 100644 --- a/client/src/vue_components/config/ConfigUsers.vue +++ b/client/src/vue_components/config/ConfigUsers.vue @@ -10,6 +10,9 @@ + @@ -93,7 +96,14 @@ export default defineComponent({ components: { CreateUser, ConfigRbac, ResetPassword }, data() { return { - userFields: ['username', 'last_login', 'last_seen', 'is_admin', { key: 'btn', label: '' }], + userFields: [ + 'username', + 'created_on', + 'last_login', + 'last_seen', + 'is_admin', + { key: 'btn', label: '' }, + ], editUser: null as number | null, resetUser: null as { id: number; username: string } | null, clientTimeout: null as ReturnType | null, diff --git a/server/alembic_config/versions/3f2343a8a936_add_created_on_timestamp_tp_users.py b/server/alembic_config/versions/3f2343a8a936_add_created_on_timestamp_tp_users.py new file mode 100644 index 00000000..34a4ca80 --- /dev/null +++ b/server/alembic_config/versions/3f2343a8a936_add_created_on_timestamp_tp_users.py @@ -0,0 +1,35 @@ +"""Add created on timestamp tp users + +Revision ID: 3f2343a8a936 +Revises: 11311df29aa4 +Create Date: 2026-06-06 23:49:09.107684 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op + + +# revision identifiers, used by Alembic. +revision: str = "3f2343a8a936" +down_revision: Union[str, None] = "11311df29aa4" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("user", schema=None) as batch_op: + batch_op.add_column(sa.Column("created_on", sa.DateTime(), nullable=True)) + + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("user", schema=None) as batch_op: + batch_op.drop_column("created_on") + + # ### end Alembic commands ### diff --git a/server/controllers/api/auth/user.py b/server/controllers/api/auth/user.py index d7248d23..4e3be9bf 100644 --- a/server/controllers/api/auth/user.py +++ b/server/controllers/api/auth/user.py @@ -72,6 +72,7 @@ async def post(self): username=username, password=hashed_password, is_admin=is_admin, + created_on=datetime.now(tz=timezone.utc), ) ) session.commit() diff --git a/server/models/user.py b/server/models/user.py index 089080ac..4371dbb4 100644 --- a/server/models/user.py +++ b/server/models/user.py @@ -67,6 +67,7 @@ class User(db.Model): username: Mapped[str | None] = mapped_column(index=True) password: Mapped[str | None] = mapped_column() is_admin: Mapped[bool | None] = mapped_column() + created_on: Mapped[datetime.datetime | None] = mapped_column() last_login: Mapped[datetime.datetime | None] = mapped_column() last_seen: Mapped[datetime.datetime | None] = mapped_column() api_token: Mapped[str | None] = mapped_column(index=True)