Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions alembic/versions/47f8adc9859b_add_unix_username_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"""Add unix username field

Revision ID: 47f8adc9859b
Revises: 4aa2a7d34719
Create Date: 2026-04-20 10:27:12.467103

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = '47f8adc9859b'
down_revision: Union[str, Sequence[str], None] = '4aa2a7d34719'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


netid_username_map = {
"thain": "gthain",
"tatannen": "tannenba",
"jamesfrey": "jfray",
"tlmiller2": "tlmiller",
"blin28": "blin",
"turatsinze": "tura",
"bockelman": "bbockelm",
"totheisen": "tim",
"mselmeci": "matyas",
"knoeller": "johnkn",
"tcartwright": "cat",
}


def upgrade() -> None:
"""Upgrade schema."""
op.execute('DROP VIEW IF EXISTS joined_projects')
op.add_column('users', sa.Column('username', sa.String(length=255), nullable=True))
users_table = sa.table(
'users',
sa.column('id', sa.Integer()),
sa.column('netid', sa.String(length=255)),
sa.column('username', sa.String(length=255)),
)

op.execute("""
UPDATE users
SET username = netid
""")

for netid, username in netid_username_map.items():
op.execute(
users_table.update()
.where(users_table.c.netid == netid)
.values(username=username)
)

op.create_unique_constraint(op.f('users_username_key'), 'users', ['username'])
op.execute("""
CREATE VIEW joined_projects AS
SELECT
u.id,
p.id AS project_id,
p.name AS project_name,
p.staff1 AS project_staff1,
p.staff2 AS project_staff2,
p.status AS project_status,
p.last_contact AS project_last_contact,
p.accounting_group AS project_accounting_group,
up.is_primary AS is_primary,
u.name,
u.username,
u.email1,
u.email2,
u.netid,
u.netid_exp_datetime,
u.phone1,
u.phone2,
u.is_admin,
u.active,
u.date,
u.unix_uid,
u.position,
up.role,
(
SELECT n.ticket
FROM notes n
LEFT JOIN user_notes un ON n.id = un.note_id
WHERE un.user_id = up.user_id AND un.project_id = up.project_id
ORDER BY n.id DESC
LIMIT 1
) AS last_note_ticket
FROM user_projects up
JOIN users u ON up.user_id = u.id
JOIN projects p ON up.project_id = p.id
""")


def downgrade() -> None:
"""Downgrade schema."""
op.execute('DROP VIEW IF EXISTS joined_projects')
op.drop_constraint(op.f('users_username_key'), 'users', type_='unique')
op.drop_column('users', 'username')
op.execute("""
CREATE VIEW joined_projects AS
SELECT
u.id,
p.id AS project_id,
p.name AS project_name,
p.staff1 AS project_staff1,
p.staff2 AS project_staff2,
p.status AS project_status,
p.last_contact AS project_last_contact,
p.accounting_group AS project_accounting_group,
up.is_primary AS is_primary,
u.name,
u.email1,
u.email2,
u.netid,
u.netid_exp_datetime,
u.phone1,
u.phone2,
u.is_admin,
u.active,
u.date,
u.unix_uid,
u.position,
up.role,
(
SELECT n.ticket
FROM notes n
LEFT JOIN user_notes un ON n.id = un.note_id
WHERE un.user_id = up.user_id AND un.project_id = up.project_id
ORDER BY n.id DESC
LIMIT 1
) AS last_note_ticket
FROM user_projects up
JOIN users u ON up.user_id = u.id
JOIN projects p ON up.project_id = p.id
""")
3 changes: 2 additions & 1 deletion userapp/api/routes/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,11 +459,12 @@ async def oidc_callback(request: Request, response: Response, session=Depends(se
user_info_resp.raise_for_status()
user_info = user_info_resp.json()

# name is required so fallback to netid if no name is found
user = UserTable(
# name is required so fallback to netid if no name is found
name=user_info.get("name") or user_info.get("sub"),
email1=user_info.get("email", None),
netid=user_info.get("sub"),
username=user_info.get("sub"),
active=False,
is_admin=False,
)
Expand Down
1 change: 0 additions & 1 deletion userapp/api/routes/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ async def update_user(user_id: int, user: UserPatchFull, session=Depends(session
return await update_one_endpoint(session, UserTable, user_id, user_update_schema, load_options=user_load_options)

elif is_admin:

# Update user
user_data_only = UserPatch(**user.model_dump(exclude_unset=True))
updated_user = await update_one_endpoint(session, UserTable, user_id, user_data_only, load_options=user_load_options)
Expand Down
3 changes: 2 additions & 1 deletion userapp/api/tests/fake_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def project_data_f(
}


def user_data_f(index: int, primary_project_id, is_admin=False) -> dict:
def user_data_f(index: int, primary_project_id, is_admin=False, username: Optional[str] = None) -> dict:
"""
Generate a unique user payload for testing, based on the UserBase schema.
"""
Expand All @@ -44,6 +44,7 @@ def user_data_f(index: int, primary_project_id, is_admin=False) -> dict:
"email1": f"testuser{rand}@example.com",
"email2": f"altuser{rand}@example.com",
"netid": f"netid{rand}",
"username": username or f"netid{rand}",
"netid_exp_datetime": datetime.now().isoformat(),
"phone1": f"555-010{index}",
"phone2": f"555-020{index}",
Expand Down
Loading
Loading