diff options
author | hardythe1 | 2014-10-30 17:39:43 +0530 |
---|---|---|
committer | hardythe1 | 2014-10-30 17:39:43 +0530 |
commit | f604c51131f625e26f1ac95d9464f59b8d89078b (patch) | |
tree | 1c5e384aacdb3b27ce2f7845ac4dadb8351dc615 /tbc | |
parent | bb5688c683a80c5de77505e42be228f46c369254 (diff) | |
parent | 503d1295c4bd146d6a36a2ddb64cb2a27211705c (diff) | |
download | Python-TBC-Interface-f604c51131f625e26f1ac95d9464f59b8d89078b.tar.gz Python-TBC-Interface-f604c51131f625e26f1ac95d9464f59b8d89078b.tar.bz2 Python-TBC-Interface-f604c51131f625e26f1ac95d9464f59b8d89078b.zip |
Conflict Resolved
Diffstat (limited to 'tbc')
-rw-r--r-- | tbc/admin.py | 4 | ||||
-rw-r--r-- | tbc/forms.py | 4 | ||||
-rw-r--r-- | tbc/models.py | 76 | ||||
-rwxr-xr-x | tbc/templates/base.html | 57 | ||||
-rw-r--r-- | tbc/templates/tbc/aicte-books.html | 25 | ||||
-rw-r--r-- | tbc/templates/tbc/ajax-matching-books.html | 24 | ||||
-rw-r--r-- | tbc/templates/tbc/book-review-details.html | 54 | ||||
-rw-r--r-- | tbc/templates/tbc/book-review.html | 6 | ||||
-rw-r--r-- | tbc/templates/tbc/confirm-aicte-details.html | 31 | ||||
-rw-r--r-- | tbc/templates/tbc/confirm-details.html | 57 | ||||
-rw-r--r-- | tbc/templates/tbc/disapprove-sample.html | 17 | ||||
-rw-r--r-- | tbc/templates/tbc/reject-proposal.html | 17 | ||||
-rw-r--r-- | tbc/templates/tbc/review-proposal.html | 98 | ||||
-rw-r--r-- | tbc/templates/tbc/submit-proposal.html | 79 | ||||
-rw-r--r-- | tbc/templates/tbc/submit-sample.html | 53 | ||||
-rw-r--r-- | tbc/templates/tbc/update-book.html | 2 | ||||
-rw-r--r-- | tbc/templates/tbc/update-code.html | 22 | ||||
-rw-r--r-- | tbc/templates/tbc/upload-content.html | 10 | ||||
-rw-r--r-- | tbc/urls.py | 19 | ||||
-rwxr-xr-x | tbc/views.py | 497 |
20 files changed, 1085 insertions, 67 deletions
diff --git a/tbc/admin.py b/tbc/admin.py index 959ce84..30b5b34 100644 --- a/tbc/admin.py +++ b/tbc/admin.py @@ -6,3 +6,7 @@ admin.site.register(Book) admin.site.register(Reviewer) admin.site.register(Chapters) admin.site.register(ScreenShots) +admin.site.register(TempBook) +admin.site.register(Proposal) +admin.site.register(SampleNotebook) +admin.site.register(AicteBook) diff --git a/tbc/forms.py b/tbc/forms.py index 8fc6e22..327c32a 100644 --- a/tbc/forms.py +++ b/tbc/forms.py @@ -59,7 +59,7 @@ class BookForm(forms.ModelForm): self.fields['isbn'].label = "ISBN No." self.fields['edition'].label = "Book Edition" self.fields['year_of_pub'].label = "Year of Publication" - self.fields['no_chapters'].label = "Number of Chapter" + self.fields['no_chapters'].label = "Number of Chapters" class Meta: model = Book exclude = ('contributor', 'approved', 'reviewer') @@ -70,5 +70,5 @@ class BookForm(forms.ModelForm): 'isbn':forms.TextInput(attrs={'placeholder':'Valid ISBN no. of the Book'}), 'edition':forms.TextInput(attrs={'placeholder':'Edition of the Book'}), 'year_of_pub':forms.TextInput(attrs={'placeholder':'Year when the Book was published'}), - 'no_chapters':forms.TextInput(attrs={'placeholder':'Total number of chapters in the Book'}), + 'no_chapters':forms.TextInput(attrs={'placeholder':'Total number of chapters in the Book (only include chapters that have solved examples)'}), } diff --git a/tbc/models.py b/tbc/models.py index 76c9dc6..67a6d09 100644 --- a/tbc/models.py +++ b/tbc/models.py @@ -1,6 +1,7 @@ from django.db import models from django.contrib.auth.models import User from PythonTBC import settings +from django.contrib.admin.models import LogEntry CATEGORY = (("fluid mechanics", "Fluid Mechanics"), @@ -37,7 +38,21 @@ ABOUT_PROJ = (("pythontbc website", "Python TBC Website"), ("mailing list", "Through Mailing List"), ("posters in college", "Through Posters in College"), ("others", "Others")) + +PROPOSAL_STATUS = (("pending","Pending"), + ("samples","Samples"), + ("sample submitted", "Sample Submitted"), + ("sample disapproved", "Sample Disapproved"), + ("sample resubmitted", "Sample Resubmitted"), + ("book alloted","Book Alloted"), + ("codes submitted", "Codes Submitted"), + ("codes disapproved", "Codes Disapproved"), + ("book completed","Book Completed"), + ("rejected","Rejected")) +BOOK_PREFERENCE = (("book1","1st Book"), + ("book2","2nd Book"), + ("book3","3rd Book")) def get_notebook_dir(instance, filename): @@ -48,8 +63,11 @@ def get_image_dir(instance, filename): return '%s/%s/screenshots/%s' % (instance.book.contributor, instance.book.title.replace(' ', '_'), filename.replace(' ', '_')) +def get_sample_dir(instance, filename): + user_name = instance.proposal.user.user.first_name+instance.proposal.user.user.last_name + return 'sample_notebooks/%s/%s' % (user_name, filename.replace(' ', '_')) + class Profile(models.Model): - """Model to store profile of a user.""" user = models.ForeignKey(User) about = models.CharField(max_length=256) insti_org = models.CharField(max_length=128) @@ -72,7 +90,6 @@ class Reviewer(models.Model): return '%s'%(name) class Book(models.Model): - """Model to store the book details""" title = models.CharField(max_length=500) author = models.CharField(max_length=300) category = models.CharField(max_length=32, choices=CATEGORY) @@ -104,3 +121,58 @@ class ScreenShots(models.Model): def __unicode__(self): name = self.caption or 'ScreenShots' return '%s'%(name) + + +class TempBook(models.Model): + title = models.CharField(max_length=500) + author = models.CharField(max_length=300) + category = models.CharField(max_length=32, choices=CATEGORY) + publisher_place = models.CharField(max_length=150) + isbn = models.CharField(max_length=50) + edition = models.CharField(max_length=15) + year_of_pub = models.CharField(max_length=4) + no_chapters = models.IntegerField(max_length=2) + def __unicode__(self): + name = self.title or 'Book' + return '%s'%(name) + + +class Proposal(models.Model): + user = models.ForeignKey(Profile) + textbooks = models.ManyToManyField(TempBook, related_name="proposed_textbooks") + accepted = models.ForeignKey(Book, related_name="approved_textbook", blank=True,null=True) + status = models.CharField(max_length=20, default="Pending", choices=PROPOSAL_STATUS) + remarks = models.CharField(max_length=1000) + def __unicode__(self): + user = self.user.user.username or 'User' + return '%s'%(user) + + +class SampleNotebook(models.Model): + proposal = models.ForeignKey(Proposal) + name = models.CharField(max_length=40) + sample_notebook = models.FileField(upload_to=get_sample_dir) + def __unicode__(self): + notebook = self.proposal.accepted.title or 'notebook' + return '%s'%(notebook) + + +class ActivityLog(LogEntry): + proposal_id = models.IntegerField(null=True) + conversation = models.TextField(null=True) + def __unicode__(self): + return 'Activity log for %d' %(proposal_id) + + +class AicteBook(models.Model): + title = models.TextField() + author = models.CharField(max_length=300L) + category = models.CharField(max_length=32L) + publisher_place = models.CharField(max_length=200L) + isbn = models.CharField(max_length=50L) + edition = models.CharField(max_length=15L) + year_of_pub = models.CharField(max_length=4L) + proposed = models.BooleanField(default=False) + def __unicode__(self): + notebook = self.title or 'Book' + return '%s'%(notebook) diff --git a/tbc/templates/base.html b/tbc/templates/base.html index e17d9bb..fbcfb05 100755 --- a/tbc/templates/base.html +++ b/tbc/templates/base.html @@ -69,8 +69,6 @@ </style> {% endblock %} - {% block script %} - {% endblock %} </head> <body> @@ -107,8 +105,9 @@ <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ user.first_name }}<b class="caret"></b></a> <ul class="dropdown-menu"> - <li><a href="{% url 'tbc:SubmitBook' %}">Submit Book</a></li> - <li><a href="{% url 'tbc:UpdateBook' %}">Update Submission</a></li> + <li><a href="{% url 'tbc:ListAICTE' %}">Submit Proposal</a></li> + <li><a href="{% url 'tbc:SubmitSample' %}">Submit Sample Notebook</a></li> + <li><a href="{% url 'tbc:ConfirmBookDetails' %}">Submit Codes</a></li> <li><a href="{% url 'tbc:UpdatePassword' %}">Update Password</a></li> <li><a href="{% url 'tbc:UserLogout' %}">Logout</a></li> </ul> @@ -120,6 +119,7 @@ <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ reviewer.first_name }} {{ reviewer.last_name }} <b class="caret"></b></a> <ul class="dropdown-menu"> <li><a href="{% url 'tbc:BookReview' %}">Review Books</a></li> + <li><a href="{% url 'tbc:ReviewProposals' %}">Review Proposals</a></li> <li><a href="{% url 'tbc:UserLogout' %}">Logout</a></li> </ul> </li> @@ -182,6 +182,52 @@ </center> <div class="clearfix"></div> {% endif %} + {% if proposal_submitted %} + <center> + <div class="alert" style="width:650px;height:40px;"> + <a class="close" data-dismiss="alert" href="#">×</a> + <p>Thank you for showing interest in contributing to Python TBC. <br>We have recevied your proposal. Please be patient we will get back to you within few days.</p> + </div> + </center> + <div class="clearfix"></div> + {% endif %} + {% if proposal_pending %} + <center> + <div class="alert" style="width:650px;height:40px;"> + <a class="close" data-dismiss="alert" href="#">×</a> + <p>You either have a proposal pending or you are already working on a book. You cannot submit a proposal at this moment.</p> + </div> + </center> + <div class="clearfix"></div> + {% endif %} + {% if no_book_alloted %} + <center> + <div class="alert" style="width:400px;height:25px;"> + <a class="close" data-dismiss="alert" href="#">×</a> + <p>There is no book alloted to you. You cannot submit codes.</p> + </div> + </center> + <div class="clearfix"></div> + {% endif %} + {% if sample_notebook %} + <center> + <div class="alert" style="width:550px;height:40px;"> + <a class="close" data-dismiss="alert" href="#">×</a> + <p>Sample notebook has been submitted successfully. Please be patient while the reviewer reviews your codes & get backs to you.</p> + </div> + </center> + <div class="clearfix"></div> + {% endif %} + {% if cannot_submit_sample %} + <center> + <div class="alert" style="width:400px;height:25px;"> + <a class="close" data-dismiss="alert" href="#">×</a> + <p>You have not been permitted to send sample notebook.</p> + </div> + </center> + <div class="clearfix"></div> + {% endif %} + <div class="row-fluid"> <h3 style='float: left;margin-left: 50px; display: inline-block;'>Recent Submissions</h3> <div style="float:right; margin-right: 50px; width: 400px;"> <script> @@ -199,7 +245,6 @@ <gcse:search></gcse:search> </div> <div style="clear:both;"></div> - <div class="row-fluid"> {% for item in items %} <div class ="module-list"> <a href="{% url 'tbc:BookDetails' item.book.id %}"><img src="{% static 'uploads/' %}{{ item.image.image }}"></a> @@ -215,7 +260,7 @@ <!-- <input type=text> <input type=submit value=Search> --> - {% endblock %} + {% endblock %} <hr> <footer> diff --git a/tbc/templates/tbc/aicte-books.html b/tbc/templates/tbc/aicte-books.html new file mode 100644 index 0000000..4cc3d15 --- /dev/null +++ b/tbc/templates/tbc/aicte-books.html @@ -0,0 +1,25 @@ +{% extends 'base.html' %} +{% load static %} +{% block content %} + <center><h3>List of AICTE Books</h3></center> + <hr> + <div id="content-wrap"> + <p>Below is the list of AICTE recommended books. You can propose a book just by clicking on the link. However, if you wish to submit your own preferences other than AICTE books, click the button given below.</p> + <a href="{% url 'tbc:SubmitProposal' %}" class="btn btn-primary">I don't want to propose AICTE book</a> + <hr> + <table class="table table-bordered table-hover"> + <th>SR #</th> + <th>Book (click on the link to propose the book)</th> + {% for book in aicte_books %} + <tr> + <td> + {{ forloop.counter }} + </td> + <td> + <a href="{% url 'tbc:SubmitAICTEProposal' book.id %}">{{ book.title }} by {{ book.author }}, {{ book.edition }} Edition</a> + </td> + </tr> + {% endfor %} + </table> + </div> +{% endblock %} diff --git a/tbc/templates/tbc/ajax-matching-books.html b/tbc/templates/tbc/ajax-matching-books.html new file mode 100644 index 0000000..c5fbfa8 --- /dev/null +++ b/tbc/templates/tbc/ajax-matching-books.html @@ -0,0 +1,24 @@ +<html> +<body> +<div> + <span id="flag">{% if flag %}match exists{% endif %}</span> + <div id="matches"> + <center><h5>The books you have proposed may already be <b>under progress</b> or <b>completed</b> by some other contributor. Kindly verify and submit the proposal.</h5></center> + <hr> + {% for match in matches %} + {% if match %} + <b><h5>Potential matching books for your book preference {{ forloop.counter }}</h5></b> + {% else %} + <h5>No matching books found for book preference {{ forloop.counter }}</h5> + {% endif %} + <ul> + {% for book in match %} + <li>{{ book.title }} by {{ book.author }}</li> + {% endfor %} + </ul> + <hr> + {% endfor %} + </div> +</div> +</body> +</html> diff --git a/tbc/templates/tbc/book-review-details.html b/tbc/templates/tbc/book-review-details.html index e55c23c..1aa888c 100644 --- a/tbc/templates/tbc/book-review-details.html +++ b/tbc/templates/tbc/book-review-details.html @@ -11,21 +11,30 @@ {% endfor %} </div> <hr> -<ul> -{% for chapter in chapters %} - <li><a href="{% url 'tbc:ConvertNotebook' chapter.notebook %}">{{ chapter.name }}</a></li> -{% endfor %} -</ul> +<table class="table table-bordered table-hover"> + {% for chapter in chapters %} + <tr> + <td><a href="{% url 'tbc:ConvertNotebook' chapter.notebook %}">{{ chapter.name }}</a></td> + </tr> + {% endfor %} +</table> <hr> -<form action="/approve-book/{{ book.id }}" method="POST"> -{% csrf_token %} -<select name=approve_notify> - <option value=none>Select an Action</option> - <option value="approve">Approve</option> - <option value="notify">Notify Changes</option> -</select> -<input type=submit value=GO> -</form> +{% if book.approved %} +<h3>Book has been completed & approved</h3> +{% else %} + <form action="/approve-book/{{ book.id }}" method="POST"> + {% csrf_token %} + <select name=approve_notify> + <option value=none>Select an Action</option> + <option value="approve">Approve</option> + <option value="notify">Notify Changes</option> + </select> + <input type=submit value=GO> + </form> + {% ifequal proposal.status 'codes disapproved' %} + <p>The required corrections have already been notified to the user. Kindly check the Activity Log for more details</p> + {% endifequal %} +{% endif %} <table> <tr><td>Author: <td>{{ book.author }} <tr><td>Publisher: <td>{{ book.publisher_place }} @@ -33,4 +42,21 @@ <tr><td>Contributor: <td>{{ book.contributor.user.first_name }} {{ book.contributor.user.last_name }} <tr><td>Email: <td>{{ book.contributor.user.email }}<br> </table> +<hr> +<table class="table table-bordered table-hover"> + <tr> + <th>User</th> + <th>Time</th> + <th>Activity</th> + <th class="span6">Conversation</th> + </tr> +{% for log in logs %} +<tr> + <td> {{ log.user }} </td> + <td> {{ log.action_time }} </td> + <td> {{ log.change_message }} </td> + <td> {{ log.conversation|linebreaksbr }} </td> +</tr> +{% endfor %} +<table> {% endblock %} diff --git a/tbc/templates/tbc/book-review.html b/tbc/templates/tbc/book-review.html index d7270b4..7bb88ff 100644 --- a/tbc/templates/tbc/book-review.html +++ b/tbc/templates/tbc/book-review.html @@ -23,4 +23,10 @@ <li><a href="{% url 'tbc:BookReview' book.id %}">{{ book.title }} {{ book.edition }} Edition</a> {% endfor %} </ol> +<center><h3>Reviewed Books</h3></center> +<ol> +{% for book in approved_books %} +<li><a href="{% url 'tbc:BookReview' book.id %}">{{ book.title }} {{ book.edition }} Edition</a></li> +{% endfor %} +<ol> {% endblock %} diff --git a/tbc/templates/tbc/confirm-aicte-details.html b/tbc/templates/tbc/confirm-aicte-details.html new file mode 100644 index 0000000..e8ab88b --- /dev/null +++ b/tbc/templates/tbc/confirm-aicte-details.html @@ -0,0 +1,31 @@ +{% extends 'base.html' %} +{% block content %} + <div id="content-wrap" style="max-width:600px;"> + <center> + <h3>AICTE Book Details</h3> + <hr> + <p> + Kindly verify the book details. Also, fill in the missing details & submit the proposal. + </p> + <hr> + </center> + <form id="proposal-form" action="/submit-aicte-proposal/{{ aicte_book.id }}/" method=POST enctype="multipart/form-data"> + {% csrf_token %} + {{ form.as_p }} + <hr> + <input id="proposal-form-submit" class="btn btn-primary" type=submit value=submit> + </form> + </div> +{% endblock %} + +{% block script %} +<script> +$( document ).ready(function() { + title = document.getElementById('id_title').readOnly = true; + author = document.getElementById('id_author').readOnly = true; + publisher_place = document.getElementById('id_publisher_place').readOnly = true; + $('#id_no_chapters').hide(); + $('label[for="id_no_chapters"]').hide(); +}); +</script> +{% endblock %} diff --git a/tbc/templates/tbc/confirm-details.html b/tbc/templates/tbc/confirm-details.html new file mode 100644 index 0000000..96393ac --- /dev/null +++ b/tbc/templates/tbc/confirm-details.html @@ -0,0 +1,57 @@ +{% extends 'base.html' %} +{% block content %} +<div id="content-wrap" style="max-width:600px;"> + <div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h3 id="myModalLabel">Verify Details</h3> + </div> + <div class="modal-body"> + <p>You are submitting codes for the book <br> <b>{{ book.title }} by {{ book.author }}</b>. + <br>Kindly verify the book details & <b>enter the number of chapters</b> you will submit the codes for.</p> + <p>Note: Consider only those chapters which have solved examples</p></p> + </div> + <div class="modal-footer"> + <button class="btn btn-primary" data-dismiss="modal">Ok</button> + </div> + </div> + <div id="chapterModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h3 id="myModalLabel">Invalid number of chapters</h3> + </div> + <div class="modal-body"> + <p>No of chapters cannot be less than 0 or greater than 100</p> + <p>However, if the textbook has more than 100 chapters kindly contact the reviewer.</p> + </div> + <div class="modal-footer"> + <button class="btn btn-primary" data-dismiss="modal">Ok</button> + </div> + </div> + <form action="/confirm-book-details/" method=POST enctype="multipart/form-data"> + {% csrf_token %} + {{ form.as_table }} + <br> + <input class="btn btn-primary" type=submit onclick="return validateChapters();" value="Update Details"> + </form> +</div> +{% endblock %} + +{% block script %} + <script> + $(document).ready(function() { + $("#myModal").modal(); + }); + + function validateChapters() + { + no_chapters = document.getElementById("id_no_chapters").value + if (no_chapters <= 0 || no_chapters > 100) + { + $("#chapterModal").modal(); + return false; + } + return true; + } + </script> +{% endblock %} diff --git a/tbc/templates/tbc/disapprove-sample.html b/tbc/templates/tbc/disapprove-sample.html new file mode 100644 index 0000000..2632edb --- /dev/null +++ b/tbc/templates/tbc/disapprove-sample.html @@ -0,0 +1,17 @@ +{% extends 'base.html' %} +{% load static %} +{% block content %} +<center><h3>Diapprove Sample Notebook</h3> +<hr> +<h4>Notifing Chages for book {{ proposal.accepted.title }} to {{ proposal.user.user.first_name }} {{ proposal.user.user.last_name }}</h4></center> +<form action="/disapprove-sample-notebook/{{ proposal.id }}" method=POST enctype="multipart/form-data"> +{% csrf_token %} + <table> + <tr><td>To</td></tr> + <tr><td><input type="text" value="{{ proposal.user.user.email }}" readonly></td></tr> + <tr><td>Changes Required</td></tr> + <tr><td><textarea rows="15" cols="100" name="changes_required" style="width:100%;"></textarea></td></tr> + <tr><td><input class="btn btn-primary" type="submit" value="Send"></td></tr> + </table> +</form> +{% endblock %} diff --git a/tbc/templates/tbc/reject-proposal.html b/tbc/templates/tbc/reject-proposal.html new file mode 100644 index 0000000..11ce874 --- /dev/null +++ b/tbc/templates/tbc/reject-proposal.html @@ -0,0 +1,17 @@ +{% extends 'base.html' %} +{% load static %} +{% block content %} +<center><h3>Proposal Rejection</h3> +<hr> +<h4>Rejecting proposal submitted by {{ proposal.user.user.first_name }} {{ proposal.user.user.last_name }}.</h4></center> +<form action="/reject-proposal/{{ proposal.id }}" method=POST enctype="multipart/form-data"> +{% csrf_token %} + <table> + <tr><td>To</td></tr> + <tr><td><input type="text" value="{{ proposal.user.user.email }}" readonly></td></tr> + <tr><td>Reason/Remarks for rejection</td></tr> + <tr><td><textarea rows="15" cols="100" name="remarks" style="width:100%;"></textarea></td></tr> + <tr><td><input class="btn btn-primary" type="submit" value="Send"></td></tr> + </table> +</form> +{% endblock %} diff --git a/tbc/templates/tbc/review-proposal.html b/tbc/templates/tbc/review-proposal.html new file mode 100644 index 0000000..b660db8 --- /dev/null +++ b/tbc/templates/tbc/review-proposal.html @@ -0,0 +1,98 @@ +{% extends 'base.html' %} +{% load static %} +{% block content %} + <center><h2>New Proposals</h2></center> + <hr> + {% if no_new_proposal %} + <center><h4>There are no new proposals</h4></center> + {% endif %} + <ol> + {% for proposal in proposals %} + <li><h4>Proposal from {{ proposal.user.user.first_name }} {{ proposal.user.user.last_name }}</h4></li> + <div class="accordion" id="accordion1{{ forloop.parentloop.counter }}{{ forloop.counter }}"> + {% for textbook in proposal.textbooks.all %} + <div class="accordion-group"> + <div class="accordion-heading"> + <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion1{{ forloop.parentloop.counter }}{{ forloop.counter }}" href="#collapse1{{ forloop.parentloop.counter }}{{forloop.counter}}"> + Book Preference {{ forloop.counter }} - {{ textbook.title }} + </a> + </div> + <div id="collapse1{{ forloop.parentloop.counter }}{{forloop.counter}}" class="accordion-body collapse"> + <div class="accordion-inner"> + Author: {{ textbook.author}}<br> + Edition: {{ textbook.edition }}<br> + Publisher: {{ textbook.publisher_place }}<br> + ISBN: {{ textbook.isbn }}<br> + Year of Pub.: {{ textbook.year_of_pub }}<br> + Category: {{ textbook.category }}<br> + <a class="btn btn-primary btn-mini" href="{% url 'tbc:ReviewProposals' proposal.id textbook.id %}">Approve & Ask for Samples</a> + </div> + </div> + </div> + {% endfor %} + <h5><b>Status:</b> You are yet to review this proposal</h5> + <a class="btn btn-primary" href="{% url 'tbc:RejectProposal' proposal.id %}">Reject</a> + </div> + {% endfor %} + </ol> + <hr> + <center><h2>Proposals in Sample Notebook phase</h2></center> + <hr> + <ol> + {% for proposal in old_proposals %} + <h4><li>Proposal from {{ proposal.proposal.user.user.first_name }} {{ proposal.proposal.user.user.last_name }}</h4></li> + <div class="accordion" id="accordion2{{ forloop.counter }}"> + {% for textbook in proposal.proposal.textbooks.all %} + <div class="accordion-group"> + <div class="accordion-heading"> + <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion2{{ forloop.parentloop.counter }}{{ forloop.counter }}" href="#collapse2{{ forloop.parentloop.counter }}{{forloop.counter}}"> + Book Preference {{ forloop.counter }} - {{ textbook.title }} + </a> + </div> + <div id="collapse2{{ forloop.parentloop.counter }}{{forloop.counter}}" class="accordion-body collapse"> + <div class="accordion-inner"> + Author: {{ textbook.author}}<br> + Edition: {{ textbook.edition }}<br> + Publisher: {{ textbook.publisher_place }}<br> + ISBN: {{ textbook.isbn }}<br> + Year of Pub.: {{ textbook.year_of_pub }}<br> + Category: {{ textbook.category }}<br> + </div> + </div> + </div> + {% endfor %} + <h5> + + {% ifequal proposal.proposal.status "samples" %} + <b>Status:</b> Sample notebook phase + {% endifequal %} + </h5> + <h5><b>Book Accepted/Alloted:</b> {{ proposal.proposal.accepted.title }}</h5> + {% ifequal proposal.proposal.status "sample resubmitted" %} + {% if proposal.sample.sample_notebook %} + <h5><a href="{% static 'uploads/' %}{{ proposal.sample.sample_notebook }}">sample notebook</a><br></h5> + <a class="btn btn-primary" href="{% url 'tbc:DisapproveProposal' proposal.proposal.id %}">Disapprove Samples</a> + <a class="btn btn-primary" href="{% url 'tbc:AllotBook' proposal.proposal.id %}">Alot Book</a> + <h5>This is resubmission of the sample notebook</h5> + {% else %} + <h5>Contributor has not re submitted sample notebook yet.</h5> + {% endif %} + {% endifequal %} + {% ifequal proposal.proposal.status "sample submitted" %} + {% if proposal.sample.sample_notebook %} + <h5><a href="{% static 'uploads/' %}{{ proposal.sample.sample_notebook }}">sample notebook</a><br></h5> + <a class="btn btn-primary" href="{% url 'tbc:DisapproveProposal' proposal.proposal.id %}">Disapprove Samples</a> + <a class="btn btn-primary" href="{% url 'tbc:AllotBook' proposal.proposal.id %}">Alot Book</a> + {% else %} + <h5>Contributor has not submitted sample notebook yet.</h5> + {% endif %} + {% endifequal %} + {% ifequal proposal.proposal.status "sample disapproved" %} + <b>Status:</b> Samples have been disapproved. Contributor has not resubmitted sample notebook yet. + {% endifequal %} + </div> + {% endfor %} + </ol> +{% endblock %} + + diff --git a/tbc/templates/tbc/submit-proposal.html b/tbc/templates/tbc/submit-proposal.html new file mode 100644 index 0000000..167fa5a --- /dev/null +++ b/tbc/templates/tbc/submit-proposal.html @@ -0,0 +1,79 @@ +{% extends 'base.html' %} +{% block content %} +<div id="content-wrap" style="max-width:600px;"> + <form id="proposal-form" action="/submit-proposal/" method=POST enctype="multipart/form-data"> + {% csrf_token %} + {% for form in book_forms %} + <h4>Book Preference {{ forloop.counter }}</h4> + {{ form.errors }} + {{ form.as_p }} + {% endfor %} + <hr> + <input id="proposal-form-submit" class="btn btn-primary" type=submit value=submit> + </form> +</div> + + +<!-- Button to trigger modal --> +<!-- Modal --> +<div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h3 id="myModalLabel">Potential Matching Books</h3> + </div> + <div class="modal-body"> + <p>One fine body…</p> + </div> + <div class="modal-footer"> + <button class="btn btn-primary" data-dismiss="modal">Go Back</button> + <button id="modal-submit-proposal" class="btn btn-danger">Submit Proposal</button> + </div> +</div> +{% endblock %} + +{% block script %} + <script> + $(document).ready(function() { + $("#proposal-form-submit").click(function(e) { + var i = 0; + var titles = []; + $titles = $("input[name='title']"); + $titles = $("input[name='title']"); + $titles.each(function(index, value) { + titles[i] = $(this).val(); + ++i; + }); + titles = JSON.stringify(titles); + + $.ajax({ + url: "/ajax/matching-books/", + type: "POST", + dataType: "html", + data: { + titles: titles + }, + success: function(output) { + console.log(output); + var $output = $(output); + if($output.find("#flag").html() == "") { + $("#proposal-form").submit(); + } else { + $(".modal-body").html($output.find("#matches").html()); + $("#myModal").modal(); + } + } + }); + e.preventDefault(); + }); + $("#modal-submit-proposal").click(function(e){ + $("#proposal-form").submit(); + e.preventDefault(); + }); + }); + $( document ).ready(function() { + $('input[id="id_no_chapters"]').hide(); + $('label[for="id_no_chapters"]').hide(); + }); + + </script> +{% endblock %} diff --git a/tbc/templates/tbc/submit-sample.html b/tbc/templates/tbc/submit-sample.html new file mode 100644 index 0000000..322c339 --- /dev/null +++ b/tbc/templates/tbc/submit-sample.html @@ -0,0 +1,53 @@ +{% extends 'base.html' %} + +{% block script %} +<script> +function validate_content(ext, name) +{ + extension = document.getElementById(ext).value; + name = document.getElementById(name).value; + extension = extension.split("."); + if (extension == "" || name == "") + { + alert("Chapter name or file field is empty !"); + return false; + } + if(extension.slice(Math.max(extension.length - 1, 1)) == "ipynb") + { + return true; + } + else + { + alert("Oops ! You can upload only Ipython Notebooks (.ipynb extension)"); + return false; + } + return true; +} +</script> +{% endblock %} + +{% block content %} +<div id="content-wrap" style="max-width:600px;"> + <h5>You are uploading sample notebook for the book <br>{{ proposal.accepted }} by {{ proposal.accepted.author }}</h5> + <p>Only .ipynb files are acceptable</p> + {% if has_old %} + <form action="/submit-sample/{{ proposal.id }}/{{ old_notebook.id }}" name="with-old" method=POST enctype="multipart/form-data" onSubmit="return validate_content('old_notebook', 'ch_name_old');"> + {% csrf_token %} + <input type=text id=ch_name_old name=ch_name_old value="{{ old_notebook.name }}"> + <input type=file id=old_notebook name=old_notebook> + <br> + <hr> + <center><input class="btn btn-primary" type=submit value=submit></center> + </form> + {% else %} + <form action="/submit-sample/{{ proposal.id }}" name="without-old" method=POST enctype="multipart/form-data" onSubmit="return validate_content('sample_notebook', 'ch_name');"> + {% csrf_token %} + <input type=text id=ch_name name=ch_name placeholder="Name of the chapter you coded the solved example from"> + <input type=file id=sample_notebook name=sample_notebook> + <br> + <hr> + <center><input class="btn btn-primary" type=submit value=submit></center> + </form> + {% endif %} +</div> +{% endblock %} diff --git a/tbc/templates/tbc/update-book.html b/tbc/templates/tbc/update-book.html index fb26a8b..c00d003 100644 --- a/tbc/templates/tbc/update-book.html +++ b/tbc/templates/tbc/update-book.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block content %} <div id="content-wrap" style="max-width:600px;"> - <form action="/update-book/" method=POST enctype="multipart/form-data"> + <form action="/confirm-book-deetails/" method=POST enctype="multipart/form-data"> {% csrf_token %} {{ form.as_table }} <br> diff --git a/tbc/templates/tbc/update-code.html b/tbc/templates/tbc/update-code.html new file mode 100644 index 0000000..cce2038 --- /dev/null +++ b/tbc/templates/tbc/update-code.html @@ -0,0 +1,22 @@ +{% extends 'base.html' %} +{% block content %} + <div id="content-wrap" style="max-width:600px;"> + <p>You are updating codes for the book {{ book.title }} by {{ book.author }}</p> + <p>Upload the corrected IPython Notebooks & screen shots.</p> + <form action="/submit-code/" method=POST enctype="multipart/form-data"> + {% csrf_token %} + {% for chapter in chapters %} + <input type=text name=chapter{{forloop.counter}} value="{{ chapter.name }}"> + <input type=file name=notebook{{forloop.counter}}> + {% endfor %} + <br> + <hr> + <p>Upload 3 screenshots from any 3 random chapters and give proper captions</p> + {% for screenshot in screenshots %} + <input type=text name=caption{{forloop.counter}} value="{{ screenshot.caption }}"> + <input type=file name=image{{forloop.counter}}> + {% endfor %} + <center><input type=submit value=submit></center> + </form> + </div> +{% endblock %} diff --git a/tbc/templates/tbc/upload-content.html b/tbc/templates/tbc/upload-content.html index ddc0f72..2423bd4 100644 --- a/tbc/templates/tbc/upload-content.html +++ b/tbc/templates/tbc/upload-content.html @@ -44,10 +44,15 @@ function validate_content() {% endblock %} {% block content %} +<center> + <h4>Submitting code for the book </h4> + <h4> {{ curr_book.title }} by {{ curr_book.author }}</h4> +</center> +<hr> <div id="content-wrap" style="max-width:600px;"> <p>Upload chapters as individual IPython notebooks. Please do not use spaces to name your Ipython Notebook files. For ex. use "chapter1.ipynb instead of chapter 1.ipynb"</p> - <form action="/upload-content/{{ curr_book.id }}" method=POST enctype="multipart/form-data" onSubmit="return validate_content();"> + <form action="/submit-code/" method=POST enctype="multipart/form-data"> {% csrf_token %} {% for i in no_notebooks %} <input type=text id=chapter{{i}} name=chapter{{i}} placeholder="Chapter {{ forloop.counter }} name"> @@ -60,7 +65,8 @@ function validate_content() <input type=text id=caption{{i}} name=caption{{i}} placeholder="Caption {{ forloop.counter }}"> <input type=file id=image{{i}} name=image{{i}}> {% endfor %} - <center><input class="btn btn-primary" type=submit value=submit></center> + <br><br> + <center><input class="btn btn-primary" type=submit value=submit onClick="return validate_content();"></center> </form> </div> {% endblock %} diff --git a/tbc/urls.py b/tbc/urls.py index 15e7816..7242fd6 100644 --- a/tbc/urls.py +++ b/tbc/urls.py @@ -14,9 +14,15 @@ urlpatterns = patterns('', url(r'^update-password/$', 'tbc.views.UpdatePassword', name='UpdatePassword'), + url(r'^submit-proposal/$', 'tbc.views.SubmitProposal', name='SubmitProposal'), + url(r'^submit-aicte-proposal/$', 'tbc.views.ListAICTE', name='ListAICTE'), + url(r'^submit-aicte-proposal/(?P<aicte_book_id>\d+)/$', 'tbc.views.SubmitAICTEProposal', name='SubmitAICTEProposal'), url(r'^submit-book/$', 'tbc.views.SubmitBook', name='SubmitBook'), - url(r'^update-book/$', 'tbc.views.UpdateBook', name='UpdateBook'), - url(r'^upload-content/(?P<book_id>\d+)$', 'tbc.views.ContentUpload', name='ContentUpload'), + url(r'^submit-sample/$', 'tbc.views.SubmitSample', name='SubmitSample'), + url(r'^submit-sample/(?P<proposal_id>\d+)$', 'tbc.views.SubmitSample', name='SubmitSample'), + url(r'^submit-sample/(?P<proposal_id>\d+)/(?P<old_notebook_id>\d+)$', 'tbc.views.SubmitSample', name='SubmitSample'), + url(r'^confirm-book-details/$', 'tbc.views.ConfirmBookDetails', name='ConfirmBookDetails'), + url(r'^submit-code/$', 'tbc.views.SubmitCode', name='SubmitCode'), url(r'^update-content/(?P<book_id>\d+)$', 'tbc.views.UpdateContent', name='UpdateContent'), url(r'^get-zip/(?P<book_id>\d+)$', 'tbc.views.GetZip', name='GetZip'), url(r'^browse-books/$', 'tbc.views.BrowseBooks', name='BrowseBooks'), @@ -30,7 +36,16 @@ urlpatterns = patterns('', url(r'^book-review/$', 'tbc.views.BookReview', name='BookReview'), + url(r'^proposal-review/$', 'tbc.views.ReviewProposals', name='ReviewProposals'), + url(r'^proposal-review/(?P<proposal_id>\d+)/(?P<textbook_id>\d+)$', 'tbc.views.ReviewProposals', name='ReviewProposals'), + url(r'^disapprove-sample-notebook/(?P<proposal_id>\d+)$', 'tbc.views.DisapproveProposal', name='DisapproveProposal'), + url(r'^allot-book/(?P<proposal_id>\d+)$', 'tbc.views.AllotBook', name='AllotBook'), + url(r'^reject-proposal/(?P<proposal_id>\d+)$', 'tbc.views.RejectProposal', name='RejectProposal'), url(r'^book-review/(?P<book_id>\d+)$', 'tbc.views.BookReview', name='BookReview'), url(r'^approve-book/(?P<book_id>\d+)$', 'tbc.views.ApproveBook', name='ApproveBook'), url(r'^notify-changes/(?P<book_id>\d+)$', 'tbc.views.NotifyChanges', name='NotifyChanges'), + + # ajax urls + url(r'^ajax/matching-books/$', 'tbc.views.ajax_matching_books', name='AjaxMatchingBooks'), + ) diff --git a/tbc/views.py b/tbc/views.py index 749c57d..0f23439 100755 --- a/tbc/views.py +++ b/tbc/views.py @@ -1,7 +1,11 @@ +from django.utils.encoding import force_text +from django.contrib.contenttypes.models import ContentType from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render_to_response, redirect +from django.views.decorators.csrf import csrf_exempt from django.core.context_processors import csrf from django.contrib.auth import authenticate, login, logout +from django.contrib.admin.models import CHANGE from models import * from tbc.forms import * import os @@ -11,9 +15,24 @@ import smtplib import shutil import string import random +import json from email.mime.text import MIMEText +def add_log(user, object, flag, message, proposal_id=None, chat='No message'): + '''Creates log entry of the user activities.''' + ActivityLog( + user_id=user.id, + content_type_id=ContentType.objects.get_for_model(object).id, + object_id=object.id, + object_repr=force_text(object), + action_flag=flag, + change_message=message, + proposal_id = proposal_id, + conversation = chat, + ).save() + + def email_send(to,subject,msg): try: smtpObj = smtplib.SMTP('localhost') @@ -25,7 +44,7 @@ def email_send(to,subject,msg): smtpObj.sendmail(mail_from, to, message.as_string()) except SMTPException: return HttpResponse("Error:unable to send email") - + def is_reviewer(user): if user.groups.filter(name='reviewer').count() == 1: @@ -62,11 +81,6 @@ def AboutPytbc(request): return render_to_response('tbc/about-pytbc.html', context) -def TemporarilyUnavailable(request): - context = {} - return render_to_response('tbc/unavailable.html', context) - - def Home(request): context = {} images = [] @@ -89,6 +103,17 @@ def Home(request): context['update_book'] = True if 'not_found' in request.GET: context['not_found'] = True + if 'proposal' in request.GET: + context['proposal_submitted'] = True + if 'proposal_pending' in request.GET: + context['proposal_pending'] = True + if 'no_book_alloted' in request.GET: + context['no_book_alloted'] = True + if 'sample_notebook' in request.GET: + context['sample_notebook'] = True + if 'cannot_submit_sample' in request.GET: + context['cannot_submit_sample'] =True + books = Book.objects.filter(approved=True).order_by("-id")[0:6] for book in books: images.append(ScreenShots.objects.filter(book=book)[0]) @@ -99,7 +124,7 @@ def Home(request): book_images.append(obj) context['items'] = book_images return render_to_response('base.html', context) - + def UserLogin(request): context = {} @@ -118,6 +143,7 @@ def UserLogin(request): curr_user = authenticate(username=username, password=password) if curr_user is not None: login(request, curr_user) + add_log(curr_user, curr_user, CHANGE, 'Logged in') else: form = UserLoginForm() context['form'] = form @@ -146,7 +172,8 @@ def UserRegister(request): if request.method == 'POST': form = UserRegisterForm(request.POST) if form.is_valid(): - form.save() + user = form.save() + add_log(user, user, CHANGE, 'Registered') return HttpResponseRedirect('/login/?signup=done') else: context = {} @@ -165,11 +192,16 @@ def UserProfile(request): user = request.user if user.is_authenticated(): if request.method == 'POST': - form = UserProfileForm(request.POST) + user_profile = Profile.objects.filter(user=user) + if user_profile.exists(): + form = UserProfileForm(request.POST, instance=user_profile[0]) + else: + form = UserProfileForm(request.POST) if form.is_valid(): data = form.save(commit=False) data.user = request.user data.save() + add_log(user, user, CHANGE,'Profile entry') return HttpResponseRedirect('/') else: context.update(csrf(request)) @@ -185,12 +217,13 @@ def UserProfile(request): return render_to_response('tbc/profile.html', context) else: return HttpResponseRedirect('/login/?require_login=True') - + def UserLogout(request): user = request.user if user.is_authenticated() and user.is_active: logout(request) + add_log(user, user, CHANGE, 'Logged out') return redirect('/?logout=done') @@ -226,7 +259,7 @@ def ForgotPassword(request): return render_to_response("tbc/login.html", context) else: context['invalid_email'] = True - return render_to_response("tbc/forgot-password.html", context) + return render_to_response("tbc/forgot-password.html", context) else: return render_to_response("tbc/forgot-password.html", context) @@ -247,6 +280,7 @@ def UpdatePassword(request): if new_password == confirm: user.set_password(new_password) user.save() + add_log(user, user, CHANGE, 'Password updated') form = UserLoginForm() context['password_updated'] = True context['form'] = form @@ -266,7 +300,7 @@ def UpdatePassword(request): context['form'] = form context['require_login'] = True return render_to_response("tbc/login.html", context) - + def SubmitBook(request): context = {} @@ -282,6 +316,8 @@ def SubmitBook(request): context['user'] = curr_user curr_book = Book.objects.order_by("-id")[0] curr_book_id = curr_book.id + proposal_id = Proposal.objects.get(accepted=curr_book) + add_log(curr_user, curr_book, CHANGE, 'Book submitted', proposal_id) return HttpResponseRedirect('/upload-content/'+str(curr_book_id)) else: context.update(csrf(request)) @@ -294,33 +330,339 @@ def SubmitBook(request): context['form'] = form context['user'] = curr_user return render_to_response('tbc/submit-book.html', context) - -def UpdateBook(request): + +def SubmitProposal(request): + curr_user = request.user + user_profile = Profile.objects.get(user=curr_user.id) + context = {} + context.update(csrf(request)) + context['user'] = curr_user + user_proposals = list(Proposal.objects.filter(user=user_profile)) + proposal_id = None + can_submit_new = True + matching_books = [] + for proposal in user_proposals: + if proposal.status != 'book completed': + can_submit_new = False + if proposal.status == 'rejected': + can_submit_new = True + proposal_id = proposal.id + + if can_submit_new: + if request.method == 'POST': + try: + proposal = Proposal.objects.get(id=proposal_id) + except: + proposal = Proposal() + proposal.user = user_profile + proposal.status = 'Pending' + proposal.save() + book_titles = request.POST.getlist('title') + book_authors = request.POST.getlist('author') + book_categories = request.POST.getlist('category') + book_pubs = request.POST.getlist('publisher_place') + book_isbns = request.POST.getlist('isbn') + book_editions = request.POST.getlist('edition') + book_years = request.POST.getlist('year_of_pub') + book_chapters = request.POST.getlist('no_chapters') + textbooks = proposal.textbooks.all() + textbooks.delete() + for item in range(3): + tempbook = TempBook(no_chapters=0) + tempbook.title = book_titles[item] + tempbook.author = book_authors[item] + tempbook.category = book_categories[item] + tempbook.publisher_place = book_pubs[item] + tempbook.isbn = book_isbns[item] + tempbook.edition = book_editions[item] + tempbook.year_of_pub = book_years[item] + tempbook.save() + proposal.textbooks.add(tempbook) + add_log(curr_user, proposal, CHANGE, 'Proposed Books', proposal.id) + return HttpResponseRedirect('/?proposal=submitted') + else: + book_forms = [] + for i in range(3): + form = BookForm() + if proposal_id: + proposal = Proposal.objects.get(id=proposal_id) + textbooks = proposal.textbooks.all() + if len(textbooks) == 3: + form.initial['title'] = textbooks[i].title + form.initial['author'] = textbooks[i].author + form.initial['category'] = textbooks[i].category + form.initial['publisher_place'] = textbooks[i].publisher_place + form.initial['isbn'] = textbooks[i].isbn + form.initial['edition'] = textbooks[i].edition + form.initial['year_of_pub'] = textbooks[i].year_of_pub + form.initial['no_chapters'] = textbooks[i].no_chapters + + book_forms.append(form) + context['book_forms'] = book_forms + return render_to_response('tbc/submit-proposal.html', context) + else: + return HttpResponseRedirect('/?proposal_pending=True') + + +def ListAICTE(request): + curr_user = request.user + user_profile = Profile.objects.get(user=curr_user.id) + user_proposals = Proposal.objects.filter(user=user_profile) + context = {} + context.update(csrf(request)) + context['user'] = curr_user + aicte_books = AicteBook.objects.filter(proposed=0) + context['aicte_books'] = aicte_books + return render_to_response('tbc/aicte-books.html', context) + + +def SubmitAICTEProposal(request, aicte_book_id=None): + curr_user = request.user + user_profile = Profile.objects.get(user=curr_user.id) + context = {} + context.update(csrf(request)) + context['user'] = curr_user + user_proposals = Proposal.objects.filter(user=user_profile) + book_proposed = AicteBook.objects.get(id=aicte_book_id) + context['aicte_book'] = book_proposed + can_submit_new = True + proposal_id = None + for proposal in user_proposals: + if proposal.status != "book completed": + can_submit_new = False + if proposal.status == 'rejected': + can_submit_new = True + proposal_id = proposal.id + if can_submit_new: + if request.method == 'POST': + book_proposed.title = request.POST['title'] + book_proposed.author = request.POST['author'] + book_proposed.category = request.POST['category'] + book_proposed.publisher_place = request.POST['publisher_place'] + book_proposed.isbn = request.POST['isbn'] + book_proposed.edition = request.POST['edition'] + book_proposed.year_of_pub = request.POST['year_of_pub'] + book_proposed.proposed = True + book_proposed.save() + try: + proposal = Proposal.objects.get(id=proposal_id) + except: + proposal = Proposal() + proposal.user = user_profile + proposal.status = 'Pending' + proposal.save() + textbooks = proposal.textbooks.all() + if textbooks: + textbooks.delete() + tempbook = TempBook(no_chapters=0) + tempbook.title = book_proposed.title + tempbook.author = book_proposed.author + tempbook.category = book_proposed.category + tempbook.publisher_place = book_proposed.publisher_place + tempbook.isbn = book_proposed.isbn + tempbook.edition = book_proposed.edition + tempbook.year_of_pub = book_proposed.year_of_pub + tempbook.save() + proposal.textbooks.add(tempbook) + print proposal.textbooks.all() + add_log(curr_user, proposal, CHANGE, 'AICTE proposal' ,proposal.id) + return HttpResponseRedirect('/?proposal=submitted') + else: + book_form = BookForm() + book_form.initial['title'] = book_proposed.title + book_form.initial['author'] = book_proposed.author + book_form.initial['publisher_place'] = book_proposed.publisher_place + book_form.initial['category'] = book_proposed.category + book_form.initial['isbn'] = book_proposed.isbn + book_form.initial['edition'] = book_proposed.edition + book_form.initial['year_of_pub'] = book_proposed.year_of_pub + context['form'] = book_form + return render_to_response('tbc/confirm-aicte-details.html', context) + else: + return HttpResponseRedirect('/?proposal_pending=True') + + +def ReviewProposals(request, proposal_id=None, textbook_id=None): + context = {} + user = request.user + if is_reviewer(user): + context['reviewer'] = user + if proposal_id: + proposal = Proposal.objects.get(id=proposal_id) + accepted_book = TempBook.objects.get(id=textbook_id) + new_book = Book() + new_book.title = accepted_book.title + new_book.author = accepted_book.author + new_book.category = accepted_book.category + new_book.publisher_place = accepted_book.publisher_place + new_book.isbn = accepted_book.isbn + new_book.edition = accepted_book.edition + new_book.year_of_pub = accepted_book.year_of_pub + new_book.no_chapters = accepted_book.no_chapters + new_book.contributor = proposal.user + new_book.reviewer = Reviewer.objects.get(pk=1) + new_book.save() + proposal.status = "samples" + proposal.accepted = new_book + proposal.save() + add_log(user, proposal, CHANGE, 'Proposal accepted', proposal.id) + return HttpResponseRedirect("/proposal-review") + else: + new_proposals = Proposal.objects.filter(status="pending") + old_proposals = [] + old_proposal_status = ['samples', 'sample disapproved', 'sample resubmitted', 'sample submitted'] + proposals = Proposal.objects.filter(status__in=old_proposal_status) + for proposal in proposals: + try: + sample_notebook = SampleNotebook.objects.get(proposal=proposal) + except: + sample_notebook = None + obj = {'proposal':proposal, 'sample':sample_notebook} + old_proposals.append(obj) + if new_proposals.count() > 0: + no_new_proposal = False + else: + no_new_proposal = True + context['no_new_proposal'] = no_new_proposal + context['proposals'] = new_proposals + context['old_proposals'] = old_proposals + return render_to_response('tbc/review-proposal.html', context) + else: + return HttpResponse("not allowed") + + +def DisapproveProposal(request, proposal_id=None): + context = {} + context.update(csrf(request)) + proposal = Proposal.objects.get(id=proposal_id) + if request.method == 'POST': + changes_required = request.POST['changes_required'] + subject = "Python-TBC: Corrections Required in the sample notebook" + message = "Hi, "+proposal.user.user.first_name+",\n"+\ + "Sample notebook for the book titled, "+proposal.accepted.title+"\ + requires following changes: \n"+\ + changes_required + add_log(request.user, proposal, CHANGE, 'Sample disapproved', + proposal_id, chat=subject + '\n' + changes_required) + context.update(csrf(request)) + proposal.status = "sample disapproved" + proposal.save() + email_send(proposal.user.user.email, subject, message) + return HttpResponseRedirect("/book-review/?mail_notify=done") + else: + context['proposal'] = proposal + return render_to_response('tbc/disapprove-sample.html', context) + + +def AllotBook(request, proposal_id=None): + context = {} + proposal = Proposal.objects.get(id=proposal_id) + proposal.status = "book alloted" + proposal.save() + subject = "Python-TBC: Book Alloted" + message = "Hi "+proposal.user.user.first_name+",\n"+\ + "The book has been alloted to you." + add_log(request.user, proposal, CHANGE, 'Book alloted', proposal_id) + email_send(proposal.user.user.email, subject, message) + return HttpResponseRedirect("/book-review/?book_alloted=done") + + +def RejectProposal(request, proposal_id=None): + context = {} + context.update(csrf(request)) + proposal = Proposal.objects.get(id=proposal_id) + if request.method == 'POST': + books = proposal.textbooks.all() + if len(books) == 1: + aicte_book = AicteBook.objects.get(isbn=books[0].isbn) + aicte_book.proposed = False + aicte_book.save() + proposal.status = 'rejected' + proposal.save() + remarks = request.POST['remarks'] + subject = "Python-TBC: Rejection of Proposal" + message = "Dear "+proposal.user.user.first_name+"\nYour proposal has been\ + rejected. "+request.POST.get('remarks') + add_log(request.user, proposal, CHANGE, 'Proposal rejected', + proposal.id, chat=subject + '\n' + remarks) + email_send(proposal.user.user.email, subject, message) + context.update(csrf(request)) + return HttpResponseRedirect("/book-review/?reject-proposal=done") + else: + context['proposal'] = proposal + return render_to_response('tbc/reject-proposal.html', context) + + +def SubmitSample(request, proposal_id=None, old_notebook_id=None): + context = {} + user = request.user + context.update(csrf(request)) + if request.method == "POST": + curr_proposal = Proposal.objects.get(id=proposal_id) + add_log(user, curr_proposal, CHANGE, 'Sample Submitted', curr_proposal.id) + if old_notebook_id: + old_notebook = SampleNotebook.objects.get(id=old_notebook_id) + old_notebook.proposal = curr_proposal + old_notebook.name = request.POST.get('ch_name_old') + old_notebook.sample_notebook = request.FILES['old_notebook'] + old_notebook.save() + curr_proposal.status = "sample resubmitted" + curr_proposal.save() + return HttpResponseRedirect('/?sample_notebook=done') + else: + sample_notebook = SampleNotebook() + sample_notebook.proposal = curr_proposal + sample_notebook.name = request.POST.get('ch_name') + sample_notebook.sample_notebook = request.FILES['sample_notebook'] + sample_notebook.save() + curr_proposal.status = "sample submitted" + curr_proposal.save() + return HttpResponseRedirect('/?sample_notebook=done') + else: + profile = Profile.objects.get(user=user) + try: + proposal = Proposal.objects.get(user=profile, status__in=['samples','sample disapproved']) + except Proposal.DoesNotExist: + return HttpResponseRedirect('/?cannot_submit_sample=True') + try: + old_notebook = SampleNotebook.objects.get(proposal=proposal) + context['has_old'] = True + context['old_notebook'] = old_notebook + context['proposal'] = proposal + return render_to_response('tbc/submit-sample.html', context) + except: + context['proposal'] = proposal + return render_to_response('tbc/submit-sample.html', context) + + +def ConfirmBookDetails(request): context = {} current_user = request.user user_profile = Profile.objects.get(user=current_user) try: - book_to_update = Book.objects.get(contributor=user_profile, approved=False) or None + proposal = Proposal.objects.get(user=user_profile, status__in=["book alloted", "codes disapproved"]) except: - return HttpResponseRedirect("/?not_found=True") - title = book_to_update.title - chapters = Chapters.objects.filter(book=book_to_update) - screenshots = ScreenShots.objects.filter(book=book_to_update) + return HttpResponseRedirect('/?no_book_alloted=true') + book_to_update = Book.objects.get(id=proposal.accepted.id) + if proposal.status == "codes disapproved": + chapters = Chapters.objects.filter(book=book_to_update) + screen_shots = ScreenShots.objects.filter(book=book_to_update) + context.update(csrf(request)) + context['book'] = book_to_update + context['chapters'] = chapters + context['screenshots'] = screen_shots + return render_to_response('tbc/update-code.html', context) if request.method == 'POST': book_form = BookForm(request.POST, instance=book_to_update) if book_form.is_valid(): - file_path = os.path.abspath(os.path.dirname(__file__)) - file_path = file_path+"/static/uploads/" - directory = file_path+book_to_update.contributor.user.first_name - os.chdir(directory) - os.popen("mv '"+title+"' '"+book_to_update.title+"'") data = book_form.save(commit=False) data.contributor = user_profile data.save() context.update(csrf(request)) context['form'] = book_form - return HttpResponseRedirect('/update-content/'+str(book_to_update.id)) + add_log(current_user, book_to_update, CHANGE, 'Book updated', proposal.id) + return HttpResponseRedirect('/submit-code/') else: book_form = BookForm() book_form.initial['title'] = book_to_update.title @@ -334,13 +676,40 @@ def UpdateBook(request): book_form.initial['reviewer'] = book_to_update.reviewer context.update(csrf(request)) context['form'] = book_form - return render_to_response('tbc/update-book.html', context) - + context['book'] = book_to_update + return render_to_response('tbc/confirm-details.html', context) -def ContentUpload(request, book_id=None): - context = {} + +def SubmitCode(request): user = request.user - curr_book = Book.objects.get(id=book_id) + curr_profile = Profile.objects.get(user=user) + context = {} + try: + curr_proposal = Proposal.objects.get(user=curr_profile, status__in=['book alloted', 'codes disapproved']) + curr_book = curr_proposal.accepted + except: + return HttpResponseRedirect('/?no_book_alloted=true') + if curr_proposal.status == "codes disapproved": + if request.method == 'POST': + chapters = Chapters.objects.filter(book=curr_book) + screen_shots = ScreenShots.objects.filter(book=curr_book) + counter = 1 + for chapter in chapters: + chapter.name = request.POST['chapter'+str(counter)] + chapter.notebook = request.FILES['notebook'+str(counter)] + chapter.save() + counter += 1 + counter = 1 + for screenshot in screen_shots: + screenshot.caption = request.POST['caption'+str(counter)] + screenshot.image = request.FILES['image'+str(counter)] + screenshot.save() + counter += 1 + curr_proposal.status = "codes submitted" + curr_proposal.save() + add_log(user, curr_book, CHANGE, 'Codes & Screenshots Resubmitted', + curr_proposal.id) + return HttpResponseRedirect('/') if request.method == 'POST': for i in range(1, curr_book.no_chapters+1): chapter = Chapters() @@ -355,6 +724,9 @@ def ContentUpload(request, book_id=None): screenshot.book = curr_book screenshot.save() book = Book.objects.order_by("-id")[0] + proposal = Proposal.objects.get(accepted=book) + proposal.status = "codes submitted" + proposal.save() subject = "Python-TBC: Book Submission" message = "Hi "+curr_book.reviewer.name+",\n"+\ "A book has been submitted on the Python TBC interface.\n"+\ @@ -366,14 +738,19 @@ def ContentUpload(request, book_id=None): "ISBN: "+curr_book.isbn+"\n"+\ "Follow the link to review the book: \n"+\ "http://tbc-python.fossee.in/book-review/"+str(curr_book.id) + log_chat = subject + '\n' + 'Book ' + curr_book.title + \ + ' has been submitted on the Python TBC interface.' + add_log(user, curr_book, CHANGE, 'Chapters and Screenshots added', + proposal.id, chat=log_chat) email_send(book.reviewer.email, subject, message) return HttpResponseRedirect('/?up=done') - context.update(csrf(request)) - context['user'] = user - context['curr_book'] = curr_book - context['no_notebooks'] = [i for i in range(1, curr_book.no_chapters+1)] - context['no_images'] = [i for i in range(1, 4)] - return render_to_response('tbc/upload-content.html', context) + else: + context.update(csrf(request)) + context['user'] = user + context['curr_book'] = curr_book + context['no_notebooks'] = [i for i in range(1, curr_book.no_chapters+1)] + context['no_images'] = [i for i in range(1, 4)] + return render_to_response('tbc/upload-content.html', context) def UpdateContent(request, book_id=None): @@ -395,6 +772,7 @@ def UpdateContent(request, book_id=None): screenshot.image = request.FILES['image'+str(i)] screenshot.book = current_book screenshot.save() + proposal = Proposal.objects.get(accepted=current_book) subject = "Python-TBC: Book Updated" message = "Hi "+current_book.reviewer.name+",\n"+\ "Submission for a book has been updated on the Python TBC interface.\n"+\ @@ -406,6 +784,10 @@ def UpdateContent(request, book_id=None): "ISBN: "+current_book.isbn+"\n"+\ "Follow the link to review the book: \n"+\ "http://dev.fossee.in/book-review/"+str(current_book.id) + log_chat = subject + '\n' + current_book.title +\ + ' book has been updated on the Python TBC interface.' + add_log(user, current_book, CHANGE, 'book updated', proposal.id, + chat=log_chat) email_send(current_book.reviewer.email, subject, message) return HttpResponseRedirect('/?update_book=done') else: @@ -461,7 +843,7 @@ def BookDetails(request, book_id=None): context['images'] = images context['book'] = book return render_to_response('tbc/book-details.html', context) - + def BookReview(request, book_id=None): context = {} @@ -470,9 +852,13 @@ def BookReview(request, book_id=None): book = Book.objects.get(id=book_id) chapters = Chapters.objects.filter(book=book).order_by('name') images = ScreenShots.objects.filter(book=book) + proposal = Proposal.objects.get(accepted=book) + logs = ActivityLog.objects.filter(proposal_id=proposal.id) + context['logs'] = logs context['chapters'] = chapters context['images'] = images context['book'] = book + context['proposal'] = proposal context['reviewer'] = request.user context.update(csrf(request)) return render_to_response('tbc/book-review-details.html', context) @@ -482,6 +868,8 @@ def BookReview(request, book_id=None): if 'mail_notify' in request.GET: context['mail_notify'] = True books = Book.objects.filter(approved=False) + approved_books = Book.objects.filter(approved=True) + context['approved_books'] = approved_books context['books'] = books context['reviewer'] = request.user context.update(csrf(request)) @@ -498,6 +886,9 @@ def ApproveBook(request, book_id=None): book = Book.objects.get(id=book_id) book.approved = True book.save() + proposal = Proposal.objects.get(accepted=book) + proposal.status = "book completed" + proposal.save() file_path = os.path.abspath(os.path.dirname(__file__)) copy_path = "/".join(file_path.split("/")[1:-2]) copy_path = "/"+copy_path+"/Python-Textbook-Companions/" @@ -531,6 +922,8 @@ def ApproveBook(request, book_id=None): "IIT Bombay, Powai, Mumbai - 400076\n"+\ "Kindly, write Python Texbook Companion on top of the envelope.\n\n\n"+\ "Regards,\n"+"Python TBC,\n"+"FOSSEE, IIT - Bombay" + add_log(user, book, CHANGE, 'Book approved', proposal.id, + chat=subject + '\n' + message) email_send(book.reviewer.email, subject, message) context['user'] = user return HttpResponseRedirect("/book-review/?book_review=done") @@ -541,19 +934,24 @@ def ApproveBook(request, book_id=None): return HttpResponseRedirect("/book-review/"+book_id) else: return render_to_response('tbc/forbidden.html') - + def NotifyChanges(request, book_id=None): context = {} if is_reviewer(request.user): book = Book.objects.get(id=book_id) + proposal = Proposal.objects.get(accepted=book) if request.method == 'POST': + proposal.status = "codes disapproved" + proposal.save() changes_required = request.POST['changes_required'] subject = "Python-TBC: Corrections Required" message = "Hi, "+book.contributor.user.first_name+",\n"+\ "Book titled, "+book.title+" requires following changes: \n"+\ changes_required context.update(csrf(request)) + add_log(request.user, book, CHANGE, 'Changes notification', + proposal.id, chat=subject+'\n'+changes_required) email_send(book.contributor.user.email, subject, message) return HttpResponseRedirect("/book-review/?mail_notify=done") else: @@ -665,3 +1063,26 @@ def RedirectToIpynb(request, notebook_path=None): notebook = "/".join(notebook) redirect_url = "https://ipynb.fossee.in/"+notebook return redirect(redirect_url) + + +# ajax views +@csrf_exempt +def ajax_matching_books(request): + titles = request.POST["titles"] + titles = json.loads(titles) + matches = [] + i = 1 + flag = None + for title in titles: + if title: + match = TempBook.objects.filter(title__icontains=title) + if match: + flag = True + matches.append(match) + else: + matches.append(None) + context = { + 'matches': matches, + 'flag': flag + } + return render_to_response('tbc/ajax-matching-books.html', context) |