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

Add Cyberstorm endpoint for disconnecting linked accounts #1047

Open
wants to merge 1 commit into
base: 12-11-Add_DisbandTeamAPIView
Choose a base branch
from
Open
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
61 changes: 58 additions & 3 deletions django/thunderstore/api/cyberstorm/views/user.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
from django.http import HttpRequest
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers, status
from rest_framework.exceptions import APIException, ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from thunderstore.api.utils import conditional_swagger_auto_schema
from thunderstore.social.views import DeleteAccountForm
from thunderstore.social.views import (
DeleteAccountForm,
LinkedAccountDisconnectExecption,
LinkedAccountDisconnectForm,
)


class CyberstormException(APIException):
status_code = status.HTTP_400_BAD_REQUEST
default_detail = _("Issue occured when trying to process action")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The word occured in the error message is misspelled - it should be occurred. The full message should read: "Issue occurred when trying to process action"

Spotted by Graphite Reviewer

Is this helpful? React 👍 or 👎 to let us know.

default_code = "error"


class CyberstormUserDeleteRequestSerialiazer(serializers.Serializer):
Expand Down Expand Up @@ -38,3 +49,47 @@ def post(self, request: HttpRequest):
return Response()
else:
raise ValidationError(form.errors)


class CyberstormUserDisconnectProviderRequestSerialiazer(serializers.Serializer):
provider = serializers.CharField()


class CyberstormUserDisconnectProviderResponseSerialiazer(serializers.Serializer):
username = serializers.CharField()
provider = serializers.CharField()


class UserLinkedAccountDisconnectAPIView(APIView):
permission_classes = [IsAuthenticated]

@conditional_swagger_auto_schema(
request_body=CyberstormUserDisconnectProviderRequestSerialiazer,
responses={200: CyberstormUserDisconnectProviderResponseSerialiazer},
operation_id="cyberstorm.current-user.linked-account-disconnect",
tags=["cyberstorm"],
)
def post(self, request: HttpRequest):
serializer = CyberstormUserDisconnectProviderRequestSerialiazer(
data=request.data
)
serializer.is_valid(raise_exception=True)
form = LinkedAccountDisconnectForm(
user=request.user,
data=serializer.validated_data,
)
if form.is_valid():
try:
form.disconnect_account(with_raise=True)
except LinkedAccountDisconnectExecption as e:
raise CyberstormException(detail=e)
return Response(
CyberstormUserDisconnectProviderResponseSerialiazer(
{
"username": request.user.username,
"provider": serializer.validated_data["provider"],
}
).data
)
else:
raise ValidationError(form.errors)
10 changes: 9 additions & 1 deletion django/thunderstore/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
TeamMemberListAPIView,
TeamServiceAccountListAPIView,
)
from thunderstore.api.cyberstorm.views.user import UserDeleteAPIView
from thunderstore.api.cyberstorm.views.user import (
UserDeleteAPIView,
UserLinkedAccountDisconnectAPIView,
)

cyberstorm_urls = [
path(
Expand Down Expand Up @@ -142,6 +145,11 @@
UserDeleteAPIView.as_view(),
name="cyberstorm.current-user.delete",
),
path(
"current-user/linked-account-disconnect/",
UserLinkedAccountDisconnectAPIView.as_view(),
name="cyberstorm.current-user.linked-account-disconnect",
),
path(
"team/<str:team_name>/members/remove/",
RemoveTeamMemberAPIView.as_view(),
Expand Down
42 changes: 35 additions & 7 deletions django/thunderstore/social/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,43 @@
from thunderstore.frontend.views import SettingsViewMixin


class LinkedAccountDisconnectExecption(Exception):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class name LinkedAccountDisconnectExecption contains a typo - it should be LinkedAccountDisconnectException. This appears to be a simple misspelling of the word "Exception".

Spotted by Graphite Reviewer

Is this helpful? React 👍 or 👎 to let us know.

"""Some problem with disconnecting a linked account"""

pass


class LinkedAccountDisconnectForm(forms.Form):
provider = forms.CharField()

def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user")
super().__init__(*args, **kwargs)

@property
def can_disconnect(self):
return self.user.social_auth.count() > 1

def clean_provider(self):
data = self.cleaned_data["provider"]
if data in ["github", "discord", "overwolf"]:
return data
else:
raise forms.ValidationError("Invalid provider")

def disconnect_account(self, with_raise=False):
if not self.can_disconnect:
if with_raise:
raise LinkedAccountDisconnectExecption(
"User must have at least one linked account"
)
else:
return
social_auth = self.user.social_auth.filter(
provider=self.cleaned_data["provider"]
).first()
social_auth.delete()


class LinkedAccountsView(SettingsViewMixin, RequireAuthenticationMixin, FormView):
template_name = "settings/linked_accounts.html"
Expand All @@ -25,14 +59,8 @@ def get_context_data(self, **kwargs):
def can_disconnect(self):
return self.request.user.social_auth.count() > 1

def disconnect_account(self, provider):
if not self.can_disconnect:
return
social_auth = self.request.user.social_auth.filter(provider=provider).first()
social_auth.delete()

def form_valid(self, form):
self.disconnect_account(form.cleaned_data["provider"])
form.disconnect_account()
return super().form_valid(form)


Expand Down
Loading