diff options
-rw-r--r-- | static/forums/templates/user-login.html | 43 | ||||
-rw-r--r-- | static/website/css/main.css | 42 | ||||
-rw-r--r-- | static/website/js/thread-user.js | 32 | ||||
-rw-r--r-- | static/website/templates/base.html | 14 | ||||
-rw-r--r-- | static/website/templates/get-question.html | 23 | ||||
-rw-r--r-- | static/website/templates/index.html | 30 | ||||
-rw-r--r-- | static/website/templates/notifications.html | 33 | ||||
-rw-r--r-- | static/website/templates/notify.html | 7 | ||||
-rw-r--r-- | static/website/templates/user-questions.html | 36 | ||||
-rw-r--r-- | static/website/templates/user-replies.html | 36 | ||||
-rw-r--r-- | website/models.py | 7 | ||||
-rw-r--r-- | website/templatetags/notify.py | 23 | ||||
-rw-r--r-- | website/urls.py | 6 | ||||
-rw-r--r-- | website/views.py | 94 |
14 files changed, 385 insertions, 41 deletions
diff --git a/static/forums/templates/user-login.html b/static/forums/templates/user-login.html index 6ac4fee..27f5a1f 100644 --- a/static/forums/templates/user-login.html +++ b/static/forums/templates/user-login.html @@ -1,4 +1,39 @@ -<form action="/accounts/login/" method="POST"> {% csrf_token %} - {{ form.as_p }} - <input type="submit" value="Login"> -</form> +{% extends "website/templates/base.html" %} +{% load widget_tweaks %} +{% block content %} +<br><br><br> +<div class="row"> + <div class="col-lg-6" style="border-right: 1px dashed #424242;"> + <h4>Please login with your <br>Spoken-Tutorial.org account.</h4> + <form action="/accounts/login/" method="POST"> {% csrf_token %} + {% with WIDGET_ERROR_CLASS='field_error' %} + <div class="form-group"> + <label for="id_username">Username:</label> + {% render_field form.username class+="form-control" %} + </div> + + <div class="form-group"> + <label for="id_username">Password:</label> + {% render_field form.password class+="form-control" %} + </div> + + <input class="btn btn-sm btn-primary" type="submit" value="Login"> + {% endwith %} + </form> + </div> <!-- /.col --> + + <div class="col-lg-6"> + <h4>Rules and Regulations</h4> + <ul> + <li>This forum is a place to discuss questions and doubts related to the Spoken-Tutorial's</li> + <li>Please restrain yourself from using abusive language.</li> + <li>This is not a place for self promotion.</li> + <li>Any violation of the above may lead to the permanent account deletion.</li> + </ul> + <h4>Dont have a Spoken-Tutorial.org account yet ?</h4> + <p> + <a class="btn btn-sm btn-success" href="#">Register</a> + </p> + </div> <!-- /.col --> +</div> <!-- /.row --> +{% endblock %} diff --git a/static/website/css/main.css b/static/website/css/main.css index 7a58a4c..a5f8c81 100644 --- a/static/website/css/main.css +++ b/static/website/css/main.css @@ -1,3 +1,8 @@ +/* override bootstrap */ +.navbar>.container .navbar-brand { + margin-left: 0; +} +/* main styles */ .container { max-width: 970px; } @@ -22,7 +27,7 @@ } #content .editable { padding: 15px 5px 15px 5px; - background: lightyellow; + background: #F0F0F0; } #content .question .title a{ padding: 0 0 7px 0; @@ -60,12 +65,14 @@ background: #f5f5f5; color: #424242; } -#content .question .user { +#content .question .meta{ position: absolute; right: 0px; bottom: 0px; - padding: 2px 7px; +} +#content .question .user{ background: #f5f5f5; + padding: 2px 7px; } #similar-link { display: none; @@ -92,7 +99,8 @@ #content .reply { position: relative; border-bottom: 1px solid #f5f5f5; - padding: 20px 0; + padding-top: 20px; + padding-bottom: 20px; margin: 10px 0px; } #content .reply .body { @@ -114,3 +122,29 @@ .field_error { border: 1px solid red; } +.notification { + position: relative; + padding: 15px; + margin: 10px 0; + border-left: 2px solid #424242; + background: #f7f7f7; +} +.notification .remove { + position: absolute; + right: 10px; + top: 15px; +} +.my-question, +.my-reply { + position: relative; + margin: 10px auto; + padding: 15px; + border-left: 2px solid #424242; + background: #f7f7f7; +} +.my-question .date, +.my-reply .date { + position: absolute; + right: 5px; + bottom: 5px; +} diff --git a/static/website/js/thread-user.js b/static/website/js/thread-user.js index 698a946..a8e7eee 100644 --- a/static/website/js/thread-user.js +++ b/static/website/js/thread-user.js @@ -21,7 +21,7 @@ $(document).ready(function() { $questionInstance = $("#questionInstance"); /* make the question editable and show modify */ - $question.addClass("editable"); + //$question.addClass("editable"); $question_modify.show(); /* edit and save click events */ @@ -43,8 +43,9 @@ $(document).ready(function() { $(this).prev().css("display", "block"); /* make the ajax call */ - var id_length = $question_save.attr("id").length; - var question_id = parseInt($question_save.attr("id").substr(id_length-1)); + //var id_length = $question_save.attr("id").length; + //var question_id = parseInt($question_save.attr("id").substr(id_length-1)); + var question_id = parseInt($question_save.data("qid")); console.log(question_id); var question_body = $questionInstance.html(); $.ajax({ @@ -76,9 +77,9 @@ $(document).ready(function() { replyNicEditor.panelInstance('replyNicPanel'); $reply_edit.click(function() { - var reply_body = $(this).data("target"); - console.log(reply_body); - replyNicEditor.addInstance(reply_body); + var target = $(this).data("target"); + console.log(target); + replyNicEditor.addInstance(target); $(this).parents("div.reply").prepend($replyPanelWrapper); $replyPanelWrapper.show(); $('#replyPanelWrapper .nicEdit-panelContain').parent().width('100%'); @@ -88,12 +89,27 @@ $(document).ready(function() { }); $reply_save.click(function() { - var reply_body = $(this).data("target"); - replyNicEditor.removeInstance(reply_body); + var target = $(this).data("target"); + replyNicEditor.removeInstance(target); $replyPanelWrapper.hide(); $('#replyPanelWrapper .nicEdit-panelContain').parent().width('100%'); $(this).hide(); $(this).prev().show(); + + var reply_id = parseInt($(this).data("rid")); + var reply_body = $("#"+target).html(); + + $.ajax({ + url: "/ajax-reply-update/", + type: "POST", + data: { + reply_id: reply_id, + reply_body: reply_body + }, + success: function(data) { + console.log(data); + } + }); }); }); diff --git a/static/website/templates/base.html b/static/website/templates/base.html index 5e397e8..c71e3ef 100644 --- a/static/website/templates/base.html +++ b/static/website/templates/base.html @@ -39,9 +39,17 @@ {{ user }}<b class="caret"></b> </a> <ul class="dropdown-menu"> - <li><a href="#">My Questions</a></li> - <li><a href="#">My Replies</a></li> - <li><a href="#">Notifications</a></li> + <li><a href="{% url 'website:user_questions' user.id %}">My Questions</a></li> + <li><a href="{% url 'website:user_replies' user.id %}">My Replies</a></li> + <li> + <a href="{% url 'website:user_notifications' user.id %}"> + Notifications + <span class="badge" style="background:#a26dc8; color:#ffffff;"> + {% load notify %} + {% notification_count user.id %} + </span> + </a> + </li> <li class="divider"></li> <li><a href="{% url 'user_logout' %}">Logout</a></li> </ul> diff --git a/static/website/templates/get-question.html b/static/website/templates/get-question.html index 5e68aed..bd63d02 100644 --- a/static/website/templates/get-question.html +++ b/static/website/templates/get-question.html @@ -2,13 +2,13 @@ {% load static %} {% load widget_tweaks %} {% block content %} -<div class="question"> +<div class="question {% ifequal question.user|stringformat:'s' user|stringformat:'s' %}editable{% endifequal %}"> <div class="title"> <a href=""> {{ question.title }} </a> </div> <div id="questionNicPanel"></div> - <div id="questionInstance" class="body"> + <div id="{% ifequal question.user|stringformat:'s' user|stringformat:'s' %}questionInstance{% endifequal %}" class="body"> {{ question.body|safe }} </div> <br> @@ -48,7 +48,7 @@ <span class="modify"> {% ifequal question.uid|stringformat:'s' user.id|stringformat:'s' %} <a class="edit btn btn-xs btn-info" href="#">Edit</a> - <a id="save-{{ question.id }}" class="save btn btn-xs btn-success" href="#">Save</a> + <a class="save btn btn-xs btn-success" data-qid="{{ question.id }}" href="#">Save</a> {% endifequal %} </span> @@ -65,7 +65,7 @@ </div> {% for reply in replies %} - <div class="reply {% ifequal reply.uid|stringformat:'s' user.id|stringformat:'s' %}editable{% endifequal %}"> + <div class="reply {% ifequal reply.uid|stringformat:'s' user.id|stringformat:'s' %}editable{% endifequal %}" id="reply{{reply.id}}"> <div class="body" id="body{{ reply.id }}"> {{ reply.body|safe }} @@ -78,7 +78,7 @@ {% ifequal reply.uid|stringformat:'s' user.id|stringformat:'s' %} <span class="modify" style="display:block"> <a class="edit btn btn-xs btn-info vs" href="#body{{ reply.id}}" data-target="body{{ reply.id }}">Edit</a> - <a id="save-{{ question.id }}" class="save btn btn-xs btn-success vs" href="#" data-target="body{{ reply.id }}">Save</a> + <a class="save btn btn-xs btn-success vs" data-target="body{{ reply.id }}" data-rid="{{ reply.id }}" href="#">Save</a> </span> {% endifequal %} </div> <!-- /.reply --> @@ -111,16 +111,5 @@ {% endblock %} {% block javascript %} - {% if user.is_authenticated %} - {% ifequal question.user|stringformat:"s" user|stringformat:"s" %} - <script src="{% static 'website/js/thread-user.js' %}"></script> - {% else %} - <script src="{% static 'website/js/thread-user.js' %}"></script> - <script type="text/javascript"> - $(document).ready(function() { - $(".question .body").removeAttr("id"); - }); - </script> - {% endifequal %} - {% endif %} + <script src="{% static 'website/js/thread-user.js' %}"></script> {% endblock %} diff --git a/static/website/templates/index.html b/static/website/templates/index.html index 43d98f0..ef840bc 100644 --- a/static/website/templates/index.html +++ b/static/website/templates/index.html @@ -1,5 +1,6 @@ {% extends 'website/templates/base.html' %} {% block content %} +{% load count_tags %} <h4><u>Recent Questions</u></h4> {% for question in questions %} <div class="question"> @@ -39,9 +40,34 @@ </small> </span> - <span class="user"> - {{ question.user }} + <span class="meta"> + <small> + <i> + {{ question.date_created }} + </i> + </small> + + <span class="user"> + {{ question.user }} + </span> </span> </div> <!-- /.question --> {% endfor %} + + {% if total > 10 %} + <ul class="pagination pull-right"> + {% for i in total|get_range:"0,10" %} + <li> + <a href="{% url 'website:home' %}?marker={{ i }}"> + {% if i == marker %} + <strong>{{ i|div:"10"|inc }}</strong> + {% else %} + {{ i|div:"10"|inc }} + {% endif %} + </a> + </li> + {% endfor %} + </ul> + {% endif %} + {% endblock %} diff --git a/static/website/templates/notifications.html b/static/website/templates/notifications.html new file mode 100644 index 0000000..aa3adce --- /dev/null +++ b/static/website/templates/notifications.html @@ -0,0 +1,33 @@ +{% extends 'website/templates/base.html' %} +{% load notify %} +{% block content%} + <h4 class="pull-left">Notifications</h4> + <a class="btn btn-xs btn-warning pull-right" href="{% url "website:clear_notifications" %}" style="margin-top: 7px;"> + Clear All + </a> + <div class="clearfix"></div> + {% for notification in notifications %} + {% get_notification notification.id %} + {% endfor %} +{% endblock %} + +{% block javascript %} + <script type="text/javascript"> + $(document).ready(function() { + $(".remove").click(function() { + $(this).parent(".notification").slideUp(); + var notification_id = $(this).data("nid"); + $.ajax({ + url: "/ajax-notification-remove/", + type: "POST", + data: { + notification_id: notification_id + }, + success: function(data) { + console.log(data); + } + }); + }); + }); + </script> +{% endblock %} diff --git a/static/website/templates/notify.html b/static/website/templates/notify.html new file mode 100644 index 0000000..7251f1b --- /dev/null +++ b/static/website/templates/notify.html @@ -0,0 +1,7 @@ +<div class="notification"> + <a href=""><strong>{{ reply.user }}</strong> replies to <strong>{{ question.title }}</strong></a> / + {{ reply.body|safe }} + <a class="remove" data-nid="{{ notification.id }}" href="#"> + <span class="glyphicon glyphicon-remove-circle"></span> + </a> +</div> <!-- /.notification --> diff --git a/static/website/templates/user-questions.html b/static/website/templates/user-questions.html new file mode 100644 index 0000000..e3d2ab6 --- /dev/null +++ b/static/website/templates/user-questions.html @@ -0,0 +1,36 @@ +{% extends 'website/templates/base.html' %} +{% load count_tags %} +{% block content %} + <h4>My Questions</h4> + {% for question in questions %} + <div class="my-question"> + <span class="title"> + {{ question.title }} + </span> + <br> + <span class="date"> + <small> + Asked on: + {{ question.date_created }} + </small> + </span> + </div> + {% endfor %} + + {% if total > 10 %} + <ul class="pagination pull-right"> + {% for i in total|get_range:"0,10" %} + <li> + <a href="{% url 'website:user_questions' user.id %}?marker={{ i }}"> + {% if i == marker %} + <strong>{{ i|div:"10"|inc }}</strong> + {% else %} + {{ i|div:"10"|inc }} + {% endif %} + </a> + </li> + {% endfor %} + </ul> + {% endif %} + +{% endblock %} diff --git a/static/website/templates/user-replies.html b/static/website/templates/user-replies.html new file mode 100644 index 0000000..c31b854 --- /dev/null +++ b/static/website/templates/user-replies.html @@ -0,0 +1,36 @@ +{% extends 'website/templates/base.html' %} +{% load count_tags %} +{% block content %} + <h4>My Replies</h4> + {% for reply in replies%} + <div class="my-reply"> + <span class="body"> + {{ reply.body|safe }} + </span> + <br> + <span class="date"> + <small> + Replied on: + {{ reply.date_created }} + </small> + </span> + </div> + {% endfor %} + + {% if total > 10 %} + <ul class="pagination pull-right"> + {% for i in total|get_range:"0,10" %} + <li> + <a href="{% url 'website:user_replies' user.id %}?marker={{ i }}"> + {% if i == marker %} + <strong>{{ i|div:"10"|inc }}</strong> + {% else %} + {{ i|div:"10"|inc }} + {% endif %} + </a> + </li> + {% endfor %} + </ul> + {% endif %} + +{% endblock %} diff --git a/website/models.py b/website/models.py index 22a1fe8..52575b8 100644 --- a/website/models.py +++ b/website/models.py @@ -33,6 +33,13 @@ class Reply(models.Model): user = User.objects.get(id=self.uid) return user.username +class Notification(models.Model): + uid = models.IntegerField() + pid = models.IntegerField() + qid = models.IntegerField() + rid = models.IntegerField() + date_created = models.DateTimeField(auto_now_add=True) + # CDEEP database created using inspectdb arg of manage.py class TutorialDetails(models.Model): id = models.IntegerField(primary_key=True) diff --git a/website/templatetags/notify.py b/website/templatetags/notify.py new file mode 100644 index 0000000..4c6692a --- /dev/null +++ b/website/templatetags/notify.py @@ -0,0 +1,23 @@ +from django import template + +from website.models import Question, Reply, Notification + +register = template.Library() + +def get_notification(nid): + notification = Notification.objects.get(pk=nid) + question = Question.objects.get(pk=notification.qid); + reply = Reply.objects.get(pk=notification.rid) + context = { + 'notification': notification, + 'question': question, + 'reply': reply, + } + return context +register.inclusion_tag('website/templates/notify.html')(get_notification) + +def notification_count(user_id): + count = Notification.objects.filter(uid=user_id).count() + return count +register.simple_tag(notification_count) + diff --git a/website/urls.py b/website/urls.py index c385ea0..20f8201 100644 --- a/website/urls.py +++ b/website/urls.py @@ -9,10 +9,16 @@ urlpatterns = patterns('', url(r'^filter/(?P<category>[^/]+)/(?P<tutorial>[^/]+)/(?P<minute_range>[^/]+)/$', 'website.views.filter', name='filter'), url(r'^filter/(?P<category>[^/]+)/(?P<tutorial>[^/]+)/(?P<minute_range>[^/]+)/(?P<second_range>[^/]+)/$', 'website.views.filter', name='filter'), url(r'^new-question/$', 'website.views.new_question', name='new_question'), + url(r'^user/(?P<user_id>\d+)/notifications/$', 'website.views.user_notifications', name='user_notifications'), + url(r'^user/(?P<user_id>\d+)/questions/$', 'website.views.user_questions', name='user_questions'), + url(r'^user/(?P<user_id>\d+)/replies/$', 'website.views.user_replies', name='user_replies'), + url(r'^clear-notifications/$', 'website.views.clear_notifications', name='clear_notifications'), # Ajax helpers url(r'^ajax-tutorials/$', 'website.views.ajax_tutorials', name='ajax_tutorials'), url(r'^ajax-duration/$', 'website.views.ajax_duration', name='ajax_duration'), url(r'^ajax-question-update/$', 'website.views.ajax_question_update', name='ajax_question_update'), + url(r'^ajax-reply-update/$', 'website.views.ajax_reply_update', name='ajax_reply_update'), url(r'^ajax-similar-questions/$', 'website.views.ajax_similar_questions', name='ajax_similar_questions'), + url(r'^ajax-notification-remove/$', 'website.views.ajax_notification_remove', name='ajax_notification_remove'), ) diff --git a/website/views.py b/website/views.py index 538d90e..b6c6670 100644 --- a/website/views.py +++ b/website/views.py @@ -5,7 +5,7 @@ from django.views.decorators.csrf import csrf_exempt from django.contrib.auth.decorators import login_required from django.db.models import Q -from website.models import Question, Reply, TutorialDetails, TutorialResources +from website.models import Question, Reply, Notification, TutorialDetails, TutorialResources from website.forms import NewQuestionForm, ReplyQuesitionForm from website.helpers import get_video_info @@ -28,10 +28,17 @@ categories = [ ] def home(request): - questions = Question.objects.all().order_by('date_created').reverse()[:10] + marker = 0 + if 'marker' in request.GET: + marker = int(request.GET['marker']) + + total = Question.objects.all().count() + total = int(total - (total % 10 - 10)) + questions = Question.objects.all().order_by('date_created').reverse()[marker:marker+10] context = { 'questions': questions, - 'user': request.user + 'total': total, + 'marker': marker } return render(request, 'website/templates/index.html', context) @@ -64,6 +71,13 @@ def question_reply(request): reply.question = question reply.body = body reply.save() + if question.uid != request.user.id: + notification = Notification() + notification.uid = question.uid + notification.pid = request.user.id + notification.qid = qid + notification.rid = reply.id + notification.save() return HttpResponseRedirect('/question/'+str(qid)) def filter(request, category=None, tutorial=None, minute_range=None, second_range=None): @@ -112,6 +126,58 @@ def new_question(request): context.update(csrf(request)) return render(request, 'website/templates/new-question.html', context) +@login_required +def user_questions(request, user_id): + marker = 0 + if 'marker' in request.GET: + marker = int(request.GET['marker']) + + if str(user_id) == str(request.user.id): + total = Question.objects.filter(uid=user_id).count() + total = int(total - (total % 10 - 10)) + questions = Question.objects.filter(uid=user_id).order_by('date_created').reverse()[marker:marker+10] + + context = { + 'questions': questions, + 'total': total, + 'marker': marker + } + return render(request, 'website/templates/user-questions.html', context) + return HttpResponse("go away") + +@login_required +def user_replies(request, user_id): + marker = 0 + if 'marker' in request.GET: + marker = int(request.GET['marker']) + + if str(user_id) == str(request.user.id): + total = Reply.objects.filter(uid=user_id).count() + total = int(total - (total % 10 - 10)) + replies =Reply.objects.filter(uid=user_id).order_by('date_created').reverse()[marker:marker+10] + context = { + 'replies': replies, + 'total': total, + 'marker': marker + } + return render(request, 'website/templates/user-replies.html', context) + return HttpResponse("go away") + +@login_required +def user_notifications(request, user_id): + if str(user_id) == str(request.user.id): + notifications = Notification.objects.filter(uid=user_id).order_by('date_created').reverse() + context = { + 'notifications': notifications + } + return render(request, 'website/templates/notifications.html', context) + return HttpResponse("go away ...") + +@login_required +def clear_notifications(request): + Notification.objects.filter(uid=request.user.id).delete() + return HttpResponseRedirect("/user/{}/notifications/".format(request.user.id)) + @csrf_exempt def ajax_tutorials(request): if request.method == 'POST': @@ -157,6 +223,18 @@ def ajax_question_update(request): return HttpResponse("saved") @csrf_exempt +def ajax_reply_update(request): + if request.method == 'POST': + rid = request.POST['reply_id'] + body = request.POST['reply_body'] + reply= get_object_or_404(Reply, pk=rid) + if reply: + if reply.uid == request.user.id: + reply.body = body + reply.save() + return HttpResponse("saved") + +@csrf_exempt def ajax_similar_questions(request): if request.method == 'POST': category = request.POST['category'] @@ -171,3 +249,13 @@ def ajax_similar_questions(request): } return render(request, 'website/templates/ajax-similar-questions.html', context); +@csrf_exempt +def ajax_notification_remove(request): + if request.method == "POST": + nid = request.POST["notification_id"] + notification = Notification.objects.get(pk=nid) + if notification: + if notification.uid == request.user.id: + notification.delete() + return HttpResponse("removed") + return HttpResponse("failed") |