From 2ed3786fad39f46a0cb0a5f67702d608e398c50b Mon Sep 17 00:00:00 2001 From: realaravinth Date: Mon, 6 Jun 2022 04:18:31 +0530 Subject: [PATCH] feat: view OAuth2 app registration form and handle POST --- ...ter_oauthintegration_client_secret_text.py | 25 +++++++ ...ter_oauthintegration_client_secret_text.py | 25 +++++++ ...integration_client_secret_text_and_more.py | 35 +++++++++ oauth/integrations/models.py | 2 +- .../templates/integrations/new.html | 24 +++++++ oauth/integrations/tests.py | 71 ++++++++++++++++++- oauth/integrations/urls.py | 4 +- oauth/integrations/views.py | 42 +++++++++-- 8 files changed, 219 insertions(+), 9 deletions(-) create mode 100644 oauth/integrations/migrations/0006_alter_oauthintegration_client_secret_text.py create mode 100644 oauth/integrations/migrations/0007_alter_oauthintegration_client_secret_text.py create mode 100644 oauth/integrations/migrations/0008_alter_oauthintegration_client_secret_text_and_more.py create mode 100644 oauth/integrations/templates/integrations/new.html diff --git a/oauth/integrations/migrations/0006_alter_oauthintegration_client_secret_text.py b/oauth/integrations/migrations/0006_alter_oauthintegration_client_secret_text.py new file mode 100644 index 0000000..52c6916 --- /dev/null +++ b/oauth/integrations/migrations/0006_alter_oauthintegration_client_secret_text.py @@ -0,0 +1,25 @@ +# Generated by Django 4.0.3 on 2022-06-05 21:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("integrations", "0005_alter_oauthintegration_client_secret_text"), + ] + + operations = [ + migrations.AlterField( + model_name="oauthintegration", + name="client_secret_text", + field=models.CharField( + blank=True, + default="nfZH00oFFZw7nj9o8zCXleNBBwqiMrgs", + editable=False, + max_length=32, + unique=True, + verbose_name="client secret", + ), + ), + ] diff --git a/oauth/integrations/migrations/0007_alter_oauthintegration_client_secret_text.py b/oauth/integrations/migrations/0007_alter_oauthintegration_client_secret_text.py new file mode 100644 index 0000000..efaf8fe --- /dev/null +++ b/oauth/integrations/migrations/0007_alter_oauthintegration_client_secret_text.py @@ -0,0 +1,25 @@ +# Generated by Django 4.0.3 on 2022-06-05 21:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("integrations", "0006_alter_oauthintegration_client_secret_text"), + ] + + operations = [ + migrations.AlterField( + model_name="oauthintegration", + name="client_secret_text", + field=models.CharField( + blank=True, + default="zc5jGzAvl32522k2bK2AGBRyjjuQ7XCS", + editable=False, + max_length=32, + unique=True, + verbose_name="client secret", + ), + ), + ] diff --git a/oauth/integrations/migrations/0008_alter_oauthintegration_client_secret_text_and_more.py b/oauth/integrations/migrations/0008_alter_oauthintegration_client_secret_text_and_more.py new file mode 100644 index 0000000..da95777 --- /dev/null +++ b/oauth/integrations/migrations/0008_alter_oauthintegration_client_secret_text_and_more.py @@ -0,0 +1,35 @@ +# Generated by Django 4.0.3 on 2022-06-05 22:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("integrations", "0007_alter_oauthintegration_client_secret_text"), + ] + + operations = [ + migrations.AlterField( + model_name="oauthintegration", + name="client_secret_text", + field=models.CharField( + blank=True, + default="Wfr9q7bWzgnbBFzBhEhPv7mpCRvyfAnc", + editable=False, + max_length=32, + unique=True, + verbose_name="client secret", + ), + ), + migrations.AlterField( + model_name="oauthintegration", + name="privacy_policy_uri", + field=models.URLField( + blank=True, + default=None, + null=True, + verbose_name="privacy policy of the application", + ), + ), + ] diff --git a/oauth/integrations/models.py b/oauth/integrations/models.py index 2a509e4..30861ac 100644 --- a/oauth/integrations/models.py +++ b/oauth/integrations/models.py @@ -37,7 +37,7 @@ class OauthIntegration(models.Model): editable=False, ) privacy_policy_uri = models.URLField( - "privacy policy of the application", default=None, blank=True + "privacy policy of the application", default=None, blank=True, null=True ) redirect_uri = models.URLField("uri where user is to be redirected", unique=True) diff --git a/oauth/integrations/templates/integrations/new.html b/oauth/integrations/templates/integrations/new.html new file mode 100644 index 0000000..cd40d6d --- /dev/null +++ b/oauth/integrations/templates/integrations/new.html @@ -0,0 +1,24 @@ +
+ {% csrf_token %} + + +

{{ create_app.function }}

+
+ + + + + + + + +
diff --git a/oauth/integrations/tests.py b/oauth/integrations/tests.py index 7ce503c..f083d18 100644 --- a/oauth/integrations/tests.py +++ b/oauth/integrations/tests.py @@ -1,3 +1,70 @@ -from django.test import TestCase +# Copyright © 2022 Aravinth Manivannan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . -# Create your tests here. + +from django.contrib.auth import get_user_model +from django.urls import reverse +from django.test import TestCase, Client + +from .views import CREATE_APP_CTX, new_app + + +class CreateNewAppTests(TestCase): + """ + Tests create new app view + """ + + def setUp(self): + self.password = "password121231" + self.user = get_user_model().objects.create_user( + username="create_new_app_tests", + email="create_new_app_tests@example.org", + password=self.password, + ) + + def test_create_new_app_unauthenticated_user(self): + """ + Tests if new_app is accessible only when user is authenticated + """ + resp = self.client.get(reverse("oauth.integrations.new_app")) + self.assertEqual(resp.status_code, 302) + + def test_create_new_app_renders(self): + """ + Tests new_app template render + """ + + c = Client() + c.login(username=self.user.username, password=self.password) + c.session.save() + + resp = c.get(reverse("oauth.integrations.new_app")) + self.assertEqual(resp.status_code, 200) + for (_, value) in CREATE_APP_CTX.items(): + self.assertContains(resp, value) + + def test_new_app_submission(self): + """ + Tests new_app template render + """ + payload = { + "name": "test_new_app_submission", + "redirect_uri": "https://test_new_app_submission.example.org", + } + c = Client() + c.login(username=self.user.username, password=self.password) + c.session.save() + resp = c.post(reverse("oauth.integrations.new_app"), payload) + self.assertEqual(resp.status_code, 200) diff --git a/oauth/integrations/urls.py b/oauth/integrations/urls.py index 315c128..f37bb55 100644 --- a/oauth/integrations/urls.py +++ b/oauth/integrations/urls.py @@ -17,4 +17,6 @@ from django.urls import path, include from . import views -urlpatterns = [path("", views.index, name="index")] +urlpatterns = [ + path("new/", views.new_app, name="oauth.integrations.new_app"), +] diff --git a/oauth/integrations/views.py b/oauth/integrations/views.py index 86dba47..80874a4 100644 --- a/oauth/integrations/views.py +++ b/oauth/integrations/views.py @@ -14,10 +14,42 @@ # along with this program. If not, see . from django.shortcuts import render -from django.http import HttpResponse - +from django.http import HttpResponse, Http404 from django.contrib.auth import authenticate +from django.contrib.auth.decorators import login_required -# Create your views here. -def index(request): - return HttpResponse("Integrations bar") +from django.views.decorators.csrf import csrf_protect + +from .models import OauthIntegration + +CREATE_APP_CTX = { + "function": "Create new OAuth2 Application", + "name": "Application Name", + "redirect_uri": "Redirect URI", + "privacy_policy": "Privacy Policy URI", +} + + +@login_required +@csrf_protect +def new_app(request): + """ + Create new OAuth integration APP + """ + if request.method == "GET": + return render(request, "integrations/new.html", {"create_app": CREATE_APP_CTX}) + + if request.method == "POST": + app = OauthIntegration( + owned_by=request.user, + name_text=request.POST["name"], + redirect_uri=request.POST["redirect_uri"], + ) + if "privacy_policy" in request.POST: + app.privacy_policy_uri = request.POST["privacy_policy"] + + print("OK") + app.save() + return HttpResponse("OK") + + return Http404("Method not supported")