diff --git a/.gitignore b/.gitignore index 3d2071c..ceeed82 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ *.pyc local_settings.py *~ -*.sw* +*.sw* \ No newline at end of file diff --git a/README.md b/README.md index 64be94b..cb55a03 100644 --- a/README.md +++ b/README.md @@ -1,18 +1 @@ -6th June, 12 -Basic Tabs done. -Please take care of the different settings that need for dajax to run. -Dont use 'shaastra' as your project folder's name. Dajax was not accepting hyphens for some reason. My folder's name is 'shaastra'. -If you have a different name please change 'Dajaxice.shaastra.events.' to 'Dajaxice..events.' in all the templates. -Dont forget to add AUTH_PROFILE_MODULE = 'events.UserProfile' to your local settings. - -9th June, 12 -Tab files added. they have add, delete functionality. -sending file uses ajax. rest can be done by dajax. -Renaming files has to be done. - -15th June, 12 Renaming of files done - -16th June, Chosen-JQuery plugin implemented in the form for adding events. 'Tags' for events can now be added in a more presentable way. - -25th June, Coords can now add questionnares. He/She can choose to add an mcq or a subjective. After adding an mcq, he/she can add choices for it. editing/deleting of options/questions can be done. -As suggested by Suraj, I have made some changes so that you dont need to name your project folder as 'shaastra'. I have added some lines to global_settings.py and added a file called context_processors.py. So in templates just use {{pro_dir}} instead of 'shaastra' now, and your folder name will get rendered there. Just add the following line as it is in your TEMPLATE_CONTEXT_PROCESSORS - "events.context_processors.project_dir_name". +Shaastra 2013 Events diff --git a/admin/ajax.py b/admin/ajax.py index 22e9336..38ead69 100644 --- a/admin/ajax.py +++ b/admin/ajax.py @@ -1,5 +1,7 @@ -#The variable Summary refers to the div where a table consisting group name and its cores is displayed -#The variable space refers to the div where different forms like add/edit group/core are displayed +#!/usr/bin/python +# -*- coding: utf-8 -*- +# The variable Summary refers to the div where a table consisting group name and its cores is displayed +# The variable space refers to the div where different forms like add/edit group/core are displayed from dajaxice.decorators import dajaxice_register from django.utils import simplejson @@ -9,95 +11,130 @@ from django.contrib.auth.models import Group, User from users.models import UserProfile + @dajaxice_register -def add_edit_group(request,form="",id=0): +def add_edit_group(request, form='', id=0): """ This function calls the AddGroupForm from forms.py If a new group is being created, a blank form is displayed and the super user can fill in necessary details. If an existing group's details is being edited, the same form is displayed populated with current group details for all fields """ + dajax = Dajax() if id: - group_form = AddGroupForm(form, instance=Group.objects.get(id=id)) + group_form = AddGroupForm(form, + instance=Group.objects.get(id=id)) else: group_form = AddGroupForm(form) if group_form.is_valid(): group_form.save() - dajax.script("updateSummary();") + dajax.script('updateSummary();') return dajax.json() + @dajaxice_register def updateSummary(request): """ This function updates the table in summary div whenever a new group/core is added or when an existing group/core is edited or deleted """ + dajax = Dajax() - dajax.assign("#summary",'innerHTML',"") - groups=Group.objects.order_by('id').all()[1:] + dajax.assign('#summary', 'innerHTML', + "
S.NoGroup NameCores
" + ) + groups = Group.objects.order_by('id').all() for g in groups: - dajax.append("#groups",'innerHTML',"") - cores=User.objects.filter(groups__name=g.name) + dajax.append('#groups', 'innerHTML', ']","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*",""],legend:[1,"
","
"],thead:[1,"
S.NoGroup NameCores
"+str(g.id-1)+""+g.name+"
' + str(g.id) + + ""+str(c)+"") - dajax.assign(".bbq-item","innerHTML","Space for displaying forms"); + dajax.append('#' + str(g.id), 'innerHTML', + "
  • \d+)', editgroup, name='editgroup'), url(r'^addcore/', addcore, name='addcore'), url(r'^editcore/(?P\d+)', editcore, name='editcore'), - url(r'^$', home, name = 'home'), -) + url(r'^$', home, name='home'), + ) diff --git a/admin/views.py b/admin/views.py index 39a44c8..2b670f5 100644 --- a/admin/views.py +++ b/admin/views.py @@ -1,3 +1,5 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- from django.http import HttpResponse, HttpResponseRedirect, Http404 from django.contrib.auth.decorators import login_required from django.shortcuts import render_to_response @@ -6,52 +8,68 @@ from admin.forms import * from django.contrib.auth.models import Group + @login_required(login_url=settings.SITE_URL + 'user/login/') def home(request): """ This is the home page view of the superuser """ - if request.user.is_superuser is False : + + if request.user.is_superuser is False: return HttpResponseRedirect(settings.SITE_URL) - return render_to_response('admin/home.html', locals(), context_instance = RequestContext(request)) + return render_to_response('admin/home.html', locals(), + context_instance=RequestContext(request)) + @login_required(login_url=settings.SITE_URL + 'user/login/') def addgroup(request): """ This is the home page view of the superuser """ - if request.user.is_superuser is False : + + if request.user.is_superuser is False: return HttpResponseRedirect(settings.SITE_URL) - group_form=AddGroupForm() - return render_to_response('ajax/admin/addgroup.html', locals(), context_instance = RequestContext(request)) + group_form = AddGroupForm() + return render_to_response('ajax/admin/addgroup.html', locals(), + context_instance=RequestContext(request)) + @login_required(login_url=settings.SITE_URL + 'user/login/') -def editgroup(request,id=0): +def editgroup(request, id=0): """ This is the home page view of the superuser """ - if request.user.is_superuser is False : + + if request.user.is_superuser is False: return HttpResponseRedirect(settings.SITE_URL) - group_form=AddGroupForm(instance=Group.objects.get(id=id)) - return render_to_response('ajax/admin/editgroup.html', locals(), context_instance = RequestContext(request)) + group_form = AddGroupForm(instance=Group.objects.get(id=id)) + return render_to_response('ajax/admin/editgroup.html', locals(), + context_instance=RequestContext(request)) + @login_required(login_url=settings.SITE_URL + 'user/login/') def addcore(request): """ This is the home page view of the superuser """ - if request.user.is_superuser is False : + + if request.user.is_superuser is False: return HttpResponseRedirect(settings.SITE_URL) - core_form=AddCoreForm() - return render_to_response('ajax/admin/addcore.html', locals(), context_instance = RequestContext(request)) + core_form = AddCoreForm() + return render_to_response('ajax/admin/addcore.html', locals(), + context_instance=RequestContext(request)) + @login_required(login_url=settings.SITE_URL + 'user/login/') -def editcore(request,id=0): +def editcore(request, id=0): """ This is the home page view of the superuser """ - if request.user.is_superuser is False : + + if request.user.is_superuser is False: return HttpResponseRedirect(settings.SITE_URL) - core_form=AddCoreForm(instance=User.objects.get(id=id)) - return render_to_response('ajax/admin/editcore.html', locals(), context_instance = RequestContext(request)) + core_form = AddCoreForm(instance=User.objects.get(id=id), + initial={'groups': User.objects.get(id=id).groups.get_query_set()[0]}) + return render_to_response('ajax/admin/editcore.html', locals(), + context_instance=RequestContext(request)) diff --git a/coord/__init__.py b/coord/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/coord/ajax.py b/coord/ajax.py new file mode 100644 index 0000000..8337677 --- /dev/null +++ b/coord/ajax.py @@ -0,0 +1,527 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import random +from dajax.core import Dajax +from django.utils import simplejson +from django.template import loader, Context, RequestContext, Template +from events.models import * +from coord.forms import * +from core.forms import AddEventForm +from dajaxice.decorators import dajaxice_register +from django.core.cache import cache +from django.contrib.sitemaps import ping_google +from operator import attrgetter + + +def get_files(tab): + + # gets all files that are related to a particular tab + + try: + return tab.tabfile_set.all() + except: + raise Http404() + + +def get_mob_app_tab(event): + try: + return event.mobapptab + except: + return None + + +def get_tabs(event): + + # gets all tabs that are related to a particular event + + try: + return event.tab_set.all() + except: + raise Http404() + + +@dajaxice_register +def edit_event( + request, + upload, + form, + id, + ): + """ + This function calls the AddEventForm from forms.py + If a new event is being created, a blank form is displayed and the core can fill in necessary details. + If an existing event's details is being edited, the same form is displayed populated with current event details for all fields + + """ + + dajax = Dajax() + event_form = AddEventForm(form, instance=Event.objects.get(id=id)) + if event_form.is_valid(): + event = event_form.save() + try: + ping_google() + except: + pass + if upload: + dajax.script('upload_events_logo(' + str(event.id) + ');') + else: + html = "

    " + event.category \ + + '
    ' + str(event) \ + + "

  • ') + dajax.script("window.location.hash='';") + return dajax.json() + + +@dajaxice_register +def add_tag(request, text): + dajax = Dajax() + if text: + try: + new_tag = Tag.objects.get(name=text) + dajax.append('#alerts', 'innerHTML', "
  • '" + text + + "' already exists!
  • ") + dajax.assign('#addTag', 'innerHTML', '') + dajax.script("$('#msg').show();") + except: + new_tag = Tag(name=text) + new_tag.save() + dajax.assign('#addTag', 'innerHTML', '') + dajax.script("$('#msg').show();$('#id_tags option:last').attr('value'," + + str(new_tag.id) + + ");$('#id_tags').trigger('liszt:updated');") + else: + dajax.alert('Tag name required!') + return dajax.json() + + +@dajaxice_register +def delete_tab(request, tab_id=0): + + # deletes the tab. shows a delete successful message. + + dajax = Dajax() + if tab_id: + tab = Tab.objects.get(id=tab_id) + title = tab.title + tab.delete() + dajax.alert(title + ' deleted sucessfully!') + dajax.script('Dajaxice.coord.updateTabs(Dajax.process);') + else: + dajax.alert('error ' + tab_id) + return dajax.json() + + +@dajaxice_register +def save_tab(request, data, tab_id=0): + + # validates the tab details that were submitted while adding a new tab + + dajax = Dajax() + if tab_id: + tab = Tab.objects.get(id=tab_id) + form = TabAddForm(data, instance=tab) + else: + form = TabAddForm(data) + if form.is_valid(): + event = request.user.get_profile().is_coord_of + unsaved_tab = form.save(commit=False) + unsaved_tab.event = event + unsaved_tab.save() + cache.set(str(unsaved_tab.id) + '_event', + str(unsaved_tab.event), 2592000) + cache.set(str(unsaved_tab.id) + '_title', + str(unsaved_tab.title), 2592000) + cache.set(str(unsaved_tab.id) + '_text', str(unsaved_tab.text), + 2592000) + cache.set(str(unsaved_tab.id) + '_pref', str(unsaved_tab.pref), + 2592000) + tab = unsaved_tab + if not tab_id: + dajax.append('#tabs', 'innerHTML', '
  • ' + str(tab.title) + '
  • ') + dajax.script("window.location.hash='" + 'customtabs/' + + str(tab.id) + "';") + return dajax.json() + else: + template = loader.get_template('ajax/coord/tab_form.html') + html = template.render(RequestContext(request, locals())) + dajax.assign('.bbq-item', 'innerHTML', html) + dajax.script("niced = new nicEditor().panelInstance('niced_text');" + ) + return dajax.json() + + +@dajaxice_register +def delete_file(request, tab_id, file_id): + + # deletes the selected file + + form = TabFile.objects.get(id=file_id) + form.delete() + tab = Tab.objects.get(id=tab_id) + file_list = get_files(tab) + template = loader.get_template('ajax/coord/tab_detail.html') + html = template.render(RequestContext(request, locals())) + dajax = Dajax() + dajax.assign('.bbq-item', 'innerHTML', html) + return dajax.json() + + +@dajaxice_register +def rename_file_done(request, form, file_id): + + # renames a file + + f = TabFile.objects.get(id=file_id) + if form['display_name']: + f.title = form['display_name'] + f.save() + tab = f.tab + file_list = get_files(tab) + template = loader.get_template('ajax/coord/tab_detail.html') + html = template.render(RequestContext(request, locals())) + dajax = Dajax() + dajax.assign('.bbq-item', 'innerHTML', html) + return dajax.json() + + +@dajaxice_register +def save_subjective(request, data, ques_id=0): + + # validates and saves a subjective question + + dajax = Dajax() + if ques_id: + ques = SubjectiveQuestion.objects.get(id=ques_id) + form = AddSubjectiveQuestionForm(data, instance=ques) + else: + form = AddSubjectiveQuestionForm(data) + if form.is_valid(): + event = request.user.get_profile().is_coord_of + unsaved_ques = form.save(commit=False) + unsaved_ques.event = event + unsaved_ques.save() + dajax.script("window.location.hash='questions'") + return dajax.json() + else: + template = loader.get_template('ajax/coord/subj_form.html') + html = template.render(RequestContext(request, locals())) + dajax.assign('.bbq-item', 'innerHTML', html) + dajax.script("niced = new nicEditor().panelInstance('niced_text');" + ) + return dajax.json() + + +@dajaxice_register +def delete_subjective(request, ques_id): + + # deletes the selected question + + ques = SubjectiveQuestion.objects.get(id=ques_id) + ques.delete() + event = request.user.get_profile().is_coord_of + text_questions = event.subjectivequestion_set.all() + mcqs = event.objectivequestion_set.all() + template = loader.get_template('ajax/coord/question_tab.html') + html = template.render(RequestContext(request, locals())) + dajax = Dajax() + dajax.assign('.bbq-item', 'innerHTML', html) + return dajax.json() + + +def saving_mcq(data, mcq): + data.pop('csrfmiddlewaretoken') + mcq.title = data.pop('title') + mcq.q_number = data.pop('q_no') + +# print data + + mcq.save() + try: + options = mcq.mcqoption_set.all() + except: + options = [] + keys = data.keys() + keys.sort() + +# print keys + + for opt_id in keys: + if not data[opt_id]: + continue + if not opt_id.startswith('o'): + +# print 'not' +# print opt_id[:-1] + + mcqoption = MCQOption(id=opt_id[:-1]) + else: + +# print 'h' +# print 'else' + + mcqoption = MCQOption() + +# print 'here' + + mcqoption.option = opt_id[-1] + mcqoption.text = data[opt_id] + mcqoption.question = mcq + mcqoption.save() + + +@dajaxice_register +def save_mcq(request, data, ques_id): + mcq = \ + (ObjectiveQuestion.objects.get(id=ques_id) if ques_id else ObjectiveQuestion(event=request.user.get_profile().is_coord_of)) + saving_mcq(data, mcq) + ques_id = mcq.id + options = mcq.mcqoption_set.all() + template = loader.get_template('ajax/coord/mcq_form.html') + form = MCQForm(mcq, options) + html = template.render(RequestContext(request, locals())) + dajax = Dajax() + dajax.script("window.location.hash='questions'") + dajax.script('alert("question saved succesfully");') + return dajax.json() + + +@dajaxice_register +def delete_mcq(request, ques_id): + + # deletes the selected mcq + + ques = ObjectiveQuestion.objects.get(id=ques_id) + ques.delete() + event = request.user.get_profile().is_coord_of + text_questions = event.subjectivequestion_set.all() + mcqs = event.objectivequestion_set.all() + template = loader.get_template('ajax/coord/question_tab.html') + t = template.render(RequestContext(request, locals())) + dajax = Dajax() + dajax.assign('.bbq-item', 'innerHTML', t) + return dajax.json() + + +@dajaxice_register +def manage_options(request, ques_id): + + # all existing options displayed with features of editing/deleting them and adding new ones + + ques = ObjectiveQuestion.objects.get(id=ques_id) + options = ques.mcqoption_set.all() + template = loader.get_template('ajax/coord/manage_options.html') + html = template.render(RequestContext(request, locals())) + dajax = Dajax() + dajax.assign('.bbq-item', 'innerHTML', html) + return dajax.json() + + +@dajaxice_register +def add_option(request, ques_id): + + # displays a form for adding an option + + ques = ObjectiveQuestion.objects.get(id=ques_id) + f = AddOptionForm() + template = loader.get_template('ajax/coord/add_option_form.html') + t = template.render(RequestContext(request, locals())) + dajax = Dajax() + dajax.assign('#option_edit', 'innerHTML', t) + return dajax.json() + + +@dajaxice_register +def save_option(request, form, ques_id): + + # validates and saves an option + + f = AddOptionForm(form) + ques = ObjectiveQuestion.objects.get(id=ques_id) + if f.is_valid(): + unsaved_option = f.save(commit=False) + unsaved_option.question = ques + unsaved_option.save() + options = ques.mcqoption_set.all() + template = loader.get_template('ajax/coord/manage_options.html') + t = template.render(RequestContext(request, locals())) + dajax = Dajax() + dajax.assign('#detail', 'innerHTML', t) + return dajax.json() + else: + template = loader.get_template('ajax/coord/add_option_form.html' + ) + t = template.render(RequestContext(request, locals())) + dajax = Dajax() + dajax.assign('#option_edit', 'innerHTML', t) + return dajax.json() + + +@dajaxice_register +def delete_option(request, option_id): + + # deletes an option + + option = MCQOption.objects.get(id=option_id) + ques = option.question + option.delete() + options = ques.mcqoption_set.all() + template = loader.get_template('ajax/coord/manage_options.html') + t = template.render(RequestContext(request, locals())) + dajax = Dajax() + dajax.assign('#detail', 'innerHTML', t) + return dajax.json() + + +@dajaxice_register +def edit_option(request, option_id): + + # loads a form for editting an existing option + + option = MCQOption.objects.get(id=option_id) + f = AddOptionForm(instance=option) + template = loader.get_template('ajax/coord/edit_option_form.html') + t = template.render(RequestContext(request, locals())) + dajax = Dajax() + dajax.assign('#option_edit', 'innerHTML', t) + return dajax.json() + + +@dajaxice_register +def save_editted_option(request, form, option_id): + + # validates and saves editted option + + option = MCQOption.objects.get(id=option_id) + ques = option.question + f = AddOptionForm(form, instance=option) + if f.is_valid(): + f.save() + options = ques.mcqoption_set.all() + template = loader.get_template('ajax/coord/manage_options.html') + t = template.render(RequestContext(request, locals())) + dajax = Dajax() + dajax.assign('#detail', 'innerHTML', t) + return dajax.json() + else: + template = \ + loader.get_template('ajax/coord/edit_option_form.html') + t = template.render(RequestContext(request, locals())) + dajax = Dajax() + dajax.assign('#option_edit', 'innerHTML', t) + return dajax.json() + + +@dajaxice_register +def add_edit_mobapp_tab(request, form=''): + dajax = Dajax() + event = request.user.get_profile().is_coord_of + mob_app_tab = get_mob_app_tab(event) + template = loader.get_template('ajax/coord/add_edit_mobapptab.html') + if mob_app_tab: + f = MobAppWriteupForm(form, instance=mob_app_tab) + else: + f = MobAppWriteupForm(form) + if f.is_valid(): + unsaved = f.save(commit=False) + unsaved.event = event + unsaved.save() + dajax.alert('saved successfully!') + dajax.script("window.location.hash='';") + else: + dajax.alert('Error. Your write up could not be saved!') + t = template.render(RequestContext(request, locals())) + dajax.assign('.bbq-item', 'innerHTML', t) + return dajax.json() + + +@dajaxice_register +def add_edit_update(request, form='', id=0): + dajax = Dajax() + event = request.user.get_profile().is_coord_of + initial = Update.objects.all() + u_flag = 0 + a_flag = 0 + for u in initial: + if u.event == event and u.category == 'Update' and u.expired \ + is False: + u_flag = u_flag + 1 + elif u.event == event and u.category == 'Announcement' \ + and u.expired is False: + a_flag = a_flag + 1 + if id: + update_form = UpdateForm(form, + instance=Update.objects.get(id=id)) + else: + update_form = UpdateForm(form) + if update_form.is_valid: + update_temp = update_form.save(commit=False) + update_temp.event = event + if u_flag >= 4 and update_temp.category == 'Update' and not id: + dajax.alert('This event already has 4 updates. Please mark atleast one update as Expired before adding a new update' + ) + elif a_flag >= 1 and update_temp.category == 'Announcement' \ + and not id: + + dajax.alert('This event already has 1 announcement. Please mark the announcement as Expired before adding a new update' + ) + else: + + update_temp.save() + dajax.assign('#updates', 'innerHTML', '

    Announcement

    ') + initial = Update.objects.all() + update = sorted(initial, key=attrgetter('id'), reverse=True) + for u in update: + if u.event == event and u.category == 'Announcement' \ + and u.expired is False: + dajax.append('#updates', 'innerHTML', '

    ' + u.subject + + ' - ' + u.description + + " Edit " + ) + dajax.append('#updates', 'innerHTML', '

    Updates

    ') + for u in update: + if u.event == event and u.category == 'Update' \ + and u.expired is False: + dajax.append('#updates', 'innerHTML', '

    ' + u.subject + + ' - ' + u.description + + " Edit " + ) + dajax.script("window.location.hash='';") + dajax.script("$('.bbq-item').hide();$('.bbq-default').show();") + else: + template = loader.get_template('ajax/coord/update.html') + t = template.render(RequestContext(request, locals())) + dajax.assign('.bbq-item', 'innerHTML', t) + return dajax.json() diff --git a/coord/forms.py b/coord/forms.py new file mode 100644 index 0000000..2fda03b --- /dev/null +++ b/coord/forms.py @@ -0,0 +1,111 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +from django import forms +from events.models import * +from django.forms import ModelForm +import os + + +class AddOptionForm(ModelForm): + + class Meta: + + model = MCQOption + exclude = ('question', ) + + +# class AddMCQForm(ModelForm): +# class Meta: +# model = ObjectiveQuestion +# fields = ('q_number', 'title') + +class AddSubjectiveQuestionForm(ModelForm): + + class Meta: + + model = SubjectiveQuestion + fields = ('q_number', 'title') + + +class TabFileForm(ModelForm): + + class Meta: + + model = TabFile + exclude = ('tab', ) + + +class EventAddForm(ModelForm): + + tags = chosenforms.ChosenModelMultipleChoiceField(required=False, + queryset=Tag.objects.all()) + + class Meta: + + model = Event + + # fields = ('title','events_logo','tags') + + fields = ('title', 'events_logo', 'tags', 'lock_status', + 'unlock_reason') + widgets = {'lock_status': forms.HiddenInput(), + 'unlock_reason': forms.HiddenInput()} + + +class TabAddForm(ModelForm): + + text = \ + forms.CharField(widget=forms.Textarea(attrs={'id': 'niced_text' + , 'height': '200', 'width': '200'})) + + class Meta: + + model = Tab + exclude = ('event', ) + + +class MobAppWriteupForm(ModelForm): + + text = \ + forms.CharField(widget=forms.Textarea(attrs={'id': 'niced_text' + , 'height': '200', 'width': '200'})) + + class Meta: + + model = MobAppTab + exclude = ('event', ) + + +class MCQForm(forms.Form): + + def __init__(self, mcq, options): + super(MCQForm, self).__init__() + (ini_title, ini_q_no) = ('', '') + if mcq: + (ini_title, ini_q_no) = (mcq.title, mcq.q_number) + self.fields['q_no'] = forms.IntegerField(initial=ini_q_no) + self.fields['title'] = forms.CharField(widget=forms.Textarea, + initial=ini_title) + index = 0 + import string + alp = string.lowercase + for option in options: + self.fields['%s%s' % (option.id, option.option)] = \ + forms.CharField(initial='%s' % option.text, + label='option %s:' % alp[index], + max_length=1000) + index += 1 + self.fields['opt%s' % alp[index]] = \ + forms.CharField(label='option %s:' % alp[index], + max_length=1000) + + +class UpdateForm(ModelForm): + + class Meta: + + model = Update + exclude = ('date', ) + widgets = {'event': forms.HiddenInput()} + + diff --git a/coord/models.py b/coord/models.py new file mode 100644 index 0000000..93afd9e --- /dev/null +++ b/coord/models.py @@ -0,0 +1,14 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +from django.db import models +from django.contrib.auth.models import User +from django import forms +from django.forms import ModelForm +from chosen import forms as chosenforms +from datetime import datetime +from django.conf import settings +from django.core.exceptions import ValidationError +import os + +# Create your models here. + diff --git a/coord/tests.py b/coord/tests.py new file mode 100644 index 0000000..a9d5fb0 --- /dev/null +++ b/coord/tests.py @@ -0,0 +1,23 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + + self.assertEqual(1 + 1, 2) + + diff --git a/coord/urls.py b/coord/urls.py new file mode 100644 index 0000000..5b3c56a --- /dev/null +++ b/coord/urls.py @@ -0,0 +1,22 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +from django.conf.urls.defaults import patterns, include, url +from coord.views import * +from submissions.views import * + +urlpatterns = patterns( + '', + url(r'^submissions/', submissions), + url(r'^customtabs/', CustomTabs()), + url(r'^questions/', Questions()), + url(r'^mobapp/$', MobApp()), + url(r'^registrations/$', Registrations()), + url(r'^viewtdpsubmissions/$', ViewTdpSubmissions), + url(r'^tabfile/$', TabFileSubmit()), + url(r'^update/$', AddUpdate), + url(r'^editupdate/(?P\d+)', EditUpdate), + url(r'^editevent/(?P\d+)', editevent, name='editevent'), + url(r'^$', CoordDashboard()), + ) + +# these urls will be imported by the root url. diff --git a/coord/views.py b/coord/views.py new file mode 100644 index 0000000..15693df --- /dev/null +++ b/coord/views.py @@ -0,0 +1,324 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +from django.http import * +from django.template import * +from django.shortcuts import * +from django.contrib import * +from django.core.context_processors import csrf +from django.contrib.auth.models import User +from events.models import * +from coord.forms import * +from core.forms import AddEventForm +from django.conf import settings +from django.contrib.auth.decorators import login_required +from django.utils.decorators import method_decorator +from django.core.exceptions import ObjectDoesNotExist + +import os +import datetime +from datetime import date +from operator import attrgetter + + +# Create your views here. + +class BaseView(object): + + # parent class. classes below inherit this + + def __call__(self, request, **kwargs): + + # handles request and dispatches the corresponding handler based on the type of request (GET/POST) + + if not self.authenticate_req(request): + return HttpResponseRedirect(settings.SITE_URL + 'user/login' + ) + method = request.META['REQUEST_METHOD'].upper() + handler = getattr(self, 'handle_%s' % method, None) + + if handler is None: + methods = [] + for x in dir(self): + if x.startswith('handle_'): + methods.append(x[7:]) + return HttpResponseNotAllowed(methods) + + return handler(request, **kwargs) + + def get_tabs(self, event): + + # returns list of all tabs of a particular event + + try: + return event.tab_set.all() + except: + raise Http404() + + def get_files(self, tab): + + # returns list of all files of a particular tab + + try: + return tab.tabfile_set.all() + except: + raise Http404() + + def authenticate_req(self, req): + try: + eve = req.user.get_profile().is_coord_of + except: + return False + return True + + +class CoordDashboard(BaseView): + + """ + displays the coord dashboard depending on the logged in coords event + """ + + __name__ = 'CoordDashboard' + + def handle_GET(self, request, **kwargs): + initial = Update.objects.all() + update = sorted(initial, key=attrgetter('id'), reverse=True) + event = request.user.get_profile().is_coord_of + tabs = self.get_tabs(event) + return render_to_response('coord/dashboard.html', locals(), + context_instance=RequestContext(request)) + + +class TabFileSubmit(BaseView): + + """ + ajax file uploads are directed to this view + """ + + def handle_POST(self, request, **kwargs): + from django.conf import settings + + # These were the headers set by the function File() to pass additional data. + # raise Http404 + + filename = request.META['HTTP_X_FILE_NAME'] + display_name = request.META['HTTP_X_NAME'] + tab_id = request.META['HTTP_X_TAB_ID'] + + tab = Tab.objects.get(id=tab_id) + direc = os.path.join('/home/shaastra/public_html/2013/media', + 'events', str(tab.event.id), + tab._meta.object_name, str(tab.id)) + + # note that event and tab IDs and not their titles have been used to create folders so that renaming does not affect the folders + + if not os.path.exists(direc): + os.makedirs(direc) + path = os.path.join(direc, filename) + a = TabFile.objects.get_or_create(tab_file=path) + + # get_or_create returns a tuple whose second element is a boolean which is True if it is creating a new object. + # the first element is the object that has been created/found. + + if a[1]: + a[0].url = os.path.join( + '/2013/media', + 'events', + str(tab.event.id), + tab._meta.object_name, + str(tab.id), + filename, + ) + f = open(path, 'w') + with f as dest: + req = request + + # Right now the file comes as raw input (in form of binary strings). Unfortunately, this is the only way I know that will make ajax work with file uploads. + + foo = req.read(1024) + while foo: + dest.write(foo) + foo = req.read(1024) + a[0].title = display_name + a[0].tab = tab + a[0].save() + file_list = self.get_files(tab) + + template = loader.get_template('ajax/coord/file_list.html') + t = template.render(RequestContext(request, locals())) + + # the ajax function File() assigns this as the innerHTML of a div after the request has been completed. + + return HttpResponse(t) + + +def get_objective(ques_id): + try: + return ObjectiveQuestion.objects.get(id=ques_id) + except: + return None + + +def get_options(mcq): + try: + return mcq.mcqoption_set.all() + except: + return [] + + +class Registrations(BaseView): + + """ + displays the questions tab + """ + + def handle_GET(self, request, **kwargs): + if request.user.get_profile().is_coord_of.has_questionnaire: + return HttpReponse("Click on the link 'Submissions' to view the registrations" + ) + registrations = \ + request.user.get_profile().is_coord_of.participants.all() + return render_to_response('ajax/coord/registrations.html', + locals(), + context_instance=RequestContext(request)) + + +class Questions(BaseView): + + """ + displays the questions tab + """ + + def handle_GET(self, request, **kwargs): + if not request.user.get_profile().is_coord_of.has_questionnaire: + return HttpResponse("This event doesn't have a questionnaire" + ) + path = request.META['PATH_INFO'].split('/') + if path[3] == 'mcq': + try: + ques_id = path[4] + except: + ques_id = 0 + mcq = get_objective(ques_id) + options = get_options(mcq) + form = MCQForm(mcq, options) + template = 'ajax/coord/mcq_form.html' + elif path[3] == 'subj': + try: + ques_id = path[4] + ques = SubjectiveQuestion.objects.get(id=ques_id) + form = AddSubjectiveQuestionForm(instance=ques) + except: + form = AddSubjectiveQuestionForm() + template = 'ajax/coord/subj_form.html' + else: + event = request.user.get_profile().is_coord_of + text_questions = event.subjectivequestion_set.all() + mcqs = event.objectivequestion_set.all() + template = 'ajax/coord/question_tab.html' + return render_to_response(template, locals(), + context_instance=RequestContext(request)) + + +class MobApp(BaseView): + + """ + displays the mobapp tab + """ + + def handle_GET(self, request, **kwargs): + event = request.user.get_profile().is_coord_of + try: + form = MobAppWriteupForm(instance=event.mobapptab) + except: + form = MobAppWriteupForm() + return render_to_response('ajax/coord/add_edit_mobapptab.html', + locals(), + context_instance=RequestContext(request)) + + +class CustomTabs(BaseView): + + """ + displays the Custom tabs + """ + + def get_files(self, tab): + + # gets all files that are related to a particular tab + + try: + return tab.tabfile_set.all() + except: + raise Http404() + + def handle_GET(self, request, **kwargs): + path = request.META['PATH_INFO'].split('/') + if path[3]: + if path[3] == 'edit': + tab_id = path[4] + tab = Tab.objects.get(id=tab_id) + form = TabAddForm(instance=tab) + template = 'ajax/coord/tab_form.html' + elif path[3] == 'files': + if path[4] == 'rename': + tab_id = path[5] + file_id = path[6] + tab = Tab.objects.get(id=tab_id) + form = TabFile.objects.get(id=file_id) + actual_name = form.tab_file.name.split('/')[-1] + file_list = self.get_files(tab) + template = 'ajax/coord/file_rename.html' + else: + form = TabFileForm() + tab_id = path[4] + tab = Tab.objects.get(id=tab_id) + file_list = self.get_files(tab) + template = 'ajax/coord/file_form.html' + else: + tab_id = path[3] + tab = Tab.objects.get(id=tab_id) + file_list = self.get_files(tab) + template = 'ajax/coord/tab_detail.html' + else: + form = TabAddForm() + template = 'ajax/coord/tab_form.html' + return render_to_response(template, locals(), + context_instance=RequestContext(request)) + + +def AddUpdate(request): + """ + """ + +# return HttpResponse("blah") + + update_form = UpdateForm() + template = 'ajax/coord/update.html' + return render_to_response(template, locals(), + context_instance=RequestContext(request)) + + +@login_required(login_url=settings.SITE_URL + 'user/login/') +def EditUpdate(request, id=0): + """ + + """ + + update_form = UpdateForm(instance=Update.objects.get(id=id)) + return render_to_response('ajax/coord/editupdate.html', locals(), + context_instance=RequestContext(request)) + + +@login_required(login_url=settings.SITE_URL + 'user/login/') +def editevent(request, id=0): + """ + This is the home page view of the superuser + """ + +# if request.user.get_profile().is_core is False : +# return HttpResponseRedirect(settings.SITE_URL) + + event_form = AddEventForm(instance=Event.objects.get(id=id)) + return render_to_response('ajax/core/editevent.html', locals(), + context_instance=RequestContext(request)) + diff --git a/core/ajax.py b/core/ajax.py index 2bd0900..5ca706c 100644 --- a/core/ajax.py +++ b/core/ajax.py @@ -1,5 +1,7 @@ -#The variable Summary refers to the div where a table consisting event name and its coords is displayed -#The variable space refers to the div where different forms like add/edit event/coord are displayed +#!/usr/bin/python +# -*- coding: utf-8 -*- +# The variable Summary refers to the div where a table consisting event name and its coords is displayed +# The variable space refers to the div where different forms like add/edit event/coord are displayed from dajaxice.decorators import dajaxice_register from django.utils import simplejson @@ -10,125 +12,78 @@ from django.contrib.auth.models import User from users.models import UserProfile + @dajaxice_register def updateSummary(request): """ This function updates the table in summary div whenever a new event/coord is added or when an existing event/coord is edited or deleted """ + dajax = Dajax() - dajax.assign("#summary",'innerHTML',"") - event=Event.objects.order_by('id').all() + dajax.assign('#summary', 'innerHTML', + "
    S.NoEvent NameCoords
    " + ) + event = Event.objects.order_by('id').all() for e in event: - dajax.append("#event",'innerHTML',"") - coords=UserProfile.objects.filter(is_coord_of__title=e.title) - for c in coords: - dajax.append("#"+str(e.id),'innerHTML',"
  • "+str(c.user)+"") + dajax.append('#event', 'innerHTML', '
  • ") + dajax.script("window.location.hash=''") return dajax.json() + @dajaxice_register -def add_edit_event(request,form="",id=0): +def add_event(request, form): """ This function calls the AddEventForm from forms.py If a new event is being created, a blank form is displayed and the core can fill in necessary details. If an existing event's details is being edited, the same form is displayed populated with current event details for all fields """ + dajax = Dajax() - if form == "" : - if id: - template = loader.get_template('ajax/core/editevent.html') - event_form = AddEventForm(instance=Event.objects.get(id=id)) - html=template.render(RequestContext(request,locals())) - else: - template = loader.get_template('ajax/core/addevent.html') - event_form = AddEventForm() - html=template.render(RequestContext(request,locals())) - dajax.assign('#space', 'innerHTML', html) - return dajax.json() - if id: - event_form = AddEventForm(form, instance=Event.objects.get(id=id)) - else: - event_form = AddEventForm(form) + try: + tags = [] + tags.append(form['tags']) + form['tags'] = tags + except: + pass + event_form = AddEventForm(form) if event_form.is_valid(): - event_form.save() - dajax.assign("#space",'innerHTML',"") - dajax.script("updateSummary();") + event = event_form.save() + user_name = event.title.replace(' ', '_') + new_user = User(username=user_name, email=user_name + + '@shaastra.org') + new_user.set_password('default') + new_user.save() + userprofile = UserProfile(user=new_user, is_coord_of=event) + userprofile.save() + dajax.script('updateSummary();') + else: + template = loader.get_template('ajax/core/addevent.html') + html = template.render(RequestContext(request, locals())) + dajax.assign('.bbq-item', 'innerHTML', html) return dajax.json() -@dajaxice_register -def del_event(request,id): - """ - This function is called when the core wants to delete an event - - """ - dajax = Dajax() - event=Event.objects.get(id=id) - event.delete() - dajax.assign('#space', 'innerHTML', "") - dajax.script("updateSummary();") - return dajax.json() @dajaxice_register -def add_edit_coord(request,form="",id=0): - """ - This function calls the AddCoordForm from forms.py - If a new coord is being created, a blank form is displayed and the core can fill in necessary details. - If an existing coord's details is being edited, the same form is displayed populated with current coord details for all fields - +def del_event(request, id): """ - dajax = Dajax() - if form == "" : - if id: - template = loader.get_template('ajax/core/editcoord.html') - coord=User.objects.get(id=id) - coord_form = AddCoordForm(instance=coord,initial={'event':coord.get_profile().is_coord_of_id,}) - html=template.render(RequestContext(request,locals())) - else: - template = loader.get_template('ajax/core/addcoord.html') - coord_form = AddCoordForm() - html=template.render(RequestContext(request,locals())) - dajax.assign('#space', 'innerHTML', html) - return dajax.json() - if id: - coord_form = AddCoordForm(form, instance=User.objects.get(id=id)) - if coord_form.is_valid(): - coord=coord_form.save() - coord_profile=coord.get_profile() - coord_profile.is_coord_of_id=form['event'] - coord_profile.save() - dajax.assign("#space",'innerHTML',"") - else: - template = loader.get_template('ajax/core/editcoord.html') - html=template.render(RequestContext(request,locals())) - dajax.assign("#space",'innerHTML',html) - else: - coord_form = AddCoordForm(form) - if coord_form.is_valid(): - coord=coord_form.save() - coord.set_password("default") - coord.groups.add(request.user.groups.get_query_set()[1]) - coord.save() - coord_profile = UserProfile(user=coord, is_coord_of_id=form['event']) - coord_profile.save() - dajax.assign("#space",'innerHTML',"") - else: - template = loader.get_template('ajax/core/addcoord.html') - html=template.render(RequestContext(request,locals())) - dajax.assign("#space",'innerHTML',html) - dajax.script("updateSummary();") - return dajax.json() + This function is called when the core wants to delete an event -@dajaxice_register -def del_coord(request,id): """ - This function is called when the core wants to delete a coord - """ dajax = Dajax() - coord=User.objects.get(id=id) - coord.delete() - dajax.assign('#space', 'innerHTML', "") - dajax.script("updateSummary();") + event = Event.objects.get(id=id) + user_name = event.title.replace(' ', '_') + user = User.objects.get(username=user_name) + userprofile = UserProfile.objects.get(user=user) + userprofile.delete() + user.delete() + event.delete() + dajax.script('updateSummary();') return dajax.json() - diff --git a/core/forms.py b/core/forms.py index 27b2f16..3c1b491 100644 --- a/core/forms.py +++ b/core/forms.py @@ -1,25 +1,41 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- from django import forms from events.models import Event from django.contrib.auth.models import User from users.models import UserProfile +from chosen import forms as chosenforms +from events.models import * +from chosen import widgets as chosenwidgets + class AddEventForm(forms.ModelForm): - """ - This form is used to add/edit events - """ + tags = chosenforms.ChosenModelMultipleChoiceField(required=False, + queryset=Tag.objects.all()) + class Meta: + model = Event - exclude=('events_logo','questions','tags','category','updates',) -class AddCoordForm(forms.ModelForm): - """ - This form is used to add/edit coords + # fields = ('title','events_logo','tags') - """ - event= forms.ModelChoiceField(queryset=Event.objects.all(),empty_label='----------') + fields = ( + 'title', + 'events_logo', + 'tags', + 'category', + 'lock_status', + 'unlock_reason', + 'registrable_online', + 'team_event', + 'team_size_min', + 'team_size_max', + 'begin_registration', + 'has_tdp', + ) + widgets = {'lock_status': forms.HiddenInput(), + 'unlock_reason': forms.HiddenInput(), + 'category': chosenwidgets.ChosenSelect()} - class Meta: - model = User - fields=('username', 'email') diff --git a/core/models.py b/core/models.py index 85206e0..60ff6cc 100644 --- a/core/models.py +++ b/core/models.py @@ -1,2 +1,4 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- from django.db import models from django.contrib.auth.models import User diff --git a/core/tests.py b/core/tests.py index 501deb7..a9d5fb0 100644 --- a/core/tests.py +++ b/core/tests.py @@ -1,3 +1,6 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + """ This file demonstrates writing tests using the unittest module. These will pass when you run "manage.py test". @@ -9,8 +12,12 @@ class SimpleTest(TestCase): + def test_basic_addition(self): """ Tests that 1 + 1 always equals 2. """ + self.assertEqual(1 + 1, 2) + + diff --git a/core/urls.py b/core/urls.py index 7d77909..db65c85 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,8 +1,12 @@ +#!/usr/bin/python # -*- coding: utf-8 -*- + from django.conf import settings from django.conf.urls.defaults import * from core.views import * -urlpatterns = patterns('', - url(r'^$', home, name = 'home'), -) \ No newline at end of file +urlpatterns = patterns('', url(r'^addevent/', addevent, name='addevent' + ), url(r'^dashboard/(?P\d+)', + eventdashboard, name='event-dashboard'), + url(r'^dashboard/', include('coord.urls'), + name='dashboard'), url(r'^$', home, name='home')) diff --git a/core/views.py b/core/views.py index 06c53e8..a07e4b5 100644 --- a/core/views.py +++ b/core/views.py @@ -1,18 +1,86 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- from django.http import HttpResponse, HttpResponseRedirect, Http404 from django.contrib.auth.models import User from django.contrib.auth.decorators import login_required from django.shortcuts import render_to_response from django.template.context import Context, RequestContext from django.conf import settings +from core.forms import * +from django.views.decorators.csrf import csrf_exempt + @login_required(login_url=settings.SITE_URL + 'user/login/') def home(request): """ This is the home page view of the core """ - if request.user.get_profile().is_core is False : + + if request.user.get_profile().is_core is False: + return HttpResponseRedirect(settings.SITE_URL) + return render_to_response('core/home.html', locals(), + context_instance=RequestContext(request)) + + +@login_required(login_url=settings.SITE_URL + 'user/login/') +@csrf_exempt +def addevent(request): + """ + This is the home page view of the superuser + """ + + if request.user.get_profile().is_core is False \ + and not request.user.get_profile().is_coord_of: return HttpResponseRedirect(settings.SITE_URL) - return render_to_response('core/home.html', locals(), context_instance = RequestContext(request)) + if request.method == 'POST': + filename = request.META['HTTP_X_FILE_NAME'] + event_id = request.META['HTTP_X_EVENT_ID'] + direc = \ + os.path.join('/home/shaastra/public_html/2013/media/events' + , event_id) + + # note that event and tab IDs and not their titles have been used to create folders so that renaming does not affect the folders + if not os.path.exists(direc): + os.makedirs(direc) + path = os.path.join(direc, filename) + event = Event.objects.get(id=event_id) + event.events_logo = path.split('/public_html')[1] + event.save() + # get_or_create returns a tuple whose second element is a boolean which is True if it is creating a new object. + # the first element is the object that has been created/found. + f = open(path, 'w') + with f as dest: + req = request + + # Right now the file comes as raw input (in form of binary strings). Unfortunately, this is the only way I know that will make ajax work with file uploads. + + foo = req.read(1024) + while foo: + dest.write(foo) + foo = req.read(1024) + html = "

    " + event.category \ + + '
    ' + str(event) \ + + "

    B.end: - They don't clash - elif A.end < B.start: - They don't clash - else: - They clash - ''' + subEventList = SubEvent.objects.all() try: - subEventList = subEventList.exclude(id = self.id) + subEventList = subEventList.exclude(id=self.id) except: pass - + subEventClashMsgs = [] - + for subEvent in subEventList: if subEvent.venue != venue: @@ -60,12 +69,13 @@ def checkSubEventClash(self, venue, start, end): if subEvent.end_date_and_time <= start: # End date-time of subEvent is before start date-time of self continue # No clash - + # The events clash. # Must tell user from when to when the venue is booked. - subEventClashMsgs.append(u'%s is unavailable from %s to %s.' % (subEvent.venue, - subEvent.start_date_and_time, - subEvent.end_date_and_time)) + + subEventClashMsgs.append(u'%s is unavailable from %s to %s.' + % (subEvent.venue, subEvent.start_date_and_time, + subEvent.end_date_and_time)) if subEventClashMsgs: return subEventClashMsgs @@ -80,46 +90,64 @@ def clean(self): * The DTV of the sub-event must not clash with any other sub-event's DTV. * The last_modified field must be updated to the current date and time. """ + # References: # https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects # https://docs.djangoproject.com/en/dev/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other # http://stackoverflow.com/questions/2117048/django-overriding-the-clean-method-in-forms-question-about-raising-errors - + errors = [] super(SubEvent, self).clean() # Calling clean method of the super class # The start of the sub-event must not be after the end. # The start of the sub-event cannot be the same as the end + if self.start_date_and_time and self.end_date_and_time: + # Ensures that both these fields are valid + if self.start_date_and_time > self.end_date_and_time: - errors.append(u'Surely the event cannot start after it has ended!') + errors.append(u'Surely the event cannot start after it has ended!' + ) elif self.start_date_and_time == self.end_date_and_time: - errors.append(u'Surely the start and end time cannot be the same!') - + errors.append(u'Surely the start and end time cannot be the same!' + ) + # The DTV of the sub-event must not clash with any other sub-event's DTV. + if self.venue: + # Ensures that event is valid # Already checked validity of start and end dates and times - subEventClashErrorMsg = self.checkSubEventClash(self.venue, self.start_date_and_time, self.end_date_and_time) + + subEventClashErrorMsg = \ + self.checkSubEventClash(self.venue, + self.start_date_and_time, + self.end_date_and_time) if subEventClashErrorMsg is not None: errors.extend(subEventClashErrorMsg) - + # The sub-event's title must be unique under its event. + if self.title: + # Ensures that the title is valid - subEventList = SubEvent.objects.filter(event = self.event) + + subEventList = SubEvent.objects.filter(event=self.event) if self.id: - subEventList = subEventList.exclude(id = self.id) + subEventList = subEventList.exclude(id=self.id) for subEvent in subEventList: if subEvent.title == self.title: - errors.append(u'You already have a sub-event with the name "%s".' % subEvent.title) + errors.append(u'You already have a sub-event with the name "%s".' + % subEvent.title) break if errors: raise ValidationError(errors) - + # The last_modified field must be updated to the current date and time. + self.last_updated = datetime.now() + diff --git a/dtvpicker/tests.py b/dtvpicker/tests.py index 501deb7..a9d5fb0 100644 --- a/dtvpicker/tests.py +++ b/dtvpicker/tests.py @@ -1,3 +1,6 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + """ This file demonstrates writing tests using the unittest module. These will pass when you run "manage.py test". @@ -9,8 +12,12 @@ class SimpleTest(TestCase): + def test_basic_addition(self): """ Tests that 1 + 1 always equals 2. """ + self.assertEqual(1 + 1, 2) + + diff --git a/dtvpicker/urls.py b/dtvpicker/urls.py index d5fea7a..016b86f 100644 --- a/dtvpicker/urls.py +++ b/dtvpicker/urls.py @@ -1,29 +1,29 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- from django.conf.urls.defaults import patterns, url -from dtvpicker.views import dtvSummaryHandler, dtvSummaryByEvent, dtvSummaryByVenue, dtvSummaryByDate, \ - dtvSummaryByEvent_PDF, dtvSummaryByVenue_PDF, dtvSummaryByDate_PDF, \ - SubEventAdd, SubEventEdit, SubEventDelete, \ - LockEvent, UnlockEvent +from dtvpicker.views import dtvSummaryHandler, dtvSummaryByEvent, \ + dtvSummaryByVenue, dtvSummaryByDate, dtvSummaryByEvent_PDF, \ + dtvSummaryByVenue_PDF, dtvSummaryByDate_PDF, SubEventAdd, \ + SubEventEdit, SubEventDelete, LockEvent, UnlockEvent -urlpatterns = patterns('', - - # DTV Summary pages - On Screen - url(r'^Summary/$', dtvSummaryHandler), - url(r'^Summary/ByEvent/$', dtvSummaryByEvent), - url(r'^Summary/ByVenue/$', dtvSummaryByVenue), - url(r'^Summary/ByDate/$', dtvSummaryByDate), - - # DTV Summary pages - PDF Versions +urlpatterns = patterns( # DTV Summary pages - On Screen + # DTV Summary pages - PDF Versions + # Add, edit, delete sub-events + # Lock, unlock events + '', + url(r'^Summary/$', dtvSummaryHandler), + url(r'^Summary/ByEvent/$', dtvSummaryByEvent), + url(r'^Summary/ByVenue/$', dtvSummaryByVenue), + url(r'^Summary/ByDate/$', dtvSummaryByDate), url(r'^Summary/ByEvent/GeneratePDF/$', dtvSummaryByEvent_PDF), - url(r'^Summary/ByVenue/GeneratePDF/$', dtvSummaryByVenue_PDF), - url(r'^Summary/ByDate/GeneratePDF/$', dtvSummaryByDate_PDF), - - # Add, edit, delete sub-events + url(r'^Summary/ByVenue/GeneratePDF/$', dtvSummaryByVenue_PDF), + url(r'^Summary/ByDate/GeneratePDF/$', dtvSummaryByDate_PDF), url(r'^(?P.*)/AddSubEvent/$', SubEventAdd()), - url(r'^(?P.*)/EditSubEvent/(?P.*)/$', SubEventEdit()), - url(r'^(?P.*)/DeleteSubEvent/(?P.*)/$', SubEventDelete()), - - # Lock, unlock events + url(r'^(?P.*)/EditSubEvent/(?P.*)/$', + SubEventEdit()), + url(r'^(?P.*)/DeleteSubEvent/(?P.*)/$', + SubEventDelete()), url(r'^(?P.*)/LockEvent/$', LockEvent()), url(r'^(?P.*)/UnlockEvent/$', UnlockEvent()), -) + ) diff --git a/dtvpicker/views/BaseClasses.py b/dtvpicker/views/BaseClasses.py index 42385c4..6816915 100644 --- a/dtvpicker/views/BaseClasses.py +++ b/dtvpicker/views/BaseClasses.py @@ -1,31 +1,42 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + """This module holds the class definitions of all the abstract base classes.""" from django.http import HttpResponseNotAllowed, Http404 from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator +from django.conf import settings from dtvpicker.models import SubEvent from events.models import Event import datetime + class BaseView(object): + """Parent class. All classes below inherit this.""" + def __call__(self, request, **kwargs): + # Handles request and dispatches the corresponding handler based on the type of request (GET/POST) + requestMethod = request.META['REQUEST_METHOD'].upper() handler = getattr(self, 'handle_%s' % requestMethod, None) - + if handler is None: methods = [] for x in dir(self): if x.startswith('handle_'): methods.append(x[7:]) return HttpResponseNotAllowed(methods) - + return handler(request, **kwargs) - + + class ProtectedView(BaseView): + """ ProtectedView requires users to authenticate themselves before proceeding to the computation logic. """ @@ -33,16 +44,17 @@ class ProtectedView(BaseView): @method_decorator(login_required) def userAuthentication(self, request, **kwargs): return True - + def __call__(self, request, **kwargs): """ * Checks authentication * Handles request * Dispatches the corresponding handler based on the type of request (GET/POST) """ + # TODO(Anant, anant.girdhar@gmail.com): Overridden class method called after authentication. # Confirm working. - + # Overriding BaseView.__call__ to check authentication. if self.userAuthentication(request, **kwargs) == False: @@ -50,10 +62,13 @@ def __call__(self, request, **kwargs): return super(ProtectedView, self).__call__(request, **kwargs) # Calling the base class' __call__() and returning whatever is returned. + class CoordProtectedView(ProtectedView): + """ CoordProtectedView requires the user to be authenticated and to be a coord before proceeding to the computation logic. """ + @method_decorator(login_required) def userAuthentication(self, request, **kwargs): if request.user.get_profile().is_coord_of is not None: @@ -64,48 +79,61 @@ def permissionsGranted(self, request, **kwargs): """ Checks if the coord has permissions to access the requested event. """ + try: - if request.user.get_profile().is_coord_of != Event.objects.get(title = kwargs['event']): + if request.user.get_profile().is_coord_of \ + != Event.objects.get(title=kwargs['event']): return False # If the coord is not coord of the requested event return True except: - raise Http404('You do not have permissions to view this page.') - #TODO(Anant): Make multiple exceptions and put correct error messages. Eg.: + raise Http404('You do not have permissions to view this page.' + ) + + + # TODO(Anant): Make multiple exceptions and put correct error messages. Eg.: # If get_profile raises an exception: 'User profile does not exist.' # If is_coord_of raises an exception: 'User profile not configured correctly. Contact webmaster for more information.' # If Event.objects.get raises an exceptions: 'Event not found.' - + class CoreProtectedView(ProtectedView): + """ CoreProtectedView requires the user to be authenticated and to be a core before proceeding to the computation logic. """ + @method_decorator(login_required) def userAuthentication(self, request, **kwargs): if request.user.get_profile().is_core: return True return False - + + class SubEventAddEditDeleteABC(CoordProtectedView): + """ ABC (Abstract Base Class) for Adding, Editing and Deleting SubEvents. This includes the functions that are required for all these operations. """ + def getSubEvent(self, subevent_name, event_name): """ Gets the subevent referenced by the url from the database. Returns an instance of SubEvent having title as given in the url. If no object is found, raises Http404. """ + eventRequested = self.getEvent(event_name) - + try: # to get the sub-event - subeventRequested = SubEvent.objects.filter(event = eventRequested) - subeventRequested = subeventRequested.get(title = subevent_name) + subeventRequested = \ + SubEvent.objects.filter(event=eventRequested) + subeventRequested = \ + subeventRequested.get(title=subevent_name) except: raise Http404('Invalid sub-event supplied') # If the sub-event requested is not found in the database - + return subeventRequested - + def getEvent(self, event_name): """ Gets the event referenced by the url from the database. @@ -113,41 +141,49 @@ def getEvent(self, event_name): If no object is found, raises Http404. If the event is locked (ie. no editing is possible), raises Http404. """ + try: # To get the event - eventRequested = Event.objects.get(title = event_name) + eventRequested = Event.objects.get(title=event_name) except: raise Http404('Invalid event supplied') # If the event requested is not found in the database - + if eventRequested.lock_status == 'locked': raise Http404('Event cannot be modified') - + return eventRequested - + def updateEventLockStatus(self, eventToUpdate): - subEventList = SubEvent.objects.filter(event = eventToUpdate) + subEventList = SubEvent.objects.filter(event=eventToUpdate) newLockStatus = 'cannot_be_locked' - + if subEventList: newLockStatus = 'not_locked' for subevent in subEventList: - if not (subevent.start_date_and_time and subevent.end_date_and_time and subevent.venue): + if not (subevent.start_date_and_time + and subevent.end_date_and_time + and subevent.venue): newLockStatus = 'cannot_be_locked' break - + eventToUpdate.lock_status = newLockStatus eventToUpdate.unlock_reason = '' eventToUpdate.save() - + def updateAndSaveSubEvent(self, subEventObject, newSubEventData): subEventObject.title = newSubEventData['title'] - subEventObject.start_date_and_time = newSubEventData['start_date_and_time'] - subEventObject.end_date_and_time = newSubEventData['end_date_and_time'] + subEventObject.start_date_and_time = \ + newSubEventData['start_date_and_time'] + subEventObject.end_date_and_time = \ + newSubEventData['end_date_and_time'] subEventObject.venue = newSubEventData['venue'] subEventObject.event = newSubEventData['event'] - subEventObject.last_modified = datetime.datetime.now() # Is handled by SubEvent.clean(). + subEventObject.last_modified = datetime.datetime.now() # Is handled by SubEvent.clean(). + # Done here just to make sure. + subEventObject.save() self.updateEventLockStatus(subEventObject.event) + diff --git a/dtvpicker/views/lockUnlockEventViews.py b/dtvpicker/views/lockUnlockEventViews.py index 1b20195..2ca88f2 100644 --- a/dtvpicker/views/lockUnlockEventViews.py +++ b/dtvpicker/views/lockUnlockEventViews.py @@ -1,8 +1,12 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + """This module holds the views to lock and unlock events.""" from BaseClasses import CoordProtectedView, CoreProtectedView -from django.http import HttpResponseRedirect, HttpResponseForbidden, Http404 +from django.http import HttpResponseRedirect, HttpResponseForbidden, \ + Http404 from django.shortcuts import render_to_response from django.template import RequestContext from django.conf import settings @@ -11,86 +15,105 @@ from events.models import Event from dtvpicker.forms import EventUnlockForm + class LockEvent(CoordProtectedView): + """ Includes the views to Lock an event. An event can be locked only when its lock status is False. This happens when: * The event has atleast one registered sub-event. * All fields of all sub-events are filled. """ + def handle_GET(self, request, **kwargs): if self.permissionsGranted(request, **kwargs) == False: return HttpResponseForbidden() - + try: # To get the event - eventRequested = Event.objects.get(title = kwargs['event']) + eventRequested = Event.objects.get(title=kwargs['event']) except: raise Http404('Invalid event supplied.') # If the event requested is not found in the database if eventRequested.lock_status != 'not_locked': raise Http404('Event cannot be locked.') - - subEventList = SubEvent.objects.filter(event = eventRequested).order_by('start_date_and_time') - - return render_to_response ('dtvpicker/EventPages/lockEvent.html', locals(), context_instance = RequestContext(request)) - + + subEventList = \ + SubEvent.objects.filter(event=eventRequested).order_by('start_date_and_time' + ) + + return render_to_response('dtvpicker/EventPages/lockEvent.html' + , locals(), + context_instance=RequestContext(request)) + def handle_POST(self, request, **kwargs): if self.permissionsGranted(request, **kwargs) == False: return HttpResponseForbidden() - + try: # To get the event - eventRequested = Event.objects.get(title = kwargs['event']) + eventRequested = Event.objects.get(title=kwargs['event']) except: raise Http404('Invalid event supplied.') # If the event requested is not found in the database if eventRequested.lock_status != 'not_locked': raise Http404('Event cannot be locked.') - + eventRequested.lock_status = 'locked' eventRequested.unlock_reason = '' eventRequested.save() - - return HttpResponseRedirect(settings.SITE_URL + 'DTVPicker/Summary/') - + + return HttpResponseRedirect(settings.SITE_URL + + 'DTVPicker/Summary/') + + class UnlockEvent(CoreProtectedView): + """ Includes the views to Unlock an event. An event can be unlocked only when it is locked """ + def handle_GET(self, request, **kwargs): try: # To get the event - eventRequested = Event.objects.get(title = kwargs['event']) + eventRequested = Event.objects.get(title=kwargs['event']) except: raise Http404('Invalid event supplied.') # If the event requested is not found in the database - + if eventRequested.lock_status != 'locked': raise Http404('Event cannot be unlocked.') - + unlockForm = EventUnlockForm() - - subEventList = SubEvent.objects.filter(event = eventRequested).order_by('start_date_and_time') - - return render_to_response ('dtvpicker/EventPages/unlockEvent.html', locals(), context_instance = RequestContext(request)) - + + subEventList = \ + SubEvent.objects.filter(event=eventRequested).order_by('start_date_and_time' + ) + + return render_to_response('dtvpicker/EventPages/unlockEvent.html' + , locals(), + context_instance=RequestContext(request)) + def handle_POST(self, request, **kwargs): try: # To get the event - eventRequested = Event.objects.get(title = kwargs['event']) + eventRequested = Event.objects.get(title=kwargs['event']) except: raise Http404('Invalid event supplied.') # If the event requested is not found in the database - + if eventRequested.lock_status != 'locked': raise Http404('Event cannot be unlocked.') - + unlockForm = EventUnlockForm(request.POST) - + if unlockForm.is_valid(): submittedData = unlockForm.cleaned_data eventRequested.lock_status = 'unlocked_by_core' - eventRequested.unlock_reason = submittedData['unlock_reason'] + eventRequested.unlock_reason = submittedData['unlock_reason' + ] eventRequested.save() - - return HttpResponseRedirect(settings.SITE_URL + 'DTVPicker/Summary/') - - return render_to_response ('dtvpicker/EventPages/unlockEvent.html', locals(), context_instance = RequestContext(request)) + + return HttpResponseRedirect(settings.SITE_URL + + 'DTVPicker/Summary/') + + return render_to_response('dtvpicker/EventPages/unlockEvent.html' + , locals(), + context_instance=RequestContext(request)) diff --git a/dtvpicker/views/miscFunctions.py b/dtvpicker/views/miscFunctions.py index 9c81e73..0fd919a 100644 --- a/dtvpicker/views/miscFunctions.py +++ b/dtvpicker/views/miscFunctions.py @@ -1,16 +1,23 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + """This module holds some utility functions that are used in the DTV Picker feature.""" from events.models import Event + def PDFGenAllowed(): """ Checks if PDF Generation is allowed. Returns True if it is and False if not. PDF Generation is allowed if all events are locked. """ + eventList = Event.objects.all() - + for event in eventList: if event.lock_status != 'locked': return False return True + + diff --git a/dtvpicker/views/pdfGeneratingViews.py b/dtvpicker/views/pdfGeneratingViews.py index 2a4c6af..c8cca36 100644 --- a/dtvpicker/views/pdfGeneratingViews.py +++ b/dtvpicker/views/pdfGeneratingViews.py @@ -1,3 +1,6 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + """This module contains the views that generate the PDFs for the DTV Picker feature.""" from django.http import HttpResponse, HttpResponseForbidden @@ -7,6 +10,7 @@ from events.models import Event # reportlab imports are for pdf generation + from reportlab.pdfgen import canvas from reportlab.lib.pagesizes import A4 from reportlab.lib.units import cm @@ -18,339 +22,472 @@ from miscFunctions import PDFGenAllowed from dtvpicker.VenueChoices import VENUE_CHOICES + def PDFSetFont(pdf, font_name, font_size): """ Sets the font and returns the lineheight. """ + pdf.setFont(font_name, font_size) - ascent, descent = getAscentDescent(font_name, font_size) - return (ascent - descent) # Returns line height - - -def initNewPDFPage(pdf, doc_title, page_no, (pageWidth, pageHeight)): + (ascent, descent) = getAscentDescent(font_name, font_size) + return ascent - descent # Returns line height + + +def initNewPDFPage( + pdf, + doc_title, + page_no, + (pageWidth, pageHeight), + ): """ Paints the headers on every new page of the PDF document. Also returns the coordinates (x, y) where the last painting operation happened. """ + y = pageHeight - + # Leave a margin of one cm at the top + y = pageHeight - cm - + # Set font for 'SHAASTRA 2013' + lineheight = PDFSetFont(pdf, 'Times-Roman', 18) # SHAASTRA 2013 in centre - pdf.drawCentredString(pageWidth/2, y, 'SHAASTRA 2013') - y -= (lineheight + cm) - + + pdf.drawCentredString(pageWidth / 2, y, 'SHAASTRA 2013') + y -= lineheight + cm + # Set font for Document Title + lineheight = PDFSetFont(pdf, 'Times-Roman', 16) - + # Document Title in next line, centre aligned - pdf.drawCentredString(pageWidth/2, y, doc_title) - + + pdf.drawCentredString(pageWidth / 2, y, doc_title) + # Set font for Document Title + PDFSetFont(pdf, 'Times-Roman', 9) # Page number in same line, right aligned + pdf.drawRightString(pageWidth - cm, y, '#%d' % page_no) - - y -= (lineheight + cm) + + y -= lineheight + cm return y - + + @login_required def dtvSummaryByVenue_PDF(request): """ Generates and returns a PDF containing the DTV Summary (by venue). Accessible by cores only. """ + try: currentUserProfile = request.user.get_profile() except: + # If the user's profile is not available - return HttpResponse("Sorry. %s's user profile is not available." % request.user.username) - + + return HttpResponse("Sorry. %s's user profile is not available." + % request.user.username) + if not currentUserProfile.is_core: - return HttpResponseForbidden("Sorry. You do not have the required permissions to view this page.") - + return HttpResponseForbidden('Sorry. You do not have the required permissions to view this page.' + ) + if not PDFGenAllowed(): - return HttpResponse('The PDF cannot be generated until all events are locked.') - + return HttpResponse('The PDF cannot be generated until all events are locked.' + ) + # Create the HttpResponse object with the appropriate PDF headers. + response = HttpResponse(mimetype='application/pdf') - response['Content-Disposition'] = 'attachment; filename=DTVSummary-ByVenue.pdf' - + response['Content-Disposition'] = \ + 'attachment; filename=DTVSummary-ByVenue.pdf' + # Create the PDF object, using the response object as its "file." - pdf = canvas.Canvas(response, pagesize = A4) - + + pdf = canvas.Canvas(response, pagesize=A4) + # Define the title of the document as printed in the document header. + doc_title = 'DTV Summary (By Venue)' # Get the width and height of the page. - A4Width, A4Height = A4 - + + (A4Width, A4Height) = A4 + # Page number + pageNo = 1 # Paint the headers and get the coordinates + y = initNewPDFPage(pdf, doc_title, pageNo, A4) - + # Setting x to be a cm from the left edge + x = cm - + # Print DTV Summary in PDF - + # Get all venues + requestedVenueList = [] venues = VENUE_CHOICES for (venue_code, venue_name) in venues: requestedVenueList.append(venue_code) - + # Sort venue list in alphabetical order - requestedVenueList.sort() - + + requestedVenueList.sort() + # List to hold venues where no events are happening + venuesWithNoEvents = [] + # Will be printed at the end of the document - + for requestedVenue in requestedVenueList: + # Get all sub-events happening at requestedVenue - Venue_SubEventList = SubEvent.objects.filter(venue = requestedVenue).order_by('start_date_and_time') # List of sub-events happening at + + Venue_SubEventList = \ + SubEvent.objects.filter(venue=requestedVenue).order_by('start_date_and_time' + ) # List of sub-events happening at + # requestedVenue + if not Venue_SubEventList: # If there are no events happening at the venue venuesWithNoEvents.append(requestedVenue) continue # Construct the table data - tableData = [ ['Event', 'Sub-Event', 'Start Date', 'Start Time', 'End Date', 'End Time', 'Duration', ], ] + + tableData = [[ + 'Event', + 'Sub-Event', + 'Start Date', + 'Start Time', + 'End Date', + 'End Time', + 'Duration', + ]] for subevent in Venue_SubEventList: - tableData.append([subevent.event.title, - subevent.title, - subevent.start_date_and_time.date().strftime("%d-%b-%y"), - subevent.start_date_and_time.time().strftime("%I:%M %p"), - subevent.end_date_and_time.date().strftime("%d-%b-%y"), - subevent.end_date_and_time.time().strftime("%I:%M %p"), - strfdelta(subevent.end_date_and_time - subevent.start_date_and_time, "%H:%M"), ]) + tableData.append([ + subevent.event.title, + subevent.title, + subevent.start_date_and_time.date().strftime('%d-%b-%y' + ), + subevent.start_date_and_time.time().strftime('%I:%M %p' + ), + subevent.end_date_and_time.date().strftime('%d-%b-%y'), + subevent.end_date_and_time.time().strftime('%I:%M %p'), + strfdelta(subevent.end_date_and_time + - subevent.start_date_and_time, '%H:%M'), + ]) + # For strftime documentation and the format specifiers see # http://docs.python.org/library/datetime.html#strftime-strptime-behavior - t = Table(tableData, repeatRows = 1) - + + t = Table(tableData, repeatRows=1) + # Set the table style - tableStyle = TableStyle([('FONTNAME', (0,1), (-1,-1), 'Times-Roman'), # Font style for Table Data - ('FONTNAME', (0,0), (-1,0), 'Times-Bold'), # Font style for Table Header - ('FONTSIZE', (0,0), (-1,-1), 12), - ('ALIGN', (0,0), (-1,-1), 'CENTRE'), - ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), - ('GRID', (0,0), (-1,-1), 1, colors.black), - ]) + + tableStyle = TableStyle([ # Font style for Table Data + # Font style for Table Header + ('FONTNAME', (0, 1), (-1, -1), 'Times-Roman'), + ('FONTNAME', (0, 0), (-1, 0), 'Times-Bold'), + ('FONTSIZE', (0, 0), (-1, -1), 12), + ('ALIGN', (0, 0), (-1, -1), 'CENTRE'), + ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), + ('GRID', (0, 0), (-1, -1), 1, colors.black), + ]) t.setStyle(tableStyle) - + # Set the font for the venue code + lineheight = PDFSetFont(pdf, 'Times-Roman', 14) - availableWidth = A4Width - 2*cm # Leaving margins of 1 cm on both sides - availableHeight = y - (lineheight + 0.2*cm) # (lineheight + 0.2*cm) subtracted to include title height - tableWidth, tableHeight = t.wrap(availableWidth, availableHeight) # find required space + availableWidth = A4Width - 2 * cm # Leaving margins of 1 cm on both sides + availableHeight = y - (lineheight + 0.2 * cm) # (lineheight + 0.2*cm) subtracted to include title height + (tableWidth, tableHeight) = t.wrap(availableWidth, + availableHeight) # find required space if tableHeight <= availableHeight: # Paint the venue code + pdf.drawString(x, y, requestedVenue) + # Add spacing - y -= (lineheight + 0.2*cm) - t.drawOn(pdf, x, y-tableHeight) - y -= (tableHeight + cm) # Find next position for painting + y -= lineheight + 0.2 * cm + + t.drawOn(pdf, x, y - tableHeight) + y -= tableHeight + cm # Find next position for painting else: pdf.showPage() pageNo += 1 y = initNewPDFPage(pdf, doc_title, pageNo, A4) # Set the font for the venue code - lineheight = PDFSetFont(pdf, 'Times-Roman', 14) + + lineheight = PDFSetFont(pdf, 'Times-Roman', 14) + # Paint the venue code + pdf.drawString(x, y, requestedVenue) + # Add spacing - y -= (lineheight + 0.2*cm) - availableHeight = y - (lineheight + 0.2*cm) # (lineheight + 0.2*cm) subtracted to include title height - tableWidth, tableHeight = t.wrap(availableWidth, availableHeight) + y -= lineheight + 0.2 * cm + + availableHeight = y - (lineheight + 0.2 * cm) # (lineheight + 0.2*cm) subtracted to include title height + (tableWidth, tableHeight) = t.wrap(availableWidth, + availableHeight) + + t.drawOn(pdf, x, y - tableHeight) + y -= tableHeight + cm # Find next position for painting - t.drawOn(pdf, x, y-tableHeight) - y -= (tableHeight + cm) # Find next position for painting - y -= cm - + if venuesWithNoEvents: + # Paint all the venues that have no events happening # Set the font for all following text + lineheight = PDFSetFont(pdf, 'Times-Roman', 14) # Calculate the space requried for all following text + numberOfVenues = venuesWithNoEvents.__len__() - + availableHeight = y - - spaceRequired = lineheight + (cm / 2) + (numberOfVenues * lineheight) + ((numberOfVenues - 1) * (cm / 3)) + + spaceRequired = lineheight + cm / 2 + numberOfVenues \ + * lineheight + (numberOfVenues - 1) * (cm / 3) + # Explanation for the above calculation: # lineheight --> for message that says 'There are no events happening at the following venues:' # (cm / 2) --> for the space after the message # (numberOfVenues * lineheight) --> for each venue (one venue per line) # ((numberOfVenues - 1) * (cm / 3)) --> for the space after each venue (except the last) - + if spaceRequired > availableHeight: + # Paint on next page # If there is space available on the same page, this will not happen and the painting will continue on the same page + pdf.showPage() pageNo += 1 y = initNewPDFPage(pdf, doc_title, pageNo, A4) - + # Set the font for all following text + lineheight = PDFSetFont(pdf, 'Times-Roman', 14) - - pdf.drawString(x, y, 'There are no events happening at the following venues:') - y -= (lineheight + (cm/2)) - + + pdf.drawString(x, y, + 'There are no events happening at the following venues:' + ) + y -= lineheight + cm / 2 + for requestedVenue in venuesWithNoEvents: - + # Check if the next event can be painted on the same page, else change the page + availableHeight = y if availableHeight < lineheight: pdf.showPage() pageNo += 1 y = initNewPDFPage(pdf, doc_title, pageNo, A4) - + # Set the font for all following text + lineheight = PDFSetFont(pdf, 'Times-Roman', 14) pdf.drawString(x, y, requestedVenue) - y -= (lineheight + (cm/3)) + y -= lineheight + cm / 3 pdf.showPage() pdf.save() - - return response - + + return response + + @login_required def dtvSummaryByDate_PDF(request): """ Generates and returns a PDF containing the DTV Summary (by date). Accessible by cores only. """ + try: currentUserProfile = request.user.get_profile() except: + # If the user's profile is not available - return HttpResponse("Sorry. %s's user profile is not available." % request.user.username) - + + return HttpResponse("Sorry. %s's user profile is not available." + % request.user.username) + if not currentUserProfile.is_core: - return HttpResponseForbidden("Sorry. You do not have the required permissions to view this page.") - + return HttpResponseForbidden('Sorry. You do not have the required permissions to view this page.' + ) + if not PDFGenAllowed(): - return HttpResponse('The PDF cannot be generated until all events are locked.') - + return HttpResponse('The PDF cannot be generated until all events are locked.' + ) + # Create the HttpResponse object with the appropriate PDF headers. + response = HttpResponse(mimetype='application/pdf') - response['Content-Disposition'] = 'attachment; filename=DTVSummary-ByDate.pdf' - + response['Content-Disposition'] = \ + 'attachment; filename=DTVSummary-ByDate.pdf' + # Create the PDF object, using the response object as its "file." - pdf = canvas.Canvas(response, pagesize = A4) - + + pdf = canvas.Canvas(response, pagesize=A4) + # Define the title of the document as printed in the document header. + doc_title = 'DTV Summary (By Date)' # Get the width and height of the page. - A4Width, A4Height = A4 - + + (A4Width, A4Height) = A4 + # Page number + pageNo = 1 # Paint the headers and get the coordinates + y = initNewPDFPage(pdf, doc_title, pageNo, A4) - + # Setting x to be a cm from the left edge + x = cm - + # Print DTV Summary in PDF - + # Get all dates + requestedDateList = [] - subEventList = SubEvent.objects.all().order_by('start_date_and_time') # List of all sub-events + subEventList = SubEvent.objects.all().order_by('start_date_and_time' + ) # List of all sub-events for subEvent in subEventList: if subEvent.start_date_and_time.date() not in requestedDateList: requestedDateList.append(subEvent.start_date_and_time.date()) - + for requestedDate in requestedDateList: + # Get all sub-events happening at requestedVenue - Date_SubEventList = SubEvent.objects.filter(start_date_and_time__startswith = requestedDate).order_by('start_date_and_time') + + Date_SubEventList = \ + SubEvent.objects.filter(start_date_and_time__startswith=requestedDate).order_by('start_date_and_time' + ) + # List of sub-events hapenning on requestedDate # For the contains part see: # http://stackoverflow.com/questions/1317714/how-can-i-filter-a-date-of-a-datetimefield-in-django # Construct the table data - tableData = [ ['Event', 'Sub-Event', 'Start Time', 'End Date', 'End Time', 'Venue', 'Duration', ], ] + + tableData = [[ + 'Event', + 'Sub-Event', + 'Start Time', + 'End Date', + 'End Time', + 'Venue', + 'Duration', + ]] for subevent in Date_SubEventList: - tableData.append([subevent.event.title, - subevent.title, - subevent.start_date_and_time.time().strftime("%I:%M %p"), - subevent.end_date_and_time.date().strftime("%d-%b-%y"), - subevent.end_date_and_time.time().strftime("%I:%M %p"), - subevent.venue, - strfdelta(subevent.end_date_and_time - subevent.start_date_and_time, "%H:%M"), ]) + tableData.append([ + subevent.event.title, + subevent.title, + subevent.start_date_and_time.time().strftime('%I:%M %p' + ), + subevent.end_date_and_time.date().strftime('%d-%b-%y'), + subevent.end_date_and_time.time().strftime('%I:%M %p'), + subevent.venue, + strfdelta(subevent.end_date_and_time + - subevent.start_date_and_time, '%H:%M'), + ]) + # For strftime documentation and the format specifiers see # http://docs.python.org/library/datetime.html#strftime-strptime-behavior - t = Table(tableData, repeatRows = 1) - + + t = Table(tableData, repeatRows=1) + # Set the table style - tableStyle = TableStyle([('FONTNAME', (0,1), (-1,-1), 'Times-Roman'), # Font style for Table Data - ('FONTNAME', (0,0), (-1,0), 'Times-Bold'), # Font style for Table Header - ('FONTSIZE', (0,0), (-1,-1), 12), - ('ALIGN', (0,0), (-1,-1), 'CENTRE'), - ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), - ('GRID', (0,0), (-1,-1), 1, colors.black), - ]) + + tableStyle = TableStyle([ # Font style for Table Data + # Font style for Table Header + ('FONTNAME', (0, 1), (-1, -1), 'Times-Roman'), + ('FONTNAME', (0, 0), (-1, 0), 'Times-Bold'), + ('FONTSIZE', (0, 0), (-1, -1), 12), + ('ALIGN', (0, 0), (-1, -1), 'CENTRE'), + ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), + ('GRID', (0, 0), (-1, -1), 1, colors.black), + ]) t.setStyle(tableStyle) - + # Set the font for the date + lineheight = PDFSetFont(pdf, 'Times-Roman', 14) - availableWidth = A4Width - 2*cm # Leaving margins of 1 cm on both sides - availableHeight = y - (lineheight + 0.2*cm) # (lineheight + 0.2*cm) subtracted to include title height - tableWidth, tableHeight = t.wrap(availableWidth, availableHeight) # find required space + availableWidth = A4Width - 2 * cm # Leaving margins of 1 cm on both sides + availableHeight = y - (lineheight + 0.2 * cm) # (lineheight + 0.2*cm) subtracted to include title height + (tableWidth, tableHeight) = t.wrap(availableWidth, + availableHeight) # find required space if tableHeight <= availableHeight: # Paint the date - pdf.drawString(x, y, requestedDate.strftime("%A %d %B %Y")) + + pdf.drawString(x, y, requestedDate.strftime('%A %d %B %Y')) + # Add spacing - y -= (lineheight + 0.2*cm) - t.drawOn(pdf, x, y-tableHeight) - y -= (tableHeight + cm) # Find next position for painting + y -= lineheight + 0.2 * cm + + t.drawOn(pdf, x, y - tableHeight) + y -= tableHeight + cm # Find next position for painting else: pdf.showPage() pageNo += 1 y = initNewPDFPage(pdf, doc_title, pageNo, A4) # Set the font for the date - lineheight = PDFSetFont(pdf, 'Times-Roman', 14) + + lineheight = PDFSetFont(pdf, 'Times-Roman', 14) + # Paint the date + pdf.drawString(x, y, requestedDate) + # Add spacing - y -= (lineheight + 0.2*cm) - availableHeight = y - (lineheight + 0.2*cm) # (lineheight + 0.2*cm) subtracted to include title height - tableWidth, tableHeight = t.wrap(availableWidth, availableHeight) + y -= lineheight + 0.2 * cm + + availableHeight = y - (lineheight + 0.2 * cm) # (lineheight + 0.2*cm) subtracted to include title height + (tableWidth, tableHeight) = t.wrap(availableWidth, + availableHeight) + + t.drawOn(pdf, x, y - tableHeight) + y -= tableHeight + cm # Find next position for painting - t.drawOn(pdf, x, y-tableHeight) - y -= (tableHeight + cm) # Find next position for painting - pdf.showPage() pdf.save() - - return response - + + return response + @login_required def dtvSummaryByEvent_PDF(request): @@ -358,107 +495,157 @@ def dtvSummaryByEvent_PDF(request): Generates and returns a PDF containing the DTV Summary (by event). Accessible by cores only. """ + try: currentUserProfile = request.user.get_profile() except: + # If the user's profile is not available - return HttpResponse("Sorry. %s's user profile is not available." % request.user.username) - + + return HttpResponse("Sorry. %s's user profile is not available." + % request.user.username) + if not currentUserProfile.is_core: - return HttpResponseForbidden("Sorry. You do not have the required permissions to view this page.") - + return HttpResponseForbidden('Sorry. You do not have the required permissions to view this page.' + ) + if not PDFGenAllowed(): - return HttpResponse('The PDF cannot be generated until all events are locked.') - + return HttpResponse('The PDF cannot be generated until all events are locked.' + ) + # Create the HttpResponse object with the appropriate PDF headers. + response = HttpResponse(mimetype='application/pdf') - response['Content-Disposition'] = 'attachment; filename=DTVSummary-ByEvent.pdf' - + response['Content-Disposition'] = \ + 'attachment; filename=DTVSummary-ByEvent.pdf' + # Create the PDF object, using the response object as its "file." - pdf = canvas.Canvas(response, pagesize = A4) - + + pdf = canvas.Canvas(response, pagesize=A4) + # Define the title of the document as printed in the document header. + doc_title = 'DTV Summary (By Event)' # Get the width and height of the page. - A4Width, A4Height = A4 - + + (A4Width, A4Height) = A4 + # Page number + pageNo = 1 # Paint the headers and get the coordinates + y = initNewPDFPage(pdf, doc_title, pageNo, A4) - + # Setting x to be a cm from the left edge + x = cm - + # Print DTV Summary in PDF - + # Get all events + requestedEventList = Event.objects.all() - + for requestedEvent in requestedEventList: + # Get all sub-events under the event - Event_SubEventList = SubEvent.objects.filter(event = requestedEvent).order_by('start_date_and_time') # List of sub-events under + + Event_SubEventList = \ + SubEvent.objects.filter(event=requestedEvent).order_by('start_date_and_time' + ) # List of sub-events under + # requestedEvent # Construct the table data - tableData = [ ['Sub-Event', 'Venue', 'Start Date', 'Start Time', 'End Date', 'End Time', 'Duration', ], ] + + tableData = [[ + 'Sub-Event', + 'Venue', + 'Start Date', + 'Start Time', + 'End Date', + 'End Time', + 'Duration', + ]] for subevent in Event_SubEventList: - tableData.append([subevent.title, - subevent.venue, - subevent.start_date_and_time.date().strftime("%d-%b-%y"), - subevent.start_date_and_time.time().strftime("%I:%M %p"), - subevent.end_date_and_time.date().strftime("%d-%b-%y"), - subevent.end_date_and_time.time().strftime("%I:%M %p"), - strfdelta(subevent.end_date_and_time - subevent.start_date_and_time, "%H:%M"), ]) + tableData.append([ + subevent.title, + subevent.venue, + subevent.start_date_and_time.date().strftime('%d-%b-%y' + ), + subevent.start_date_and_time.time().strftime('%I:%M %p' + ), + subevent.end_date_and_time.date().strftime('%d-%b-%y'), + subevent.end_date_and_time.time().strftime('%I:%M %p'), + strfdelta(subevent.end_date_and_time + - subevent.start_date_and_time, '%H:%M'), + ]) + # For strftime documentation and the format specifiers see # http://docs.python.org/library/datetime.html#strftime-strptime-behavior - t = Table(tableData, repeatRows = 1) - + + t = Table(tableData, repeatRows=1) + # Set the table style - tableStyle = TableStyle([('FONTNAME', (0,1), (-1,-1), 'Times-Roman'), # Font style for Table Data - ('FONTNAME', (0,0), (-1,0), 'Times-Bold'), # Font style for Table Header - ('FONTSIZE', (0,0), (-1,-1), 12), - ('ALIGN', (0,0), (-1,-1), 'CENTRE'), - ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), - ('GRID', (0,0), (-1,-1), 1, colors.black), - ]) + + tableStyle = TableStyle([ # Font style for Table Data + # Font style for Table Header + ('FONTNAME', (0, 1), (-1, -1), 'Times-Roman'), + ('FONTNAME', (0, 0), (-1, 0), 'Times-Bold'), + ('FONTSIZE', (0, 0), (-1, -1), 12), + ('ALIGN', (0, 0), (-1, -1), 'CENTRE'), + ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), + ('GRID', (0, 0), (-1, -1), 1, colors.black), + ]) t.setStyle(tableStyle) - + # Set the font for the event title + lineheight = PDFSetFont(pdf, 'Times-Roman', 14) - availableWidth = A4Width - 2*cm # Leaving margins of 1 cm on both sides - availableHeight = y - (lineheight + 0.2*cm) # (lineheight + 0.2*cm) subtracted to include title height - tableWidth, tableHeight = t.wrap(availableWidth, availableHeight) # find required space + availableWidth = A4Width - 2 * cm # Leaving margins of 1 cm on both sides + availableHeight = y - (lineheight + 0.2 * cm) # (lineheight + 0.2*cm) subtracted to include title height + (tableWidth, tableHeight) = t.wrap(availableWidth, + availableHeight) # find required space if tableHeight <= availableHeight: # Paint the event title + pdf.drawString(x, y, requestedEvent.title) + # Add spacing - y -= (lineheight + 0.2*cm) - t.drawOn(pdf, x, y-tableHeight) - y -= (tableHeight + cm) # Find next position for painting + y -= lineheight + 0.2 * cm + + t.drawOn(pdf, x, y - tableHeight) + y -= tableHeight + cm # Find next position for painting else: pdf.showPage() pageNo += 1 y = initNewPDFPage(pdf, doc_title, pageNo, A4) # Set the font for the event title - lineheight = PDFSetFont(pdf, 'Times-Roman', 14) + + lineheight = PDFSetFont(pdf, 'Times-Roman', 14) + # Paint the event title + pdf.drawString(x, y, requestedEvent.title) + # Add spacing - y -= (lineheight + 0.2*cm) - availableHeight = y - (lineheight + 0.2*cm) # (lineheight + 0.2*cm) subtracted to include title height - tableWidth, tableHeight = t.wrap(availableWidth, availableHeight) + y -= lineheight + 0.2 * cm - t.drawOn(pdf, x, y-tableHeight) - y -= (tableHeight + cm) # Find next position for painting + availableHeight = y - (lineheight + 0.2 * cm) # (lineheight + 0.2*cm) subtracted to include title height + (tableWidth, tableHeight) = t.wrap(availableWidth, + availableHeight) + + t.drawOn(pdf, x, y - tableHeight) + y -= tableHeight + cm # Find next position for painting pdf.showPage() pdf.save() - + return response diff --git a/dtvpicker/views/subeventViews.py b/dtvpicker/views/subeventViews.py index df38354..6d32ec2 100644 --- a/dtvpicker/views/subeventViews.py +++ b/dtvpicker/views/subeventViews.py @@ -1,8 +1,12 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + """This module holds the views to add, edit and delete sub-events.""" from BaseClasses import SubEventAddEditDeleteABC -from django.http import HttpResponseForbidden, HttpResponseRedirect, Http404 +from django.http import HttpResponseForbidden, HttpResponseRedirect, \ + Http404 from django.shortcuts import render_to_response from django.template import RequestContext from django.conf import settings @@ -11,113 +15,145 @@ from events.models import Event from dtvpicker.forms import SubEventForm + class SubEventAdd(SubEventAddEditDeleteABC): + """ Adding a sub-event to the database. Permissions: Coords only. Access: Only own events. """ - + def handle_GET(self, request, **kwargs): if self.permissionsGranted(request, **kwargs) == False: return HttpResponseForbidden() - + eventRequested = self.getEvent(kwargs['event']) - - form = SubEventForm(initial = {'event' : '%d' % eventRequested.id, }) + + form = SubEventForm(initial={'event': '%d' % eventRequested.id}) form_mode = 'add' # For re-using the template (only difference: add/edit button) - return render_to_response ('dtvpicker/SubeventPages/addEditSubEvent.html', locals(), context_instance = RequestContext(request)) - + return render_to_response('dtvpicker/SubeventPages/addEditSubEvent.html' + , locals(), + context_instance=RequestContext(request)) + def handle_POST(self, request, **kwargs): if self.permissionsGranted(request, **kwargs) == False: return HttpResponseForbidden() - + eventRequested = self.getEvent(kwargs['event']) - + formDataReceived = request.POST.copy() formDataReceived['event'] = eventRequested.id - + form = SubEventForm(formDataReceived) - + if form.is_valid(): newSubEventData = form.cleaned_data newSubEvent = SubEvent() self.updateAndSaveSubEvent(newSubEvent, newSubEventData) - return HttpResponseRedirect(settings.SITE_URL + 'DTVPicker/Summary/') - + return HttpResponseRedirect(settings.SITE_URL + + 'DTVPicker/Summary/') + form_mode = 'add' # For re-using the template (only difference: add/edit button) - return render_to_response ('dtvpicker/SubeventPages/addEditSubEvent.html', locals(), context_instance = RequestContext(request)) - + return render_to_response('dtvpicker/SubeventPages/addEditSubEvent.html' + , locals(), + context_instance=RequestContext(request)) + + class SubEventEdit(SubEventAddEditDeleteABC): + """ Editing details of sub-event. Permissions: Coords only. Access: Only own events. """ + def handle_GET(self, request, **kwargs): if self.permissionsGranted(request, **kwargs) == False: return HttpResponseForbidden() eventRequested = self.getEvent(kwargs['event']) - subeventRequested = self.getSubEvent(kwargs['subevent'], kwargs['event']) + subeventRequested = self.getSubEvent(kwargs['subevent'], + kwargs['event']) - form = SubEventForm(initial = {'title' : subeventRequested.title, - 'start_date_and_time' : subeventRequested.start_date_and_time, - 'end_date_and_time' : subeventRequested.end_date_and_time, - 'venue' : subeventRequested.venue, - 'event' : eventRequested, }) + form = SubEventForm(initial={ + 'title': subeventRequested.title, + 'start_date_and_time': subeventRequested.start_date_and_time, + 'end_date_and_time': subeventRequested.end_date_and_time, + 'venue': subeventRequested.venue, + 'event': eventRequested, + }) form_mode = 'edit' # For re-using the template (only difference: add/edit button) - return render_to_response ('dtvpicker/SubeventPages/addEditSubEvent.html', locals(), context_instance = RequestContext(request)) - + return render_to_response('dtvpicker/SubeventPages/addEditSubEvent.html' + , locals(), + context_instance=RequestContext(request)) + def handle_POST(self, request, **kwargs): if self.permissionsGranted(request, **kwargs) == False: return HttpResponseForbidden() eventRequested = self.getEvent(kwargs['event']) - subeventRequested = self.getSubEvent(kwargs['subevent'], kwargs['event']) - + subeventRequested = self.getSubEvent(kwargs['subevent'], + kwargs['event']) + formDataReceived = request.POST.copy() - form = SubEventForm(formDataReceived, instance = self.getSubEvent(kwargs['subevent'], kwargs['event'])) - # Here I have not set the instance as subeventRequested + form = SubEventForm(formDataReceived, + instance=self.getSubEvent(kwargs['subevent' + ], kwargs['event'])) + + # Here I have not set the instance as subeventRequested # (although I use it for almost everything else) # but rather I have called the getSubEvent method again # because if the form is posted with a different title # then the title of the subeventRequested object is also updated. # This does not have any effect on this method - # but I have used subeventRequested in the template for displaying the + # but I have used subeventRequested in the template for displaying the # the sub-event's title which changes although you still want to update the same instance! if form.is_valid(): newSubEventData = form.cleaned_data newSubEvent = subeventRequested # We want to update this SubEvent instance self.updateAndSaveSubEvent(newSubEvent, newSubEventData) - return HttpResponseRedirect(settings.SITE_URL + 'DTVPicker/Summary/') + return HttpResponseRedirect(settings.SITE_URL + + 'DTVPicker/Summary/') form_mode = 'edit' # For re-using the template (only difference: add/edit button) - return render_to_response ('dtvpicker/SubeventPages/addEditSubEvent.html', locals(), context_instance = RequestContext(request)) - + return render_to_response('dtvpicker/SubeventPages/addEditSubEvent.html' + , locals(), + context_instance=RequestContext(request)) + + class SubEventDelete(SubEventAddEditDeleteABC): + """ Deleting sub-event. Permissions: Coords only. Access: Only own events. - """ + """ + def handle_GET(self, request, **kwargs): if self.permissionsGranted(request, **kwargs) == False: return HttpResponseForbidden() eventRequested = self.getEvent(kwargs['event']) - subeventRequested = self.getSubEvent(kwargs['subevent'], kwargs['event']) + subeventRequested = self.getSubEvent(kwargs['subevent'], + kwargs['event']) + + return render_to_response('dtvpicker/SubeventPages/deleteSubEvent.html' + , locals(), + context_instance=RequestContext(request)) - return render_to_response ('dtvpicker/SubeventPages/deleteSubEvent.html', locals(), context_instance = RequestContext(request)) - def handle_POST(self, request, **kwargs): if self.permissionsGranted(request, **kwargs) == False: return HttpResponseForbidden() - subeventRequested = self.getSubEvent(kwargs['subevent'], kwargs['event']) + subeventRequested = self.getSubEvent(kwargs['subevent'], + kwargs['event']) subeventRequested.delete() self.updateEventLockStatus(self.getEvent(kwargs['event'])) - return HttpResponseRedirect(settings.SITE_URL + 'DTVPicker/Summary/') + + return HttpResponseRedirect(settings.SITE_URL + + 'DTVPicker/Summary/') + diff --git a/dtvpicker/views/summaryViews.py b/dtvpicker/views/summaryViews.py index ad9a1a4..1e4a78d 100644 --- a/dtvpicker/views/summaryViews.py +++ b/dtvpicker/views/summaryViews.py @@ -1,6 +1,10 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + """This module holds the views that show the DTV Summary on screen.""" -from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse +from django.http import HttpResponseRedirect, HttpResponseForbidden, \ + HttpResponse from django.shortcuts import render_to_response from django.template import RequestContext from django.contrib.auth.decorators import login_required @@ -12,6 +16,7 @@ from events.models import Event from dtvpicker.VenueChoices import VENUE_CHOICES + @login_required def dtvSummaryHandler(request): """ @@ -20,23 +25,33 @@ def dtvSummaryHandler(request): If a Core logs in, and all the events are unlocked, it gives three options to see the DTV Summary by Event / Venue / Date. If all events are not locked, the Core is redirected to the By Event Page. """ + try: currentUserProfile = request.user.get_profile() except: + # If the user's profile is not available - return HttpResponse("Sorry. %s's user profile is not available." % request.user.username) + + return HttpResponse("Sorry. %s's user profile is not available." + % request.user.username) if currentUserProfile.is_coord_of: - return HttpResponseRedirect(settings.SITE_URL + 'DTVPicker/Summary/ByEvent/') - + return HttpResponseRedirect(settings.SITE_URL + + 'DTVPicker/Summary/ByEvent/') + if currentUserProfile.is_core: - + if PDFGenAllowed(): - return render_to_response("dtvpicker/SummaryPages/DTVLanding.html", locals(), context_instance = RequestContext(request)) - - return HttpResponseRedirect(settings.SITE_URL + 'DTVPicker/Summary/ByEvent/') - - return HttpResponseForbidden('This page can be accessed by Cores and Coordinators only. Please login with proper authentication to proceed.') + return render_to_response('dtvpicker/SummaryPages/DTVLanding.html' + , locals(), + context_instance=RequestContext(request)) + + return HttpResponseRedirect(settings.SITE_URL + + 'DTVPicker/Summary/ByEvent/') + + return HttpResponseForbidden('This page can be accessed by Cores and Coordinators only. Please login with proper authentication to proceed.' + ) + @login_required def dtvSummaryByEvent(request): @@ -46,41 +61,62 @@ def dtvSummaryByEvent(request): If coord logs in: Displays summary of his event and sub-events with their date-time-venue (dtv). There is a DTV PDF Generating option also which is available only to cores and only after all events are locked. """ + try: currentUserProfile = request.user.get_profile() except: + # If the user's profile is not available - return HttpResponse("Sorry. %s's user profile is not available." % request.user.username) - + + return HttpResponse("Sorry. %s's user profile is not available." + % request.user.username) + if currentUserProfile.is_core: # A core is allowed to see all events + requestedEventList = Event.objects.all() - happenings = [] # happenings is a list of tuples where + happenings = [] # happenings is a list of tuples where + # the tuple structure is: # (Event, [Sub-events under Event]) - enablePDFPrinting = PDFGenAllowed() # Passed to the template to activate the PDF generation link. + enablePDFPrinting = PDFGenAllowed() # Passed to the template to activate the PDF generation link. for requestedEvent in requestedEventList: - Event_SubEventList = SubEvent.objects.filter(event = requestedEvent).order_by('start_date_and_time') # List of sub-events under + Event_SubEventList = \ + SubEvent.objects.filter(event=requestedEvent).order_by('start_date_and_time' + ) # List of sub-events under + # requestedEvent + happenings.append((requestedEvent, Event_SubEventList)) - - return render_to_response("dtvpicker/SummaryPages/CoreDTVSummary_ByEvent.html", locals(), context_instance = RequestContext(request)) - + + return render_to_response('dtvpicker/SummaryPages/CoreDTVSummary_ByEvent.html' + , locals(), + context_instance=RequestContext(request)) else: # A coord can see only the events for which he is coord + requestedEvent = request.user.get_profile().is_coord_of - happenings = [] # happenings is a list of tuples where + happenings = [] # happenings is a list of tuples where + # the tuple structure is: # (Event, [Sub-events under Event]) - Event_SubEventList = SubEvent.objects.filter(event = requestedEvent).order_by('start_date_and_time') # List of sub-events under + + Event_SubEventList = \ + SubEvent.objects.filter(event=requestedEvent).order_by('start_date_and_time' + ) # List of sub-events under + # requestedEvent + happenings.append((requestedEvent, Event_SubEventList)) - return render_to_response("dtvpicker/SummaryPages/CoordDTVSummary_ByEvent.html", locals(), context_instance = RequestContext(request)) - + return render_to_response('dtvpicker/SummaryPages/CoordDTVSummary_ByEvent.html' + , locals(), + context_instance=RequestContext(request)) + + @login_required def dtvSummaryByVenue(request): """ @@ -88,34 +124,48 @@ def dtvSummaryByVenue(request): Available to Cores only. Displays summary of all sub-events with their date-time-venue (dtv). """ + try: currentUserProfile = request.user.get_profile() except: + # If the user's profile is not available - return HttpResponse("Sorry. %s's user profile is not available." % request.user.username) - + + return HttpResponse("Sorry. %s's user profile is not available." + % request.user.username) + if currentUserProfile.is_core: - + requestedVenueList = [] venues = VENUE_CHOICES for (venue_code, venue_name) in venues: requestedVenueList.append(venue_code) - happeningsByVenue = [] # happenings is a list of tuples where + happeningsByVenue = [] # happenings is a list of tuples where + # the tuple structure is: # (Venue, [Sub-events happening at Venue]) - enablePDFPrinting = PDFGenAllowed() # Passed to the template to activate the PDF generation link. + enablePDFPrinting = PDFGenAllowed() # Passed to the template to activate the PDF generation link. for requestedVenue in requestedVenueList: - Venue_SubEventList = SubEvent.objects.filter(venue = requestedVenue).order_by('start_date_and_time') # List of sub-events under + Venue_SubEventList = \ + SubEvent.objects.filter(venue=requestedVenue).order_by('start_date_and_time' + ) # List of sub-events under + # requestedVenue + if Venue_SubEventList: - happeningsByVenue.append((requestedVenue, Venue_SubEventList)) - - return render_to_response("dtvpicker/SummaryPages/CoreDTVSummary_ByVenue.html", locals(), context_instance = RequestContext(request)) - - return HttpResponseForbidden('This page can be accessed by Cores only. Please login with proper authentication to proceed.') + happeningsByVenue.append((requestedVenue, + Venue_SubEventList)) + + return render_to_response('dtvpicker/SummaryPages/CoreDTVSummary_ByVenue.html' + , locals(), + context_instance=RequestContext(request)) + + return HttpResponseForbidden('This page can be accessed by Cores only. Please login with proper authentication to proceed.' + ) + @login_required def dtvSummaryByDate(request): @@ -124,34 +174,47 @@ def dtvSummaryByDate(request): Available to Cores only. Displays summary of all events and sub-events with their date-time-venue (dtv). """ + try: currentUserProfile = request.user.get_profile() except: + # If the user's profile is not available - return HttpResponse("Sorry. %s's user profile is not available." % request.user.username) - + + return HttpResponse("Sorry. %s's user profile is not available." + % request.user.username) + if currentUserProfile.is_core: - + requestedDateList = [] - subEventList = SubEvent.objects.all().order_by('start_date_and_time') # List of all sub-events + subEventList = \ + SubEvent.objects.all().order_by('start_date_and_time') # List of all sub-events for subEvent in subEventList: - if subEvent.start_date_and_time.date() not in requestedDateList: + if subEvent.start_date_and_time.date() \ + not in requestedDateList: requestedDateList.append(subEvent.start_date_and_time.date()) happeningsByDate = [] # happenings is a list of tuples where + # the tuple structure is: # (Date, [Sub-events starting on Date]) - enablePDFPrinting = PDFGenAllowed() # Passed to the template to activate the PDF generation link. + enablePDFPrinting = PDFGenAllowed() # Passed to the template to activate the PDF generation link. for requestedDate in requestedDateList: - Date_SubEventList = SubEvent.objects.filter(start_date_and_time__startswith = requestedDate).order_by('start_date_and_time') + Date_SubEventList = \ + SubEvent.objects.filter(start_date_and_time__startswith=requestedDate).order_by('start_date_and_time' + ) + # List of sub-events hapenning on requestedDate # For the contains part see: # http://stackoverflow.com/questions/1317714/how-can-i-filter-a-date-of-a-datetimefield-in-django - + happeningsByDate.append((requestedDate, Date_SubEventList)) - return render_to_response("dtvpicker/SummaryPages/CoreDTVSummary_ByDate.html", locals(), context_instance = RequestContext(request)) - - return HttpResponseForbidden('This page can be accessed by Cores only. Please login with proper authentication to proceed.') + return render_to_response('dtvpicker/SummaryPages/CoreDTVSummary_ByDate.html' + , locals(), + context_instance=RequestContext(request)) + + return HttpResponseForbidden('This page can be accessed by Cores only. Please login with proper authentication to proceed.' + ) diff --git a/dtvpicker/views/timedeltaFormattingClass.py b/dtvpicker/views/timedeltaFormattingClass.py index ba5a6ee..3a4566b 100644 --- a/dtvpicker/views/timedeltaFormattingClass.py +++ b/dtvpicker/views/timedeltaFormattingClass.py @@ -1,32 +1,40 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + """This module holds the necessary modules for formatting timedelta objects.""" from string import Template + # Code copied from http://stackoverflow.com/questions/8906926/formatting-python-timedelta-objects and then modified. class DeltaTemplate(Template): - delimiter = "%" + + delimiter = '%' + def strfdelta(tdelta, fmt): - d = {"D": tdelta.days} - d["H"], rem = divmod(tdelta.seconds, 3600) - d["M"], d["S"] = divmod(rem, 60) - d["H"] += d["D"]*24 - del d["D"] - if d["H"] < 10: - d["H"] = '0' + str(d["H"]) + d = {'D': tdelta.days} + (d['H'], rem) = divmod(tdelta.seconds, 3600) + (d['M'], d['S']) = divmod(rem, 60) + d['H'] += d['D'] * 24 + del d['D'] + if d['H'] < 10: + d['H'] = '0' + str(d['H']) else: - d["H"] = str(d["H"]) - - if d["M"] < 10: - d["M"] = '0' + str(d["M"]) + d['H'] = str(d['H']) + + if d['M'] < 10: + d['M'] = '0' + str(d['M']) else: - d["M"] = str(d["M"]) + d['M'] = str(d['M']) - if d["S"] < 10: - d["S"] = '0' + str(d["S"]) + if d['S'] < 10: + d['S'] = '0' + str(d['S']) else: - d["S"] = str(d["S"]) + d['S'] = str(d['S']) t = DeltaTemplate(fmt) return t.substitute(**d) + + diff --git a/events/ajax.py b/events/ajax.py index 172eac6..48f7004 100644 --- a/events/ajax.py +++ b/events/ajax.py @@ -1,473 +1,594 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- import random from dajax.core import Dajax from django.utils import simplejson from django.template import loader, Context, RequestContext, Template from events.models import * from dajaxice.decorators import dajaxice_register +from django.core.cache import cache + def get_files(tab): + # gets all files that are related to a particular tab + try: return tab.tabfile_set.all() except: raise Http404() + def get_mob_app_tab(event): try: return event.mobapptab except: return None + def get_tabs(event): + # gets all tabs that are related to a particular event + try: return event.tab_set.all() except: raise Http404() - - + + @dajaxice_register def delete_tab(request, tab_id): + # deletes the tab. shows a delete successful message. - tab = Tab.objects.get(id = tab_id) + + tab = Tab.objects.get(id=tab_id) x = tab.title tab.delete() event = request.user.get_profile().is_coord_of tabs = get_tabs(event) template = """{{x}} deleted successfully!""" - t1 = Template(template).render(RequestContext(request,locals())) + t1 = Template(template).render(RequestContext(request, locals())) template = loader.get_template('ajax/events/tab_list.html') - t2 = template.render(RequestContext(request,locals())) + t2 = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t1) - dajax.assign('#tabs','innerHTML', t2) + dajax.assign('#tabs', 'innerHTML', t2) return dajax.json() - + + @dajaxice_register def confirm_delete_tab(request, tab_id): + # asks coord 'are u sure u want to delete this tab?' - tab = Tab.objects.get(id = tab_id) + + tab = Tab.objects.get(id=tab_id) template = loader.get_template('ajax/events/tab_delete.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def save_editted_tab(request, form, tab_id): + # validates the tab details that were submitted while editing an existing tab - tab = Tab.objects.get(id = tab_id) - f = TabAddForm(form, instance = tab) + + tab = Tab.objects.get(id=tab_id) + f = TabAddForm(form, instance=tab) if f.is_valid(): event = request.user.get_profile().is_coord_of - unsaved_tab = f.save(commit = False) + unsaved_tab = f.save(commit=False) unsaved_tab.event = event unsaved_tab.save() tab = unsaved_tab tabs = get_tabs(event) template = loader.get_template('ajax/events/tab_list.html') - t1 = template.render(RequestContext(request,locals())) + t1 = template.render(RequestContext(request, locals())) template2 = loader.get_template('ajax/events/tab_detail.html') - t2 = template2.render(RequestContext(request,locals())) + t2 = template2.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#tabs','innerHTML', t1) + dajax.assign('#tabs', 'innerHTML', t1) dajax.assign('#detail', 'innerHTML', t2) return dajax.json() else: template = loader.get_template('ajax/events/tab_edit_form.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() + @dajaxice_register def save_tab(request, form): + # validates the tab details that were submitted while adding a new tab + f = TabAddForm(form) if f.is_valid(): event = request.user.get_profile().is_coord_of - unsaved_tab = f.save(commit = False) + unsaved_tab = f.save(commit=False) unsaved_tab.event = event unsaved_tab.save() tab = unsaved_tab tabs = get_tabs(event) template = loader.get_template('ajax/events/tab_list.html') - t1 = template.render(RequestContext(request,locals())) + t1 = template.render(RequestContext(request, locals())) template2 = loader.get_template('ajax/events/tab_detail.html') - t2 = template2.render(RequestContext(request,locals())) + t2 = template2.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#tabs','innerHTML', t1) + dajax.assign('#tabs', 'innerHTML', t1) dajax.assign('#detail', 'innerHTML', t2) return dajax.json() else: template = loader.get_template('ajax/events/tab_add_form.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def add_tab(request): + # loads a form for creating a new tab + f = TabAddForm() template = loader.get_template('ajax/events/tab_add_form.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#detail','innerHTML', t) + dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def edit_tab(request, tab_id): + # loads a form for editing the tab details - tab = Tab.objects.get(id = tab_id) - f = TabAddForm(instance = tab) + + tab = Tab.objects.get(id=tab_id) + f = TabAddForm(instance=tab) template = loader.get_template('ajax/events/tab_edit_form.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#detail','innerHTML', t) + dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def load_tab(request, tab_id): + # loads the tab details of the tab you clicked on - tab = Tab.objects.get(id = tab_id) + + event_name = cache.get(str(tab_id) + '_event') + if event_name != None: + event = Event.objects.get(title=event_name) + title = cache.get(str(tab_id) + '_title') + text = cache.get(str(tab_id) + '_text') + pref = cache.get(str(tab_id) + '_pref') + tab = Tab(event=event, title=title, text=text, pref=int(pref)) + else: + tab = Tab.objects.get(id=tab_id) + cache.set(str(unsaved_tab.id) + '_event', + str(unsaved_tab.event), 2592000) + cache.set(str(unsaved_tab.id) + '_title', + str(unsaved_tab.title), 2592000) + cache.set(str(unsaved_tab.id) + '_text', str(unsaved_tab.text), + 2592000) + cache.set(str(unsaved_tab.id) + '_pref', str(unsaved_tab.pref), + 2592000) file_list = get_files(tab) template = loader.get_template('ajax/events/tab_detail.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#detail','innerHTML', t) + dajax.assign('#detail', 'innerHTML', t) return dajax.json() + @dajaxice_register def add_file(request, tab_id): + # loads a form for adding files inside a tab + f = TabFileForm() - tab = Tab.objects.get(id = tab_id) + tab = Tab.objects.get(id=tab_id) file_list = get_files(tab) template = loader.get_template('ajax/events/file_form.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#detail','innerHTML', t) + dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def delete_file(request, tab_id, file_id): + # deletes the selected file - f = TabFile.objects.get(id = file_id) + + f = TabFile.objects.get(id=file_id) f.delete() - tab = Tab.objects.get(id = tab_id) + tab = Tab.objects.get(id=tab_id) file_list = get_files(tab) template = loader.get_template('ajax/events/tab_detail.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#detail','innerHTML', t) + dajax.assign('#detail', 'innerHTML', t) return dajax.json() + @dajaxice_register def rename_file(request, tab_id, file_id): + # loads a form for renaming a file - tab = Tab.objects.get(id = tab_id) - f = TabFile.objects.get(id = file_id) + + tab = Tab.objects.get(id=tab_id) + f = TabFile.objects.get(id=file_id) actual_name = f.tab_file.name.split('/')[-1] file_list = get_files(tab) template = loader.get_template('ajax/events/file_rename.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#detail','innerHTML', t) - return dajax.json() - + dajax.assign('#detail', 'innerHTML', t) + return dajax.json() + + @dajaxice_register def rename_file_done(request, form, file_id): + # renames a file - f = TabFile.objects.get(id = file_id) + + f = TabFile.objects.get(id=file_id) if form['display_name']: f.title = form['display_name'] f.save() tab = f.tab file_list = get_files(tab) template = loader.get_template('ajax/events/tab_detail.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#detail','innerHTML', t) + dajax.assign('#detail', 'innerHTML', t) return dajax.json() + @dajaxice_register def load_question_tab(request): + # question tab is displayed + event = request.user.get_profile().is_coord_of text_questions = event.subjectivequestion_set.all() mcqs = event.objectivequestion_set.all() template = loader.get_template('ajax/events/question_tab.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def add_subjective(request): + # loads a form for creating a new subjective question. + f = AddSubjectiveQuestionForm() - template = loader.get_template('ajax/events/add_subjective_form.html') - t = template.render(RequestContext(request,locals())) + template = \ + loader.get_template('ajax/events/add_subjective_form.html') + t = template.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#detail','innerHTML', t) + dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def save_subjective(request, form): + # validates and saves a subjective question + from django.conf import settings f = AddSubjectiveQuestionForm(form) if f.is_valid(): event = request.user.get_profile().is_coord_of - unsaved_ques = f.save(commit = False) + unsaved_ques = f.save(commit=False) unsaved_ques.event = event unsaved_ques.save() text_questions = event.subjectivequestion_set.all() mcqs = event.objectivequestion_set.all() template = loader.get_template('ajax/events/question_tab.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() else: - template = loader.get_template('ajax/events/add_subjective_form.html') - t = template.render(RequestContext(request,locals())) + template = \ + loader.get_template('ajax/events/add_subjective_form.html') + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() -@dajaxice_register + +@dajaxice_register def edit_subjective(request, ques_id): + # loads a form for editing the selected question - ques = SubjectiveQuestion.objects.get(id = ques_id) - f = AddSubjectiveQuestionForm(instance = ques) - template = loader.get_template('ajax/events/edit_subjective_form.html') - t = template.render(RequestContext(request,locals())) + + ques = SubjectiveQuestion.objects.get(id=ques_id) + f = AddSubjectiveQuestionForm(instance=ques) + template = \ + loader.get_template('ajax/events/edit_subjective_form.html') + t = template.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#detail','innerHTML', t) + dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def save_editted_subjective(request, form, ques_id): + # validates the question details that were submitted while editing an existing question. - ques = SubjectiveQuestion.objects.get(id = ques_id) - f = AddSubjectiveQuestionForm(form, instance = ques) + + ques = SubjectiveQuestion.objects.get(id=ques_id) + f = AddSubjectiveQuestionForm(form, instance=ques) if f.is_valid(): event = request.user.get_profile().is_coord_of - unsaved_ques = f.save(commit = False) + unsaved_ques = f.save(commit=False) unsaved_ques.event = event unsaved_ques.save() text_questions = event.subjectivequestion_set.all() mcqs = event.objectivequestion_set.all() template = loader.get_template('ajax/events/question_tab.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() else: - template = loader.get_template('ajax/events/edit_subjective_form.html') - t = template.render(RequestContext(request,locals())) + template = \ + loader.get_template('ajax/events/edit_subjective_form.html') + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() -@dajaxice_register + +@dajaxice_register def delete_subjective(request, ques_id): + # deletes the selected question - ques = SubjectiveQuestion.objects.get(id = ques_id) + + ques = SubjectiveQuestion.objects.get(id=ques_id) ques.delete() event = request.user.get_profile().is_coord_of text_questions = event.subjectivequestion_set.all() mcqs = event.objectivequestion_set.all() template = loader.get_template('ajax/events/question_tab.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def add_mcq(request): + # loads a form for creating a new mcq question. + f = AddMCQForm() template = loader.get_template('ajax/events/add_mcq_form.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#detail','innerHTML', t) + dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def save_mcq(request, form): + # validates and saves the mcq and displays a page to manage options + from django.conf import settings f = AddMCQForm(form) if f.is_valid(): event = request.user.get_profile().is_coord_of - ques = f.save(commit = False) + ques = f.save(commit=False) ques.event = event ques.save() - template = loader.get_template('ajax/events/manage_options.html') - t = template.render(RequestContext(request,locals())) + template = loader.get_template('ajax/events/manage_options.html' + ) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() else: template = loader.get_template('ajax/events/add_mcq_form.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() -@dajaxice_register + +@dajaxice_register def edit_mcq(request, ques_id): + # loads a form for editing the selected mcq - ques = ObjectiveQuestion.objects.get(id = ques_id) - f = AddMCQForm(instance = ques) + + ques = ObjectiveQuestion.objects.get(id=ques_id) + f = AddMCQForm(instance=ques) template = loader.get_template('ajax/events/edit_mcq_form.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#detail','innerHTML', t) + dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def save_editted_mcq(request, form, ques_id): + # validates the question details that were submitted while editing an existing mcq and displays a page to manage options - ques = ObjectiveQuestion.objects.get(id = ques_id) - f = AddMCQForm(form, instance = ques) + + ques = ObjectiveQuestion.objects.get(id=ques_id) + f = AddMCQForm(form, instance=ques) if f.is_valid(): event = request.user.get_profile().is_coord_of - unsaved_ques = f.save(commit = False) + unsaved_ques = f.save(commit=False) unsaved_ques.event = event unsaved_ques.save() options = unsaved_ques.mcqoption_set.all() - template = loader.get_template('ajax/events/manage_options.html') - t = template.render(RequestContext(request,locals())) + template = loader.get_template('ajax/events/manage_options.html' + ) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() else: template = loader.get_template('ajax/events/edit_mcq_form.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() -@dajaxice_register + +@dajaxice_register def delete_mcq(request, ques_id): + # deletes the selected mcq - ques = ObjectiveQuestion.objects.get(id = ques_id) + + ques = ObjectiveQuestion.objects.get(id=ques_id) ques.delete() event = request.user.get_profile().is_coord_of text_questions = event.subjectivequestion_set.all() mcqs = event.objectivequestion_set.all() template = loader.get_template('ajax/events/question_tab.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() - -@dajaxice_register + + +@dajaxice_register def manage_options(request, ques_id): + # all existing options displayed with features of editing/deleting them and adding new ones - ques = ObjectiveQuestion.objects.get(id = ques_id) + + ques = ObjectiveQuestion.objects.get(id=ques_id) options = ques.mcqoption_set.all() template = loader.get_template('ajax/events/manage_options.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def add_option(request, ques_id): + # displays a form for adding an option - ques = ObjectiveQuestion.objects.get(id = ques_id) + + ques = ObjectiveQuestion.objects.get(id=ques_id) f = AddOptionForm() template = loader.get_template('ajax/events/add_option_form.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#option_edit', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def save_option(request, form, ques_id): + # validates and saves an option + f = AddOptionForm(form) - ques = ObjectiveQuestion.objects.get(id = ques_id) + ques = ObjectiveQuestion.objects.get(id=ques_id) if f.is_valid(): - unsaved_option = f.save(commit = False) + unsaved_option = f.save(commit=False) unsaved_option.question = ques unsaved_option.save() options = ques.mcqoption_set.all() - template = loader.get_template('ajax/events/manage_options.html') - t = template.render(RequestContext(request,locals())) + template = loader.get_template('ajax/events/manage_options.html' + ) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() else: - template = loader.get_template('ajax/events/add_option_form.html') - t = template.render(RequestContext(request,locals())) + template = \ + loader.get_template('ajax/events/add_option_form.html') + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#option_edit', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def delete_option(request, option_id): + # deletes an option - option = MCQOption.objects.get(id = option_id) + + option = MCQOption.objects.get(id=option_id) ques = option.question option.delete() options = ques.mcqoption_set.all() template = loader.get_template('ajax/events/manage_options.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def edit_option(request, option_id): + # loads a form for editting an existing option - option = MCQOption.objects.get(id = option_id) - f = AddOptionForm(instance = option) + + option = MCQOption.objects.get(id=option_id) + f = AddOptionForm(instance=option) template = loader.get_template('ajax/events/edit_option_form.html') - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax = Dajax() - dajax.assign('#option_edit','innerHTML', t) + dajax.assign('#option_edit', 'innerHTML', t) return dajax.json() - + + @dajaxice_register def save_editted_option(request, form, option_id): + # validates and saves editted option - option = MCQOption.objects.get(id = option_id) + + option = MCQOption.objects.get(id=option_id) ques = option.question - f = AddOptionForm(form, instance = option) + f = AddOptionForm(form, instance=option) if f.is_valid(): f.save() options = ques.mcqoption_set.all() - template = loader.get_template('ajax/events/manage_options.html') - t = template.render(RequestContext(request,locals())) + template = loader.get_template('ajax/events/manage_options.html' + ) + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#detail', 'innerHTML', t) return dajax.json() else: - template = loader.get_template('ajax/events/edit_option_form.html') - t = template.render(RequestContext(request,locals())) + template = \ + loader.get_template('ajax/events/edit_option_form.html') + t = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#option_edit', 'innerHTML', t) return dajax.json() + @dajaxice_register -def add_edit_mobapp_tab(request, form = ''): +def add_edit_mobapp_tab(request, form=''): dajax = Dajax() event = request.user.get_profile().is_coord_of mob_app_tab = get_mob_app_tab(event) - template = loader.get_template('ajax/events/add_edit_mobapptab.html') + template = loader.get_template('ajax/events/add_edit_mobapptab.html' + ) if form: if mob_app_tab: - f = MobAppWriteupForm(form, instance = mob_app_tab) + f = MobAppWriteupForm(form, instance=mob_app_tab) else: f = MobAppWriteupForm(form) if f.is_valid(): - unsaved = f.save(commit = False) + unsaved = f.save(commit=False) unsaved.event = event unsaved.save() dajax.alert('saved successfully!') @@ -475,10 +596,10 @@ def add_edit_mobapp_tab(request, form = ''): dajax.alert('Error. Your write up could not be saved!') else: if mob_app_tab: - f = MobAppWriteupForm(instance = mob_app_tab) + f = MobAppWriteupForm(instance=mob_app_tab) else: f = MobAppWriteupForm() - t = template.render(RequestContext(request,locals())) + t = template.render(RequestContext(request, locals())) dajax.assign('#detail', 'innerHTML', t) return dajax.json() - + diff --git a/events/forms.py b/events/forms.py index c2b2f1d..c3493cc 100644 --- a/events/forms.py +++ b/events/forms.py @@ -1,6 +1,33 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- from django import forms -from events.models import* +from events.models import * from django.forms import ModelForm import os + +class MCQForm(forms.Form): + + def __init__(self, mcq, options): + super(MCQForm, self).__init__() + (ini_title, ini_q_no) = ('', '') + if mcq: + (ini_title, ini_q_no) = (mcq.title, mcq.q_number) + self.fields['q_no'] = forms.IntegerField(initial=ini_q_no) + self.fields['title'] = forms.CharField(widget=forms.Textarea, + initial=ini_title) + index = 0 + import string + alp = string.lowercase + for option in options: + self.fields['%s%s' % (option.id, option.option)] = \ + forms.CharField(initial='%s' % option.text, + label='option %s:' % alp[index], + max_length=1000) + index += 1 + self.fields['opt%s' % alp[index]] = \ + forms.CharField(label='option %s:' % alp[index], + max_length=1000) + + # no forms here. defined model forms in models itself. diff --git a/events/models.py b/events/models.py index e6f4c6d..d954063 100644 --- a/events/models.py +++ b/events/models.py @@ -1,147 +1,255 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- from django.db import models from django.contrib.auth.models import User +#from users.models import Team from django import forms from django.forms import ModelForm from chosen import forms as chosenforms from datetime import datetime from django.conf import settings from django.core.exceptions import ValidationError +from django.core.cache import cache import os +EVENT_CATEGORIES = ( + ('Aerofest', 'Aerofest'), + ('Coding', 'Coding'), + ('Design and Build', 'Design and Build'), + ('Involve', 'Involve'), + ('Quizzes', 'Quizzes'), + ('Online', 'Online'), + ('Department Flagship', 'Department Flagship'), + ('Spotlight', 'Spotlight'), + ('Workshops', 'Workshops'), + ('Exhibitions', 'Exhibitions'), + ('Associated Events', 'Associated Events'), + ('Sampark', 'Sampark'), + ) + +CATEGORY = (('Update', 'Update'), ('Announcement', 'Announcement')) + + # Create your models here. + def upload_handler(model_name): + def upload_func(instance, filename): return os.path.join(model_name, instance.title, filename) + return upload_func + class Tag(models.Model): - name = models.CharField(max_length = 25) - def __unicode__(self,*args,**kwargs): + + name = models.CharField(max_length=25) + + def __unicode__(self, *args, **kwargs): return self.name -class Category(models.Model): - name = models.CharField(max_length = 25) - -class Update(models.Model): - subject = models.CharField(max_length = 25) - description = models.TextField() - date = models.DateField(default = datetime.now) class Event(models.Model): - title = models.CharField(max_length = 30) - events_logo = models.ImageField(upload_to = upload_handler('Events')) - tags = models.ManyToManyField(Tag, blank = True, null = True) - category = models.ForeignKey(Category, blank = True, null = True) - updates = models.ManyToManyField(Update, blank = True, null = True) - lock_status = models.CharField(default = 'cannot_be_locked', max_length = 20) - unlock_reason = models.TextField(default = '', blank = True) - + + title = models.CharField(max_length=30) + events_logo = models.FileField(upload_to=upload_handler('Events'), + blank=True, null=True) + tags = models.ManyToManyField(Tag, blank=True, null=True) + category = models.CharField(max_length=50, choices=EVENT_CATEGORIES) + lock_status = models.CharField(default='cannot_be_locked', + max_length=20) + unlock_reason = models.TextField(default='', blank=True) + + registrable_online = models.BooleanField(default=False, + help_text='Can participants register online?') + team_event = models.BooleanField(default=False, + help_text='Is this a team event?') + team_size_min = models.IntegerField(default=1, + verbose_name='Minimum team size') + team_size_max = models.IntegerField(default=1, + verbose_name='Maximum team size') + + begin_registration = models.BooleanField(default=False, + help_text='Mark as True to begin online registration') + has_tdp = models.BooleanField(default=False, + help_text='Does this event require participants to submit a TDP?' + ) + has_questionnaire = models.BooleanField(default=False, + help_text='Will the participant have to answer a questionnaire?' + ) + fb_event_id = models.CharField(max_length=20, null=True) + updated = models.BooleanField(default=False) + sponsor_logo_url= models.CharField(max_length=150) + def __unicode__(self): return '%s' % self.title + + def clean(self): + """ + This method will work to clean the instance of Event created. + Custom validations to be performed: + * If the event is not a team event, then the team sizes must not be specified. + * If team sizes are not specified, they should be set to one each (individual participation). + * Minimum team size should not be greater than the maximum team size. + """ + # References: + # https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects + # https://docs.djangoproject.com/en/dev/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other + # http://stackoverflow.com/questions/2117048/django-overriding-the-clean-method-in-forms-question-about-raising-errors + + errors = [] + super(Event, self).clean() # Calling clean method of the super class + try: + team_event + if team_size_min > team_size_max: + errors.append(u'The minimum team size cannot be more than the maximum team size.') + if team_size_max == 1: + errors.append(u'The maximum team size is 1. Did you mean to make this a non-team event?') + except: + team_size_min = team_size_max = 1 + if not team_size_min: + team_size_min = 1 + if not team_size_max: + team_size_max = 1 + if errors: + raise ValidationError(errors) + + def construct_dir_path(self): + try: + return settings.EVENT_DIR + 'event_' + str(self.id) + '/' + except AttributeError: + return 'events/event_' + str(self.id) + '/' + +class EventSingularRegistration(models.Model): + + user = models.ForeignKey(User) + event = models.ForeignKey(Event) + + def __unicode__(self): + return '%s <- User: %s' % (event, user) + +''' +class EventTeamRegistration(models.Model): + + team = models.ForeignKey(Team) + event = models.ForeignKey(Event) + + def __unicode__(self): + return '%s <- Team: %s' % (event, team) +''' + +class Update(models.Model): + + subject = models.CharField(max_length=25) + description = models.TextField() + date = models.DateField(default=datetime.now) + category = models.CharField(max_length=15, choices=CATEGORY, + help_text='You can add 4 updates and 1 announcement. Mark as announcement only if the information is of highest importance' + ) + event = models.ForeignKey(Event, null=True, blank=True) + expired = models.BooleanField(default=False, + help_text='Mark an update/announcement as expired if it is no longer relevant or you have more than 4 updates (or 1 announcement) ' + ) + class Tab(models.Model): - event = models.ForeignKey(Event, blank = True, null = True) - title = models.CharField(max_length = 30) + + event = models.ForeignKey(Event, blank=True, null=True) + title = models.CharField(max_length=30) text = models.TextField() - pref = models.IntegerField(max_length=2,default = 0, blank=False) - + pref = models.IntegerField(max_length=2, default=0, blank=False, + help_text='This is the order in which your tabs will be displayed on main site.' + ) + +# def save(self): +# cache.set(str(self.id)+"_event", str(self.event), 2592000) +# cache.set(str(self.id)+"_title", str(self.title), 2592000) +# cache.set(str(self.id)+"_text", str(self.text), 2592000) +# cache.set(str(self.id)+"_pref", str(self.pref), 2592000) +# super(Tab, self).save(*args, **kwargs) + def delete(self): file_list = self.tabfile_set.all() for f in file_list: f.delete() super(Tab, self).delete() - + class Meta: + ordering = ['pref'] - + + class TabFile(models.Model): - title = models.CharField(max_length = 50) - tab_file = models.FileField(upload_to = upload_handler('Events/TabFiles')) - tab = models.ForeignKey(Tab, blank = True, null = True) - url = models.CharField(max_length = 50) - + + title = models.CharField(max_length=50) + tab_file = \ + models.FileField(upload_to=upload_handler('Events/TabFiles')) + tab = models.ForeignKey(Tab, blank=True, null=True) + url = models.CharField(max_length=200) + def delete(self): os.remove(self.tab_file.name) super(TabFile, self).delete() - + + class Question(models.Model): - q_number = models.IntegerField(max_length=2) - title = models.CharField(max_length=1500, blank = False) - + + q_number = models.IntegerField(max_length=2) + title = models.TextField(max_length=1500, blank=False) + def __unicode__(self): return self.title - + class Meta: + ordering = ['q_number'] - + + class SubjectiveQuestion(Question): - event= models.ForeignKey(Event) + + event = models.ForeignKey(Event) + class ObjectiveQuestion(Question): - event= models.ForeignKey(Event) - + + event = models.ForeignKey(Event) + def delete(self): options = self.mcqoption_set.all() for option in options: option.delete() super(ObjectiveQuestion, self).delete() + class MCQOption(models.Model): - question = models.ForeignKey(ObjectiveQuestion) - option = models.CharField(max_length = 1) - text = models.TextField(max_length = 1000) + + question = models.ForeignKey(ObjectiveQuestion, null=True, + blank=True) + option = models.CharField(max_length=1) + text = models.TextField(max_length=1000) + def __unicode__(self): return self.text - - class Meta: - ordering = ['option'] - -class MobAppTab(models.Model): - event = models.OneToOneField(Event, blank = True, null = True) - text = models.TextField() - - -class AddOptionForm(ModelForm): class Meta: - model = MCQOption - exclude = ('question',) -class AddMCQForm(ModelForm): - class Meta: - model = ObjectiveQuestion - fields = ('q_number', 'title') + ordering = ['option'] -class AddSubjectiveQuestionForm(ModelForm): - class Meta: - model = SubjectiveQuestion - fields = ('q_number', 'title') -class TabFileForm(ModelForm): - class Meta: - model = TabFile - exclude = ('tab',) - -class EventAddForm(ModelForm): - tags = chosenforms.ChosenModelMultipleChoiceField(required = False,queryset = Tag.objects.all()) - class Meta: - model = Event - # fields = ('title','events_logo','tags') - fields = ('title','events_logo', 'tags', 'lock_status', 'unlock_reason') - widgets = { - 'lock_status' : forms.HiddenInput(), - 'unlock_reason' : forms.HiddenInput(), - } - -class TabAddForm(ModelForm): - class Meta: - model = Tab - exclude = ('event',) - -class MobAppWriteupForm(ModelForm): - class Meta: - model = MobAppTab - exclude = ('event',) - +class MobAppTab(models.Model): + + event = models.OneToOneField(Event, blank=True, null=True) + text = models.TextField() +class Sponsor(models.Model): + """ + This model is for adding details about sponsors + """ + name = models.CharField(max_length = 20,unique = True, help_text = 'Enter company name (Required)') + index_number = models.IntegerField(blank = True, help_text = 'Indicates order of importance of sponsor - The most important sponsor will be index 1.') + url = models.URLField(blank = True) + logo = models.URLField(blank = True) + year = models.IntegerField(default = "2013") + about = models.CharField(max_length = 50, help_text = 'Type of sponsor') + def __unicode__(self): + return self.name diff --git a/events/tests.py b/events/tests.py index 501deb7..a9d5fb0 100644 --- a/events/tests.py +++ b/events/tests.py @@ -1,3 +1,6 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + """ This file demonstrates writing tests using the unittest module. These will pass when you run "manage.py test". @@ -9,8 +12,12 @@ class SimpleTest(TestCase): + def test_basic_addition(self): """ Tests that 1 + 1 always equals 2. """ + self.assertEqual(1 + 1, 2) + + diff --git a/events/urls.py b/events/urls.py index 4ca79d2..257466f 100644 --- a/events/urls.py +++ b/events/urls.py @@ -1,9 +1,17 @@ -from django.conf.urls.defaults import patterns, include, url +#!/usr/bin/python +# -*- coding: utf-8 -*- + +from django.conf import settings +from django.conf.urls.defaults import * +from django.views.generic.simple import direct_to_template from events.views import * urlpatterns = patterns('', - url(r'^$', CoordDashboard()), - url(r'^tabfile/$', TabFileSubmit()), -) - -#these urls will be imported by the root url. + url(r'^sponslogo', logo, name='spons-logo'), + url(r'^(?P\d+)/register/$', register), + url(r'^(?P\d+)/cancelregistration/$', cancel_registration), + #url(r'^(?P.+)/tab/(?P.+)', tabs, name='tab-list'), + url(r'^(?P.+)', events, name='event-list'), + url(r'^sampark/', sampark, name='sampark-home'), + url(r'^$', home, name='event-home'), + ) diff --git a/events/views.py b/events/views.py index 2839270..9e91bfd 100644 --- a/events/views.py +++ b/events/views.py @@ -1,167 +1,235 @@ -from django.http import * -from django.template import * -from django.shortcuts import * -from django.contrib import * -from django.contrib.auth.forms import UserCreationForm -from django.core.context_processors import csrf -from django.contrib import * -from django.contrib.auth.models import User -from events.models import * +#!/usr/bin/python +# -*- coding: utf-8 -*- +from django.http import HttpResponse, HttpResponseRedirect, Http404 +from django.template.context import Context, RequestContext +from django.shortcuts import render_to_response from django.conf import settings +from events.models import * +from users.models import Team +from operator import attrgetter +from django.template.defaultfilters import slugify from django.contrib.auth.decorators import login_required -from django.utils.decorators import method_decorator -from django.core.exceptions import ObjectDoesNotExist +import urllib -import os -import datetime -from datetime import date # Create your views here. +def home(request): + event_name = request.GET.get('_escaped_fragment_','') + if event_name: + event_name = event_name.split('/')[1] + event_name = event_name.replace('-', ' ') + if event_name=="robo oceana": + event_name="robo-oceana" + elif event_name=="lectures video conferences": + event_name="lectures & video conferences" + if event_name == 'sampark/' : + return sampark(request) + event = Event.objects.get(title=event_name) + initial_updates = Update.objects.filter(category = 'Update') + updates = sorted(initial_updates, key=attrgetter('id'), reverse=True) + initial_announcements = Update.objects.filter(category = 'Announcement') + announcements = sorted(initial_announcements, key=attrgetter('id'), reverse=True) + tab_set = event.tab_set.all() + files_set = [tab.tabfile_set.all() for tab in tab_set] + tabs = zip(tab_set,files_set) + return render_to_response('ajax/events/events.html', locals(), context_instance=RequestContext(request)) + return render_to_response('events/events_home.html', locals(), context_instance=RequestContext(request)) -class BaseView(object): - # parent class. classes below inherit this - def __call__(self, request, **kwargs): - # handles request and dispatches the corresponding handler based on the type of request (GET/POST) - method = request.META['REQUEST_METHOD'].upper() - handler = getattr(self, 'handle_%s' %method, None) - - if handler is None: - methods = [] - for x in dir(self): - if x.startswith('handle_'): - methods.append(x[7:]) - return HttpResponseNotAllowed(methods) - - return handler(request, **kwargs) - - def get_tabs(self,event): - # returns list of all tabs of a particular event - try: - return event.tab_set.all() - except: - raise Http404() - - def get_files(self, tab): - # returns list of all files of a particular tab - try: - return tab.tabfile_set.all() - except: - print 'here too' - raise Http404() - +def events(request, event_name): + event_name = event_name.replace('-', ' ') + if event_name=="robo oceana": + event_name="robo-oceana" + elif event_name=="lectures video conferences": + event_name="lectures & video conferences" + if event_name == 'sampark/' : + return sampark(request) + event = Event.objects.get(title=event_name) + initial_updates = Update.objects.filter(category = 'Update') + updates = sorted(initial_updates, key=attrgetter('id'), reverse=True) + initial_announcements = Update.objects.filter(category = 'Announcement') + announcements = sorted(initial_announcements, key=attrgetter('id'), reverse=True) + tab_set = event.tab_set.all() + files_set = [tab.tabfile_set.all() for tab in tab_set] + tabs = zip(tab_set,files_set) + #assert False + return render_to_response('events/events.html', locals(), context_instance=RequestContext(request)) -class ProtectedView(BaseView): - """ - ProtectedView requires users to authenticate themselves before proceeding to the computation logic. - """ +''' +def tabs(request, event_name, tab_name): + event_name = event_name.replace('-', ' ') + tab_name = tab_name.replace('-', ' ') + if event_name=="robo oceana": + event_name="robo-oceana" + elif event_name=="lectures video conferences": + event_name="lectures & video conferences" + event = Event.objects.get(title=event_name) + tab_set = event.tab_set.all() + tab = tab_set.get(title=tab_name) + file_set = tab.tabfile_set.all() + return render_to_response('events/tabs.html', locals(), context_instance=RequestContext(request)) +''' +def sampark(request): +# if path: +# assert False +# return HttpResponseRedirect(settings.SITE_URL+path) + bengaluruevents = [] + hyderabadevents = [] + puneevents = [] + coimbatoreevents = [] + chennaievents = [] + event = Event.objects.all() + city_set = ['Bengaluru', 'Hyderabad', 'Coimbatore', 'Pune', 'Chennai'] + for e in event: + if e.title.split('_')[0] == 'B': + bengaluruevents.append(e) + if e.title.split('_')[0] == 'H': + hyderabadevents.append(e) + if e.title.split('_')[0] == 'P': + puneevents.append(e) + if e.title.split('_')[0] == 'C': + coimbatoreevents.append(e) + if e.title.split('_')[0] == 'Ch': + chennaievents.append(e) + #Code for search + result_list=[] + for t in Tag.objects.all(): + row=[] + row.append(str(t.name)) + temp=[] + for x in t.event_set.all(): + url = slugify(x) + '/tab/' + x.tab_set.all()[0].title + temp.append([str(x),str(url)]) + row.append(temp) + result_list.append(row) + #End of search code + return render_to_response('events/sampark_home.html', locals(), context_instance=RequestContext(request)) - @method_decorator(login_required) - def userAuthentication(self, request, **kwargs): - return True +def logo(request): + name = request.GET.get('name','') + url = request.GET.get('url','') + logo = request.GET.get('logo','') + about = request.GET.get('about','') + index_number = request.GET.get('index','') + year = request.GET.get('year',2013) + #event = Event.objects.get(title=event_name) + #event.sponsor_logo_url = spons_logo_url + #event.save() + #event = Event.objects.get(title=event_name) + try: + spons = Sponsor.objects.get(name = name) + spons.url = url + spons.index_number = index_number + spons.year = year + spons.logo = logo + spons.about = about + except: + spons = Sponsor(name = name, url = url, index_number = index_number,year = year, logo = logo, about = about) + spons.save() + if(spons): + return HttpResponse("True") + else: + return HttpResponse("False") - def __call__(self, request, **kwargs): - """ - * Checks authentication - * Handles request - * Dispatches the corresponding handler based on the type of request (GET/POST) - """ - # TODO(Anant, anant.girdhar@gmail.com): Instead of copying the code, it would be better if we override BaseView.__call__ - # and add the necessary lines for authentication. - - # Copied code from BaseView.__call__ - # Overriding BaseView.__call__ to check authentication. - if self.userAuthentication(request, **kwargs) == False: - return HttpResponseForbidden() - method = request.META['REQUEST_METHOD'].upper() - handler = getattr(self, 'handle_%s' %method, None) - - if handler is None: - methods = [] - for x in dir(self): - if x.startswith('handle_'): - methods.append(x[7:]) - return HttpResponseNotAllowed(methods) - return handler(request, **kwargs) +### Methods for event registration: -class CoordProtectedView(ProtectedView): - """ - CoordProtectedView requires the user to be authenticated and to be a coord before proceeding to the computation logic. +def register_singular_event(request, event): + user = request.user + userProfile = user.get_profile() + singularRegistrations = EventSingularRegistration.objects.filter(event = event) + registration_done_message = None + try: + userRegistration = singularRegistrations.get(user = user) + except: + # This means that the user is not registered. + # We must now execute the registration logic. + if request.method == 'POST': + # If the user submitted the registration form (which is just a confirm button) + newRegistration = EventSingularRegistration(user = user, event = event) + newRegistration.save() + registration_done_message = u'You have been registered for this event.' + else: + # If the form has not been submitted, we have to render the form. + # TODO: The template below should have a form which allows the user to choose whether he wants to register or not. TODO done + return render_to_response('events/register_singular_event.html', locals(), context_instance=RequestContext(request)) + if registration_done_message is None: + # If registration_done_message exists, then the user just registered. Do not change this message here. + # If it does not exist, the user registered earlier. Set the message. + registration_done_message = u'You have already registered for this event.' + # TODO: The template below should tell the user that he is registered. TODO done + # TODO: The template should also allow the user to cancel his registration + return render_to_response('events/registration_done.html', locals(), context_instance=RequestContext(request)) + +def register_team_event(request, event): + user = request.user + userProfile = user.get_profile() + teams = Team.objects.filter(event = event) + try: + userTeam = teams.get(members = user) + except Team.DoesNotExist: + # This means that the user is not a part of any registered team. + # We must now execute the team registration logic. + # To register for an event, the user must create a team. + # If the user wants to join another team, the leader of that team must send the user a request. + # Here we must redirect to the create team view. + return render_to_response('events/team_registration_required.html', locals(), context_instance=RequestContext(request)) + #return HttpResponseRedirect(settings.SITE_URL + 'user/teams/create/' + str(event.id) + '/') + # Else the user is already part of a team. + return render_to_response('events/team_registration_done.html', locals(), context_instance=RequestContext(request)) + +@login_required +def register(request, event_id): + """ + This is the event registration view. + If the event is a singular event, i.e. individual participation, the + user will be shown a form asking him to register. + If the event is a team event, the user will be redirected to the team + selection page """ - @method_decorator(login_required) - def userAuthentication(self, request, **kwargs): - if request.user.get_profile().is_coord_of is not None: - return True - return False + event_id = int(event_id) + try: + event = Event.objects.get(id = event_id) + except Event.DoesNotExist: + raise Http404('It seems like you the event you have requested for does not exist.') + if not event.registrable_online: + return render_to_response('events/register_offline.html', locals(), context_instance=RequestContext(request)) + #TODO: This template should tell the user that the event cannot be registered for online and that the registration is only on site. TODO done + if not event.begin_registration: + return render_to_response('events/registration_not_started.html', locals(), context_instance=RequestContext(request)) + #TODO: This template should tell the user that the event registration is online but has not started yet. Stay tuned for updates. TODO done + if not event.team_event: # This means that the event is a singular event. + response = register_singular_event(request, event) + return response + else: # The event is a team event. + response = register_team_event(request, event) + return response - def permissionsGranted(self, request, **kwargs): - """ - Checks if the coord has permissions to access the requested event. - """ - try: - if request.user.get_profile().is_coord_of != Event.objects.get(title = kwargs['event']): - return False # If the coord is not coord of the requested event - return True - except: - raise Http404('You do not have permissions to view this page') - -class CoreProtectedView(ProtectedView): +@login_required +def cancel_registration(request, event_id): """ - CoreProtectedView requires the user to be authenticated and to be a core before proceeding to the computation logic. + This view cancels a users registration for an event. """ - @method_decorator(login_required) - def userAuthentication(self, request, **kwargs): - if request.user.get_profile().is_core: - return True - return False + event_id = int(event_id) + user = request.user + try: + event = Event.objects.get(id = event_id) + except Event.DoesNotExist: + raise Http404('It seems like you the event you have requested for does not exist.') + if event.team_event: + # TODO: This template should tell the user how to deregister from a team event TODO done + return render_to_response('events/team_deregister.html', locals(), context_instance=RequestContext(request)) + try: + user_registration = EventSingularRegistration.objects.filter(event=event).get(user=user) + except: + raise Http404('You are not registered for this event.') -class CoordDashboard(CoordProtectedView): - """ - displays the coord dashboard depending on the logged in coords event - """ - def handle_GET(self, request, **kwargs): - event = request.user.get_profile().is_coord_of - tabs = self.get_tabs(event) - return render_to_response('events/dashboard.html', locals(), context_instance = RequestContext(request)) - -class TabFileSubmit(CoordProtectedView): - """ - ajax file uploads are directed to this view - """ - def handle_POST(self, request, **kwargs): - from django.conf import settings - # These were the headers set by the function File() to pass additional data. - filename = request.META['HTTP_X_FILE_NAME'] - display_name = request.META['HTTP_X_NAME'] - tab_id = request.META['HTTP_X_TAB_ID'] - - tab = Tab.objects.get(id = tab_id) - direc = os.path.join(settings.PROJECT_DIR + settings.MEDIA_URL, 'events', str(tab.event.id), tab._meta.object_name, str(tab.id)) - # note that event and tab IDs and not their titles have been used to create folders so that renaming does not affect the folders - if not os.path.exists(direc): - os.makedirs(direc) - path = os.path.join(direc, filename) - a = TabFile.objects.get_or_create(tab_file = path) - # get_or_create returns a tuple whose second element is a boolean which is True if it is creating a new object. - # the first element is the object that has been created/found. - if a[1]: - a[0].url = os.path.join(settings.MEDIA_URL, 'events', str(tab.event.id), tab._meta.object_name, str(tab.id), filename) - f = open(path, 'w') - with f as dest: - req = request - # Right now the file comes as raw input (in form of binary strings). Unfortunately, this is the only way I know that will make ajax work with file uploads. - foo = req.read( 1024 ) - while foo: - dest.write( foo ) - foo = req.read( 1024 ) - a[0].title = display_name - a[0].tab = tab - a[0].save() - file_list = self.get_files(tab) + if request.method == 'POST': + # If the user submitted the registration cancellation form (which is just a confirm button) + user_registration.delete() + return render_to_response('events/deregistration_done.html', locals(), context_instance=RequestContext(request)) + else: + # If the form has not been submitted, we have to render the form. + # TODO: The template below should have a form which allows the user to choose whether he wants to cancel registration or not. TODO done + return render_to_response('events/deregister_singular_event.html', locals(), context_instance=RequestContext(request)) + - template = loader.get_template('ajax/events/file_list.html') - t = template.render(RequestContext(request, locals())) - # the ajax function File() assigns this as the innerHTML of a div after the request has been completed. - return HttpResponse(t) - - diff --git a/fb/__init__.py b/fb/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fb/models.py b/fb/models.py new file mode 100644 index 0000000..5d9cac1 --- /dev/null +++ b/fb/models.py @@ -0,0 +1,18 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +from django.db import models +from events.models import Event + + +# Create your models here. + +class sampark(models.Model): + place = models.CharField(max_length = 20) + headerlink = models.CharField(max_length = 100) + writeup = models.CharField(max_length=500) + albumid = models.BigIntegerField() + + def __unicode__(self): + return '%s' % self.place + + diff --git a/fb/tests.py b/fb/tests.py new file mode 100644 index 0000000..a9d5fb0 --- /dev/null +++ b/fb/tests.py @@ -0,0 +1,23 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + + self.assertEqual(1 + 1, 2) + + diff --git a/fb/urls.py b/fb/urls.py new file mode 100644 index 0000000..607b387 --- /dev/null +++ b/fb/urls.py @@ -0,0 +1,14 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +from django.conf.urls.defaults import patterns, include, url +from django.conf import settings +from django.contrib.auth import views +from fb.views import * +from django.views.generic.simple import direct_to_template + +urlpatterns = patterns('', + url(r'^events/(?P.+)', events, name='event-list'), + url(r'^hero/', hero, name='hero'), + url(r'^sampark/(?P.+)', sampark, name='sampark'), + url(r'^$', home, name='home'), + ) diff --git a/fb/views.py b/fb/views.py new file mode 100644 index 0000000..efcea10 --- /dev/null +++ b/fb/views.py @@ -0,0 +1,117 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +from django.http import HttpResponse, HttpResponseRedirect, Http404 +from django.template.context import Context, RequestContext +from django.shortcuts import render_to_response +from django.conf import settings +from events.models import Event, EVENT_CATEGORIES,Tag +from django.contrib.auth.decorators import login_required +from django.views.decorators.csrf import csrf_exempt +from dtvpicker.models import SubEvent +import urllib +import json,cgi +from django.template.defaultfilters import slugify + +@csrf_exempt +def home(request): + ''' + event_set = Event.objects.all() + for event in event_set: + if event.fb_event_id and not event.updated: + + # Event needs to be updated + + subevent = SubEvent.objects.filter(event=event)[0] + event_data = { + 'name': event.title, + 'owner': settings.FACEBOOK_APP_ID, + 'description': event.mobapptab.text, + 'start_time': subevent.start_date_and_time.isoformat(' ' + ), + 'end_time': subevent.end_date_and_time.isoformat(' '), + 'location': subevent.venue, + 'access_token': '291744470918252|RCjCxoQPQZdXAiWBiURxP81aUm8', + } + target = urllib.urlopen('https://graph.facebook.com/' + + event.fb_event_id, + urllib.urlencode(event_data)).read() + elif not event.fb_event_id: + + # Event needs to be created + + subevent = SubEvent.objects.filter(event=event)[0] + if subevent: + event_data = { + 'name': event.title, + 'owner': settings.FACEBOOK_APP_ID, + 'description': event.mobapptab.text, + 'start_time': subevent.start_date_and_time.isoformat(' '), + 'end_time': subevent.end_date_and_time.isoformat(' '), + 'location': subevent.venue, + 'access_token': '291744470918252|RCjCxoQPQZdXAiWBiURxP81aUm8', + } + target = \ + urllib.urlopen('https://graph.facebook.com/app/events', + urllib.urlencode(event_data)).read() + response = json.loads(target) + event.fb_event_id = response['id'] + event.save() + ''' + result_list=[] + for t in Tag.objects.all(): + row=[] + row.append(str(t.name)) + temp=[] + for x in t.event_set.all(): + url = slugify(x) + temp.append([str(x),str(url)]) + row.append(temp) + result_list.append(row) + event_set = [] + for c in EVENT_CATEGORIES: + event_category_set = Event.objects.filter(category=c[0]) + if c[0] == "Sampark": + pass + elif event_category_set: + event_set.append(event_category_set) + return render_to_response('fb/home.html', locals(), + context_instance=RequestContext(request)) + +@csrf_exempt +def hero(request): + target = urllib.urlopen('https://graph.facebook.com/424935270885525/photos').read() + photos = json.loads(target)["data"] + srcs=[] + for photo in photos: + srcs.append(photo["images"][0]["source"]) + return render_to_response('fb/hero.html', locals(), + context_instance=RequestContext(request)) +@csrf_exempt +def events(request, event_name): + event_name = event_name.replace('-', ' ') + if event_name=="robo oceana": + event_name="robo-oceana" + elif event_name=="lectures video conferences": + event_name="lectures & video conferences" + event = Event.objects.get(title=event_name) + try: + temp = (request.META['HTTP_REFERER'])[:23] + if temp == 'http://www.facebook.com': + url=settings.SITE_URL + '#events/' + event.title + '/tab/' + event.tab_set.all()[0].title + return HttpResponseRedirect(url) + except: + pass + event_intro = "Desciption comes here!" +# event_intro = event.mobapptab.text + return render_to_response('ajax/fb/events.html', locals(), + context_instance=RequestContext(request)) + +@csrf_exempt +def sampark(request, place_name): + #target = urllib.urlopen('https://graph.facebook.com/424935270885525/photos').read() + #photos = json.loads(target)["data"] + #srcs=[] + #for photo in photos: + #srcs.append(photo["images"][0]["source"]) + place = place_name + return render_to_response('fb/sampark.html', locals(), context_instance=RequestContext(request)) \ No newline at end of file diff --git a/forms.py b/forms.py index f70fb01..64a0296 100644 --- a/forms.py +++ b/forms.py @@ -1,26 +1,38 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- from django import forms from django.forms.util import ValidationError from django.contrib.auth.models import User + class RegistrationForm(forms.Form): - first_name = forms.CharField(help_text = 'Your first name') - email = forms. EmailField(help_text = 'Email id') - username = forms.RegexField(regex = r'^\w+$', max_length = 30, help_text = 'Username must contain only alphabets / digits') - password = forms.CharField(widget = forms.PasswordInput, help_text = 'Password must contain at least 6 characters', min_length = 6) - confirm_password = forms.CharField(widget = forms.PasswordInput, help_text = 'Confirm Password', min_length = 6) - + + first_name = forms.CharField(help_text='Your first name') + email = forms.EmailField(help_text='Email id') + username = forms.RegexField(regex=r'^\w+$', max_length=30, + help_text='Username must contain only alphabets / digits' + ) + password = forms.CharField(widget=forms.PasswordInput, + help_text='Password must contain at least 6 characters' + , min_length=6) + confirm_password = forms.CharField(widget=forms.PasswordInput, + help_text='Confirm Password', min_length=6) + def clean_username(self): data = self.cleaned_data try: - user = User.objects.get(username = data['username']) + user = User.objects.get(username=data['username']) except User.DoesNotExist: return data['username'] raise forms.ValidationError(u'Username already exists') - + def clean_confirm_password(self): data = self.cleaned_data pass1 = data['password'] pass2 = data['confirm_password'] if pass1 and pass2: - if pass1 != pass2: raise forms.ValidationError(u'Passwords do not match') + if pass1 != pass2: + raise forms.ValidationError(u'Passwords do not match') return self.cleaned_data['confirm_password'] + + diff --git a/global_settings.py b/global_settings.py index faf5535..cfff722 100644 --- a/global_settings.py +++ b/global_settings.py @@ -7,7 +7,8 @@ # settings that will be common and useful. PROJECT_DIR = os.path.dirname(os.path.realpath(__file__)) PROJECT_DIR_NAME = PROJECT_DIR.split('/')[-1] # used in dajaxice.[my_project_folder_name].events.[ajax_function] (see context_processors.py) -AJAX_TEMPLATE_DIR = os.path.join(PROJECT_DIR, 'templates/events', 'ajax') # path where ajax templates are stored +AJAX_TEMPLATE_DIR = os.path.join(PROJECT_DIR, 'templates', 'ajax') # path where ajax templates are stored +FIXTURES_DIR = os.path.dirname(__file__) SITE_ID = 1 @@ -18,10 +19,6 @@ AUTH_PROFILE_MODULE = 'users.UserProfile' -FACEBOOK_APP_ID = '291744470918252' -FACEBOOK_APP_SECRET = '599f13aad496d3acc8ea887a0e889b92' -FACEBOOK_SCOPE = 'email' - TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', @@ -35,7 +32,6 @@ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', ) - ROOT_URLCONF = 'urls' INSTALLED_APPS = ( @@ -44,15 +40,18 @@ 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', + 'django.contrib.sitemaps', 'django.contrib.messages', 'admin', + 'core', + 'coord', 'users', 'events', - 'dajaxice', - 'dajax', - 'core', 'submissions', 'dtvpicker', + 'dajaxice', + 'dajax', + 'recaptcha', ) # A sample logging configuration. The only tangible logging @@ -82,6 +81,8 @@ 'django.contrib.auth.backends.ModelBackend', ) +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' + # List of finder classes that know how to find static files in # various locations. STATICFILES_FINDERS = ( @@ -104,10 +105,12 @@ DAJAXICE_MEDIA_PREFIX="dajaxice" DAJAXICE_DEBUG = True -EMAIL_HOST='localhost' -#Default: 'localhost' -#The host to use for sending e-mail. -EMAIL_HOST_PASSWORD='$#aastra20iiw3b0ps' -#Default: '' (Empty string) -EMAIL_HOST_USER='shaastra' +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', + 'LOCATION': '127.0.0.1:11211', + } +} +RECAPTCHA_PUBLIC_KEY = '6Lf1ktUSAAAAALOtemzm08LVwHmfku6yXXCdrMJn' +RECAPTCHA_PRIVATE_KEY = '6Lf1ktUSAAAAANLvSSLPiSpgocDrjyK9ApPUvcaF' diff --git a/recaptcha/__init__.py b/recaptcha/__init__.py new file mode 100644 index 0000000..de40ea7 --- /dev/null +++ b/recaptcha/__init__.py @@ -0,0 +1 @@ +__import__('pkg_resources').declare_namespace(__name__) diff --git a/recaptcha/client/__init__.py b/recaptcha/client/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/recaptcha/client/captcha.py b/recaptcha/client/captcha.py new file mode 100644 index 0000000..1213fc4 --- /dev/null +++ b/recaptcha/client/captcha.py @@ -0,0 +1,94 @@ +import urllib2, urllib + +API_SSL_SERVER="https://www.google.com/recaptcha/api" +API_SERVER="http://www.google.com/recaptcha/api" +VERIFY_SERVER="www.google.com" + +class RecaptchaResponse(object): + def __init__(self, is_valid, error_code=None): + self.is_valid = is_valid + self.error_code = error_code + +def displayhtml (public_key, + use_ssl = False, + error = None): + """Gets the HTML to display for reCAPTCHA + + public_key -- The public api key + use_ssl -- Should the request be sent over ssl? + error -- An error message to display (from RecaptchaResponse.error_code)""" + + error_param = '' + if error: + error_param = '&error=%s' % error + + if use_ssl: + server = API_SSL_SERVER + else: + server = API_SERVER + + return """ + + +""" % { + 'ApiServer' : server, + 'PublicKey' : public_key, + 'ErrorParam' : error_param, + } + + +def submit (recaptcha_challenge_field, + recaptcha_response_field, + private_key, + remoteip): + """ + Submits a reCAPTCHA request for verification. Returns RecaptchaResponse + for the request + + recaptcha_challenge_field -- The value of recaptcha_challenge_field from the form + recaptcha_response_field -- The value of recaptcha_response_field from the form + private_key -- your reCAPTCHA private key + remoteip -- the user's ip address + """ + + if not (recaptcha_response_field and recaptcha_challenge_field and + len (recaptcha_response_field) and len (recaptcha_challenge_field)): + return RecaptchaResponse (is_valid = False, error_code = 'incorrect-captcha-sol') + + + def encode_if_necessary(s): + if isinstance(s, unicode): + return s.encode('utf-8') + return s + + params = urllib.urlencode ({ + 'privatekey': encode_if_necessary(private_key), + 'remoteip' : encode_if_necessary(remoteip), + 'challenge': encode_if_necessary(recaptcha_challenge_field), + 'response' : encode_if_necessary(recaptcha_response_field), + }) + + request = urllib2.Request ( + url = "http://%s/recaptcha/api/verify" % VERIFY_SERVER, + data = params, + headers = { + "Content-type": "application/x-www-form-urlencoded", + "User-agent": "reCAPTCHA Python" + } + ) + + httpresp = urllib2.urlopen (request) + + return_values = httpresp.read ().splitlines (); + httpresp.close(); + + return_code = return_values [0] + + if (return_code == "true"): + return RecaptchaResponse (is_valid=True) + else: + return RecaptchaResponse (is_valid=False, error_code = return_values [1]) diff --git a/recaptcha/client/mailhide.py b/recaptcha/client/mailhide.py new file mode 100644 index 0000000..437b2c2 --- /dev/null +++ b/recaptcha/client/mailhide.py @@ -0,0 +1,68 @@ +import base64 +import cgi + +try: + from Crypto.Cipher import AES +except: + raise Exception ("You need the pycrpyto library: http://cheeseshop.python.org/pypi/pycrypto/") + +MAIL_HIDE_BASE="http://www.google.com/recaptcha/mailhide" + +def asurl (email, + public_key, + private_key): + """Wraps an email address with reCAPTCHA mailhide and + returns the url. public_key is the public key from reCAPTCHA + (in the base 64 encoded format). Private key is the AES key, and should + be 32 hex chars.""" + + cryptmail = _encrypt_string (email, base64.b16decode (private_key, casefold=True), '\0' * 16) + base64crypt = base64.urlsafe_b64encode (cryptmail) + + return "%s/d?k=%s&c=%s" % (MAIL_HIDE_BASE, public_key, base64crypt) + +def ashtml (email, + public_key, + private_key): + """Wraps an email address with reCAPTCHA Mailhide and + returns html that displays the email""" + + url = asurl (email, public_key, private_key) + (userpart, domainpart) = _doterizeemail (email) + + return """%(user)s...@%(domain)s""" % { + 'user' : cgi.escape (userpart), + 'domain' : cgi.escape (domainpart), + 'url' : cgi.escape (url), + } + + +def _pad_string (str, block_size): + numpad = block_size - (len (str) % block_size) + return str + numpad * chr (numpad) + +def _encrypt_string (str, aes_key, aes_iv): + if len (aes_key) != 16: + raise Exception ("expecting key of length 16") + if len (aes_iv) != 16: + raise Exception ("expecting iv of length 16") + return AES.new (aes_key, AES.MODE_CBC, aes_iv).encrypt (_pad_string (str, 16)) + +def _doterizeemail (email): + """replaces part of the username with dots""" + + try: + [user, domain] = email.split ('@') + except: + # handle invalid emails... sorta + user = email + domain = "" + + if len(user) <= 4: + user_prefix = user[:1] + elif len(user) <= 6: + user_prefix = user[:3] + else: + user_prefix = user[:4] + + return (user_prefix, domain) diff --git a/settings.py b/settings.py index 135e60f..dc8d16f 100644 --- a/settings.py +++ b/settings.py @@ -1,3 +1,4 @@ +#import debugger +#from debugger import * import local_settings -from local_settings import * - +from local_settings import * \ No newline at end of file diff --git a/sitemaps.py b/sitemaps.py new file mode 100644 index 0000000..cf21927 --- /dev/null +++ b/sitemaps.py @@ -0,0 +1,212 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import datetime +from django.db import models +from django.contrib.sitemaps import * +from django.contrib.auth.models import * +from events.models import * +from django.contrib.sites import * +from django.core.urlresolvers import * +from users.models import * +from django.core.urlresolvers import reverse +from settings import SITE_URL +from admin.urls import * +from users.urls import * +from dtvpicker.models import * +from dtvpicker.urls import * +from submissions.urls import * +from django.template.defaultfilters import slugify + + +# For simple urls + +class EventSitemap(Sitemap): + + changefreq = 'always' + priority = '0.5' + + def items(self): + return Event.objects.all() + + def lastmod(self, obj): + return obj.updated + + def location(self, obj): + + # return '/#events/' + slugify(obj.title) + try : + tab_name=Tab.objects.filter(event=obj).order_by('pref')[0].title + except: + tab_name="" + if obj.title.split('_')[0].__len__() ==1 : + return '/2013/main/events/sampark/#events/' + slugify(obj.title) + '/tab/' + tab_name + return '/2013/main/#events/' + slugify(obj.title) + '/tab/' + tab_name + + +class SiteSiteMap(Sitemap): + + def __init__(self, names): + self.names = names + + def items(self): + return self.names + + def changefreq(self, obj): + return 'always' + + def location(self, obj): + try: + if obj != None: + return reverse(obj, args=[obj.pk]) + else: + return reverse(obj) + except: + return str(obj) + + +# admin captured parameter urls start + +class EditCoreSiteMap(Sitemap): + + changefreq = 'always' + priority = '0.5' + + def items(self): + allusers = UserProfile.objects.all() + returnset = [] + for object in allusers: + + # profile=UserProfile.objects.filter(id=object.id) + + if object: + if object.is_core: + returnset.append(object) + return returnset + + def location(self, obj): + return '/editcore/' + str(obj.id) + + +class EditGroupSiteMap(Sitemap): + + changefreq = 'always' + priority = '0.5' + + def items(self): + allgroups = Group.objects.all() + returnset = [] + for object in allgroups: + returnset.append(object) + return returnset + + def location(self, obj): + return '/editgroup/' + str(obj.id) + + +# admin captured parameter urls end +# users captured parameter urls start +# users captured parameter urls end +# dtvpicker captured parameter urls start + +class AddSubEventSiteMap(Sitemap): + + changefreq = 'always' + priority = '0.5' + + def items(self): + allevents = Event.objects.all() + returnset = [] + for object in allevents: + returnset.append(object) + return returnset + + def location(self, obj): + return '/' + str(obj.title) + '/AddSubEvent/' + + +class EditSubEventSiteMap(Sitemap): + + changefreq = 'always' + priority = '0.5' + + def items(self): + allsubevents = SubEvent.objects.all() + returnset = [] + for object in allsubevents: + returnset.append(object) + return returnset + + def location(self, obj): + return '/' + str(obj.event.title) + '/EditSubEvent/' \ + + str(obj.title) + + +class DeleteSubEventSiteMap(Sitemap): + + changefreq = 'always' + priority = '0.5' + + def items(self): + allsubevents = SubEvent.objects.all() + returnset = [] + for object in allsubevents: + returnset.append(object) + return returnset + + def location(self, obj): + return '/' + str(obj.event.title) + '/DeleteSubEvent/' \ + + str(obj.title) + + +class LockEventSiteMap(Sitemap): + + changefreq = 'always' + priority = '0.5' + + def items(self): + allevents = Event.objects.all() + returnset = [] + for object in allevents: + returnset.append(object) + return returnset + + def location(self, obj): + return '/' + str(obj.title) + '/LockEvent/' + + +class UnlockEventSiteMap(Sitemap): + + changefreq = 'always' + priority = '0.5' + + def items(self): + allevents = Event.objects.all() + returnset = [] + for object in allevents: + returnset.append(object) + return returnset + + def location(self, obj): + return '/' + str(obj.title) + '/UnlockEvent/' + + +# dtvpicker captured parameter urls end here +# submissions captured parameter urls start here + +class Event_SubmissionSiteMap(Sitemap): + + changefreq = 'always' + priority = '0.5' + + def items(self): + allevents = Event.objects.all() + returnset = [] + for object in allevents: + returnset.append(object) + return returnset + + def location(self, obj): + return '/' + str(obj.id) + '/' + + +# submissions captured parameter urls end here \ No newline at end of file diff --git a/static/css/chosen.css b/static/css/chosen.css deleted file mode 100644 index e704d3b..0000000 --- a/static/css/chosen.css +++ /dev/null @@ -1,390 +0,0 @@ -/* @group Base */ -.chzn-container { - font-size: 13px; - position: relative; - display: inline-block; - zoom: 1; - *display: inline; -} -.chzn-container .chzn-drop { - background: #fff; - border: 1px solid #aaa; - border-top: 0; - position: absolute; - top: 29px; - left: 0; - -webkit-box-shadow: 0 4px 5px rgba(0,0,0,.15); - -moz-box-shadow : 0 4px 5px rgba(0,0,0,.15); - -o-box-shadow : 0 4px 5px rgba(0,0,0,.15); - box-shadow : 0 4px 5px rgba(0,0,0,.15); - z-index: 999; -} -/* @end */ - -/* @group Single Chosen */ -.chzn-container-single .chzn-single { - background-color: #ffffff; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #f4f4f4), color-stop(0.48, #eeeeee), color-stop(0.5, #f6f6f6), color-stop(0.8, #ffffff)); - background-image: -webkit-linear-gradient(center bottom, #f4f4f4 0%, #eeeeee 48%, #f6f6f6 50%, #ffffff 80%); - background-image: -moz-linear-gradient(center bottom, #f4f4f4 0%, #eeeeee 48%, #f6f6f6 50%, #ffffff 80%); - background-image: -o-linear-gradient(top, #f4f4f4 0%, #eeeeee 48%, #f6f6f6 50%, #ffffff 80%); - background-image: -ms-linear-gradient(top, #f4f4f4 0%, #eeeeee 48%, #f6f6f6 50%, #ffffff 80%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff',GradientType=0 ); - background-image: linear-gradient(top, #f4f4f4 0%, #eeeeee 48%, #f6f6f6 50%, #ffffff 80%); - -webkit-border-radius: 5px; - -moz-border-radius : 5px; - border-radius : 5px; - -moz-background-clip : padding; - -webkit-background-clip: padding-box; - background-clip : padding-box; - border: 1px solid #aaaaaa; - -webkit-box-shadow: 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1); - -moz-box-shadow : 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1); - box-shadow : 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1); - display: block; - overflow: hidden; - white-space: nowrap; - position: relative; - height: 23px; - line-height: 23px; - padding: 0 0 0 8px; - color: #444444; - text-decoration: none; -} -.chzn-container-single .chzn-single span { - margin-right: 26px; - display: block; - overflow: hidden; - white-space: nowrap; - -o-text-overflow: ellipsis; - -ms-text-overflow: ellipsis; - text-overflow: ellipsis; -} -.chzn-container-single .chzn-single abbr { - display: block; - position: absolute; - right: 26px; - top: 6px; - width: 12px; - height: 13px; - font-size: 1px; - background: url('../img/chosen-sprite.png') right top no-repeat; -} -.chzn-container-single .chzn-single abbr:hover { - background-position: right -11px; -} -.chzn-container-single .chzn-single div { - position: absolute; - right: 0; - top: 0; - display: block; - height: 100%; - width: 18px; -} -.chzn-container-single .chzn-single div b { - background: url('../img/chosen-sprite.png') no-repeat 0 0; - display: block; - width: 100%; - height: 100%; -} -.chzn-container-single .chzn-search { - padding: 3px 4px; - position: relative; - margin: 0; - white-space: nowrap; - z-index: 1010; -} -.chzn-container-single .chzn-search input { - background: #fff url('../img/chosen-sprite.png') no-repeat 100% -22px; - background: url('../img/chosen-sprite.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); - background: url('../img/chosen-sprite.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('../img/chosen-sprite.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('../img/chosen-sprite.png') no-repeat 100% -22px, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); - background: url('../img/chosen-sprite.png') no-repeat 100% -22px, -ms-linear-gradient(top, #ffffff 85%,#eeeeee 99%); - background: url('../img/chosen-sprite.png') no-repeat 100% -22px, linear-gradient(top, #ffffff 85%,#eeeeee 99%); - margin: 1px 0; - padding: 4px 20px 4px 5px; - outline: 0; - border: 1px solid #aaa; - font-family: sans-serif; - font-size: 1em; -} -.chzn-container-single .chzn-drop { - -webkit-border-radius: 0 0 4px 4px; - -moz-border-radius : 0 0 4px 4px; - border-radius : 0 0 4px 4px; - -moz-background-clip : padding; - -webkit-background-clip: padding-box; - background-clip : padding-box; -} -/* @end */ - -.chzn-container-single-nosearch .chzn-search input { - position: absolute; - left: -9000px; -} - -/* @group Multi Chosen */ -.chzn-container-multi .chzn-choices { - background-color: #fff; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); - background-image: -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background-image: -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background-image: -o-linear-gradient(bottom, white 85%, #eeeeee 99%); - background-image: -ms-linear-gradient(top, #ffffff 85%, #eeeeee 99%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee',GradientType=0 ); - background-image: linear-gradient(top, #ffffff 85%, #eeeeee 99%); - border: 1px solid #aaa; - margin: 0; - padding: 0; - cursor: text; - overflow: hidden; - height: auto !important; - height: 1%; - position: relative; -} -.chzn-container-multi .chzn-choices li { - float: left; - list-style: none; -} -.chzn-container-multi .chzn-choices .search-field { - white-space: nowrap; - margin: 0; - padding: 0; -} -.chzn-container-multi .chzn-choices .search-field input { - color: #666; - background: transparent !important; - border: 0 !important; - font-family: sans-serif; - font-size: 100%; - height: 15px; - padding: 5px; - margin: 1px 0; - outline: 0; - -webkit-box-shadow: none; - -moz-box-shadow : none; - -o-box-shadow : none; - box-shadow : none; -} -.chzn-container-multi .chzn-choices .search-field .default { - color: #999; -} -.chzn-container-multi .chzn-choices .search-choice { - -webkit-border-radius: 3px; - -moz-border-radius : 3px; - border-radius : 3px; - -moz-background-clip : padding; - -webkit-background-clip: padding-box; - background-clip : padding-box; - background-color: #e4e4e4; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.48, #e8e8e8), color-stop(0.5, #f0f0f0), color-stop(0.8, #f4f4f4)); - background-image: -webkit-linear-gradient(center bottom, #eeeeee 0%, #e8e8e8 48%, #f0f0f0 50%, #f4f4f4 80%); - background-image: -moz-linear-gradient(center bottom, #eeeeee 0%, #e8e8e8 48%, #f0f0f0 50%, #f4f4f4 80%); - background-image: -o-linear-gradient(top, #eeeeee 0%, #e8e8e8 48%, #f0f0f0 50%, #f4f4f4 80%); - background-image: -ms-linear-gradient(top, #eeeeee 0%, #e8e8e8 48%, #f0f0f0 50%, #f4f4f4 80%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#f4f4f4',GradientType=0 ); - background-image: linear-gradient(top, #eeeeee 0%, #e8e8e8 48%, #f0f0f0 50%, #f4f4f4 80%); - -webkit-box-shadow: 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); - -moz-box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); - box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); - color: #333; - border: 1px solid #aaaaaa; - line-height: 13px; - padding: 3px 20px 3px 5px; - margin: 3px 0 3px 5px; - position: relative; -} -.chzn-container-multi .chzn-choices .search-choice span { - cursor: default; -} -.chzn-container-multi .chzn-choices .search-choice-focus { - background: #d4d4d4; -} -.chzn-container-multi .chzn-choices .search-choice .search-choice-close { - display: block; - position: absolute; - right: 3px; - top: 4px; - width: 12px; - height: 13px; - font-size: 1px; - background: url('../img/chosen-sprite.png') right top no-repeat; -} -.chzn-container-multi .chzn-choices .search-choice .search-choice-close:hover { - background-position: right -11px; -} -.chzn-container-multi .chzn-choices .search-choice-focus .search-choice-close { - background-position: right -11px; -} -/* @end */ - -/* @group Results */ -.chzn-container .chzn-results { - margin: 0 4px 4px 0; - max-height: 240px; - padding: 0 0 0 4px; - position: relative; - overflow-x: hidden; - overflow-y: auto; -} -.chzn-container-multi .chzn-results { - margin: -1px 0 0; - padding: 0; -} -.chzn-container .chzn-results li { - display: none; - line-height: 15px; - padding: 5px 6px; - margin: 0; - list-style: none; -} -.chzn-container .chzn-results .active-result { - cursor: pointer; - display: list-item; -} -.chzn-container .chzn-results .highlighted { - background-color: #3875d7; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.1, #2a62bc), color-stop(0.8, #3875d7)); - background-image: -webkit-linear-gradient(center bottom, #2a62bc 10%, #3875d7 80%); - background-image: -moz-linear-gradient(center bottom, #2a62bc 10%, #3875d7 80%); - background-image: -o-linear-gradient(bottom, #2a62bc 10%, #3875d7 80%); - background-image: -ms-linear-gradient(top, #2a62bc 10%, #3875d7 80%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2a62bc', endColorstr='#3875d7',GradientType=0 ); - background-image: linear-gradient(top, #2a62bc 10%, #3875d7 80%); - color: #fff; -} -.chzn-container .chzn-results li em { - background: #feffde; - font-style: normal; -} -.chzn-container .chzn-results .highlighted em { - background: transparent; -} -.chzn-container .chzn-results .no-results { - background: #f4f4f4; - display: list-item; -} -.chzn-container .chzn-results .group-result { - cursor: default; - color: #999; - font-weight: bold; -} -.chzn-container .chzn-results .group-option { - padding-left: 15px; -} -.chzn-container-multi .chzn-drop .result-selected { - display: none; -} -.chzn-container .chzn-results-scroll { - background: white; - margin: 0px 4px; - position: absolute; - text-align: center; - width: 321px; /* This should by dynamic with js */ - z-index: 1; -} -.chzn-container .chzn-results-scroll span { - display: inline-block; - height: 17px; - text-indent: -5000px; - width: 9px; -} -.chzn-container .chzn-results-scroll-down { - bottom: 0; -} -.chzn-container .chzn-results-scroll-down span { - background: url('../img/chosen-sprite.png') no-repeat -4px -3px; -} -.chzn-container .chzn-results-scroll-up span { - background: url('../img/chosen-sprite.png') no-repeat -22px -3px; -} -/* @end */ - -/* @group Active */ -.chzn-container-active .chzn-single { - -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3); - -moz-box-shadow : 0 0 5px rgba(0,0,0,.3); - -o-box-shadow : 0 0 5px rgba(0,0,0,.3); - box-shadow : 0 0 5px rgba(0,0,0,.3); - border: 1px solid #5897fb; -} -.chzn-container-active .chzn-single-with-drop { - border: 1px solid #aaa; - -webkit-box-shadow: 0 1px 0 #fff inset; - -moz-box-shadow : 0 1px 0 #fff inset; - -o-box-shadow : 0 1px 0 #fff inset; - box-shadow : 0 1px 0 #fff inset; - background-color: #eee; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.2, white), color-stop(0.8, #eeeeee)); - background-image: -webkit-linear-gradient(center bottom, white 20%, #eeeeee 80%); - background-image: -moz-linear-gradient(center bottom, white 20%, #eeeeee 80%); - background-image: -o-linear-gradient(bottom, white 20%, #eeeeee 80%); - background-image: -ms-linear-gradient(top, #ffffff 20%,#eeeeee 80%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee',GradientType=0 ); - background-image: linear-gradient(top, #ffffff 20%,#eeeeee 80%); - -webkit-border-bottom-left-radius : 0; - -webkit-border-bottom-right-radius: 0; - -moz-border-radius-bottomleft : 0; - -moz-border-radius-bottomright: 0; - border-bottom-left-radius : 0; - border-bottom-right-radius: 0; -} -.chzn-container-active .chzn-single-with-drop div { - background: transparent; - border-left: none; -} -.chzn-container-active .chzn-single-with-drop div b { - background-position: -18px 1px; -} -.chzn-container-active .chzn-choices { - -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3); - -moz-box-shadow : 0 0 5px rgba(0,0,0,.3); - -o-box-shadow : 0 0 5px rgba(0,0,0,.3); - box-shadow : 0 0 5px rgba(0,0,0,.3); - border: 1px solid #5897fb; -} -.chzn-container-active .chzn-choices .search-field input { - color: #111 !important; -} -/* @end */ - -/* @group Disabled Support */ -.chzn-disabled { - cursor: default; - opacity:0.5 !important; -} -.chzn-disabled .chzn-single { - cursor: default; -} -.chzn-disabled .chzn-choices .search-choice .search-choice-close { - cursor: default; -} - -/* @group Right to Left */ -.chzn-rtl { direction:rtl;text-align: right; } -.chzn-rtl .chzn-single { padding-left: 0; padding-right: 8px; } -.chzn-rtl .chzn-single span { margin-left: 26px; margin-right: 0; } - -.chzn-rtl .chzn-single div { left: 3px; right: auto; } -.chzn-rtl .chzn-single abbr { - left: 26px; - right: auto; -} -.chzn-rtl .chzn-choices li { float: right; } -.chzn-rtl .chzn-choices .search-choice { padding: 3px 5px 3px 19px; margin: 3px 5px 3px 0; } -.chzn-rtl .chzn-choices .search-choice .search-choice-close { left: 4px; right: auto; background-position: right top;} -.chzn-rtl.chzn-container-single .chzn-results { margin-left: 4px; margin-right: 0; padding-left: 0; padding-right: 4px; } -.chzn-rtl .chzn-results .group-option { padding-left: 0; padding-right: 20px; } -.chzn-rtl.chzn-container-active .chzn-single-with-drop div { border-right: none; } -.chzn-rtl .chzn-search input { - background: url('../img/chosen-sprite.png') no-repeat -38px -22px, #ffffff; - background: url('../img/chosen-sprite.png') no-repeat -38px -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); - background: url('../img/chosen-sprite.png') no-repeat -38px -22px, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('../img/chosen-sprite.png') no-repeat -38px -22px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('../img/chosen-sprite.png') no-repeat -38px -22px, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); - background: url('../img/chosen-sprite.png') no-repeat -38px -22px, -ms-linear-gradient(top, #ffffff 85%,#eeeeee 99%); - background: url('../img/chosen-sprite.png') no-repeat -38px -22px, linear-gradient(top, #ffffff 85%,#eeeeee 99%); - padding: 4px 5px 4px 20px; -} -/* @end */ \ No newline at end of file diff --git a/static/css/demo_page.css b/static/css/demo_page.css deleted file mode 100644 index 088d8b9..0000000 --- a/static/css/demo_page.css +++ /dev/null @@ -1,99 +0,0 @@ - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * General page setup - */ -#dt_example { - font: 80%/1.45em "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; - margin: 0; - padding: 0; - color: #333; - background-color: #fff; -} - - -#dt_example #container { - width: 800px; - margin: 30px auto; - padding: 0; -} - - -#dt_example #footer { - margin: 50px auto 0 auto; - padding: 0; -} - -#dt_example #demo { - margin: 30px auto 0 auto; -} - -#dt_example .demo_jui { - margin: 30px auto 0 auto; -} - -#dt_example .big { - font-size: 1.3em; - font-weight: bold; - line-height: 1.6em; - color: #4E6CA3; -} - -#dt_example .spacer { - height: 20px; - clear: both; -} - -#dt_example .clear { - clear: both; -} - -#dt_example pre { - padding: 15px; - background-color: #F5F5F5; - border: 1px solid #CCCCCC; -} - -#dt_example h1 { - margin-top: 2em; - font-size: 1.3em; - font-weight: normal; - line-height: 1.6em; - color: #4E6CA3; - border-bottom: 1px solid #B0BED9; - clear: both; -} - -#dt_example h2 { - font-size: 1.2em; - font-weight: normal; - line-height: 1.6em; - color: #4E6CA3; - clear: both; -} - -#dt_example a { - color: #0063DC; - text-decoration: none; -} - -#dt_example a:hover { - text-decoration: underline; -} - -#dt_example ul { - color: #4E6CA3; -} - -.css_right { - float: right; -} - -.css_left { - float: left; -} - -.demo_links { - float: left; - width: 50%; - margin-bottom: 1em; -} \ No newline at end of file diff --git a/static/css/demo_table.css b/static/css/demo_table.css deleted file mode 100644 index f7d9be7..0000000 --- a/static/css/demo_table.css +++ /dev/null @@ -1,577 +0,0 @@ -/* - * File: demo_table.css - * CVS: $Id$ - * Description: CSS descriptions for DataTables demo pages - * Author: Allan Jardine - * Created: Tue May 12 06:47:22 BST 2009 - * Modified: $Date$ by $Author$ - * Language: CSS - * Project: DataTables - * - * Copyright 2009 Allan Jardine. All Rights Reserved. - * - * *************************************************************************** - * DESCRIPTION - * - * The styles given here are suitable for the demos that are used with the standard DataTables - * distribution (see www.datatables.net). You will most likely wish to modify these styles to - * meet the layout requirements of your site. - * - * Common issues: - * 'full_numbers' pagination - I use an extra selector on the body tag to ensure that there is - * no conflict between the two pagination types. If you want to use full_numbers pagination - * ensure that you either have "example_alt_pagination" as a body class name, or better yet, - * modify that selector. - * Note that the path used for img is relative. All img are by default located in - * ../img/ - relative to this CSS file. - */ - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * DataTables features - */ - -.dataTables_wrapper { - position: relative; - min-height: 302px; - clear: both; - _height: 302px; - zoom: 1; /* Feeling sorry for IE */ -} - -.dataTables_processing { - position: absolute; - top: 50%; - left: 50%; - width: 250px; - height: 30px; - margin-left: -125px; - margin-top: -15px; - padding: 14px 0 2px 0; - border: 1px solid #ddd; - text-align: center; - color: #999; - font-size: 14px; - background-color: white; -} - -.dataTables_length { - width: 40%; - float: left; -} - -.dataTables_filter { - width: 50%; - float: right; - text-align: right; -} - -.dataTables_info { - width: 60%; - float: left; -} - -.dataTables_paginate { - float: right; - text-align: right; -} - -/* Pagination nested */ -.paginate_disabled_previous, .paginate_enabled_previous, -.paginate_disabled_next, .paginate_enabled_next { - height: 19px; - float: left; - cursor: pointer; - *cursor: hand; - color: #111 !important; -} -.paginate_disabled_previous:hover, .paginate_enabled_previous:hover, -.paginate_disabled_next:hover, .paginate_enabled_next:hover { - text-decoration: none !important; -} -.paginate_disabled_previous:active, .paginate_enabled_previous:active, -.paginate_disabled_next:active, .paginate_enabled_next:active { - outline: none; -} - -.paginate_disabled_previous, -.paginate_disabled_next { - color: #666 !important; -} -.paginate_disabled_previous, .paginate_enabled_previous { - padding-left: 23px; -} -.paginate_disabled_next, .paginate_enabled_next { - padding-right: 23px; - margin-left: 10px; -} - -.paginate_disabled_previous { - background: url('../img/back_disabled.png') no-repeat top left; -} - -.paginate_enabled_previous { - background: url('../img/back_enabled.png') no-repeat top left; -} -.paginate_enabled_previous:hover { - background: url('../img/back_enabled_hover.png') no-repeat top left; -} - -.paginate_disabled_next { - background: url('../img/forward_disabled.png') no-repeat top right; -} - -.paginate_enabled_next { - background: url('../img/forward_enabled.png') no-repeat top right; -} -.paginate_enabled_next:hover { - background: url('../img/forward_enabled_hover.png') no-repeat top right; -} - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * DataTables display - */ -table.display { - margin: 0 auto; - clear: both; - width: 100%; - - /* Note Firefox 3.5 and before have a bug with border-collapse - * ( https://bugzilla.mozilla.org/show%5Fbug.cgi?id=155955 ) - * border-spacing: 0; is one possible option. Conditional-css.com is - * useful for this kind of thing - * - * Further note IE 6/7 has problems when calculating widths with border width. - * It subtracts one px relative to the other browsers from the first column, and - * adds one to the end... - * - * If you want that effect I'd suggest setting a border-top/left on th/td's and - * then filling in the gaps with other borders. - */ -} - -table.display thead th { - padding: 3px 18px 3px 10px; - border-bottom: 1px solid black; - font-weight: bold; - cursor: pointer; - * cursor: hand; -} - -table.display tfoot th { - padding: 3px 18px 3px 10px; - border-top: 1px solid black; - font-weight: bold; -} - -table.display tr.heading2 td { - border-bottom: 1px solid #aaa; -} - -table.display td { - padding: 3px 10px; -} - -table.display td.center { - text-align: center; -} - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * DataTables sorting - */ - -.sorting_asc { - background: url('../img/sort_asc.png') no-repeat center right; -} - -.sorting_desc { - background: url('../img/sort_desc.png') no-repeat center right; -} - -.sorting { - background: url('../img/sort_both.png') no-repeat center right; -} - -.sorting_asc_disabled { - background: url('../img/sort_asc_disabled.png') no-repeat center right; -} - -.sorting_desc_disabled { - background: url('../img/sort_desc_disabled.png') no-repeat center right; -} - -th:active { - outline: none; -} - - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * DataTables row classes - */ -table.display tr.odd.gradeA { - background-color: #ddffdd; -} - -table.display tr.even.gradeA { - background-color: #eeffee; -} - -table.display tr.odd.gradeC { - background-color: #ddddff; -} - -table.display tr.even.gradeC { - background-color: #eeeeff; -} - -table.display tr.odd.gradeX { - background-color: #ffdddd; -} - -table.display tr.even.gradeX { - background-color: #ffeeee; -} - -table.display tr.odd.gradeU { - background-color: #ddd; -} - -table.display tr.even.gradeU { - background-color: #eee; -} - - -tr.odd { - background-color: #E2E4FF; -} - -tr.even { - background-color: white; -} - - - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Misc - */ -.dataTables_scroll { - clear: both; -} - -.dataTables_scrollBody { - *margin-top: -1px; -} - -.top, .bottom { - padding: 15px; - background-color: #F5F5F5; - border: 1px solid #CCCCCC; -} - -.top .dataTables_info { - float: none; -} - -.clear { - clear: both; -} - -.dataTables_empty { - text-align: center; -} - -tfoot input { - margin: 0.5em 0; - width: 100%; - color: #444; -} - -tfoot input.search_init { - color: #999; -} - -td.group { - background-color: #d1cfd0; - border-bottom: 2px solid #A19B9E; - border-top: 2px solid #A19B9E; -} - -td.details { - background-color: #d1cfd0; - border: 2px solid #A19B9E; -} - - -.example_alt_pagination div.dataTables_info { - width: 40%; -} - -.paging_full_numbers { - width: 400px; - height: 22px; - line-height: 22px; -} - -.paging_full_numbers a:active { - outline: none -} - -.paging_full_numbers a:hover { - text-decoration: none; -} - -.paging_full_numbers a.paginate_button, - .paging_full_numbers a.paginate_active { - border: 1px solid #aaa; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - padding: 2px 5px; - margin: 0 3px; - cursor: pointer; - *cursor: hand; - color: #333 !important; -} - -.paging_full_numbers a.paginate_button { - background-color: #ddd; -} - -.paging_full_numbers a.paginate_button:hover { - background-color: #ccc; - text-decoration: none !important; -} - -.paging_full_numbers a.paginate_active { - background-color: #99B3FF; -} - -table.display tr.even.row_selected td { - background-color: #B0BED9; -} - -table.display tr.odd.row_selected td { - background-color: #9FAFD1; -} - - -/* - * Sorting classes for columns - */ -/* For the standard odd/even */ -tr.odd td.sorting_1 { - background-color: #D3D6FF; -} - -tr.odd td.sorting_2 { - background-color: #DADCFF; -} - -tr.odd td.sorting_3 { - background-color: #E0E2FF; -} - -tr.even td.sorting_1 { - background-color: #EAEBFF; -} - -tr.even td.sorting_2 { - background-color: #F2F3FF; -} - -tr.even td.sorting_3 { - background-color: #F9F9FF; -} - - -/* For the Conditional-CSS grading rows */ -/* - Colour calculations (based off the main row colours) - Level 1: - dd > c4 - ee > d5 - Level 2: - dd > d1 - ee > e2 - */ -tr.odd.gradeA td.sorting_1 { - background-color: #c4ffc4; -} - -tr.odd.gradeA td.sorting_2 { - background-color: #d1ffd1; -} - -tr.odd.gradeA td.sorting_3 { - background-color: #d1ffd1; -} - -tr.even.gradeA td.sorting_1 { - background-color: #d5ffd5; -} - -tr.even.gradeA td.sorting_2 { - background-color: #e2ffe2; -} - -tr.even.gradeA td.sorting_3 { - background-color: #e2ffe2; -} - -tr.odd.gradeC td.sorting_1 { - background-color: #c4c4ff; -} - -tr.odd.gradeC td.sorting_2 { - background-color: #d1d1ff; -} - -tr.odd.gradeC td.sorting_3 { - background-color: #d1d1ff; -} - -tr.even.gradeC td.sorting_1 { - background-color: #d5d5ff; -} - -tr.even.gradeC td.sorting_2 { - background-color: #e2e2ff; -} - -tr.even.gradeC td.sorting_3 { - background-color: #e2e2ff; -} - -tr.odd.gradeX td.sorting_1 { - background-color: #ffc4c4; -} - -tr.odd.gradeX td.sorting_2 { - background-color: #ffd1d1; -} - -tr.odd.gradeX td.sorting_3 { - background-color: #ffd1d1; -} - -tr.even.gradeX td.sorting_1 { - background-color: #ffd5d5; -} - -tr.even.gradeX td.sorting_2 { - background-color: #ffe2e2; -} - -tr.even.gradeX td.sorting_3 { - background-color: #ffe2e2; -} - -tr.odd.gradeU td.sorting_1 { - background-color: #c4c4c4; -} - -tr.odd.gradeU td.sorting_2 { - background-color: #d1d1d1; -} - -tr.odd.gradeU td.sorting_3 { - background-color: #d1d1d1; -} - -tr.even.gradeU td.sorting_1 { - background-color: #d5d5d5; -} - -tr.even.gradeU td.sorting_2 { - background-color: #e2e2e2; -} - -tr.even.gradeU td.sorting_3 { - background-color: #e2e2e2; -} - - -/* - * Row highlighting example - */ -.ex_highlight #example tbody tr.even:hover, #example tbody tr.even td.highlighted { - background-color: #ECFFB3; -} - -.ex_highlight #example tbody tr.odd:hover, #example tbody tr.odd td.highlighted { - background-color: #E6FF99; -} - -.ex_highlight_row #example tr.even:hover { - background-color: #ECFFB3; -} - -.ex_highlight_row #example tr.even:hover td.sorting_1 { - background-color: #DDFF75; -} - -.ex_highlight_row #example tr.even:hover td.sorting_2 { - background-color: #E7FF9E; -} - -.ex_highlight_row #example tr.even:hover td.sorting_3 { - background-color: #E2FF89; -} - -.ex_highlight_row #example tr.odd:hover { - background-color: #E6FF99; -} - -.ex_highlight_row #example tr.odd:hover td.sorting_1 { - background-color: #D6FF5C; -} - -.ex_highlight_row #example tr.odd:hover td.sorting_2 { - background-color: #E0FF84; -} - -.ex_highlight_row #example tr.odd:hover td.sorting_3 { - background-color: #DBFF70; -} - - -/* - * KeyTable - */ -table.KeyTable td { - border: 3px solid transparent; -} - -table.KeyTable td.focus { - border: 3px solid #3366FF; -} - -table.display tr.gradeA { - background-color: #eeffee; -} - -table.display tr.gradeC { - background-color: #ddddff; -} - -table.display tr.gradeX { - background-color: #ffdddd; -} - -table.display tr.gradeU { - background-color: #ddd; -} - -div.box { - height: 100px; - padding: 10px; - overflow: auto; - border: 1px solid #8080FF; - background-color: #E5E5FF; -} diff --git a/static/img/Sorting icons.psd b/static/img/Sorting icons.psd deleted file mode 100644 index 53b2e06..0000000 Binary files a/static/img/Sorting icons.psd and /dev/null differ diff --git a/static/img/back_disabled.png b/static/img/back_disabled.png deleted file mode 100644 index 881de79..0000000 Binary files a/static/img/back_disabled.png and /dev/null differ diff --git a/static/img/back_enabled.png b/static/img/back_enabled.png deleted file mode 100644 index c608682..0000000 Binary files a/static/img/back_enabled.png and /dev/null differ diff --git a/static/img/back_enabled_hover.png b/static/img/back_enabled_hover.png deleted file mode 100644 index d300f10..0000000 Binary files a/static/img/back_enabled_hover.png and /dev/null differ diff --git a/static/img/chosen-sprite.png b/static/img/chosen-sprite.png deleted file mode 100644 index 231fe90..0000000 Binary files a/static/img/chosen-sprite.png and /dev/null differ diff --git a/static/img/forward_disabled.png b/static/img/forward_disabled.png deleted file mode 100644 index 6a6ded7..0000000 Binary files a/static/img/forward_disabled.png and /dev/null differ diff --git a/static/img/forward_enabled.png b/static/img/forward_enabled.png deleted file mode 100644 index a4e6b53..0000000 Binary files a/static/img/forward_enabled.png and /dev/null differ diff --git a/static/img/forward_enabled_hover.png b/static/img/forward_enabled_hover.png deleted file mode 100644 index fc46c5e..0000000 Binary files a/static/img/forward_enabled_hover.png and /dev/null differ diff --git a/static/img/loading.gif b/static/img/loading.gif deleted file mode 100644 index c9a1eab..0000000 Binary files a/static/img/loading.gif and /dev/null differ diff --git a/static/img/sort_asc.png b/static/img/sort_asc.png deleted file mode 100644 index a88d797..0000000 Binary files a/static/img/sort_asc.png and /dev/null differ diff --git a/static/img/sort_asc_disabled.png b/static/img/sort_asc_disabled.png deleted file mode 100644 index 4e144cf..0000000 Binary files a/static/img/sort_asc_disabled.png and /dev/null differ diff --git a/static/img/sort_both.png b/static/img/sort_both.png deleted file mode 100644 index 1867040..0000000 Binary files a/static/img/sort_both.png and /dev/null differ diff --git a/static/img/sort_desc.png b/static/img/sort_desc.png deleted file mode 100644 index def071e..0000000 Binary files a/static/img/sort_desc.png and /dev/null differ diff --git a/static/img/sort_desc_disabled.png b/static/img/sort_desc_disabled.png deleted file mode 100644 index 7824973..0000000 Binary files a/static/img/sort_desc_disabled.png and /dev/null differ diff --git a/static/js/chosen.jquery.js b/static/js/chosen.jquery.js deleted file mode 100644 index 6d63089..0000000 --- a/static/js/chosen.jquery.js +++ /dev/null @@ -1,946 +0,0 @@ -// Chosen, a Select Box Enhancer for jQuery and Protoype -// by Patrick Filler for Harvest, http://getharvest.com -// -// Version 0.9.7 -// Full source at https://github.com/harvesthq/chosen -// Copyright (c) 2011 Harvest http://getharvest.com - -// MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md -// This file is generated by `cake build`, do not edit it by hand. -(function() { - var SelectParser; - - SelectParser = (function() { - - function SelectParser() { - this.options_index = 0; - this.parsed = []; - } - - SelectParser.prototype.add_node = function(child) { - if (child.nodeName === "OPTGROUP") { - return this.add_group(child); - } else { - return this.add_option(child); - } - }; - - SelectParser.prototype.add_group = function(group) { - var group_position, option, _i, _len, _ref, _results; - group_position = this.parsed.length; - this.parsed.push({ - array_index: group_position, - group: true, - label: group.label, - children: 0, - disabled: group.disabled - }); - _ref = group.childNodes; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - option = _ref[_i]; - _results.push(this.add_option(option, group_position, group.disabled)); - } - return _results; - }; - - SelectParser.prototype.add_option = function(option, group_position, group_disabled) { - if (option.nodeName === "OPTION") { - if (option.text !== "") { - if (group_position != null) this.parsed[group_position].children += 1; - this.parsed.push({ - array_index: this.parsed.length, - options_index: this.options_index, - value: option.value, - text: option.text, - html: option.innerHTML, - selected: option.selected, - disabled: group_disabled === true ? group_disabled : option.disabled, - group_array_index: group_position, - classes: option.className, - style: option.style.cssText - }); - } else { - this.parsed.push({ - array_index: this.parsed.length, - options_index: this.options_index, - empty: true - }); - } - return this.options_index += 1; - } - }; - - return SelectParser; - - })(); - - SelectParser.select_to_array = function(select) { - var child, parser, _i, _len, _ref; - parser = new SelectParser(); - _ref = select.childNodes; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - child = _ref[_i]; - parser.add_node(child); - } - return parser.parsed; - }; - - this.SelectParser = SelectParser; - -}).call(this); - -/* -Chosen source: generate output using 'cake build' -Copyright (c) 2011 by Harvest -*/ - -(function() { - var AbstractChosen, root; - - root = this; - - AbstractChosen = (function() { - - function AbstractChosen(form_field, options) { - this.form_field = form_field; - this.options = options != null ? options : {}; - this.set_default_values(); - this.is_multiple = this.form_field.multiple; - this.default_text_default = this.is_multiple ? "Select Some Options" : "Select an Option"; - this.setup(); - this.set_up_html(); - this.register_observers(); - this.finish_setup(); - } - - AbstractChosen.prototype.set_default_values = function() { - var _this = this; - this.click_test_action = function(evt) { - return _this.test_active_click(evt); - }; - this.activate_action = function(evt) { - return _this.activate_field(evt); - }; - this.active_field = false; - this.mouse_on_container = false; - this.results_showing = false; - this.result_highlighted = null; - this.result_single_selected = null; - this.allow_single_deselect = (this.options.allow_single_deselect != null) && (this.form_field.options[0] != null) && this.form_field.options[0].text === "" ? this.options.allow_single_deselect : false; - this.disable_search_threshold = this.options.disable_search_threshold || 0; - this.choices = 0; - return this.results_none_found = this.options.no_results_text || "No results match"; - }; - - AbstractChosen.prototype.mouse_enter = function() { - return this.mouse_on_container = true; - }; - - AbstractChosen.prototype.mouse_leave = function() { - return this.mouse_on_container = false; - }; - - AbstractChosen.prototype.input_focus = function(evt) { - var _this = this; - if (!this.active_field) { - return setTimeout((function() { - return _this.container_mousedown(); - }), 50); - } - }; - - AbstractChosen.prototype.input_blur = function(evt) { - var _this = this; - if (!this.mouse_on_container) { - this.active_field = false; - return setTimeout((function() { - return _this.blur_test(); - }), 100); - } - }; - - AbstractChosen.prototype.result_add_option = function(option) { - var classes, style; - if (!option.disabled) { - option.dom_id = this.container_id + "_o_" + option.array_index; - classes = option.selected && this.is_multiple ? [] : ["active-result"]; - if (option.selected) classes.push("result-selected"); - if (option.group_array_index != null) classes.push("group-option"); - if (option.classes !== "") classes.push(option.classes); - style = option.style.cssText !== "" ? " style=\"" + option.style + "\"" : ""; - return '
  • ' + option.html + '
  • '; - } else { - return ""; - } - }; - - AbstractChosen.prototype.results_update_field = function() { - this.result_clear_highlight(); - this.result_single_selected = null; - return this.results_build(); - }; - - AbstractChosen.prototype.results_toggle = function() { - if (this.results_showing) { - return this.results_hide(); - } else { - return this.results_show(); - } - }; - - AbstractChosen.prototype.results_search = function(evt) { - if (this.results_showing) { - return this.winnow_results(); - } else { - return this.results_show(); - } - }; - - AbstractChosen.prototype.keyup_checker = function(evt) { - var stroke, _ref; - stroke = (_ref = evt.which) != null ? _ref : evt.keyCode; - this.search_field_scale(); - switch (stroke) { - case 8: - if (this.is_multiple && this.backstroke_length < 1 && this.choices > 0) { - return this.keydown_backstroke(); - } else if (!this.pending_backstroke) { - this.result_clear_highlight(); - return this.results_search(); - } - break; - case 13: - evt.preventDefault(); - if (this.results_showing) return this.result_select(evt); - break; - case 27: - if (this.results_showing) this.results_hide(); - return true; - case 9: - case 38: - case 40: - case 16: - case 91: - case 17: - break; - default: - return this.results_search(); - } - }; - - AbstractChosen.prototype.generate_field_id = function() { - var new_id; - new_id = this.generate_random_id(); - this.form_field.id = new_id; - return new_id; - }; - - AbstractChosen.prototype.generate_random_char = function() { - var chars, newchar, rand; - chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ"; - rand = Math.floor(Math.random() * chars.length); - return newchar = chars.substring(rand, rand + 1); - }; - - return AbstractChosen; - - })(); - - root.AbstractChosen = AbstractChosen; - -}).call(this); - -/* -Chosen source: generate output using 'cake build' -Copyright (c) 2011 by Harvest -*/ - -(function() { - var $, Chosen, get_side_border_padding, root, - __hasProp = Object.prototype.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }; - - root = this; - - $ = (typeof window.django != 'undefined') ? django.jQuery : jQuery; - - $.fn.extend({ - chosen: function(options) { - if ($.browser.msie && ($.browser.version === "6.0" || $.browser.version === "7.0")) { - return this; - } - return $(this).each(function(input_field) { - if (!($(this)).hasClass("chzn-done")) return new Chosen(this, options); - }); - } - }); - - Chosen = (function(_super) { - - __extends(Chosen, _super); - - function Chosen() { - Chosen.__super__.constructor.apply(this, arguments); - } - - Chosen.prototype.setup = function() { - this.form_field_jq = $(this.form_field); - return this.is_rtl = this.form_field_jq.hasClass("chzn-rtl"); - }; - - Chosen.prototype.finish_setup = function() { - return this.form_field_jq.addClass("chzn-done"); - }; - - Chosen.prototype.set_up_html = function() { - var container_div, dd_top, dd_width, sf_width; - this.container_id = this.form_field.id.length ? this.form_field.id.replace(/(:|\.)/g, '_') : this.generate_field_id(); - this.container_id += "_chzn"; - this.f_width = this.form_field_jq.outerWidth(); - this.default_text = this.form_field_jq.data('placeholder') ? this.form_field_jq.data('placeholder') : this.default_text_default; - container_div = $("
    ", { - id: this.container_id, - "class": "chzn-container" + (this.is_rtl ? ' chzn-rtl' : ''), - style: 'width: ' + this.f_width + 'px;' - }); - if (this.is_multiple) { - container_div.html('
      '); - } else { - container_div.html('' + this.default_text + '
        '); - } - this.form_field_jq.hide().after(container_div); - this.container = $('#' + this.container_id); - this.container.addClass("chzn-container-" + (this.is_multiple ? "multi" : "single")); - this.dropdown = this.container.find('div.chzn-drop').first(); - dd_top = this.container.height(); - dd_width = this.f_width - get_side_border_padding(this.dropdown); - this.dropdown.css({ - "width": dd_width + "px", - "top": dd_top + "px" - }); - this.search_field = this.container.find('input').first(); - this.search_results = this.container.find('ul.chzn-results').first(); - this.search_field_scale(); - this.search_no_results = this.container.find('li.no-results').first(); - if (this.is_multiple) { - this.search_choices = this.container.find('ul.chzn-choices').first(); - this.search_container = this.container.find('li.search-field').first(); - } else { - this.search_container = this.container.find('div.chzn-search').first(); - this.selected_item = this.container.find('.chzn-single').first(); - sf_width = dd_width - get_side_border_padding(this.search_container) - get_side_border_padding(this.search_field); - this.search_field.css({ - "width": sf_width + "px" - }); - } - this.results_build(); - this.set_tab_index(); - return this.form_field_jq.trigger("liszt:ready", { - chosen: this - }); - }; - - Chosen.prototype.register_observers = function() { - var _this = this; - this.container.mousedown(function(evt) { - return _this.container_mousedown(evt); - }); - this.container.mouseup(function(evt) { - return _this.container_mouseup(evt); - }); - this.container.mouseenter(function(evt) { - return _this.mouse_enter(evt); - }); - this.container.mouseleave(function(evt) { - return _this.mouse_leave(evt); - }); - this.search_results.mouseup(function(evt) { - return _this.search_results_mouseup(evt); - }); - this.search_results.mouseover(function(evt) { - return _this.search_results_mouseover(evt); - }); - this.search_results.mouseout(function(evt) { - return _this.search_results_mouseout(evt); - }); - this.form_field_jq.bind("liszt:updated", function(evt) { - return _this.results_update_field(evt); - }); - this.search_field.blur(function(evt) { - return _this.input_blur(evt); - }); - this.search_field.keyup(function(evt) { - return _this.keyup_checker(evt); - }); - this.search_field.keydown(function(evt) { - return _this.keydown_checker(evt); - }); - if (this.is_multiple) { - this.search_choices.click(function(evt) { - return _this.choices_click(evt); - }); - return this.search_field.focus(function(evt) { - return _this.input_focus(evt); - }); - } else { - return this.container.click(function(evt) { - return evt.preventDefault(); - }); - } - }; - - Chosen.prototype.search_field_disabled = function() { - this.is_disabled = this.form_field_jq[0].disabled; - if (this.is_disabled) { - this.container.addClass('chzn-disabled'); - this.search_field[0].disabled = true; - if (!this.is_multiple) { - this.selected_item.unbind("focus", this.activate_action); - } - return this.close_field(); - } else { - this.container.removeClass('chzn-disabled'); - this.search_field[0].disabled = false; - if (!this.is_multiple) { - return this.selected_item.bind("focus", this.activate_action); - } - } - }; - - Chosen.prototype.container_mousedown = function(evt) { - var target_closelink; - if (!this.is_disabled) { - target_closelink = evt != null ? ($(evt.target)).hasClass("search-choice-close") : false; - if (evt && evt.type === "mousedown") evt.stopPropagation(); - if (!this.pending_destroy_click && !target_closelink) { - if (!this.active_field) { - if (this.is_multiple) this.search_field.val(""); - $(document).click(this.click_test_action); - this.results_show(); - } else if (!this.is_multiple && evt && (($(evt.target)[0] === this.selected_item[0]) || $(evt.target).parents("a.chzn-single").length)) { - evt.preventDefault(); - this.results_toggle(); - } - return this.activate_field(); - } else { - return this.pending_destroy_click = false; - } - } - }; - - Chosen.prototype.container_mouseup = function(evt) { - if (evt.target.nodeName === "ABBR") return this.results_reset(evt); - }; - - Chosen.prototype.blur_test = function(evt) { - if (!this.active_field && this.container.hasClass("chzn-container-active")) { - return this.close_field(); - } - }; - - Chosen.prototype.close_field = function() { - $(document).unbind("click", this.click_test_action); - if (!this.is_multiple) { - this.selected_item.attr("tabindex", this.search_field.attr("tabindex")); - this.search_field.attr("tabindex", -1); - } - this.active_field = false; - this.results_hide(); - this.container.removeClass("chzn-container-active"); - this.winnow_results_clear(); - this.clear_backstroke(); - this.show_search_field_default(); - return this.search_field_scale(); - }; - - Chosen.prototype.activate_field = function() { - if (!this.is_multiple && !this.active_field) { - this.search_field.attr("tabindex", this.selected_item.attr("tabindex")); - this.selected_item.attr("tabindex", -1); - } - this.container.addClass("chzn-container-active"); - this.active_field = true; - this.search_field.val(this.search_field.val()); - return this.search_field.focus(); - }; - - Chosen.prototype.test_active_click = function(evt) { - if ($(evt.target).parents('#' + this.container_id).length) { - return this.active_field = true; - } else { - return this.close_field(); - } - }; - - Chosen.prototype.results_build = function() { - var content, data, _i, _len, _ref; - this.parsing = true; - this.results_data = root.SelectParser.select_to_array(this.form_field); - if (this.is_multiple && this.choices > 0) { - this.search_choices.find("li.search-choice").remove(); - this.choices = 0; - } else if (!this.is_multiple) { - this.selected_item.find("span").text(this.default_text); - if (this.form_field.options.length <= this.disable_search_threshold) { - this.container.addClass("chzn-container-single-nosearch"); - } else { - this.container.removeClass("chzn-container-single-nosearch"); - } - } - content = ''; - _ref = this.results_data; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - data = _ref[_i]; - if (data.group) { - content += this.result_add_group(data); - } else if (!data.empty) { - content += this.result_add_option(data); - if (data.selected && this.is_multiple) { - this.choice_build(data); - } else if (data.selected && !this.is_multiple) { - this.selected_item.find("span").text(data.text); - if (this.allow_single_deselect) this.single_deselect_control_build(); - } - } - } - this.search_field_disabled(); - this.show_search_field_default(); - this.search_field_scale(); - this.search_results.html(content); - return this.parsing = false; - }; - - Chosen.prototype.result_add_group = function(group) { - if (!group.disabled) { - group.dom_id = this.container_id + "_g_" + group.array_index; - return '
      • ' + $("
        ").text(group.label).html() + '
      • '; - } else { - return ""; - } - }; - - Chosen.prototype.result_do_highlight = function(el) { - var high_bottom, high_top, maxHeight, visible_bottom, visible_top; - if (el.length) { - this.result_clear_highlight(); - this.result_highlight = el; - this.result_highlight.addClass("highlighted"); - maxHeight = parseInt(this.search_results.css("maxHeight"), 10); - visible_top = this.search_results.scrollTop(); - visible_bottom = maxHeight + visible_top; - high_top = this.result_highlight.position().top + this.search_results.scrollTop(); - high_bottom = high_top + this.result_highlight.outerHeight(); - if (high_bottom >= visible_bottom) { - return this.search_results.scrollTop((high_bottom - maxHeight) > 0 ? high_bottom - maxHeight : 0); - } else if (high_top < visible_top) { - return this.search_results.scrollTop(high_top); - } - } - }; - - Chosen.prototype.result_clear_highlight = function() { - if (this.result_highlight) this.result_highlight.removeClass("highlighted"); - return this.result_highlight = null; - }; - - Chosen.prototype.results_show = function() { - var dd_top; - if (!this.is_multiple) { - this.selected_item.addClass("chzn-single-with-drop"); - if (this.result_single_selected) { - this.result_do_highlight(this.result_single_selected); - } - } - dd_top = this.is_multiple ? this.container.height() : this.container.height() - 1; - this.dropdown.css({ - "top": dd_top + "px", - "left": 0 - }); - this.results_showing = true; - this.search_field.focus(); - this.search_field.val(this.search_field.val()); - return this.winnow_results(); - }; - - Chosen.prototype.results_hide = function() { - if (!this.is_multiple) { - this.selected_item.removeClass("chzn-single-with-drop"); - } - this.result_clear_highlight(); - this.dropdown.css({ - "left": "-9000px" - }); - return this.results_showing = false; - }; - - Chosen.prototype.set_tab_index = function(el) { - var ti; - if (this.form_field_jq.attr("tabindex")) { - ti = this.form_field_jq.attr("tabindex"); - this.form_field_jq.attr("tabindex", -1); - if (this.is_multiple) { - return this.search_field.attr("tabindex", ti); - } else { - this.selected_item.attr("tabindex", ti); - return this.search_field.attr("tabindex", -1); - } - } - }; - - Chosen.prototype.show_search_field_default = function() { - if (this.is_multiple && this.choices < 1 && !this.active_field) { - this.search_field.val(this.default_text); - return this.search_field.addClass("default"); - } else { - this.search_field.val(""); - return this.search_field.removeClass("default"); - } - }; - - Chosen.prototype.search_results_mouseup = function(evt) { - var target; - target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); - if (target.length) { - this.result_highlight = target; - return this.result_select(evt); - } - }; - - Chosen.prototype.search_results_mouseover = function(evt) { - var target; - target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); - if (target) return this.result_do_highlight(target); - }; - - Chosen.prototype.search_results_mouseout = function(evt) { - if ($(evt.target).hasClass("active-result" || $(evt.target).parents('.active-result').first())) { - return this.result_clear_highlight(); - } - }; - - Chosen.prototype.choices_click = function(evt) { - evt.preventDefault(); - if (this.active_field && !($(evt.target).hasClass("search-choice" || $(evt.target).parents('.search-choice').first)) && !this.results_showing) { - return this.results_show(); - } - }; - - Chosen.prototype.choice_build = function(item) { - var choice_id, link, - _this = this; - choice_id = this.container_id + "_c_" + item.array_index; - this.choices += 1; - this.search_container.before('
      • ' + item.html + '
      • '); - link = $('#' + choice_id).find("a").first(); - return link.click(function(evt) { - return _this.choice_destroy_link_click(evt); - }); - }; - - Chosen.prototype.choice_destroy_link_click = function(evt) { - evt.preventDefault(); - if (!this.is_disabled) { - this.pending_destroy_click = true; - return this.choice_destroy($(evt.target)); - } else { - return evt.stopPropagation; - } - }; - - Chosen.prototype.choice_destroy = function(link) { - this.choices -= 1; - this.show_search_field_default(); - if (this.is_multiple && this.choices > 0 && this.search_field.val().length < 1) { - this.results_hide(); - } - this.result_deselect(link.attr("rel")); - return link.parents('li').first().remove(); - }; - - Chosen.prototype.results_reset = function(evt) { - this.form_field.options[0].selected = true; - this.selected_item.find("span").text(this.default_text); - this.show_search_field_default(); - $(evt.target).remove(); - this.form_field_jq.trigger("change"); - if (this.active_field) return this.results_hide(); - }; - - Chosen.prototype.result_select = function(evt) { - var high, high_id, item, position; - if (this.result_highlight) { - high = this.result_highlight; - high_id = high.attr("id"); - this.result_clear_highlight(); - if (this.is_multiple) { - this.result_deactivate(high); - } else { - this.search_results.find(".result-selected").removeClass("result-selected"); - this.result_single_selected = high; - } - high.addClass("result-selected"); - position = high_id.substr(high_id.lastIndexOf("_") + 1); - item = this.results_data[position]; - item.selected = true; - this.form_field.options[item.options_index].selected = true; - if (this.is_multiple) { - this.choice_build(item); - } else { - this.selected_item.find("span").first().text(item.text); - if (this.allow_single_deselect) this.single_deselect_control_build(); - } - if (!(evt.metaKey && this.is_multiple)) this.results_hide(); - this.search_field.val(""); - this.form_field_jq.trigger("change"); - return this.search_field_scale(); - } - }; - - Chosen.prototype.result_activate = function(el) { - return el.addClass("active-result"); - }; - - Chosen.prototype.result_deactivate = function(el) { - return el.removeClass("active-result"); - }; - - Chosen.prototype.result_deselect = function(pos) { - var result, result_data; - result_data = this.results_data[pos]; - result_data.selected = false; - this.form_field.options[result_data.options_index].selected = false; - result = $("#" + this.container_id + "_o_" + pos); - result.removeClass("result-selected").addClass("active-result").show(); - this.result_clear_highlight(); - this.winnow_results(); - this.form_field_jq.trigger("change"); - return this.search_field_scale(); - }; - - Chosen.prototype.single_deselect_control_build = function() { - if (this.allow_single_deselect && this.selected_item.find("abbr").length < 1) { - return this.selected_item.find("span").first().after(""); - } - }; - - Chosen.prototype.winnow_results = function() { - var found, option, part, parts, regex, result, result_id, results, searchText, startpos, text, zregex, _i, _j, _len, _len2, _ref; - this.no_results_clear(); - results = 0; - searchText = this.search_field.val() === this.default_text ? "" : $('
        ').text($.trim(this.search_field.val())).html(); - regex = new RegExp('^' + searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i'); - zregex = new RegExp(searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i'); - _ref = this.results_data; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - option = _ref[_i]; - if (!option.disabled && !option.empty) { - if (option.group) { - $('#' + option.dom_id).css('display', 'none'); - } else if (!(this.is_multiple && option.selected)) { - found = false; - result_id = option.dom_id; - result = $("#" + result_id); - if (regex.test(option.html)) { - found = true; - results += 1; - } else if (option.html.indexOf(" ") >= 0 || option.html.indexOf("[") === 0) { - parts = option.html.replace(/\[|\]/g, "").split(" "); - if (parts.length) { - for (_j = 0, _len2 = parts.length; _j < _len2; _j++) { - part = parts[_j]; - if (regex.test(part)) { - found = true; - results += 1; - } - } - } - } - if (found) { - if (searchText.length) { - startpos = option.html.search(zregex); - text = option.html.substr(0, startpos + searchText.length) + '' + option.html.substr(startpos + searchText.length); - text = text.substr(0, startpos) + '' + text.substr(startpos); - } else { - text = option.html; - } - result.html(text); - this.result_activate(result); - if (option.group_array_index != null) { - $("#" + this.results_data[option.group_array_index].dom_id).css('display', 'list-item'); - } - } else { - if (this.result_highlight && result_id === this.result_highlight.attr('id')) { - this.result_clear_highlight(); - } - this.result_deactivate(result); - } - } - } - } - if (results < 1 && searchText.length) { - return this.no_results(searchText); - } else { - return this.winnow_results_set_highlight(); - } - }; - - Chosen.prototype.winnow_results_clear = function() { - var li, lis, _i, _len, _results; - this.search_field.val(""); - lis = this.search_results.find("li"); - _results = []; - for (_i = 0, _len = lis.length; _i < _len; _i++) { - li = lis[_i]; - li = $(li); - if (li.hasClass("group-result")) { - _results.push(li.css('display', 'auto')); - } else if (!this.is_multiple || !li.hasClass("result-selected")) { - _results.push(this.result_activate(li)); - } else { - _results.push(void 0); - } - } - return _results; - }; - - Chosen.prototype.winnow_results_set_highlight = function() { - var do_high, selected_results; - if (!this.result_highlight) { - selected_results = !this.is_multiple ? this.search_results.find(".result-selected.active-result") : []; - do_high = selected_results.length ? selected_results.first() : this.search_results.find(".active-result").first(); - if (do_high != null) return this.result_do_highlight(do_high); - } - }; - - Chosen.prototype.no_results = function(terms) { - var no_results_html; - no_results_html = $('
      • ' + this.results_none_found + ' ""
      • '); - no_results_html.find("span").first().html(terms); - return this.search_results.append(no_results_html); - }; - - Chosen.prototype.no_results_clear = function() { - return this.search_results.find(".no-results").remove(); - }; - - Chosen.prototype.keydown_arrow = function() { - var first_active, next_sib; - if (!this.result_highlight) { - first_active = this.search_results.find("li.active-result").first(); - if (first_active) this.result_do_highlight($(first_active)); - } else if (this.results_showing) { - next_sib = this.result_highlight.nextAll("li.active-result").first(); - if (next_sib) this.result_do_highlight(next_sib); - } - if (!this.results_showing) return this.results_show(); - }; - - Chosen.prototype.keyup_arrow = function() { - var prev_sibs; - if (!this.results_showing && !this.is_multiple) { - return this.results_show(); - } else if (this.result_highlight) { - prev_sibs = this.result_highlight.prevAll("li.active-result"); - if (prev_sibs.length) { - return this.result_do_highlight(prev_sibs.first()); - } else { - if (this.choices > 0) this.results_hide(); - return this.result_clear_highlight(); - } - } - }; - - Chosen.prototype.keydown_backstroke = function() { - if (this.pending_backstroke) { - this.choice_destroy(this.pending_backstroke.find("a").first()); - return this.clear_backstroke(); - } else { - this.pending_backstroke = this.search_container.siblings("li.search-choice").last(); - return this.pending_backstroke.addClass("search-choice-focus"); - } - }; - - Chosen.prototype.clear_backstroke = function() { - if (this.pending_backstroke) { - this.pending_backstroke.removeClass("search-choice-focus"); - } - return this.pending_backstroke = null; - }; - - Chosen.prototype.keydown_checker = function(evt) { - var stroke, _ref; - stroke = (_ref = evt.which) != null ? _ref : evt.keyCode; - this.search_field_scale(); - if (stroke !== 8 && this.pending_backstroke) this.clear_backstroke(); - switch (stroke) { - case 8: - this.backstroke_length = this.search_field.val().length; - break; - case 9: - if (this.results_showing && !this.is_multiple) this.result_select(evt); - this.mouse_on_container = false; - break; - case 13: - evt.preventDefault(); - break; - case 38: - evt.preventDefault(); - this.keyup_arrow(); - break; - case 40: - this.keydown_arrow(); - break; - } - }; - - Chosen.prototype.search_field_scale = function() { - var dd_top, div, h, style, style_block, styles, w, _i, _len; - if (this.is_multiple) { - h = 0; - w = 0; - style_block = "position:absolute; left: -1000px; top: -1000px; display:none;"; - styles = ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height', 'text-transform', 'letter-spacing']; - for (_i = 0, _len = styles.length; _i < _len; _i++) { - style = styles[_i]; - style_block += style + ":" + this.search_field.css(style) + ";"; - } - div = $('
        ', { - 'style': style_block - }); - div.text(this.search_field.val()); - $('body').append(div); - w = div.width() + 25; - div.remove(); - if (w > this.f_width - 10) w = this.f_width - 10; - this.search_field.css({ - 'width': w + 'px' - }); - dd_top = this.container.height(); - return this.dropdown.css({ - "top": dd_top + "px" - }); - } - }; - - Chosen.prototype.generate_random_id = function() { - var string; - string = "sel" + this.generate_random_char() + this.generate_random_char() + this.generate_random_char(); - while ($("#" + string).length > 0) { - string += this.generate_random_char(); - } - return string; - }; - - return Chosen; - - })(AbstractChosen); - - get_side_border_padding = function(elmt) { - var side_border_padding; - return side_border_padding = elmt.outerWidth() - elmt.width(); - }; - - root.get_side_border_padding = get_side_border_padding; - -}).call(this); \ No newline at end of file diff --git a/static/js/chosen.jquery.min.js b/static/js/chosen.jquery.min.js deleted file mode 100644 index 5548f2d..0000000 --- a/static/js/chosen.jquery.min.js +++ /dev/null @@ -1,10 +0,0 @@ -// Chosen, a Select Box Enhancer for jQuery and Protoype -// by Patrick Filler for Harvest, http://getharvest.com -// -// Version 0.9.7 -// Full source at https://github.com/harvesthq/chosen -// Copyright (c) 2011 Harvest http://getharvest.com - -// MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md -// This file is generated by `cake build`, do not edit it by hand. -((function(){var a;a=function(){function a(){this.options_index=0,this.parsed=[]}return a.prototype.add_node=function(a){return a.nodeName==="OPTGROUP"?this.add_group(a):this.add_option(a)},a.prototype.add_group=function(a){var b,c,d,e,f,g;b=this.parsed.length,this.parsed.push({array_index:b,group:!0,label:a.label,children:0,disabled:a.disabled}),f=a.childNodes,g=[];for(d=0,e=f.length;d"+a.html+"")},a.prototype.results_update_field=function(){return this.result_clear_highlight(),this.result_single_selected=null,this.results_build()},a.prototype.results_toggle=function(){return this.results_showing?this.results_hide():this.results_show()},a.prototype.results_search=function(a){return this.results_showing?this.winnow_results():this.results_show()},a.prototype.keyup_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale();switch(b){case 8:if(this.is_multiple&&this.backstroke_length<1&&this.choices>0)return this.keydown_backstroke();if(!this.pending_backstroke)return this.result_clear_highlight(),this.results_search();break;case 13:a.preventDefault();if(this.results_showing)return this.result_select(a);break;case 27:return this.results_showing&&this.results_hide(),!0;case 9:case 38:case 40:case 16:case 91:case 17:break;default:return this.results_search()}},a.prototype.generate_field_id=function(){var a;return a=this.generate_random_id(),this.form_field.id=a,a},a.prototype.generate_random_char=function(){var a,b,c;return a="0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ",c=Math.floor(Math.random()*a.length),b=a.substring(c,c+1)},a}(),b.AbstractChosen=a}.call(this),function(){var a,b,c,d,e=Object.prototype.hasOwnProperty,f=function(a,b){function d(){this.constructor=a}for(var c in b)e.call(b,c)&&(a[c]=b[c]);return d.prototype=b.prototype,a.prototype=new d,a.__super__=b.prototype,a};d=this,a=(window.django?django.jQuery:jQuery),a.fn.extend({chosen:function(c){return!a.browser.msie||a.browser.version!=="6.0"&&a.browser.version!=="7.0"?a(this).each(function(d){if(!a(this).hasClass("chzn-done"))return new b(this,c)}):this}}),b=function(b){function e(){e.__super__.constructor.apply(this,arguments)}return f(e,b),e.prototype.setup=function(){return this.form_field_jq=a(this.form_field),this.is_rtl=this.form_field_jq.hasClass("chzn-rtl")},e.prototype.finish_setup=function(){return this.form_field_jq.addClass("chzn-done")},e.prototype.set_up_html=function(){var b,d,e,f;return this.container_id=this.form_field.id.length?this.form_field.id.replace(/(:|\.)/g,"_"):this.generate_field_id(),this.container_id+="_chzn",this.f_width=this.form_field_jq.outerWidth(),this.default_text=this.form_field_jq.data("placeholder")?this.form_field_jq.data("placeholder"):this.default_text_default,b=a("
        ",{id:this.container_id,"class":"chzn-container"+(this.is_rtl?" chzn-rtl":""),style:"width: "+this.f_width+"px;"}),this.is_multiple?b.html('
          '):b.html(''+this.default_text+'
            '),this.form_field_jq.hide().after(b),this.container=a("#"+this.container_id),this.container.addClass("chzn-container-"+(this.is_multiple?"multi":"single")),this.dropdown=this.container.find("div.chzn-drop").first(),d=this.container.height(),e=this.f_width-c(this.dropdown),this.dropdown.css({width:e+"px",top:d+"px"}),this.search_field=this.container.find("input").first(),this.search_results=this.container.find("ul.chzn-results").first(),this.search_field_scale(),this.search_no_results=this.container.find("li.no-results").first(),this.is_multiple?(this.search_choices=this.container.find("ul.chzn-choices").first(),this.search_container=this.container.find("li.search-field").first()):(this.search_container=this.container.find("div.chzn-search").first(),this.selected_item=this.container.find(".chzn-single").first(),f=e-c(this.search_container)-c(this.search_field),this.search_field.css({width:f+"px"})),this.results_build(),this.set_tab_index(),this.form_field_jq.trigger("liszt:ready",{chosen:this})},e.prototype.register_observers=function(){var a=this;return this.container.mousedown(function(b){return a.container_mousedown(b)}),this.container.mouseup(function(b){return a.container_mouseup(b)}),this.container.mouseenter(function(b){return a.mouse_enter(b)}),this.container.mouseleave(function(b){return a.mouse_leave(b)}),this.search_results.mouseup(function(b){return a.search_results_mouseup(b)}),this.search_results.mouseover(function(b){return a.search_results_mouseover(b)}),this.search_results.mouseout(function(b){return a.search_results_mouseout(b)}),this.form_field_jq.bind("liszt:updated",function(b){return a.results_update_field(b)}),this.search_field.blur(function(b){return a.input_blur(b)}),this.search_field.keyup(function(b){return a.keyup_checker(b)}),this.search_field.keydown(function(b){return a.keydown_checker(b)}),this.is_multiple?(this.search_choices.click(function(b){return a.choices_click(b)}),this.search_field.focus(function(b){return a.input_focus(b)})):this.container.click(function(a){return a.preventDefault()})},e.prototype.search_field_disabled=function(){this.is_disabled=this.form_field_jq[0].disabled;if(this.is_disabled)return this.container.addClass("chzn-disabled"),this.search_field[0].disabled=!0,this.is_multiple||this.selected_item.unbind("focus",this.activate_action),this.close_field();this.container.removeClass("chzn-disabled"),this.search_field[0].disabled=!1;if(!this.is_multiple)return this.selected_item.bind("focus",this.activate_action)},e.prototype.container_mousedown=function(b){var c;if(!this.is_disabled)return c=b!=null?a(b.target).hasClass("search-choice-close"):!1,b&&b.type==="mousedown"&&b.stopPropagation(),!this.pending_destroy_click&&!c?(this.active_field?!this.is_multiple&&b&&(a(b.target)[0]===this.selected_item[0]||a(b.target).parents("a.chzn-single").length)&&(b.preventDefault(),this.results_toggle()):(this.is_multiple&&this.search_field.val(""),a(document).click(this.click_test_action),this.results_show()),this.activate_field()):this.pending_destroy_click=!1},e.prototype.container_mouseup=function(a){if(a.target.nodeName==="ABBR")return this.results_reset(a)},e.prototype.blur_test=function(a){if(!this.active_field&&this.container.hasClass("chzn-container-active"))return this.close_field()},e.prototype.close_field=function(){return a(document).unbind("click",this.click_test_action),this.is_multiple||(this.selected_item.attr("tabindex",this.search_field.attr("tabindex")),this.search_field.attr("tabindex",-1)),this.active_field=!1,this.results_hide(),this.container.removeClass("chzn-container-active"),this.winnow_results_clear(),this.clear_backstroke(),this.show_search_field_default(),this.search_field_scale()},e.prototype.activate_field=function(){return!this.is_multiple&&!this.active_field&&(this.search_field.attr("tabindex",this.selected_item.attr("tabindex")),this.selected_item.attr("tabindex",-1)),this.container.addClass("chzn-container-active"),this.active_field=!0,this.search_field.val(this.search_field.val()),this.search_field.focus()},e.prototype.test_active_click=function(b){return a(b.target).parents("#"+this.container_id).length?this.active_field=!0:this.close_field()},e.prototype.results_build=function(){var a,b,c,e,f;this.parsing=!0,this.results_data=d.SelectParser.select_to_array(this.form_field),this.is_multiple&&this.choices>0?(this.search_choices.find("li.search-choice").remove(),this.choices=0):this.is_multiple||(this.selected_item.find("span").text(this.default_text),this.form_field.options.length<=this.disable_search_threshold?this.container.addClass("chzn-container-single-nosearch"):this.container.removeClass("chzn-container-single-nosearch")),a="",f=this.results_data;for(c=0,e=f.length;c'+a("
            ").text(b.label).html()+"")},e.prototype.result_do_highlight=function(a){var b,c,d,e,f;if(a.length){this.result_clear_highlight(),this.result_highlight=a,this.result_highlight.addClass("highlighted"),d=parseInt(this.search_results.css("maxHeight"),10),f=this.search_results.scrollTop(),e=d+f,c=this.result_highlight.position().top+this.search_results.scrollTop(),b=c+this.result_highlight.outerHeight();if(b>=e)return this.search_results.scrollTop(b-d>0?b-d:0);if(c'+b.html+''),d=a("#"+c).find("a").first(),d.click(function(a){return e.choice_destroy_link_click(a)})},e.prototype.choice_destroy_link_click=function(b){return b.preventDefault(),this.is_disabled?b.stopPropagation:(this.pending_destroy_click=!0,this.choice_destroy(a(b.target)))},e.prototype.choice_destroy=function(a){return this.choices-=1,this.show_search_field_default(),this.is_multiple&&this.choices>0&&this.search_field.val().length<1&&this.results_hide(),this.result_deselect(a.attr("rel")),a.parents("li").first().remove()},e.prototype.results_reset=function(b){this.form_field.options[0].selected=!0,this.selected_item.find("span").text(this.default_text),this.show_search_field_default(),a(b.target).remove(),this.form_field_jq.trigger("change");if(this.active_field)return this.results_hide()},e.prototype.result_select=function(a){var b,c,d,e;if(this.result_highlight)return b=this.result_highlight,c=b.attr("id"),this.result_clear_highlight(),this.is_multiple?this.result_deactivate(b):(this.search_results.find(".result-selected").removeClass("result-selected"),this.result_single_selected=b),b.addClass("result-selected"),e=c.substr(c.lastIndexOf("_")+1),d=this.results_data[e],d.selected=!0,this.form_field.options[d.options_index].selected=!0,this.is_multiple?this.choice_build(d):(this.selected_item.find("span").first().text(d.text),this.allow_single_deselect&&this.single_deselect_control_build()),(!a.metaKey||!this.is_multiple)&&this.results_hide(),this.search_field.val(""),this.form_field_jq.trigger("change"),this.search_field_scale()},e.prototype.result_activate=function(a){return a.addClass("active-result")},e.prototype.result_deactivate=function(a){return a.removeClass("active-result")},e.prototype.result_deselect=function(b){var c,d;return d=this.results_data[b],d.selected=!1,this.form_field.options[d.options_index].selected=!1,c=a("#"+this.container_id+"_o_"+b),c.removeClass("result-selected").addClass("active-result").show(),this.result_clear_highlight(),this.winnow_results(),this.form_field_jq.trigger("change"),this.search_field_scale()},e.prototype.single_deselect_control_build=function(){if(this.allow_single_deselect&&this.selected_item.find("abbr").length<1)return this.selected_item.find("span").first().after('')},e.prototype.winnow_results=function(){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r;this.no_results_clear(),i=0,j=this.search_field.val()===this.default_text?"":a("
            ").text(a.trim(this.search_field.val())).html(),f=new RegExp("^"+j.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),m=new RegExp(j.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),r=this.results_data;for(n=0,p=r.length;n=0||c.html.indexOf("[")===0){e=c.html.replace(/\[|\]/g,"").split(" ");if(e.length)for(o=0,q=e.length;o"+c.html.substr(k+j.length),l=l.substr(0,k)+""+l.substr(k)):l=c.html,g.html(l),this.result_activate(g),c.group_array_index!=null&&a("#"+this.results_data[c.group_array_index].dom_id).css("display","list-item")):(this.result_highlight&&h===this.result_highlight.attr("id")&&this.result_clear_highlight(),this.result_deactivate(g))}}return i<1&&j.length?this.no_results(j):this.winnow_results_set_highlight()},e.prototype.winnow_results_clear=function(){var b,c,d,e,f;this.search_field.val(""),c=this.search_results.find("li"),f=[];for(d=0,e=c.length;d'+this.results_none_found+' ""'),c.find("span").first().html(b),this.search_results.append(c)},e.prototype.no_results_clear=function(){return this.search_results.find(".no-results").remove()},e.prototype.keydown_arrow=function(){var b,c;this.result_highlight?this.results_showing&&(c=this.result_highlight.nextAll("li.active-result").first(),c&&this.result_do_highlight(c)):(b=this.search_results.find("li.active-result").first(),b&&this.result_do_highlight(a(b)));if(!this.results_showing)return this.results_show()},e.prototype.keyup_arrow=function(){var a;if(!this.results_showing&&!this.is_multiple)return this.results_show();if(this.result_highlight)return a=this.result_highlight.prevAll("li.active-result"),a.length?this.result_do_highlight(a.first()):(this.choices>0&&this.results_hide(),this.result_clear_highlight())},e.prototype.keydown_backstroke=function(){return this.pending_backstroke?(this.choice_destroy(this.pending_backstroke.find("a").first()),this.clear_backstroke()):(this.pending_backstroke=this.search_container.siblings("li.search-choice").last(),this.pending_backstroke.addClass("search-choice-focus"))},e.prototype.clear_backstroke=function(){return this.pending_backstroke&&this.pending_backstroke.removeClass("search-choice-focus"),this.pending_backstroke=null},e.prototype.keydown_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale(),b!==8&&this.pending_backstroke&&this.clear_backstroke();switch(b){case 8:this.backstroke_length=this.search_field.val().length;break;case 9:this.results_showing&&!this.is_multiple&&this.result_select(a),this.mouse_on_container=!1;break;case 13:a.preventDefault();break;case 38:a.preventDefault(),this.keyup_arrow();break;case 40:this.keydown_arrow()}},e.prototype.search_field_scale=function(){var b,c,d,e,f,g,h,i,j;if(this.is_multiple){d=0,h=0,f="position:absolute; left: -1000px; top: -1000px; display:none;",g=["font-size","font-style","font-weight","font-family","line-height","text-transform","letter-spacing"];for(i=0,j=g.length;i",{style:f}),c.text(this.search_field.val()),a("body").append(c),h=c.width()+25,c.remove(),h>this.f_width-10&&(h=this.f_width-10),this.search_field.css({width:h+"px"}),b=this.container.height(),this.dropdown.css({top:b+"px"})}},e.prototype.generate_random_id=function(){var b;b="sel"+this.generate_random_char()+this.generate_random_char()+this.generate_random_char();while(a("#"+b).length>0)b+=this.generate_random_char();return b},e}(AbstractChosen),c=function(a){var b;return b=a.outerWidth()-a.width()},d.get_side_border_padding=c}.call(this) diff --git a/static/js/chosen.jquery_ready.js b/static/js/chosen.jquery_ready.js deleted file mode 100644 index 65308b8..0000000 --- a/static/js/chosen.jquery_ready.js +++ /dev/null @@ -1,24 +0,0 @@ -(function ($) { - $(function () { - $(".chzn-select").each(function(i, select) { - var $select = $(select); - - // Set overflow:visible on parent .form-row for django admin - $select.parents('.form-row').css('overflow', 'visible'); - - if (typeof grappelli == 'object') { - // Set overflow:visible on grappelli fieldset.module .row - $select.parents('.row').filter(function(i) { - return $(this).parent('fieldset.module').length; - }).css('overflow', 'visible'); - // Set overflow:visible on grappelli tabular module - $select.parents('td').filter(function(i) { - return $(this).parent('.module.table').length; - }).css('overflow', 'visible'); - } - - // Initialize Chosen - $select.chosen(); - }); - }); -})((typeof window.django != 'undefined') ? django.jQuery : jQuery); \ No newline at end of file diff --git a/static/js/college.reg.js b/static/js/college.reg.js index 36d3342..8441cb9 100644 --- a/static/js/college.reg.js +++ b/static/js/college.reg.js @@ -23,7 +23,7 @@ function reg_done(data) } $(document).ready(function(){ - html="
            " + html=""; $("table tr:eq(6)").append(html); }); $(document).ready(function(){ @@ -33,4 +33,7 @@ $(document).ready(function(){ Dajaxice.users.college_register(Dajax.process); }); }); - +function close_reg(){ + $("#reg").html(""); + $("#msg").show(); +} diff --git a/static/js/jquery-1.7.2.min.js b/static/js/jquery-1.7.2.min.js deleted file mode 100644 index 5627896..0000000 --- a/static/js/jquery-1.7.2.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.7.2 jquery.com | jquery.org/license */ -(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"":"")+""),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;e=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
            S.NoEvent Name
            "+str(e.id)+""+e.title+"
            ' + str(e.id) + + '
            Register New College
            Register New College
            a",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q="

            "+""+"
            ",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="
            t
            ",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="
            ",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function( -a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&j.push({elem:this,matches:d.slice(e)});for(k=0;k0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

            ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
            ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/
            ","
            "],tr:[2,"","
            "],td:[3,"","
            "],col:[2,"","
            "],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
            ","
            "]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f -.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(;d1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]===""&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/)<[^<]*)*<\/script>/gi,bN=/^(?:select|textarea)/i,bO=/\s+/,bP=/([?&])_=[^&]*/,bQ=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bR=f.fn.load,bS={},bT={},bU,bV,bW=["*/"]+["*"];try{bU=e.href}catch(bX){bU=c.createElement("a"),bU.href="",bU=bU.href}bV=bQ.exec(bU.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bR)return bR.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
            ").append(c.replace(bM,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bN.test(this.nodeName)||bH.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bE,"\r\n")}}):{name:b.name,value:c.replace(bE,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b$(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b$(a,b);return a},ajaxSettings:{url:bU,isLocal:bI.test(bV[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bY(bS),ajaxTransport:bY(bT),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?ca(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cb(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bF,"").replace(bK,bV[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bO),d.crossDomain==null&&(r=bQ.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bV[1]&&r[2]==bV[2]&&(r[3]||(r[1]==="http:"?80:443))==(bV[3]||(bV[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bZ(bS,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bJ.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bL.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bP,"$1_="+x);d.url=y+(y===d.url?(bL.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bW+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bZ(bT,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bC,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=typeof b.data=="string"&&/^application\/x\-www\-form\-urlencoded/.test(b.contentType);if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n);try{m.text=h.responseText}catch(a){}try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(ct("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);f.fn[a]=function(e){return f.access(this,function(a,e,g){var h=cy(a);if(g===b)return h?c in h?h[c]:f.support.boxModel&&h.document.documentElement[e]||h.document.body[e]:a[e];h?h.scrollTo(d?f(h).scrollLeft():g,d?g:f(h).scrollTop()):a[e]=g},a,e,arguments.length,null)}}),f.each({Height:"height",Width:"width"},function(a,c){var d="client"+a,e="scroll"+a,g="offset"+a;f.fn["inner"+a]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,c,"padding")):this[c]():null},f.fn["outer"+a]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,c,a?"margin":"border")):this[c]():null},f.fn[c]=function(a){return f.access(this,function(a,c,h){var i,j,k,l;if(f.isWindow(a)){i=a.document,j=i.documentElement[d];return f.support.boxModel&&j||i.body&&i.body[d]||j}if(a.nodeType===9){i=a.documentElement;if(i[d]>=i[e])return i[d];return Math.max(a.body[e],i[e],a.body[g],i[g])}if(h===b){k=f.css(a,c),l=parseFloat(k);return f.isNumeric(l)?l:k}f(a).css(c,h)},c,a,arguments.length,null)}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); diff --git a/static/js/jquery.ba-bbq.js b/static/js/jquery.ba-bbq.js deleted file mode 100644 index f251123..0000000 --- a/static/js/jquery.ba-bbq.js +++ /dev/null @@ -1,1137 +0,0 @@ -/*! - * jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010 - * http://benalman.com/projects/jquery-bbq-plugin/ - * - * Copyright (c) 2010 "Cowboy" Ben Alman - * Dual licensed under the MIT and GPL licenses. - * http://benalman.com/about/license/ - */ - -// Script: jQuery BBQ: Back Button & Query Library -// -// *Version: 1.2.1, Last updated: 2/17/2010* -// -// Project Home - http://benalman.com/projects/jquery-bbq-plugin/ -// GitHub - http://github.com/cowboy/jquery-bbq/ -// Source - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.js -// (Minified) - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.min.js (4.0kb) -// -// About: License -// -// Copyright (c) 2010 "Cowboy" Ben Alman, -// Dual licensed under the MIT and GPL licenses. -// http://benalman.com/about/license/ -// -// About: Examples -// -// These working examples, complete with fully commented code, illustrate a few -// ways in which this plugin can be used. -// -// Basic AJAX - http://benalman.com/code/projects/jquery-bbq/examples/fragment-basic/ -// Advanced AJAX - http://benalman.com/code/projects/jquery-bbq/examples/fragment-advanced/ -// jQuery UI Tabs - http://benalman.com/code/projects/jquery-bbq/examples/fragment-jquery-ui-tabs/ -// Deparam - http://benalman.com/code/projects/jquery-bbq/examples/deparam/ -// -// About: Support and Testing -// -// Information about what version or versions of jQuery this plugin has been -// tested with, what browsers it has been tested in, and where the unit tests -// reside (so you can test it yourself). -// -// jQuery Versions - 1.3.2, 1.4.1, 1.4.2 -// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4, -// Chrome 4-5, Opera 9.6-10.1. -// Unit Tests - http://benalman.com/code/projects/jquery-bbq/unit/ -// -// About: Release History -// -// 1.2.1 - (2/17/2010) Actually fixed the stale window.location Safari bug from -// in BBQ, which was the main reason for the -// previous release! -// 1.2 - (2/16/2010) Integrated v1.2, which fixes a -// Safari bug, the event can now be bound before DOM ready, and IE6/7 -// page should no longer scroll when the event is first bound. Also -// added the method, and reworked the -// internal "add" method to be compatible with -// changes made to the jQuery 1.4.2 special events API. -// 1.1.1 - (1/22/2010) Integrated v1.1, which fixes an -// obscure IE8 EmulateIE7 meta tag compatibility mode bug. -// 1.1 - (1/9/2010) Broke out the jQuery BBQ event.special -// functionality into a separate plugin for users who want just the -// basic event & back button support, without all the extra awesomeness -// that BBQ provides. This plugin will be included as part of jQuery BBQ, -// but also be available separately. See -// plugin for more information. Also added the -// method and added additional examples. -// 1.0.3 - (12/2/2009) Fixed an issue in IE 6 where location.search and -// location.hash would report incorrectly if the hash contained the ? -// character. Also and -// will no longer parse params out of a URL that doesn't contain ? or #, -// respectively. -// 1.0.2 - (10/10/2009) Fixed an issue in IE 6/7 where the hidden IFRAME caused -// a "This page contains both secure and nonsecure items." warning when -// used on an https:// page. -// 1.0.1 - (10/7/2009) Fixed an issue in IE 8. Since both "IE7" and "IE8 -// Compatibility View" modes erroneously report that the browser -// supports the native window.onhashchange event, a slightly more -// robust test needed to be added. -// 1.0 - (10/2/2009) Initial release - -(function($,window){ - '$:nomunge'; // Used by YUI compressor. - - // Some convenient shortcuts. - var undefined, - aps = Array.prototype.slice, - decode = decodeURIComponent, - - // Method / object references. - jq_param = $.param, - jq_param_fragment, - jq_deparam, - jq_deparam_fragment, - jq_bbq = $.bbq = $.bbq || {}, - jq_bbq_pushState, - jq_bbq_getState, - jq_elemUrlAttr, - jq_event_special = $.event.special, - - // Reused strings. - str_hashchange = 'hashchange', - str_querystring = 'querystring', - str_fragment = 'fragment', - str_elemUrlAttr = 'elemUrlAttr', - str_location = 'location', - str_href = 'href', - str_src = 'src', - - // Reused RegExp. - re_trim_querystring = /^.*\?|#.*$/g, - re_trim_fragment = /^.*\#/, - re_no_escape, - - // Used by jQuery.elemUrlAttr. - elemUrlAttr_cache = {}; - - // A few commonly used bits, broken out to help reduce minified file size. - - function is_string( arg ) { - return typeof arg === 'string'; - }; - - // Why write the same function twice? Let's curry! Mmmm, curry.. - - function curry( func ) { - var args = aps.call( arguments, 1 ); - - return function() { - return func.apply( this, args.concat( aps.call( arguments ) ) ); - }; - }; - - // Get location.hash (or what you'd expect location.hash to be) sans any - // leading #. Thanks for making this necessary, Firefox! - function get_fragment( url ) { - return url.replace( /^[^#]*#?(.*)$/, '$1' ); - }; - - // Get location.search (or what you'd expect location.search to be) sans any - // leading #. Thanks for making this necessary, IE6! - function get_querystring( url ) { - return url.replace( /(?:^[^?#]*\?([^#]*).*$)?.*/, '$1' ); - }; - - // Section: Param (to string) - // - // Method: jQuery.param.querystring - // - // Retrieve the query string from a URL or if no arguments are passed, the - // current window.location. - // - // Usage: - // - // > jQuery.param.querystring( [ url ] ); - // - // Arguments: - // - // url - (String) A URL containing query string params to be parsed. If url - // is not passed, the current window.location is used. - // - // Returns: - // - // (String) The parsed query string, with any leading "?" removed. - // - - // Method: jQuery.param.querystring (build url) - // - // Merge a URL, with or without pre-existing query string params, plus any - // object, params string or URL containing query string params into a new URL. - // - // Usage: - // - // > jQuery.param.querystring( url, params [, merge_mode ] ); - // - // Arguments: - // - // url - (String) A valid URL for params to be merged into. This URL may - // contain a query string and/or fragment (hash). - // params - (String) A params string or URL containing query string params to - // be merged into url. - // params - (Object) A params object to be merged into url. - // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not - // specified, and is as-follows: - // - // * 0: params in the params argument will override any query string - // params in url. - // * 1: any query string params in url will override params in the params - // argument. - // * 2: params argument will completely replace any query string in url. - // - // Returns: - // - // (String) Either a params string with urlencoded data or a URL with a - // urlencoded query string in the format 'a=b&c=d&e=f'. - - // Method: jQuery.param.fragment - // - // Retrieve the fragment (hash) from a URL or if no arguments are passed, the - // current window.location. - // - // Usage: - // - // > jQuery.param.fragment( [ url ] ); - // - // Arguments: - // - // url - (String) A URL containing fragment (hash) params to be parsed. If - // url is not passed, the current window.location is used. - // - // Returns: - // - // (String) The parsed fragment (hash) string, with any leading "#" removed. - - // Method: jQuery.param.fragment (build url) - // - // Merge a URL, with or without pre-existing fragment (hash) params, plus any - // object, params string or URL containing fragment (hash) params into a new - // URL. - // - // Usage: - // - // > jQuery.param.fragment( url, params [, merge_mode ] ); - // - // Arguments: - // - // url - (String) A valid URL for params to be merged into. This URL may - // contain a query string and/or fragment (hash). - // params - (String) A params string or URL containing fragment (hash) params - // to be merged into url. - // params - (Object) A params object to be merged into url. - // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not - // specified, and is as-follows: - // - // * 0: params in the params argument will override any fragment (hash) - // params in url. - // * 1: any fragment (hash) params in url will override params in the - // params argument. - // * 2: params argument will completely replace any query string in url. - // - // Returns: - // - // (String) Either a params string with urlencoded data or a URL with a - // urlencoded fragment (hash) in the format 'a=b&c=d&e=f'. - - function jq_param_sub( is_fragment, get_func, url, params, merge_mode ) { - var result, - qs, - matches, - url_params, - hash; - - if ( params !== undefined ) { - // Build URL by merging params into url string. - - // matches[1] = url part that precedes params, not including trailing ?/# - // matches[2] = params, not including leading ?/# - // matches[3] = if in 'querystring' mode, hash including leading #, otherwise '' - matches = url.match( is_fragment ? /^([^#]*)\#?(.*)$/ : /^([^#?]*)\??([^#]*)(#?.*)/ ); - - // Get the hash if in 'querystring' mode, and it exists. - hash = matches[3] || ''; - - if ( merge_mode === 2 && is_string( params ) ) { - // If merge_mode is 2 and params is a string, merge the fragment / query - // string into the URL wholesale, without converting it into an object. - qs = params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' ); - - } else { - // Convert relevant params in url to object. - url_params = jq_deparam( matches[2] ); - - params = is_string( params ) - - // Convert passed params string into object. - ? jq_deparam[ is_fragment ? str_fragment : str_querystring ]( params ) - - // Passed params object. - : params; - - qs = merge_mode === 2 ? params // passed params replace url params - : merge_mode === 1 ? $.extend( {}, params, url_params ) // url params override passed params - : $.extend( {}, url_params, params ); // passed params override url params - - // Convert params object to a string. - qs = jq_param( qs ); - - // Unescape characters specified via $.param.noEscape. Since only hash- - // history users have requested this feature, it's only enabled for - // fragment-related params strings. - if ( is_fragment ) { - qs = qs.replace( re_no_escape, decode ); - } - } - - // Build URL from the base url, querystring and hash. In 'querystring' - // mode, ? is only added if a query string exists. In 'fragment' mode, # - // is always added. - result = matches[1] + ( is_fragment ? '#' : qs || !matches[1] ? '?' : '' ) + qs + hash; - - } else { - // If URL was passed in, parse params from URL string, otherwise parse - // params from window.location. - result = get_func( url !== undefined ? url : window[ str_location ][ str_href ] ); - } - - return result; - }; - - jq_param[ str_querystring ] = curry( jq_param_sub, 0, get_querystring ); - jq_param[ str_fragment ] = jq_param_fragment = curry( jq_param_sub, 1, get_fragment ); - - // Method: jQuery.param.fragment.noEscape - // - // Specify characters that will be left unescaped when fragments are created - // or merged using , or when the fragment is modified - // using . This option only applies to serialized data - // object fragments, and not set-as-string fragments. Does not affect the - // query string. Defaults to ",/" (comma, forward slash). - // - // Note that this is considered a purely aesthetic option, and will help to - // create URLs that "look pretty" in the address bar or bookmarks, without - // affecting functionality in any way. That being said, be careful to not - // unescape characters that are used as delimiters or serve a special - // purpose, such as the "#?&=+" (octothorpe, question mark, ampersand, - // equals, plus) characters. - // - // Usage: - // - // > jQuery.param.fragment.noEscape( [ chars ] ); - // - // Arguments: - // - // chars - (String) The characters to not escape in the fragment. If - // unspecified, defaults to empty string (escape all characters). - // - // Returns: - // - // Nothing. - - jq_param_fragment.noEscape = function( chars ) { - chars = chars || ''; - var arr = $.map( chars.split(''), encodeURIComponent ); - re_no_escape = new RegExp( arr.join('|'), 'g' ); - }; - - // A sensible default. These are the characters people seem to complain about - // "uglifying up the URL" the most. - jq_param_fragment.noEscape( ',/' ); - - // Section: Deparam (from string) - // - // Method: jQuery.deparam - // - // Deserialize a params string into an object, optionally coercing numbers, - // booleans, null and undefined values; this method is the counterpart to the - // internal jQuery.param method. - // - // Usage: - // - // > jQuery.deparam( params [, coerce ] ); - // - // Arguments: - // - // params - (String) A params string to be parsed. - // coerce - (Boolean) If true, coerces any numbers or true, false, null, and - // undefined to their actual value. Defaults to false if omitted. - // - // Returns: - // - // (Object) An object representing the deserialized params string. - - $.deparam = jq_deparam = function( params, coerce ) { - var obj = {}, - coerce_types = { 'true': !0, 'false': !1, 'null': null }; - - // Iterate over all name=value pairs. - $.each( params.replace( /\+/g, ' ' ).split( '&' ), function(j,v){ - var param = v.split( '=' ), - key = decode( param[0] ), - val, - cur = obj, - i = 0, - - // If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it - // into its component parts. - keys = key.split( '][' ), - keys_last = keys.length - 1; - - // If the first keys part contains [ and the last ends with ], then [] - // are correctly balanced. - if ( /\[/.test( keys[0] ) && /\]$/.test( keys[ keys_last ] ) ) { - // Remove the trailing ] from the last keys part. - keys[ keys_last ] = keys[ keys_last ].replace( /\]$/, '' ); - - // Split first keys part into two parts on the [ and add them back onto - // the beginning of the keys array. - keys = keys.shift().split('[').concat( keys ); - - keys_last = keys.length - 1; - } else { - // Basic 'foo' style key. - keys_last = 0; - } - - // Are we dealing with a name=value pair, or just a name? - if ( param.length === 2 ) { - val = decode( param[1] ); - - // Coerce values. - if ( coerce ) { - val = val && !isNaN(val) ? +val // number - : val === 'undefined' ? undefined // undefined - : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null - : val; // string - } - - if ( keys_last ) { - // Complex key, build deep object structure based on a few rules: - // * The 'cur' pointer starts at the object top-level. - // * [] = array push (n is set to array length), [n] = array if n is - // numeric, otherwise object. - // * If at the last keys part, set the value. - // * For each keys part, if the current level is undefined create an - // object or array based on the type of the next keys part. - // * Move the 'cur' pointer to the next level. - // * Rinse & repeat. - for ( ; i <= keys_last; i++ ) { - key = keys[i] === '' ? cur.length : keys[i]; - cur = cur[key] = i < keys_last - ? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] ) - : val; - } - - } else { - // Simple key, even simpler rules, since only scalars and shallow - // arrays are allowed. - - if ( $.isArray( obj[key] ) ) { - // val is already an array, so push on the next value. - obj[key].push( val ); - - } else if ( obj[key] !== undefined ) { - // val isn't an array, but since a second value has been specified, - // convert val into an array. - obj[key] = [ obj[key], val ]; - - } else { - // val is a scalar. - obj[key] = val; - } - } - - } else if ( key ) { - // No value was defined, so set something meaningful. - obj[key] = coerce - ? undefined - : ''; - } - }); - - return obj; - }; - - // Method: jQuery.deparam.querystring - // - // Parse the query string from a URL or the current window.location, - // deserializing it into an object, optionally coercing numbers, booleans, - // null and undefined values. - // - // Usage: - // - // > jQuery.deparam.querystring( [ url ] [, coerce ] ); - // - // Arguments: - // - // url - (String) An optional params string or URL containing query string - // params to be parsed. If url is omitted, the current window.location - // is used. - // coerce - (Boolean) If true, coerces any numbers or true, false, null, and - // undefined to their actual value. Defaults to false if omitted. - // - // Returns: - // - // (Object) An object representing the deserialized params string. - - // Method: jQuery.deparam.fragment - // - // Parse the fragment (hash) from a URL or the current window.location, - // deserializing it into an object, optionally coercing numbers, booleans, - // null and undefined values. - // - // Usage: - // - // > jQuery.deparam.fragment( [ url ] [, coerce ] ); - // - // Arguments: - // - // url - (String) An optional params string or URL containing fragment (hash) - // params to be parsed. If url is omitted, the current window.location - // is used. - // coerce - (Boolean) If true, coerces any numbers or true, false, null, and - // undefined to their actual value. Defaults to false if omitted. - // - // Returns: - // - // (Object) An object representing the deserialized params string. - - function jq_deparam_sub( is_fragment, url_or_params, coerce ) { - if ( url_or_params === undefined || typeof url_or_params === 'boolean' ) { - // url_or_params not specified. - coerce = url_or_params; - url_or_params = jq_param[ is_fragment ? str_fragment : str_querystring ](); - } else { - url_or_params = is_string( url_or_params ) - ? url_or_params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' ) - : url_or_params; - } - - return jq_deparam( url_or_params, coerce ); - }; - - jq_deparam[ str_querystring ] = curry( jq_deparam_sub, 0 ); - jq_deparam[ str_fragment ] = jq_deparam_fragment = curry( jq_deparam_sub, 1 ); - - // Section: Element manipulation - // - // Method: jQuery.elemUrlAttr - // - // Get the internal "Default URL attribute per tag" list, or augment the list - // with additional tag-attribute pairs, in case the defaults are insufficient. - // - // In the and methods, this list - // is used to determine which attribute contains the URL to be modified, if - // an "attr" param is not specified. - // - // Default Tag-Attribute List: - // - // a - href - // base - href - // iframe - src - // img - src - // input - src - // form - action - // link - href - // script - src - // - // Usage: - // - // > jQuery.elemUrlAttr( [ tag_attr ] ); - // - // Arguments: - // - // tag_attr - (Object) An object containing a list of tag names and their - // associated default attribute names in the format { tag: 'attr', ... } to - // be merged into the internal tag-attribute list. - // - // Returns: - // - // (Object) An object containing all stored tag-attribute values. - - // Only define function and set defaults if function doesn't already exist, as - // the urlInternal plugin will provide this method as well. - $[ str_elemUrlAttr ] || ($[ str_elemUrlAttr ] = function( obj ) { - return $.extend( elemUrlAttr_cache, obj ); - })({ - a: str_href, - base: str_href, - iframe: str_src, - img: str_src, - input: str_src, - form: 'action', - link: str_href, - script: str_src - }); - - jq_elemUrlAttr = $[ str_elemUrlAttr ]; - - // Method: jQuery.fn.querystring - // - // Update URL attribute in one or more elements, merging the current URL (with - // or without pre-existing query string params) plus any params object or - // string into a new URL, which is then set into that attribute. Like - // , but for all elements in a jQuery - // collection. - // - // Usage: - // - // > jQuery('selector').querystring( [ attr, ] params [, merge_mode ] ); - // - // Arguments: - // - // attr - (String) Optional name of an attribute that will contain a URL to - // merge params or url into. See for a list of default - // attributes. - // params - (Object) A params object to be merged into the URL attribute. - // params - (String) A URL containing query string params, or params string - // to be merged into the URL attribute. - // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not - // specified, and is as-follows: - // - // * 0: params in the params argument will override any params in attr URL. - // * 1: any params in attr URL will override params in the params argument. - // * 2: params argument will completely replace any query string in attr - // URL. - // - // Returns: - // - // (jQuery) The initial jQuery collection of elements, but with modified URL - // attribute values. - - // Method: jQuery.fn.fragment - // - // Update URL attribute in one or more elements, merging the current URL (with - // or without pre-existing fragment/hash params) plus any params object or - // string into a new URL, which is then set into that attribute. Like - // , but for all elements in a jQuery - // collection. - // - // Usage: - // - // > jQuery('selector').fragment( [ attr, ] params [, merge_mode ] ); - // - // Arguments: - // - // attr - (String) Optional name of an attribute that will contain a URL to - // merge params into. See for a list of default - // attributes. - // params - (Object) A params object to be merged into the URL attribute. - // params - (String) A URL containing fragment (hash) params, or params - // string to be merged into the URL attribute. - // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not - // specified, and is as-follows: - // - // * 0: params in the params argument will override any params in attr URL. - // * 1: any params in attr URL will override params in the params argument. - // * 2: params argument will completely replace any fragment (hash) in attr - // URL. - // - // Returns: - // - // (jQuery) The initial jQuery collection of elements, but with modified URL - // attribute values. - - function jq_fn_sub( mode, force_attr, params, merge_mode ) { - if ( !is_string( params ) && typeof params !== 'object' ) { - // force_attr not specified. - merge_mode = params; - params = force_attr; - force_attr = undefined; - } - - return this.each(function(){ - var that = $(this), - - // Get attribute specified, or default specified via $.elemUrlAttr. - attr = force_attr || jq_elemUrlAttr()[ ( this.nodeName || '' ).toLowerCase() ] || '', - - // Get URL value. - url = attr && that.attr( attr ) || ''; - - // Update attribute with new URL. - that.attr( attr, jq_param[ mode ]( url, params, merge_mode ) ); - }); - - }; - - $.fn[ str_querystring ] = curry( jq_fn_sub, str_querystring ); - $.fn[ str_fragment ] = curry( jq_fn_sub, str_fragment ); - - // Section: History, hashchange event - // - // Method: jQuery.bbq.pushState - // - // Adds a 'state' into the browser history at the current position, setting - // location.hash and triggering any bound callbacks - // (provided the new state is different than the previous state). - // - // If no arguments are passed, an empty state is created, which is just a - // shortcut for jQuery.bbq.pushState( {}, 2 ). - // - // Usage: - // - // > jQuery.bbq.pushState( [ params [, merge_mode ] ] ); - // - // Arguments: - // - // params - (String) A serialized params string or a hash string beginning - // with # to merge into location.hash. - // params - (Object) A params object to merge into location.hash. - // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not - // specified (unless a hash string beginning with # is specified, in which - // case merge behavior defaults to 2), and is as-follows: - // - // * 0: params in the params argument will override any params in the - // current state. - // * 1: any params in the current state will override params in the params - // argument. - // * 2: params argument will completely replace current state. - // - // Returns: - // - // Nothing. - // - // Additional Notes: - // - // * Setting an empty state may cause the browser to scroll. - // * Unlike the fragment and querystring methods, if a hash string beginning - // with # is specified as the params agrument, merge_mode defaults to 2. - - jq_bbq.pushState = jq_bbq_pushState = function( params, merge_mode ) { - if ( is_string( params ) && /^#/.test( params ) && merge_mode === undefined ) { - // Params string begins with # and merge_mode not specified, so completely - // overwrite window.location.hash. - merge_mode = 2; - } - - var has_args = params !== undefined, - // Merge params into window.location using $.param.fragment. - url = jq_param_fragment( window[ str_location ][ str_href ], - has_args ? params : {}, has_args ? merge_mode : 2 ); - - // Set new window.location.href. If hash is empty, use just # to prevent - // browser from reloading the page. Note that Safari 3 & Chrome barf on - // location.hash = '#'. - window[ str_location ][ str_href ] = url + ( /#/.test( url ) ? '' : '#' ); - }; - - // Method: jQuery.bbq.getState - // - // Retrieves the current 'state' from the browser history, parsing - // location.hash for a specific key or returning an object containing the - // entire state, optionally coercing numbers, booleans, null and undefined - // values. - // - // Usage: - // - // > jQuery.bbq.getState( [ key ] [, coerce ] ); - // - // Arguments: - // - // key - (String) An optional state key for which to return a value. - // coerce - (Boolean) If true, coerces any numbers or true, false, null, and - // undefined to their actual value. Defaults to false. - // - // Returns: - // - // (Anything) If key is passed, returns the value corresponding with that key - // in the location.hash 'state', or undefined. If not, an object - // representing the entire 'state' is returned. - - jq_bbq.getState = jq_bbq_getState = function( key, coerce ) { - return key === undefined || typeof key === 'boolean' - ? jq_deparam_fragment( key ) // 'key' really means 'coerce' here - : jq_deparam_fragment( coerce )[ key ]; - }; - - // Method: jQuery.bbq.removeState - // - // Remove one or more keys from the current browser history 'state', creating - // a new state, setting location.hash and triggering any bound - // callbacks (provided the new state is different than - // the previous state). - // - // If no arguments are passed, an empty state is created, which is just a - // shortcut for jQuery.bbq.pushState( {}, 2 ). - // - // Usage: - // - // > jQuery.bbq.removeState( [ key [, key ... ] ] ); - // - // Arguments: - // - // key - (String) One or more key values to remove from the current state, - // passed as individual arguments. - // key - (Array) A single array argument that contains a list of key values - // to remove from the current state. - // - // Returns: - // - // Nothing. - // - // Additional Notes: - // - // * Setting an empty state may cause the browser to scroll. - - jq_bbq.removeState = function( arr ) { - var state = {}; - - // If one or more arguments is passed.. - if ( arr !== undefined ) { - - // Get the current state. - state = jq_bbq_getState(); - - // For each passed key, delete the corresponding property from the current - // state. - $.each( $.isArray( arr ) ? arr : arguments, function(i,v){ - delete state[ v ]; - }); - } - - // Set the state, completely overriding any existing state. - jq_bbq_pushState( state, 2 ); - }; - - // Event: hashchange event (BBQ) - // - // Usage in jQuery 1.4 and newer: - // - // In jQuery 1.4 and newer, the event object passed into any hashchange event - // callback is augmented with a copy of the location.hash fragment at the time - // the event was triggered as its event.fragment property. In addition, the - // event.getState method operates on this property (instead of location.hash) - // which allows this fragment-as-a-state to be referenced later, even after - // window.location may have changed. - // - // Note that event.fragment and event.getState are not defined according to - // W3C (or any other) specification, but will still be available whether or - // not the hashchange event exists natively in the browser, because of the - // utility they provide. - // - // The event.fragment property contains the output of - // and the event.getState method is equivalent to the - // method. - // - // > $(window).bind( 'hashchange', function( event ) { - // > var hash_str = event.fragment, - // > param_obj = event.getState(), - // > param_val = event.getState( 'param_name' ), - // > param_val_coerced = event.getState( 'param_name', true ); - // > ... - // > }); - // - // Usage in jQuery 1.3.2: - // - // In jQuery 1.3.2, the event object cannot to be augmented as in jQuery 1.4+, - // so the fragment state isn't bound to the event object and must instead be - // parsed using the and methods. - // - // > $(window).bind( 'hashchange', function( event ) { - // > var hash_str = $.param.fragment(), - // > param_obj = $.bbq.getState(), - // > param_val = $.bbq.getState( 'param_name' ), - // > param_val_coerced = $.bbq.getState( 'param_name', true ); - // > ... - // > }); - // - // Additional Notes: - // - // * Due to changes in the special events API, jQuery BBQ v1.2 or newer is - // required to enable the augmented event object in jQuery 1.4.2 and newer. - // * See for more detailed information. - - jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], { - - // Augmenting the event object with the .fragment property and .getState - // method requires jQuery 1.4 or newer. Note: with 1.3.2, everything will - // work, but the event won't be augmented) - add: function( handleObj ) { - var old_handler; - - function new_handler(e) { - // e.fragment is set to the value of location.hash (with any leading # - // removed) at the time the event is triggered. - var hash = e[ str_fragment ] = jq_param_fragment(); - - // e.getState() works just like $.bbq.getState(), but uses the - // e.fragment property stored on the event object. - e.getState = function( key, coerce ) { - return key === undefined || typeof key === 'boolean' - ? jq_deparam( hash, key ) // 'key' really means 'coerce' here - : jq_deparam( hash, coerce )[ key ]; - }; - - old_handler.apply( this, arguments ); - }; - - // This may seem a little complicated, but it normalizes the special event - // .add method between jQuery 1.4/1.4.1 and 1.4.2+ - if ( $.isFunction( handleObj ) ) { - // 1.4, 1.4.1 - old_handler = handleObj; - return new_handler; - } else { - // 1.4.2+ - old_handler = handleObj.handler; - handleObj.handler = new_handler; - } - } - - }); - -})(jQuery,this); - -/*! - * jQuery hashchange event - v1.2 - 2/11/2010 - * http://benalman.com/projects/jquery-hashchange-plugin/ - * - * Copyright (c) 2010 "Cowboy" Ben Alman - * Dual licensed under the MIT and GPL licenses. - * http://benalman.com/about/license/ - */ - -// Script: jQuery hashchange event -// -// *Version: 1.2, Last updated: 2/11/2010* -// -// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/ -// GitHub - http://github.com/cowboy/jquery-hashchange/ -// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js -// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (1.1kb) -// -// About: License -// -// Copyright (c) 2010 "Cowboy" Ben Alman, -// Dual licensed under the MIT and GPL licenses. -// http://benalman.com/about/license/ -// -// About: Examples -// -// This working example, complete with fully commented code, illustrate one way -// in which this plugin can be used. -// -// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/ -// -// About: Support and Testing -// -// Information about what version or versions of jQuery this plugin has been -// tested with, what browsers it has been tested in, and where the unit tests -// reside (so you can test it yourself). -// -// jQuery Versions - 1.3.2, 1.4.1, 1.4.2 -// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4, Chrome, Opera 9.6-10.1. -// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/ -// -// About: Known issues -// -// While this jQuery hashchange event implementation is quite stable and robust, -// there are a few unfortunate browser bugs surrounding expected hashchange -// event-based behaviors, independent of any JavaScript window.onhashchange -// abstraction. See the following examples for more information: -// -// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/ -// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/ -// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/ -// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/ -// -// About: Release History -// -// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin -// from a page on another domain would cause an error in Safari 4. Also, -// IE6/7 Iframe is now inserted after the body (this actually works), -// which prevents the page from scrolling when the event is first bound. -// Event can also now be bound before DOM ready, but it won't be usable -// before then in IE6/7. -// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug -// where browser version is incorrectly reported as 8.0, despite -// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag. -// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special -// window.onhashchange functionality into a separate plugin for users -// who want just the basic event & back button support, without all the -// extra awesomeness that BBQ provides. This plugin will be included as -// part of jQuery BBQ, but also be available separately. - -(function($,window,undefined){ - '$:nomunge'; // Used by YUI compressor. - - // Method / object references. - var fake_onhashchange, - jq_event_special = $.event.special, - - // Reused strings. - str_location = 'location', - str_hashchange = 'hashchange', - str_href = 'href', - - // IE6/7 specifically need some special love when it comes to back-button - // support, so let's do a little browser sniffing.. - browser = $.browser, - mode = document.documentMode, - is_old_ie = browser.msie && ( mode === undefined || mode < 8 ), - - // Does the browser support window.onhashchange? Test for IE version, since - // IE8 incorrectly reports this when in "IE7" or "IE8 Compatibility View"! - supports_onhashchange = 'on' + str_hashchange in window && !is_old_ie; - - // Get location.hash (or what you'd expect location.hash to be) sans any - // leading #. Thanks for making this necessary, Firefox! - function get_fragment( url ) { - url = url || window[ str_location ][ str_href ]; - return url.replace( /^[^#]*#?(.*)$/, '$1' ); - }; - - // Property: jQuery.hashchangeDelay - // - // The numeric interval (in milliseconds) at which the - // polling loop executes. Defaults to 100. - - $[ str_hashchange + 'Delay' ] = 100; - - // Event: hashchange event - // - // Fired when location.hash changes. In browsers that support it, the native - // window.onhashchange event is used (IE8, FF3.6), otherwise a polling loop is - // initialized, running every milliseconds to see if - // the hash has changed. In IE 6 and 7, a hidden Iframe is created to allow - // the back button and hash-based history to work. - // - // Usage: - // - // > $(window).bind( 'hashchange', function(e) { - // > var hash = location.hash; - // > ... - // > }); - // - // Additional Notes: - // - // * The polling loop and Iframe are not created until at least one callback - // is actually bound to 'hashchange'. - // * If you need the bound callback(s) to execute immediately, in cases where - // the page 'state' exists on page load (via bookmark or page refresh, for - // example) use $(window).trigger( 'hashchange' ); - // * The event can be bound before DOM ready, but since it won't be usable - // before then in IE6/7 (due to the necessary Iframe), recommended usage is - // to bind it inside a $(document).ready() callback. - - jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], { - - // Called only when the first 'hashchange' event is bound to window. - setup: function() { - // If window.onhashchange is supported natively, there's nothing to do.. - if ( supports_onhashchange ) { return false; } - - // Otherwise, we need to create our own. And we don't want to call this - // until the user binds to the event, just in case they never do, since it - // will create a polling loop and possibly even a hidden Iframe. - $( fake_onhashchange.start ); - }, - - // Called only when the last 'hashchange' event is unbound from window. - teardown: function() { - // If window.onhashchange is supported natively, there's nothing to do.. - if ( supports_onhashchange ) { return false; } - - // Otherwise, we need to stop ours (if possible). - $( fake_onhashchange.stop ); - } - - }); - - // fake_onhashchange does all the work of triggering the window.onhashchange - // event for browsers that don't natively support it, including creating a - // polling loop to watch for hash changes and in IE 6/7 creating a hidden - // Iframe to enable back and forward. - fake_onhashchange = (function(){ - var self = {}, - timeout_id, - iframe, - set_history, - get_history; - - // Initialize. In IE 6/7, creates a hidden Iframe for history handling. - function init(){ - // Most browsers don't need special methods here.. - set_history = get_history = function(val){ return val; }; - - // But IE6/7 do! - if ( is_old_ie ) { - - // Create hidden Iframe after the end of the body to prevent initial - // page load from scrolling unnecessarily. - iframe = $(' +
            +
            +
            + Shaastra will now be held between 5th and 8th January +

            This New Year, watch the power of technology enchant minds at the much awaited technical festival of IIT Madras- Shaastra. The 14th edition of the festival, to be held between 5th and 8th January, focuses on bringing out the spirit of engineering, creating a platform for innovation, ideation and ingenuity. Be it planes soaring, RC engines racing, robots fighting or dominos falling; be prepared to be transported into a world of future.

            +

            Apocalypse will have to wait since Shaastra is all set to Ignite your Imagination, as the best minds of the country redefine the boundaries between dream and reality.

            Tech is in the air, breathe Shaastra.

            +
            + + + +
            +
            + + + {% endblock %} + {% block events_menu %} + {% endblock %} + +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            + + {% block footer %}{% endblock %} +{% block modal %} + +{% endblock %} + + + + + + + + + + diff --git a/templates/coord/dashboard.html b/templates/coord/dashboard.html new file mode 100644 index 0000000..e39a4c9 --- /dev/null +++ b/templates/coord/dashboard.html @@ -0,0 +1,423 @@ +{% load dajaxice_templatetags %} + + + Shaastra 2013 | Coord Dashboard + {% dajaxice_js_import %} + + + + + + + + + + + + + + + + + +
            +
            + {% csrf_token %} + + +
            +
            +
            + +
            +
            +
            +

            {{event.category}}
            + {{event}}

            +
            + +
            +
            +
            +

            +
            +
            +
            + + + + + +
            + Click on a Tab you would like to view +
            + +
            +
            +
            +
            + +
            +

            Announcement

            + {% for u in update %} + {% if u.event == request.user.get_profile.is_coord_of and u.category == 'Announcement' and u.expired == 0 %} +

            {{u.subject}} - {{u.description}} + {% endif %} + {% endfor %}
            +

            Updates

            + {% for u in update %} + {% if u.event == request.user.get_profile.is_coord_of and u.category == 'Update' and u.expired == 0 %} +

            {{u.subject}} - {{u.description}} > + {% endif %} + {% endfor %} + +

            +
            + +
            + + + diff --git a/templates/core/home.html b/templates/core/home.html index 2940bb2..9060b13 100644 --- a/templates/core/home.html +++ b/templates/core/home.html @@ -1,100 +1,134 @@ {% load dajaxice_templatetags %} - Shaastra 2013 - {% dajaxice_js_import %} + Shaastra 2013 | Core Dashboard +{% dajaxice_js_import %} + + + + + + + + - Welcome {{ request.user }} | {{ request.user.groups.get_query_set.1 }} core
            - Logout - Edit Profile - Change Password -
            +
            +

            -
            -
            +
            +
            +
            -
            +
            +
            +
            + + + + + +
            + Space for displaying forms +
            + +
            +
            +
            +
            +
            diff --git a/templates/dtvpicker/SubeventPages/addEditSubEvent.html b/templates/dtvpicker/SubeventPages/addEditSubEvent.html index f94b4cd..6636469 100644 --- a/templates/dtvpicker/SubeventPages/addEditSubEvent.html +++ b/templates/dtvpicker/SubeventPages/addEditSubEvent.html @@ -13,13 +13,13 @@ {% block dtvBody %}

            {% ifequal form_mode 'add' %} - Add Sub-Event: +

            Add Sub-Event:

            {% else %} - Edit Sub-Event "{{ subeventRequested.title }}": +

            Edit Sub-Event "{{ subeventRequested.title }}":

            {% endifequal %}

            {% if form.errors %} -

            +

            Please correct the error{{ form.errors|pluralize }} below.

            {% endif %} @@ -31,13 +31,13 @@
            {% ifequal form_mode 'add' %} - + {% else %} - + {% endifequal %} - Cancel + Cancel {% endblock %} diff --git a/templates/dtvpicker/SubeventPages/deleteSubEvent.html b/templates/dtvpicker/SubeventPages/deleteSubEvent.html index 31e8562..ed96923 100644 --- a/templates/dtvpicker/SubeventPages/deleteSubEvent.html +++ b/templates/dtvpicker/SubeventPages/deleteSubEvent.html @@ -11,7 +11,7 @@ Are you sure you want to delete the following sub-event?

            - +
            @@ -34,9 +34,9 @@ {% csrf_token %} - + - No. Don't delete sub-event. + No. Don't delete sub-event. {% endblock %} diff --git a/templates/dtvpicker/SummaryPages/CoordDTVSummary_ByEvent.html b/templates/dtvpicker/SummaryPages/CoordDTVSummary_ByEvent.html index 0a3aa72..c719efd 100644 --- a/templates/dtvpicker/SummaryPages/CoordDTVSummary_ByEvent.html +++ b/templates/dtvpicker/SummaryPages/CoordDTVSummary_ByEvent.html @@ -3,22 +3,21 @@ {% block eventActions %} {% ifequal event.lock_status 'locked' %}

            LOCKED

            - {% else %} - Add Sub-Event -
            + {% else %} + Add Sub-Event {% for event, subEventList in happenings %} {# There will be only one tuple here (only one event) #} - {% ifequal event.lock_status 'not_locked' %} - Lock Event + {% ifequal event.lock_status 'not_locked' %} + Lock Event {% endifequal %} {% endfor %} {% endifequal %} -
            +

            {% endblock %} {% block subEventActions %} {% ifnotequal event.lock_status 'locked' %} - - + + {% endifnotequal %} {% endblock %} @@ -26,7 +25,7 @@

            LOCKED

            {% for event, subEventList in happenings %} {# There will be only one tuple here (only one event) #} {% ifequal event.lock_status 'unlocked_by_core' %}

            - Your event has been unlocked by the cores.
            +

            Your event has been unlocked by the cores.


            Reason: {{ event.unlock_reason }}

            diff --git a/templates/dtvpicker/SummaryPages/CoreDTVSummary_ByDate.html b/templates/dtvpicker/SummaryPages/CoreDTVSummary_ByDate.html index 55aa7bb..a489b14 100644 --- a/templates/dtvpicker/SummaryPages/CoreDTVSummary_ByDate.html +++ b/templates/dtvpicker/SummaryPages/CoreDTVSummary_ByDate.html @@ -1,7 +1,7 @@ {% extends "dtvpicker/dtvBase.html" %} {% block dtvTitle %} - Summary | By Date +

            Summary | By Date

            {% endblock %} {% block onScreenPageTitle %} DTV Summary (By Date) {% endblock %} @@ -10,7 +10,7 @@ {% for date, subEventList in happeningsByDate %}

            {{ date|date:"D, d M Y" }}

            {% if subEventList %} -
            Sub-Event Start Date
            Edit Delete EditDelete
            +
            @@ -40,10 +40,10 @@

            {{ date|date:"D, d M Y" }}



            - Go back to the DTV Summary Landing + Go back to the DTV Summary Landing {% if enablePDFPrinting %} - or print these details as PDF. + or print these details as PDF. {% endif %}
            diff --git a/templates/dtvpicker/SummaryPages/CoreDTVSummary_ByEvent.html b/templates/dtvpicker/SummaryPages/CoreDTVSummary_ByEvent.html index 94099fa..4687913 100644 --- a/templates/dtvpicker/SummaryPages/CoreDTVSummary_ByEvent.html +++ b/templates/dtvpicker/SummaryPages/CoreDTVSummary_ByEvent.html @@ -1,14 +1,14 @@ {% extends "dtvpicker/SummaryPages/dtvSummary.html" %} {% block dtvTitle %} - Summary | By Event +

            Summary | By Event

            {% endblock %} {% block onScreenPageTitle %} DTV Summary (By Event) {% endblock %} {% block eventActions %} {% ifequal event.lock_status 'locked' %} - Unlock Event + Unlock Event {% else %}
            AWAITING LOCK
            {% endifequal %} @@ -17,11 +17,12 @@
            AWAITING LOCK
            {% block miscActions %}

            {% if enablePDFPrinting %} - Go back to the DTV Summary Landing - or print these details as PDF. + Go back to the DTV Summary Landing + or print these details as PDF. {% else %} - View DTV Summary By Venue
            - View DTV Summary By Date + View DTV Summary By Venue + View DTV Summary By Date {% endif %}

            -{% endblock %} + +{% endblock %} \ No newline at end of file diff --git a/templates/dtvpicker/SummaryPages/CoreDTVSummary_ByVenue.html b/templates/dtvpicker/SummaryPages/CoreDTVSummary_ByVenue.html index 91dab4f..db5ca7e 100644 --- a/templates/dtvpicker/SummaryPages/CoreDTVSummary_ByVenue.html +++ b/templates/dtvpicker/SummaryPages/CoreDTVSummary_ByVenue.html @@ -1,7 +1,7 @@ {% extends "dtvpicker/dtvBase.html" %} {% block dtvTitle %} - Summary | By Venue +

            Summary | By Venue

            {% endblock %} {% block onScreenPageTitle %} DTV Summary (By Venue) {% endblock %} @@ -10,7 +10,7 @@ {% for venue, subEventList in happeningsByVenue %}

            {{ venue }}

            {% if subEventList %} -
            Event Sub-Event
            +
            @@ -40,10 +40,10 @@

            {{ venue }}



            - Go back to the DTV Summary Landing + Go back to the DTV Summary Landing {% if enablePDFPrinting %} - or print these details as PDF. + or print these details as PDF. {% endif %}
            diff --git a/templates/dtvpicker/SummaryPages/DTVLanding.html b/templates/dtvpicker/SummaryPages/DTVLanding.html index 7b83966..27ae504 100644 --- a/templates/dtvpicker/SummaryPages/DTVLanding.html +++ b/templates/dtvpicker/SummaryPages/DTVLanding.html @@ -11,22 +11,22 @@ You are seeing this page because all events are locked and cannot be modified further until they are unlocked by the Core team.

            Use the following links to see / generate PDFs for the events' DTV Summary: -
            Event Sub-Event
            +
            - - + + - - + + - - + +
            View Print PDF
            By Event Print PDF By Event Print PDF
            By Venue Print PDF By Venue Print PDF
            By Date Print PDF By Date Print PDF

            diff --git a/templates/dtvpicker/SummaryPages/dtvSummary.html b/templates/dtvpicker/SummaryPages/dtvSummary.html index 216583d..9eb7e71 100644 --- a/templates/dtvpicker/SummaryPages/dtvSummary.html +++ b/templates/dtvpicker/SummaryPages/dtvSummary.html @@ -12,7 +12,7 @@

            {{ event }}

            {% block eventActions %} {% endblock %} {% if subEventList %} - +
            @@ -21,6 +21,7 @@

            {{ event }}

            + {% for subEvent in subEventList %} diff --git a/templates/dtvpicker/dtvBase.html b/templates/dtvpicker/dtvBase.html index 2de164c..1acbcac 100644 --- a/templates/dtvpicker/dtvBase.html +++ b/templates/dtvpicker/dtvBase.html @@ -5,8 +5,24 @@ DTV | {% block dtvTitle %}{% endblock %} - + + + + + +

            {% block onScreenPageTitle %} {% endblock %}

            - {% block dtvBody %} {% endblock %} + {% block dtvBody %} {% endblock %}

            + Home +
            diff --git a/templates/email/activate.html b/templates/email/activate.html index e4dcdb9..29c4384 100644 --- a/templates/email/activate.html +++ b/templates/email/activate.html @@ -9,6 +9,8 @@ Your login username is {{ username }} and password is as you entered when you registered. +If you would like world class internships to be delivered in your inbox, visit www.internshala.com + Cheers, The Shaastra WebOps Team diff --git a/templates/events/contacts.html b/templates/events/contacts.html new file mode 100644 index 0000000..917c0da --- /dev/null +++ b/templates/events/contacts.html @@ -0,0 +1,187 @@ +{% extends "base.html" %} +{% block hash_handler %} + $(function(){ + // Keep a mapping of url-to-container for caching purposes. + var cache = { + // If url is '' (no fragment), display this div's content. + '': $('.bbq-default') + }; + + // Bind an event to window.onhashchange that, when the history state changes, + // gets the url from the hash and displays either our cached content or fetches + // new content to be displayed. + $(window).bind( 'hashchange', function(e) { + + // Get the hash (fragment) as a string, with any leading # removed. Note that + // in jQuery 1.4, you should use e.fragment instead of $.param.fragment(). + var url = $.param.fragment(); + $( '.bbq-item,.bbq-default' ).hide(); + if(!url) { + $('.bbq-default').show(); + return; + } + var event_name=url.split('/tab')[0]; + if(cache[event_name]) { + var event = cache[event_name]; + if(cache[url]) { + event.find(".tabtext").html(cache[url]); + } else { + event.find(".tabtext").load("{{site_url}}"+url, function(){ + // Content loaded, hide "loading" content. + $( '.bbq-loading' ).hide(); + resetabs(); + cache[url] = event.find(".tabtext").html(); + }); + } + event.show(); + } else { + cache[event_name] = $( '
            ' ).appendTo( '.bbq-content' ); + + // Load external content via AJAX. Note that in order to keep this + // example streamlined, only the content in .infobox is shown. You'll + // want to change this based on your needs. + cache[event_name].load("{{site_url}}"+event_name, function(){ + + cache[event_name].find(".tabtext").load( "{{site_url}}"+url, function(){ + // Content loaded, hide "loading" content. + $( '.bbq-loading' ).hide(); + resetabs(); + cache[url] = cache[event_name].find(".tabtext").html(); + }); + }); + } + }) + $(window).trigger('hashchange'); + }); +{% endblock %} +{% block footer %} + + + + +{% endblock %} +{% block content %} +
            +
            + + + + +
            +
            +
            +
          • Student In-Charge

          • +
          • Sohan Jawale : +91-9952936437
          • +
          • cas@smail.iitm.ac.in


          • +
          • Sponsorship

          • +
          • Asha Chigurapati : +91-9543987685;
          • +
          • asha@shaastra.org
          • +
          • Tejas Balasubramanya : +91-8939336379
          • +
          • tejas@shaastra.org


          • +
          • Student Relations

          • +
          • Syamantak Basu : +91-9962265947
          • +
          • syamantak@shaastra.org
          • +
            +
            +
            +
            +
            +
            +
            +{% endblock %} +{% block events_menu %} + {% for city in city_set %} + + {% endfor %} +{% endblock %} diff --git a/templates/events/dashboard.html b/templates/events/dashboard.html deleted file mode 100644 index 6c7bc6f..0000000 --- a/templates/events/dashboard.html +++ /dev/null @@ -1,178 +0,0 @@ - -{% load dajaxice_templatetags %} - - - - - - - - -{% dajaxice_js_import %} - - -

            Welcome {{request.user}} | {{request.user.get_profile.is_coord_of.title}} coord

            -Logout -

            -{% csrf_token %} -Questions -Mobile App Writeup -Submissions -


            -
            - {% for tab in tabs %} - {{tab.title}} - {% endfor %} -
            -add a tab -

            -

            - - \ No newline at end of file diff --git a/templates/events/deregister_singular_event.html b/templates/events/deregister_singular_event.html new file mode 100644 index 0000000..5b84333 --- /dev/null +++ b/templates/events/deregister_singular_event.html @@ -0,0 +1,14 @@ +{% extends "events/registration_base.html" %} + +{% block body %} +

            + To deregister, click the button.
            +

            + + {% csrf_token %} + + + + Stay Registered + +{% endblock %} diff --git a/templates/events/deregistration_done.html b/templates/events/deregistration_done.html new file mode 100644 index 0000000..9eab576 --- /dev/null +++ b/templates/events/deregistration_done.html @@ -0,0 +1,7 @@ +{% extends "events/registration_base.html" %} + +{% block body %} + +

            Your registration for this event has been canceled.

            + +{% endblock %} diff --git a/templates/events/events.html b/templates/events/events.html new file mode 100644 index 0000000..822b87d --- /dev/null +++ b/templates/events/events.html @@ -0,0 +1,94 @@ +
            +
            +

            {{event.title|cut:"H_"|cut:"B_"|cut:"P_"|cut:"C_"|cut:"Ch_"}}

            +
              + {% for tab in tab_set %} +
            • {{tab.title}}

            • + {% endfor %} + {% if user.is_authenticated %} + {% if event.has_tdp == 1 and event.begin_registration == 1 %} +
            • Submit TDP

            • + + {% endif %} + {% endif %} +
            +
            +
            +
            + {% for tab in tabs %} +
            +
            + +

            + {{tab.0.text|safe}} + {% if tab.1 %} +


            + Downloads:
            + + {% endif %} +

            +
            +
            + {% endfor %} +
            +
            +
            +
            +

            Announcements

            + {% if event.begin_registration %} + Registrations are now open. Click to register. + {% endif %} + {% for a in announcements %} + {% if a.event == event and a.expired == 0 %} +

            {{a.subject}} - {{a.description}}

            + {% endif %} + {% if forloop.last %}
            {% endif %} + {% endfor %} + + {% for u in updates %} + {% if forloop.first %} +

            Updates

            + {% endif %} + {% if u.event == event and u.expired == 0 %} +

            {{u.subject}} - {{u.description}}

            + {% endif %} + {% endfor %} +
            +
            +
            + diff --git a/templates/events/events_home.html b/templates/events/events_home.html new file mode 100644 index 0000000..6959131 --- /dev/null +++ b/templates/events/events_home.html @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/templates/events/eventsa.html b/templates/events/eventsa.html new file mode 100644 index 0000000..e176c6e --- /dev/null +++ b/templates/events/eventsa.html @@ -0,0 +1,24 @@ +{% extends "index.html" %} +{% block event %} +
            +
            +
            {{event.title}}
            + +
            +
            Click on a tab to view it +
            + +
            +

            Announcement

            +
            +

            Updates

            +
            +
            +{% endblock %} diff --git a/templates/events/register_offline.html b/templates/events/register_offline.html new file mode 100644 index 0000000..9ee3959 --- /dev/null +++ b/templates/events/register_offline.html @@ -0,0 +1,7 @@ +{% extends "events/registration_base.html" %} + +{% block body %} + +

            This event does not allow online registrations. The registrations for this event will be done on the spot.

            + +{% endblock %} diff --git a/templates/events/register_singular_event.html b/templates/events/register_singular_event.html new file mode 100644 index 0000000..dc965e2 --- /dev/null +++ b/templates/events/register_singular_event.html @@ -0,0 +1,14 @@ +{% extends "events/registration_base.html" %} + +{% block body %} +

            + To register, click the button.
            +

            + + {% csrf_token %} + + + + Cancel + +{% endblock %} diff --git a/templates/events/registration_base.html b/templates/events/registration_base.html new file mode 100644 index 0000000..c73256b --- /dev/null +++ b/templates/events/registration_base.html @@ -0,0 +1,50 @@ + + +Single Register + + + + + +
            + +
            +
            + +{% block body %} +{% endblock %} +
            +
            + + diff --git a/templates/events/registration_done.html b/templates/events/registration_done.html new file mode 100644 index 0000000..fc40492 --- /dev/null +++ b/templates/events/registration_done.html @@ -0,0 +1,12 @@ +{% extends "events/registration_base.html" %} + +{% block body %} + +

            {{registration_done_message}}

            + +

            Click + Cancel + to cancel the Registeration. +

            + +{% endblock %} diff --git a/templates/events/registration_not_started.html b/templates/events/registration_not_started.html new file mode 100644 index 0000000..2742676 --- /dev/null +++ b/templates/events/registration_not_started.html @@ -0,0 +1,7 @@ +{% extends "events/registration_base.html" %} + +{% block body %} + +

            The registrations for this event have not yet started. Stay tuned for more updates. Please note that the registrations for this event will be online.

            + +{% endblock %} diff --git a/templates/events/sampark_home.html b/templates/events/sampark_home.html new file mode 100644 index 0000000..19354d4 --- /dev/null +++ b/templates/events/sampark_home.html @@ -0,0 +1,214 @@ +{% extends "base.html" %} +{% block hash_handler %} + +{% endblock %} +{% block footer %} + + + +{% endblock %} +{% block content %} +
            +
            + + + +
            +
            +
            Move your pointer over each city picture for the corresponding events list. Click on each event for details
            +
            +

            Samparks are a series of workshops, events, lectures and qualifiers that are held at cities across India in an effort to bring Shaastra closer to everyone. This year, with new and improved events that assure wildcard entries, never before seen demonstrations and much more , the Samparks in your city are something that you can not afford to miss!

            +
            Sub-Event Start Date End Time Venue Last Modified Actions
            + + + + + + + + + + + + + + + + + +
            Sampark Chennai +
            Robotics Workshop, IIT MadrasHovercraft Workshop, IIT Madras
            + IBot, Robotics club of IIT Madras presents you the chance to learn Autonomous Robotics. A one day workshop participants are given a hands-on experience of building line follower bot using Arduino development platform. Did you ever dream of coding a Robot and got stuck as a beginner! Then here is your chance to dive into the world of robotics. + + This Shaastra, we give you a chance to take a leap into the world of aerobotics. Learn how a hovercraft is built from scratch, and get the confidence to go ahead and build or modify your hovercraft to new levels.The workshop is aimed for amateurs in aerobotics and is a rare opportunity for teams to make a hovercraft hands-on and also get to know the principles behind this craft’s mechanisms and electronics. +
            Registrations are now open. Limited seats available! Use the links below to register as early as possible.
            +

            + + + +

            +
            + + +{% endblock %} +{% block events_menu %} + {% for city in city_set %} + + {% endfor %} +{% endblock %} + + + diff --git a/templates/events/tabs.html b/templates/events/tabs.html new file mode 100644 index 0000000..011fc41 --- /dev/null +++ b/templates/events/tabs.html @@ -0,0 +1,11 @@ +{{tab.text|safe}} + +{% if file_set %} +
            + Downloads:
            + +{% endif %} diff --git a/templates/events/team_deregister.html b/templates/events/team_deregister.html new file mode 100644 index 0000000..c8d7487 --- /dev/null +++ b/templates/events/team_deregister.html @@ -0,0 +1,11 @@ +{% extends "events/registration_base.html" %} + +{% block body %} + +

            This event is a team event. To deregister from a team event you may:

            +
              +
            • Leave the team you are currently a part of.
            • +
            • Dissolve your team (only if you are the leader).
            • +
            + +{% endblock %} diff --git a/templates/events/team_registration_done.html b/templates/events/team_registration_done.html new file mode 100644 index 0000000..933e618 --- /dev/null +++ b/templates/events/team_registration_done.html @@ -0,0 +1,7 @@ +{% extends "events/registration_base.html" %} + +{% block body %} + +

            You are already registered for this event as a part of the team {{userTeam.name}}

            + +{% endblock %} diff --git a/templates/events/team_registration_required.html b/templates/events/team_registration_required.html new file mode 100644 index 0000000..cdb74c1 --- /dev/null +++ b/templates/events/team_registration_required.html @@ -0,0 +1,10 @@ +{% extends "events/registration_base.html" %} + +{% block body %} + +

            This event is a team event. You need to form a team to register for this event.

            +

            To form a team + click here. +

            + +{% endblock %} diff --git a/templates/fb/channel.html b/templates/fb/channel.html new file mode 100644 index 0000000..0915335 --- /dev/null +++ b/templates/fb/channel.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/fb/hero.html b/templates/fb/hero.html new file mode 100644 index 0000000..8dd09bc --- /dev/null +++ b/templates/fb/hero.html @@ -0,0 +1,17 @@ +
            + +

            Shaastra is the annual technical festival of IIT Madras. It is the largest technical fest of its kind in India and has the distinction of being the first ISO 9001:2008 certified student-organized event in the world. +

            + +
            +
            \ No newline at end of file diff --git a/templates/fb/home.html b/templates/fb/home.html new file mode 100644 index 0000000..09044c2 --- /dev/null +++ b/templates/fb/home.html @@ -0,0 +1,253 @@ +{% load dajaxice_templatetags %} + + + Shaastra + + + + + + + + + + + +
            + +
            +
            + +

            +
            +
            + +
            +
            +
            + +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            + + + + + + + + + + + + + + + + + + + + + + diff --git a/templates/fb/sampark.html b/templates/fb/sampark.html new file mode 100644 index 0000000..53ed47f --- /dev/null +++ b/templates/fb/sampark.html @@ -0,0 +1,18 @@ +
            +
            +

            Sampark @ {{place}}

            +
            + +
            +
            +
            \ No newline at end of file diff --git a/templates/home.html b/templates/home.html deleted file mode 100644 index 1b1dfc4..0000000 --- a/templates/home.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - Shaastra 2013 - - - {% if user.is_authenticated %} -

            Welcome {{ user.first_name }},

            - {% if user.get_profile.facebook_id %} -
            - {% else %} - Change Password - {% endif %} - Edit Profile - Logout -
            - {% else %} - Login - {% endif %} - - \ No newline at end of file diff --git a/templates/hospi/hospi_home.html b/templates/hospi/hospi_home.html new file mode 100644 index 0000000..2438b40 --- /dev/null +++ b/templates/hospi/hospi_home.html @@ -0,0 +1,299 @@ + +
            +
            + +
            +
            +
            +
            +

            On behalf of the entire Shaastra team, we would like to extend a warm welcome to you and hope that you cherish each and every moment of your stay at the beautiful campus of IIT Madras. Shaastra, the annual technical festival of IIT Madras, is undeniably one of the largest technical festivals of India having achieved huge feats with unparalleled figures ever since its inception in 2000. It provides a unique platform for young minds to stretch their imaginations to the limit and exhibit their skills across a multitude of technically challenging, arduous and thought provoking events traversing all fields of engineering. A festival of this magnitude naturally implies a humungous turn up of participants. We, the Hospitality team at Shaastra have pledged to leave no stone unturned to ensure that your stay with us is enjoyable and comfortable. Hospitality of the guests is of paramount importance to us.

            +

            IIT Madras is commonly referred to as ‘Land of stationary rivers and moving mountains’ +thanks to the hostel names, based on Indian rivers. It is situated on Sardar Patel Road and is +flanked by Adyar, Taramani and Velachery. The campus is opposite to the Central Leather +Research Institute and Anna University and is spread over 630 acres of lush green forest. One +could go on a bird-watching spree and spot exotic species nesting in the forest cover. Be it the +lush-green Chemplast Cricket stadium or the extensive grazing grounds for the deer in the +campus or the magnificent lake in the forest, the campus could well be a destination for all you +nature-lovers out there!

            +

            Hope to see you here at Shaastra 2013. We will be more than happy to be able to address your +suggestions and queries.

            +
            +
            +
            +
            +
            +

            The campus is midway between the Chennai Airport and the Central Railway station. It is 12 +kms from the Central Railway station, Chennai Airport and the central bus depot and is well connected by buses.

            + +

            A. From Chennai Central Station

            + +

            The Shaastra team will be sending Institute buses to receive participants at Chennai Central. +The representatives of the Hospitality department will be present to greet you near the exit +of the station. Timings of the buses will be communicated to you.

            +

            Alternately if you are unable to come through Institute buses, other means of transportation +are readily available in the city at all times.

            +
              +
            • Local train-If you do not have heavy luggage, the MRTS Station called "Park Town" on +the Beach-Velachery line, opposite to Chennai-Central station, is a good option. From +there, you can take a train to Kasturba Nagar (Adyar) and walk to campus main gate +from the station. From the gate there are IITM buses to the hostels, every 20 minutes.
            • +
            • +Local Bus-If you are traveling with light luggage, you can take a city bus to IIT. The bus +stop is opposite to the Central Station. The direct buses to the campus are 19B and 5C. +Alternatively, one can take a bus to Saidapet from central and from there to Adyar signal +followed by a bus to the main gate of the Institute.
            • + +

              Given are a list of buses you can take to reach IITM

              + +
            • Auto/Taxi- There is a good and efficient prepaid taxi service operated by the Chennai +Police available at the Central Station. The booth for the prepaid taxi is just outside +platform no.11. Alternately you can call private taxi services like Fast track. The fare will +be roughly Rs.350-380 for a Taxi and Rs.200-250 for an Auto-rickshaw.
            • +
            +

            B. From Chennai Egmore train station

            +
              +
            • Local Train- Participants arriving at Egmore station can board a local train from +platform 7 or 8 to “Park” station (the next stop). At Park please change trains and board +a train on the Beach-Velachery line and get down at Kasturba Nagar Station. The main +gate of the campus is at walking distance from the station.
            • + +
            • Local Bus-You can catch the MTC bus no. 23C which heads directly to IITM. From the +main gate there are IITM buses to the hostels, every 20 minutes.
            • + +
            • Auto/Taxi- If you have heavy luggage we would advise you hire an auto/taxi. Autos +and taxis are available outside the station. Also you can call private taxi services like +fast-track to pick you up outside the station. The auto and taxi fares from Egmore are +approximately Rs.200 and Rs.250-300 respectively.
            • +
            +

            C. From Airport

            +

            To reach the campus from the airport you can hire a Taxi from counters located outside the +airport terminal or catch a local train/bus.

            +
              +
            • Local Train- If you are travelling with light luggage then you could prefer to take a local +train. Board a train on the Tambaram line from Tirusulam Railway station nearby the +airport and travel to “Park” station. Change trains there and board a train on the Beach- +Velachery line to Kasturba Nagar Railway Station which is very near to the Institute +main gate.
            • +
            • Taxi- There are three options:
            • +
                +
              1. A state-government pre-paid taxi, which is quite efficient, with old ambassadors + for about Rs. 350.
              2. +
              3. There are private operators:
              4. +
              +
                +
              • Aviation express, which operates new Taveras and Innovas for Rs. 450-500.
              • +
              • Fast track, which operates Indicas and Indigos for about Rs. 400.
              • +
              +
            • Local bus-Alternatively you can catch the bus PP21 directly to Institute or 21G to Gandhi Mandapam +which is very near from the main gate of the campus. IITM buses depart every 20 minutes +from the main gate to the Gajendra circle.
            • +
            +

            D. From CMBT (Chennai Mofussil Bus Terminus)

            +

            You can catch bus number 23M or 5E which will drop you off near to the Institute main gate. +You can also hire an auto/taxi for a fare of around Rs.250/300 respectively. From the main gate +there are IITM buses to the hostels, every 20 minutes.

            +

            Given are approximate fares from the above mentioned sources to IIT Madras and +contact numbers and basic tariff structure of a few call taxi operators in Chennai.

            + +
            +
            +
            +
            +

            The Hospitality team at Shaastra is dedicated to help you and attend to all your doubts and +queries throughout your stay with us. Apart from our Reception Desk, the Shaastra Desk - +which forms an indispensable part of Shaastra, will be set up close to the festive area in +order to disseminate information and share the latest news regarding events. It is also the +one stop center to answer all your queries. You can also approach the Shaastra Desk for +other information like updates, event results, daily events, etc. Also, registration for some +of the events takes place at the Shaastra Desk. Please consult the Shaastra website for more +information on the events that have on the spot registration on the Shaastra Desk. For event +registration at the Shaastra Desk, production of the Shaastra ID card is mandatory. The +Shaastra Desk will be functional throughout the day between 9 A.M. to 5 P.M. In case you +have queries and are not nearby the Shaastra Desk or the Reception Desk, you can call us at +the Shaastra Desk on the Hospitality Helpline number. Calls on the helpline number will be +entertained only during the timings when the Shaastra Desk is operational.

            +
            +
            +
            +
            +

            Because of limited space on campus, we might not be able to provide accommodation to +all participants who apply for accommodation. In case you don't receive a confirmation +mail regarding your accommodation from the Hospitality team, you could always make +arrangements for your stay outside campus. We have uploaded a list of hotels and lodges for +your reference

            +
            +
            +
            +
            +

            The Institute in itself is located around 2.5 kms inside the campus. Two parallel roads, Bonn +Avenue and Delhi avenue, lead you through the residential zone, under a canopy of green, to +Gajendra Circle (otherwise called GC) and the administrative block. Buses ply between the +gate and other locations on campus at regular intervals. The IITM buses take you to the GC, +academic zone and hostels. We at Shaastra; strive to make your stay with us, as pleasant and +comfortable as we can. Upon reaching the IIT Madras campus, participants are requested to +report to the Reception Desk, which will be operational throughout Shaastra (except from +6:30 P.M. to 8:30 P.M. on all days). Participants will be requested to produce all necessary +documents at the Reception Desk; nominal charges for accommodation will be collected here +depending on the number of days you wish to avail this facility. The Reception Desk will close +on the afternoon of the final day of Shaastra. All participants are required to carry their SAAR +(Shaastra Advanced Accommodation Registration) letter which will be mailed to people whose +accommodation is confirmed along with photocopies of their College IDs and Bonafide +Certificates from their college to avail the accommodation facilities. Participants are also +expected to follow certain Rules and Regulations to help us maintain the decorum in the +Institute as mentioned in the SAAR. To participate in any event at Shaastra, you would need to +report to the Shaastra Desk and a passport will be issued to you.

            +
            +
            +
            +
            +

            When can I enter the IITM campus?

            +

            The Institute main gate will be open at all times. You may enter and depart from the campus at +all times. But, please make sure to carry your college id cards for purpose of security check at +the main gate.

            + +

            What should I do after coming to the campus?

            +

            Outstation participants who have registered for accommodation and received a confirmation +regarding the same are requested to report to the Reception Desk where the required +formalities involving checking of documents and allotment of rooms will be finished. We +shall not be providing accommodation for local participants. All the participants who are +accommodated at IITM are supposed to collect their Shaastra ID Cards from the Hospitality +team.

            + +

            What should I bring with me?

            +

            1. It is mandatory for all participants to carry College IDs AND Bonafide certificates issued by +your college.

            +

            2. If your accommodation is confirmed, you are required to bring a hard copy of the Shaastra +Advanced Accommodation Registration (SAAR) letter which will be mailed to you.

            +

            3. Participants are requested to carry your own locks. Please make sure that the locks you get +should have at least 3 keys.

            +

            4. Mattresses and pillows shall be provided to you if your accommodation is confirmed. +Participants will have to bring their own things which they require for the events in which they +are participating.

            + +

            What about the accommodation facilities?

            +

            Accommodation to participants will be provided to outstation participants if they have applied +for accommodation on the Shaastra website and their accommodation has been approved by +us. The rooms will be allotted on a sharing basis due to space constraints. The participants who +have not been confirmed for accommodation are requested to arrange for their stay outside +the Institute in Hotels or lodges. A list of Hotels and lodges in Chennai has been provided in the +“Alternate Accommodation” tab.

            + +

            Will all the team members be given accommodation at the same place?

            +

            We will strive for that; but we do not guarantee it.

            + +

            What about the charges for accommodation?

            +

            A nominal payment will have to be made by the participants for accommodation while +registering at Reception Desk. Please note that in case some of your team mates have not been +confirmed for accommodation then the charges for accommodation will be applicable to only +those team mates who have been provided accommodation.

            + +

            Can we adjust the remaining team members of our team in the space provided to us?

            +

            No, the members of your team who have not been provided accommodation cannot stay in +your allotted rooms. They are requested to stay at nearby hotels or lodges outside the campus. +Security checks will be done and defaulters will be penalized.

            + +

            What about the eating facilities?

            +

            A variety of food stalls shall be set up in the heart of the festive area which will cater to all your +food requirements. Apart from that, there are other eating outlets in and around the campus +like Cafe Coffee Day, Tiffany's Tiffin centre, Campus Cafe, Zaitoon restaurant & Gurunath.

            + +

            What about the Hospital facility?

            +

            There is an Institute Hospital located close to Gajendra Circle. In case you fall ill or any of your +team-mates meet with any accident, you are advised to report to us at Reception +Desk immediately. We shall make appropriate arrangements for emergencies to be treated at +the Institute Hospital.

            + +

            What about the security facilities?

            +

            IITM campus has a vigilant and round-the-clock security service. To ensure the safety of the +participants, there will be additional security guards in hostels in order to avoid thefts and +other mishaps. However, the Shaastra team will not take responsibility of any theft or other +mishaps. Therefore, participants are requested to take care of their belongings.

            + +

            What about certificates and prize money?

            +

            Prize winning teams will be given certificates and prize money, (if any) from the Prize and +Prize Money Desk (PPM Desk).The prize amount is event-specific and details can be found +out by visiting the events page on the Shaastra website. For some of the major events, all +participants qualifying to the final round will be issued certificates. If you do not win any prize, +participation certificates will be issued at the Shaastra Desk and the Reception Desks. Please +collect it when you leave.

            + +

            One of our team members who had been provided accommodation is unable to come; so +can we replace him with our other team member?

            +

            First, kindly get approval for replacement of your old team member from the coordinator of +the event in which your team member was supposed to participate. After consulting with the +event coordinator we will inform you whether we will be able to accommodate your new team +member. The new team member coming should have all the documents as mentioned above.

            + +

            Are there ATMs inside the campus?

            +

            There is a SBI branch and SBI, ICICI and Canara Bank ATMs inside the campus.

            + +

            Is there any internal transport keeping in mind the huge area of the campus?

            +

            Internal transportation is available inside the campus in form of buses that are available at +various bus stops located throughout the campus.

            + +

            Will there be any kind of transportation facility from airport/railway station to IIT-M +campus for participants?

            +

            Yes, we will be receiving participants from Chennai central via Institute buses several times a +day. The Hospitality team will be there to receive you. The timings for the buses will be updated +soon in this space.
            +We look forward to having you at Shaastra 2013 and hope that you have an amazing stay at our +beautiful campus!
            +
            +Still have unanswered queries? Check out www.forums.shaastra.org +

            +
            +
            +
            +
            +
              +
            • We shall provide you with mattresses. However, you are encouraged to carry +your own blankets since it might be a little cold at night.
            • + +
            • At the time of check-out the participants are required to return all the commodities +provided to them.
            • + +
            • Only those participants who have been given accommodation will be allowed to stay
            • + +
            • All student participants must carry their valid College photo ID card. Others must bring their +valid photo identity for the purpose of entry. People without valid photo identity card will +not be allowed inside the campus during Shaastra 2013.
            • + +
            • Alcohol, drugs and explosives of any kind are strictly prohibited inside the campus. Any +other item if deemed unsafe will be prohibited. The decision of Security and Shaastra team +will be final in case of any disputes.
            • + +
            • Kindly keep an eye on your belongings. The Shaastra team will not be responsible in case of any mishaps.
            • +
            +
            +
            +
            +
            +

            For Hospitality related queries, please feel free to reach out the Hospitality team at +hospitality@shaastra.org or paragmanudhane@shaastra.org

            +
            +

            Parag Manudhane,
            +Hospitality Core,
            +Shaastra 2013

            +
            +
            +
            +
            +
            + diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..e460e5e --- /dev/null +++ b/templates/index.html @@ -0,0 +1,164 @@ +{% extends "base.html" %} +{% block hash_handler %} + +{% endblock %} +{% block functions %}{% endblock %} +{% block events_menu %} + {% for category in event_set %} + + {% endfor %} +{% endblock %} +{% block footer %} + +{% endblock %} diff --git a/templates/login.html b/templates/login.html deleted file mode 100644 index c6346be..0000000 --- a/templates/login.html +++ /dev/null @@ -1,15 +0,0 @@ -{% if errors %} -

            Sorry, that's not a valid username or password

            - {% endif %} - -
            {% csrf_token%} - - - - - - - - - -
            diff --git a/templates/register.html b/templates/register.html deleted file mode 100644 index 4cf2c23..0000000 --- a/templates/register.html +++ /dev/null @@ -1,14 +0,0 @@ - - -
            Registration
            - -
            - {% csrf_token %} - - {{form.as_table}} -
            - - -
            - - diff --git a/templates/registration/password_change_done.html b/templates/registration/password_change_done.html new file mode 100644 index 0000000..68543a7 --- /dev/null +++ b/templates/registration/password_change_done.html @@ -0,0 +1,30 @@ + + +Password Change + + + + +{% load i18n %} +{% load url from future %} +{% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}{% trans 'Documentation' %} / {% endif %}{% endblock %} +
            +

            Password Change Successful

            + +
            + + \ No newline at end of file diff --git a/templates/registration/password_change_form.html b/templates/registration/password_change_form.html new file mode 100644 index 0000000..a178a45 --- /dev/null +++ b/templates/registration/password_change_form.html @@ -0,0 +1,65 @@ + + +Password Change + + + +{% load i18n adminmedia %} +{% load url from future %} + +{% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}{% trans 'Documentation' %} / {% endif %} {% endblock %} + +{% block content %}
            + +
            {% csrf_token %} +
            +{% if form.errors %} +

            + {% blocktrans count form.errors.items|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %} +

            +{% endif %} + +

            {% trans 'Password change' %}

            + +

            {% trans "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly." %}

            + +
            + +
            + {{ form.old_password.errors }} + {{ form.old_password }} +
            + +
            + {{ form.new_password1.errors }} + {{ form.new_password1 }} +
            + +
            +{{ form.new_password2.errors }} + {{ form.new_password2 }} +
            + +
            +

            +
            + + +
            + + +
            +
            + +
            + +{% endblock %} + + diff --git a/templates/registration/password_reset_complete.html b/templates/registration/password_reset_complete.html new file mode 100644 index 0000000..a69d223 --- /dev/null +++ b/templates/registration/password_reset_complete.html @@ -0,0 +1,28 @@ + + +Password Reset + + + +{% load i18n %} +
            {% trans 'Password reset complete' %} +

            {% trans "Your password has been set. You may go ahead and log in now." %}

            + + + \ No newline at end of file diff --git a/templates/registration/password_reset_confirm.html b/templates/registration/password_reset_confirm.html new file mode 100644 index 0000000..fcacd8e --- /dev/null +++ b/templates/registration/password_reset_confirm.html @@ -0,0 +1,42 @@ + + +Password Reset + + + + +{% load i18n %} + + + +
            +{% if validlink %} + +

            {% trans 'Enter new password' %}

            + +

            {% trans "Please enter your new password twice so we can verify you typed it in correctly." %}

            + +
            {% csrf_token %} +{{ form.new_password1.errors }} +

            {{ form.new_password1 }}

            +{{ form.new_password2.errors }} +

            {{ form.new_password2 }}

            +

            +
            + +{% else %} +
            +

            Password reset unsuccessful

            + +

            {% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}

            +
            +{% endif %} +
            + + \ No newline at end of file diff --git a/templates/registration/password_reset_done.html b/templates/registration/password_reset_done.html new file mode 100644 index 0000000..0f200ef --- /dev/null +++ b/templates/registration/password_reset_done.html @@ -0,0 +1,24 @@ + + +Password Reset + + + + +{% load i18n %} +
            +

            Password reset successful

            +

            Password reset successful

            +

            We've e-mailed you instructions for setting your password to the e-mail address you submitted. You should be receiving it shortly

            + +
            + + \ No newline at end of file diff --git a/templates/registration/password_reset_email.html b/templates/registration/password_reset_email.html new file mode 100644 index 0000000..de9dc79 --- /dev/null +++ b/templates/registration/password_reset_email.html @@ -0,0 +1,14 @@ +{% load i18n %}{% load url from future %}{% autoescape off %} +{% blocktrans %}You're receiving this e-mail because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %} + +{% trans "Please go to the following page and choose a new password:" %} +{% block reset_link %} +{{ protocol }}://{{ domain }}{% url 'django.contrib.auth.views.password_reset_confirm' uidb36=uid token=token %} +{% endblock %} +{% trans "Your username, in case you've forgotten:" %} {{ user.username }} + +{% trans "Thanks for using our site!" %} + +{% blocktrans %}The {{ site_name }} team{% endblocktrans %} + +{% endautoescape %} diff --git a/templates/registration/password_reset_form.html b/templates/registration/password_reset_form.html new file mode 100644 index 0000000..00ddc26 --- /dev/null +++ b/templates/registration/password_reset_form.html @@ -0,0 +1,28 @@ + + +Password Reset + + + + +{% load i18n %} +
            +

            {% trans "Password reset" %}

            + +

            {% trans "Forgotten your password? Enter your e-mail address below, and we'll e-mail instructions for setting a new one." %}

            + +
            {% csrf_token %} +{{ form.email.errors }} +

            {{ form.email }} +

            +
            + +
            + + \ No newline at end of file diff --git a/templates/spons_home.html b/templates/spons_home.html new file mode 100644 index 0000000..f1ae89a --- /dev/null +++ b/templates/spons_home.html @@ -0,0 +1,53 @@ +
            +
            + +
            +
            +
            +
            + + {% for s in present_sponsors %} + + + + + {% endfor %} +

            {{s.about}}

            {{s.url}}
            +
            +
            +
            +
            +
            +
            + + {% for s in previous_sponsors %} + + + + + {% endfor %} +

            {{s.about}}

            {{s.url}}
            +
            +
            +
            +
            +
            +
            + + {% for s in previous_sponsors2 %} + + + + + {% endfor %} +

            {{s.about}}

            {{s.url}}
            +
            +
            +
            +
            +
            +
            diff --git a/templates/submissions/submission.html b/templates/submissions/submission.html index 8350712..28d298f 100644 --- a/templates/submissions/submission.html +++ b/templates/submissions/submission.html @@ -1,61 +1,12 @@ - -{% load dajaxice_templatetags %} - - - - - -{% dajaxice_js_import %} - - - -
            Welcome {{request.user}}
            -{{event.title}}'s question list.
            -
            q_no
            -mcqs:
            +

            {{event.title}}'s question list.

            +mcqs: +
            {% for q in mcqs %} -
          • {{q.q_number}} +
          • {{q.q_number}}
          • {% endfor %}
            text:
            {% for q in subjectives %} -
          • {{q.q_number}} +
          • {{q.q_number}}
          • {% endfor %} -
            -
            q_detail
            - - +
            + diff --git a/templates/users/edit_profile.html b/templates/users/edit_profile.html index 22535d1..78caa6f 100644 --- a/templates/users/edit_profile.html +++ b/templates/users/edit_profile.html @@ -7,18 +7,101 @@ - + + + + + -

            - Edit profile: -

            -
            - {% csrf_token %} +
            + +
            + +

            Edit profile:


            +
            {% csrf_token %} {{ editProfileForm.as_table }} -
            - +
            + +
            - Home +
            + +
            diff --git a/templates/users/edit_profile_c.html b/templates/users/edit_profile_c.html new file mode 100644 index 0000000..4bcfe72 --- /dev/null +++ b/templates/users/edit_profile_c.html @@ -0,0 +1,47 @@ +{% load dajaxice_templatetags %} + + + Edit Profile + {% dajaxice_js_import %} + + + + + + + + + +
            +
            +
            +
            +

            Edit profile:


            +
            {% csrf_token %} + + {{ editProfileForm.as_table }} +

            + + Home +
            +
            +
            +
            + + diff --git a/templates/users/login.html b/templates/users/login.html index 6c74d45..9dd1c61 100644 --- a/templates/users/login.html +++ b/templates/users/login.html @@ -1,18 +1,193 @@ - - - - Shaastra 2013 - - - {{msg}} -
            - Login via Facebook - - {% csrf_token %} - {{form.as_table}} -
            - - Register -
            - - \ No newline at end of file + + +Shaastra - Log in + + + + + + +
            + +
            +

            {{msg}}

            +
            +
            + {% csrf_token %} + + +

            +

            + +

            forgot password

            +
            +
            + +
            + + + diff --git a/templates/users/register.html b/templates/users/register.html index 4af7d9e..fbf0a28 100644 --- a/templates/users/register.html +++ b/templates/users/register.html @@ -2,11 +2,134 @@ Shaastra 2013 + + {% dajaxice_js_import %} + + + + + + + + + + + - Register
            -
            +
            + +
            + +
            + +
            {% csrf_token %} {{ form.as_table }}
            +
            + + + - - Home - - + {% if captcha_response != "" %} +

            The words typed did not match the words in the image

            + {% endif %}
            + + +
            +
            + + - \ No newline at end of file + diff --git a/templates/users/teams/already_part_of_a_team.html b/templates/users/teams/already_part_of_a_team.html new file mode 100644 index 0000000..700e44c --- /dev/null +++ b/templates/users/teams/already_part_of_a_team.html @@ -0,0 +1,10 @@ +{% extends "users/teams/teams_base.html" %} + +{% block body %} + +

            There was an error while trying to add {{ user }} to the team. Please check the following:

            +

            1. {{ user }} is a valid user, who has registered through the Shaastra 2011 Registration page.

            +

            2. {{ user }} has activated his/her account

            +

            3. {{ user }} is not already a part of another team for the same event. In this case, he/she must drop out of the other team in order to create/join a new one.

            + +{% endblock %} diff --git a/templates/users/teams/create_team.html b/templates/users/teams/create_team.html new file mode 100644 index 0000000..df915b0 --- /dev/null +++ b/templates/users/teams/create_team.html @@ -0,0 +1,23 @@ +{% extends "users/teams/teams_base.html" %} + +{% block body %} + +
            +

            Create a team to participate in {{ event.title }}:

            +
            + {% csrf_token %} + + {{ form.as_table }} + +
            +
            + + + + +
            +
            +
            +
            + +{% endblock %} diff --git a/templates/users/teams/remove_members_first.html b/templates/users/teams/remove_members_first.html new file mode 100644 index 0000000..d9793f3 --- /dev/null +++ b/templates/users/teams/remove_members_first.html @@ -0,0 +1,7 @@ +{% extends "users/teams/teams_base.html" %} + +{% block body %} + +

            You can't dissolve the team until all members (other than you, of course) have been removed.

            + +{% endblock %} diff --git a/templates/users/teams/team_form.html b/templates/users/teams/team_form.html new file mode 100644 index 0000000..eaf3c53 --- /dev/null +++ b/templates/users/teams/team_form.html @@ -0,0 +1,29 @@ +{% extends "users/teams/teams_base.html" %} + +{% block body %} + + + +{% endblock %} diff --git a/templates/users/teams/team_home.html b/templates/users/teams/team_home.html new file mode 100644 index 0000000..b840ee4 --- /dev/null +++ b/templates/users/teams/team_home.html @@ -0,0 +1,159 @@ +{% extends "users/teams/teams_base.html" %} + +{% block media_location %} + + + +{% endblock %} + +{% block body %} +

            {{team.name}} Home

            +

            + {% ifequal team_size_message 'big' %} + Your team has too many members. The maximum number allowable is {{event.team_size_max}}. + {% else %} + {% ifequal team_size_message 'small' %} + Your team needs more members to participate. The minimum number required is {{event.team_size_min}}. + {% else %} + Your team is ready to participate in {{event.title}}. + {% endifequal %} + {% endifequal %} +

            +
            +

            Members:

            + {% if team.leader == user %} +

            Click to remove a member (you can't remove yourself this way)

            + {% endif %} + + + {% for member in team.members.all %} + {% if member != user %} + {% if team.leader == user %} + + + + + + + {% else %} + + + + {% endif %} + {% endif %} + {% endfor %} +
            You ({{request.user.username}})
            +
            + {{ member.username }} +
            +
            +
            + {% csrf_token %} + + +
            + + + + +
            +
            +
            +
            + {{ member.username }} +
            +
            +
            + +


            + + {% if team.leader == user %} +
            +

            Add a member:

            +
            + {% csrf_token %} + {{ add_member_form.member.errors }} + + {{ add_member_form.member }} + +

            +

            + + + + +
            +

            +
            +


            + {% else %} + +
            + {% csrf_token %} + +
            + Leave this team

            + {% endif %} + + {% if team.leader == user %} +
            +

            Change the team leader

            +
            + {% csrf_token %} + {{ change_leader_form.new_leader.errors }} + + {{ change_leader_form.new_leader }} + +
            + + + + +
            +
            +
            +
            + +

            + {% endif %} + +{% endblock %} diff --git a/templates/users/teams/teams_base.html b/templates/users/teams/teams_base.html new file mode 100644 index 0000000..d4cc63f --- /dev/null +++ b/templates/users/teams/teams_base.html @@ -0,0 +1,47 @@ + + +Team Register + + + + + + +
            +
            +
            +{% block body %} +{% endblock %} +
            +
            + + diff --git a/templates/users/teams/you_are_leader.html b/templates/users/teams/you_are_leader.html new file mode 100644 index 0000000..aecc273 --- /dev/null +++ b/templates/users/teams/you_are_leader.html @@ -0,0 +1,7 @@ +{% extends "users/teams/teams_base.html" %} + +{% block body %} + +

            You're the team, leader! You can't abandon your team! At least pass on leadership to someone else first...

            + +{% endblock %} diff --git a/templates/users/teams/you_arent_leader.html b/templates/users/teams/you_arent_leader.html new file mode 100644 index 0000000..06b48d4 --- /dev/null +++ b/templates/users/teams/you_arent_leader.html @@ -0,0 +1,7 @@ +{% extends "users/teams/teams_base.html" %} + +{% block body %} + +

            You are not the team leader, so you can't be doing this... Hey! How did you manage to get here anyway?

            + +{% endblock %} diff --git a/urls.py b/urls.py index 90c692e..325dfde 100644 --- a/urls.py +++ b/urls.py @@ -1,27 +1,68 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- from django.conf.urls.defaults import patterns, include, url +from django.views.generic.simple import direct_to_template from django.conf import settings +from settings import SITE_URL +from django.contrib.auth import views +from django.contrib.sites import * +from django.contrib.sitemaps import * +from sitemaps import * +from users.urls import * +from events.urls import * from dajaxice.core import dajaxice_autodiscover dajaxice_autodiscover() +from django.contrib import admin as superuser +superuser.autodiscover() -urlpatterns = patterns('', - url(r'^$', 'views.home', name = 'home'), +urlpatterns = patterns( + '', + url(r'^$', 'views.home', name='home'), + url(r'^spons', 'views.spons', name='spons'), url(r'^user/', include('users.urls')), url(r'^admin/', include('admin.urls')), url(r'^core/', include('core.urls')), - url(r'^coord/', include('events.urls')), + url(r'^coord/', include('coord.urls')), + url(r'^events/', include('events.urls')), + url(r'^fb/', include('fb.urls')), + url(r'^hospi/', 'views.hospi', name='hospi'), url(r'^submission/', include('submissions.urls')), url(r'^DTVPicker/', include('dtvpicker.urls')), - url(r'^%s/' % settings.DAJAXICE_MEDIA_PREFIX, include('dajaxice.urls')), -) + url(r'^%s/' % settings.DAJAXICE_MEDIA_PREFIX, + include('dajaxice.urls')), + url(r'^superuser/', include(superuser.site.urls)), + ) -urlpatterns += patterns('', - url(r'^media/(?P.*)$', 'django.views.static.serve', { - 'document_root': settings.MEDIA_ROOT, - }), -) +urlpatterns += patterns('', url(r'^media/(?P.*)$', + 'django.views.static.serve', + {'document_root': settings.MEDIA_ROOT})) -urlpatterns += patterns('django.views.static', - (r'^static/(?P.*)$', - 'serve', { - 'document_root': settings.STATIC_ROOT, - 'show_indexes': True }),) +urlpatterns += patterns('django.views.static', (r'^static/(?P.*)$' + , 'serve', + {'document_root': settings.STATIC_ROOT, + 'show_indexes': True})) + +base_url_name = '/2013/main/' +sitelist = [base_url_name, base_url_name + '#events/', base_url_name + + 'user/login/', base_url_name + 'events/sampark/', base_url_name +'#hospi/'] + +sitemaps = {'event': EventSitemap, 'sites': Sitemap, + 'pages': SiteSiteMap(sitelist)} + +# 'flatpages':FlatPageSitemap, +# 'editcoresitemap':EditCoreSiteMap(), +# 'editgroupsitemap':EditGroupSiteMap(), +# 'editgroupsitemap':Register_ActivateSiteMap(), +# 'addsubeventsitemap':AddSubEventSiteMap(), +# 'editsubeventsitemap':EditSubEventSiteMap(), +# 'deletesubeventsitemap':DeleteSubEventSiteMap(), +# 'lockeventsitemap':LockEventSiteMap(), +# 'unlockeventsitemap':UnlockEventSiteMap(), +# 'event_submissionsitemap':Event_SubmissionSiteMap() + +urlpatterns += patterns('', (r'^sitemap\.xml$', + 'django.contrib.sitemaps.views.sitemap', + {'sitemaps': sitemaps}), + (r'^sitemap-(?P
            .+)\.xml$', + 'django.contrib.sitemaps.views.sitemap', + {'sitemaps': sitemaps})) # ...... \ No newline at end of file diff --git a/users/ajax.py b/users/ajax.py index 20853bc..392564c 100644 --- a/users/ajax.py +++ b/users/ajax.py @@ -1,3 +1,5 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- from django.utils import simplejson from dajaxice.decorators import dajaxice_register from django.template import Template, Context, RequestContext, loader @@ -5,32 +7,35 @@ from users.forms import AddCollegeForm from users.models import College + @dajaxice_register -def college_register(request, form=""): - if form == "" : - template = loader.get_template('ajax/users/college_register.html') - coll_form=AddCollegeForm() - html=template.render(RequestContext(request,locals())) +def college_register(request, form=''): + if form == '': + template = \ + loader.get_template('ajax/users/college_register.html') + coll_form = AddCollegeForm() + html = template.render(RequestContext(request, locals())) dajax = Dajax() dajax.assign('#reg', 'innerHTML', html) return dajax.json() dajax = Dajax() coll_form = AddCollegeForm(form) if coll_form.is_valid(): - college=coll_form.cleaned_data['name'] - if college.find('&')>=0: - college = college.replace('&','and') - city=coll_form.cleaned_data['city'] - state=coll_form.cleaned_data['state'] - - if len(College.objects.filter(name=college, city=city, state=state))== 0 : - college=College (name = college, city = city, state = state) + college = coll_form.cleaned_data['name'] + if college.find('&') >= 0: + college = college.replace('&', 'and') + city = coll_form.cleaned_data['city'] + state = coll_form.cleaned_data['state'] + + if len(College.objects.filter(name=college, city=city, + state=state)) == 0: + college = College(name=college, city=city, state=state) college.save() - data = college.name+","+college.city - flag=1 + data = college.name + ',' + college.city + flag = 1 else: - flag=2 + flag = 2 else: - flag=0 + flag = 0 dajax.add_data(flag, 'reg_done') return dajax.json() diff --git a/users/context_processors.py b/users/context_processors.py index a525668..bc53d44 100644 --- a/users/context_processors.py +++ b/users/context_processors.py @@ -1,3 +1,9 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + + def site_url(request): from django.conf import settings - return {'site_url': settings.SITE_URL} \ No newline at end of file + return {'site_url': settings.SITE_URL} + + diff --git a/users/fb_views.py b/users/fb_views.py index d8fe1ec..b2dc80a 100644 --- a/users/fb_views.py +++ b/users/fb_views.py @@ -1,4 +1,8 @@ -import urllib, cgi,json +#!/usr/bin/python +# -*- coding: utf-8 -*- +import urllib +import cgi +import json from django.http import HttpResponseRedirect from django.shortcuts import * @@ -14,60 +18,76 @@ def login(request): """ First step of process, redirects user to facebook, which redirects to authentication_callback. """ - args = { - 'client_id': settings.FACEBOOK_APP_ID, - 'scope': settings.FACEBOOK_SCOPE, - 'redirect_uri': request.build_absolute_uri(settings.SITE_URL+'user/facebook/authentication_callback/'), - } + args = {'client_id': settings.FACEBOOK_APP_ID, + 'scope': settings.FACEBOOK_SCOPE, + 'redirect_uri': request.build_absolute_uri(settings.SITE_URL + + 'user/facebook/authentication_callback/')} + + return HttpResponseRedirect('https://www.facebook.com/dialog/oauth?' + + urllib.urlencode(args)) - return HttpResponseRedirect('https://www.facebook.com/dialog/oauth?' + urllib.urlencode(args)) def authentication_callback(request): """ Second step of the login process. It reads in a code from Facebook, then redirects back to the home page. """ + code = request.GET.get('code') - """ Reads in a Facebook code and asks Facebook if it's valid and what user it points to. """ args = { 'client_id': settings.FACEBOOK_APP_ID, 'client_secret': settings.FACEBOOK_APP_SECRET, - 'redirect_uri': request.build_absolute_uri(settings.SITE_URL+'user/facebook/authentication_callback/'), + 'redirect_uri': request.build_absolute_uri(settings.SITE_URL + + 'user/facebook/authentication_callback/'), 'code': code, - } + } # Get a legit access token - target = urllib.urlopen('https://graph.facebook.com/oauth/access_token?' + urllib.urlencode(args)).read() + + target = \ + urllib.urlopen('https://graph.facebook.com/oauth/access_token?' + + urllib.urlencode(args)).read() response = cgi.parse_qs(target) access_token = response['access_token'][-1] # access_token = authenticate(token=code, request=request) # Read the user's profile information - fb_profile = urllib.urlopen('https://graph.facebook.com/me?access_token=%s' % access_token) + + fb_profile = \ + urllib.urlopen('https://graph.facebook.com/me?access_token=%s' + % access_token) fb_profile = json.load(fb_profile) try: + # Try and find existing user - fb_user = UserProfile.objects.get(facebook_id=str(fb_profile['id'])) - user=authenticate(username=fb_user.user,password="default") + + fb_user = \ + UserProfile.objects.get(facebook_id=str(fb_profile['id'])) + user = authenticate(username=fb_user.user, password='default') if user is not None: - auth_login(request,user) + auth_login(request, user) return HttpResponseRedirect(settings.SITE_URL) - except UserProfile.DoesNotExist: + # No existing user # Not all users have usernames - username = fb_profile.get('username', fb_profile['email'].split('@')[0]) - email=fb_profile['email'] + + username = fb_profile.get('username', fb_profile['email' + ].split('@')[0]) + email = fb_profile['email'] first_name = fb_profile['first_name'] last_name = fb_profile['last_name'] - facebook_id=str(fb_profile['id']) - password="default" - password_again="default" - if fb_profile['gender'] == "female" : - gender='F' + facebook_id = str(fb_profile['id']) + password = 'default' + password_again = 'default' + if fb_profile['gender'] == 'female': + gender = 'F' else: - gender='M' - post_url = settings.SITE_URL+'user/register_fb/' + gender = 'M' + post_url = settings.SITE_URL + 'user/register_fb/' form = FacebookUserForm(initial=locals()) - return render_to_response('users/register.html',locals(), context_instance=RequestContext(request)) \ No newline at end of file + return render_to_response('users/register.html', locals(), + context_instance=RequestContext(request)) + + diff --git a/users/fixtures/initial.json b/users/fixtures/initial.json new file mode 100644 index 0000000..eef5c33 --- /dev/null +++ b/users/fixtures/initial.json @@ -0,0 +1,1132 @@ +[ + { + "model": "auth.group", + "pk": 1, + "fields": { + "name": "Events" + + } + }, + { + "model": "auth.user", + "pk": 1, + "fields": { + "username": "air_show", + "email": "air_show@shaastra.org", + "password":"pbkdf2_sha256$10000$XLMcWaxp1ymN$+Z0up91z74pDGnSt1Uezbd7T3xjgxmblOQzvr2a9t3c=" + + } + }, + { + "model": "auth.user", + "pk": 2, + "fields": { + "username": "wright_design", + "email": "wright_design@shaastra.org", + "password":"pbkdf2_sha256$10000$CaZ2x6V8KV2G$vugBJHyHa7NaiQWe9ze2iWzYZ3DeF+NGdPonLnjLTqw=" + + } + }, + { + "model": "auth.user", + "pk": 3, + "fields": { + "username": "paper_planes", + "email": "paper_planes@shaastra.org", + "password":"pbkdf2_sha256$10000$6EeRBKnPWBfU$GQodMJnICkfFDT9XIjSFKGHrE++0fFfPUbf4Hsv7Pi0=" + + } + }, + { + "model": "auth.user", + "pk": 4, + "fields": { + "username": "aerobotics", + "email": "aerobotics@shaastra.org", + "password":"pbkdf2_sha256$10000$ZULvKaikPY34$V7Hpa0ZcKPk1+S73CW4/gxiR36ZfRA0mhspjLkE86hc=" + + } + }, + { + "model": "auth.user", + "pk": 5, + "fields": { + "username": "hackfest", + "email": "hackfest@shaastra.org", + "password":"pbkdf2_sha256$10000$sjEhC73xUZci$pwfhJ8a4y1X6w/jVCDW2X8pQz2+KlnfHRrRjrRCN46A=" + + } + }, + { + "model": "auth.user", + "pk": 6, + "fields": { + "username": "opc", + "email": "opc@shaastra.org", + "password":"pbkdf2_sha256$10000$9mVUOrR7B8od$ZwuwIVfuqMNj31YYU8RhiXSaxgVv8D+k/uqnpbGr4Jk=" + + } + }, + { + "model": "auth.user", + "pk": 7, + "fields": { + "username": "reverse_coding", + "email": "reverse_coding@shaastra.org", + "password":"pbkdf2_sha256$10000$i8rFt4paVuYN$g2Ra1m0LPl35vDLjTg7PschbNpYSy+dfy5EZ5Cf3ZiE=" + + } + }, + { + "model": "auth.user", + "pk": 8, + "fields": { + "username": "robowars", + "email": "robowars@shaastra.org", + "password":"pbkdf2_sha256$10000$W6cwRxk6DPY6$h5HRflKbtatoIta5Ntagkv0Kl9DnuIffXRaD5ldZoR8=" + + } + }, + { + "model": "auth.user", + "pk": 9, + "fields": { + "username": "contraption", + "email": "contraption@shaastra.org", + "password":"pbkdf2_sha256$10000$wI4yVebZrDCv$7R+QDGLi9duNQpmRD5Hew4qAT2C3be/+m6j21+f1jDE=" + + } + }, + { + "model": "auth.user", + "pk": 10, + "fields": { + "username": "fire_n_ice", + "email": "fire_n_ice@shaastra.org", + "password":"pbkdf2_sha256$10000$Su45DPt6gJCi$yvf/FkEohbssNHZm3AOobjh1Gk4SuZPeGOus1RIb5Jk=" + + } + }, + { + "model": "auth.user", + "pk": 11, + "fields": { + "username": "robotics", + "email": "robotics@shaastra.org", + "password":"pbkdf2_sha256$10000$Reuo46seB4Gg$jxKY/+ASo0dzopz6qEidk1KBBVFVhi1/q6M26qVZM2s=" + + } + }, + { + "model": "auth.user", + "pk": 12, + "fields": { + "username": "junkyard_wars", + "email": "junkyard_wars@shaastra.org", + "password":"pbkdf2_sha256$10000$spcZZ7m4fOnc$8Zk5byUB2+rNyiPjtO7COBV832as1JwSVW9RusXe8yc=" + + } + }, + { + "model": "auth.user", + "pk": 13, + "fields": { + "username": "ultimate_engineer", + "email": "ultimate_engineer@shaastra.org", + "password":"pbkdf2_sha256$10000$yPBnjXidCFhm$U3mNsV0qqya3QmN/6sVWyE1xAoH3zJGfVMGZEeVWVP0=" + + } + }, + { + "model": "auth.user", + "pk": 14, + "fields": { + "username": "project_x", + "email": "project_x@shaastra.org", + "password":"pbkdf2_sha256$10000$1wi59UjEgoFA$qKhFoPii15hSJPy72jb4NOkx3ysDXs/I975igAAJpcI=" + } + }, + { + "model": "auth.user", + "pk": 15, + "fields": { + "username": "shaastra_cube_open", + "email": "shaastra_cube_open@shaastra.org", + "password":"pbkdf2_sha256$10000$d52marUfSY64$24eB3UzhOsN+oByNawD/uVHBvwAyxVDJQCZ5/fuQaMc=" + } + }, + { + "model": "auth.user", + "pk": 16, + "fields": { + "username": "puzzle_champ", + "email": "puzzle_champ@shaastra.org", + "password":"pbkdf2_sha256$10000$a6VlP9twmOlx$vnh1ovI4kcHMfnadcvGTOfoh6eKaDiwnJmbwvbgMP2w=" + + } + }, + { + "model": "auth.user", + "pk": 17, + "fields": { + "username": "math_modelling", + "email": "math_modelling@shaastra.org", + "password":"pbkdf2_sha256$10000$DGpPlY4mMTwT$MjBdGtodAgpG2pn5nBJ/yv+pD0l4uyCdH/ykUfJg3fQ=" + + } + }, + { + "model": "auth.user", + "pk": 18, + "fields": { + "username": "fox_hunt", + "email": "fox_hunt@shaastra.org", + "password":"pbkdf2_sha256$10000$x1EZTOJnaKLM$yN5cI/9BT+stySP7+AvoY0zLcj9m3RL7P122wzz29O8=" + + } + }, + { + "model": "auth.user", + "pk": 19, + "fields": { + "username": "shaastra_main_quiz", + "email": "shaastra_main_quiz@shaastra.org", + "password":"pbkdf2_sha256$10000$jjrVPDi0cKAZ$1dS6XBAE3DeH4INN2kpF34ZNeSlWu3G5X4ByHfYPz4E=" + + } + }, + { + "model": "auth.user", + "pk": 20, + "fields": { + "username": "htw", + "email": "htw@shaastra.org", + "password":"pbkdf2_sha256$10000$cHkLngN0cbIt$FhQGJgs43Iq2on5QiJ276qDRmK3lPIglBSFVE8Q5vxc=" + + } + }, + { + "model": "auth.user", + "pk": 21, + "fields": { + "username": "auto_quiz", + "email": "auto_quiz@shaastra.org", + "password":"pbkdf2_sha256$10000$CO8qjQmfGPhN$LVeeKb/19wOLdchSHRhCO2IdDWFsQRRQCWTUpummxsM=" + + } + }, + { + "model": "auth.user", + "pk": 22, + "fields": { + "username": "shaastra_junior_quiz", + "email": "shaastra_junior_quiz@shaastra.org", + "password":"pbkdf2_sha256$10000$XipZtX6AFuHz$UJmyLGX0DbNzCS4Pf6YpGAkVF8MD1P5yKmHm02NCwvk=" + + } + }, + { + "model": "auth.user", + "pk": 23, + "fields": { + "username": "online_events", + "email": "online_events@shaastra.org", + "password":"pbkdf2_sha256$10000$zkorYYhoHUkF$xRjH1V+2rpJrCMWmAphDuKVD0lTzbTmklPJCzAJHFuU=" + + } + }, + { + "model": "auth.user", + "pk": 24, + "fields": { + "username": "desmod", + "email": "desmod@shaastra.org", + "password":"pbkdf2_sha256$10000$kuoPthH5v5sD$z5/8YMbwduKTCN0y0OvWvHbwKRUJ+79x8ZB7mTq1n4w=" + + } + }, + { + "model": "auth.user", + "pk": 25, + "fields": { + "username": "scdc", + "email": "scdc@shaastra.org", + "password":"pbkdf2_sha256$10000$t5JETuiW5BK3$3yaNfP/X1y1QPsgLdEG7fg/PgUpAwKeszvMoKpJyaaM=" + + } + }, + { + "model": "auth.user", + "pk": 26, + "fields": { + "username": "robo-oceana", + "email": "robo-oceana@shaastra.org", + "password":"pbkdf2_sha256$10000$eEh5vnxKrEvW$iuZQLj4bojMJezLRRcw88a4m9d4I4BbiS7dq9+36Kxo=" + + } + }, + { + "model": "auth.user", + "pk": 27, + "fields": { + "username": "game_drome", + "email": "game_drome@shaastra.org", + "password":"pbkdf2_sha256$10000$KjGgL4bm7Vdg$c2RX7oDES2jEmG0E6/ollLZjNHicB4weAf/ixu3pZt8=" + + } + }, + { + "model": "auth.user", + "pk": 28, + "fields": { + "username": "idp", + "email": "idp@shaastra.org", + "password":"pbkdf2_sha256$10000$mIOdhtl6tEQ8$rAyNH8YB/pNKpOO802H9lIUa8pedPywT+9/JLqaolps=" + + } + }, + { + "model": "auth.user", + "pk": 29, + "fields": { + "username": "shaastra_junior", + "email": "shaastra_junior@shaastra.org", + "password":"pbkdf2_sha256$10000$yCsKOjPE9Yvy$iPIM3UaB03UApXoc82IZe8AAcq++5260lchzeta/FnQ=" + + } + }, + { + "model": "auth.user", + "pk": 30, + "fields": { + "username": "sustainable_cityscape", + "email": "sustainable_cityscape@shaastra.org", + "password":"pbkdf2_sha256$10000$pu2trNSpCj3T$xAZf9S2AtrWaq1aW28kixRek2NPZbwCxB+Zd56r0YQI=" + + } + }, + { + "model": "auth.user", + "pk": 31, + "fields": { + "username": "case_study", + "email": "case_study@shaastra.org", + "password":"pbkdf2_sha256$10000$jUVxM6XH7qRm$To5PH//pEfHUk66lhEd+ZZooR5oXojb5SBC58DqNqRc=" + + } + }, + { + "model": "auth.user", + "pk": 32, + "fields": { + "username": "magic", + "email": "magic@shaastra.org", + "password":"pbkdf2_sha256$10000$kXDAPgQqSOTm$h+57nS6oESxwB50PqOvVptlNFcmNNE8vj00cwpMqmgQ=" + + } + }, + { + "model": "auth.user", + "pk": 33, + "fields": { + "username": "e-waste", + "email": "e-waste@shaastra.org", + "password":"pbkdf2_sha256$10000$uE4oGD5zKXBG$FkkBNRfQUddpXBfZ/xi9MW0MuC3K/te/uXxULsTAPOE=" + + } + }, + { + "model": "auth.user", + "pk": 34, + "fields": { + "username": "face_off", + "email": "face_off@shaastra.org", + "password":"pbkdf2_sha256$10000$2EEl3PlTvTzv$E3vGK2B8/SoD1KutZtTqvrhdqkjL8C1/C1Pnn+YQblE=" + + } + }, + { + "model": "auth.user", + "pk": 35, + "fields": { + "username": "sketch_it", + "email": "sketch_it@shaastra.org", + "password":"pbkdf2_sha256$10000$4glQjSaK92yd$qk1RvWOseVvI/K4uCEFX9xl5QjYE53pzBOZAyK78/t8=" + + } + }, + { + "model": "auth.user", + "pk": 36, + "fields": { + "username": "pilot_training", + "email": "pilot_training@shaastra.org", + "password":"pbkdf2_sha256$10000$8qefsTGyyB5Z$M1NRk+g1Qw4Bb45CQzq6LK26XqzfEM2DRb5KtrevzP8=" + + } + }, + { + "model": "auth.user", + "pk": 37, + "fields": { + "username": "hovercraft", + "email": "hovercraft@shaastra.org", + "password":"pbkdf2_sha256$10000$WFbCo0pHpVNX$/mKYR1FZuUrxNiSNnNfBHwyHMSF7sxtTvzYWlls9/0E=" + + } + }, + { + "model": "auth.user", + "pk": 38, + "fields": { + "username": "research_expo", + "email": "research_expo@shaastra.org", + "password":"pbkdf2_sha256$10000$hZWgdVyCGtQD$B2p0JwLOhX9ubWfyceaWxKmEy20ACHhzK0+LeS7l4tQ=" + + } + }, + { + "model": "auth.user", + "pk": 39, + "fields": { + "username": "lectures", + "email": "lectures@shaastra.org", + "password":"pbkdf2_sha256$10000$HGtrUGkfKbNz$vfQTpLP1daWhwAtVlUZnERMSyH/U49li9Fc9wnJE+p4=" + + } + }, + { + "model": "auth.user", + "pk": 40, + "fields": { + "username": "shaastra", + "email": "webmaster@shaastra.org", + "password": "pbkdf2_sha256$10000$JhYBxenid3J3$nbmsiyYzCvlolGaLKoNOy0lFbtrKmCmZNhZGC1wVF1Y=", + "is_superuser": "1" + + } + }, + { + "model": "auth.user", + "pk": 41, + "fields": { + "username": "eventscore", + "email": "tanuj1411@gmail.com", + "password":"pbkdf2_sha256$10000$comzrAtwP18E$nqG+rlOmGsVUizeJUyUxhLg37B0B4nZwbKs2/IbB55Y=", + "groups" : "1" + + } + }, + { + "model": "events.event", + "pk": 1, + "fields": { + "title": "Air Show", + "category": "Aerofest" + + } + }, + { + "model": "events.event", + "pk": 2, + "fields": { + "title": "Wright Design", + "category": "Aerofest" + + } + }, + { + "model": "events.event", + "pk": 3, + "fields": { + "title": "Paper Planes", + "category": "Aerofest" + + } + }, + { + "model": "events.event", + "pk": 4, + "fields": { + "title": "Aerobotics", + "category": "Aerofest" + + } + }, + { + "model": "events.event", + "pk": 5, + "fields": { + "title": "Hackfest", + "category": "Coding" + + } + }, + { + "model": "events.event", + "pk": 6, + "fields": { + "title": "Online Programming Contest", + "category": "Coding" + + } + }, + { + "model": "events.event", + "pk": 7, + "fields": { + "title": "Reverse Coding", + "category": "Coding" + + } + }, + { + "model": "events.event", + "pk": 8, + "fields": { + "title": "Robowars", + "category": "Design and Build" + + } + }, + { + "model": "events.event", + "pk": 9, + "fields": { + "title": "Contraptions", + "category": "Design and Build" + + } + }, + { + "model": "events.event", + "pk": 10, + "fields": { + "title": "Fire n Ice", + "category": "Design and Build" + + } + }, + { + "model": "events.event", + "pk": 11, + "fields": { + "title": "Robotics", + "category": "Design and Build" + + } + }, + { + "model": "events.event", + "pk": 12, + "fields": { + "title": "Junkyard Wars", + "category": "Design and Build" + + } + }, + { + "model": "events.event", + "pk": 13, + "fields": { + "title": "Ultimate Engineer", + "category": "Design and Build" + + } + }, + { + "model": "events.event", + "pk": 14, + "fields": { + "title": "Project X", + "category": "Involve" + + } + }, + { + "model": "events.event", + "pk": 15, + "fields": { + "title": "Shaastra Cube Open", + "category": "Involve" + + } + }, + { + "model": "events.event", + "pk": 16, + "fields": { + "title": "Puzzle Champ", + "category": "Involve" + + } + }, + { + "model": "events.event", + "pk": 17, + "fields": { + "title": "Math Modelling", + "category": "Involve" + + } + }, + { + "model": "events.event", + "pk": 18, + "fields": { + "title": "Fox Hunt", + "category": "Involve" + + } + }, + { + "model": "events.event", + "pk": 19, + "fields": { + "title": "Shaastra Main Quiz", + "category": "Quizzes" + + } + }, + { + "model": "events.event", + "pk": 20, + "fields": { + "title": "How Things Work", + "category": "Quizzes" + + } + }, + { + "model": "events.event", + "pk": 21, + "fields": { + "title": "Auto Quiz", + "category": "Quizzes" + + } + }, + { + "model": "events.event", + "pk": 22, + "fields": { + "title": "Shaastra Junior Quiz", + "category": "Quizzes" + + } + }, + { + "model": "events.event", + "pk": 23, + "fields": { + "title": "Online Events", + "category": "Online" + + } + }, + { + "model": "events.event", + "pk": 24, + "fields": { + "title": "Desmod", + "category": "Department Flagship" + + } + }, + { + "model": "events.event", + "pk": 25, + "fields": { + "title": "SCDC", + "category": "Department Flagship" + + } + }, + { + "model": "events.event", + "pk": 26, + "fields": { + "title": "Robo-Oceana", + "category": "Department Flagship" + + } + }, + { + "model": "events.event", + "pk": 27, + "fields": { + "title": "Game Drome", + "category": "Spotlight" + + } + }, + { + "model": "events.event", + "pk": 28, + "fields": { + "title": "IDP", + "category": "Spotlight" + + } + }, + { + "model": "events.event", + "pk": 29, + "fields": { + "title": "Shaastra Junior", + "category": "Spotlight" + + } + }, + { + "model": "events.event", + "pk": 30, + "fields": { + "title": "Sustainable Cityscape", + "category": "Spotlight" + + } + }, + { + "model": "events.event", + "pk": 31, + "fields": { + "title": "Case Study", + "category": "Spotlight" + + } + }, + { + "model": "events.event", + "pk": 32, + "fields": { + "title": "Magic", + "category": "Spotlight" + + } + }, + { + "model": "events.event", + "pk": 33, + "fields": { + "title": "E-Waste", + "category": "Spotlight" + + } + }, + { + "model": "events.event", + "pk": 34, + "fields": { + "title": "Face Off", + "category": "Spotlight" + + } + }, + { + "model": "events.event", + "pk": 35, + "fields": { + "title": "Sketch It", + "category": "Workshops" + + } + }, + { + "model": "events.event", + "pk": 36, + "fields": { + "title": "Pilot Training", + "category": "Workshops" + + } + }, + { + "model": "events.event", + "pk": 37, + "fields": { + "title": "Hovercraft", + "category": "Workshops" + + } + }, + { + "model": "events.event", + "pk": 38, + "fields": { + "title": "Research Expo", + "category": "Others" + + } + }, + { + "model": "events.event", + "pk": 39, + "fields": { + "title": "Lectures", + "category": "Others" + + } + }, + { + "model": "users.UserProfile", + "pk": 1, + "fields": { + "user": "1", + "is_coord_of": "1" + + } + }, + { + "model": "users.UserProfile", + "pk": 2, + "fields": { + "user": "2", + "is_coord_of": "2" + + } + }, + { + "model": "users.UserProfile", + "pk": 3, + "fields": { + "user": "3", + "is_coord_of": "3" + + } + }, + { + "model": "users.UserProfile", + "pk": 4, + "fields": { + "user": "4", + "is_coord_of": "4" + + } + }, + { + "model": "users.UserProfile", + "pk": 5, + "fields": { + "user": "5", + "is_coord_of": "5" + + } + }, + { + "model": "users.UserProfile", + "pk": 6, + "fields": { + "user": "6", + "is_coord_of": "6" + + } + }, + { + "model": "users.UserProfile", + "pk": 7, + "fields": { + "user": "7", + "is_coord_of": "7" + + } + }, + { + "model": "users.UserProfile", + "pk": 8, + "fields": { + "user": "8", + "is_coord_of": "8" + + } + }, + { + "model": "users.UserProfile", + "pk": 9, + "fields": { + "user": "9", + "is_coord_of": "9" + + } + }, + { + "model": "users.UserProfile", + "pk": 10, + "fields": { + "user": "10", + "is_coord_of": "10" + + } + }, + { + "model": "users.UserProfile", + "pk": 11, + "fields": { + "user": "11", + "is_coord_of": "11" + + } + }, + { + "model": "users.UserProfile", + "pk": 12, + "fields": { + "user": "12", + "is_coord_of": "12" + + } + }, + { + "model": "users.UserProfile", + "pk": 13, + "fields": { + "user": "13", + "is_coord_of": "13" + + } + }, + { + "model": "users.UserProfile", + "pk": 14, + "fields": { + "user": "14", + "is_coord_of": "14" + + } + }, + { + "model": "users.UserProfile", + "pk": 15, + "fields": { + "user": "15", + "is_coord_of": "15" + + } + }, + { + "model": "users.UserProfile", + "pk": 16, + "fields": { + "user": "16", + "is_coord_of": "16" + + } + }, + { + "model": "users.UserProfile", + "pk": 17, + "fields": { + "user": "17", + "is_coord_of": "17" + + } + }, + { + "model": "users.UserProfile", + "pk": 18, + "fields": { + "user": "18", + "is_coord_of": "18" + + } + }, + { + "model": "users.UserProfile", + "pk": 19, + "fields": { + "user": "19", + "is_coord_of": "19" + + } + }, + { + "model": "users.UserProfile", + "pk": 20, + "fields": { + "user": "20", + "is_coord_of": "20" + + } + }, + { + "model": "users.UserProfile", + "pk": 21, + "fields": { + "user": "21", + "is_coord_of": "21" + + } + }, + { + "model": "users.UserProfile", + "pk": 22, + "fields": { + "user": "22", + "is_coord_of": "22" + + } + }, + { + "model": "users.UserProfile", + "pk": 23, + "fields": { + "user": "23", + "is_coord_of": "23" + + } + }, + { + "model": "users.UserProfile", + "pk": 24, + "fields": { + "user": "24", + "is_coord_of": "24" + + } + }, + { + "model": "users.UserProfile", + "pk": 25, + "fields": { + "user": "25", + "is_coord_of": "25" + + } + }, + { + "model": "users.UserProfile", + "pk": 26, + "fields": { + "user": "26", + "is_coord_of": "26" + + } + }, + { + "model": "users.UserProfile", + "pk": 27, + "fields": { + "user": "27", + "is_coord_of": "27" + + } + }, + { + "model": "users.UserProfile", + "pk": 28, + "fields": { + "user": "28", + "is_coord_of": "28" + + } + }, + { + "model": "users.UserProfile", + "pk": 29, + "fields": { + "user": "29", + "is_coord_of": "29" + + } + }, + { + "model": "users.UserProfile", + "pk": 30, + "fields": { + "user": "30", + "is_coord_of": "30" + + } + }, + { + "model": "users.UserProfile", + "pk": 31, + "fields": { + "user": "31", + "is_coord_of": "31" + + } + }, + { + "model": "users.UserProfile", + "pk": 32, + "fields": { + "user": "32", + "is_coord_of": "32" + + } + }, + { + "model": "users.UserProfile", + "pk": 33, + "fields": { + "user": "33", + "is_coord_of": "33" + + } + }, + { + "model": "users.UserProfile", + "pk": 34, + "fields": { + "user": "34", + "is_coord_of": "34" + + } + }, + { + "model": "users.UserProfile", + "pk": 35, + "fields": { + "user": "35", + "is_coord_of": "35" + + } + }, + { + "model": "users.UserProfile", + "pk": 36, + "fields": { + "user": "36", + "is_coord_of": "36" + + } + }, + { + "model": "users.UserProfile", + "pk": 37, + "fields": { + "user": "37", + "is_coord_of": "37" + + } + }, + { + "model": "users.UserProfile", + "pk": 38, + "fields": { + "user": "38", + "is_coord_of": "38" + + } + }, + { + "model": "users.UserProfile", + "pk": 39, + "fields": { + "user": "39", + "is_coord_of": "39" + + } + }, + { + "model": "users.UserProfile", + "pk": 40, + "fields": { + "user": "41", + "is_core": "1" + + + } + } +] diff --git a/users/forms.py b/users/forms.py index b9804b5..5b6e096 100644 --- a/users/forms.py +++ b/users/forms.py @@ -1,7 +1,10 @@ +#!/usr/bin/python # -*- coding: utf-8 -*- -#We can use the same forms as last time for registation. We are not really changing anything here so. -#If we have to change anything it shouldn't be much of a problem -import re + +# We can use the same forms as last time for registation. We are not really changing anything here so. +# If we have to change anything it shouldn't be much of a problem + +import re from django import forms from django.forms import ModelForm from django.db import models as d_models @@ -9,154 +12,380 @@ from django.template import Template, Context from django.utils.safestring import mark_safe from users.models import * +from chosen import forms as chosenforms + +# from recaptcha import fields as recaptcha_fields import settings -alnum_re = re.compile(r'^[\w.-]+$') # regexp. from jamesodo in #django [a-zA-Z0-9_.] +alnum_re = re.compile(r'^[\w.-]+$') # regexp. from jamesodo in #django [a-zA-Z0-9_.] alphanumric = re.compile(r"[a-zA-Z0-9]+$") -GENDER_CHOICES = ( - (1, 'Male'), - (2, 'Female'), - ) - -''' -class HorizRadioRenderer(forms.RadioSelect.renderer): - #this overrides widget method to put radio buttons horizontally instead of vertically. - def render(self): - #Outputs radios - return mark_safe(u'\n'.join([u'%s\n' % w for w in self])) -''' - +GENDER_CHOICES = ((1, 'Male'), (2, 'Female')) +BRANCH_CHOICES = ( + ('Arts', 'Arts'), + ('Accounting', 'Accounting'), + ('Applied Mechanics', 'Applied Mechanics'), + ('Mechatronics', 'Mechatronics'), + ('Aerospace Engineering', 'Aerospace Engineering'), + ('Automobile Engineering', 'Automobile Engineering'), + ('Biotech / Biochemical / Biomedical', 'Biotech / Biochemical / Biomedical'), + ('Biology', 'Biology'), + ('Ceramic Engineering', 'Ceramic Engineering'), + ('Chemical Engineering', 'Chemical Engineering'), + ('Chemistry', 'Chemistry'), + ('Design', 'Design'), + ('Engineering Design', 'Engineering Design'), + ('Civil Engineering', 'Civil Engineering'), + ('Computer Science and Engineering', 'Computer Science and Engineering'), + ('Electronics and Communications Engineering', 'Electronics and Communications Engineering'), + ('Electrical and Electronics Engineering', 'Electrical and Electronics Engineering'), + ('Electrical Engineering', 'Electrical Engineering'), + ('Electronics and Instrumentation Engineering', 'Electronics and Instrumentation Engineering'), + ('Engineering Physics', 'Engineering Physics'), + ('Economics', 'Economics'), + ('Fashion Technology', 'Fashion Technology'), + ('Humanities and Social Sciences', 'Humanities and Social Sciences'), + ('Industrial Production', 'Industrial Production'), + ('Production', 'Production'), + ('Information Technology and Information Science', 'Information Technology and Sciences'), + ('Management', 'Management'), + ('Manufacturing', 'Manufacturing'), + ('Mathematics', 'Mathematics'), + ('Metallurgy and Material Science', 'Metallurgy and Material Science'), + ('Mechanical Engineering', 'Mechanical Engineering'), + ('Ocean Engineering and Naval Architecture', 'Ocean Engineering and Naval Architecture'), + ('Physics', 'Physics'), + ('Telecom', 'Telecom'), + ('Textile Engineering', 'Textile Engineering'), + ('Others', 'Others'), +) + class LoginForm(forms.Form): - username=forms.CharField(help_text='Your Shaastra 2013 username') - password=forms.CharField(widget=forms.PasswordInput, help_text='Your password') + username = forms.CharField(help_text='Your Shaastra 2013 username') + password = forms.CharField(widget=forms.PasswordInput, + help_text='Your password') + class BaseUserForm(forms.ModelForm): - first_name = forms.CharField (max_length=30, help_text='Enter your first name here.') - last_name = forms.CharField (max_length=30, help_text='Enter your last name here.') - + first_name = forms.CharField(max_length=30) + last_name = forms.CharField(max_length=30) + class Meta: + model = UserProfile - + + # The following code is to clean the a age field and to ensure that age is between 12 and 80. + # Age limit has now been removed as demanded in Issue #29. To add it back, uncomment the + # following and also add the help_text in the age field in the model. + ''' def clean_age(self): - if (self.cleaned_data['age']>80 or self.cleaned_data['age']<12): - raise forms.ValidationError(u'Please enter an acceptable age (12 to 80)') - else: - return self.cleaned_data['age'] - + if self.cleaned_data['age'] > 80 or self.cleaned_datlease enter your current mobile number +a['age'] \ + < 12: + raise forms.ValidationError(u'

            Please enter an acceptable age (12 to 80)

            ' + ) + else: + return self.cleaned_data['age'] + ''' + def clean_mobile_number(self): - if (len(self.cleaned_data['mobile_number'])!=10 or (self.cleaned_data['mobile_number'][0]!='7' and self.cleaned_data['mobile_number'][0]!='8' and self.cleaned_data['mobile_number'][0]!='9') or (not self.cleaned_data['mobile_number'].isdigit())): - raise forms.ValidationError(u'Enter a valid mobile number') - if UserProfile.objects.filter(mobile_number=self.cleaned_data['mobile_number']): - pass - else: - return self.cleaned_data['mobile_number'] - raise forms.ValidationError('This mobile number is already registered') - + if len(self.cleaned_data['mobile_number']) != 10 \ + or self.cleaned_data['mobile_number'][0] != '7' \ + and self.cleaned_data['mobile_number'][0] != '8' \ + and self.cleaned_data['mobile_number'][0] != '9' \ + or not self.cleaned_data['mobile_number'].isdigit(): + raise forms.ValidationError(u'

            Enter a valid mobile number

            ' + ) + if UserProfile.objects.filter(mobile_number=self.cleaned_data['mobile_number' + ]): + pass + else: + return self.cleaned_data['mobile_number'] + raise forms.ValidationError('

            This mobile number is already registered

            ' + ) + def clean_first_name(self): - if not self.cleaned_data['first_name'].replace(' ','').isalpha(): - raise forms.ValidationError(u'Names cannot contain anything other than alphabets.') - else: - return self.cleaned_data['first_name'] - + if not self.cleaned_data['first_name'].replace(' ', '' + ).isalpha(): + raise forms.ValidationError(u'

            Names cannot contain anything other than alphabets.

            ' + ) + else: + return self.cleaned_data['first_name'] + def clean_last_name(self): - if not self.cleaned_data['last_name'].replace(' ','').isalpha(): - raise forms.ValidationError(u'Names cannot contain anything other than alphabets.') - else: - return self.cleaned_data['last_name'] + if not self.cleaned_data['last_name'].replace(' ', '' + ).isalpha(): + raise forms.ValidationError(u'

            Names cannot contain anything other than alphabets.

            ' + ) + else: + return self.cleaned_data['last_name'] + class AddUserForm(BaseUserForm): - username = forms.CharField (max_length=30, help_text='Your Shaastra 2013 username') - email = forms.EmailField (help_text='Enter your e-mail address. eg, someone@gmail.com') - password = forms.CharField (min_length=6, - max_length=30, - widget=forms.PasswordInput, - help_text='Enter a password that you can remember') - password_again = forms.CharField (max_length=30, - widget=forms.PasswordInput, - help_text='Enter the same password that you entered above') - + username = forms.CharField(max_length=30, + help_text='Please select a username.', + label='Shaastra username') + email = \ + forms.EmailField() + password = forms.CharField(min_length=6, max_length=30, + widget=forms.PasswordInput, + help_text='Passwords need to be atleast 6 characters long.' + ) + password_again = forms.CharField(max_length=30, + widget=forms.PasswordInput, + help_text='Enter the same password that you entered above') + + branch = chosenforms.ChosenChoiceField(overlay="You major in...", choices = BRANCH_CHOICES) + college = chosenforms.ChosenModelChoiceField(overlay="You study at...", queryset=College.objects.all()) + class Meta(BaseUserForm.Meta): - fields=('first_name', 'last_name', 'username', 'email', 'password', 'password_again', 'college', 'college_roll', 'gender', 'age', 'branch', 'mobile_number') - #exclude = {'is_coord','coord_event','shaastra_id','activation_key','key_expires','UID','user',} + + fields = ( + 'first_name', + 'last_name', + 'username', + 'email', + 'password', + 'password_again', + 'college', + 'college_roll', + 'gender', + 'age', + 'branch', + 'mobile_number', + 'want_accomodation', + ) + + # exclude = {'is_coord','coord_event','shaastra_id','activation_key','key_expires','UID','user',} def clean_username(self): if not alnum_re.search(self.cleaned_data['username']): - raise forms.ValidationError(u'Usernames can only contain letters, numbers and underscores') + raise forms.ValidationError(u'Usernames can only contain letters, numbers and underscores' + ) if User.objects.filter(username=self.cleaned_data['username']): pass else: return self.cleaned_data['username'] - raise forms.ValidationError('This username is already taken. Please choose another.') + raise forms.ValidationError('This username is already taken. Please choose another.' + ) def clean_email(self): if User.objects.filter(email=self.cleaned_data['email']): pass else: return self.cleaned_data['email'] - raise forms.ValidationError('This email address is already taken. Please choose another.') + raise forms.ValidationError('This email address is already taken. Please choose another.' + ) def clean_password(self): if self.prefix: - field_name1 = '%s-password'%self.prefix - field_name2 = '%s-password_again'%self.prefix + field_name1 = '%s-password' % self.prefix + field_name2 = '%s-password_again' % self.prefix else: field_name1 = 'password' field_name2 = 'password_again' - - if self.data[field_name1] != '' and self.data[field_name1] != self.data[field_name2]: - raise forms.ValidationError ("The entered passwords do not match.") + + if self.data[field_name1] != '' and self.data[field_name1] \ + != self.data[field_name2]: + raise forms.ValidationError('The entered passwords do not match.' + ) else: return self.data[field_name1] -class EditUserForm(BaseUserForm): +class EditUserForm(BaseUserForm): + branch = chosenforms.ChosenChoiceField(overlay="You major in...", choices = BRANCH_CHOICES) + college = chosenforms.ChosenModelChoiceField(overlay="You study at...", queryset=College.objects.all()) class Meta(BaseUserForm.Meta): - fields=('first_name', 'last_name', 'gender', 'age', 'branch', 'mobile_number', 'college', 'college_roll' ) - #exclude = ('user', 'facebook_id', 'activation_key', 'key_expires', 'is_coord', 'access_token', 'username', 'email',) + fields = ( + 'first_name', + 'last_name', + 'gender', + 'age', + 'branch', + 'mobile_number', + 'college', + 'college_roll', + 'want_accomodation', + ) + + # exclude = ('user', 'facebook_id', 'activation_key', 'key_expires', 'is_coord', 'access_token', 'username', 'email',) def clean_mobile_number(self): - if (len(self.cleaned_data['mobile_number'])!=10 or (self.cleaned_data['mobile_number'][0]!='7' and self.cleaned_data['mobile_number'][0]!='8' and self.cleaned_data['mobile_number'][0]!='9') or (not self.cleaned_data['mobile_number'].isdigit())): - raise forms.ValidationError(u'Enter a valid mobile number') + if len(self.cleaned_data['mobile_number']) != 10 \ + or self.cleaned_data['mobile_number'][0] != '7' \ + and self.cleaned_data['mobile_number'][0] != '8' \ + and self.cleaned_data['mobile_number'][0] != '9' \ + or not self.cleaned_data['mobile_number'].isdigit(): + raise forms.ValidationError(u'Enter a valid mobile number') elif 'mobile_number' in self.changed_data: - if UserProfile.objects.filter(mobile_number=self.cleaned_data['mobile_number']): - raise forms.ValidationError('This mobile number is already registered') + if UserProfile.objects.filter(mobile_number=self.cleaned_data['mobile_number' + ]): + raise forms.ValidationError('This mobile number is already registered' + ) else: return self.cleaned_data['mobile_number'] - return self.cleaned_data['mobile_number'] - + return self.cleaned_data['mobile_number'] class FacebookUserForm(BaseUserForm): - username = forms.CharField (max_length=30, help_text='Your Shaastra 2013 username') - email = forms.EmailField (help_text='Enter your e-mail address. eg, someone@gmail.com') + username = forms.CharField(max_length=30, + help_text='Your Shaastra 2013 username') + email = \ + forms.EmailField(help_text='Enter your e-mail address. eg, someone@gmail.com' + ) class Meta(BaseUserForm.Meta): - fields=('first_name', 'last_name', 'username', 'email', 'gender', 'age', 'college', 'college_roll', 'branch', 'mobile_number') + + fields = ( + 'first_name', + 'last_name', + 'username', + 'email', + 'gender', + 'age', + 'college', + 'college_roll', + 'branch', + 'mobile_number', + ) def clean_username(self): if not alnum_re.search(self.cleaned_data['username']): - raise forms.ValidationError(u'Usernames can only contain letters, numbers and underscores') + raise forms.ValidationError(u'Usernames can only contain letters, numbers and underscores' + ) if User.objects.filter(username=self.cleaned_data['username']): pass else: return self.cleaned_data['username'] - raise forms.ValidationError('This username is already taken. Please choose another.') + raise forms.ValidationError('This username is already taken. Please choose another.' + ) def clean_email(self): if User.objects.filter(email=self.cleaned_data['email']): pass else: return self.cleaned_data['email'] - raise forms.ValidationError('This email address is already taken. Please choose another.') - -class AddCollegeForm (ModelForm): + raise forms.ValidationError('This email address is already taken. Please choose another.' + ) + + +class AddCollegeForm(ModelForm): + class Meta: + model = College - fields=('name','city','state') \ No newline at end of file + fields = ('name', 'city', 'state') + +class CreateTeamForm(forms.ModelForm): + + def clean_event(self): + if 'event' in self.cleaned_data: + event = self.cleaned_data['event'] + try: + Event.objects.get(pk = event.id) + except Event.DoesNotExist: + raise forms.ValidationError('Not a valid event') + return self.cleaned_data['event'] + + def clean(self): + data = self.cleaned_data + if 'name' in data and 'event' in data: + try: + Team.objects.filter(event__id = data['event'].id).get(name__iexact = data['name']) + raise forms.ValidationError('A team with the same name already exists for this event!') + except Team.DoesNotExist: + pass + return data + + class Meta: + model = Team + fields = ('name', 'event') + widgets = { + 'event' : forms.HiddenInput(), + } + +class JoinTeamForm(forms.ModelForm): + + def clean_event(self): + if 'event' in self.cleaned_data: + event = self.cleaned_data['event'] + try: + Event.objects.get(pk = event.id) + except Event.DoesNotExist: + raise forms.ValidationError('Not a valid event') + return self.cleaned_data['event'] + + def clean(self): + data = self.cleaned_data + if 'name' in data and 'event' in data: + try: + Team.objects.filter(event__id = data['event'].id).get(name__iexact = data['name']) + except Team.DoesNotExist: + raise forms.ValidationError('A team with this name does not exist for this event!') + return data + + class Meta: + model = Team + fields = ('name', 'event') + +class AddMemberForm(forms.Form): + member = forms.CharField(max_length = 50, help_text = "Please enter your friend's username") + team_id = forms.IntegerField() + + def clean_team_id(self): + team_id = self.cleaned_data['team_id'] + try: + team = Team.objects.get(pk = team_id) + except Team.DoesNotExist: + raise forms.ValidationError('Team does not exist!') + return team_id + + def clean_member(self): + member = self.cleaned_data['member'] + try: + user = User.objects.get(username = member) + if not user.is_active: + raise forms.ValidationError('This user is not active! Please ask him/her to activate his account first.') + except User.DoesNotExist: + raise forms.ValidationError('No such user!') + return member + + def clean(self): + data = self.cleaned_data + if 'team_id' and 'member' in data: + team = Team.objects.get(pk = data['team_id']) + # check if this user is already a part of another team (any team) for the same event + if Team.objects.filter(event = team.event).filter(members__username = data['member']).count() > 0: + msg = 'This user is already a part of a team for this event!' + self._errors['member'] = self.error_class([ msg, ]) + del data['member'] + return data + +class ChangeLeaderForm(forms.Form): + new_leader = forms.CharField(max_length = 50, help_text = "Please enter the new leader's username") + team_id = forms.IntegerField() + + def clean_team_id(self): + team_id = self.cleaned_data['team_id'] + try: + team = Team.objects.get(pk = int(team_id)) + except Team.DoesNotExist: + raise forms.ValidationError('Team does not exist!') + return team_id + + def clean(self): + data = self.cleaned_data + if 'team_id' and 'new_leader' in data: + team = Team.objects.get(pk = data['team_id']) + try: + user = team.members.get(username = data['new_leader']) + except User.DoesNotExist: + raise forms.ValidationError('This user is not a part of this team') + return data diff --git a/users/models.py b/users/models.py index b186aa3..14546ab 100644 --- a/users/models.py +++ b/users/models.py @@ -1,111 +1,122 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- from django.db import models from django.contrib.auth.models import User from events.models import Event -GENDER_CHOICES = ( - ('M','Male'), - ('F','Female'), -) +GENDER_CHOICES = (('M', 'Male'), ('F', 'Female')) STATE_CHOICES = ( - ("Andhra Pradesh" , "Andhra Pradesh"), - ("Arunachal Pradesh" , "Arunachal Pradesh"), - ("Assam" , "Assam"), - ("Bihar" , "Bihar"), - ("Chhattisgarh" , "Chhattisgarh"), - ("Goa" , "Goa"), - ("Gujarat" , "Gujarat"), - ("Haryana" , "Haryana"), - ("Himachal Pradesh" , "Himachal Pradesh"), - ("Jammu And Kashmir" , "Jammu And Kashmir"), - ("Jharkhand" , "Jharkhand"), - ("Karnataka" , "Karnataka"), - ("Kerala" , "Kerala"), - ("Madhya Pradesh" , "Madhya Pradesh"), - ("Maharashtra" , "Maharashtra"), - ("Manipur" , "Manipur"), - ("Meghalaya" , "Meghalaya"), - ("Mizoram" , "Mizoram"), - ("Nagaland" , "Nagaland"), - ("Orissa" , "Orissa"), - ("Punjab" , "Punjab"), - ("Rajasthan" , "Rajasthan"), - ("Sikkim" , "Sikkim"), - ("Tamil Nadu" , "Tamil Nadu"), - ("Tripura" , "Tripura"), - ("Uttar Pradesh" , "Uttar Pradesh"), - ("Uttarakhand" , "Uttarakhand"), - ("West Bengal" , "West Bengal"), - ("Andaman And Nicobar Islands" , "Andaman And Nicobar Islands"), - ("Chandigarh" , "Chandigarh"), - ("Dadra And Nagar Haveli" , "Dadra And Nagar Haveli"), - ("Daman And Diu" , "Daman And Diu"), - ("Lakshadweep" , "Lakshadweep"), - ("NCT/Delhi" , "NCT/Delhi"), - ("Puducherry" , "Puducherry"), - ("Outside India" , "Outside India"), -) + ('Andhra Pradesh', 'Andhra Pradesh'), + ('Arunachal Pradesh', 'Arunachal Pradesh'), + ('Assam', 'Assam'), + ('Bihar', 'Bihar'), + ('Chhattisgarh', 'Chhattisgarh'), + ('Goa', 'Goa'), + ('Gujarat', 'Gujarat'), + ('Haryana', 'Haryana'), + ('Himachal Pradesh', 'Himachal Pradesh'), + ('Jammu And Kashmir', 'Jammu And Kashmir'), + ('Jharkhand', 'Jharkhand'), + ('Karnataka', 'Karnataka'), + ('Kerala', 'Kerala'), + ('Madhya Pradesh', 'Madhya Pradesh'), + ('Maharashtra', 'Maharashtra'), + ('Manipur', 'Manipur'), + ('Meghalaya', 'Meghalaya'), + ('Mizoram', 'Mizoram'), + ('Nagaland', 'Nagaland'), + ('Orissa', 'Orissa'), + ('Punjab', 'Punjab'), + ('Rajasthan', 'Rajasthan'), + ('Sikkim', 'Sikkim'), + ('Tamil Nadu', 'Tamil Nadu'), + ('Tripura', 'Tripura'), + ('Uttar Pradesh', 'Uttar Pradesh'), + ('Uttarakhand', 'Uttarakhand'), + ('West Bengal', 'West Bengal'), + ('Andaman And Nicobar Islands', 'Andaman And Nicobar Islands'), + ('Chandigarh', 'Chandigarh'), + ('Dadra And Nagar Haveli', 'Dadra And Nagar Haveli'), + ('Daman And Diu', 'Daman And Diu'), + ('Lakshadweep', 'Lakshadweep'), + ('NCT/Delhi', 'NCT/Delhi'), + ('Puducherry', 'Puducherry'), + ('Outside India', 'Outside India'), + ) + class College(models.Model): - name=models.CharField (max_length = 255,help_text = 'The name of your college. Please refrain from using short forms.') - city=models.CharField (max_length = 30,help_text = 'The name of the city where your college is located. Please refrain from using short forms.' ) - state=models.CharField (max_length = 40,choices = STATE_CHOICES,help_text = 'The state where your college is located. Select from the drop down list' ) + + name = models.CharField(max_length=255, + help_text='The name of your college. Please refrain from using short forms.' + ) + city = models.CharField(max_length=30, + help_text='The name of the city where your college is located. Please refrain from using short forms.' + ) + state = models.CharField(max_length=40, choices=STATE_CHOICES, + help_text='The state where your college is located. Select from the drop down list' + ) def __unicode__(self): - return "%s, %s, %s"%(self.name, self.city, self.state) + return '%s, %s, %s' % (self.name, self.city, self.state) class Admin: + pass -#User profile common to all users + +# User profile common to all users + class UserProfile(models.Model): - user = models.ForeignKey (User, unique = True) - gender = models.CharField (max_length = 1, choices = GENDER_CHOICES, default = 'F') #Defaults to 'girl' ;-) - age = models.IntegerField (default = 18 , help_text = 'You need to be over 12 and under 80 years of age to participate') - branch = models.CharField (max_length = 50, blank = True, null=True, help_text = 'Your branch of study') - mobile_number = models.CharField (max_length = 15, null=True , help_text='Please enter your current mobile number') - college = models.ForeignKey (College, null=True, blank=True) - college_roll = models.CharField (max_length = 40, null=True) -# shaastra_id = models.CharField (max_length = 20, unique = True, null=True) - activation_key = models.CharField (max_length = 40, null=True) - key_expires = models.DateTimeField (null=True) - want_hospi = models.BooleanField (default = False) - is_core = models.BooleanField (default = False) -# is_coord = models.BooleanField (default = False) - is_coord_of = models.ForeignKey (Event, null = True) + + user = models.ForeignKey(User, unique=True) + gender = models.CharField(max_length=1, choices=GENDER_CHOICES, + default='F') # Defaults to 'girl' ;-) + age = models.IntegerField(default=18) + # help_text='You need to be over 12 and under 80 years of age to participate' + # No age limit now. + branch = models.CharField(max_length=50, blank=True, null=True, + help_text='Your branch of study') + mobile_number = models.CharField(max_length=15, null=True, + help_text='Please enter your current mobile number') + college = models.ForeignKey(College, null=True, blank=True) + college_roll = models.CharField(max_length=40, null=True) + + shaastra_id = models.CharField(max_length = 20, unique = True, null=True) + + activation_key = models.CharField(max_length=40, null=True) + key_expires = models.DateTimeField(null=True) + want_accomodation = models.BooleanField(default=False, help_text = "This doesn't guarantee accommodation during Shaastra.") + is_core = models.BooleanField(default=False) + +# is_coord = models.BooleanField....(default = False) + + is_coord_of = models.ForeignKey(Event, null=True) + # registered = models.ManyToManyField(Event, null=True, related_name='registered_users') #Events which this user has registered for - facebook_id = models.CharField (max_length=20) - access_token = models.CharField (max_length=250) + + facebook_id = models.CharField(max_length=20) + access_token = models.CharField(max_length=250) + registered_events = models.ManyToManyField(Event, + related_name='participants', null=True) def __unicode__(self): return self.user.first_name class Admin: - pass - -''' -class Feedback(models.Model): - name = models.CharField ( max_length = 30, null = True, help_text = 'Your first name' ) - email = models.EmailField ( null = True, help_text = 'The email id to respond to' ) - content = models.CharField ( max_length = 10000, null = True, help_text= 'Please stick to the point' ) - radiocontent = models.CharField ( max_length = 10000, null = True) - def __unicode__(self): - return self.content - - class Admin: - pass + pass class Team(models.Model): - name = models.CharField(max_length = 50) + name = models.CharField(max_length = 50) event = models.ForeignKey(Event, null = False) leader = models.ForeignKey(User, related_name = 'own_teams', blank = False, null = False) members = models.ManyToManyField(User, related_name = 'joined_teams', blank = True, null = True) def __unicode__(self): return self.name - - class Admin: - pass - -''' + ''' + class Meta: + unique_together('name', 'event', ) + ''' diff --git a/users/tests.py b/users/tests.py index 501deb7..a9d5fb0 100644 --- a/users/tests.py +++ b/users/tests.py @@ -1,3 +1,6 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + """ This file demonstrates writing tests using the unittest module. These will pass when you run "manage.py test". @@ -9,8 +12,12 @@ class SimpleTest(TestCase): + def test_basic_addition(self): """ Tests that 1 + 1 always equals 2. """ + self.assertEqual(1 + 1, 2) + + diff --git a/users/urls.py b/users/urls.py index d4fdc40..220fa18 100644 --- a/users/urls.py +++ b/users/urls.py @@ -1,20 +1,53 @@ +#!/usr/bin/python # -*- coding: utf-8 -*- + from django.conf.urls.defaults import * from users.views import * import django.contrib.auth.views from django.views.generic.simple import redirect_to -urlpatterns = patterns('', - url(r'^login/$', 'views.method_splitter', {'GET': login_get, 'POST': login_post}), - url(r'^register/$', 'views.method_splitter', {'GET': register_get, 'POST': register_post}), - url(r'^register_fb/$', register_post_fb), - url(r'^register/activate/(?P[\w]+)/?$', 'main_site.users.views.activate'), - url(r'^editprofile/$', 'views.method_splitter', {'GET': editprofile_get, 'POST': editprofile_post}), +urlpatterns = patterns( # url(r'^reset/(?P[0-9A-Za-z]+)-(?P.+)/$', 'django.contrib.auth.views.password_reset_confirm'), + '', + url(r'^login/$', 'views.method_splitter', {'GET': login_get, + 'POST': login_post}), + url(r'^register/$', 'views.method_splitter', {'GET': register_get, + 'POST': register_post}), + url(r'^register_fb/$', register_post_fb), + url(r'^register/activate/(?P[\w]+)/?$', + 'users.views.activate'), + url(r'^editprofile/$', 'views.method_splitter', + {'GET': editprofile_get, 'POST': editprofile_post}), url(r'^facebook/login/?$', 'users.fb_views.login'), - url(r'^facebook/authentication_callback/?$', 'users.fb_views.authentication_callback'), - url(r'^password_change/$', 'django.contrib.auth.views.password_change'), - url(r'^password_change/done/$', 'django.contrib.auth.views.password_change_done'), - url(r'^logout/$', 'users.views.logout', name = 'logout'), - url(r'^$',redirect_to,{'url':'/2013/main/test'}), + url(r'^facebook/authentication_callback/?$', + 'users.fb_views.authentication_callback'), + url(r'^password_change/$', + 'django.contrib.auth.views.password_change'), + url(r'^password_change/done/$', + 'django.contrib.auth.views.password_change_done'), + url(r'^logout/$', 'users.views.logout', name='logout'), + url(r'^$', redirect_to, {'url': '/2013/main/test'}), + url(r'^admin/password_reset/$', + 'django.contrib.auth.views.password_reset', + name='password_reset'), + url(r'^password_reset/done/$', + 'django.contrib.auth.views.password_reset_done'), + url(r'^reset/(?P[0-9A-Za-z]+)-(?P.+)/$', + 'django.contrib.auth.views.password_reset_confirm'), + url(r'^reset/done/$', + 'django.contrib.auth.views.password_reset_complete'), + url(r'^events/$', 'users.views.events'), + url(r'^ajax_login/$', ajax_login_link), + ) + +# URLs for teams +urlpatterns += patterns('', + url(r'^teams/(?P\d+)/$', team_home), + url(r'^teams/create/(?P\d+)/$', create_team), + url(r'^teams/(?P\d+)/add_member/$', add_member), + url(r'^teams/(?P\d+)/change_leader/$', change_team_leader), + url(r'^teams/(?P\d+)/drop_out/$', drop_out), + url(r'^teams/(?P\d+)/remove_member/$', remove_member), + url(r'^teams/(?P\d+)/dissolve/$', dissolve_team), + ) + # url(r'^admin/$','users.views.admin', name="super-user"), -) diff --git a/users/views.py b/users/views.py index 34a33b6..bcd594e 100644 --- a/users/views.py +++ b/users/views.py @@ -1,158 +1,233 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import django from django.http import HttpResponse, HttpResponseRedirect, Http404 from django.contrib.auth.models import User, Group from django.template.context import Context, RequestContext from django.template.loader import get_template from django.shortcuts import render_to_response from django.views.decorators.csrf import csrf_exempt -from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout +from django.contrib.auth import authenticate, login as auth_login, \ + logout as auth_logout from django.contrib.auth.decorators import login_required from django.conf import settings +from events.models import Event from users.models import UserProfile, College from django.utils.translation import ugettext as _ from users.forms import * from django.contrib.sessions.models import Session -from django.core.mail import send_mail,EmailMessage,SMTPConnection,EmailMultiAlternatives -import sha,random,datetime +from django.core.mail import EmailMessage, EmailMultiAlternatives +from django.core.mail import send_mail as mailsender +from recaptcha.client import captcha +import sha +import random +import datetime + def login_get(request): - if request.user.is_authenticated() : - currentuser=request.user - currentUserProfile=currentuser.get_profile() - if request.user.is_superuser : + if request.user.is_authenticated(): + currentuser = request.user + if request.user.is_superuser: return HttpResponseRedirect(settings.SITE_URL + 'admin/') - elif currentUserProfile.is_core : + elif currentuser.get_profile().is_core: return HttpResponseRedirect(settings.SITE_URL + 'core/') - elif currentUserProfile.is_coord_of : + elif currentuser.get_profile().is_coord_of: return HttpResponseRedirect(settings.SITE_URL + 'coord/') else: return HttpResponseRedirect(settings.SITE_URL) form = LoginForm() - return render_to_response('users/login.html',locals(),context_instance = RequestContext(request)) - + try: + msg=request.session['msg'] + del request.session['msg'] + except: + pass + return render_to_response('users/login.html', locals(), + context_instance=RequestContext(request)) + + def login_post(request): username = request.POST.get('username', '') password = request.POST.get('password', '') - user = authenticate(username = username, password = password) + user = authenticate(username=username, password=password) if user is not None and user.is_active: auth_login(request, user) - if user.is_superuser : + nextURL = request.GET.get('next', '') + if nextURL != '': + nextURL = nextURL[1:] # For removing the leading slash from in front of the next parameter + redirectURL = settings.SITE_URL + nextURL + return HttpResponseRedirect(redirectURL) + if user.is_superuser: return HttpResponseRedirect(settings.SITE_URL + 'admin/') - elif user.get_profile().is_core : + elif user.get_profile().is_core: return HttpResponseRedirect(settings.SITE_URL + 'core/') - elif user.get_profile().is_coord_of : + elif user.get_profile().is_coord_of: return HttpResponseRedirect(settings.SITE_URL + 'coord/') else: return HttpResponseRedirect(settings.SITE_URL) - msg="Username and Password does not match." - form=LoginForm() - return render_to_response('users/login.html',locals(),context_instance = RequestContext(request)) + msg = 'Username and Password does not match.' + form = LoginForm() + return render_to_response('users/login.html', locals(), + context_instance=RequestContext(request)) + -@login_required(login_url=settings.SITE_URL + 'user/login/') +#@login_required(login_url=settings.SITE_URL + 'user/login/') def logout(request): auth_logout(request) return HttpResponseRedirect(settings.SITE_URL) + def register_get(request): form = AddUserForm() - post_url = settings.SITE_URL+'user/register/' - return render_to_response('users/register.html', locals(), context_instance = RequestContext(request)) - + post_url = settings.SITE_URL + 'user/register/' + captcha_response = '' # Added so that nothing gets displayed in the template if this variable is not set + return render_to_response('users/register.html', locals(), + context_instance=RequestContext(request)) + + def register_post(request): """ This is the user registration view """ - + form = AddUserForm(request.POST) - if form.is_valid(): - data = form.cleaned_data - new_user = User(first_name = data['first_name'], last_name=data['last_name'], username= data['username'], email = data['email']) - new_user.set_password(data['password']) - new_user.is_active= False - new_user.save() - salt = sha.new(str(random.random())).hexdigest()[:5] - activation_key = sha.new(salt+new_user.username).hexdigest() - key_expires = datetime.datetime.today() + datetime.timedelta(2) - userprofile = UserProfile( - user = new_user, - activation_key = activation_key, - key_expires = key_expires, - gender = data['gender'], - age = data['age'], - branch = data['branch'], - mobile_number = data['mobile_number'], - college = data['college'], - college_roll = data['college_roll'], + captcha_response = '' # Added so that nothing gets displayed in the template if this variable is not set + + # talk to the reCAPTCHA service + response = captcha.submit( + request.POST.get('recaptcha_challenge_field'), + request.POST.get('recaptcha_response_field'), + settings.RECAPTCHA_PRIVATE_KEY, + request.META['REMOTE_ADDR'],) + + # see if the user correctly entered CAPTCHA information + # and handle it accordingly. + if response.is_valid: + if form.is_valid(): + data = form.cleaned_data + new_user = User(first_name=data['first_name'], + last_name=data['last_name'], + username=data['username'], email=data['email']) + new_user.set_password(data['password']) + new_user.is_active = False + new_user.save() + x = 1300000 + new_user.id + salt = sha.new(str(random.random())).hexdigest()[:5] + activation_key = sha.new(salt + new_user.username).hexdigest() + key_expires = datetime.datetime.today() + datetime.timedelta(2) + userprofile = UserProfile( + user=new_user, + activation_key=activation_key, + key_expires=key_expires, + gender=data['gender'], + age=data['age'], + branch=data['branch'], + mobile_number=data['mobile_number'], + college=data['college'], + college_roll=data['college_roll'], + shaastra_id= ("SHA" + str(x)), + want_accomodation = data['want_accomodation'], ) - userprofile.save() - mail_template=get_template('email/activate.html') - body = mail_template.render(Context({'username':new_user.username, - 'SITE_URL':settings.SITE_URL, - 'activationkey':userprofile.activation_key })) - send_mail('Your new Shaastra2013 account confirmation', body,'noreply@shaastra.org', [new_user.email,], fail_silently=False) - request.session['registered_user'] = True -# new_user = authenticate(username = data['username'], password = data['password']) -# auth_login(request, new_user) - msg='A mail has been sent to the mail id u provided. Please activate your account within 48 hours.' - form = LoginForm() - return render_to_response('users/login.html', locals(), context_instance = RequestContext(request)) - return render_to_response('users/register.html', locals(), context_instance = RequestContext(request)) + userprofile.save() + mail_template = get_template('email/activate.html') + body = \ + mail_template.render(Context({'username': new_user.username, + 'SITE_URL': settings.SITE_URL, + 'activationkey': userprofile.activation_key})) + mailsender('Your new Shaastra2013 account confirmation', body, + 'noreply@shaastra.org', [new_user.email], + fail_silently=False) + request.session['registered_user'] = True + request.session['msg']="A mail has been sent to the mail id you provided. Please activate your account within 48 hours. Check your spam folder if you do not receive the mail in your inbox." + return HttpResponseRedirect(settings.SITE_URL+'user/login') + else: + captcha_response = response.error_code + return render_to_response('users/register.html', locals(), + context_instance=RequestContext(request)) + def register_post_fb(request): """ This is the user registration view for fb """ + form = FacebookUserForm(request.POST) facebook_id = request.POST['facebook_id'] access_token = request.POST['access_token'] if form.is_valid(): data = form.cleaned_data - new_user = User(first_name = data['first_name'], last_name=data['last_name'], username= data['username'], email = data['email']) + new_user = User(first_name=data['first_name'], + last_name=data['last_name'], + username=data['username'], email=data['email']) new_user.set_password('default') new_user.save() + x = 1300000 + new_user.id userprofile = UserProfile( - user = new_user, - gender = data['gender'], - age = data['age'], - branch = data['branch'], - mobile_number = data['mobile_number'], - college = data['college'], - college_roll = data['college_roll'], - facebook_id = facebook_id, - access_token = access_token, - ) + user=new_user, + gender=data['gender'], + age=data['age'], + branch=data['branch'], + mobile_number=data['mobile_number'], + college=data['college'], + college_roll=data['college_roll'], + facebook_id=facebook_id, + access_token=access_token, + shaastra_id = "SHA" + str(x), + ) userprofile.save() - new_user = authenticate(username = data['username'], password = "default") + new_user = authenticate(username=data['username'], + password='default') auth_login(request, new_user) return HttpResponseRedirect(settings.SITE_URL) - return render_to_response('users/register.html', locals(), context_instance = RequestContext(request)) + return render_to_response('users/register.html', locals(), + context_instance=RequestContext(request)) -@login_required(login_url=settings.SITE_URL + "user/login/") + +@login_required(login_url=settings.SITE_URL + 'user/login/') def editprofile_get(request): currentUser = request.user currentUserProfile = currentUser.get_profile() - values = { 'first_name' : currentUser.first_name, - 'last_name' : currentUser.last_name,} - editProfileForm = EditUserForm(instance=currentUserProfile,initial=values) - return render_to_response('users/edit_profile.html', locals(), context_instance = RequestContext(request)) + values = {'first_name': currentUser.first_name, + 'last_name': currentUser.last_name} + editProfileForm = EditUserForm(instance=currentUserProfile, + initial=values) + if request.user.get_profile().is_core \ + or request.user.get_profile().is_coord_of: + return render_to_response('users/edit_profile_c.html', + locals(), + context_instance=RequestContext(request)) + else: + return render_to_response('users/edit_profile.html', locals(), + context_instance=RequestContext(request)) -@login_required(login_url=settings.SITE_URL + "user/login/") + +@login_required(login_url=settings.SITE_URL + 'user/login/') def editprofile_post(request): """ Edits a user's profile. """ + currentUser = request.user currentUserProfile = currentUser.get_profile() - editProfileForm = EditUserForm(request.POST,instance=currentUserProfile) + editProfileForm = EditUserForm(request.POST, + instance=currentUserProfile) if editProfileForm.is_valid(): editProfileForm.save() currentUser.first_name = request.POST['first_name'] currentUser.last_name = request.POST['last_name'] currentUser.save() - return HttpResponseRedirect (settings.SITE_URL) - return render_to_response('users/edit_profile.html', locals(), context_instance = RequestContext(request)) + return HttpResponseRedirect(settings.SITE_URL) + if request.user.get_profile().is_core \ + or request.user.get_profile().is_coord_of: + return render_to_response('users/edit_profile_c.html', + locals(), + context_instance=RequestContext(request)) + else: + return render_to_response('users/edit_profile.html', locals(), + context_instance=RequestContext(request)) + -def activate (request, a_key = None ): +def activate(request, a_key=None): """ The activation_key (a_key) is trapped from the url. If the key is not empty then the corresponding userprofile object is retrieved. If the object doesn't exist and ObjectDoesNotExist error is flagged. @@ -160,62 +235,239 @@ def activate (request, a_key = None ): Note that, if is_active is not set to true, the user cannot login. """ + SITE_URL = settings.SITE_URL - if (a_key == '' or a_key==None): - key_dne = True + if a_key == '' or a_key == None: + key_dne = True else: try: - user_profile = UserProfile.objects.get(activation_key = a_key) + user_profile = UserProfile.objects.get(activation_key=a_key) except ObjectDoesNotExist: prof_dne = True - # try-except-else is actually there! God knows what for... Nested try blocks work just as well... else: + + # try-except-else is actually there! God knows what for... Nested try blocks work just as well... + if user_profile.user.is_active == True: activated = True elif user_profile.key_expires < datetime.datetime.today(): - expired = True - user = user_profile.user - user.delete() - user_profile.delete() + expired = True + user = user_profile.user + user.delete() + user_profile.delete() else: user = user_profile.user user.is_active = True + x = 1300000 + user.id + user_profile.shaastra_id = "SHA"+ str(x) + user_profile.save() user.save() - request.session["registered"] = True + request.session['registered'] = True activated = True - return render_to_response('users/activated.html',locals(), context_instance= RequestContext(request)) + return render_to_response('users/activated.html', locals(), + context_instance=RequestContext(request)) -''' -def forgot_password(request): - reset_password_form = forms.ResetPasswordForm() - username_form = forms.UsernameForm() - if request.method == 'GET' and 'password_key' in request.GET: +def events(request): + event = Event.objects.all() + return render_to_response('users/events.html', locals(), + context_instance=RequestContext(request)) + + +def ajax_login_link(request): + return HttpResponse('Click here to login' + % settings.SITE_URL) + +### Views for teams: + +def get_authentic_team(request = None, team_id = None): + if team_id is None or request is None: + return None + try: + team = Team.objects.get(pk = int(team_id)) try: - profile = UserProfile.objects.get(activation_key = request.GET['password_key']) - profile.save() - user = profile.user - reset_password_form = forms.ResetPasswordForm(initial = {'user' : user.id, }) - return render_to_response('users/reset_password_form.html', locals(), context_instance = global_context(request)) - except UserProfile.DoesNotExist: - raise Http404 - elif request.method == 'POST': - username_form = forms.UsernameForm(request.POST) - if username_form.is_valid(): - username = username_form.cleaned_data['username'] - user = User.objects.get(username = username) - profile = user.get_profile() - salt = sha.new(str(random.random())).hexdigest()[:5] - profile.activation_key = sha.new(salt+user.username).hexdigest() - profile.save() - - mail_template = get_template('email/forgot_password.html') - body = mail_template.render(Context( { - 'username' : user.username, - 'SITE_URL' : settings.SITE_URL, - 'passwordkey' : profile.activation_key - } )) - send_mail('[Shaastra 2011] Password reset request', body,'noreply@shaastra.org', [user.email,], fail_silently = False) - return HttpResponseRedirect('%smyshaastra/forgot_password/done/' % settings.SITE_URL) - return render_to_response('users/username_form.html', locals(), context_instance = global_context(request)) -''' \ No newline at end of file + team.members.get(pk = request.user.id) + return team + # Non-members fail the test + except User.DoesNotExist: + return None + except Team.DoesNotExist: + return None + return None + +@login_required +def team_home(request, team_id = None): + team = get_authentic_team(request, team_id) + if team is not None: + add_member_form = AddMemberForm() + change_leader_form = ChangeLeaderForm() + event = team.event + team_size = team.members.count() + if team_size > event.team_size_max: + team_size_message = 'big' + elif team_size < event.team_size_min: + team_size_message = 'small' + else: + team_size_message = 'correct' + return render_to_response('users/teams/team_home.html', locals(), context_instance = RequestContext(request)) + raise Http404 + +@login_required +def create_team(request, event_id = None): + if event_id is None: + raise Http404 + user = request.user + try: + event = Event.objects.get(pk = int(event_id)) + except: + raise Http404('You have requested for an invalid event.') + if not event.begin_registration: + raise Http404('The registrations for this event have closed. New teams can no longer be registered.') + form = CreateTeamForm(initial = {'event' : event.id, } ) + view = "Create" + if request.method == 'POST': + form = CreateTeamForm(request.POST) + if form.is_valid(): + try: + Team.objects.get(members__pk = request.user.id, event = form.cleaned_data['event']) + return render_to_response('users/teams/already_part_of_a_team.html', locals(), context_instance = RequestContext(request)) + except Team.DoesNotExist: + pass + team = form.save(commit = False) + team.leader = user + ''' + try: + team.leader.get_profile().registered.get(pk = team.event.id) + except Event.DoesNotExist: + team.leader.get_profile().registered.add(team.event) + ''' + team.save() + team.members.add(user) + return HttpResponseRedirect('%suser/teams/%s/' % (settings.SITE_URL, team.id)) + return render_to_response('users/teams/create_team.html', locals(), context_instance = RequestContext(request)) + +''' +def join_team(request): + user = request.user + form = JoinTeamForm() + view = "Join" + if request.method == 'POST': + form = JoinTeamForm(request.POST) + if form.is_valid(): + team = Team.objects.get(name = form.cleaned_data['name'], event = form.cleaned_data['event']) + team.join_requests.add(user) + return HttpResponseRedirect('%smyshaastra/' % settings.SITE_URL) + return render_to_response('myshaastra/team_form.html', locals(), context_instance = RequestContext['request']) +''' + +@login_required +def add_member(request, team_id = None): + team = get_authentic_team(request, team_id) + if team is not None: + event = team.event + team_size = team.members.count() + if team_size == event.team_size_max: + raise Http404('Your team is already of the maximum permitted size. You cannot add more people to the team without removing someone.') + add_member_form = AddMemberForm() + change_leader_form = ChangeLeaderForm() + + if team_size > event.team_size_max: + team_size_message = 'big' + elif team_size < event.team_size_min: + team_size_message = 'small' + else: + team_size_message = 'correct' + + if request.method == 'POST': + user = request.user + add_member_form = AddMemberForm(request.POST) + if add_member_form.is_valid(): + if user != team.leader: + return render_to_response('users/teams/you_arent_leader.html', locals(), context_instance = RequestContext(request)) + member = User.objects.get(username = add_member_form.cleaned_data['member']) + ''' + # autoregister member on addition to the team + try: + member.get_profile().registered.get(pk = team.event.id) + except Event.DoesNotExist: + member.get_profile().registered.add(team.event) + ''' + team.members.add(member) + return HttpResponseRedirect('%suser/teams/%s/' % (settings.SITE_URL, team.id)) + else: + try: + if add_member_form['member'].errors != []: + return render_to_response( + 'users/teams/already_part_of_a_team.html', + { 'user' : request.POST['member'], }, + context_instance = RequestContext(request) + ) + except KeyError: + pass + return render_to_response('users/teams/team_home.html', locals(), context_instance = RequestContext(request)) + raise Http404 + +@login_required +def change_team_leader(request, team_id = None): + team = get_authentic_team(request, team_id) + if team is not None: + change_leader_form = ChangeLeaderForm() + add_member_form = AddMemberForm() + if request.method == 'POST': + user = request.user + change_leader_form = ChangeLeaderForm(request.POST) + if change_leader_form.is_valid(): + if user != team.leader: + return render_to_response('users/teams/you_arent_leader.html', locals(), context_instance = RequestContext(request)) + new_leader = team.members.get(username = change_leader_form.cleaned_data['new_leader']) + team.leader = new_leader + team.save() + return HttpResponseRedirect('%suser/teams/%s/' % (settings.SITE_URL, team.id)) + return render_to_response('users/teams/team_home.html', locals(), context_instance = RequestContext(request)) + raise Http404 + +@login_required +def drop_out(request, team_id = None): + team = get_authentic_team(request, team_id) + if team is not None: + user = request.user + if user == team.leader: + return render_to_response('users/teams/you_are_leader.html', locals(), context_instance = RequestContext(request)) + else: + team.members.remove(user) + return HttpResponseRedirect('%sevents/' % settings.SITE_URL) + raise Http404 + +@login_required +def remove_member(request, team_id = None): + team = get_authentic_team(request, team_id) + if team is not None: + change_leader_form = ChangeLeaderForm() # it is the same form essentially :P + add_member_form = AddMemberForm() + if request.method == 'POST': + user = request.user + change_leader_form = ChangeLeaderForm(request.POST) + if change_leader_form.is_valid(): + team = Team.objects.get(pk = change_leader_form.cleaned_data['team_id']) + if user != team.leader: + return render_to_response('users/teams/you_arent_leader.html', locals(), context_instance = RequestContext(request)) + new_leader = team.members.get(username = change_leader_form.cleaned_data['new_leader']) + team.members.remove(new_leader) # yes i know, it looks bad. but what the hell. i'm lazy. + return HttpResponseRedirect('%suser/teams/%s/' % (settings.SITE_URL, team.id)) + return render_to_response('users/teams/team_home.html', locals(), context_instance = RequestContext(request)) + raise Http404 + +@login_required +def dissolve_team(request, team_id = None): + team = get_authentic_team(request, team_id) + if team is not None: + if team.members.all().count() > 1: + return render_to_response('users/teams/remove_members_first.html', locals(), context_instance = RequestContext(request)) + else: + if team.leader != request.user: + return render_to_response('users/teams/you_arent_leader.html', locals(), context_instance = RequestContext(request)) + team.members.clear() + team.delete() + return HttpResponseRedirect('%sevents/' % settings.SITE_URL) + raise Http404 + diff --git a/views.py b/views.py index e441b68..17baed0 100755 --- a/views.py +++ b/views.py @@ -2,18 +2,68 @@ from django.template.context import Context, RequestContext from django.shortcuts import render_to_response from django.conf import settings +from events.models import Event, EVENT_CATEGORIES, Tag, Update, Sponsor +from django.template.defaultfilters import slugify +from events.views import home as events_home def home(request): + fragment = request.GET.get('_escaped_fragment_','') + splits = fragment.split('/') + if fragment == 'hospi': + return render_to_response('ajax/hospi_home.html',locals(),context_instance = RequestContext(request)) + elif fragment == 'spons': + return render_to_response('ajax/spons_home.html',locals(),context_instance = RequestContext(request)) + elif splits[0] == 'events': + return events_home(request) + event_set=[] + for c in EVENT_CATEGORIES : + event_category_set = Event.objects.filter(category=c[0]) + if event_category_set : + event_set.append(event_category_set) + + #Code for search + result_list=[] + for t in Tag.objects.all(): + row=[] + row.append(str(t.name)) + temp=[] + for x in t.event_set.all(): + url = slugify(x) + temp.append([str(x),str(url)]) + row.append(temp) + result_list.append(row) + #End of search code + # adding code for announcements on main page + events = Event.objects.all() + announcements = [] + for e in events: + try: + data = {'event':e,'announcement':Update.objects.get(event = e, category = "Announcement"),} + announcements.append(data) + except: + pass + # end announcements code if request.user.is_authenticated(): if request.user.is_superuser: return HttpResponseRedirect(settings.SITE_URL + 'admin/') elif request.user.get_profile().is_core: return HttpResponseRedirect(settings.SITE_URL + 'core/') + elif request.user.get_profile().is_coord_of: + return HttpResponseRedirect(settings.SITE_URL + 'coord/') else: - return render_to_response('home.html',locals(),context_instance = RequestContext(request)) + return render_to_response('index.html',locals(),context_instance = RequestContext(request)) else: - return render_to_response('home.html',locals(),context_instance = RequestContext(request)) - + return render_to_response('index.html',locals(),context_instance = RequestContext(request)) + +def hospi(request): + return render_to_response('hospi/hospi_home.html',locals(),context_instance = RequestContext(request)) + +def spons(request): + present_sponsors = Sponsor.objects.filter(year=2013).order_by('index_number') + previous_sponsors = Sponsor.objects.filter(year=2011).order_by('index_number') + previous_sponsors2 = Sponsor.objects.filter(year=2010).order_by('index_number') + return render_to_response('spons_home.html',locals(),context_instance = RequestContext(request)) + def method_splitter(request, *args, **kwargs): get_view = kwargs.pop('GET', None) post_view = kwargs.pop('POST', None) @@ -21,4 +71,4 @@ def method_splitter(request, *args, **kwargs): return get_view(request, *args, **kwargs) elif request.method == 'POST' and post_view is not None: return post_view(request, *args, **kwargs) - raise Http404 \ No newline at end of file + raise Http404