Skip to content

Commit

Permalink
Merge pull request #78 from Open-Model-Initiative/73-user-is-active-t…
Browse files Browse the repository at this point in the history
…oggling

Add user is_active toggling to the admin dashboard
  • Loading branch information
fearnworks authored Oct 5, 2024
2 parents 6c08681 + efc908c commit 6cb8395
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 5 deletions.
6 changes: 3 additions & 3 deletions modules/odr_core/odr_core/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ class User(Base):
image = Column(String)
identity_provider = Column(String, index=True, default="omi")
hashed_password = Column(String)
is_active = Column(Boolean, default=True)
is_superuser = Column(Boolean, default=False)
dco_accepted = Column(Boolean, default=False)
is_active = Column(Boolean, nullable=False, default=True)
is_superuser = Column(Boolean, nullable=False, default=False)
dco_accepted = Column(Boolean, nullable=False, default=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""'Update users table to have non nullable and default values for flags'
Revision ID: e06f931c3c84
Revises: 6917b71d9140
Create Date: 2024-10-03 18:14:20.255813
"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = 'e06f931c3c84'
down_revision: Union[str, None] = '6917b71d9140'
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! ###
op.alter_column('users', 'is_active',
existing_type=sa.BOOLEAN(),
nullable=False,
server_default=sa.text('true'))
op.alter_column('users', 'is_superuser',
existing_type=sa.BOOLEAN(),
nullable=False,
server_default=sa.text('false'))
op.alter_column('users', 'dco_accepted',
existing_type=sa.BOOLEAN(),
nullable=False,
server_default=sa.text('false'))
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('users', 'dco_accepted',
existing_type=sa.BOOLEAN(),
nullable=True,
server_default=sa.text('false'))
op.alter_column('users', 'is_superuser',
existing_type=sa.BOOLEAN(),
nullable=True,
server_default=sa.text('false'))
op.alter_column('users', 'is_active',
existing_type=sa.BOOLEAN(),
nullable=True,
server_default=sa.text('true'))
# ### end Alembic commands ###
2 changes: 2 additions & 0 deletions modules/odr_frontend/src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const authorizationHandle:Handle = async ({ event, resolve }) => {
throw redirect(303, '/auth');
} else if (!session.user) {
throw redirect(303, '/auth');
} else if (!event.url.pathname.startsWith('/inactive') && (!session.user.is_active)) {
throw redirect(303, '/inactive');
} else if (!event.url.pathname.startsWith('/dco') && (!session.user.dco_accepted)) {
throw redirect(303, '/dco');
} else if (event.url.pathname.startsWith('/admin') && (!session.user.is_superuser)) {
Expand Down
14 changes: 14 additions & 0 deletions modules/odr_frontend/src/lib/admin/ActiveToggle.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
import type { IDBUser } from '$lib/server/pg';
import { SlideToggle } from '@skeletonlabs/skeleton';
import { toggleActive } from './utils';
export let checked: boolean = false;
export let user: IDBUser;
function _toggleActive(e: Event) {
toggleActive(user);
}
</script>

<SlideToggle name="slide" bind:checked on:change={_toggleActive} />
16 changes: 15 additions & 1 deletion modules/odr_frontend/src/lib/admin/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
import type { IDBUser } from '$lib/server/pg';

export async function toggleSuperUser(user: IDBUser) {
const req = await fetch('/admin/users/api', {
const req = await fetch('/admin/users/api/toggleSuperUser', {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ user })
});
const res = await req.json();
if (!res.success) {
console.error(res.error); //TODO: Need to add a toast here
}
}

export async function toggleActive(user: IDBUser) {
const req = await fetch('/admin/users/api/toggleActive', {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
Expand Down
2 changes: 1 addition & 1 deletion modules/odr_frontend/src/lib/server/pg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import pg from 'pg';
export interface IDBUser {
id: number;
email: string;
is_active: boolean | null;
is_active: boolean;
is_superuser: boolean;
created_at: Date;
updated_at: Date | null;
Expand Down
1 change: 1 addition & 0 deletions modules/odr_frontend/src/routes/admin/users/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<th>id</th>
<th>name</th>
<th>isSuperUser?</th>
<th>isActive?</th>
<th>email</th>
</tr>
</thead>
Expand Down
2 changes: 2 additions & 0 deletions modules/odr_frontend/src/routes/admin/users/UserRow.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import SuperUserToggle from '$lib/admin/SuperUserToggle.svelte';
import ActiveToggle from '$lib/admin/ActiveToggle.svelte';
import type { IDBUser } from '$lib/server/pg';
export let user: IDBUser;
</script>
Expand All @@ -8,6 +9,7 @@
<td><a href="/admin/users/{user.id}">{user.id}</a></td>
<td><a href="/admin/users/{user.id}">{user.name}</a></td>
<td><SuperUserToggle {user} bind:checked={user.is_superuser} /></td>
<td><ActiveToggle {user} bind:checked={user.is_active} /></td>
<td>{user.email}</td>
</tr>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { pgClient, type IDBUser } from '$lib/server/pg';
import type { RequestHandler } from '@sveltejs/kit';
export const PUT: RequestHandler = async ({ request }) => {
const body = await request.json();
if (!body.user) {
return new Response(JSON.stringify({ success: false, error: 'No user provided' }));
}
const user: IDBUser = body.user;
try {
const result = await pgClient.query('UPDATE users SET is_active=$1 WHERE id=$2', [
user.is_active,
user.id
]);
console.info(`Set user ${user.id} as ${user.is_active ? 'active' : 'not active'}`);
return new Response(JSON.stringify({ success: true, result: result }));
} catch (e) {
console.error(
`Failed to set user ${user.id} as ${user.is_active ? 'active' : 'not active'}`
);
return new Response(JSON.stringify({ success: false, error: e }));
}
};
29 changes: 29 additions & 0 deletions modules/odr_frontend/src/routes/inactive/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<svelte:head>
<title>Inactive User | OMI Data Pipeline</title>
</svelte:head>

<div class="flex flex-col overflow-y-auto">
<main class="container mx-auto p-4">

<h1 class="text-3xl font-bold mb-4">Inactive User</h1>

<p>
Your user account is inactive. If you believe this is in error, please reach out in our
<a href="https://discord.gg/vANKjzDDkQ"
class="underline"
target="_blank"
rel="noopener noreferrer">
Discord
</a>
for support.
</p>

</main>
</div>

<style>
.container {
max-width: 800px;
padding-bottom: 2rem;
}
</style>

0 comments on commit 6cb8395

Please sign in to comment.