# Episodes.Community - Community-Driven TV Show Episode Link Sharing Site # Copyright (C) 2017 Evert "Diamond" Prants , Taizo "Tsa6" Simpson # # 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 . from django.template import RequestContext from django.shortcuts import render, get_list_or_404, get_object_or_404, redirect from django.views import View from django.views.generic.base import TemplateView from django.contrib.auth.decorators import login_required from django.conf import settings from django.utils.text import slugify 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 from guardian.decorators import permission_required_or_403 from LandingPage.models import User, Show, Season, Episode, Submission, SubmissionVote, Ban, Report, UserAction from . import forms import datetime # Create your views here. # Index page of a show class IndexView(TemplateView): template_name = "show.html" def get_context_data(self, abbr, **kwargs): 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 return ctx # Episodes page of a show class EpisodeView(TemplateView): template_name = "episode.html" def get_context_data(self, abbr, season, episode, **kwargs): ctx = super().get_context_data() 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) ctx['url'] = '%s/episode/%d/%d'%(show.url(), season_number, episode_number) elif episode_number > int(lastep.episode): season_number += 1 episode_number = 1 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) # 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') ).order_by('-pinned', '-score') # Add fields to context ctx['show'] = show ctx['episode'] = episode ctx['submissions'] = submissions 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 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) return HttpResponseRedirect('%s/episode/%d/%d?submission=%d'%(show.url(), episode.season.number, episode.episode, submission)) # 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 form = forms.SubmissionForm() # Request context ctx = { 'form': form, 'show': show, 'episode': episode } # 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.
Reason: %s'%(bans.first().reason)) # 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) 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) 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() return HttpResponseRedirect('%s/episode/%d/%d'%(show.url(), episode.season.number, episode.episode)) else: ctx['error'] = 'Invalid fields!' return render(req, "submit.html", ctx) # Edit a submission - for moderators @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, '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() 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() 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() 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 @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, '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() return HttpResponseRedirect(show.url()) else: ctx['error'] = 'Invalid fields!' return render(req, "season_add.html", ctx) # Episode form GET and POST @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, '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() 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): # 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: return HttpResponse('

Error

You cannot vote for your own submission.

', status=400) 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.
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: 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, 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() return HttpResponseRedirect('%s/episode/%d/%d'%(show.url(), submission.episode.season.number, submission.episode.episode)) # 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)) if ban_target == user: return HttpResponseForbidden('You cannot ban yourself!') if ban_target.is_staff: return HttpResponseForbidden('You cannot ban a staff member!') if ban_target.has_perm('LandingPage.can_moderate_show', show): return HttpResponseForbidden('You cannot ban another moderator!') form = forms.BanForm() # Request context ctx = { 'form': form, 'show': show, 'target': ban_target } # 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 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() return HttpResponseRedirect(show.url()) else: ctx['error'] = 'Invalid fields!' return render(req, "create_ban.html", ctx) @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.
Reason: %s'%(bans.first().reason)) # Request context ctx = { 'form': form, 'show': show, 'episode': episode, 'submission': submission } url = '%s/episode/%d/%d?submission=%s'%(show.url(), episode.season.number, episode.episode, submission.pk) # Handle POST if req.method == 'POST': form = forms.ReportForm(req.POST) ctx['form'] = form if form.is_valid(): form_data = form.cleaned_data 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: 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) # Save new_report = form.save(commit=False) new_report.reporter = user new_report.url = url new_report.show = show new_report.save() return HttpResponseRedirect('%s/episode/%d/%d'%(show.url(), episode.season.number, episode.episode)) 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)