From bf20363adec8afed8d8e10ad7e0b641c51568cff Mon Sep 17 00:00:00 2001 From: ashwinishinde Date: Fri, 19 Jun 2015 15:39:01 +0530 Subject: Subject: Added Vote Functionality Description: 1) Implementation of vote for question 2) Added CSS for vote-up and vope-down --- forums/settings.py | 7 +- forums/urls.py | 1 + requirements.txt | 1 + static/website/css/main.css | 83 +++++++++++ static/website/images/down1-off.png | Bin 0 -> 483 bytes static/website/images/down1-on.png | Bin 0 -> 285 bytes static/website/images/up1-off.png | Bin 0 -> 458 bytes static/website/images/up1-on.png | Bin 0 -> 274 bytes static/website/templates/base.html | 9 ++ static/website/templates/get-question.html | 214 +++++++++++++++-------------- static/website/templates/questions.html | 2 +- static/website/templates/search.html | 1 + website/models.py | 10 +- website/urls.py | 4 +- website/views.py | 58 +++++++- 15 files changed, 282 insertions(+), 108 deletions(-) create mode 100644 static/website/images/down1-off.png create mode 100644 static/website/images/down1-on.png create mode 100644 static/website/images/up1-off.png create mode 100644 static/website/images/up1-on.png diff --git a/forums/settings.py b/forums/settings.py index b556319..c21d2e0 100644 --- a/forums/settings.py +++ b/forums/settings.py @@ -142,6 +142,8 @@ INSTALLED_APPS = ( 'compressor', 'debug_toolbar', 'captcha', + 'googlesearch', + 'gtm', #'migrate_spoken', ) @@ -177,11 +179,12 @@ LOGGING = { TEMPLATE_CONTEXT_PROCESSORS += ( 'django.core.context_processors.request', 'website.context_processors.admin_processor', + ) COMPRESS_ROOT = PROJECT_DIR + "/static/" -COMPRESS_ENABLED = True # disable in production Env -HTML_MINIFY = True # disable in production Env +COMPRESS_ENABLED = False # disable in production Env +HTML_MINIFY = False # disable in production Env HTML_MINIFY = HTML_MINIFY RECAPTCHA_PUBLIC_KEY = '6LemngMTAAAAAAC0Fkv0CQcavkTIIJ3LTDzi9gMq' diff --git a/forums/urls.py b/forums/urls.py index 31c679b..4584b66 100644 --- a/forums/urls.py +++ b/forums/urls.py @@ -23,4 +23,5 @@ urlpatterns = patterns('', url(r"^accounts/confirm/(?P\w+)/(?P[\w. @-]+)/$", 'forums.views.confirm', name='confirm'), url(r"^accounts/profile/(?P[\w. @-]+)/$", 'forums.views.account_profile', name='profile'), url(r"^accounts/view-profile/(?P[\w. @-]+)/$", 'forums.views.account_view_profile', name='view_profile'), + url(r'^search/', include('googlesearch.urls')), ) diff --git a/requirements.txt b/requirements.txt index e7beaee..1adb4bb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,3 +13,4 @@ html5lib==1.0b3 six==1.6.1 sqlparse==0.1.11 wsgiref==0.1.2 +django-googlesearch diff --git a/static/website/css/main.css b/static/website/css/main.css index 20f220a..774871e 100644 --- a/static/website/css/main.css +++ b/static/website/css/main.css @@ -248,6 +248,8 @@ table .question a{ margin: 5px 0px; } #content .answer .body { + padding-bottom: 10px; + ,, } #content .answer .user { padding: 2px 7px; @@ -401,3 +403,84 @@ table .question a{ font-size: 22px; overflow: hidden; } + + +.votes { + color: rgb(85, 85, 85); + padding-top: 8px; + padding-bottom: 8px; + text-align: center; +} + +.vote span { + display: block; + color: rgb(128, 129, 133); + font-weight: normal; +} + +.vote-count-post { + display: block; + font-size: 17px; + +} + +.votecell { + background:#ffffff; + + float:left; + width:60px; + height:100px; + margin-right:5px; + padding:0; + border-radius: 3px; +} + +.post-text { + word-wrap: break-word; + width: 660px; + font-size: 107%; + margin-bottom: 5px; + margin-right: 5px; + margin-right-value: 5px; + margin-right-ltr-source: physical; + margin-right-rtl-source: physical; + line-height: 130%; +} + +.post-taglist { + margin-bottom: 10px; + clear: both; +} + +.vote { + text-align: center; +} + + +.vote-up-off, .vote-up-on, .vote-down-off, .vote-down-on, .star-on, .star-off, .comment-up-off, .comment-up-on, .comment-flag, .flag-off, .vote-accepted-off, .vote-accepted-on { + text-indent: -9999em; + font-size: 1px; +} + +.vote-up-off, .vote-up-on, .vote-down-off, .vote-down-on, .star-on, .star-off { + background-position: 0px -265px; + display: block; + margin: 0px auto; + margin-top: 0px; + margin-right-value: auto; + margin-bottom: 0px; + margin-left-value: auto; + margin-left-ltr-source: physical; + margin-left-rtl-source: physical; + margin-right-ltr-source: physical; + margin-right-rtl-source: physical; + width: 41px; + height: 25px; +} + + +.space { + padding-top: 20px; +} + + diff --git a/static/website/images/down1-off.png b/static/website/images/down1-off.png new file mode 100644 index 0000000..c720b49 Binary files /dev/null and b/static/website/images/down1-off.png differ diff --git a/static/website/images/down1-on.png b/static/website/images/down1-on.png new file mode 100644 index 0000000..84f1a23 Binary files /dev/null and b/static/website/images/down1-on.png differ diff --git a/static/website/images/up1-off.png b/static/website/images/up1-off.png new file mode 100644 index 0000000..9fecb01 Binary files /dev/null and b/static/website/images/up1-off.png differ diff --git a/static/website/images/up1-on.png b/static/website/images/up1-on.png new file mode 100644 index 0000000..f756707 Binary files /dev/null and b/static/website/images/up1-on.png differ diff --git a/static/website/templates/base.html b/static/website/templates/base.html index b174d69..b5d087b 100644 --- a/static/website/templates/base.html +++ b/static/website/templates/base.html @@ -21,6 +21,15 @@ {% endcompress %} + + + +
diff --git a/static/website/templates/get-question.html b/static/website/templates/get-question.html index c31259b..7c93803 100644 --- a/static/website/templates/get-question.html +++ b/static/website/templates/get-question.html @@ -9,17 +9,47 @@ {% endblock %} {% block content %} + saving . . . saved
+ + +
+ + + + +
+
+ {% ifequal thisUserUpvote 0 %} + + {% else %} + + {% endifequal %} + + + {{ net_count }} + + + {% ifequal thisUserDownvote 0 %} + + {% else %} + + {% endifequal %} +
+ +
{{ question.title }}
+ +
Title
Question
@@ -62,10 +92,13 @@ {{ question.user }} +
+
+

Answers:

+ + + - +{% endblock %} + +{% block javascript %} + -{% endblock %} + + - - + {% endblock %} diff --git a/static/website/templates/questions.html b/static/website/templates/questions.html index 98d016d..96f596d 100644 --- a/static/website/templates/questions.html +++ b/static/website/templates/questions.html @@ -49,8 +49,8 @@ {{ question.answer_set.count }} + - {{ question.user|truncatechars:10 }} diff --git a/static/website/templates/search.html b/static/website/templates/search.html index a7ac917..c374b47 100644 --- a/static/website/templates/search.html +++ b/static/website/templates/search.html @@ -1,4 +1,5 @@ {% extends 'website/templates/base.html' %} +{% load i18n googlesearch_inclusion_tags %} {% load static %} {% block content %} diff --git a/website/models.py b/website/models.py index c7e43aa..b0a9fc3 100644 --- a/website/models.py +++ b/website/models.py @@ -23,13 +23,14 @@ class Issue(models.Model): class Question(models.Model): user = models.ForeignKey(User) category = models.ForeignKey(FossCategory) - #tutorial = models.ForeignKey(Issue) title = models.CharField(max_length=200) body = models.TextField() date_created = models.DateTimeField(auto_now_add=True) date_modified = models.DateTimeField(auto_now=True) views = models.IntegerField(default=1) - # votes = models.IntegerField(default=0) + userUpVotes = models.ManyToManyField(User, blank=True, related_name='postUpVotes') + userDownVotes = models.ManyToManyField(User, blank=True, related_name='postDownVotes') + num_votes = models.IntegerField(default=0) def __unicode__(self): return '%s' % (self.user) @@ -53,7 +54,10 @@ class Answer(models.Model): body = models.TextField() date_created = models.DateTimeField(auto_now_add=True) date_modified = models.DateTimeField(auto_now=True) - # votes = models.IntegerField(default=0) + #userUpVotes = models.ManyToManyField(User, blank=True, related_name='postUpVotes') + #userDownVotes = models.ManyToManyField(User, blank=True, related_name='postDownVotes') + upvotes = models.IntegerField(default=0) + num_votes = models.IntegerField(default=0) def user(self): user = User.objects.get(id=self.uid) diff --git a/website/urls.py b/website/urls.py index 1c7d75e..71588af 100644 --- a/website/urls.py +++ b/website/urls.py @@ -1,4 +1,5 @@ from django.conf.urls import patterns, include, url +from website import views urlpatterns = patterns('', url(r'^$', 'website.views.home', name='home'), @@ -9,6 +10,7 @@ urlpatterns = patterns('', url(r'^answer-comment/$', 'website.views.answer_comment', name='answer_comment'), url(r'^filter/(?P[^/]+)/$', 'website.views.filter', name='filter'), url(r'^filter/(?P[^/]+)/$', 'website.views.filter', name='filter'), + #url(r'^filter/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/$', 'website.views.filter', name='filter'), #url(r'^filter/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/$', 'website.views.filter', name='filter'), url(r'^new-question/$', 'website.views.new_question', name='new_question'), @@ -18,7 +20,7 @@ urlpatterns = patterns('', url(r'^clear-notifications/$', 'website.views.clear_notifications', name='clear_notifications'), url(r'^search/$', 'website.views.search', name='search'), url(r'^unanswered-notification/$', 'website.views.unanswered_notification', name='unanswered_notification'), - + url(r'^vote_post/$', 'website.views.vote_post', name='vote_post'), # Ajax helpers url(r'^ajax-tutorials/$', 'website.views.ajax_tutorials', name='ajax_tutorials'), url(r'^ajax-duration/$', 'website.views.ajax_duration', name='ajax_duration'), diff --git a/website/views.py b/website/views.py index f80ee13..c9a2a5f 100644 --- a/website/views.py +++ b/website/views.py @@ -55,10 +55,17 @@ def get_question(request, question_id=None, pretty_url=None): return HttpResponseRedirect('/question/'+ question_id + '/' + pretty_title) answers = question.answer_set.all() form = AnswerQuestionForm() + thisuserupvote = question.userUpVotes.filter(id=request.user.id).count() + thisuserdownvote = question.userDownVotes.filter(id=request.user.id).count() + + net_count = question.userUpVotes.count() - question.userDownVotes.count() context = { 'question': question, 'answers': answers, - 'form': form + 'form': form, + 'thisUserUpvote': thisuserupvote, + 'thisUserDownvote': thisuserdownvote, + 'net_count': net_count } context.update(csrf(request)) @@ -292,6 +299,55 @@ def new_question(request): context.update(csrf(request)) return render(request, 'website/templates/new-question.html', context) + +def vote_post(request): + + print "post" + post_id = int(request.POST.get('id')) + + vote_type = request.POST.get('type') + vote_action = request.POST.get('action') + print post_id + cur_post = get_object_or_404(Question, id=post_id) + + thisuserupvote = cur_post.userUpVotes.filter(id=request.user.id).count() + thisuserdownvote = cur_post.userDownVotes.filter(id=request.user.id).count() + + initial_votes = cur_post.userUpVotes.count() - cur_post.userDownVotes.count() + + # print "User Initial Upvote and Downvote: %d %d %s " % (thisuserupvote, thisuserdownvote, vote_action) + + #This loop is for voting + if vote_action == 'vote': + if (thisuserupvote == 0) and (thisuserdownvote == 0): + if vote_type == 'up': + cur_post.userUpVotes.add(request.user) + elif vote_type == 'down': + cur_post.userDownVotes.add(request.user) + else: + return HttpResponse("Error: Unknown vote-type passed.") + else: + return HttpResponse(initial_votes) + #This loop is for canceling vote + elif vote_action == 'recall-vote': + if (vote_type == 'up') and (thisuserupvote == 1): + cur_post.userUpVotes.remove(request.user) + elif (vote_type == 'down') and (thisuserdownvote == 1): + cur_post.userDownVotes.remove(request.user) + else: + # "Error - Unknown vote type or no vote to recall" + return HttpResponse(initial_votes) + else: + return HttpResponse("Error: Bad Action.") + + num_votes = cur_post.userUpVotes.count() - cur_post.userDownVotes.count() + cur_post.num_votes = num_votes + cur_post.save() + + print "Num Votes: %s" % num_votes + + return HttpResponse(num_votes) + # Notification Section @login_required def user_questions(request, user_id): -- cgit