From 8533d61eb93ecb4c943ec3c3b83dfef87b20a916 Mon Sep 17 00:00:00 2001 From: Jayaram Pai Date: Sun, 1 Dec 2013 13:09:49 +0530 Subject: basic auth and new-question --- forums/forms.py | 6 ++ forums/settings.py | 1 + forums/urls.py | 4 ++ forums/views.py | 34 +++++++++ static/forums/templates/user-login.html | 4 ++ static/website/css/main.css | 8 ++- static/website/images/ajax-loader.gif | Bin 0 -> 847 bytes static/website/js/custom.js | 44 ++++++++++++ static/website/templates/ajax-duration.html | 16 +++++ static/website/templates/ajax-tutorials.html | 4 ++ static/website/templates/base.html | 3 +- static/website/templates/fetch_questions.html | 9 +++ static/website/templates/fetch_tutorials.html | 2 +- static/website/templates/get_tutorial.html | 12 ++++ static/website/templates/index.html | 6 +- static/website/templates/new-post.html | 45 ++++++++++++ static/website/templates/new-question.html | 45 ++++++++++++ static/website/templates/recent_questions.html | 5 ++ website/forms.py | 71 ++++++++++++++++++ website/helpers.py | 3 + website/models.py | 8 ++- website/templatetags/count_tags.py | 60 ++++++++++++++-- website/templatetags/sidebar_tags.py | 11 ++- website/urls.py | 10 ++- website/views.py | 96 +++++++++++++++---------- 25 files changed, 448 insertions(+), 59 deletions(-) create mode 100644 forums/forms.py create mode 100644 forums/views.py create mode 100644 static/forums/templates/user-login.html create mode 100644 static/website/images/ajax-loader.gif create mode 100644 static/website/js/custom.js create mode 100644 static/website/templates/ajax-duration.html create mode 100644 static/website/templates/ajax-tutorials.html create mode 100644 static/website/templates/fetch_questions.html create mode 100644 static/website/templates/get_tutorial.html create mode 100644 static/website/templates/new-post.html create mode 100644 static/website/templates/new-question.html create mode 100644 static/website/templates/recent_questions.html create mode 100644 website/forms.py diff --git a/forums/forms.py b/forums/forms.py new file mode 100644 index 0000000..2e3a6d1 --- /dev/null +++ b/forums/forms.py @@ -0,0 +1,6 @@ +from django import forms + +class UserLoginForm(forms.Form): + username = forms.CharField() + password = forms.CharField(widget=forms.PasswordInput()) + diff --git a/forums/settings.py b/forums/settings.py index 3345be2..37d6202 100644 --- a/forums/settings.py +++ b/forums/settings.py @@ -143,6 +143,7 @@ INSTALLED_APPS = ( # Uncomment the next line to enable admin documentation: # 'django.contrib.admindocs', 'website', + 'widget_tweaks', ) # A sample logging configuration. The only tangible logging diff --git a/forums/urls.py b/forums/urls.py index 1e4ee04..e129d4b 100644 --- a/forums/urls.py +++ b/forums/urls.py @@ -15,4 +15,8 @@ urlpatterns = patterns('', # Uncomment the next line to enable the admin: url(r'^admin/', include(admin.site.urls)), + + # User account urls + url(r'^accounts/login/', 'forums.views.user_login', name='user_login'), + url(r'^accounts/logout/', 'forums.views.user_logout', name='user_logout'), ) diff --git a/forums/views.py b/forums/views.py new file mode 100644 index 0000000..6890d61 --- /dev/null +++ b/forums/views.py @@ -0,0 +1,34 @@ +from django.http import HttpResponse, HttpResponseRedirect +from django.contrib.auth import login, logout, authenticate +from django.shortcuts import render_to_response +from django.core.context_processors import csrf + +from forums.forms import UserLoginForm + +def user_login(request): + if request.user.is_anonymous(): + if request.method == 'POST': + username = request.POST['username'] + password = request.POST['password'] + user = authenticate(username=username, password=password) + if user is not None: + if user.is_active: + login(request, user) + return HttpResponseRedirect('/') + else: + return HttpResponse('you are blocked') + else: + return HttpResponse('Invalid username or password') + else: + form = UserLoginForm() + context = { + 'form': form + } + context.update(csrf(request)) + return render_to_response('forums/templates/user-login.html', context) + else: + return HttpResponseRedirect('/') + +def user_logout(request): + logout(request) + return HttpResponseRedirect('/') diff --git a/static/forums/templates/user-login.html b/static/forums/templates/user-login.html new file mode 100644 index 0000000..6ac4fee --- /dev/null +++ b/static/forums/templates/user-login.html @@ -0,0 +1,4 @@ +
{% csrf_token %} + {{ form.as_p }} + +
diff --git a/static/website/css/main.css b/static/website/css/main.css index 997a154..9e68e7f 100644 --- a/static/website/css/main.css +++ b/static/website/css/main.css @@ -9,12 +9,15 @@ } #content-inner { +} +#content{ + min-height: 600px; } #content .category { min-height: 50px; border-bottom: 1px solid #f5f5f5; } -#content .category .posts { +#content .category .questions { color: #7395d9; } #content .category .replies { @@ -38,3 +41,6 @@ #footer-inner { } +.field_error { + border: 1px solid red; +} diff --git a/static/website/images/ajax-loader.gif b/static/website/images/ajax-loader.gif new file mode 100644 index 0000000..e192ca8 Binary files /dev/null and b/static/website/images/ajax-loader.gif differ diff --git a/static/website/js/custom.js b/static/website/js/custom.js new file mode 100644 index 0000000..20801f6 --- /dev/null +++ b/static/website/js/custom.js @@ -0,0 +1,44 @@ +$(document).ready(function() { + $category = $("#id_category"); + $tutorial = $("#id_tutorial"); + $minute_range = $("#id_minute_range"); + $second_range = $("#id_second_range"); + + $category.change(function() { + var category = $(this).val(); + $.ajax({ + url: "/ajax-tutorials/", + type: "POST", + data: { + category: category + }, + success: function(data) { + $("#id_tutorial").html(data); + $("#id_tutorial").removeAttr("disabled"); + console.log("response = " + data); + } + }); + }); + + $tutorial.change(function() { + console.log("tut changed"); + var category = $category.val(); + var tutorial = $(this).val(); + $.ajax({ + url: "/ajax-duration/", + type: "POST", + data: { + category: category, + tutorial: tutorial + }, + success: function(data){ + var $response = $(data); + console.log($response.html()); + $minute_range.html($response.find("#minutes").html()) + $minute_range.removeAttr("disabled"); + $second_range.html($response.find("#seconds").html()) + $second_range.removeAttr("disabled"); + } + }); + }); +}); diff --git a/static/website/templates/ajax-duration.html b/static/website/templates/ajax-duration.html new file mode 100644 index 0000000..f89927b --- /dev/null +++ b/static/website/templates/ajax-duration.html @@ -0,0 +1,16 @@ +{% load count_tags %} +
+
+ + {% for i in minutes|inc|get_range %} + + {% endfor %} +
+ +
+ + {% for i in seconds|get_range:"0,10" %} + + {% endfor %} +
+
diff --git a/static/website/templates/ajax-tutorials.html b/static/website/templates/ajax-tutorials.html new file mode 100644 index 0000000..7429f59 --- /dev/null +++ b/static/website/templates/ajax-tutorials.html @@ -0,0 +1,4 @@ + +{% for tutorial in tutorials %} + +{% endfor %} diff --git a/static/website/templates/base.html b/static/website/templates/base.html index dd81da9..f89417f 100644 --- a/static/website/templates/base.html +++ b/static/website/templates/base.html @@ -53,7 +53,7 @@ {% block sidebar %}

Recent Posts

{% load sidebar_tags %} - {% recent_posts %} + {% recent_questions %} {% endblock %} @@ -70,5 +70,6 @@ + diff --git a/static/website/templates/fetch_questions.html b/static/website/templates/fetch_questions.html new file mode 100644 index 0000000..d7492fc --- /dev/null +++ b/static/website/templates/fetch_questions.html @@ -0,0 +1,9 @@ +{% extends 'website/templates/base.html' %} +{% block content %} +{{ category }}, {{ tutorial }} +
+Number of questions: {{ questions|length }}
+{% for question in questions %} + {{ question.title }} +{% endfor %} +{% endblock %} diff --git a/static/website/templates/fetch_tutorials.html b/static/website/templates/fetch_tutorials.html index a99caec..246c35f 100644 --- a/static/website/templates/fetch_tutorials.html +++ b/static/website/templates/fetch_tutorials.html @@ -2,7 +2,7 @@ {% block content %} {% for tut in tutorials %}
- + {{tut.tutorial_name}}
diff --git a/static/website/templates/get_tutorial.html b/static/website/templates/get_tutorial.html new file mode 100644 index 0000000..159f342 --- /dev/null +++ b/static/website/templates/get_tutorial.html @@ -0,0 +1,12 @@ +{% extends 'website/templates/base.html' %} +{% block content %} +

{{question.title}}

+

+ {{ question.body }} +

+ +Replies +{% for reply in replies %} + {{ reply.body }} +{% endfor %} +{% endblock %} diff --git a/static/website/templates/index.html b/static/website/templates/index.html index c8b11b3..471fb48 100644 --- a/static/website/templates/index.html +++ b/static/website/templates/index.html @@ -5,11 +5,11 @@ {{ category }}
{% load count_tags %} - - {% category_post_count category %} posts, + + {% category_question_count category %} questions, - {% category_post_count category %} replies + {% category_question_count category %} replies A diff --git a/static/website/templates/new-post.html b/static/website/templates/new-post.html new file mode 100644 index 0000000..8487b70 --- /dev/null +++ b/static/website/templates/new-post.html @@ -0,0 +1,45 @@ +{% extends 'website/templates/base.html' %} +{% load widget_tweaks %} +{% block content %} +

+ + Create a new question . . . +

+
+
+ {% with WIDGET_ERROR_CLASS='field_error' %} + +

Please enter the tutorial details.

+
+
+ {% render_field form.category class+="form-control"%} +
+
+ {% render_field form.tutorial class+="form-control" disabled="disabled" %} +
+
+ {% render_field form.minute_range class+="form-control" disabled="disabled" %} +
+
+ {% render_field form.second_range class+="form-control" disabled="disabled" %} +
+
+
+ +

Please enter your question details.

+
+
+
+ + {% render_field form.title class+="form-control" %} +
+
+ + {% render_field form.body class+="form-control" %} +
+
+
+ + {% endwith %} +
+{% endblock %} diff --git a/static/website/templates/new-question.html b/static/website/templates/new-question.html new file mode 100644 index 0000000..5005e13 --- /dev/null +++ b/static/website/templates/new-question.html @@ -0,0 +1,45 @@ +{% extends 'website/templates/base.html' %} +{% load widget_tweaks %} +{% block content %} +

+ + Create a new question . . . +

+
+
{% csrf_token %} + {% with WIDGET_ERROR_CLASS='field_error' %} + +

Please enter the tutorial details.

+
+
+ {% render_field form.category class+="form-control"%} +
+
+ {% render_field form.tutorial class+="form-control" disabled="disabled" %} +
+
+ {% render_field form.minute_range class+="form-control" disabled="disabled" %} +
+
+ {% render_field form.second_range class+="form-control" disabled="disabled" %} +
+
+
+ +

Please enter your question details.

+
+
+
+ + {% render_field form.title class+="form-control" %} +
+
+ + {% render_field form.body class+="form-control" %} +
+
+
+ + {% endwith %} +
+{% endblock %} diff --git a/static/website/templates/recent_questions.html b/static/website/templates/recent_questions.html new file mode 100644 index 0000000..1a4cc44 --- /dev/null +++ b/static/website/templates/recent_questions.html @@ -0,0 +1,5 @@ + diff --git a/website/forms.py b/website/forms.py new file mode 100644 index 0000000..00b0cfe --- /dev/null +++ b/website/forms.py @@ -0,0 +1,71 @@ +from django import forms + +from website.models import Question + +categories = ( + ("None", "Select a Category"), + ('Advanced-C++', 'Advanced-C++'), + ('BASH', 'BASH'), + ('Blender', 'Blender'), + ('C-and-C++', 'C-and-C++'), + ('CellDesigner', 'CellDesigner'), + ('Digital-Divide', 'Digital-Divide'), + ('Drupal', 'Drupal'), + ('Firefox', 'Firefox'), + ('GChemPaint', 'GChemPaint'), + ('Geogebra', 'Geogebra'), + ('GeoGebra-for-Engineering-drawing', 'GeoGebra-for-Engineering-drawing'), + ('GIMP', 'GIMP'), + ('GNS3', 'GNS3'), + ('GSchem', 'GSchem'), + ('Java', 'Java'), + ('Java-Business-Application', 'Java-Business-Application'), + ('KiCad', 'KiCad'), + ('KTouch', 'KTouch'), + ('KTurtle', 'KTurtle'), + ('LaTeX', 'LaTeX'), + ('LibreOffice-Suite-Base', 'LibreOffice-Suite-Base'), + ('LibreOffice-Suite-Calc', 'LibreOffice-Suite-Calc'), + ('LibreOffice-Suite-Draw', 'LibreOffice-Suite-Draw'), + ('LibreOffice-Suite-Impress', 'LibreOffice-Suite-Impress'), + ('LibreOffice-Suite-Math', 'LibreOffice-Suite-Math'), + ('LibreOffice-Suite-Writer', 'LibreOffice-Suite-Writer'), + ('Linux', 'Linux'), + ('Netbeans', 'Netbeans'), + ('Ngspice', 'Ngspice'), + ('OpenFOAM', 'OpenFOAM'), + ('Orca', 'Orca'), + ('PERL', 'PERL'), + ('PHP-and-MySQL', 'PHP-and-MySQL'), + ('Python', 'Python'), + ('Python-Old-Version', 'Python-Old-Version'), + ('QCad', 'QCad'), + ('R', 'R'), + ('Ruby', 'Ruby'), + ('Scilab', 'Scilab'), + ('Selenium', 'Selenium'), + ('Single-Board-Heater-System', 'Single-Board-Heater-System'), + ('Spoken-Tutorial-Technology', 'Spoken-Tutorial-Technology'), + ('Step', 'Step'), + ('Thunderbird', 'Thunderbird'), + ('Tux-Typing', 'Tux-Typing'), + ('What-is-Spoken-Tutorial', 'What-is-Spoken-Tutorial'), + ('Xfig', 'Xfig') +) +tutorials = ( + ("None", "Select a Tutorial"), +) +minutes = ( + ("None", "min"), +) +seconds= ( + ("None", "sec"), +) + +class NewQuestionForm(forms.Form): + category = forms.CharField(widget=forms.Select(choices=categories)) + tutorial = forms.CharField(widget=forms.Select(choices=tutorials)) + minute_range = forms.CharField(widget=forms.Select(choices=minutes)) + second_range = forms.CharField(widget=forms.Select(choices=seconds)) + title = forms.CharField(max_length=200) + body = forms.CharField(widget=forms.Textarea()) diff --git a/website/helpers.py b/website/helpers.py index dd37152..0d67da0 100644 --- a/website/helpers.py +++ b/website/helpers.py @@ -20,6 +20,9 @@ def get_video_info(path): total += 60 * minutes total += seconds + info_m['hours'] = hours + info_m['minutes'] = minutes + info_m['seconds'] = seconds info_m['duration'] = total info_m['width'] = int(info_m['width']) info_m['height'] = int(info_m['height']) diff --git a/website/models.py b/website/models.py index 9570965..ce8d4dc 100644 --- a/website/models.py +++ b/website/models.py @@ -1,10 +1,14 @@ from django.db import models from django.contrib.auth.models import User -class Post(models.Model): +class Question(models.Model): user = models.ForeignKey(User) category = models.CharField(max_length=200) tutorial = models.CharField(max_length=200) + minute_start = models.IntegerField() + minute_end = models.IntegerField() + second_start = models.IntegerField() + second_end = models.IntegerField() title = models.CharField(max_length=200) body = models.TextField() date_created = models.DateTimeField(auto_now_add=True) @@ -12,7 +16,7 @@ class Post(models.Model): class Reply(models.Model): user = models.ForeignKey(User) - post = models.ForeignKey(Post) + question = models.ForeignKey(Question) title = models.CharField(max_length=200) body = models.TextField() date_created = models.DateTimeField(auto_now_add=True) diff --git a/website/templatetags/count_tags.py b/website/templatetags/count_tags.py index e4233f1..33aff7f 100644 --- a/website/templatetags/count_tags.py +++ b/website/templatetags/count_tags.py @@ -1,11 +1,61 @@ from django import template -from website.models import Post, Reply +from website.models import Question, Reply register = template.Library() -def category_post_count(category): - category_post_count = Post.objects.filter(category=category).count() - return category_post_count -register.simple_tag(category_post_count) +# Counts the number of questions in +def category_question_count(category): + category_question_count =Question.objects.filter(category=category).count() + return category_question_count +register.simple_tag(category_question_count) +# Implementing range(x) function in templates +def get_range(value, arg=''): + args = arg.split(',') + n = len(args) + + if n == 0 or arg =='': + # if no arguments set value as limit + start = 0 + limit = value + step = 1 + elif n == 1: + start = int(args[0]) + limit = value + step = 1 + elif n == 2: + start = int(args[0]) + limit = value + step = int(args[1]) + else: + raise TypeError('get_range() takes maximum 2 arguments, {} given'.format(n)) + + return range(start, limit, step) +register.filter('get_range', get_range) + +# Implementing increment and decrement functions +def inc(value, arg=1): + return value + int(arg) +register.filter('inc', inc) + +def dec(value, arg=1): + return value-int(arg) +register.filter('dec', dec) + +# Implementing calculator for templates +def add(value, arg=0): + return value + int(arg) +register.filter('add', add) + +def sub(value, arg=0): + return value - int(arg) +register.filter('sub', sub) + +def mul(value, arg=1): + return value * int(arg) +register.filter('mul', mul) + +def div(value, arg=1): + return value / int(arg) +register.filter('div', div) diff --git a/website/templatetags/sidebar_tags.py b/website/templatetags/sidebar_tags.py index a7e5cc7..8b7efb9 100644 --- a/website/templatetags/sidebar_tags.py +++ b/website/templatetags/sidebar_tags.py @@ -1,12 +1,11 @@ from django import template -from website.models import Post, Reply +from website.models import Question, Reply register = template.Library() -def recent_posts(): - recent_posts = Post.objects.all().order_by('-id')[:5] - return {'recent_posts': recent_posts} - -register.inclusion_tag('website/templates/recent_posts.html')(recent_posts) +def recent_questions(): + recent_questions = Question.objects.all().order_by('-id')[:5] + return {'recent_questions': recent_questions} +register.inclusion_tag('website/templates/recent_questions.html')(recent_questions) diff --git a/website/urls.py b/website/urls.py index 29c25ea..9d1b048 100644 --- a/website/urls.py +++ b/website/urls.py @@ -3,7 +3,11 @@ from django.conf.urls import patterns, include, url urlpatterns = patterns('', url(r'^$', 'website.views.home', name='home'), url(r'^category/(?P.+)/$', 'website.views.fetch_tutorials', name='fetch_tutorials'), - url(r'^tutorial/(?P.+)/(?P.+)/$', 'website.views.fetch_posts', name='fetch_posts'), - url(r'^post/(?P\d+)$', 'website.views.get_post', name='get_post'), - url(r'^new-post/$', 'website.views.new_post', name='new_post'), + url(r'^tutorial/(?P.+)/(?P.+)/$', 'website.views.fetch_questions', name='fetch_questions'), + url(r'^question/(?P\d+)$', 'website.views.get_question', name='get_question'), + url(r'^new-question/$', 'website.views.new_question', name='new_question'), + + # 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 0a8f43b..c5b71af 100644 --- a/website/views.py +++ b/website/views.py @@ -1,9 +1,11 @@ -import math - from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render_to_response, get_object_or_404 +from django.core.context_processors import csrf +from django.views.decorators.csrf import csrf_exempt +from django.contrib.auth.decorators import login_required -from website.models import Post, Reply, TutorialDetails, TutorialResources +from website.models import Question, Reply, TutorialDetails, TutorialResources +from website.forms import NewQuestionForm from website.helpers import get_video_info categories = [ @@ -37,48 +39,68 @@ def fetch_tutorials(request, category=None): } return render_to_response('website/templates/fetch_tutorials.html', context) -def fetch_posts(request, category=None, tutorial=None): - posts = Post.objects.filter(category=category).filter(tutorial=tutorial) +def fetch_questions(request, category=None, tutorial=None): + questions = Question.objects.filter(category=category).filter(tutorial=tutorial) context = { 'category': category, 'tutorial': tutorial, - 'posts': posts + 'questions': questions } - return render_to_response('website/templates/fetch_posts.html', context) + return render_to_response('website/templates/fetch_questions.html', context) -def get_post(request, post_id=None): - post = get_object_or_404(Post, id=post_id) - replies = post.reply_set.all() +def get_question(request, question_id=None): + question = get_object_or_404(Question, id=question_id) + replies = question.reply_set.all() context = { - 'post': post, + 'question': question, 'replies': replies } - return render_to_response('website/templates/get_post.html', context) - -def new_post(request): - video_info = get_video_info('/home/cheese/test-video.ogv') - duration = math.ceil(video_info['duration']/60) #assuming the video is less than an hour - return HttpResponse(duration) - - - - - - - - - - - - - - - - - - - - + return render_to_response('website/templates/get_question.html', context) +@login_required +def new_question(request): + if request.method == 'POST': + form = NewQuestionForm(request.POST) + if form.is_valid(): + return HttpResponse("valid") + else: + form = NewQuestionForm() + context = { + 'form': form + } + context.update(csrf(request)) + return render_to_response('website/templates/new-question.html', context) + +@csrf_exempt +def ajax_tutorials(request): + if request.method == 'POST': + category = request.POST.get('category') + tutorials = TutorialDetails.objects.using('spoken').filter(foss_category=category) + context = { + 'tutorials': tutorials + } + return render_to_response('website/templates/ajax-tutorials.html', context) + +@csrf_exempt +def ajax_duration(request): + if request.method == 'POST': + category = request.POST['category'] + tutorial =request.POST['tutorial'] + video_info = get_video_info('/home/cheese/test-video.ogv') + + # convert minutes to 1 if less than 0 + # convert seconds to nearest upper 10th number eg(23->30) + minutes = video_info['minutes'] + seconds = video_info['seconds'] + if minutes < 0: + minutes = 1 + seconds = int(seconds - (seconds % 10 - 10)) + + print minutes, seconds + context = { + 'minutes': minutes, + 'seconds':seconds, + } + return render_to_response('website/templates/ajax-duration.html', context) -- cgit