This repository has been archived on 2022-11-26. You can view files and clone it, but cannot push or open issues or pull requests.
Episodes.Community/Show/views.py

527 lines
19 KiB
Python
Raw Permalink Normal View History

2017-12-28 10:39:02 +00:00
# Episodes.Community - Community-Driven TV Show Episode Link Sharing Site
# Copyright (C) 2017 Evert "Diamond" Prants <evert@lunasqu.ee>, Taizo "Tsa6" Simpson <taizo@tsa6.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# 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 <https://www.gnu.org/licenses/>.
2017-11-11 12:57:52 +00:00
from django.template import RequestContext
from django.shortcuts import render, get_list_or_404, get_object_or_404, redirect
2017-11-10 13:55:39 +00:00
from django.views import View
from django.views.generic.base import TemplateView
from django.contrib.auth.decorators import login_required
2017-11-10 13:55:39 +00:00
from django.conf import settings
from django.utils.text import slugify
2017-12-27 15:01:39 +00:00
from django.http import Http404, HttpResponseForbidden, HttpResponse, HttpResponseRedirect
from django.db.models import Case, When, Value, IntegerField, Count, F, Q
from django.contrib.auth.mixins import LoginRequiredMixin
2017-11-10 13:55:39 +00:00
from guardian.decorators import permission_required_or_403
from LandingPage.models import User, Show, Season, Episode, Submission, SubmissionVote, Ban, Report, UserAction
2017-08-25 18:03:37 +00:00
2017-11-11 12:57:52 +00:00
from . import forms
import datetime
2017-08-25 18:03:37 +00:00
# Create your views here.
2017-11-10 13:55:39 +00:00
# Index page of a show
2017-11-10 15:21:21 +00:00
class IndexView(TemplateView):
2017-11-10 13:55:39 +00:00
template_name = "show.html"
def get_context_data(self, abbr, **kwargs):
2017-11-10 13:55:39 +00:00
ctx = super().get_context_data()
# Get show by abbr, add episode count to the show and return only the first object
show = get_object_or_404(Show, abbr=abbr)
# Get all seasons of the show and annotate episode counts onto them
seasons = show.seasons.all()
# Add fields to context
ctx['show'] = show
ctx['seasons'] = seasons
2017-11-10 15:21:21 +00:00
return ctx
# Episodes page of a show
2017-11-10 15:21:21 +00:00
class EpisodeView(TemplateView):
template_name = "episode.html"
def get_context_data(self, abbr, season, episode, **kwargs):
2017-11-10 15:21:21 +00:00
ctx = super().get_context_data()
2017-12-29 14:22:58 +00:00
highlight = self.request.GET.get('submission', None)
if not highlight == None:
highlight = int(highlight)
# Get show by abbr
show = get_object_or_404(Show, abbr=abbr)
# Check next or previous
season_number = int(season)
episode_number = int(episode)
lastep = Episode.objects.filter(season__number=season_number,show=show).order_by('episode').last()
season_count = Season.objects.filter(show=show).count()
if season_count == 0:
raise Http404('This show has no episodes.')
if episode_number == 0 and season_number > 1:
season_number -= 1
epobj = Episode.objects.filter(season__number=season_number,show=show).order_by('episode').last()
if not epobj:
raise Http404('No Episode matches the given query.')
episode_number = int(epobj.episode)
2018-03-02 13:46:25 +00:00
ctx['url'] = '%s/episode/%d/%d'%(show.url(), season_number, episode_number)
elif episode_number > int(lastep.episode):
season_number += 1
episode_number = 1
2018-03-02 13:46:25 +00:00
ctx['url'] = '%s/episode/%d/%d'%(show.url(), season_number, episode_number)
if 'url' in ctx:
return ctx
episode = get_object_or_404(Episode, show=show,season__number=season,episode=episode)
2017-11-10 15:21:21 +00:00
# I acknowledge that this is a mess. A functional mess. But a mess nonetheless. Hey, that rhymed!
submissions = episode.submissions.annotate(
positives=Count(
Case(
When(
votes__positive=True,
then=Value(1)
)
)
),
negatives=Count('votes') - F('positives'),
score=F('positives') - F('negatives')
2017-12-28 15:34:58 +00:00
).order_by('-pinned', '-score')
2017-11-10 15:21:21 +00:00
# Add fields to context
ctx['show'] = show
ctx['episode'] = episode
ctx['submissions'] = submissions
2017-12-29 14:22:58 +00:00
ctx['highlight'] = highlight
ctx['has_previous'] = episode_number > 1 or season_number > 1
ctx['has_next'] = episode_number < int(lastep.episode) or season_number < season_count
2017-11-10 15:21:21 +00:00
2017-11-10 13:55:39 +00:00
return ctx
def render_to_response(self, context):
if 'url' in context:
return redirect(context['url'])
return super(EpisodeView, self).render_to_response(context)
def EpisodeFindSubmission(req, abbr, submission):
show = get_object_or_404(Show, abbr=abbr)
submission = int(submission)
episode = get_object_or_404(Episode, submissions__id=submission)
2018-03-02 13:46:25 +00:00
return HttpResponseRedirect('%s/episode/%d/%d?submission=%d'%(show.url(), episode.season.number, episode.episode, submission))
2017-11-11 12:57:52 +00:00
# Submission form GET and POST
@login_required
def SubmissionForm(req, abbr, season, episode):
show = get_object_or_404(Show, abbr=abbr)
episode = get_object_or_404(Episode, show=show,season__number=season,episode=episode)
user = req.user
2017-11-11 12:57:52 +00:00
form = forms.SubmissionForm()
# Request context
ctx = {
'form': form,
'show': show,
2018-03-02 13:46:25 +00:00
'episode': episode
2017-11-11 12:57:52 +00:00
}
2017-12-27 15:01:39 +00:00
# Get bans for this user regarding this show
bans = Ban.objects.filter(Q(scope=show) | Q(site_wide=True), Q(expiration__gte=datetime.datetime.now()) | Q(permanent=True), user=user)
if bans.count() > 0:
return HttpResponseForbidden('You are banned from submitting links to this show.<br>Reason: %s'%(bans.first().reason))
2017-11-11 12:57:52 +00:00
# Handle POST
if req.method == 'POST':
form = forms.SubmissionForm(req.POST)
ctx['form'] = form
if form.is_valid():
form_data = form.cleaned_data
# Check if the URL has already been submitted
if Submission.objects.filter(episode=episode,url=form_data['url']).count() > 0:
ctx['error'] = 'This URL has already been submitted!'
return render(req, "submit.html", ctx)
2017-12-27 15:01:39 +00:00
if not user.has_perm('LandingPage.can_moderate_show', show):
# Check if there has been a submission by this user for this episode within the last 24 hours
if Submission.objects.filter(user=user,episode=episode,timestamp__gte=datetime.datetime.now() - datetime.timedelta(hours=24)).count() > 0:
ctx['error'] = 'You can only submit one link for an episode in 24 hours!'
return render(req, "submit.html", ctx)
2017-11-11 12:57:52 +00:00
new_submission = form.save(commit=False)
new_submission.user = user
new_submission.episode = episode
new_submission.save()
act = UserAction(user=user,show=show,act_type=1,url='%s/episode/%d/%d?submission=%d'%(show.url(), episode.season.number, episode.episode, new_submission.pk))
act.save()
2018-03-02 13:46:25 +00:00
return HttpResponseRedirect('%s/episode/%d/%d'%(show.url(), episode.season.number, episode.episode))
2017-11-11 12:57:52 +00:00
else:
ctx['error'] = 'Invalid fields!'
return render(req, "submit.html", ctx)
# Edit a submission - for moderators
2017-12-27 15:01:39 +00:00
@permission_required_or_403('LandingPage.can_moderate_show', (Show, 'abbr', 'abbr'), accept_global_perms=True)
def SubmissionModForm(req, abbr, submission):
show = get_object_or_404(Show, abbr=abbr)
submission = get_object_or_404(Submission, pk=submission)
episode = submission.episode
user = req.user
form = forms.SubmissionFormAdmin(instance=submission)
# Request context
ctx = {
'form': form,
'show': show,
2018-03-02 13:46:25 +00:00
'episode': episode
}
# Handle POST
if req.method == 'POST':
if 'delete' in req.POST:
act = UserAction(user=user,show=show,act_type=4,url='%s/episode/%d/%d?submission=%d'%(show.url(), episode.season.number, episode.episode, submission.pk))
act.save()
submission.delete()
2018-03-02 13:46:25 +00:00
return HttpResponseRedirect('%s/episode/%d/%d'%(show.url(), episode.season.number, episode.episode))
if 'delete_ban' in req.POST:
act = UserAction(user=user,show=show,act_type=4,url='%s/episode/%d/%d?submission=%d'%(show.url(), episode.season.number, episode.episode, submission.pk))
act.save()
submission.delete()
2018-03-02 13:46:25 +00:00
return HttpResponseRedirect('%s/create_ban?user=%s'%(show.url(),submission.user.username))
form = forms.SubmissionFormAdmin(req.POST, instance=submission)
ctx['form'] = form
if form.is_valid():
form_data = form.cleaned_data
form.save()
act = UserAction(user=user,show=show,act_type=3,url='%s/episode/%d/%d?submission=%d'%(show.url(), episode.season.number, episode.episode, submission.pk))
act.save()
2018-03-02 13:46:25 +00:00
return HttpResponseRedirect('%s/episode/%d/%d'%(show.url(), episode.season.number, episode.episode))
else:
ctx['error'] = 'Invalid fields!'
return render(req, "submit_mod.html", ctx)
# Season form GET and POST
2017-12-27 15:01:39 +00:00
@permission_required_or_403('LandingPage.can_moderate_show', (Show, 'abbr', 'abbr'), accept_global_perms=True)
def SeasonSubmitForm(req, abbr):
show = get_object_or_404(Show, abbr=abbr)
user = req.user
form = forms.SeasonForm()
# Request context
ctx = {
'form': form,
2018-03-02 13:46:25 +00:00
'show': show
}
# Handle POST
if req.method == 'POST':
form = forms.SeasonForm(req.POST)
ctx['form'] = form
if form.is_valid():
form_data = form.cleaned_data
# Check if the URL has already been submitted
if Season.objects.filter(show=show,number=form_data['number']).count() > 0:
ctx['error'] = 'This season has already been submitted!'
return render(req, "season_add.html", ctx)
new_season = form.save(commit=False)
new_season.show = show
new_season.save()
act = UserAction(user=user,show=show,act_type=0,url='%s#season-%d'%(show.url(), new_season.number))
act.save()
2018-03-02 13:46:25 +00:00
return HttpResponseRedirect(show.url())
else:
ctx['error'] = 'Invalid fields!'
return render(req, "season_add.html", ctx)
# Episode form GET and POST
2017-12-27 15:01:39 +00:00
@permission_required_or_403('LandingPage.can_moderate_show', (Show, 'abbr', 'abbr'), accept_global_perms=True)
def EpisodeSubmitForm(req, abbr, season):
show = get_object_or_404(Show, abbr=abbr)
season = get_object_or_404(Season, show=show,number=season)
user = req.user
form = forms.EpisodeForm()
# Request context
ctx = {
'form': form,
'season': season,
2018-03-02 13:46:25 +00:00
'show': show
}
# Handle POST
if req.method == 'POST':
form = forms.EpisodeForm(req.POST)
ctx['form'] = form
if form.is_valid():
form_data = form.cleaned_data
# Check if the URL has already been submitted
if Episode.objects.filter(show=show,episode=form_data['episode'],season=season).count() > 0:
ctx['error'] = 'This episode has already been submitted!'
return render(req, "episode_add.html", ctx)
new_episode = form.save(commit=False)
new_episode.show = show
new_episode.season = season
new_episode.save()
act = UserAction(user=user,show=show,act_type=0,url='%s/episode/%d/%d'%(show.url(), season.number, new_episode.episode))
act.save()
2018-03-02 13:46:25 +00:00
return HttpResponseRedirect(show.url())
else:
ctx['error'] = 'Invalid fields!'
return render(req, "episode_add.html", ctx)
# Vote request
# /show/{{abbr}}/vote/{{submission id}}/{{positive == 1}}
class SubmissionVoteSubmit(LoginRequiredMixin, View):
def post (self, req, abbr, subid, positive):
2017-11-11 09:26:26 +00:00
# Convert positive parameter into a boolean
pos_bool = int(positive) == 1
user = req.user
# Get the submission from the database
submission = get_object_or_404(Submission, id=subid)
# Prevent voting for own submission
if submission.user == user:
2017-11-11 10:41:41 +00:00
return HttpResponse('<h1>Error</h1><p>You cannot vote for your own submission.</p>', status=400)
2017-12-27 15:01:39 +00:00
show = submission.episode.show
# Get bans for this user regarding this show
bans = Ban.objects.filter(Q(scope=show) | Q(site_wide=True), Q(expiration__gte=datetime.datetime.now()) | Q(permanent=True), user=user)
if bans.count() > 0:
return HttpResponseForbidden('You are banned from voting on this show.<br>Reason: %s'%(bans.first().reason))
# Allow changing a vote from positive to negative or vice-versa. Delete vote if its a re-vote
vote = submission.votes.filter(user=user,submission__id=submission.id).first()
if vote:
2017-11-11 09:26:26 +00:00
if not vote.positive == pos_bool:
vote.positive = pos_bool
vote.save()
act = UserAction(user=user,show=show,act_type=6 + int(positive),url='%s/episode/%d/%d?submission=%d'%(show.url(),
submission.episode.season.number, submission.episode.episode, submission.pk))
act.save()
else:
vote.delete()
else:
new_vote = SubmissionVote(
user=user,
submission=submission,
2017-11-11 09:26:26 +00:00
positive=pos_bool
)
new_vote.save()
act = UserAction(user=user,show=show,act_type=6 + int(positive),url='%s/episode/%d/%d?submission=%d'%(show.url(),
submission.episode.season.number, submission.episode.episode, submission.pk))
act.save()
2018-03-02 13:46:25 +00:00
return HttpResponseRedirect('%s/episode/%d/%d'%(show.url(), submission.episode.season.number, submission.episode.episode))
2017-12-27 15:01:39 +00:00
# Episode form GET and POST
@permission_required_or_403('LandingPage.can_create_show_ban', (Show, 'abbr', 'abbr'), accept_global_perms=True)
def BanFromShowForm(req, abbr):
show = get_object_or_404(Show, abbr=abbr)
user = req.user
ban_target = get_object_or_404(User, username=req.GET.get('user', None))
2017-12-27 15:01:39 +00:00
if ban_target == user:
2017-12-27 15:01:39 +00:00
return HttpResponseForbidden('You cannot ban yourself!')
if ban_target.is_staff:
2017-12-27 15:01:39 +00:00
return HttpResponseForbidden('You cannot ban a staff member!')
if ban_target.has_perm('LandingPage.can_moderate_show', show):
2017-12-27 15:01:39 +00:00
return HttpResponseForbidden('You cannot ban another moderator!')
form = forms.BanForm()
# Request context
ctx = {
'form': form,
'show': show,
'target': ban_target
2017-12-27 15:01:39 +00:00
}
# Handle POST
if req.method == 'POST':
form = forms.BanForm(req.POST)
ctx['form'] = form
if form.is_valid():
form_data = form.cleaned_data
# Save
new_ban = form.save(commit=False)
if form_data['permanent']:
new_ban.expiration = datetime.datetime.now()
new_ban.site_wide = False
new_ban.user = ban_target
2017-12-27 15:01:39 +00:00
new_ban.admin = user
new_ban.save()
# Add show to scope
new_ban.scope.add(show)
act = UserAction(user=user,show=show,act_type=5,url='/community/user/%d-%s'%(ban_target.pk, slugify(ban_target.display_name)))
act.save()
# Delete all of the user's submissions for this show
if 'delete' in req.POST:
Submission.objects.filter(episode__show=show,user=ban_target).delete()
2018-03-02 13:46:25 +00:00
return HttpResponseRedirect(show.url())
2017-12-27 15:01:39 +00:00
else:
ctx['error'] = 'Invalid fields!'
return render(req, "create_ban.html", ctx)
2017-12-29 14:22:58 +00:00
@login_required
def ReportSubmission(req, abbr, submission):
show = get_object_or_404(Show, abbr=abbr)
submission = get_object_or_404(Submission, pk=submission,episode__show=show)
episode = submission.episode
user = req.user
form = forms.ReportForm()
# Get bans for this user regarding this show
bans = Ban.objects.filter(Q(expiration__gte=datetime.datetime.now()) | Q(permanent=True), user=user, site_wide=True)
if bans.count() > 0:
return HttpResponseForbidden('You are banned from the site and therefor not allowed to create reports.<br>Reason: %s'%(bans.first().reason))
# Request context
ctx = {
'form': form,
'show': show,
'episode': episode,
'submission': submission
2017-12-29 14:22:58 +00:00
}
2018-03-02 13:46:25 +00:00
url = '%s/episode/%d/%d?submission=%s'%(show.url(), episode.season.number, episode.episode, submission.pk)
2018-03-01 13:48:20 +00:00
2017-12-29 14:22:58 +00:00
# Handle POST
if req.method == 'POST':
form = forms.ReportForm(req.POST)
ctx['form'] = form
if form.is_valid():
form_data = form.cleaned_data
2018-03-01 13:48:20 +00:00
if not user.has_perm('LandingPage.can_moderate_show', show):
# Check if there have been many reports by this user within the last 12 hours
if Report.objects.filter(reporter=user,timestamp__gte=datetime.datetime.now() - datetime.timedelta(hours=12)).count() > 5:
2018-03-01 13:48:20 +00:00
ctx['error'] = 'You\'ve created too many reports recently!'
return render(req, "report_reply.html", ctx)
if Report.objects.filter(url=url).count() > 1:
ctx['error'] = 'This submission has already been brought to our attention! Thank you for reporting.'
return render(req, "report_reply.html", ctx)
2017-12-29 14:22:58 +00:00
# Save
new_report = form.save(commit=False)
new_report.reporter = user
2018-03-01 13:48:20 +00:00
new_report.url = url
2018-03-03 09:39:56 +00:00
new_report.show = show
2017-12-29 14:22:58 +00:00
new_report.save()
2018-03-02 13:46:25 +00:00
return HttpResponseRedirect('%s/episode/%d/%d'%(show.url(), episode.season.number, episode.episode))
2017-12-29 14:22:58 +00:00
else:
ctx['error'] = 'Invalid fields!'
return render(req, "report.html", ctx)
@permission_required_or_403('LandingPage.can_create_show_ban', (Show, 'abbr', 'abbr'), accept_global_perms=True)
def ModDashboard(req, abbr):
show = get_object_or_404(Show, abbr=abbr)
activity = UserAction.objects.filter(show=show).order_by("-timestamp")[:20]
reports = Report.objects.filter(show=show,resolved=False).order_by("-timestamp")
ctx = {}
ctx['actions'] = activity
ctx['reports'] = reports
ctx['show'] = show
return render(req, "mod_dash.html", ctx)
@permission_required_or_403('LandingPage.can_create_show_ban', (Show, 'abbr', 'abbr'), accept_global_perms=True)
def ModReport(req, abbr, repid):
show = get_object_or_404(Show, abbr=abbr)
report = get_object_or_404(Report, pk=repid)
user = req.user
ctx = {}
ctx['report'] = report
ctx['show'] = show
if req.method == 'POST':
if 'delete' in req.POST:
Report.objects.filter(pk=report.pk).delete()
return HttpResponseRedirect('%s/moderator'%(show.url()))
elif 'delete_ban' in req.POST:
Report.objects.filter(pk=report.pk).delete()
return HttpResponseRedirect('%s/create_ban?user=%s'%(show.url(),report.reporter.username))
else:
Report.objects.filter(pk=report.pk).update(read_at=datetime.datetime.now(),read_by=user,resolved=True)
return HttpResponseRedirect('%s/moderator'%(show.url()))
if not report.resolved:
Report.objects.filter(pk=report.pk).update(read_at=datetime.datetime.now(),read_by=user)
return render(req, "mod_report.html", ctx)