diff options
author | Akshen | 2019-03-19 13:43:58 +0530 |
---|---|---|
committer | Akshen | 2019-03-19 13:43:58 +0530 |
commit | a7844e4135f1452b5156561882e4ccb754ac1dd3 (patch) | |
tree | f730a784fa498f798662e7148087db1f77883077 /fossee_manim | |
parent | efda4b675ab162346a72abf0ceee29cfc0f99001 (diff) | |
download | FOSSEE_animations-a7844e4135f1452b5156561882e4ccb754ac1dd3.tar.gz FOSSEE_animations-a7844e4135f1452b5156561882e4ccb754ac1dd3.tar.bz2 FOSSEE_animations-a7844e4135f1452b5156561882e4ccb754ac1dd3.zip |
Major Update 2
- Contributor can add animation videos
Diffstat (limited to 'fossee_manim')
-rw-r--r-- | fossee_manim/forms.py | 19 | ||||
-rw-r--r-- | fossee_manim/models.py | 35 | ||||
-rw-r--r-- | fossee_manim/send_mails.py | 31 | ||||
-rw-r--r-- | fossee_manim/templates/fossee_manim/categorical_list.html | 28 | ||||
-rw-r--r-- | fossee_manim/templates/fossee_manim/edit_proposal.html | 12 | ||||
-rw-r--r-- | fossee_manim/templates/fossee_manim/upload_success.html | 29 | ||||
-rw-r--r-- | fossee_manim/templates/fossee_manim/video.html | 24 | ||||
-rw-r--r-- | fossee_manim/urls.py | 17 | ||||
-rw-r--r-- | fossee_manim/views.py | 142 |
9 files changed, 277 insertions, 60 deletions
diff --git a/fossee_manim/forms.py b/fossee_manim/forms.py index ec7568d..b3b33eb 100644 --- a/fossee_manim/forms.py +++ b/fossee_manim/forms.py @@ -2,7 +2,7 @@ from django import forms from django.utils import timezone from .models import ( Profile, User, Animation, - Comment + Comment, AnimationStats ) from string import punctuation, digits try: @@ -253,7 +253,6 @@ class AnimationProposal(forms.ModelForm): class CommentForm(forms.ModelForm): """ - Instructors will post comments on Coordinators profile """ def __init__(self, *args, **kwargs): @@ -267,4 +266,18 @@ class CommentForm(forms.ModelForm): exclude = ['animation', 'created_date', 'commentor'] widgets = { 'comments': forms.CharField(), - }
\ No newline at end of file + } + + +class UploadAnimationForm(forms.ModelForm): + + def __init__(self, *args, **kwargs): + super(UploadAnimationForm, self).__init__(*args, **kwargs) + self.fields['video_path'].label = "Animation" + + class Meta: + model = AnimationStats + exclude = ['animation', 'views', 'like', 'dislike', 'thumbnail'] + widgets = { + 'video_path': forms.FileInput(), + } diff --git a/fossee_manim/models.py b/fossee_manim/models.py index 77c7552..75f03da 100644 --- a/fossee_manim/models.py +++ b/fossee_manim/models.py @@ -1,9 +1,14 @@ from django.db import models from django.contrib.auth.models import User from django.core.validators import RegexValidator +from django.conf import settings +from django.utils import timezone +from django.core.files import File from taggit.managers import TaggableManager from simple_history.models import HistoricalRecords -from django.utils import timezone +from os import path, sep +import tempfile +import subprocess position_choices = ( @@ -96,6 +101,12 @@ def has_profile(user): return True if hasattr(user, 'profile') else False +def attachments(instance, filename): + return path.join(instance.animation.category.name, + instance.animation.title, + str(instance.animation.id), filename) + + class Profile(models.Model): """Profile for users(instructors and coordinators)""" @@ -156,7 +167,6 @@ class Animation(models.Model): github = models.TextField() category = models.ForeignKey(Category, on_delete=models.CASCADE) created = models.DateTimeField(default=timezone.now) - updated = models.DateTimeField(default=timezone.now) tags = TaggableManager() history = HistoricalRecords() @@ -181,4 +191,23 @@ class AnimationStats(models.Model): animation = models.ForeignKey(Animation, on_delete=models.CASCADE) views = models.PositiveIntegerField(default=0) like = models.PositiveIntegerField(default=0) - dislike = models.PositiveIntegerField(default=0)
\ No newline at end of file + dislike = models.PositiveIntegerField(default=0) + thumbnail = models.ImageField(null=True, blank=True, upload_to=attachments) + video_path = models.FileField(null=True, blank=True, upload_to=attachments) + + def _create_thumbnail(self): + # anime = AnimationStats.objects.get( + # animation=proposal) + video_path = self.video_path.path + img_output = path.join( + tempfile.mkdtemp(), "{0}.jpg".format(self.animation.title) + ) + file_name = "{0}.jpg".format(self.animation.title) + subprocess.call(['ffmpeg', '-i', video_path, '-ss', '00:00:09.000', + '-vframes', '1', img_output]) + if path.exists(img_output): + que_file = open(img_output, 'rb') + # Converting to Python file object with + # some Django-specific additions + django_file = File(que_file) + self.thumbnail.save(file_name, django_file, save=True) diff --git a/fossee_manim/send_mails.py b/fossee_manim/send_mails.py index f9f7a75..a329e8b 100644 --- a/fossee_manim/send_mails.py +++ b/fossee_manim/send_mails.py @@ -1,20 +1,19 @@ -from django.core.mail import EmailMultiAlternatives +from django.core.mail import EmailMultiAlternatives, send_mail from django.conf import settings +from django.utils.crypto import get_random_string from os import listdir, path from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.base import MIMEBase from email import encoders from time import sleep -import hashlib -import logging.config -import re -from django.core.mail import send_mail from textwrap import dedent from random import randint from smtplib import SMTP -from django.utils.crypto import get_random_string from string import punctuation, digits +from hashlib import sha256 +import logging.config +import re try: from string import letters except ImportError: @@ -29,13 +28,15 @@ from fossee_anime.settings import ( SENDER_EMAIL, ADMIN_EMAIL ) + + __author__ = "Akshen Doke" def validateEmail(email): if len(email) > 7: if re.match("^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,3}|[0-9]{1,3})(\\]?)$", - email) != None: + email) is not None: return 1 return 0 @@ -43,8 +44,8 @@ def validateEmail(email): def generate_activation_key(username): """Generates hashed secret key for email activation""" chars = letters + digits + punctuation - secret_key = get_random_string(randint(10,40), chars) - return hashlib.sha256((secret_key + username).encode('utf-8')).hexdigest() + secret_key = get_random_string(randint(10, 40), chars) + return sha256((secret_key + username).encode('utf-8')).hexdigest() def send_email(request, call_on, contributor=None, key=None, proposal=None): @@ -53,7 +54,7 @@ def send_email(request, call_on, contributor=None, key=None, proposal=None): try: with open(path.join(settings.LOG_FOLDER, - 'emailconfig.yaml'), 'r') as configfile: + 'emailconfig.yaml'), 'r') as configfile: config_dict = yaml.load(configfile) logging.config.dictConfig(config_dict) except: @@ -87,7 +88,8 @@ def send_email(request, call_on, contributor=None, key=None, proposal=None): Congratulations! your animations has been released on FOSSEE's website. - Please start with your honouriam process + Your animation will be live in 72 working hours. + Please start with your honorarium process In case of queries, please revert to this email.""".format(contributor.profile.user.username)) @@ -112,7 +114,7 @@ def send_email(request, call_on, contributor=None, key=None, proposal=None): logging.info("Animation Rejected: %s", request.user.email) send_mail( "FOSSEE Animation Status Update", message, SENDER_EMAIL, - [contributor.profile.user.email], fail_silently=True + [contributor.profile.user.email], fail_silently=True ) elif call_on == 'changes': message = dedent("""\ @@ -123,10 +125,9 @@ def send_email(request, call_on, contributor=None, key=None, proposal=None): In case of queries, please revert to this email.""".format(contributor.profile.user.username, - proposal.title)) + proposal.title)) logging.info("Changes Required: %s", request.user.email) send_mail( "FOSSEE Animation Changes required", message, SENDER_EMAIL, - [contributor.profile.user.email], fail_silently=True - )
\ No newline at end of file + [contributor.profile.user.email], fail_silently=True) diff --git a/fossee_manim/templates/fossee_manim/categorical_list.html b/fossee_manim/templates/fossee_manim/categorical_list.html new file mode 100644 index 0000000..a61ab40 --- /dev/null +++ b/fossee_manim/templates/fossee_manim/categorical_list.html @@ -0,0 +1,28 @@ +{% extends 'fossee_manim/base.html' %} + + {% block title %} + FOSSEE Animation + {% endblock %} + +{% block content %} + <br> + <div class="container" align="center"> + <br> + <div class="row"> + <div class="col-md-12"> + <h1 style="float: left;">{{ categorial_list.0.animation.category }}</h1> + </div> + </div> + <hr> + <br> + <div style="width:150px; float: left;"> + {% for video in categorial_list %} + <div class="row"> + <a href="{% url 'video' video.id %}" ><img height="100%" width="200%" src="{{ video.thumbnail.url }}"></a> + </div> + <hr> + {% endfor %} + </div> + <br> + </div> +{% endblock %}
\ No newline at end of file diff --git a/fossee_manim/templates/fossee_manim/edit_proposal.html b/fossee_manim/templates/fossee_manim/edit_proposal.html index c73071b..3edad99 100644 --- a/fossee_manim/templates/fossee_manim/edit_proposal.html +++ b/fossee_manim/templates/fossee_manim/edit_proposal.html @@ -19,7 +19,19 @@ <br> <button class="btn btn-primary pull-right" type="submit">Save</button> + <br> + </form> + <br> + + {% if proposal_form.instance.status == 'changes' %} + <form method="POST" action="{% url 'upload_animation' proposal_form.instance.id %}" enctype="multipart/form-data"> + {% csrf_token %} + <label class="btn btn-info"> + {{ upload_form }} + <button class="btn btn-success" type="submit">Upload</button> + </label> </form> + {% endif %} <br><br> {% if request.user.profile.position == 'reviewer' %} diff --git a/fossee_manim/templates/fossee_manim/upload_success.html b/fossee_manim/templates/fossee_manim/upload_success.html new file mode 100644 index 0000000..61a992a --- /dev/null +++ b/fossee_manim/templates/fossee_manim/upload_success.html @@ -0,0 +1,29 @@ + +{% extends 'fossee_manim/base.html' %} + +{% block title %} + Upload success +{% endblock %} + + + {% block extra %} + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> + <script src="{{URL_ROOT}}/static/fossee_manim/js/bootstrap-3.3.7.min.js"></script> + <script type="text/javascript"> + window.setTimeout(function() + { + location.href="{% url 'proposal_status' %}" + }, 9000); +</script> + + {% endblock %} +{% block content %} + <div class="container"> + <br><br> + <div class="jumbotron"> + <h3><strong>Congrats!</strong> video uploaded successfully!</h3> + <br> + <h5><strong>If you've previously uploaded any video, it would be overridden by this upload</h5> + </div> + </div> +{% endblock %}
\ No newline at end of file diff --git a/fossee_manim/templates/fossee_manim/video.html b/fossee_manim/templates/fossee_manim/video.html new file mode 100644 index 0000000..ff020e5 --- /dev/null +++ b/fossee_manim/templates/fossee_manim/video.html @@ -0,0 +1,24 @@ +{% extends 'fossee_manim/base.html' %} + + {% block title %} + FOSSEE Animation + {% endblock %} + +{% block content %} + <br> + <div class="container" align="center"> + <br> + <div class="row" > + <div class="col-md-8"> + <video width="100%" height="100%" controls> + <source src="{{video.0.video_path.url}}" type="video/mp4"> + </video> + <p style="float: left;"> {{ video.0.views }} views</p> + </div> + <div class="col-md-4"> + </div> + + </div> + <br> + </div> +{% endblock %}
\ No newline at end of file diff --git a/fossee_manim/urls.py b/fossee_manim/urls.py index 7bc7740..278dee2 100644 --- a/fossee_manim/urls.py +++ b/fossee_manim/urls.py @@ -1,5 +1,8 @@ from django.conf.urls import url from fossee_manim import views +from django.conf import settings +from django.conf.urls.static import static + urlpatterns = [ url(r'^$', views.index, name='index'), @@ -11,8 +14,18 @@ urlpatterns = [ url(r'^send_proposal/$', views.send_proposal, name='send_proposal'), url(r'^edit_proposal/([1-9][0-9]*)$', views.edit_proposal, name='edit_proposal'), + url(r'^upload_animation/([1-9][0-9]*)$', views.upload_animation, + name='upload_animation'), url(r'^proposal_status/$', views.proposal_status, name='proposal_status'), url(r'^search/$', views.search, name='search'), url(r'^view_profile/$', views.view_profile, name='view_profile'), - url(r'^edit_profile/$', views.edit_profile, name='edit_profile') -]
\ No newline at end of file + url(r'^edit_profile/$', views.edit_profile, name='edit_profile'), + url(r'^video/([1-9][0-9]*)$', views.video, name='video'), + url(r'^search_category/(?P<cat>.+)$', views.search_category, + name='search_category') +] + +urlpatterns += static( + settings.MEDIA_URL, + document_root=settings.MEDIA_ROOT +) diff --git a/fossee_manim/views.py b/fossee_manim/views.py index d9b27b2..58cc794 100644 --- a/fossee_manim/views.py +++ b/fossee_manim/views.py @@ -1,12 +1,13 @@ -from django.shortcuts import render +from os import listdir, path, sep, makedirs, remove from .forms import ( UserRegistrationForm, UserLoginForm, - ProfileForm, AnimationProposal, - CommentForm + ProfileForm, AnimationProposal, + CommentForm, UploadAnimationForm ) from .models import ( Profile, User, AnimationStats, - has_profile, Animation, Comment + has_profile, Animation, Comment, + Category ) from datetime import datetime, date from django.contrib.auth import login, logout, authenticate @@ -15,24 +16,42 @@ from django.contrib import messages from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.shortcuts import render, redirect from django.utils import timezone -from .send_mails import send_email from django.http import HttpResponse, HttpResponseRedirect -from textwrap import dedent from django.conf import settings -from os import listdir, path, sep -from zipfile import ZipFile +from django.core.files.uploadhandler import FileUploadHandler from django.contrib import messages -from django.db.models import Q +from django.db.models import F, Subquery, OuterRef +from zipfile import ZipFile +from textwrap import dedent +from requests import get +from .send_mails import send_email import datetime as dt -import os +import shutil try: from StringIO import StringIO as string_io except ImportError: from io import BytesIO as string_io +def makepath(proposal_data, reject=None): + if not path.exists(path.join(settings.MEDIA_ROOT, + proposal_data.category.name)): + makedirs(path.join(settings.MEDIA_ROOT, + proposal_data.category.name)) + + if reject: + shutil.rmtree(path.join( + settings.MEDIA_ROOT, proposal_data.category.name, + proposal_data.title.replace(" ", "_") + + str(proposal_data.id))) + else: + makedirs(path.join(settings.MEDIA_ROOT, proposal_data.category.name, + proposal_data.title.replace(" ", "_") + + str(proposal_data.id))) + + def check_repo(link): - return True if 'github.com' in link else False + return (get(link).status_code == 200) def is_email_checked(user): @@ -43,7 +62,7 @@ def is_email_checked(user): def is_superuser(user): - return True if user.is_superuser else False + return user.is_superuser def index(request): @@ -52,8 +71,8 @@ def index(request): user = request.user form = UserLoginForm() if user.is_authenticated() and is_email_checked(user): - if user.groups.filter(name='reviewer').count() > 0: - return redirect('/view_profile/') + if user.groups.filter(name='reviewer').exists: + return redirect('/proposal_status/') return redirect('/view_profile/') elif request.method == "POST": form = UserLoginForm(request.POST) @@ -62,8 +81,8 @@ def index(request): login(request, user) if is_superuser(user): return redirect("/admin") - if user.groups.filter(name='reviewer').count() > 0: - return redirect('/view_profile/') + if user.groups.filter(name='reviewer').exists(): + return redirect('/proposal_status/') return redirect('/view_profile/') return render(request, "fossee_manim/index.html", {"form": form}) @@ -71,7 +90,7 @@ def index(request): def is_reviewer(user): '''Check if the user is having reviewer rights''' - return True if user.groups.filter(name='reviewer').count() > 0 else False + return user.groups.filter(name='reviewer').exists() def user_login(request): @@ -248,14 +267,15 @@ def send_proposal(request): if form.is_valid(): form_data = form.save(commit=False) form_data.contributor = user - form_data.status = "pending" + form_data.status = "pending" if check_repo(form_data.github): form_data.save() form.save_m2m() + # makepath(form_data) else: messages.warning(request, 'Please enter valid github details') return render(request, 'fossee_manim/send_proposal.html', - {'form': form}) + {'form': form}) return redirect('/proposal_status/') else: form = AnimationProposal() @@ -272,8 +292,7 @@ def proposal_status(request): if profile.position == 'contributor': anime = Animation.objects.filter(contributor_id=user) else: - anime_list = Animation.objects.filter(Q(status='pending') | - Q(status='changes')) + anime_list = Animation.objects.order_by('-created') return render(request, 'fossee_manim/proposal_status.html', {'anime': anime, 'anime_list': anime_list}) @@ -284,28 +303,30 @@ def edit_proposal(request, proposal_id=None): comment_form = CommentForm() proposal = Animation.objects.get(id=proposal_id) proposal_form = AnimationProposal(instance=proposal) + upload_form = UploadAnimationForm() try: - comments = Comment.objects.all().order_by('-created_date') + comments = Comment.objects.filter(animation_id=proposal_id).order_by( + '-created_date' + ) except: comments = None if request.method == 'POST': text = request.POST.get('comment') - s1 = request.POST.get('release') - s2 = request.POST.get('rejected') + status1 = request.POST.get('release') + status2 = request.POST.get('rejected') - if s1 or s2 is not None: - if s1: + if status1 or status2 is not None: + if status1: proposal.status = 'released' - proposal.reviewer = user - proposal.save() send_email(request, call_on='released', - contributor=proposal.contributor) + contributor=proposal.contributor) else: proposal.status = 'rejected' - proposal.reviewer = user - proposal.save() + makepath(proposal, reject=1) send_email(request, call_on='rejected', - contributor=proposal.contributor) + contributor=proposal.contributor) + proposal.reviewer = user + proposal.save() return redirect('/proposal_status/') if text is not None: @@ -315,9 +336,10 @@ def edit_proposal(request, proposal_id=None): form_data.animation = proposal if user.profile.position == 'reviewer': proposal.status = 'changes' + proposal.save() send_email(request, call_on='changes', - contributor=proposal.contributor, - proposal=proposal) + contributor=proposal.contributor, + proposal=proposal) form_data.save() return redirect('/edit_proposal/{}'.format(proposal_id)) proposal_form = AnimationProposal(request.POST, instance=proposal) @@ -345,13 +367,59 @@ def edit_proposal(request, proposal_id=None): comments = paginator.page(paginator.num_pages) return render(request, 'fossee_manim/edit_proposal.html', {'proposal_form': proposal_form, - "comments": comments, - "comment_form": comment_form}) + "comments": comments, + "comment_form": comment_form, + "upload_form": upload_form}) def search(request): if request.method == 'POST': word = request.POST.get('sbox') - return render(request, 'fossee_manim/search_results.html') + +@login_required +def upload_animation(request, proposal_id=None): + if request.method == 'POST': + proposal = Animation.objects.get(id=proposal_id) + anim_stats = UploadAnimationForm(request.POST or None, + request.FILES or None) + + # return redirect('/edit_proposal/{}'.format(proposal_id)) + if anim_stats.is_valid(): + anim = AnimationStats.objects.filter( + animation=proposal) + if anim.exists(): + anobj = anim.first() + try: + remove(anobj.thumbnail.path) + except: + pass + remove(anobj.video_path.path) + anobj.delete() + anobj = AnimationStats.objects.create( + animation=proposal, video_path=request.FILES['video_path']) + else: + anobj = AnimationStats.objects.create( + animation=proposal, video_path=request.FILES['video_path']) + anobj._create_thumbnail() + return render(request, 'fossee_manim/upload_success.html') + else: + return redirect('/view_profile/') + + +def video(request, id=None): + video = AnimationStats.objects.filter(id=id) + # if views crosses limit comment the line below + video.update(views=F('views')+1) + video.update(like=F('like')+1) + suggestion_list = AnimationStats.objects.filter() + return render(request, 'fossee_manim/video.html', {'video': video}) + + +def search_category(request, cat=None): + cat_id = Category.objects.get(name=cat) + anim_list = AnimationStats.objects.all() + cat_video_list = [x for x in anim_list if (x.animation.category == cat_id)] + return render(request, 'fossee_manim/categorical_list.html', + {'categorial_list': cat_video_list}) |