Skip to content

Commit

Permalink
Fix token admin headers and add createtoken command
Browse files Browse the repository at this point in the history
This fixes the token admin headers like we did with Tecken. Further, it
adds a createtoken command like Tecken has allowing us to create tokens
from the command line in the local dev environment.
  • Loading branch information
willkg committed May 16, 2024
1 parent cd3ef85 commit c864e93
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 0 deletions.
3 changes: 3 additions & 0 deletions webapp/crashstats/tokens/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ class TokenAdmin(admin.ModelAdmin):
list_filter = ["permissions"]
search_fields = ["user__email", "notes"]

@admin.display(description="Key")
def key_truncated(self, obj):
return obj.key[:12] + "..."

@admin.display(description="Permissions")
def get_permissions(self, obj):
return ", ".join(perm.codename for perm in obj.permissions.all())

@admin.display(description="Email")
def get_user_email(self, obj):
return obj.user.email
3 changes: 3 additions & 0 deletions webapp/crashstats/tokens/management/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
3 changes: 3 additions & 0 deletions webapp/crashstats/tokens/management/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
57 changes: 57 additions & 0 deletions webapp/crashstats/tokens/management/commands/createtoken.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

from django.contrib.auth.models import Permission, User
from django.core.management.base import BaseCommand, CommandError

from crashstats.tokens.models import make_key, Token


class Command(BaseCommand):
help = "Create an API token."

def add_arguments(self, parser):
parser.add_argument("email")
parser.add_argument("token_key", default=None, nargs="?")
parser.add_argument(
"--try-upload",
action="store_true",
help="If true, create the token with Upload Try Symbols",
)

def handle(self, *args, **options):
email = options["email"]

token_key = options["token_key"]
if not token_key:
token_key = make_key()

try:
user = User.objects.get(email__iexact=email)
except User.DoesNotExist:
raise CommandError(f"Account {email!r} does not exist.") from None

if Token.objects.filter(user=user, key=token_key).exists():
raise CommandError(f"Token with key {token_key!r} already exists")

# Add permissions to token that user has
permissions_to_add = [
"view_pii",
"view_rawdump",
"reprocess_crashes",
]
permissions = [
Permission.objects.get(codename=permission)
for permission in permissions_to_add
if user.has_perm(permission)
]

token = Token.objects.create(
user=user,
key=token_key,
)
self.stdout.write(self.style.SUCCESS(f"{token_key} created"))
for permission in permissions:
token.permissions.add(permission)
self.stdout.write(self.style.SUCCESS(f"{permission} added"))
42 changes: 42 additions & 0 deletions webapp/crashstats/tokens/tests/test_createtoken.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

from io import StringIO

import pytest

from django.core.management import call_command
from django.core.management.base import CommandError

from crashstats.tokens.models import make_key, Token


@pytest.mark.django_db
def test_createtoken_no_key_command():
assert Token.objects.all().count() == 0
stdout = StringIO()
call_command("makesuperuser", "foo@example.com", stdout=stdout)
stdout = StringIO()
call_command("createtoken", "foo@example.com", stdout=stdout)

assert Token.objects.all().count() == 1


@pytest.mark.django_db
def test_createtoken_with_key_command():
assert Token.objects.all().count() == 0
stdout = StringIO()
call_command("makesuperuser", "foo@example.com", stdout=stdout)
stdout = StringIO()
token_key = make_key()
call_command("createtoken", "foo@example.com", token_key, stdout=stdout)

assert Token.objects.filter(key=token_key).count() == 1


@pytest.mark.django_db
def test_createtoken_command_no_user():
with pytest.raises(CommandError):
stdout = StringIO()
call_command("createtoken", "foo@example.com", stdout=stdout)

0 comments on commit c864e93

Please sign in to comment.