mirror of
https://git.vectorsigma.ru/public/tubearchivist.git
synced 2026-08-05 01:59:27 +00:00
reset migrations, split user app
This commit is contained in:
@@ -5,17 +5,11 @@ from django.urls import path
|
||||
|
||||
urlpatterns = [
|
||||
path("ping/", views.PingView.as_view(), name="ping"),
|
||||
path("login/", views.LoginApiView.as_view(), name="api-login"),
|
||||
path(
|
||||
"refresh/",
|
||||
views.RefreshView.as_view(),
|
||||
name="api-refresh",
|
||||
),
|
||||
path(
|
||||
"config/user/",
|
||||
views.UserConfigView.as_view(),
|
||||
name="api-config-user",
|
||||
),
|
||||
path(
|
||||
"watched/",
|
||||
views.WatchedView.as_view(),
|
||||
|
||||
@@ -9,14 +9,11 @@ from home.src.index.generic import Pagination
|
||||
from home.src.ta.config import AppConfig, ReleaseVersion
|
||||
from home.src.ta.settings import EnvironmentSettings
|
||||
from home.src.ta.ta_redis import RedisArchivist
|
||||
from home.src.ta.users import UserConfig
|
||||
from rest_framework import permissions
|
||||
from rest_framework.authentication import (
|
||||
SessionAuthentication,
|
||||
TokenAuthentication,
|
||||
)
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework.authtoken.views import ObtainAuthToken
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from task.tasks import check_reindex
|
||||
@@ -123,34 +120,6 @@ class PingView(ApiBaseView):
|
||||
return Response(data)
|
||||
|
||||
|
||||
class LoginApiView(ObtainAuthToken):
|
||||
"""resolves to /api/login/
|
||||
POST: return token and username after successful login
|
||||
"""
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""post data"""
|
||||
# pylint: disable=no-member
|
||||
serializer = self.serializer_class(
|
||||
data=request.data, context={"request": request}
|
||||
)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
user = serializer.validated_data["user"]
|
||||
token, _ = Token.objects.get_or_create(user=user)
|
||||
|
||||
print(f"returning token for user with id {user.pk}")
|
||||
|
||||
return Response(
|
||||
{
|
||||
"token": token.key,
|
||||
"user_id": user.pk,
|
||||
"is_superuser": user.is_superuser,
|
||||
"is_staff": user.is_staff,
|
||||
"user_groups": [group.name for group in user.groups.all()],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class RefreshView(ApiBaseView):
|
||||
"""resolves to /api/refresh/
|
||||
GET: get refresh progress
|
||||
@@ -185,42 +154,6 @@ class RefreshView(ApiBaseView):
|
||||
return Response(data)
|
||||
|
||||
|
||||
class UserConfigView(ApiBaseView):
|
||||
"""resolves to /api/config/user/
|
||||
GET: return current user config
|
||||
POST: update user config
|
||||
"""
|
||||
|
||||
def get(self, request):
|
||||
"""get config"""
|
||||
user_id = request.user.id
|
||||
response = UserConfig(user_id).get_config()
|
||||
response.update({"user_id": user_id})
|
||||
|
||||
return Response(response)
|
||||
|
||||
def post(self, request):
|
||||
"""update config"""
|
||||
user_id = request.user.id
|
||||
data = request.data
|
||||
|
||||
user_conf = UserConfig(user_id)
|
||||
for key, value in data.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)
|
||||
|
||||
|
||||
class WatchedView(ApiBaseView):
|
||||
"""resolves to /api/watched/
|
||||
POST: change watched state of video, channel or playlist
|
||||
|
||||
@@ -10,8 +10,8 @@ import os
|
||||
import re
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from home.models import Account
|
||||
from home.src.ta.settings import EnvironmentSettings
|
||||
from user.models import Account
|
||||
|
||||
LOGO = """
|
||||
|
||||
|
||||
@@ -9,23 +9,23 @@ from datetime import datetime
|
||||
from random import randint
|
||||
from time import sleep
|
||||
|
||||
from appsettings.src.index_setup import ElasitIndexWrap
|
||||
from appsettings.src.snapshot import ElasticSnapshot
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.utils import dateformat
|
||||
from django_celery_beat.models import CrontabSchedule, PeriodicTasks
|
||||
from home.models import CustomPeriodicTask
|
||||
from home.src.es.connect import ElasticWrap
|
||||
from home.src.es.index_setup import ElasitIndexWrap
|
||||
from home.src.es.snapshot import ElasticSnapshot
|
||||
from home.src.ta.config import AppConfig, ReleaseVersion
|
||||
from home.src.ta.config_schedule import ScheduleBuilder
|
||||
from home.src.ta.helper import clear_dl_cache
|
||||
from home.src.ta.notify import Notifications
|
||||
from home.src.ta.settings import EnvironmentSettings
|
||||
from home.src.ta.ta_redis import RedisArchivist
|
||||
from home.src.ta.task_config import TASK_CONFIG
|
||||
from home.src.ta.task_manager import TaskManager
|
||||
from home.tasks import version_check
|
||||
from task.models import CustomPeriodicTask
|
||||
from task.src.config_schedule import ScheduleBuilder
|
||||
from task.src.notify import Notifications
|
||||
from task.src.task_config import TASK_CONFIG
|
||||
from task.src.task_manager import TaskManager
|
||||
from task.tasks import version_check
|
||||
|
||||
TOPIC = """
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ INSTALLED_APPS = [
|
||||
"task",
|
||||
"appsettings",
|
||||
"stats",
|
||||
"user",
|
||||
"config",
|
||||
]
|
||||
|
||||
@@ -226,7 +227,7 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
},
|
||||
]
|
||||
|
||||
AUTH_USER_MODEL = "home.Account"
|
||||
AUTH_USER_MODEL = "user.Account"
|
||||
|
||||
# Forward-auth authentication
|
||||
if bool(environ.get("TA_ENABLE_AUTH_PROXY")):
|
||||
|
||||
@@ -27,5 +27,6 @@ urlpatterns = [
|
||||
path("api/task/", include("task.urls")),
|
||||
path("api/appsettings/", include("appsettings.urls")),
|
||||
path("api/stats/", include("stats.urls")),
|
||||
path("api/user/", include("user.urls")),
|
||||
path("admin/", admin.site.urls),
|
||||
]
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
"""custom admin classes"""
|
||||
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||
from django_celery_beat import models as BeatModels
|
||||
|
||||
from .models import Account
|
||||
|
||||
|
||||
class HomeAdmin(BaseUserAdmin):
|
||||
"""register in admin page"""
|
||||
|
||||
list_display = ("name", "is_staff", "is_superuser")
|
||||
list_filter = ("is_superuser",)
|
||||
|
||||
fieldsets = (
|
||||
(None, {"fields": ("is_staff", "is_superuser", "password")}),
|
||||
("Personal info", {"fields": ("name",)}),
|
||||
("Groups", {"fields": ("groups",)}),
|
||||
("Permissions", {"fields": ("user_permissions",)}),
|
||||
)
|
||||
add_fieldsets = (
|
||||
(
|
||||
None,
|
||||
{"fields": ("is_staff", "is_superuser", "password1", "password2")},
|
||||
),
|
||||
("Personal info", {"fields": ("name",)}),
|
||||
("Groups", {"fields": ("groups",)}),
|
||||
("Permissions", {"fields": ("user_permissions",)}),
|
||||
)
|
||||
|
||||
search_fields = ("name",)
|
||||
ordering = ("name",)
|
||||
filter_horizontal = ()
|
||||
|
||||
|
||||
admin.site.register(Account, HomeAdmin)
|
||||
admin.site.unregister(
|
||||
[
|
||||
BeatModels.ClockedSchedule,
|
||||
BeatModels.CrontabSchedule,
|
||||
BeatModels.IntervalSchedule,
|
||||
BeatModels.PeriodicTask,
|
||||
BeatModels.SolarSchedule,
|
||||
]
|
||||
)
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
# Generated by Django 4.1.5 on 2023-02-02 06:49
|
||||
|
||||
from django.db import migrations, models
|
||||
import home.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Account',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('name', models.CharField(max_length=150, unique=True)),
|
||||
('is_staff', models.BooleanField(default=False)),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
managers=[
|
||||
('objects', home.models.AccountManager()),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 4.2.7 on 2023-12-05 13:47
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_celery_beat', '0018_improve_crontab_helptext'),
|
||||
('home', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CustomPeriodicTask',
|
||||
fields=[
|
||||
('periodictask_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='django_celery_beat.periodictask')),
|
||||
('task_config', models.JSONField(default=dict)),
|
||||
],
|
||||
bases=('django_celery_beat.periodictask',),
|
||||
),
|
||||
]
|
||||
@@ -1,17 +0,0 @@
|
||||
# Generated by Django 5.0.7 on 2024-07-20 10:09
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("home", "0002_customperiodictask"),
|
||||
("task", "0002_migrate_scheduler"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name="CustomPeriodicTask",
|
||||
),
|
||||
]
|
||||
@@ -1,54 +0,0 @@
|
||||
"""custom models"""
|
||||
|
||||
from django.contrib.auth.models import (
|
||||
AbstractBaseUser,
|
||||
BaseUserManager,
|
||||
PermissionsMixin,
|
||||
)
|
||||
from django.db import models
|
||||
|
||||
|
||||
class AccountManager(BaseUserManager):
|
||||
"""manage user creation methods"""
|
||||
|
||||
use_in_migrations = True
|
||||
|
||||
def _create_user(self, name, password, **extra_fields):
|
||||
"""create regular user private"""
|
||||
values = [name, password]
|
||||
field_value_map = dict(zip(self.model.REQUIRED_FIELDS, values))
|
||||
for field_name, value in field_value_map.items():
|
||||
if not value:
|
||||
raise ValueError(f"The {field_name} value must be set")
|
||||
|
||||
user = self.model(name=name, **extra_fields)
|
||||
user.set_password(password)
|
||||
user.save(using=self._db)
|
||||
return user
|
||||
|
||||
def create_user(self, name, password):
|
||||
"""create regular user public"""
|
||||
return self._create_user(name, password)
|
||||
|
||||
def create_superuser(self, name, password, **extra_fields):
|
||||
"""create super user"""
|
||||
extra_fields.setdefault("is_staff", True)
|
||||
extra_fields.setdefault("is_superuser", True)
|
||||
|
||||
if extra_fields.get("is_staff") is not True:
|
||||
raise ValueError("Superuser must have is_staff=True.")
|
||||
if extra_fields.get("is_superuser") is not True:
|
||||
raise ValueError("Superuser must have is_superuser=True.")
|
||||
|
||||
return self._create_user(name, password, **extra_fields)
|
||||
|
||||
|
||||
class Account(AbstractBaseUser, PermissionsMixin):
|
||||
"""handle account creation"""
|
||||
|
||||
name = models.CharField(max_length=150, unique=True)
|
||||
is_staff = models.BooleanField(default=False)
|
||||
objects = AccountManager()
|
||||
|
||||
USERNAME_FIELD = "name"
|
||||
REQUIRED_FIELDS = ["password"]
|
||||
|
||||
@@ -8,7 +8,7 @@ import math
|
||||
from download.src.yt_dlp_base import YtWrap
|
||||
from home.src.es.connect import ElasticWrap
|
||||
from home.src.ta.config import AppConfig
|
||||
from home.src.ta.users import UserConfig
|
||||
from user.src.user_config import UserConfig
|
||||
|
||||
|
||||
class YouTubeItem:
|
||||
|
||||
@@ -46,13 +46,13 @@ from home.src.ta.config import AppConfig, ReleaseVersion
|
||||
from home.src.ta.helper import check_stylesheet, time_parser
|
||||
from home.src.ta.settings import EnvironmentSettings
|
||||
from home.src.ta.ta_redis import RedisArchivist
|
||||
from home.src.ta.users import UserConfig
|
||||
from playlist.src.index import YoutubePlaylist
|
||||
from rest_framework.authtoken.models import Token
|
||||
from task.models import CustomPeriodicTask
|
||||
from task.src.config_schedule import ScheduleBuilder
|
||||
from task.src.notify import Notifications, get_all_notifications
|
||||
from task.tasks import index_channel_playlists, subscribe_to
|
||||
from user.src.user_config import UserConfig
|
||||
from video.src.constants import VideoTypeEnum
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ from channel.src import index as channel
|
||||
from download.src.thumbnails import ThumbManager
|
||||
from home.src.es.connect import ElasticWrap, IndexPaginate
|
||||
from home.src.index.generic import YouTubeItem
|
||||
from video.src.index import YoutubeVideo
|
||||
from video.src import index as ta_video
|
||||
|
||||
|
||||
class YoutubePlaylist(YouTubeItem):
|
||||
@@ -255,7 +255,7 @@ class YoutubePlaylist(YouTubeItem):
|
||||
i = 0
|
||||
while i < len(playlist):
|
||||
video_id = playlist[i]["youtube_id"]
|
||||
video = YoutubeVideo(video_id)
|
||||
video = ta_video.YoutubeVideo(video_id)
|
||||
video.get_from_es()
|
||||
if (
|
||||
channel_id is None
|
||||
@@ -278,7 +278,7 @@ class YoutubePlaylist(YouTubeItem):
|
||||
if i["downloaded"]
|
||||
]
|
||||
for youtube_id in all_youtube_id:
|
||||
YoutubeVideo(youtube_id).delete_media_file()
|
||||
ta_video.YoutubeVideo(youtube_id).delete_media_file()
|
||||
|
||||
self.delete_metadata()
|
||||
|
||||
@@ -312,7 +312,7 @@ class YoutubePlaylist(YouTubeItem):
|
||||
)
|
||||
self.set_playlist_thumbnail()
|
||||
self.upload_to_es()
|
||||
video = YoutubeVideo(video_id)
|
||||
video = ta_video.YoutubeVideo(video_id)
|
||||
video.get_from_es()
|
||||
if "playlist" not in video.json_data:
|
||||
video.json_data["playlist"] = []
|
||||
@@ -321,7 +321,7 @@ class YoutubePlaylist(YouTubeItem):
|
||||
return True
|
||||
|
||||
def remove_playlist_from_video(self, video_id):
|
||||
video = YoutubeVideo(video_id)
|
||||
video = ta_video.YoutubeVideo(video_id)
|
||||
video.get_from_es()
|
||||
if video.json_data is not None and "playlist" in video.json_data:
|
||||
video.json_data["playlist"].remove(self.youtube_id)
|
||||
@@ -410,7 +410,7 @@ class YoutubePlaylist(YouTubeItem):
|
||||
)
|
||||
|
||||
def get_video_is_watched(self, video_id):
|
||||
video = YoutubeVideo(video_id)
|
||||
video = ta_video.YoutubeVideo(video_id)
|
||||
video.get_from_es()
|
||||
return video.json_data["player"]["watched"]
|
||||
|
||||
@@ -426,7 +426,7 @@ class YoutubePlaylist(YouTubeItem):
|
||||
self.get_playlist_art()
|
||||
|
||||
def get_video_metadata(self, video_id):
|
||||
video = YoutubeVideo(video_id)
|
||||
video = ta_video.YoutubeVideo(video_id)
|
||||
video.get_from_es()
|
||||
video_json_data = {
|
||||
"youtube_id": video.json_data["youtube_id"],
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
from api.views import AdminWriteOnly, ApiBaseView
|
||||
from download.src.subscriptions import PlaylistSubscription
|
||||
from home.src.ta.users import UserConfig
|
||||
from playlist.src.index import YoutubePlaylist
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from task.tasks import subscribe_to
|
||||
from user.src.user_config import UserConfig
|
||||
|
||||
|
||||
class PlaylistApiListView(ApiBaseView):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.0.7 on 2024-07-20 09:54
|
||||
# Generated by Django 5.0.7 on 2024-07-22 18:39
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
"""custom migration to copy CustomPeriodicTask to new task app"""
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
def copy_data(apps, schema_editor):
|
||||
"""copy between apps"""
|
||||
|
||||
OldCustomPeriodicTask = apps.get_model("home", "CustomPeriodicTask")
|
||||
NewCustomPeriodicTask = apps.get_model("task", "CustomPeriodicTask")
|
||||
|
||||
for old_instance in OldCustomPeriodicTask.objects.all():
|
||||
field_data = {
|
||||
field.name: getattr(old_instance, field.name)
|
||||
for field in OldCustomPeriodicTask._meta.fields
|
||||
}
|
||||
field_data.pop("id", None)
|
||||
new_instance = NewCustomPeriodicTask(**field_data)
|
||||
new_instance.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
"""migration"""
|
||||
|
||||
dependencies = [
|
||||
("task", "0001_initial"),
|
||||
("home", "0002_customperiodictask"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(copy_data),
|
||||
]
|
||||
0
tubearchivist/user/__init__.py
Normal file
0
tubearchivist/user/__init__.py
Normal file
45
tubearchivist/user/admin.py
Normal file
45
tubearchivist/user/admin.py
Normal file
@@ -0,0 +1,45 @@
|
||||
"""custom admin classes"""
|
||||
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||
from django_celery_beat import models as BeatModels
|
||||
from user.models import Account
|
||||
|
||||
|
||||
class HomeAdmin(BaseUserAdmin):
|
||||
"""register in admin page"""
|
||||
|
||||
list_display = ("name", "is_staff", "is_superuser")
|
||||
list_filter = ("is_superuser",)
|
||||
|
||||
fieldsets = (
|
||||
(None, {"fields": ("is_staff", "is_superuser", "password")}),
|
||||
("Personal info", {"fields": ("name",)}),
|
||||
("Groups", {"fields": ("groups",)}),
|
||||
("Permissions", {"fields": ("user_permissions",)}),
|
||||
)
|
||||
add_fieldsets = (
|
||||
(
|
||||
None,
|
||||
{"fields": ("is_staff", "is_superuser", "password1", "password2")},
|
||||
),
|
||||
("Personal info", {"fields": ("name",)}),
|
||||
("Groups", {"fields": ("groups",)}),
|
||||
("Permissions", {"fields": ("user_permissions",)}),
|
||||
)
|
||||
|
||||
search_fields = ("name",)
|
||||
ordering = ("name",)
|
||||
filter_horizontal = ()
|
||||
|
||||
|
||||
admin.site.register(Account, HomeAdmin)
|
||||
admin.site.unregister(
|
||||
[
|
||||
BeatModels.ClockedSchedule,
|
||||
BeatModels.CrontabSchedule,
|
||||
BeatModels.IntervalSchedule,
|
||||
BeatModels.PeriodicTask,
|
||||
BeatModels.SolarSchedule,
|
||||
]
|
||||
)
|
||||
75
tubearchivist/user/migrations/0001_initial.py
Normal file
75
tubearchivist/user/migrations/0001_initial.py
Normal file
@@ -0,0 +1,75 @@
|
||||
# Generated by Django 5.0.7 on 2024-07-22 19:26
|
||||
|
||||
import user.models
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
("auth", "0012_alter_user_first_name_max_length"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Account",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("password", models.CharField(max_length=128, verbose_name="password")),
|
||||
(
|
||||
"last_login",
|
||||
models.DateTimeField(
|
||||
blank=True, null=True, verbose_name="last login"
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_superuser",
|
||||
models.BooleanField(
|
||||
default=False,
|
||||
help_text="Designates that this user has all permissions without explicitly assigning them.",
|
||||
verbose_name="superuser status",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=150, unique=True)),
|
||||
("is_staff", models.BooleanField(default=False)),
|
||||
(
|
||||
"groups",
|
||||
models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
|
||||
related_name="user_set",
|
||||
related_query_name="user",
|
||||
to="auth.group",
|
||||
verbose_name="groups",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user_permissions",
|
||||
models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="Specific permissions for this user.",
|
||||
related_name="user_set",
|
||||
related_query_name="user",
|
||||
to="auth.permission",
|
||||
verbose_name="user permissions",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
managers=[
|
||||
("objects", user.models.AccountManager()),
|
||||
],
|
||||
),
|
||||
]
|
||||
0
tubearchivist/user/migrations/__init__.py
Normal file
0
tubearchivist/user/migrations/__init__.py
Normal file
54
tubearchivist/user/models.py
Normal file
54
tubearchivist/user/models.py
Normal file
@@ -0,0 +1,54 @@
|
||||
"""custom models"""
|
||||
|
||||
from django.contrib.auth.models import (
|
||||
AbstractBaseUser,
|
||||
BaseUserManager,
|
||||
PermissionsMixin,
|
||||
)
|
||||
from django.db import models
|
||||
|
||||
|
||||
class AccountManager(BaseUserManager):
|
||||
"""manage user creation methods"""
|
||||
|
||||
use_in_migrations = True
|
||||
|
||||
def _create_user(self, name, password, **extra_fields):
|
||||
"""create regular user private"""
|
||||
values = [name, password]
|
||||
field_value_map = dict(zip(self.model.REQUIRED_FIELDS, values))
|
||||
for field_name, value in field_value_map.items():
|
||||
if not value:
|
||||
raise ValueError(f"The {field_name} value must be set")
|
||||
|
||||
user = self.model(name=name, **extra_fields)
|
||||
user.set_password(password)
|
||||
user.save(using=self._db)
|
||||
return user
|
||||
|
||||
def create_user(self, name, password):
|
||||
"""create regular user public"""
|
||||
return self._create_user(name, password)
|
||||
|
||||
def create_superuser(self, name, password, **extra_fields):
|
||||
"""create super user"""
|
||||
extra_fields.setdefault("is_staff", True)
|
||||
extra_fields.setdefault("is_superuser", True)
|
||||
|
||||
if extra_fields.get("is_staff") is not True:
|
||||
raise ValueError("Superuser must have is_staff=True.")
|
||||
if extra_fields.get("is_superuser") is not True:
|
||||
raise ValueError("Superuser must have is_superuser=True.")
|
||||
|
||||
return self._create_user(name, password, **extra_fields)
|
||||
|
||||
|
||||
class Account(AbstractBaseUser, PermissionsMixin):
|
||||
"""handle account creation"""
|
||||
|
||||
name = models.CharField(max_length=150, unique=True)
|
||||
is_staff = models.BooleanField(default=False)
|
||||
objects = AccountManager()
|
||||
|
||||
USERNAME_FIELD = "name"
|
||||
REQUIRED_FIELDS = ["password"]
|
||||
20
tubearchivist/user/serializers.py
Normal file
20
tubearchivist/user/serializers.py
Normal file
@@ -0,0 +1,20 @@
|
||||
"""serializer for account model"""
|
||||
|
||||
from rest_framework import serializers
|
||||
from user.models import Account
|
||||
|
||||
|
||||
class AccountSerializer(serializers.ModelSerializer):
|
||||
"""serialize account"""
|
||||
|
||||
class Meta:
|
||||
model = Account
|
||||
fields = (
|
||||
"id",
|
||||
"name",
|
||||
"is_superuser",
|
||||
"is_staff",
|
||||
"groups",
|
||||
"user_permissions",
|
||||
"last_login",
|
||||
)
|
||||
0
tubearchivist/user/src/__init__.py
Normal file
0
tubearchivist/user/src/__init__.py
Normal file
9
tubearchivist/user/urls.py
Normal file
9
tubearchivist/user/urls.py
Normal file
@@ -0,0 +1,9 @@
|
||||
"""all user API urls"""
|
||||
|
||||
from django.urls import path
|
||||
from user import views
|
||||
|
||||
urlpatterns = [
|
||||
path("login/", views.LoginApiView.as_view(), name="api-user-login"),
|
||||
path("me/", views.UserConfigView.as_view(), name="api-user-me"),
|
||||
]
|
||||
77
tubearchivist/user/views.py
Normal file
77
tubearchivist/user/views.py
Normal file
@@ -0,0 +1,77 @@
|
||||
"""all user api views"""
|
||||
|
||||
from api.views import ApiBaseView
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework.authtoken.views import ObtainAuthToken
|
||||
from rest_framework.response import Response
|
||||
from user.models import Account
|
||||
from user.serializers import AccountSerializer
|
||||
from user.src.user_config import UserConfig
|
||||
|
||||
|
||||
class UserConfigView(ApiBaseView):
|
||||
"""resolves to /api/config/user/
|
||||
GET: return current user config
|
||||
POST: update user config
|
||||
"""
|
||||
|
||||
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()
|
||||
|
||||
config = UserConfig(user_id).get_config()
|
||||
response.update({"config": config})
|
||||
|
||||
return Response(response)
|
||||
|
||||
def post(self, request):
|
||||
"""update config"""
|
||||
user_id = request.user.id
|
||||
data = request.data
|
||||
|
||||
user_conf = UserConfig(user_id)
|
||||
for key, value in data.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)
|
||||
|
||||
|
||||
class LoginApiView(ObtainAuthToken):
|
||||
"""resolves to /api/login/
|
||||
POST: return token and username after successful login
|
||||
"""
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""post data"""
|
||||
# pylint: disable=no-member
|
||||
serializer = self.serializer_class(
|
||||
data=request.data, context={"request": request}
|
||||
)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
user = serializer.validated_data["user"]
|
||||
token, _ = Token.objects.get_or_create(user=user)
|
||||
|
||||
print(f"returning token for user with id {user.pk}")
|
||||
|
||||
return Response(
|
||||
{
|
||||
"token": token.key,
|
||||
"user_id": user.pk,
|
||||
"is_superuser": user.is_superuser,
|
||||
"is_staff": user.is_staff,
|
||||
"user_groups": [group.name for group in user.groups.all()],
|
||||
}
|
||||
)
|
||||
@@ -14,9 +14,9 @@ from home.src.es.connect import ElasticWrap
|
||||
from home.src.index.generic import YouTubeItem
|
||||
from home.src.ta.helper import get_duration_sec, get_duration_str, randomizor
|
||||
from home.src.ta.settings import EnvironmentSettings
|
||||
from home.src.ta.users import UserConfig
|
||||
from playlist.src import index as ta_playlist
|
||||
from ryd_client import ryd_client
|
||||
from user.src.user_config import UserConfig
|
||||
from video.src.comments import Comments
|
||||
from video.src.constants import VideoTypeEnum
|
||||
from video.src.media_streams import MediaStreamExtractor
|
||||
|
||||
Reference in New Issue
Block a user