From: Georgios Atheridis Date: Mon, 23 Jan 2023 14:03:54 +0000 (+0000) Subject: Admin has more options on which clips to allow and deny X-Git-Url: https://git.atheridis.org/?a=commitdiff_plain;h=816468ee3f3cbc0fd7f28ae090878232fd0e5b73;p=ihaspeks%2Fclip-ranker.git Admin has more options on which clips to allow and deny The admin can now choose to only allow clips from specific channel, clips that were made during a specific date or later, whether or not the user who is uploading the clip also needs to be the one who has clipped, and also added a cutoff point for being able to upload clips. Fixed some timezone issues caused in the Clips model. --- diff --git a/TODO b/TODO index eaaad18..7185a54 100644 --- a/TODO +++ b/TODO @@ -1,10 +1,10 @@ - Clips should only be accepted under certain conditions layed out in the database. --- Clip for channels --- Clip needs to be created within a timeframe --- Clip needs to be created by user adding the clip +-- Allow admin site to add username instead of broadcaster id in ResetData - Implement Clip categories - Display clip info more clearly -- Who uploaded the clip -- Clip comments + +- Refresh tokens diff --git a/core/manager/admin.py b/core/manager/admin.py index 83244a4..9a25d48 100644 --- a/core/manager/admin.py +++ b/core/manager/admin.py @@ -17,7 +17,18 @@ along with this program. If not, see . from django.contrib import admin # Register your models here. -from .models import Clip, ResetData +from .models import Clip, ResetData, AllowedChannel + + +class AllowedChannelInline(admin.TabularInline): + model = AllowedChannel + + +class ResetDataAdmin(admin.ModelAdmin): + inlines = [ + AllowedChannelInline, + ] + admin.site.register(Clip) -admin.site.register(ResetData) +admin.site.register(ResetData, ResetDataAdmin) diff --git a/core/manager/errors.py b/core/manager/errors.py index 4eeb691..702232d 100644 --- a/core/manager/errors.py +++ b/core/manager/errors.py @@ -14,5 +14,23 @@ 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 . """ -class TooManyClips(Exception): + + +class TooManyClipsError(Exception): + pass + + +class TooLateError(Exception): + pass + + +class ChannelNotAllowedError(Exception): + pass + + +class UserNotCreatedClipError(Exception): + pass + + +class ClipTooOldError(Exception): pass diff --git a/core/manager/migrations/0013_resetdata_clip_limit_to_channels_and_more.py b/core/manager/migrations/0013_resetdata_clip_limit_to_channels_and_more.py new file mode 100644 index 0000000..62a60d9 --- /dev/null +++ b/core/manager/migrations/0013_resetdata_clip_limit_to_channels_and_more.py @@ -0,0 +1,29 @@ +# Generated by Django 4.1.5 on 2023-01-23 11:51 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("manager", "0012_resetdata_ranks"), + ] + + operations = [ + migrations.AddField( + model_name="resetdata", + name="clip_limit_to_channels", + field=models.JSONField(null=True), + ), + migrations.AddField( + model_name="resetdata", + name="clip_newer_than", + field=models.DateTimeField(default=datetime.datetime(1970, 1, 1, 0, 0, 1)), + ), + migrations.AddField( + model_name="resetdata", + name="user_created_clip", + field=models.BooleanField(default=True), + ), + ] diff --git a/core/manager/migrations/0014_allowedchannel.py b/core/manager/migrations/0014_allowedchannel.py new file mode 100644 index 0000000..ec93b98 --- /dev/null +++ b/core/manager/migrations/0014_allowedchannel.py @@ -0,0 +1,36 @@ +# Generated by Django 4.1.5 on 2023-01-23 12:03 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("manager", "0013_resetdata_clip_limit_to_channels_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="AllowedChannel", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("broadcaster_id", models.CharField(max_length=100)), + ( + "reset_data", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="manager.resetdata", + ), + ), + ], + ), + ] diff --git a/core/manager/migrations/0015_remove_resetdata_clip_limit_to_channels_and_more.py b/core/manager/migrations/0015_remove_resetdata_clip_limit_to_channels_and_more.py new file mode 100644 index 0000000..3ad93f1 --- /dev/null +++ b/core/manager/migrations/0015_remove_resetdata_clip_limit_to_channels_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.5 on 2023-01-23 12:14 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("manager", "0014_allowedchannel"), + ] + + operations = [ + migrations.RemoveField( + model_name="resetdata", + name="clip_limit_to_channels", + ), + migrations.AddField( + model_name="resetdata", + name="end_date_time", + field=models.DateTimeField(default=datetime.datetime(2038, 1, 19, 3, 14)), + ), + ] diff --git a/core/manager/models.py b/core/manager/models.py index 6c6fc88..bd497b7 100644 --- a/core/manager/models.py +++ b/core/manager/models.py @@ -14,14 +14,26 @@ 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 . """ +from datetime import datetime from django.db import models from django.contrib.auth.models import User class ResetData(models.Model): date_time = models.DateTimeField() + end_date_time = models.DateTimeField(default=datetime.utcfromtimestamp(2147483640)) max_clips = models.IntegerField(default=2) ranks = models.IntegerField(default=5) + user_created_clip = models.BooleanField(default=True) + clip_newer_than = models.DateTimeField(default=datetime.utcfromtimestamp(1)) + + +class AllowedChannel(models.Model): + broadcaster_id = models.CharField(max_length=100) + reset_data = models.ForeignKey(ResetData, on_delete=models.CASCADE) + + class Meta: + unique_together = ('broadcaster_id', 'reset_data',) class Clip(models.Model): diff --git a/core/manager/request_clip.py b/core/manager/request_clip.py index 47654ca..bdfddbc 100644 --- a/core/manager/request_clip.py +++ b/core/manager/request_clip.py @@ -16,10 +16,11 @@ along with this program. If not, see . """ import requests import datetime -from .errors import TooManyClips +import pytz +from .errors import TooManyClipsError, TooLateError, ChannelNotAllowedError, UserNotCreatedClipError, ClipTooOldError from .models import Clip, ResetData from urllib.parse import urlparse -from allauth.socialaccount.models import SocialApp, SocialToken +from allauth.socialaccount.models import SocialApp, SocialToken, SocialAccount from django.contrib.auth.models import User @@ -28,9 +29,11 @@ def request_clip(user, clip: str): user = User.objects.get(id=user.id) reset_data = ResetData.objects.latest('date_time') reset_time = reset_data.date_time - print(reset_time) max_clips = reset_data.max_clips + if reset_data.end_date_time < datetime.datetime.now(pytz.utc): + raise TooLateError + if ( len( Clip.objects.filter(account=user).filter( @@ -39,7 +42,7 @@ def request_clip(user, clip: str): ) >= max_clips ): - raise TooManyClips + raise TooManyClipsError social_app: SocialApp = SocialApp.objects.first() oauth = SocialToken.objects.first().token @@ -58,7 +61,22 @@ def request_clip(user, clip: str): raise Exception data = r.json()["data"][0] - print(data) + + if reset_data.user_created_clip: + if not SocialAccount.objects.get(user=user).uid == data["creator_id"]: + raise UserNotCreatedClipError + + if reset_data.allowedchannel_set.count() != 0: + allowed_channels = reset_data.allowedchannel_set.filter(broadcaster_id=data["broadcaster_id"]) + if not allowed_channels.exists(): + raise ChannelNotAllowedError + + if ( + reset_data.clip_newer_than + > datetime.datetime.strptime(data["created_at"], "%Y-%m-%dT%H:%M:%S%z") + ): + raise ClipTooOldError + clip = Clip( id=data["id"], url=data["url"], @@ -75,7 +93,7 @@ def request_clip(user, clip: str): thumbnail_url=data["thumbnail_url"], duration=data["duration"], vod_offset=data["vod_offset"], - date_added=datetime.datetime.now(), + date_added=datetime.datetime.now(pytz.utc), account=user, ) clip.validate_unique() diff --git a/core/manager/views.py b/core/manager/views.py index a9441ab..5d66eca 100644 --- a/core/manager/views.py +++ b/core/manager/views.py @@ -20,7 +20,7 @@ from django.contrib.admin.views.decorators import staff_member_required from .request_clip import request_clip from .forms import ClipForm, RankForm -from .errors import TooManyClips +from .errors import TooManyClipsError, TooLateError, ChannelNotAllowedError, UserNotCreatedClipError, ClipTooOldError from .models import Clip, ResetData @@ -28,16 +28,15 @@ from .models import Clip, ResetData def show_clips(request, id): reset_data = ResetData.objects.latest('date_time') reset_time = reset_data.date_time - print(reset_time) try: - video = Clip.objects.filter(date_added__gt=reset_time)[id - 1] + video = Clip.objects.filter( + date_added__gt=reset_time + ).order_by("date_added")[id - 1] except IndexError: - print("hi") return redirect(final_ranking) if request.method == "POST": form = RankForm(request.POST) if form.is_valid(): - print(f"post: {id} | {form.cleaned_data['value']}") video.rank = form.cleaned_data["value"] video.save() return redirect(show_clips, id=id + 1) @@ -51,7 +50,6 @@ def show_clips(request, id): def final_ranking(request): reset_data = ResetData.objects.latest('date_time') reset_time = reset_data.date_time - print(reset_time) return render(request, "manager/final.html", context={ "videos": Clip.objects.filter(date_added__gt=reset_time), "ranks": range(reset_data.ranks, 0, -1), @@ -69,24 +67,21 @@ def get_name(request): request_clip(user=request.user, clip=form.cleaned_data["clip"]) except ValidationError: message = "Sorry, clip already exists. Please send another clip." - return render(request, "manager/index.html", {"message": message}) - # return HttpResponse(b"

Clip already exists

") - except TooManyClips: + except TooManyClipsError: message = "Sorry, you have already reached the clip limit." - return render(request, "manager/index.html", {"message": message}) - # return HttpResponse(b"

You have submitted the maximum number of clips

") + except TooLateError: + message = "Sorry, the deadline for posting has passed" + except ChannelNotAllowedError: + message = "Sorry, you're not allowed to send a clip from that channel." + except UserNotCreatedClipError: + message = "Sorry, you need to be the one who has created the clip." + except ClipTooOldError: + message = "Sorry, the clip is too old. Please send a newer clip." except Exception: message = "Something went wrong." - return render(request, "manager/index.html", {"message": message}) - # return HttpResponse(b"

NOPE

") - # process the data in form.cleaned_data as required - # ... - # redirect to a new URL: - message = "Thank you for submitting a clip." + else: + message = "Thank you for submitting a clip." return render(request, "manager/index.html", {"message": message}) - # return HttpResponseRedirect("/thanks/") - else: - print("invalid") # if a GET (or any other method) we'll create a blank form else: