summaryrefslogtreecommitdiff
path: root/tbc
diff options
context:
space:
mode:
authorhardythe12014-10-30 17:39:43 +0530
committerhardythe12014-10-30 17:39:43 +0530
commitf604c51131f625e26f1ac95d9464f59b8d89078b (patch)
tree1c5e384aacdb3b27ce2f7845ac4dadb8351dc615 /tbc
parentbb5688c683a80c5de77505e42be228f46c369254 (diff)
parent503d1295c4bd146d6a36a2ddb64cb2a27211705c (diff)
downloadPython-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.py4
-rw-r--r--tbc/forms.py4
-rw-r--r--tbc/models.py76
-rwxr-xr-xtbc/templates/base.html57
-rw-r--r--tbc/templates/tbc/aicte-books.html25
-rw-r--r--tbc/templates/tbc/ajax-matching-books.html24
-rw-r--r--tbc/templates/tbc/book-review-details.html54
-rw-r--r--tbc/templates/tbc/book-review.html6
-rw-r--r--tbc/templates/tbc/confirm-aicte-details.html31
-rw-r--r--tbc/templates/tbc/confirm-details.html57
-rw-r--r--tbc/templates/tbc/disapprove-sample.html17
-rw-r--r--tbc/templates/tbc/reject-proposal.html17
-rw-r--r--tbc/templates/tbc/review-proposal.html98
-rw-r--r--tbc/templates/tbc/submit-proposal.html79
-rw-r--r--tbc/templates/tbc/submit-sample.html53
-rw-r--r--tbc/templates/tbc/update-book.html2
-rw-r--r--tbc/templates/tbc/update-code.html22
-rw-r--r--tbc/templates/tbc/upload-content.html10
-rw-r--r--tbc/urls.py19
-rwxr-xr-xtbc/views.py497
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="#">&times;</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="#">&times;</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="#">&times;</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="#">&times;</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="#">&times;</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: &nbsp;&nbsp;<td>{{ book.author }}
<tr><td>Publisher: &nbsp;&nbsp;<td>{{ book.publisher_place }}
@@ -33,4 +42,21 @@
<tr><td>Contributor: &nbsp;&nbsp;<td>{{ book.contributor.user.first_name }} {{ book.contributor.user.last_name }}
<tr><td>Email: &nbsp;&nbsp;<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 &amp; <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)