Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Django Admin -> Changes to replace Admin API #4473

Merged
merged 8 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/offboarding.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ assignees: ''
- [ ] Remove from active Figma projects
- [ ] Remove from Mural
- [ ] Remove from Zendesk [here](https://fac-gov.zendesk.com/admin/people/team/members).
- [ ] Remove from the list of staff users in the Django Admin app [here](https://app.fac.gov/admin/users/staffuser/).
- [ ] Remove email from the list of Django Admin users in [staffusers.json](../../backend/config/staffusers.json).
- [ ] Check for and remove admin access in the FAC application: this may include designated permissions and/or checked-in API access ([for example](https://github.com/GSA-TTS/FAC/blob/fb0e7bdf1cb1807291e6b6eef068e97b4574078c/backend/support/api/admin_api_v1_1_0/create_access_tables.sql#L21))

## For GitHub contributors
Expand Down
5 changes: 4 additions & 1 deletion .github/ISSUE_TEMPLATE/onboarding.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ Note: If you're not able to do any of these yourself, you're still responsible f
- [ ] [Add as a form manager to the touchpoints recruitment intercept](https://touchpoints.app.cloud.gov/admin/forms/9412c559/permissions)

**For engineers, also...**
- [ ] Make sure you have a `login.gov` account and have logged into the FAC application at least once.
- [ ] Then, add your email to the `readonly` list in [staffusers.json](../../backend/config/staffusers.json).
- [ ] [Add as a member of the FAC group in New Relic](https://one.newrelic.com/admin-portal/organizations/users-list) (@GSA-TTS/fac-admins can do this)

**For product leads/owners, also...**
Expand All @@ -88,5 +90,6 @@ Note: If you're not able to do any of these yourself, you're still responsible f
- [ ] Also give them the `Maintainer` role in [the FAC-team team in GitHub](https://github.com/orgs/GSA-TTS/teams/fac-team/members).

**For helpdesk, also...**
- [ ] Add them to the list of staff users for [Django Admin](https://app.fac.gov/admin/users/staffuser/).
- [ ] Make sure you have a `login.gov` account and have logged into the FAC application at least once.
- [ ] Then, add your email to the `helpdesk` list in [staffusers.json](../../backend/config/staffusers.json).
- [ ] Give them access to the [Help Desk](https://fac-gov.zendesk.com/admin/people/team/members) as a team member.
20 changes: 20 additions & 0 deletions backend/config/staffusers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"readonly": [
"philip.dominguez@gsa.gov"
],
"helpdesk": [
"alexander.steel@gsa.gov",
"robert.novak@gsa.gov",
"analyn.delossantos@gsa.gov",
"hassandeme.mamasambo@gsa.gov",
"marissa.henderson@gsa.gov",
"james.p.mason@gsa.gov",
"james.person@gsa.gov",
"leigh.cox@gsa.gov",
"rochelle.ribeiro@gsa.gov"
],
"superuser": [
"matthew.jadud@gsa.gov",
rnovak338 marked this conversation as resolved.
Show resolved Hide resolved
"daniel.swick@gsa.gov"
]
}
27 changes: 26 additions & 1 deletion backend/dissemination/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from django.contrib import admin

from dissemination.models import (
AdditionalEin,
AdditionalUei,
Expand All @@ -11,7 +10,9 @@
Note,
Passthrough,
SecondaryAuditor,
TribalApiAccessKeyIds,
)
import datetime


class AdditionalEinAdmin(admin.ModelAdmin):
Expand Down Expand Up @@ -257,6 +258,29 @@ def has_view_permission(self, request, obj=None):
search_fields = ("report_id",)


class TribalApiAccessKeyIdsAdmin(admin.ModelAdmin):

list_display = (
"email",
"key_id",
"date_added",
)

search_fields = (
"email",
"key_id",
)

fields = [
"email",
"key_id",
]

def save_model(self, request, obj, form, change):
obj.date_added = datetime.date.today()
super().save_model(request, obj, form, change)


admin.site.register(AdditionalEin, AdditionalEinAdmin)
admin.site.register(AdditionalUei, AdditionalUeiAdmin)
admin.site.register(CapText, CapTextAdmin)
Expand All @@ -267,3 +291,4 @@ def has_view_permission(self, request, obj=None):
admin.site.register(Note, NoteAdmin)
admin.site.register(Passthrough, PassThroughAdmin)
admin.site.register(SecondaryAuditor, SecondaryAuditorAdmin)
admin.site.register(TribalApiAccessKeyIds, TribalApiAccessKeyIdsAdmin)
5 changes: 5 additions & 0 deletions backend/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ gonogo "curation_audit_tracking_init"
seed_cog_baseline
gonogo "seed_cog_baseline"

#####
# CREATE STAFF USERS
# Prepares staff users for Django admin
python manage.py create_staffusers

#####
# LAUNCH THE APP
# We will have died long ago if things didn't work.
Expand Down
29 changes: 24 additions & 5 deletions backend/users/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,34 @@ class PermissionAdmin(admin.ModelAdmin):

@admin.register(User)
class UserAdmin(admin.ModelAdmin):
list_display = ["email", "can_read_tribal", "last_login", "date_joined"]
list_filter = ["is_staff", "is_superuser"]
exclude = ["groups", "user_permissions", "password"]
list_display = [
"email",
"can_read_tribal",
"last_login",
"date_joined",
"assigned_groups",
]
list_filter = ["is_staff", "is_superuser", "groups"]
exclude = ["user_permissions", "password"]
readonly_fields = ["date_joined", "last_login"]
search_fields = ("email", "username")

def can_read_tribal(self, obj):
return _can_read_tribal(obj)

def assigned_groups(self, obj):
return ", ".join([g.name for g in obj.groups.all()])


@admin.register(UserPermission)
class UserPermissionAdmin(admin.ModelAdmin):
list_display = ["user", "email", "permission"]
search_fields = ("email", "permission", "user")
fields = ["email", "permission"]

def save_model(self, request, obj, form, change):
obj.user = User.objects.get(email=obj.email)
super().save_model(request, obj, form, change)


@admin.register(StaffUserLog)
Expand All @@ -57,8 +71,7 @@ def has_delete_permission(self, request, obj=None):
class StaffUserAdmin(admin.ModelAdmin):
list_display = [
"staff_email",
"added_by_email",
"date_added",
"privilege",
]
fields = [
"staff_email",
Expand Down Expand Up @@ -91,3 +104,9 @@ def has_add_permission(self, request, obj=None):

def has_delete_permission(self, request, obj=None):
return request.user.is_superuser

def privilege(self, obj):
user = User.objects.get(email=obj.staff_email, is_staff=True)
if user.is_superuser:
return "Superuser"
return ", ".join([g.name for g in user.groups.all()])
115 changes: 115 additions & 0 deletions backend/users/management/commands/create_staffusers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group, Permission
from django.core.management.base import BaseCommand
from django.db import transaction
from users.models import StaffUser
import json
import logging
import os

logger = logging.getLogger(__name__)
User = get_user_model()


class Command(BaseCommand):

def handle(self, *args, **kwargs):
"""Create a group with readonly permissions."""
group_readonly, created = Group.objects.get_or_create(name="Read-only")
readonly_codenames = [
"view_access",
"view_deletedaccess",
"view_singleauditchecklist",
"view_sacvalidationwaiver",
"view_ueivalidationwaiver",
"view_additionalein",
"view_additionaluei",
"view_captext",
"view_federalaward",
"view_findingtext",
"view_finding",
"view_general",
"view_note",
"view_passthrough",
"view_secondaryauditor",
"view_cognizantassignment",
"view_cognizantbaseline",
"view_staffuser",
"view_userpermission",
"view_tribalapiaccesskeyids",
]
group_readonly.permissions.clear()
for code in readonly_codenames:
group_readonly.permissions.add(Permission.objects.get(codename=code))
group_readonly.save()

"""Create a group with helpdesk permissions."""
group_helpdesk, created = Group.objects.get_or_create(name="Helpdesk")
helpdesk_codenames = readonly_codenames + [
"add_userpermission",
"change_userpermission",
"delete_userpermission",
"add_tribalapiaccesskeyids",
"change_tribalapiaccesskeyids",
"delete_tribalapiaccesskeyids",
"add_sacvalidationwaiver",
"add_ueivalidationwaiver",
"add_cognizantassignment",
]
group_helpdesk.permissions.clear()
for code in helpdesk_codenames:
group_helpdesk.permissions.add(Permission.objects.get(codename=code))
group_helpdesk.save()

# read in staffusers JSON.
user_list = None
with open(
os.path.join(settings.BASE_DIR, "config/staffusers.json"), "r"
) as file:
user_list = json.load(file)

if user_list:

# clear superuser privileges.
superusers = User.objects.filter(is_superuser=True)
for superuser in superusers:
superuser.is_superuser = False
superuser.save()

# clear existing staff users.
StaffUser.objects.all().delete()

for role in user_list:
for email in user_list[role]:

# create staff user for each role.
with transaction.atomic():

StaffUser(
staff_email=email,
).save()

# attempt to update the user.
try:
user = User.objects.get(email=email, is_staff=True)

user.groups.clear()
match role:
case "readonly":
user.groups.add(group_readonly)
case "helpdesk":
user.groups.clear()
user.groups.add(group_helpdesk)
case "superuser":
user.is_superuser = True

user.save()
logger.info(f"Synced {email} to a StaffUser role.")

# for whatever reason, this failed. Revert staffuser creation.
except User.DoesNotExist:
transaction.set_rollback(True)
logger.warning(
f"StaffUser not created for {email}, they have not logged in yet."
)
1 change: 1 addition & 0 deletions backend/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def delete(self, *args, **kwargs):
try:
user = User.objects.get(email=self.staff_email)
user.is_staff = False
user.is_superuser = False
user.save()
except User.DoesNotExist:
pass # silently ignore. Nothing to do.
Expand Down