Skip to content
Draft
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
3 changes: 2 additions & 1 deletion dandiapi/api/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
upload_initialize_view,
upload_validate_view,
)
from .users import users_me_view, users_search_view
from .users import user_email_view, users_me_view, users_search_view
from .version import VersionViewSet

__all__ = [
Expand All @@ -31,6 +31,7 @@
'upload_complete_view',
'upload_validate_view',
'user_approval_view',
'user_email_view',
'users_me_view',
'user_questionnaire_form_view',
'users_search_view',
Expand Down
12 changes: 12 additions & 0 deletions dandiapi/api/views/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import TYPE_CHECKING, Any

from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.db.models.query_utils import Q
from drf_yasg.utils import swagger_serializer_method
Expand Down Expand Up @@ -40,6 +41,17 @@ class UserDetailSerializer(serializers.Serializer):
status = serializers.CharField()


class UserEmailSerializer(serializers.Serializer):
subject = serializers.CharField()
message = serializers.CharField()
username = serializers.CharField()

def validate_username(self, value):
if not User.objects.filter(username=value).exists():
raise serializers.ValidationError("No user found with that username.")
return value


class DandisetSerializer(serializers.ModelSerializer):
contact_person = serializers.SerializerMethodField(method_name='get_contact_person')
star_count = serializers.SerializerMethodField()
Expand Down
35 changes: 34 additions & 1 deletion dandiapi/api/views/users.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
from __future__ import annotations

import json
import logging
import re
from typing import TYPE_CHECKING

from allauth.socialaccount.models import SocialAccount
from django.contrib.auth.models import User
from django.core import mail
from django.core.exceptions import PermissionDenied
from django.db.models import OuterRef, Q, Subquery
from drf_yasg.utils import swagger_auto_schema
from rest_framework import serializers
from rest_framework.decorators import api_view, parser_classes, permission_classes
from rest_framework.parsers import JSONParser
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from dandiapi.api.mail import build_message
from dandiapi.api.models import UserMetadata
from dandiapi.api.permissions import IsApproved
from dandiapi.api.views.serializers import UserDetailSerializer, UserSerializer
from dandiapi.api.views.serializers import UserDetailSerializer, UserEmailSerializer, UserSerializer

if TYPE_CHECKING:
from django.http.response import HttpResponseBase
Expand Down Expand Up @@ -144,3 +149,31 @@ def users_search_view(request: Request) -> HttpResponseBase:
users = [serialize_user(user) for user in qs]
response_serializer = UserDetailSerializer(users, many=True)
return Response(response_serializer.data)

@swagger_auto_schema(
method='POST',
operation_summary='Send an email to the specified user (Superuser only)',
request_body=UserEmailSerializer,
responses={
200: UserEmailSerializer,
403: 'Permission Denied: Only superusers can access this endpoint.'
},
)
@parser_classes([JSONParser])
@api_view(['POST'])
def user_email_view(request: Request) -> HttpResponseBase:
# If they are authenticated but are not a superuser, deny access
if not request.user.is_superuser:
raise PermissionDenied

request_serializer = UserEmailSerializer(data=request.data)
request_serializer.is_valid(raise_exception=True)
message = build_message(
subject=request_serializer.validated_data["subject"],
message=request_serializer.validated_data["message"],
to=[request_serializer.validated_data["username"]],
)
# TODO enable
# with mail.get_connection() as connection:
# connection.send_messages([message])
return Response(request_serializer.data)
2 changes: 2 additions & 0 deletions dandiapi/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
upload_initialize_view,
upload_validate_view,
user_approval_view,
user_email_view,
user_questionnaire_form_view,
users_me_view,
users_search_view,
Expand Down Expand Up @@ -75,6 +76,7 @@
name='upload-validate',
),
path('api/users/me/', users_me_view),
path('api/users/mail/', user_email_view),
Copy link
Member

Choose a reason for hiding this comment

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

and may be later

/dandisets/{dandiset__pk}/mail/

to target corresponding author of the dandiset without requiring custom code to figure out who that is. Then that endpoint would first figure out corresponding author(s) and build the to and potentially even subject prefix.

path('api/users/search/', users_search_view),
re_path(
r'^api/users/questionnaire-form/$', user_questionnaire_form_view, name='user-questionnaire'
Expand Down
Loading