Skip to content

Commit d5da62b

Browse files
MattBlack85auvipy
authored andcommitted
Added management command to create applications (#704)
1 parent 1efe210 commit d5da62b

File tree

2 files changed

+212
-0
lines changed

2 files changed

+212
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
from django.core.exceptions import ValidationError
2+
from django.core.management.base import BaseCommand
3+
4+
from oauth2_provider.models import get_application_model
5+
6+
Application = get_application_model()
7+
8+
9+
class Command(BaseCommand):
10+
help = "Shortcut to create a new application in a programmatic way"
11+
12+
def add_arguments(self, parser):
13+
parser.add_argument(
14+
'client_type',
15+
type=str,
16+
help='The client type, can be confidential or public',
17+
)
18+
parser.add_argument(
19+
'authorization_grant_type',
20+
type=str,
21+
help='The type of authorization grant to be used',
22+
)
23+
parser.add_argument(
24+
'--client-id',
25+
type=str,
26+
help='The ID of the new application',
27+
)
28+
parser.add_argument(
29+
'--user',
30+
type=str,
31+
help='The user the application belongs to',
32+
)
33+
parser.add_argument(
34+
'--redirect-uris',
35+
type=str,
36+
help='The redirect URIs, this must be a space separated string e.g "URI1 URI2',
37+
)
38+
parser.add_argument(
39+
'--client-secret',
40+
type=str,
41+
help='The secret for this application',
42+
)
43+
parser.add_argument(
44+
'--name',
45+
type=str,
46+
help='The name this application',
47+
)
48+
parser.add_argument(
49+
'--skip-authorization',
50+
action='store_true',
51+
help='The ID of the new application',
52+
)
53+
54+
def handle(self, *args, **options):
55+
# Extract all fields related to the application, this will work now and in the future
56+
# and also with custom application models.
57+
application_fields = [field.name for field in Application._meta.fields]
58+
application_data = {}
59+
for key, value in options.items():
60+
# Data in options must be cleaned because there are unneded key-value like
61+
# verbosity and others. Also do not pass any None to the Application
62+
# instance so default values will be generated for those fields
63+
if key in application_fields and value:
64+
if key == 'user':
65+
application_data.update({'user_id': value})
66+
else:
67+
application_data.update({key: value})
68+
69+
new_application = Application(**application_data)
70+
71+
try:
72+
new_application.full_clean()
73+
except ValidationError as exc:
74+
errors = "\n ".join(['- ' + err_key + ': ' + str(err_value) for err_key,
75+
err_value in exc.message_dict.items()])
76+
self.stdout.write(
77+
self.style.ERROR(
78+
'Please correct the following errors:\n %s' % errors
79+
)
80+
)
81+
else:
82+
new_application.save()
83+
self.stdout.write(
84+
self.style.SUCCESS('New application created successfully')
85+
)

tests/test_commands.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
from io import StringIO
2+
3+
from django.contrib.auth import get_user_model
4+
from django.core.management import call_command
5+
from django.core.management.base import CommandError
6+
from django.test import TestCase
7+
8+
from oauth2_provider.models import get_application_model
9+
10+
Application = get_application_model()
11+
12+
13+
class CreateApplicationTest(TestCase):
14+
15+
def test_command_creates_application(self):
16+
output = StringIO()
17+
self.assertEqual(Application.objects.count(), 0)
18+
call_command(
19+
'createapplication',
20+
'confidential',
21+
'authorization-code',
22+
'--redirect-uris=http://example.com http://example2.com',
23+
stdout=output,
24+
)
25+
self.assertEqual(Application.objects.count(), 1)
26+
self.assertIn('New application created successfully', output.getvalue())
27+
28+
def test_missing_required_args(self):
29+
self.assertEqual(Application.objects.count(), 0)
30+
with self.assertRaises(CommandError) as ctx:
31+
call_command(
32+
'createapplication',
33+
'--redirect-uris=http://example.com http://example2.com',
34+
)
35+
36+
self.assertIn('client_type', ctx.exception.args[0])
37+
self.assertIn('authorization_grant_type', ctx.exception.args[0])
38+
self.assertEqual(Application.objects.count(), 0)
39+
40+
def test_command_creates_application_with_skipped_auth(self):
41+
self.assertEqual(Application.objects.count(), 0)
42+
call_command(
43+
'createapplication',
44+
'confidential',
45+
'authorization-code',
46+
'--redirect-uris=http://example.com http://example2.com',
47+
'--skip-authorization',
48+
)
49+
app = Application.objects.get()
50+
51+
self.assertTrue(app.skip_authorization)
52+
53+
def test_application_created_normally_with_no_skipped_auth(self):
54+
call_command(
55+
'createapplication',
56+
'confidential',
57+
'authorization-code',
58+
'--redirect-uris=http://example.com http://example2.com',
59+
)
60+
app = Application.objects.get()
61+
62+
self.assertFalse(app.skip_authorization)
63+
64+
def test_application_created_with_name(self):
65+
call_command(
66+
'createapplication',
67+
'confidential',
68+
'authorization-code',
69+
'--redirect-uris=http://example.com http://example2.com',
70+
'--name=TEST',
71+
)
72+
app = Application.objects.get()
73+
74+
self.assertEqual(app.name, 'TEST')
75+
76+
def test_application_created_with_client_secret(self):
77+
call_command(
78+
'createapplication',
79+
'confidential',
80+
'authorization-code',
81+
'--redirect-uris=http://example.com http://example2.com',
82+
'--client-secret=SECRET',
83+
)
84+
app = Application.objects.get()
85+
86+
self.assertEqual(app.client_secret, 'SECRET')
87+
88+
def test_application_created_with_client_id(self):
89+
call_command(
90+
'createapplication',
91+
'confidential',
92+
'authorization-code',
93+
'--redirect-uris=http://example.com http://example2.com',
94+
'--client-id=someId',
95+
)
96+
app = Application.objects.get()
97+
98+
self.assertEqual(app.client_id, 'someId')
99+
100+
def test_application_created_with_user(self):
101+
User = get_user_model()
102+
user = User.objects.create()
103+
call_command(
104+
'createapplication',
105+
'confidential',
106+
'authorization-code',
107+
'--redirect-uris=http://example.com http://example2.com',
108+
'--user=%s' % user.pk,
109+
)
110+
app = Application.objects.get()
111+
112+
self.assertEqual(app.user, user)
113+
114+
def test_validation_failed_message(self):
115+
output = StringIO()
116+
call_command(
117+
'createapplication',
118+
'confidential',
119+
'authorization-code',
120+
'--redirect-uris=http://example.com http://example2.com',
121+
'--user=783',
122+
stdout=output,
123+
)
124+
125+
self.assertIn('user', output.getvalue())
126+
self.assertIn('783', output.getvalue())
127+
self.assertIn('does not exist', output.getvalue())

0 commit comments

Comments
 (0)