mirror of
https://github.com/tubearchivist/tubearchivist.git
synced 2025-05-09 04:41:10 +00:00
serialize user, add account endpoint
This commit is contained in:
parent
5498958b36
commit
5772ab3e68
@ -1,5 +1,7 @@
|
||||
"""serializer for account model"""
|
||||
|
||||
# pylint: disable=abstract-method
|
||||
|
||||
from rest_framework import serializers
|
||||
from user.models import Account
|
||||
|
||||
@ -18,3 +20,45 @@ class AccountSerializer(serializers.ModelSerializer):
|
||||
"user_permissions",
|
||||
"last_login",
|
||||
)
|
||||
|
||||
|
||||
class UserMeConfigSerializer(serializers.Serializer):
|
||||
"""serialize user me config"""
|
||||
|
||||
stylesheet = serializers.CharField()
|
||||
page_size = serializers.IntegerField()
|
||||
sort_by = serializers.ChoiceField(
|
||||
choices=[
|
||||
"published",
|
||||
"downloaded",
|
||||
"views",
|
||||
"likes",
|
||||
"duration",
|
||||
"filesize",
|
||||
]
|
||||
)
|
||||
sort_order = serializers.ChoiceField(choices=["asc", "desc"])
|
||||
view_style_home = serializers.ChoiceField(choices=["grid", "list"])
|
||||
view_style_channel = serializers.ChoiceField(choices=["grid", "list"])
|
||||
view_style_downloads = serializers.ChoiceField(choices=["grid", "list"])
|
||||
view_style_playlist = serializers.ChoiceField(choices=["grid", "list"])
|
||||
grid_items = serializers.IntegerField()
|
||||
hide_watched = serializers.BooleanField()
|
||||
show_ignored_only = serializers.BooleanField()
|
||||
show_subed_only = serializers.BooleanField()
|
||||
show_help_text = serializers.BooleanField()
|
||||
|
||||
def __init__(self, *args, required=True, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Override 'required' for all fields if provided
|
||||
for field in self.fields.values():
|
||||
field.required = required
|
||||
|
||||
|
||||
class LoginSerializer(serializers.Serializer):
|
||||
"""serialize login"""
|
||||
|
||||
username = serializers.CharField()
|
||||
password = serializers.CharField()
|
||||
remember_me = serializers.ChoiceField(choices=["on", "off"], default="off")
|
||||
|
@ -143,6 +143,16 @@ class UserConfig:
|
||||
|
||||
return config
|
||||
|
||||
def update_config(self, to_update: dict) -> None:
|
||||
"""update config object"""
|
||||
data = {"doc": {"config": to_update}}
|
||||
response, status = ElasticWrap(self.es_update_url).post(data)
|
||||
if status < 200 or status > 299:
|
||||
raise ValueError(f"Failed storing user value {status}: {response}")
|
||||
|
||||
for key, value in to_update.items():
|
||||
print(f"User {self._user_id} value '{key}' change: to {value}")
|
||||
|
||||
def sync_defaults(self):
|
||||
"""set initial defaults on 404"""
|
||||
response, _ = ElasticWrap(self.es_url).post(
|
||||
|
@ -6,5 +6,6 @@ from user import views
|
||||
urlpatterns = [
|
||||
path("login/", views.LoginApiView.as_view(), name="api-user-login"),
|
||||
path("logout/", views.LogoutApiView.as_view(), name="api-user-logout"),
|
||||
path("account/", views.UserAccountView.as_view(), name="api-user-account"),
|
||||
path("me/", views.UserConfigView.as_view(), name="api-user-me"),
|
||||
]
|
||||
|
@ -1,63 +1,75 @@
|
||||
"""all user api views"""
|
||||
|
||||
from common.serializers import ErrorResponseSerializer
|
||||
from common.views import ApiBaseView
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from user.models import Account
|
||||
from user.serializers import AccountSerializer
|
||||
from user.serializers import (
|
||||
AccountSerializer,
|
||||
LoginSerializer,
|
||||
UserMeConfigSerializer,
|
||||
)
|
||||
from user.src.user_config import UserConfig
|
||||
|
||||
|
||||
class UserAccountView(ApiBaseView):
|
||||
"""resolves to /api/user/account/
|
||||
GET: return current user account
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
responses=AccountSerializer(),
|
||||
)
|
||||
def get(self, request):
|
||||
"""get user account"""
|
||||
user_id = request.user.id
|
||||
account = Account.objects.get(id=user_id)
|
||||
account_serializer = AccountSerializer(account)
|
||||
return Response(account_serializer.data)
|
||||
|
||||
|
||||
class UserConfigView(ApiBaseView):
|
||||
"""resolves to /api/user/me/
|
||||
GET: return current user config
|
||||
POST: update user config
|
||||
"""
|
||||
|
||||
@extend_schema(responses=UserMeConfigSerializer())
|
||||
def get(self, request):
|
||||
"""get config"""
|
||||
user_id = request.user.id
|
||||
account = Account.objects.get(id=user_id)
|
||||
serializer = AccountSerializer(account)
|
||||
response = serializer.data.copy()
|
||||
"""get user config"""
|
||||
config = UserConfig(request.user.id).get_config()
|
||||
serializer = UserMeConfigSerializer(config)
|
||||
|
||||
config = UserConfig(user_id).get_config()
|
||||
response.update({"config": config})
|
||||
|
||||
return Response(response)
|
||||
return Response(serializer.data)
|
||||
|
||||
@extend_schema(
|
||||
request=UserMeConfigSerializer(required=False),
|
||||
responses={
|
||||
200: UserMeConfigSerializer(),
|
||||
400: OpenApiResponse(
|
||||
ErrorResponseSerializer(), description="Bad request"
|
||||
),
|
||||
},
|
||||
)
|
||||
def post(self, request):
|
||||
"""update config"""
|
||||
user_id = request.user.id
|
||||
data = request.data
|
||||
"""update config, allows partial update"""
|
||||
|
||||
data_config = data.get("config")
|
||||
if not data_config:
|
||||
message = {
|
||||
"status": "Bad Request",
|
||||
"message": "missing config key",
|
||||
}
|
||||
return Response(message, status=400)
|
||||
data_serializer = UserMeConfigSerializer(
|
||||
data=request.data, required=False
|
||||
)
|
||||
data_serializer.is_valid(raise_exception=True)
|
||||
validated_data = data_serializer.validated_data
|
||||
UserConfig(request.user.id).update_config(to_update=validated_data)
|
||||
config = UserConfig(request.user.id).get_config()
|
||||
serializer = UserMeConfigSerializer(config)
|
||||
|
||||
user_conf = UserConfig(user_id)
|
||||
for key, value in data_config.items():
|
||||
try:
|
||||
user_conf.set_value(key, value)
|
||||
except ValueError as err:
|
||||
message = {
|
||||
"status": "Bad Request",
|
||||
"message": f"failed updating {key} to '{value}', {err}",
|
||||
}
|
||||
return Response(message, status=400)
|
||||
|
||||
response = user_conf.get_config()
|
||||
response.update({"user_id": user_id})
|
||||
|
||||
return Response(response)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name="dispatch")
|
||||
@ -67,21 +79,37 @@ class LoginApiView(APIView):
|
||||
"""
|
||||
|
||||
permission_classes = [AllowAny]
|
||||
SEC_IN_DAY = 60 * 60 * 24
|
||||
|
||||
@extend_schema(
|
||||
request=LoginSerializer(),
|
||||
responses={204: OpenApiResponse(description="login successful")},
|
||||
)
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""post data"""
|
||||
"""login with username and password"""
|
||||
# pylint: disable=no-member
|
||||
data_serializer = LoginSerializer(data=request.data)
|
||||
data_serializer.is_valid(raise_exception=True)
|
||||
validated_data = data_serializer.validated_data
|
||||
|
||||
username = request.data.get("username")
|
||||
password = request.data.get("password")
|
||||
username = validated_data["username"]
|
||||
password = validated_data["password"]
|
||||
remember_me = validated_data.get("remember_me")
|
||||
|
||||
user = authenticate(request, username=username, password=password)
|
||||
if user is None:
|
||||
error = ErrorResponseSerializer({"error": "Invalid credentials"})
|
||||
return Response(error.data, status=400)
|
||||
|
||||
if user is not None:
|
||||
login(request, user) # Creates a session for the user
|
||||
return Response({"message": "Login successful"}, status=200)
|
||||
if remember_me == "on":
|
||||
request.session.set_expiry(self.SEC_IN_DAY * 365)
|
||||
else:
|
||||
request.session.set_expiry(self.SEC_IN_DAY * 2)
|
||||
|
||||
return Response({"message": "Invalid credentials"}, status=400)
|
||||
print(f"expire session in {request.session.get_expiry_age()} secs")
|
||||
|
||||
login(request, user) # Creates a session for the user
|
||||
return Response(status=204)
|
||||
|
||||
|
||||
class LogoutApiView(ApiBaseView):
|
||||
@ -89,7 +117,10 @@ class LogoutApiView(ApiBaseView):
|
||||
POST: handle logout
|
||||
"""
|
||||
|
||||
@extend_schema(
|
||||
responses={204: OpenApiResponse(description="logout successful")}
|
||||
)
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""logout on post request"""
|
||||
"""logout user from session"""
|
||||
logout(request)
|
||||
return Response({"message": "Successfully logged out."}, status=200)
|
||||
return Response(status=204)
|
||||
|
@ -53,8 +53,8 @@ class SponsorBlock:
|
||||
print(f"{youtube_id}: get sponsorblock timestamps")
|
||||
try:
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
except requests.ReadTimeout:
|
||||
print(f"{youtube_id}: sponsorblock API timeout")
|
||||
except (requests.ReadTimeout, requests.ConnectionError) as err:
|
||||
print(f"{youtube_id}: sponsorblock API error: {str(err)}")
|
||||
return False
|
||||
|
||||
if not response.ok:
|
||||
|
Loading…
x
Reference in New Issue
Block a user