diff options
author | Akshen | 2019-03-05 11:33:41 +0530 |
---|---|---|
committer | Akshen | 2019-03-05 11:33:41 +0530 |
commit | efda4b675ab162346a72abf0ceee29cfc0f99001 (patch) | |
tree | 72b1f971823ecb1aed88ce793c69921f66e4291e | |
parent | eed46efdccfb2821cb07b6a189f439ba6f7bb3f2 (diff) | |
download | FOSSEE_animations-efda4b675ab162346a72abf0ceee29cfc0f99001.tar.gz FOSSEE_animations-efda4b675ab162346a72abf0ceee29cfc0f99001.tar.bz2 FOSSEE_animations-efda4b675ab162346a72abf0ceee29cfc0f99001.zip |
Major Update 1
- User can register/login/logout
- Contributor can send proposal and comment on it
- Reviewer can comment/approve/reject proposals
-rw-r--r-- | fossee_anime/settings.py | 8 | ||||
-rw-r--r-- | fossee_manim/admin.py | 18 | ||||
-rw-r--r-- | fossee_manim/forms.py | 83 | ||||
-rw-r--r-- | fossee_manim/models.py | 84 | ||||
-rw-r--r-- | fossee_manim/send_mails.py | 83 | ||||
-rw-r--r-- | fossee_manim/templates/fossee_manim/base.html | 34 | ||||
-rw-r--r-- | fossee_manim/templates/fossee_manim/edit_proposal.html | 97 | ||||
-rw-r--r-- | fossee_manim/templates/fossee_manim/proposal_status.html | 53 | ||||
-rw-r--r-- | fossee_manim/templates/fossee_manim/search_results.html | 13 | ||||
-rw-r--r-- | fossee_manim/templates/fossee_manim/send_proposal.html | 41 | ||||
-rw-r--r-- | fossee_manim/templates/password_reset_confirm.html | 15 | ||||
-rw-r--r-- | fossee_manim/urls.py | 15 | ||||
-rw-r--r-- | fossee_manim/views.py | 142 | ||||
-rw-r--r-- | requirements.txt | 2 |
14 files changed, 585 insertions, 103 deletions
diff --git a/fossee_anime/settings.py b/fossee_anime/settings.py index c448124..53b200b 100644 --- a/fossee_anime/settings.py +++ b/fossee_anime/settings.py @@ -18,7 +18,8 @@ from local_settings import ( EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, EMAIL_USE_TLS, - SENDER_EMAIL + SENDER_EMAIL, + SECRET_KEY_SETTINGS ) # Build paths inside the project like this: os.path.join(BASE_DIR, ...) @@ -29,7 +30,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'axx=vuttrki_26n0l!cx569(h_ze)981u+9_@mw35^^b!l5g)y' +SECRET_KEY = SECRET_KEY_SETTINGS # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -47,6 +48,8 @@ INSTALLED_APPS = [ 'django.contrib.messages', 'django.contrib.staticfiles', 'fossee_manim', + 'taggit', + 'simple_history' ] MIDDLEWARE_CLASSES = [ @@ -58,6 +61,7 @@ MIDDLEWARE_CLASSES = [ 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'simple_history.middleware.HistoryRequestMiddleware', ] ROOT_URLCONF = 'fossee_anime.urls' diff --git a/fossee_manim/admin.py b/fossee_manim/admin.py index f076a3c..35bf57b 100644 --- a/fossee_manim/admin.py +++ b/fossee_manim/admin.py @@ -1,16 +1,16 @@ from django.contrib import admin import csv from django.http import HttpResponse -from .models import ( - Profile - ) +from .models import (Category, Profile, User, Animation, Comment, + AnimationStats) # Register your models here. try: - from StringIO import StringIO as string_io + from StringIO import StringIO as string_io except ImportError: - from io import BytesIO as string_io + from io import BytesIO as string_io -#Custom Classes + +# Custom Classes class ProfileAdmin(admin.ModelAdmin): list_display = ['title','user', 'institute','location','department', 'phone_number','position'] @@ -41,6 +41,10 @@ class ProfileAdmin(admin.ModelAdmin): download_csv.short_description = "Download CSV file for selected stats." +class CategoryAdmin(admin.ModelAdmin): + list_display = ['name', 'created', 'description'] + list_filter = ['name'] -admin.site.register(Profile, ProfileAdmin) +admin.site.register(Category, CategoryAdmin) +admin.site.register(Profile, ProfileAdmin)
\ No newline at end of file diff --git a/fossee_manim/forms.py b/fossee_manim/forms.py index 177e01f..ec7568d 100644 --- a/fossee_manim/forms.py +++ b/fossee_manim/forms.py @@ -1,7 +1,8 @@ from django import forms from django.utils import timezone from .models import ( - Profile, User + Profile, User, Animation, + Comment ) from string import punctuation, digits try: @@ -13,7 +14,6 @@ from django.contrib.auth.models import User from django.contrib.auth import authenticate from .send_mails import generate_activation_key - UNAME_CHARS = letters + "._" + digits PWD_CHARS = letters + punctuation + digits @@ -63,8 +63,8 @@ states = ( ("IN-AS", "Assam"), ("IN-BR", "Bihar"), ("IN-CT", "Chhattisgarh"), - ("IN-GA", "Goa"), - ("IN-GJ", "Gujarat"), + ("IN-GA", "Goa"), + ("IN-GJ", "Gujarat"), ("IN-HR", "Haryana"), ("IN-HP", "Himachal Pradesh"), ("IN-JK", "Jammu and Kashmir"), @@ -87,7 +87,7 @@ states = ( ("IN-UT", "Uttarakhand"), ("IN-UP", "Uttar Pradesh"), ("IN-WB", "West Bengal"), - ("IN-AN", "Andaman and Nicobar Islands"), + ("IN-AN", "Andaman and Nicobar Islands"), ("IN-CH", "Chandigarh"), ("IN-DN", "Dadra and Nagar Haveli"), ("IN-DD", "Daman and Diu"), @@ -107,19 +107,22 @@ class UserRegistrationForm(forms.Form): period and underscore only.''') email = forms.EmailField() password = forms.CharField(max_length=32, widget=forms.PasswordInput()) - confirm_password = forms.CharField\ - (max_length=32, widget=forms.PasswordInput()) + confirm_password = forms.CharField( + max_length=32, widget=forms.PasswordInput()) title = forms.ChoiceField(choices=title) first_name = forms.CharField(max_length=32) last_name = forms.CharField(max_length=32) - phone_number = forms.RegexField(regex=r'^.{10}$', - error_messages={'invalid':"Phone number must be entered \ - in the format: '9999999999'.\ - Up to 10 digits allowed."}) - institute = forms.CharField(max_length=128, - help_text='Please write full name of your Institute/Organization') + phone_number = forms.RegexField(regex=r'^.{10}$', + error_messages={'invalid': "Phone number\ + must be entered \ + in the format: '9999999999'.\ + Up to 10 digits allowed."}) + institute = forms.CharField(max_length=128, + help_text='Please write full name of your\ + Institute/Organization' + ) department = forms.ChoiceField(help_text='Department you work/study', - choices=department_choices) + choices=department_choices) location = forms.CharField(max_length=255, help_text="Place/City") state = forms.ChoiceField(choices=states) how_did_you_hear_about_us = forms.ChoiceField(choices=source) @@ -176,10 +179,11 @@ class UserRegistrationForm(forms.Form): new_profile.location = cleaned_data["location"] new_profile.title = cleaned_data["title"] new_profile.state = cleaned_data["state"] - new_profile.how_did_you_hear_about_us = cleaned_data["how_did_you_hear_about_us" ] + new_profile.how_did_you_hear_about_us = cleaned_data + ["how_did_you_hear_about_us"] new_profile.activation_key = generate_activation_key(new_user.username) - new_profile.key_expiry_time = timezone.now() + \ - timezone.timedelta(days=1) + new_profile.key_expiry_time = timezone.now() + timezone.timedelta( + days=1) new_profile.save() key = Profile.objects.get(user=new_user).activation_key return u_name, pwd, key @@ -189,10 +193,10 @@ class UserLoginForm(forms.Form): """Creates a form which will allow the user to log into the system.""" username = forms.CharField(max_length=32, - widget=forms.TextInput()) + widget=forms.TextInput()) password = forms.CharField(max_length=32, - widget=forms.PasswordInput()) + widget=forms.PasswordInput()) def clean(self): super(UserLoginForm, self).clean() @@ -224,4 +228,43 @@ class ProfileForm(forms.ModelForm): user = kwargs.pop('user') super(ProfileForm, self).__init__(*args, **kwargs) self.fields['first_name'].initial = user.first_name - self.fields['last_name'].initial = user.last_name
\ No newline at end of file + self.fields['last_name'].initial = user.last_name + + +class AnimationProposal(forms.ModelForm): + """Animation form """ + required_css_class = 'required' + errorlist_css_class = 'errorlist' + + def __init__(self, *args, **kwargs): + super(AnimationProposal, self).__init__(*args, **kwargs) + self.fields['github'].widget.attrs['rows'] = 1 + self.fields['github'].widget.attrs['cols'] = 50 + self.fields['github'].widget.attrs['placeholder'] = 'Put your repo\ + link here' + self.fields['description'].widget.attrs['placeholder'] = 'NOTE:-Do\ + add info about prerequisites if any also possible textbooks or \ + other related information' + + class Meta: + model = Animation + fields = ['category', 'title', 'description', 'github', 'tags'] + + +class CommentForm(forms.ModelForm): + """ + Instructors will post comments on Coordinators profile + """ + + def __init__(self, *args, **kwargs): + super(CommentForm, self).__init__(*args, **kwargs) + self.fields['comment'].label = "" + self.fields['comment'].widget.attrs['rows'] = 5 + self.fields['comment'].widget.attrs['cols'] = 95 + + class Meta: + model = Comment + exclude = ['animation', 'created_date', 'commentor'] + widgets = { + 'comments': forms.CharField(), + }
\ No newline at end of file diff --git a/fossee_manim/models.py b/fossee_manim/models.py index dd3f6b3..77c7552 100644 --- a/fossee_manim/models.py +++ b/fossee_manim/models.py @@ -1,12 +1,16 @@ from django.db import models from django.contrib.auth.models import User from django.core.validators import RegexValidator +from taggit.managers import TaggableManager +from simple_history.models import HistoricalRecords +from django.utils import timezone + position_choices = ( ("contributor", "Contributor"), ("reviewer", "Reviewer") ) - + department_choices = ( ("computer engineering", "Computer Science"), ("information technology", "Information Technology"), @@ -79,6 +83,14 @@ states = ( ("IN-PY", "Puducherry") ) +status = ( + ("pending", "Pending Acceptance"), + ("rejected", "Rejected"), + ("changes", "Changes Required"), + ("released", "Released") +) + + def has_profile(user): """ check if user has profile """ return True if hasattr(user, 'profile') else False @@ -88,23 +100,30 @@ class Profile(models.Model): """Profile for users(instructors and coordinators)""" user = models.OneToOneField(User) - title = models.CharField(max_length=32,blank=True, choices=title) - institute = models.CharField(max_length=150) + title = models.CharField(max_length=32, blank=True, choices=title) + institute = models.CharField(max_length=150, blank=True) department = models.CharField(max_length=150, choices=department_choices) phone_number = models.CharField( max_length=10, validators=[RegexValidator( regex=r'^.{10}$', message=( - "Phone number must be entered \ + "Phone number must be entered \ in the format: '9999999999'.\ Up to 10 digits allowed.") - )] - ,null=False) + )], null=False) position = models.CharField(max_length=32, choices=position_choices, - default='contributor') - how_did_you_hear_about_us = models.CharField(max_length=255, blank=True,choices=source) - location = models.CharField(max_length=255,blank=True, help_text="Place/City") + default='contributor') + how_did_you_hear_about_us = models.CharField(max_length=255, blank=True, + choices=source) + location = models.CharField(max_length=255, blank=True, + help_text="Place/City") state = models.CharField(max_length=255, choices=states, default="IN-MH") + pincode = models.CharField(max_length=6, blank=True, + validators=[RegexValidator( + regex=r'^.{6}$', message=( + "Please enter valid PINCODE" + ) + )]) is_email_verified = models.BooleanField(default=False) activation_key = models.CharField(max_length=255, blank=True, null=True) key_expiry_time = models.DateTimeField(blank=True, null=True) @@ -116,3 +135,50 @@ class Profile(models.Model): self.user.last_name, self.user.email ) + + +class Category(models.Model): + name = models.CharField(max_length=255, unique=True) + created = models.DateTimeField(default=timezone.now) + description = models.TextField() + + def __str__(self): + return u"{0}".format(self.name) + + +class Animation(models.Model): + title = models.CharField(max_length=255) + contributor = models.ForeignKey(User, on_delete=models.CASCADE) + reviewer = models.ForeignKey(User, null=True, on_delete=models.CASCADE, + related_name="%(app_label)s_%(class)s_related") + description = models.TextField() + status = models.CharField(max_length=255, choices=status) + 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() + + def __str__(self): + return u"{0} | {1}".format(self.title, self.status) + + +class Comment(models.Model): + comment = models.TextField() + commentor = models.ForeignKey(User, on_delete=models.CASCADE) + animation = models.ForeignKey(Animation, on_delete=models.CASCADE) + created_date = models.DateTimeField(default=timezone.now) + + def __str__(self): + return u"{1} | {0}".format( + self.created_date, + self.commentor + ) + + +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 diff --git a/fossee_manim/send_mails.py b/fossee_manim/send_mails.py index b2bf80d..f9f7a75 100644 --- a/fossee_manim/send_mails.py +++ b/fossee_manim/send_mails.py @@ -1,5 +1,11 @@ -__author__ = "Akshen Doke" - +from django.core.mail import EmailMultiAlternatives +from django.conf import settings +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 @@ -23,14 +29,7 @@ from fossee_anime.settings import ( SENDER_EMAIL, ADMIN_EMAIL ) -from django.core.mail import EmailMultiAlternatives -from django.conf import settings -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 +__author__ = "Akshen Doke" def validateEmail(email): @@ -48,15 +47,13 @@ def generate_activation_key(username): return hashlib.sha256((secret_key + username).encode('utf-8')).hexdigest() - -def send_email(request, call_on, - user_name=None, other_email=None, - institute=None, key=None - ): +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: + with open(path.join(settings.LOG_FOLDER, + 'emailconfig.yaml'), 'r') as configfile: config_dict = yaml.load(configfile) logging.config.dictConfig(config_dict) except: @@ -76,12 +73,60 @@ def send_email(request, call_on, logging.info("New Registration from: %s", request.user.email) try: send_mail( - "User/Contributor Registration at FOSSEE, IIT Bombay", message, SENDER_EMAIL, - [request.user.email], fail_silently=True - ) + "User/Contributor Registration at FOSSEE, IIT Bombay", message, + SENDER_EMAIL, [request.user.email], fail_silently=True) except Exception: send_smtp_email(request=request, subject="User/Contributor Registration - FOSSEE, IIT Bombay", message=message, other_email=request.user.email, + ) + elif call_on == 'released': + message = dedent("""\ + Hey {0}, + + Congratulations! your animations has been released on + FOSSEE's website. + Please start with your honouriam process + + In case of queries, please revert to this + email.""".format(contributor.profile.user.username)) + + logging.info("Released Animation: %s", request.user.email) + send_mail( + "Congratulations! Animation Released!", message, SENDER_EMAIL, + [contributor.profile.user.email], fail_silently=True + ) + elif call_on == 'rejected': + message = dedent("""\ + Hey {0}, + + We are sorry to inform you that your proposal for + FOSSEE Animation is rejected. + You can work on the feedback given by the reviewer or + send us another proposal on a different topic! + + In case of queries, please revert to this + email.""".format(contributor.profile.user.username)) + + logging.info("Animation Rejected: %s", request.user.email) + send_mail( + "FOSSEE Animation Status Update", message, SENDER_EMAIL, + [contributor.profile.user.email], fail_silently=True + ) + elif call_on == 'changes': + message = dedent("""\ + Hey {0}, + + Please check your proposal {1} + for comments by our reviewers + + In case of queries, please revert to this + email.""".format(contributor.profile.user.username, + 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 diff --git a/fossee_manim/templates/fossee_manim/base.html b/fossee_manim/templates/fossee_manim/base.html index 0e86ecc..c9d6242 100644 --- a/fossee_manim/templates/fossee_manim/base.html +++ b/fossee_manim/templates/fossee_manim/base.html @@ -9,7 +9,6 @@ </title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> - <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.bundle.min.js"></script> <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"> @@ -20,7 +19,8 @@ </head> <!-- For js/ajax and other related scripts --> - {% block extra %} + {% block extra %} + {% endblock %} <body style="overflow: scroll;"> @@ -33,12 +33,12 @@ </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> - <ul class="navbar-nav mr-auto"> - - <form class="form-inline"> - <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search"> - <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button> - </form> + <ul class="navbar-nav mr-auto"> + <form class="form-inline" method="POST" action="/search/"> + {% csrf_token %} + <input class="form-control mr-sm-2" id="sbox" name="sbox" type="search" placeholder="Search" aria-label="Search"> + <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button> + </form> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Categories @@ -59,16 +59,16 @@ </a> {% if request.user.profile.position == 'contributor' %} <div class="dropdown-menu" aria-labelledby="navbarDropdown"> - <a class="dropdown-item" href="#">Send Proposal</a> - <a class="dropdown-item" href="#">Proposal Status</a> - <a class="dropdown-item" href="{{URL_ROOT}}/view_profile">View Profile</a> - <a class="dropdown-item" href="{{URL_ROOT}}/logout">Logout</a> + <a class="dropdown-item" href="{% url 'send_proposal' %}">Send Proposal</a> + <a class="dropdown-item" href="{% url 'proposal_status' %}">Proposal Status</a> + <a class="dropdown-item" href="{% url 'view_profile' %}">View Profile</a> + <a class="dropdown-item" href="{% url 'logout' %}">Logout</a> </div> {% else %} <div class="dropdown-menu" aria-labelledby="navbarDropdown"> - <a class="dropdown-item" href="#">Proposal Status</a> - <a class="dropdown-item" href="{{URL_ROOT}}/view_profile">View Profile</a> - <a class="dropdown-item" href="{{URL_ROOT}}/logout">Logout</a> + <a class="dropdown-item" href="{% url 'proposal_status' %}">Proposal Status</a> + <a class="dropdown-item" href="{% url 'view_profile' %}">View Profile</a> + <a class="dropdown-item" href="{% url 'logout' %}">Logout</a> </div> {% endif %} </li> @@ -76,10 +76,10 @@ {% else %} <ul class="navbar-nav ml-auto"> <li class="nav-item"> - <a class="nav-link" href="{{ URL_ROOT}}/register">Register</a> + <a class="nav-link" href="{% url 'register' %}">Register</a> </li> <li class="nav-item"> - <a class="nav-link" href="{{ URL_ROOT}}/login">Login</a> + <a class="nav-link" href="{% url 'login' %}">Login</a> </li> </ul> {% endif %} diff --git a/fossee_manim/templates/fossee_manim/edit_proposal.html b/fossee_manim/templates/fossee_manim/edit_proposal.html new file mode 100644 index 0000000..c73071b --- /dev/null +++ b/fossee_manim/templates/fossee_manim/edit_proposal.html @@ -0,0 +1,97 @@ +{% extends 'fossee_manim/base.html' %} + + {% block title %} + Edit Proposal + {% endblock %} + +{% block content %} +<script type="text/javascript"> + var url = window.location.href.split('/').pop(); +</script> +<br> +<div class="container"> + <form method="POST" > + {% csrf_token %} + + <table class="table table-bordered"> + {{ proposal_form.as_table }} + </table> + + <br> + <button class="btn btn-primary pull-right" type="submit">Save</button> + </form> + + <br><br> + {% if request.user.profile.position == 'reviewer' %} + <form method="POST" > + {% csrf_token %} + <div class="form-group"> + <div class="row"> + <button class="btn btn-success pull-left" type="submit" name="release" value="1">Approve</button> + <button class="btn btn-danger pull-left" type="submit" name="rejected" value="2" style="margin-left: 3%">Reject</button> + </div> + </div> + </form> + {% endif %} + <br><br> + + <h2>Comments</h2> + <div> + <form method="POST"> + <br> + {% csrf_token %} + {{ comment_form.as_p }} + <button type="submit" class="btn btn-default">Post</button> + </form> + + </div> + <hr style="background-color: #fff; + border-top: 5px double #8c8b8b;"> + <table> + {% for comment in comments %} + <tbody> + <tr> + <td> + <h5>{{ comment.commentor.profile.user.get_full_name }} | {{ comment.created_date | date }}</h5> + <h6 style="background-color: #ecf0f1; padding:10px;">{{ comment.comment }}</h6> + <hr style="border-top: 0.5px solid #8c8b8b;"> + </td> + </tr> + </tbody> + {% endfor %} + </table> + +<br><br> + </div> + + <!-- Page Navigation --> + <div class="container"> + <div class="Page-Nav" align="center"> + <nav aria-label="Page navigation"> + <ul class="pagination pagination-sm"> + <li class="page-item"> + {% if comments.has_previous %} + <a class="page-link" tabindex="-1" + href="?page={{ comments.previous_page_number }}">Previous</a> + {% endif %} + </li> + <li class="page-item"> + <span class="current"> + Page {{ comments.number }} of {{ comments.paginator.num_pages }} + </span> + </li> + <li class="page-item"> + {% if comments.has_next %} + <a class="page-link" href="?page={{ comments.next_page_number }}">Next + </a> + {% endif %} + </li> + </ul> + </nav> + </div> + <br> + </div> + +</div> + +{% endblock %}
\ No newline at end of file diff --git a/fossee_manim/templates/fossee_manim/proposal_status.html b/fossee_manim/templates/fossee_manim/proposal_status.html new file mode 100644 index 0000000..b7a62f6 --- /dev/null +++ b/fossee_manim/templates/fossee_manim/proposal_status.html @@ -0,0 +1,53 @@ +{% extends 'fossee_manim/base.html' %} + + {% block title %} + Proposal Status + {% endblock %} + +{% block content %} + <br> + <div class="container" align="center"> + {% if request.user.profile.position == 'contributor' %} + <table class="table table-hover"> + <thead> + <tr> + <th>Title</th> + <th>Status</th> + </tr> + </thead> + {% for an in anime %} + <tbody> + <tr> + <td>{{ an.title }}</td> + <td><span class="badge">{{ an.status }}</span></td> + <td><a href="{% url 'edit_proposal' an.id %}"><button type="button" class="btn btn-info">Edit</button></a></td> + </tr> + </tbody> + {% endfor %} + </table> + {% else %} + + <table class="table table-hover"> + <thead> + <tr> + <th>Title</th> + <th>Contributor Name</th> + <th>Status</th> + </tr> + </thead> + {% for an in anime_list %} + <tbody> + <tr> + <td>{{ an.title }}</td> + <td>{{ an.contributor.get_full_name }}</td> + <td><span class="badge">{{ an.status }}</span></td> + <td><a href="{% url 'edit_proposal' an.id %}"><button type="button" class="btn btn-info">View</button></a></td> + </tr> + </tbody> + {% endfor %} + {% endif %} + + </table> + </div> + + {% endblock %}
\ No newline at end of file diff --git a/fossee_manim/templates/fossee_manim/search_results.html b/fossee_manim/templates/fossee_manim/search_results.html new file mode 100644 index 0000000..2e70f78 --- /dev/null +++ b/fossee_manim/templates/fossee_manim/search_results.html @@ -0,0 +1,13 @@ +{% extends 'fossee_manim/base.html' %} + + {% block title %} + Login + {% endblock %} + +{% block content %} + <br> + <div class="container" align="center"> + {{ args }} + </div> + + {% endblock %}
\ No newline at end of file diff --git a/fossee_manim/templates/fossee_manim/send_proposal.html b/fossee_manim/templates/fossee_manim/send_proposal.html new file mode 100644 index 0000000..bd56ede --- /dev/null +++ b/fossee_manim/templates/fossee_manim/send_proposal.html @@ -0,0 +1,41 @@ +{% extends 'fossee_manim/base.html' %} + + {% block title %} + Send Proposals + {% endblock %} + + {% block content %} + <br> + {% if messages %} + <ul class="messages"> + {% for message in messages %} + <div class="alert alert-{{ message.tags }}"> + <li {% if message.tags %} class="{{ message.tags }}"{% endif %}> {{ message }} + </li> + </div> + {% endfor %} + </ul> + {% endif %} + <br> + + <div class="container" align="center"> + <div class="alert alert-info"> + Please Note: If you're not serious about the animation then do not send us a proposal, + fake/time wasting submissions will result in permanent ban. + </div> + <br> + + <form method="post"> + {% csrf_token %} + <br/> + <table> + {{ form.as_table }} + </table> + <br> + <br> + <button class="btn btn-success" type="submit">Save</button> + </form> + + + </div> + {% endblock %}
\ No newline at end of file diff --git a/fossee_manim/templates/password_reset_confirm.html b/fossee_manim/templates/password_reset_confirm.html deleted file mode 100644 index 9f5b47a..0000000 --- a/fossee_manim/templates/password_reset_confirm.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "base.html" %} -{% block pagetitle %}Reset Password{% endblock %} - -{% block content %} - {% if validlink %} - <p>Please enter your new password twice so we can verify you typed it in correctly</p>. - <form method="post"> - {% csrf_token %} - {{ form.as_p }} - <button class= "btn" type="submit">Submit</button> - </form> - {% else %} - <p>This reset link is no longer valid!</p> - {% endif %} -{% endblock %}
\ No newline at end of file diff --git a/fossee_manim/urls.py b/fossee_manim/urls.py index abdc74b..7bc7740 100644 --- a/fossee_manim/urls.py +++ b/fossee_manim/urls.py @@ -3,11 +3,16 @@ from fossee_manim import views urlpatterns = [ url(r'^$', views.index, name='index'), - url(r'^register/$', views.user_register), + url(r'^register/$', views.user_register, name='register'), url(r'^activate_user/(?P<key>.+)$', views.activate_user), url(r'^activate_user/$', views.activate_user), - url(r'^login/$', views.user_login), - url(r'^logout/$', views.user_logout), - url(r'^view_profile/$', views.view_profile), - url(r'^edit_profile/$', views.edit_profile) + url(r'^login/$', views.user_login, name='login'), + url(r'^logout/$', views.user_logout, name='logout'), + 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'^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 diff --git a/fossee_manim/views.py b/fossee_manim/views.py index 6ba5d68..d9b27b2 100644 --- a/fossee_manim/views.py +++ b/fossee_manim/views.py @@ -1,11 +1,12 @@ from django.shortcuts import render from .forms import ( UserRegistrationForm, UserLoginForm, - ProfileForm + ProfileForm, AnimationProposal, + CommentForm ) from .models import ( - Profile, User, - has_profile + Profile, User, AnimationStats, + has_profile, Animation, Comment ) from datetime import datetime, date from django.contrib.auth import login, logout, authenticate @@ -21,13 +22,19 @@ from django.conf import settings from os import listdir, path, sep from zipfile import ZipFile from django.contrib import messages +from django.db.models import Q import datetime as dt +import os try: from StringIO import StringIO as string_io except ImportError: from io import BytesIO as string_io +def check_repo(link): + return True if 'github.com' in link else False + + def is_email_checked(user): if hasattr(user, 'profile'): return True if user.profile.is_email_verified else False @@ -46,7 +53,7 @@ def index(request): form = UserLoginForm() if user.is_authenticated() and is_email_checked(user): if user.groups.filter(name='reviewer').count() > 0: - return redirect('/manage/') + return redirect('/view_profile/') return redirect('/view_profile/') elif request.method == "POST": form = UserLoginForm(request.POST) @@ -56,7 +63,7 @@ def index(request): if is_superuser(user): return redirect("/admin") if user.groups.filter(name='reviewer').count() > 0: - return redirect('/manage/') + return redirect('/view_profile/') return redirect('/view_profile/') return render(request, "fossee_manim/index.html", {"form": form}) @@ -167,7 +174,6 @@ def user_register(request): return render(request, "fossee_manim/registration/register.html", {"form": form}) - @login_required def view_profile(request): """ view instructor and coordinator profile """ @@ -196,9 +202,9 @@ def edit_profile(request): return redirect('/admin') if is_email_checked(user): if is_reviewer(user): - template = 'fossee_manim/manage.html' + template = 'fossee_manim/view_profile.html' else: - template = 'fossee_manim/booking.html' + template = 'fossee_manim/proposal_status.html' else: try: logout(request) @@ -230,4 +236,122 @@ def edit_profile(request): return render(request, 'fossee_manim/edit_profile.html', context) else: form = ProfileForm(user=user, instance=profile) - return render(request, 'fossee_manim/edit_profile.html', {'form': form}) + return render(request, 'fossee_manim/edit_profile.html', {'form': form} + ) + + +@login_required +def send_proposal(request): + user = request.user + if request.method == 'POST': + form = AnimationProposal(request.POST) + if form.is_valid(): + form_data = form.save(commit=False) + form_data.contributor = user + form_data.status = "pending" + if check_repo(form_data.github): + form_data.save() + form.save_m2m() + else: + messages.warning(request, 'Please enter valid github details') + return render(request, 'fossee_manim/send_proposal.html', + {'form': form}) + return redirect('/proposal_status/') + else: + form = AnimationProposal() + return render(request, 'fossee_manim/send_proposal.html', + {'form': form}) + + +@login_required +def proposal_status(request): + user = request.user + profile = Profile.objects.get(user_id=user) + anime = {} + anime_list = {} + if profile.position == 'contributor': + anime = Animation.objects.filter(contributor_id=user) + else: + anime_list = Animation.objects.filter(Q(status='pending') | + Q(status='changes')) + return render(request, 'fossee_manim/proposal_status.html', + {'anime': anime, 'anime_list': anime_list}) + + +@login_required +def edit_proposal(request, proposal_id=None): + user = request.user + comment_form = CommentForm() + proposal = Animation.objects.get(id=proposal_id) + proposal_form = AnimationProposal(instance=proposal) + try: + comments = Comment.objects.all().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') + + if s1 or s2 is not None: + if s1: + proposal.status = 'released' + proposal.reviewer = user + proposal.save() + send_email(request, call_on='released', + contributor=proposal.contributor) + else: + proposal.status = 'rejected' + proposal.reviewer = user + proposal.save() + send_email(request, call_on='rejected', + contributor=proposal.contributor) + return redirect('/proposal_status/') + + if text is not None: + comment_form = CommentForm(request.POST) + form_data = comment_form.save(commit=False) + form_data.commentor = user + form_data.animation = proposal + if user.profile.position == 'reviewer': + proposal.status = 'changes' + send_email(request, call_on='changes', + contributor=proposal.contributor, + proposal=proposal) + form_data.save() + return redirect('/edit_proposal/{}'.format(proposal_id)) + proposal_form = AnimationProposal(request.POST, instance=proposal) + if proposal_form.is_valid(): + p_f = proposal_form.save(commit=False) + p_f.contributor = user + p_f.save() + proposal_form.save_m2m() + else: + if user.profile.position == 'contributor': + if user.id != proposal.contributor_id: + return redirect('/logout/') + + if comments is not None: + #Show upto 12 Workshops per page + paginator = Paginator(comments, 9) + page = request.GET.get('page') + try: + comments = paginator.page(page) + except PageNotAnInteger: + #If page is not an integer, deliver first page. + comments = paginator.page(1) + except EmptyPage: + #If page is out of range(e.g 999999), deliver last page. + comments = paginator.page(paginator.num_pages) + return render(request, 'fossee_manim/edit_proposal.html', + {'proposal_form': proposal_form, + "comments": comments, + "comment_form": comment_form}) + + +def search(request): + if request.method == 'POST': + word = request.POST.get('sbox') + + return render(request, 'fossee_manim/search_results.html') + diff --git a/requirements.txt b/requirements.txt index 1efdb8d..85b47d2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ Django==1.11 +django-simple-history==2.7.0 +django-taggit==0.23.0 pytz==2018.9 |