From 4cc0e0fe4f1c401b478cb841ebf712719e79659d Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 20 Jun 2017 11:08:14 -0400 Subject: [PATCH] delete regluit.questionnaire --- core/models/bibmodels.py | 2 +- frontend/forms.py | 2 +- frontend/views.py | 4 +- questionnaire/__init__.py | 83 -- questionnaire/admin.py | 97 -- questionnaire/apps.py | 29 - questionnaire/context_processors/__init__.py | 0 questionnaire/context_processors/settings.py | 23 - questionnaire/dependency_checker.py | 147 --- questionnaire/emails.py | 156 --- questionnaire/fixtures/sampleSurvey.json | 512 -------- questionnaire/fixtures/testQuestions.yaml | 455 ------- questionnaire/langtemplateloader.py | 58 - questionnaire/legacy_test_urls.py | 17 - questionnaire/legacy_tests.py | 192 --- questionnaire/locale/de/LC_MESSAGES/django.po | 158 --- questionnaire/locale/fr/LC_MESSAGES/django.po | 160 --- questionnaire/locale/it/LC_MESSAGES/django.po | 174 --- questionnaire/locale/ru/LC_MESSAGES/django.mo | Bin 3375 -> 0 bytes questionnaire/locale/ru/LC_MESSAGES/django.po | 190 --- questionnaire/management/__init__.py | 0 questionnaire/management/commands/__init__.py | 0 .../management/commands/make_survey_nonces.py | 14 - .../commands/questionnaire_emails.py | 8 - questionnaire/migrations/0001_initial.py | 208 ---- .../migrations/0002_auto_20160929_1320.py | 36 - .../migrations/0003_auto_20160929_1321.py | 36 - .../migrations/0004_auto_20160929_1800.py | 47 - questionnaire/migrations/__init__.py | 0 questionnaire/models.py | 542 -------- questionnaire/modelutils.py | 5 - questionnaire/page/__init__.py | 0 questionnaire/page/admin.py | 8 - questionnaire/page/models.py | 21 - questionnaire/page/views.py | 40 - questionnaire/parsers.py | 142 --- questionnaire/profiler.py | 68 - questionnaire/qprocessors/__init__.py | 10 - questionnaire/qprocessors/choice.py | 224 ---- questionnaire/qprocessors/custom.py | 28 - questionnaire/qprocessors/range_or_number.py | 107 -- questionnaire/qprocessors/simple.py | 137 -- questionnaire/qprocessors/timeperiod.py | 62 - questionnaire/request_cache.py | 75 -- .../static/bootstrap/bootstrap.min.css | 6 - questionnaire/static/jquery-1.7.1.min.js | 4 - questionnaire/static/progress.js | 17 - questionnaire/static/progressbar.css | 114 -- questionnaire/static/questionnaire.css | 146 --- questionnaire/static/questionset.js | 147 --- questionnaire/static/range.js | 59 - .../questionnaire/question/change_form.html | 17 - .../questionnaire/question/change_list.html | 37 - .../questionnaire/subject/change_form.html | 14 - .../templates/base-questionnaire.html | 57 - questionnaire/templates/page.html | 12 - questionnaire/templates/pages/complete.html | 8 - questionnaire/templates/pages/generic.html | 14 - questionnaire/templates/pages/summaries.html | 35 - .../questionnaire/choice-freeform.html | 25 - .../choice-multiple-freeform.html | 52 - .../questionnaire/choice-yesnocomment.html | 43 - .../templates/questionnaire/choice.html | 20 - .../templates/questionnaire/comment.html | 0 .../templates/questionnaire/complete.de.html | 10 - .../templates/questionnaire/complete.en.html | 18 - .../templates/questionnaire/custom.html | 1 - .../templates/questionnaire/dropdown.html | 11 - .../templates/questionnaire/number.html | 9 - .../questionnaire/open-textfield.html | 9 - .../templates/questionnaire/open.html | 10 - .../templates/questionnaire/questionset.html | 186 --- .../templates/questionnaire/range.html | 1 - .../templates/questionnaire/timeperiod.html | 13 - questionnaire/templatetags/__init__.py | 0 .../templatetags/dynamicStyleTags.py | 15 - questionnaire/templatetags/landings.py | 15 - questionnaire/templatetags/questionnaire.py | 29 - questionnaire/tests.py | 62 - questionnaire/urls.py | 41 - questionnaire/utils.py | 92 -- questionnaire/utils_noncircular.py | 20 - questionnaire/views.py | 1107 ----------------- requirements_versioned.pip | 1 + settings/common.py | 8 +- urls.py | 2 +- 86 files changed, 11 insertions(+), 6753 deletions(-) delete mode 100644 questionnaire/__init__.py delete mode 100644 questionnaire/admin.py delete mode 100644 questionnaire/apps.py delete mode 100644 questionnaire/context_processors/__init__.py delete mode 100644 questionnaire/context_processors/settings.py delete mode 100644 questionnaire/dependency_checker.py delete mode 100644 questionnaire/emails.py delete mode 100644 questionnaire/fixtures/sampleSurvey.json delete mode 100644 questionnaire/fixtures/testQuestions.yaml delete mode 100644 questionnaire/langtemplateloader.py delete mode 100644 questionnaire/legacy_test_urls.py delete mode 100644 questionnaire/legacy_tests.py delete mode 100644 questionnaire/locale/de/LC_MESSAGES/django.po delete mode 100644 questionnaire/locale/fr/LC_MESSAGES/django.po delete mode 100644 questionnaire/locale/it/LC_MESSAGES/django.po delete mode 100644 questionnaire/locale/ru/LC_MESSAGES/django.mo delete mode 100644 questionnaire/locale/ru/LC_MESSAGES/django.po delete mode 100644 questionnaire/management/__init__.py delete mode 100644 questionnaire/management/commands/__init__.py delete mode 100644 questionnaire/management/commands/make_survey_nonces.py delete mode 100644 questionnaire/management/commands/questionnaire_emails.py delete mode 100644 questionnaire/migrations/0001_initial.py delete mode 100644 questionnaire/migrations/0002_auto_20160929_1320.py delete mode 100644 questionnaire/migrations/0003_auto_20160929_1321.py delete mode 100644 questionnaire/migrations/0004_auto_20160929_1800.py delete mode 100644 questionnaire/migrations/__init__.py delete mode 100644 questionnaire/models.py delete mode 100644 questionnaire/modelutils.py delete mode 100644 questionnaire/page/__init__.py delete mode 100644 questionnaire/page/admin.py delete mode 100644 questionnaire/page/models.py delete mode 100644 questionnaire/page/views.py delete mode 100644 questionnaire/parsers.py delete mode 100644 questionnaire/profiler.py delete mode 100644 questionnaire/qprocessors/__init__.py delete mode 100644 questionnaire/qprocessors/choice.py delete mode 100644 questionnaire/qprocessors/custom.py delete mode 100644 questionnaire/qprocessors/range_or_number.py delete mode 100644 questionnaire/qprocessors/simple.py delete mode 100644 questionnaire/qprocessors/timeperiod.py delete mode 100644 questionnaire/request_cache.py delete mode 100644 questionnaire/static/bootstrap/bootstrap.min.css delete mode 100644 questionnaire/static/jquery-1.7.1.min.js delete mode 100644 questionnaire/static/progress.js delete mode 100644 questionnaire/static/progressbar.css delete mode 100644 questionnaire/static/questionnaire.css delete mode 100644 questionnaire/static/questionset.js delete mode 100644 questionnaire/static/range.js delete mode 100644 questionnaire/templates/admin/questionnaire/question/change_form.html delete mode 100644 questionnaire/templates/admin/questionnaire/question/change_list.html delete mode 100644 questionnaire/templates/admin/questionnaire/subject/change_form.html delete mode 100644 questionnaire/templates/base-questionnaire.html delete mode 100644 questionnaire/templates/page.html delete mode 100644 questionnaire/templates/pages/complete.html delete mode 100644 questionnaire/templates/pages/generic.html delete mode 100644 questionnaire/templates/pages/summaries.html delete mode 100644 questionnaire/templates/questionnaire/choice-freeform.html delete mode 100644 questionnaire/templates/questionnaire/choice-multiple-freeform.html delete mode 100644 questionnaire/templates/questionnaire/choice-yesnocomment.html delete mode 100644 questionnaire/templates/questionnaire/choice.html delete mode 100644 questionnaire/templates/questionnaire/comment.html delete mode 100644 questionnaire/templates/questionnaire/complete.de.html delete mode 100644 questionnaire/templates/questionnaire/complete.en.html delete mode 100644 questionnaire/templates/questionnaire/custom.html delete mode 100644 questionnaire/templates/questionnaire/dropdown.html delete mode 100644 questionnaire/templates/questionnaire/number.html delete mode 100644 questionnaire/templates/questionnaire/open-textfield.html delete mode 100644 questionnaire/templates/questionnaire/open.html delete mode 100644 questionnaire/templates/questionnaire/questionset.html delete mode 100644 questionnaire/templates/questionnaire/range.html delete mode 100644 questionnaire/templates/questionnaire/timeperiod.html delete mode 100644 questionnaire/templatetags/__init__.py delete mode 100644 questionnaire/templatetags/dynamicStyleTags.py delete mode 100644 questionnaire/templatetags/landings.py delete mode 100644 questionnaire/templatetags/questionnaire.py delete mode 100644 questionnaire/tests.py delete mode 100644 questionnaire/urls.py delete mode 100644 questionnaire/utils.py delete mode 100644 questionnaire/utils_noncircular.py delete mode 100644 questionnaire/views.py diff --git a/core/models/bibmodels.py b/core/models/bibmodels.py index 618ed188..826c5685 100644 --- a/core/models/bibmodels.py +++ b/core/models/bibmodels.py @@ -24,7 +24,7 @@ from django.db.models.signals import post_save, pre_delete import regluit from regluit.marc.models import MARCRecord as NewMARC from regluit.utils.localdatetime import now -from regluit.questionnaire.models import Landing +from questionnaire.models import Landing from regluit.core import mobi import regluit.core.cc as cc diff --git a/frontend/forms.py b/frontend/forms.py index b333d366..fa4f0785 100644 --- a/frontend/forms.py +++ b/frontend/forms.py @@ -71,7 +71,7 @@ from regluit.utils.text import sanitize_line, remove_badxml from regluit.mobi import Mobi from regluit.pyepub import EPUB from regluit.bisac.models import BisacHeading -from regluit.questionnaire.models import Questionnaire +from questionnaire.models import Questionnaire logger = logging.getLogger(__name__) nulls = [False, 'delete', ''] diff --git a/frontend/views.py b/frontend/views.py index 78d67c12..ec64a671 100755 --- a/frontend/views.py +++ b/frontend/views.py @@ -134,8 +134,8 @@ from regluit.libraryauth.forms import UserNamePass from regluit.libraryauth.views import Authenticator, superlogin, login_user from regluit.libraryauth.models import Library from regluit.marc.views import qs_marc_records -from regluit.questionnaire.models import Landing, Questionnaire -from regluit.questionnaire.views import export_summary as answer_summary, export_csv as export_answers +from questionnaire.models import Landing, Questionnaire +from questionnaire.views import export_summary as answer_summary, export_csv as export_answers logger = logging.getLogger(__name__) diff --git a/questionnaire/__init__.py b/questionnaire/__init__.py deleted file mode 100644 index d11a5a99..00000000 --- a/questionnaire/__init__.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -questionnaire - Django Questionnaire App -======================================== - -Create flexible questionnaires. - -Author: Robert Thomson -""" - -from django.dispatch import Signal - -__all__ = ['question_proc', 'answer_proc', 'add_type', 'AnswerException', - 'questionset_done', 'questionnaire_done', ] - -default_app_config = '{}.apps.QuestionnaireConfig'.format(__name__) - -QuestionChoices = [] -QuestionProcessors = {} # supply additional information to the templates -Processors = {} # for processing answers - -questionnaire_start = Signal(providing_args=["runinfo", "questionnaire"]) -questionset_start = Signal(providing_args=["runinfo", "questionset"]) -questionset_done = Signal(providing_args=["runinfo", "questionset"]) -questionnaire_done = Signal(providing_args=["runinfo", "questionnaire"]) - - -class AnswerException(Exception): - """Thrown from an answer processor to generate an error message""" - pass - -def question_proc(*names): - """ - Decorator to create a question processor for one or more - question types. - - Usage: - @question_proc('typename1', 'typename2') - def qproc_blah(request, question): - ... - """ - - def decorator(func): - global QuestionProcessors - for name in names: - QuestionProcessors[name] = func - return func - - return decorator - - -def answer_proc(*names): - """ - Decorator to create an answer processor for one or more - question types. - - Usage: - @question_proc('typename1', 'typename2') - def qproc_blah(request, question): - ... - """ - - def decorator(func): - global Processors - for name in names: - Processors[name] = func - return func - - return decorator - - -def add_type(id, name): - """ - Register a new question type in the admin interface. - At least an answer processor must also be defined for this - type. - - Usage: - add_type('mysupertype', 'My Super Type [radio]') - """ - global QuestionChoices - QuestionChoices.append((id, name)) - - diff --git a/questionnaire/admin.py b/questionnaire/admin.py deleted file mode 100644 index c82ec5cc..00000000 --- a/questionnaire/admin.py +++ /dev/null @@ -1,97 +0,0 @@ -from django.utils.translation import ugettext as _ -from django.contrib import admin -from django.core.urlresolvers import reverse -from .models import (Choice, Questionnaire, Question, QuestionSet, Subject, - RunInfo, RunInfoHistory, Answer, DBStylesheet, Landing) - -adminsite = admin.site - - -class SubjectAdmin(admin.ModelAdmin): - search_fields = ['surname', 'givenname', 'email'] - list_display = ['surname', 'givenname', 'email'] - - -class ChoiceAdmin(admin.ModelAdmin): - list_display = ['sortid', 'text', 'value', 'question'] - - -class ChoiceInline(admin.TabularInline): - ordering = ['sortid'] - model = Choice - extra = 5 - - -class QuestionSetAdmin(admin.ModelAdmin): - ordering = ['questionnaire', 'sortid', ] - list_filter = ['questionnaire', ] - list_display = ['questionnaire', 'heading', 'sortid', ] - list_editable = ['sortid', ] - - -class QuestionAdmin(admin.ModelAdmin): - ordering = ['questionset__questionnaire', 'questionset', 'sort_id', 'number'] - inlines = [ChoiceInline] - list_filter = ['questionset__questionnaire'] - - def changelist_view(self, request, extra_context=None): - "Hack to have Questionnaire list accessible for custom changelist template" - if not extra_context: - extra_context = {} - - questionnaire_id = request.GET.get('questionset__questionnaire__id__exact', None) - if questionnaire_id: - args = {"id": questionnaire_id} - else: - args = {} - extra_context['questionnaires'] = Questionnaire.objects.filter(**args).order_by('name') - return super(QuestionAdmin, self).changelist_view(request, extra_context) - - -class QuestionnaireAdmin(admin.ModelAdmin): - list_display = ('name', 'redirect_url', 'export') - readonly_fields = ('export',) - - def export(self, obj): - csv_url = reverse("export_csv", args=[obj.id,]) - summary_url = reverse("export_summary", args=[obj.id,]) - return '{} {}'.format( - csv_url, _("Download data"), summary_url, _("Show summary") - ) - - export.allow_tags = True - export.short_description = _('Export to CSV') - - -class RunInfoAdmin(admin.ModelAdmin): - list_display = ['random', 'run', 'subject', 'created', 'emailsent', 'lastemailerror'] - pass - - -class RunInfoHistoryAdmin(admin.ModelAdmin): - pass - - -class AnswerAdmin(admin.ModelAdmin): - search_fields = ['subject__email', 'run__id', 'question__number', 'answer'] - list_display = ['id', 'run', 'subject', 'question'] - list_filter = ['subject', 'run__id'] - ordering = [ 'id', 'subject', 'run__id', 'question', ] - -from django.contrib import admin - -# new in dj1.7 -# @admin.register(Landing) -class LandingAdmin(admin.ModelAdmin): - list_display = ('label', 'content_type', 'object_id', ) - ordering = [ 'object_id', ] - -adminsite.register(Questionnaire, QuestionnaireAdmin) -adminsite.register(Question, QuestionAdmin) -adminsite.register(QuestionSet, QuestionSetAdmin) -adminsite.register(Subject, SubjectAdmin) -adminsite.register(RunInfo, RunInfoAdmin) -adminsite.register(RunInfoHistory, RunInfoHistoryAdmin) -adminsite.register(Answer, AnswerAdmin) -adminsite.register(Landing, LandingAdmin) -adminsite.register(DBStylesheet) diff --git a/questionnaire/apps.py b/questionnaire/apps.py deleted file mode 100644 index d4c12d9e..00000000 --- a/questionnaire/apps.py +++ /dev/null @@ -1,29 +0,0 @@ -# questionnaire/apps.py -import imp -from django.conf import settings - -from . import qprocessors, add_type # make sure ours are imported first # noqa -from . import __name__ as app_name -from django.apps import AppConfig - -class QuestionnaireConfig(AppConfig): - name = app_name - verbose_name = "FEF Questionnaire" - label = 'questionnaire' - - def ready(self): - - add_type('sameas', 'Same as Another Question (put sameas=question.number in checks or sameasid=question.id)') - - for app in settings.INSTALLED_APPS: - try: - app_path = __import__(app, {}, {}, [app.split('.')[-1]]).__path__ - except AttributeError: - continue - - try: - imp.find_module('qprocessors', app_path) - except ImportError: - continue - - __import__("%s.qprocessors" % app) diff --git a/questionnaire/context_processors/__init__.py b/questionnaire/context_processors/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/questionnaire/context_processors/settings.py b/questionnaire/context_processors/settings.py deleted file mode 100644 index a159ce1d..00000000 --- a/questionnaire/context_processors/settings.py +++ /dev/null @@ -1,23 +0,0 @@ -from django.conf import settings - - -def load_settings(request): - """ - A template context processor that adds the Questionnaire - Settings to the template context. - """ - try: - use_session = settings.QUESTIONNAIRE_USE_SESSION - except AttributeError: - use_session = False - - try: - debug_questionnaire = settings.QUESTIONNAIRE_DEBUG - except AttributeError: - debug_questionnaire = False - - context = { - 'debug_questionnaire': debug_questionnaire, - 'use_session': use_session - } - return context diff --git a/questionnaire/dependency_checker.py b/questionnaire/dependency_checker.py deleted file mode 100644 index 4f3cd3d3..00000000 --- a/questionnaire/dependency_checker.py +++ /dev/null @@ -1,147 +0,0 @@ -from .models import Question, Answer -import logging - - -def explode_answer_into_list(answers): - answer_list = [] - - for answer in answers: - if type(answer) == type(list()): - string_list = filter(lambda v: not isinstance(v, int), answer) - # remove all number values from list - this means choice-multiple-values's values - answer_list.extend(string_list) - else: - answer_list.append(answer) - - return answer_list - - -def check_actual_answers_against_expression(check_answer, actual_answer, check_question): - # Numeric Value Expressions - if check_answer[0:1] in "<>": - try: - actual_answer = float(actual_answer) - if check_answer[1:2] == "=": - check_value = float(check_answer[2:]) - else: - check_value = float(check_answer[1:]) - except: - logging.error("ERROR: must use numeric values with < <= => > checks (%r)" % check_question) - return False - if check_answer.startswith("<="): - return actual_answer <= check_value - if check_answer.startswith(">="): - return actual_answer >= check_value - if check_answer.startswith("<"): - return actual_answer < check_value - if check_answer.startswith(">"): - return actual_answer > check_value - - # Convert answer to list if not already one - if type(actual_answer) != type(list()): - actual_answer = [actual_answer] - - # Negative Value Expressions - if check_answer.startswith("!"): - if len(actual_answer) == 0: - return False - for actual_answer in actual_answer: - if actual_answer == '': - return False - if check_answer[1:].strip() == actual_answer.strip(): - return False - return True - - # Positive Value Expressions - for actual_answer in actual_answer: - if check_answer.strip() == actual_answer.strip(): - return True - return False - - -def dep_check(expr, runinfo, answerdict): - """ - Given a comma separated question number and expression, determine if the - provided answer to the question number satisfies the expression. - - If the expression starts with >, >=, <, or <=, compare the rest of - the expression numerically and return False if it's not able to be - converted to an integer. - - If the expression starts with !, return true if the rest of the expression - does not match the answer. - - Otherwise return true if the expression matches the answer. - - If there is no comma and only a question number, it checks if the answer - is "yes" - - When looking up the answer, it first checks if it's in the answerdict, - then it checks runinfo's cookies, then it does a database lookup to find - the answer. - - The use of the comma separator is purely historical. - """ - - if hasattr(runinfo, 'questionset'): - questionnaire = runinfo.questionset.questionnaire - elif hasattr(runinfo, 'questionnaire'): - questionnaire = runinfo.questionnaire - else: - assert False - - # Parse expression - if "," not in expr: - expr += ",yes" - - check_question_number, check_answer = expr.split(",", 1) - - # Get question to check - try: - check_question = Question.objects.get(number=check_question_number, - questionset__questionnaire=questionnaire) - except Question.DoesNotExist: - return False - - # Parse & load actual answer(s) from user - if check_question in answerdict: - # test for membership in multiple choice questions - # FIXME: only checking answerdict - for k, v in answerdict[check_question].items(): - if not k.startswith('multiple_'): - continue - if check_answer.startswith("!"): - if check_answer[1:].strip() == v.strip(): - return False - elif check_answer.strip() == v.strip(): - return True - actual_answer = answerdict[check_question].get('ANSWER', '') - elif hasattr(runinfo, 'get_cookie') and runinfo.get_cookie(check_question_number, False): - actual_answer = runinfo.get_cookie(check_question_number) - else: - # retrieve from database - answer_object = Answer.objects.filter(question=check_question, - run=runinfo.run, - subject=runinfo.subject) - if answer_object: - actual_answer = answer_object[0].split_answer() - logging.warn("Put `store` in checks field for question %s" % check_question_number) - else: - actual_answer = None - - if not actual_answer: - if check_question.getcheckdict(): - actual_answer = check_question.getcheckdict().get('default') - - if actual_answer is None: - actual_answer = u'' - - # Convert freeform question type answers from a list of lists to just a single list. - # FIXME: Figure out why the hell freeform questions store their values as lists within lists. - #Don't shrink to one list if it isn't even a list though, otherwise we could get a string - #becoming a character array and falsely failing the comparison. - answer_list = actual_answer #might not actually be a list but meh - if type(actual_answer) == type(list()): - answer_list = explode_answer_into_list(actual_answer) - - return check_actual_answers_against_expression(check_answer, answer_list, check_question) diff --git a/questionnaire/emails.py b/questionnaire/emails.py deleted file mode 100644 index c4173cc5..00000000 --- a/questionnaire/emails.py +++ /dev/null @@ -1,156 +0,0 @@ -# -*- coding: utf-8 -""" -Functions to send email reminders to users. -""" - -import random, time, smtplib, rfc822 -from datetime import datetime -from email.Header import Header -from email.Utils import formataddr, parseaddr -from django.core.mail import get_connection, EmailMessage -from django.contrib.auth.decorators import login_required -from django.template import loader -from django.utils import translation -from django.conf import settings -from django.http import Http404, HttpResponse -from django.shortcuts import render_to_response, get_object_or_404 -from .models import Subject, QuestionSet, RunInfo, Questionnaire - -try: from hashlib import md5 -except: from md5 import md5 - - -def encode_emailaddress(address): - """ - Encode an email address as ASCII using the Encoded-Word standard. - Needed to work around http://code.djangoproject.com/ticket/11144 - """ - try: return address.encode('ascii') - except UnicodeEncodeError: pass - nm, addr = parseaddr(address) - return formataddr( (str(Header(nm, settings.DEFAULT_CHARSET)), addr) ) - - -def _new_random(subject): - """ - Create a short unique randomized string. - Returns: subject_id + 'z' + - md5 hexdigest of subject's surname, nextrun date, and a random number - """ - return "%dz%s" % (subject.id, md5(subject.surname + str(subject.nextrun) + hex(random.randint(1,999999))).hexdigest()[:6]) - - -def _new_runinfo(subject, questionset): - """ - Create a new RunInfo entry with a random code - - If a unique subject+runid entry already exists, return that instead.. - That should only occurs with manual database changes - """ - nextrun = subject.nextrun - runid = str(nextrun.year) - (run, created) = Run.objects.get_or_create(runid=runid) - (r, created) = RunInfo.objects.get_or_create(run=run, subject=subject) - if created: - r.random = _new_random(subject) - r.emailcount = 0 - r.questionset = questionset - r.save() - if nextrun.month == 2 and nextrun.day == 29: # the only exception? - subject.nextrun = datetime(nextrun.year + 1, 2, 28) - else: - subject.nextrun = datetime(nextrun.year + 1, nextrun.month, nextrun.day) - subject.save() - return r - -def _send_email(runinfo): - "Send the email for a specific runinfo entry" - subject = runinfo.subject - translation.activate(subject.language) - tmpl = loader.get_template(settings.QUESTIONNAIRE_EMAIL_TEMPLATE) - c = {} - c['surname'] = subject.surname - c['givenname'] = subject.givenname - c['gender'] = subject.gender - c['email'] = subject.email - c['random'] = runinfo.random - c['runid'] = runinfo.run.runid - c['created'] = runinfo.created - c['site'] = getattr(settings, 'QUESTIONNAIRE_URL', '(settings.QUESTIONNAIRE_URL not set)') - email = tmpl.render(c) - emailFrom = settings.QUESTIONNAIRE_EMAIL_FROM - emailSubject, email = email.split("\n",1) # subject must be on first line - emailSubject = emailSubject.strip() - emailFrom = emailFrom.replace("$RUNINFO", runinfo.random) - emailTo = '"%s, %s" <%s>' % (subject.surname, subject.givenname, subject.email) - - emailTo = encode_emailaddress(emailTo) - emailFrom = encode_emailaddress(emailFrom) - - try: - conn = get_connection() - msg = EmailMessage(emailSubject, email, emailFrom, [ emailTo ], - connection=conn) - msg.send() - runinfo.emailcount = 1 + runinfo.emailcount - runinfo.emailsent = datetime.now() - runinfo.lastemailerror = "OK, accepted by server" - runinfo.save() - return True - except smtplib.SMTPRecipientsRefused: - runinfo.lastemailerror = "SMTP Recipient Refused" - except smtplib.SMTPHeloError: - runinfo.lastemailerror = "SMTP Helo Error" - except smtplib.SMTPSenderRefused: - runinfo.lastemailerror = "SMTP Sender Refused" - except smtplib.SMTPDataError: - runinfo.lastemailerror = "SMTP Data Error" - runinfo.save() - return False - - -def send_emails(request=None, qname=None): - """ - 1. Create a runinfo entry for each subject who is due and has state 'active' - 2. Send an email for each runinfo entry whose subject receives email, - providing that the last sent email was sent more than a week ago. - - This can be called either by "./manage.py questionnaire_emails" (without - request) or through the web, if settings.EMAILCODE is set and matches. - """ - if request and request.GET.get('code') != getattr(settings,'EMAILCODE', False): - raise Http404 - if not qname: - qname = getattr(settings, 'QUESTIONNAIRE_DEFAULT', None) - if not qname: - raise Exception("QUESTIONNAIRE_DEFAULT not in settings") - questionnaire = Questionnaire.objects.get(name=qname) - questionset = QuestionSet.objects.filter(questionnaire__name=qname).order_by('sortid') - if not questionset: - raise Exception("No questionsets for questionnaire '%s' (in settings.py)" % qname) - return - questionset = questionset[0] - - viablesubjects = Subject.objects.filter(nextrun__lte = datetime.now(), state='active') - for s in viablesubjects: - r = _new_runinfo(s, questionset) - runinfos = RunInfo.objects.filter(subject__formtype='email', questionset__questionnaire=questionnaire) - WEEKAGO = time.time() - (60 * 60 * 24 * 7) # one week ago - outlog = [] - for r in runinfos: - if r.run.runid.startswith('test:'): - continue - if r.emailcount == -1: - continue - if r.emailcount == 0 or time.mktime(r.emailsent.timetuple()) < WEEKAGO: - try: - if _send_email(r): - outlog.append(u"[%s] %s, %s: OK" % (r.run.runid, r.subject.surname, r.subject.givenname)) - else: - outlog.append(u"[%s] %s, %s: %s" % (r.run.runid, r.subject.surname, r.subject.givenname, r.lastemailerror)) - except Exception, e: - outlog.append("Exception: [%s] %s: %s" % (r.run.runid, r.subject.surname, str(e))) - if request: - return HttpResponse("Sent Questionnaire Emails:\n " - +"\n ".join(outlog), content_type="text/plain") - return "\n".join(outlog) diff --git a/questionnaire/fixtures/sampleSurvey.json b/questionnaire/fixtures/sampleSurvey.json deleted file mode 100644 index b45f2d9b..00000000 --- a/questionnaire/fixtures/sampleSurvey.json +++ /dev/null @@ -1,512 +0,0 @@ -[ - { - "fields": { - "anonymous": false, - "email": "test@example.com", - "formtype": "email", - "gender": "male", - "givenname": "TestGivenname", - "ip_address": null, - "language": "de", - "nextrun": "2009-05-15", - "state": "active", - "surname": "TestSurname" - }, - "model": "questionnaire.subject", - "pk": 1 - }, - { - "fields": { - "admin_access_only": false, - "html": "survey html here", - "name": "MappingSurvey", - "parse_html": false, - "redirect_url": "" - }, - "model": "questionnaire.questionnaire", - "pk": 3 - }, - { - "fields": { - "content_type": 22, - "label": "Open Book Publishers", - "nonce": "xxxxxx", - "object_id": 81834, - "questionnaire": 3 - }, - "model": "questionnaire.landing", - "pk": 1234 - }, - { - "fields": { - "checks": "", - "heading": "Open Access Ebooks (Part 1)", - "parse_html": true, - "questionnaire": 3, - "sortid": 1, - "text_en": "

Introduction

\r\n

\r\nWelcome, reader of {{ landing_object.title }}! And thanks for visiting Unglue.it to help us out with this \u2026\r\n

\r\n

\r\nAs Open Access publishers, {{ landing_object.claim.all.0.rights_holder }} are truly committed to making academic research broadly accessible - so we want to understand how people like you are actually accessing and using our Open Access titles. \r\n

\r\n

\r\nWe have a bunch of questions for you (well - only 9 actually) about how you found this book and what you\u2019re going to do with it. Please tell us the things you think are interesting or relevant. We really want to know!\r\n

\r\n

\r\n[Privacy policy: There are no marketing traps, we\u2019re not going to surreptitiously drop cookies on you to carry around for us, or swamp you with emails afterwards, or tell our \u201cfriends\u201d about you - we\u2019re just going to store your answers to create a database of usage examples that can be used to understand what Open Access publishing enables." - }, - "model": "questionnaire.questionset", - "pk": 5 - }, - { - "fields": { - "checks": "", - "heading": "Now About You...", - "parse_html": true, - "questionnaire": 3, - "sortid": 2, - "text_en": "

And now, three questions about you as well ...

" - }, - "model": "questionnaire.questionset", - "pk": 6 - }, - { - "fields": { - "checks": "", - "heading": "Follow-up", - "parse_html": true, - "questionnaire": 3, - "sortid": 3, - "text_en": "

We would really like to be able to follow up with some of the respondents to this questionnaire to ask them a few more questions - particularly if you\u2019ve told us something really interesting in a comment (for example). [There will also be a little reward (a free book no less!) for those of you we do contact in this way.]

\r\n\r\n

Thanks so much for your time and efforts answering these questions for us - we love you for it!

\r\n\r\n

We hope you enjoy {{ landing_object.title }}.

\r\n\r\n

{{ landing_object.claim.all.0.rights_holder }} and Unglue.it

\r\n" - }, - "model": "questionnaire.questionset", - "pk": 7 - }, - { - "fields": { - "checks": "", - "extra_en": "", - "footer_en": "", - "number": "1", - "parse_html": true, - "questionset": 5, - "sort_id": 1, - "text_en": "How did you find out about this book in the first place?

\r\n\r\nFor example: Was it from a Google search? Following a wikipedia link? A tweet? Referenced in another book? A late night session with a friend (we don\u2019t need to know much more about that!)? - or in some other way?\r\n", - "type": "open" - }, - "model": "questionnaire.question", - "pk": 16 - }, - { - "fields": { - "checks": "", - "extra_en": "", - "footer_en": "", - "number": "2", - "parse_html": false, - "questionset": 5, - "sort_id": 2, - "text_en": "How did you get hold of this particular copy? \r\n\r\nFor example: Did you download it from the publisher's website? Amazon or another retailer? Find it on academia.edu? Or somewhere like aaaaarg? Get it from a friend? ", - "type": "open" - }, - "model": "questionnaire.question", - "pk": 17 - }, - { - "fields": { - "checks": "", - "extra_en": "", - "footer_en": "", - "number": "3", - "parse_html": true, - "questionset": 5, - "sort_id": 3, - "text_en": "Why are you interested in this book?", - "type": "choice-multiple-freeform" - }, - "model": "questionnaire.question", - "pk": 18 - }, - { - "fields": { - "checks": "", - "extra_en": "If Yes - why are you using this edition and not one of the other ones?", - "footer_en": "", - "number": "4", - "parse_html": false, - "questionset": 5, - "sort_id": 4, - "text_en": "Are you aware that this title is available in multiple different digital and printed formats?", - "type": "choice-yesnocomment" - }, - "model": "questionnaire.question", - "pk": 19 - }, - { - "fields": { - "checks": "", - "extra_en": "Please tell us in more detail:", - "footer_en": "\r\n\r\n\r\n\r\n\r\n\r\n\r\n", - "number": "5", - "parse_html": false, - "questionset": 5, - "sort_id": 5, - "text_en": "What are you going to do with it now you have it?", - "type": "choice-multiple-freeform" - }, - "model": "questionnaire.question", - "pk": 20 - }, - { - "fields": { - "checks": "", - "extra_en": "", - "footer_en": "", - "number": "1", - "parse_html": false, - "questionset": 6, - "sort_id": null, - "text_en": "Where do you live?", - "type": "choice-freeform" - }, - "model": "questionnaire.question", - "pk": 21 - }, - { - "fields": { - "checks": "", - "extra_en": "", - "footer_en": "", - "number": "2", - "parse_html": false, - "questionset": 6, - "sort_id": null, - "text_en": "What do you do for a living?", - "type": "open" - }, - "model": "questionnaire.question", - "pk": 22 - }, - { - "fields": { - "checks": "", - "extra_en": "", - "footer_en": "\r\n\r\n \r\n\r\n", - "number": "3", - "parse_html": false, - "questionset": 6, - "sort_id": null, - "text_en": "When did you finish your formal education?", - "type": "choice-freeform" - }, - "model": "questionnaire.question", - "pk": 23 - }, - { - "fields": { - "checks": "required-no", - "extra_en": "", - "footer_en": "", - "number": "4", - "parse_html": false, - "questionset": 6, - "sort_id": null, - "text_en": "Is there anything else you would like to tell us, or think we should know?", - "type": "open-textfield" - }, - "model": "questionnaire.question", - "pk": 24 - }, - { - "fields": { - "checks": "", - "extra_en": "", - "footer_en": "", - "number": "1", - "parse_html": false, - "questionset": 7, - "sort_id": null, - "text_en": "If you\u2019re willing, then please leave us an email address where we could make contact with you (information which we won\u2019t share or make public).\r\n", - "type": "open" - }, - "model": "questionnaire.question", - "pk": 25 - }, - { - "fields": { - "question": 18, - "sortid": 1, - "tags": "", - "text_en": "For personal use - I\u2019m interested in the topic ", - "value": "personal" - }, - "model": "questionnaire.choice", - "pk": 17 - }, - { - "fields": { - "question": 18, - "sortid": 2, - "tags": "", - "text_en": "For my job - it relates to what I do ", - "value": "job" - }, - "model": "questionnaire.choice", - "pk": 18 - }, - { - "fields": { - "question": 18, - "sortid": 3, - "tags": "", - "text_en": "I need to read it for a course", - "value": "course" - }, - "model": "questionnaire.choice", - "pk": 19 - }, - { - "fields": { - "question": 20, - "sortid": 1, - "tags": "", - "text_en": "Save it, in case I need to use it in the future", - "value": "save" - }, - "model": "questionnaire.choice", - "pk": 20 - }, - { - "fields": { - "question": 20, - "sortid": 2, - "tags": "", - "text_en": "Skim through it and see if it\u2019s at all interesting", - "value": "skim" - }, - "model": "questionnaire.choice", - "pk": 21 - }, - { - "fields": { - "question": 20, - "sortid": 3, - "tags": "", - "text_en": "There\u2019s only really a section/chapter I\u2019m interested in - I\u2019ll probably just read that", - "value": "section" - }, - "model": "questionnaire.choice", - "pk": 22 - }, - { - "fields": { - "question": 20, - "sortid": 4, - "tags": "", - "text_en": "The whole book looks fascinating - I\u2019m going to read it all!", - "value": "whole" - }, - "model": "questionnaire.choice", - "pk": 23 - }, - { - "fields": { - "question": 20, - "sortid": 5, - "tags": "", - "text_en": "I\u2019m going to adapt it and use it (or, at least, parts of it) for another purpose (eg a student coursepack, lecture/briefing notes \u2026)", - "value": "adapt" - }, - "model": "questionnaire.choice", - "pk": 24 - }, - { - "fields": { - "question": 20, - "sortid": 6, - "tags": "", - "text_en": "Share it with my friends ", - "value": "share" - }, - "model": "questionnaire.choice", - "pk": 25 - }, - { - "fields": { - "question": 20, - "sortid": 7, - "tags": "", - "text_en": "Print it out and ceremoniously burn it!", - "value": "print" - }, - "model": "questionnaire.choice", - "pk": 26 - }, - { - "fields": { - "question": 20, - "sortid": 8, - "tags": "", - "text_en": "I\u2019m creating/collating a (online) library", - "value": "catalog" - }, - "model": "questionnaire.choice", - "pk": 27 - }, - { - "fields": { - "question": 20, - "sortid": 9, - "tags": "", - "text_en": "Something else entirely \u2026. ", - "value": "else" - }, - "model": "questionnaire.choice", - "pk": 28 - }, - { - "fields": { - "question": 21, - "sortid": 1, - "tags": "", - "text_en": "USA/Canada", - "value": "us" - }, - "model": "questionnaire.choice", - "pk": 29 - }, - { - "fields": { - "question": 21, - "sortid": 2, - "tags": "", - "text_en": "Europe", - "value": "eu" - }, - "model": "questionnaire.choice", - "pk": 30 - }, - { - "fields": { - "question": 21, - "sortid": 3, - "tags": "", - "text_en": "South America", - "value": "sa" - }, - "model": "questionnaire.choice", - "pk": 31 - }, - { - "fields": { - "question": 21, - "sortid": 4, - "tags": "", - "text_en": "Central America/ Caribbean", - "value": "ca" - }, - "model": "questionnaire.choice", - "pk": 32 - }, - { - "fields": { - "question": 21, - "sortid": 5, - "tags": "", - "text_en": "Asia", - "value": "as" - }, - "model": "questionnaire.choice", - "pk": 33 - }, - { - "fields": { - "question": 21, - "sortid": 6, - "tags": "", - "text_en": "Africa", - "value": "af" - }, - "model": "questionnaire.choice", - "pk": 34 - }, - { - "fields": { - "question": 21, - "sortid": 7, - "tags": "", - "text_en": "Middle East", - "value": "me" - }, - "model": "questionnaire.choice", - "pk": 35 - }, - { - "fields": { - "question": 21, - "sortid": 8, - "tags": "", - "text_en": "Another Planet", - "value": "ap" - }, - "model": "questionnaire.choice", - "pk": 36 - }, - { - "fields": { - "question": 23, - "sortid": 1, - "tags": "", - "text_en": "I haven\u2019t - I\u2019m still a student", - "value": "x" - }, - "model": "questionnaire.choice", - "pk": 37 - }, - { - "fields": { - "question": 23, - "sortid": 2, - "tags": "", - "text_en": "At primary school", - "value": "8" - }, - "model": "questionnaire.choice", - "pk": 38 - }, - { - "fields": { - "question": 23, - "sortid": 3, - "tags": "", - "text_en": "At high school", - "value": "h" - }, - "model": "questionnaire.choice", - "pk": 39 - }, - { - "fields": { - "question": 23, - "sortid": 4, - "tags": "", - "text_en": "After trade qualifications", - "value": "t" - }, - "model": "questionnaire.choice", - "pk": 40 - }, - { - "fields": { - "question": 23, - "sortid": 5, - "tags": "", - "text_en": "At College/Undergraduate Degree ", - "value": "c" - }, - "model": "questionnaire.choice", - "pk": 41 - }, - { - "fields": { - "question": 23, - "sortid": 6, - "tags": "", - "text_en": "At Grad School/post-graduate university", - "value": "g" - }, - "model": "questionnaire.choice", - "pk": 42 - } -] diff --git a/questionnaire/fixtures/testQuestions.yaml b/questionnaire/fixtures/testQuestions.yaml deleted file mode 100644 index 16488795..00000000 --- a/questionnaire/fixtures/testQuestions.yaml +++ /dev/null @@ -1,455 +0,0 @@ -- fields: { - state: active, - surname: TestSurname, - givenname: TestGivenname, - email: test@example.com, - gender: male, - formtype: email, - language: de, - nextrun: 2009-05-15 - } - model: questionnaire.subject - pk: 1 -- fields: { - name: Test, - redirect_url: / - } - model: questionnaire.questionnaire - pk: 1 -- fields: { - name: TagTest, - redirect_url: / - } - model: questionnaire.questionnaire - pk: 2 -- fields: { - checks: '', - heading: 001_TestQS, - questionnaire: 1, - sortid: 1, - text_de: Test Fragebogenseite 1, - text_en: Test QuestionSet 1, - } - model: questionnaire.questionset - pk: 1 -- fields: { - checks: '', - heading: 002_TestQS, - questionnaire: 1, - sortid: 2, - text_de: Test Fragebogenseite 1, - text_en: Test QuestionSet 1, - } - model: questionnaire.questionset - pk: 2 -- fields: { - checks: '', - heading: always, - questionnaire: 2, - sortid: 1, - text_de: always shown, - text_en: always shown, - } - model: questionnaire.questionset - pk: 3 -- fields: { - checks: 'iftag=testtag', - heading: shown with testtag, - questionnaire: 2, - sortid: 2, - text_de: shown with testtag, - text_en: shown with testtag, - } - model: questionnaire.run - pk: 1 -- fields: { - runid: 'test:test', - } - model: questionnaire.run - pk: 2 -- fields: { - runid: 'test:withtags', - } - model: questionnaire.run - pk: 3 -- fields: { - runid: 'test:withouttags', - } - model: questionnaire.questionset - pk: 4 -- fields: { - cookies: null, - created: !!timestamp '2009-05-15 10:19:03.905232', - emailcount: 0, - emailsent: !!timestamp '2009-05-16 15:05:11.775082', - lastemailerror: null, - questionset: 1, - random: 'test:test', - run: 1, - state: '', - subject: 1 - } - model: questionnaire.runinfo - pk: 1 -- fields: { - cookies: null, - created: !!timestamp '2009-05-15 10:19:03.905232', - emailcount: 0, - emailsent: !!timestamp '2009-05-16 15:05:11.775082', - lastemailerror: null, - questionset: 3, - random: 'test:withtags', - run: 2, - state: '', - tags: 'testtag', - subject: 1 - } - model: questionnaire.runinfo - pk: 2 -- fields: { - cookies: null, - created: !!timestamp '2009-05-15 10:19:03.905232', - emailcount: 0, - emailsent: !!timestamp '2009-05-16 15:05:11.775082', - lastemailerror: null, - questionset: 3, - random: 'test:withouttags', - run: 3, - state: '', - tags: '', - subject: 1 - } - model: questionnaire.runinfo - pk: 3 -- fields: { - completed: 2009-05-16, - run: 1, - subject: 1, - questionnaire: 1, - } - model: questionnaire.runinfohistory - pk: 1 -- fields: { - checks: '', - extra_de: '', - extra_en: '', - number: '1', - questionset: 1, - text_de: '[de] Question 1', - text_en: '[en] Question 1', - type: open - } - model: questionnaire.question - pk: 1 -- fields: { - checks: '', - extra_de: '', - extra_en: '', - number: '2', - questionset: 1, - text_de: '[de] Question 2', - text_en: '[en] Question 2', - type: open-textfield - } - model: questionnaire.question - pk: 2 -- fields: { - checks: '', - extra_de: '', - extra_en: '', - number: '3', - questionset: 1, - text_de: '[de] Question 3', - text_en: '[en] Question 3', - type: choice-yesno - } - model: questionnaire.question - pk: 3 -- fields: { - checks: '', - extra_de: '', - extra_en: '', - number: '4', - questionset: 1, - text_de: '[de] Question 4', - text_en: '[en] Question 4', - type: choice-yesnodontknow - } - model: questionnaire.question - pk: 4 -- fields: { - checks: required-yes, - extra_de: '', - extra_en: '', - number: '5', - questionset: 1, - text_de: '[de] Question 5', - text_en: '[en] Question 5', - type: choice-yesnocomment - } - model: questionnaire.question - pk: 5 -- fields: { - checks: required-no, - extra_de: '', - extra_en: '', - number: '6', - questionset: 1, - text_de: '[de] Question 6', - text_en: '[en] Question 6', - type: choice-yesnocomment - } - model: questionnaire.question - pk: 6 -- fields: { - checks: 'range=5-10 requiredif=3,yes', - extra_de: '', - extra_en: '', - number: '7', - questionset: 1, - text_de: '[de] Question 7, requiredif 3,yes', - text_en: '[en] Question 7, requiredif 3,yes', - type: range - } - model: questionnaire.question - pk: 7 -- fields: { - checks: 'units=day,week,month,year', - extra_de: '', - extra_en: '', - number: '8', - questionset: 1, - text_de: '[de] Question 8', - text_en: '[en] Question 8', - type: timeperiod - } - model: questionnaire.question - pk: 8 -- fields: { - checks: '', - extra_de: '', - extra_en: '', - number: '9', - questionset: 2, - text_de: '[de] Question 9', - text_en: '[en] Question 9', - type: choice - } - model: questionnaire.question - pk: 9 -- fields: { - checks: '', - extra_de: '', - extra_en: '', - number: '10', - questionset: 2, - text_de: '[de] Question 10', - text_en: '[en] Question 10', - type: choice-freeform - } - model: questionnaire.question - pk: 10 -- fields: { - checks: '', - extra_de: '', - extra_en: '', - number: '11', - questionset: 2, - text_de: '[de] Question 11', - text_en: '[en] Question 11', - type: choice-multiple - } - model: questionnaire.question - pk: 11 -- fields: { - checks: '', - extra_de: '', - extra_en: '', - number: '12', - questionset: 2, - text_de: '[de] Question 12', - text_en: '[en] Question 12', - type: choice-multiple-freeform - } - model: questionnaire.question - pk: 12 -- fields: { - checks: '', - extra_de: '', - extra_en: '', - number: '12', - questionset: 3, - text_de: '[de] tag test always', - text_en: '[en] tag test always', - type: choice-multiple-freeform - } - model: questionnaire.question - pk: 13 -- fields: { - checks: 'iftag=testtag', - extra_de: '', - extra_en: '', - number: '12', - questionset: 3, - text_de: '[de] tag test checked', - text_en: '[en] tag test checked', - type: choice-multiple-freeform - } - model: questionnaire.question - pk: 14 -- fields: { - checks: '', - extra_de: '', - extra_en: '', - number: '12', - questionset: 4, - text_de: '[de] tag test always', - text_en: '[en] tag test always', - type: choice-multiple-freeform - } - model: questionnaire.question - pk: 15 -- fields: { - question: 9, - sortid: 1, - text_de: Option 1, - text_en: Choice 1, - value: q9_choice1 - } - model: questionnaire.choice - pk: 1 -- fields: { - question: 9, - sortid: 2, - text_de: Option 2, - text_en: Choice 2, - value: q9_choice2 - } - model: questionnaire.choice - pk: 2 -- fields: { - question: 9, - sortid: 3, - text_de: Option 3, - text_en: Choice 3, - value: q9_choice3 - } - model: questionnaire.choice - pk: 3 -- fields: { - question: 9, - sortid: 4, - text_de: Option 4, - text_en: Choice 4, - value: q9_choice4 - } - model: questionnaire.choice - pk: 4 -- fields: { - question: 10, - sortid: 1, - text_de: Option 1, - text_en: Choice 1, - value: q10_choice1 - } - model: questionnaire.choice - pk: 5 -- fields: { - question: 10, - sortid: 2, - text_de: Option 2, - text_en: Choice 2, - value: q10_choice2 - } - model: questionnaire.choice - pk: 6 -- fields: { - question: 10, - sortid: 3, - text_de: Option 3, - text_en: Choice 3, - value: q10_choice3 - } - model: questionnaire.choice - pk: 7 -- fields: { - question: 10, - sortid: 4, - text_de: Option 4, - text_en: Choice 4, - value: q10_choice4 - } - model: questionnaire.choice - pk: 8 -- fields: { - question: 11, - sortid: 1, - text_de: Option 1, - text_en: Choice 1, - value: q11_choice1 - } - model: questionnaire.choice - pk: 9 -- fields: { - question: 11, - sortid: 2, - text_de: Option 2, - text_en: Choice 2, - value: q11_choice2 - } - model: questionnaire.choice - pk: 10 -- fields: { - question: 11, - sortid: 3, - text_de: Option 3, - text_en: Choice 3, - value: q11_choice3 - } - model: questionnaire.choice - pk: 11 -- fields: { - question: 11, - sortid: 4, - text_de: Option 4, - text_en: Choice 4, - value: q11_choice4 - } - model: questionnaire.choice - pk: 12 -- fields: { - question: 12, - sortid: 1, - text_de: Option 1, - text_en: Choice 1, - value: q12_choice1 - } - model: questionnaire.choice - pk: 13 -- fields: { - question: 12, - sortid: 2, - text_de: Option 2, - text_en: Choice 2, - value: q12_choice2 - } - model: questionnaire.choice - pk: 14 -- fields: { - question: 12, - sortid: 3, - text_de: Option 3, - text_en: Choice 3, - value: q12_choice3 - } - model: questionnaire.choice - pk: 15 -- fields: { - question: 12, - sortid: 4, - text_de: Option 4, - text_en: Choice 4, - value: q12_choice4 - } - model: questionnaire.choice - pk: 16 diff --git a/questionnaire/langtemplateloader.py b/questionnaire/langtemplateloader.py deleted file mode 100644 index a0e9b749..00000000 --- a/questionnaire/langtemplateloader.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Wrapper for loading templates from the filesystem. -""" - -from django.conf import settings -from django.template import TemplateDoesNotExist -from django.utils._os import safe_join -from django.utils import translation - -def get_template_sources(template_name, template_dirs=None): - """ - Returns the absolute paths to "template_name", when appended to each - directory in "template_dirs". Any paths that don't lie inside one of the - template dirs are excluded from the result set, for security reasons. - """ - if not template_dirs: - template_dirs = settings.TEMPLATE_DIRS - for template_dir in template_dirs: - try: - yield safe_join(template_dir, template_name) - except UnicodeDecodeError: - # The template dir name was a bytestring that wasn't valid UTF-8. - raise - except ValueError: - # The joined path was located outside of this particular - # template_dir (it might be inside another one, so this isn't - # fatal). - pass - -def _load_template_source(template_name, template_dirs=None): - tried = [] - for filepath in get_template_sources(template_name, template_dirs): - try: - return (open(filepath).read().decode(settings.FILE_CHARSET), filepath) - except IOError: - tried.append(filepath) - if tried: - error_msg = "Tried %s" % tried - else: - error_msg = "Your TEMPLATE_DIRS setting is empty. Change it to point to at least one template directory." - raise TemplateDoesNotExist, error_msg - -def load_template_source(template_name, template_dirs=None): - """Assuming the current language is German. - If template_name is index.$LANG.html, try index.de.html then index.html - Also replaces .. with . when attempting fallback. - """ - if "$LANG" in template_name: - lang = translation.get_language() - try: - t = template_name.replace("$LANG", lang) - res = _load_template_source(t, template_dirs) - return res - except TemplateDoesNotExist: - t = template_name.replace("$LANG", "").replace("..",".") - return _load_template_source(t, template_dirs) - return _load_template_source(template_name, template_dirs) -load_template_source.is_usable = True diff --git a/questionnaire/legacy_test_urls.py b/questionnaire/legacy_test_urls.py deleted file mode 100644 index 034e0082..00000000 --- a/questionnaire/legacy_test_urls.py +++ /dev/null @@ -1,17 +0,0 @@ -# vim: set fileencoding=utf-8 - -from django.conf.urls.defaults import * -from . import views - -urlpatterns = [ - url(r'^q/(?P[^/]+)/(?P\d+)/$', - views.questionnaire, name='questionset'), - url(r'^q/([^/]+)/', - views.questionnaire, name='questionset'), - url(r'^q/manage/csv/(\d+)/', - 'views.export_csv), - url(r'^q/manage/sendemail/(\d+)/$', - views.send_email), - url(r'^q/manage/manage/sendemails/$', - views.send_emails), -] diff --git a/questionnaire/legacy_tests.py b/questionnaire/legacy_tests.py deleted file mode 100644 index ac5b5eb9..00000000 --- a/questionnaire/legacy_tests.py +++ /dev/null @@ -1,192 +0,0 @@ -""" -Basic Test Suite for Questionnaire Application - -Unfortunately Django 1.0 only has TestCase and not TransactionTestCase -so we can't test that a submitted page with an error does not have any -answers submitted to the DB. -""" -from django.test import TestCase -from django.test.client import Client -from .models import * -from datetime import datetime -import os - -class TypeTest(TestCase): - fixtures = ( 'testQuestions.yaml', ) - urls = 'questionnaire.test_urls' - - def setUp(self): - self.ansdict1 = { - 'questionset_id' : '1', - 'question_1' : 'Open Answer 1', - 'question_2' : 'Open Answer 2\r\nMultiline', - 'question_3' : 'yes', - 'question_4' : 'dontknow', - 'question_5' : 'yes', - 'question_5_comment' : 'this comment is required because of required-yes check', - 'question_6' : 'no', - 'question_6_comment' : 'this comment is required because of required-no check', - 'question_7' : '5', - 'question_8_unit' : 'week', - 'question_8' : '2', - } - self.ansdict2 = { - 'questionset_id' : '2', - 'question_9' : 'q9_choice1', # choice - 'question_10' : '_entry_', # choice-freeform - 'question_10_comment' : 'my freeform', - 'question_11_multiple_2' : 'q11_choice2', # choice-multiple - 'question_11_multiple_4' : 'q11_choice4', # choice-multiple - 'question_12_multiple_1' : 'q12_choice1',# choice-multiple-freeform - 'question_12_more_1' : 'blah', # choice-multiple-freeform - } - runinfo = self.runinfo = RunInfo.objects.get(run__runid='test:test') - self.runid = runinfo.run.runid - self.subject_id = runinfo.subject_id - - - def test010_redirect(self): - "Check redirection from generic questionnaire to questionset" - response = self.client.get('/q/test:test/') - self.assertEqual(response['Location'], 'http://testserver/q/test:test/1/') - - - def test020_get_questionset_1(self): - "Get first page of Questions" - response = self.client.get('/q/test:test/1/') - self.assertEqual(response.status_code, 200) - self.assertEqual(response.template[0].name, 'questionnaire/questionset.html') - - - def test030_language_setting(self): - "Set the language and confirm it is set in DB" - response = self.client.get('/q/test:test/1/', {"lang" : "en"}) - self.assertEqual(response.status_code, 302) - self.assertEqual(response['Location'], 'http://testserver/q/test:test/1/') - response = self.client.get('/q/test:test/1/') - assert "Don't Know" in response.content - self.assertEqual(response.status_code, 200) - runinfo = RunInfo.objects.get(run__runid='test:test') - self.assertEqual(runinfo.subject.language, 'en') - response = self.client.get('/q/test:test/1/', {"lang" : "de"}) - self.assertEqual(response.status_code, 302) - self.assertEqual(response['Location'], 'http://testserver/q/test:test/1/') - response = self.client.get('/q/test:test/1/') - assert "Weiss nicht" in response.content - self.assertEqual(response.status_code, 200) - runinfo = RunInfo.objects.get(run__runid='test:test') - self.assertEqual(runinfo.subject.language, 'de') - - - def test040_missing_question(self): - "Post questions with a mandatory field missing" - c = self.client - ansdict = self.ansdict1.copy() - del ansdict['question_3'] - response = c.post('/q/test:test/1/', ansdict) - self.assertEqual(response.status_code, 200) - errors = response.context[-1]['errors'] - self.assertEqual(len(errors), 1) and errors.has_key('3') - - - def test050_missing_question(self): - "Post questions with a mandatory field missing" - c = self.client - ansdict = self.ansdict1.copy() - del ansdict['question_5_comment'] - # first set language to english - response = self.client.get('/q/test:test/1/', {"lang" : "en"}) - response = c.post('/q/test:test/1/', ansdict) - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.context[-1]['errors']), 1) - - - def test060_successful_questionnaire(self): - "POST complete answers for QuestionSet 1" - c = self.client - ansdict1 = self.ansdict1 - runinfo = RunInfo.objects.get(run__runid='test:test') - runid = runinfo.random = runinfo.run.runid = '1real' - runinfo.save() - runinfo.run.save() - - response = c.get('/q/1real/1/') - self.assertEqual(response.status_code, 200) - self.assertEqual(response.template[0].name, 'questionnaire/questionset.html') - response = c.post('/q/1real/', ansdict1) - self.assertEqual(response.status_code, 302) - self.assertEqual(response['Location'], 'http://testserver/q/1real/2/') - "POST complete answers for QuestionSet 2" - c = self.client - - ansdict2 = self.ansdict2 - response = c.get('/q/1real/2/') - self.assertEqual(response.status_code, 200) - self.assertEqual(response.template[0].name, 'questionnaire/questionset.html') - response = c.post('/q/1real/', ansdict2) - self.assertEqual(response.status_code, 302) - self.assertEqual(response['Location'], 'http://testserver/') - - self.assertEqual(RunInfo.objects.filter(run__runid='1real').count(), 0) - - # TODO: The format of these answers seems very strange to me. It was - # simpler before I changed it to get the test to work. - # I'll have to revisit this once I figure out how this is meant to work - # for now it is more important to me that all tests pass - - dbvalues = { - '1' : u'["%s"]' % ansdict1['question_1'], - '2' : u'["%s"]' % ansdict1['question_2'], - '3' : u'["%s"]' % ansdict1['question_3'], - '4' : u'["%s"]' % ansdict1['question_4'], - '5' : u'["%s", ["%s"]]' % (ansdict1['question_5'], ansdict1['question_5_comment']), - '6' : u'["%s", ["%s"]]' % (ansdict1['question_6'], ansdict1['question_6_comment']), - '7' : u'[%s]' % ansdict1['question_7'], - '8' : u'%s; %s' % (ansdict1['question_8'], ansdict1['question_8_unit']), - '9' : u'["q9_choice1"]', - '10' : u'[["my freeform"]]', - '11' : u'["q11_choice2", "q11_choice4"]', - '12' : u'["q12_choice1", ["blah"]]', - } - for k, v in dbvalues.items(): - ans = Answer.objects.get(run__runid=runid, subject__id=self.subject_id, - question__number=k) - - v = v.replace('\r', '\\r').replace('\n', '\\n') - self.assertEqual(ans.answer, v) - - def test070_tags(self): - c = self.client - - # the first questionset in questionnaire 2 is always shown, - # but one of its 2 questions is tagged with testtag - with_tags = c.get('/q/test:withtags/1/') - - # so we'll get two questions shown if the run is tagged - self.assertEqual(with_tags.status_code, 200) - self.assertEqual(len(with_tags.context['qlist']), 2) - - # one question, if the run is not tagged - without_tags = c.get('/q/test:withouttags/1/') - - self.assertEqual(without_tags.status_code, 200) - self.assertEqual(len(without_tags.context['qlist']), 1) - - # the second questionset is only shown if the run is tagged - with_tags = c.get('/q/test:withtags/2/') - - self.assertEqual(with_tags.status_code, 200) - self.assertEqual(len(with_tags.context['qlist']), 1) - - # meaning it'll be skipped on the untagged run - without_tags = c.get('/q/test.withouttags/2/') - - self.assertEqual(without_tags.status_code, 302) # redirect - - # the progress values of the first questionset should reflect - # the fact that in one run there's only one questionset - with_tags = c.get('/q/test:withtags/1/') - without_tags = c.get('/q/test:withouttags/1/') - - self.assertEqual(with_tags.context['progress'], 50) - self.assertEqual(without_tags.context['progress'], 100) \ No newline at end of file diff --git a/questionnaire/locale/de/LC_MESSAGES/django.po b/questionnaire/locale/de/LC_MESSAGES/django.po deleted file mode 100644 index b295e99c..00000000 --- a/questionnaire/locale/de/LC_MESSAGES/django.po +++ /dev/null @@ -1,158 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-06-04 10:11+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: models.py:16 -msgid "Active" -msgstr "Aktiv" - -#: models.py:17 -msgid "Inactive" -msgstr "Inaktiv" - -#: models.py:22 -msgid "State" -msgstr "Status" - -#: models.py:24 -msgid "Surname" -msgstr "Nachname" - -#: models.py:26 -msgid "Given name" -msgstr "Vorname" - -#: models.py:27 -msgid "Email" -msgstr "Email" - -#: models.py:29 -msgid "Gender" -msgstr "Geschlecht" - -#: models.py:30 -msgid "Unset" -msgstr "Keine Angabe" - -#: models.py:31 -msgid "Male" -msgstr "Männlich" - -#: models.py:32 -msgid "Female" -msgstr "Weiblich" - -#: models.py:35 -msgid "Next Run" -msgstr "Nächste Ausführung" - -#: models.py:37 -msgid "Form Type" -msgstr "Art des Formulars" - -#: models.py:39 -msgid "Subject receives emails" -msgstr "Person bekommt Emails" - -#: models.py:40 -msgid "Subject is sent paper form" -msgstr "Person bekommt Papierformular" - -#: models.py:43 -msgid "Language" -msgstr "Sprache" - -#: qprocessors/choice.py:38 qprocessors/simple.py:66 -msgid "You must select an option" -msgstr "Sie müssen eine Option auswählen" - -#: qprocessors/choice.py:42 qprocessors/simple.py:70 qprocessors/simple.py:72 -#: qprocessors/simple.py:74 qprocessors/simple.py:77 -#: qprocessors/timeperiod.py:56 -msgid "Field cannot be blank" -msgstr "Dieses Feld muss ausgefüllt werden" - -#: qprocessors/choice.py:46 -msgid "Invalid option!" -msgstr "Ungültige Angabe" - -#: qprocessors/choice.py:107 -#, python-format -msgid "You must select at least %d option" -msgid_plural "You must select at least %d options" -msgstr[0] "Sie müssen mindestens %d Option auswählen" -msgstr[1] "Sie müssen mindestens %d Optionen auswählen" - -#: qprocessors/custom.py:27 -msgid "Processor not defined for this question" -msgstr "" - -#: qprocessors/range.py:35 -msgid "Out of range" -msgstr "" - -#: qprocessors/timeperiod.py:5 -msgid "second(s)" -msgstr "Sekunde(n)" - -#: qprocessors/timeperiod.py:6 -msgid "minute(s)" -msgstr "Minute(n)" - -#: qprocessors/timeperiod.py:7 -msgid "hour(s)" -msgstr "Stunde(n)" - -#: qprocessors/timeperiod.py:8 -msgid "day(s)" -msgstr "Tag(e)" - -#: qprocessors/timeperiod.py:9 -msgid "week(s)" -msgstr "Woche(n)" - -#: qprocessors/timeperiod.py:10 -msgid "month(s)" -msgstr "Monat(e)" - -#: qprocessors/timeperiod.py:11 -msgid "year(s)" -msgstr "Jahr(e)" - -#: qprocessors/timeperiod.py:42 qprocessors/timeperiod.py:58 -msgid "Invalid time period" -msgstr "Ungültiger Zeitraum" - -#: qprocessors/timeperiod.py:48 -msgid "Time period must be a whole number" -msgstr "Angabe muss aus einer ganzen Zahl bestehen" - -#: templates/questionnaire/choice-yesnocomment.html:3 -msgid "Yes" -msgstr "Ja" - -#: templates/questionnaire/choice-yesnocomment.html:5 -msgid "No" -msgstr "Nein" - -#: templates/questionnaire/choice-yesnocomment.html:8 -msgid "Don't Know" -msgstr "Weiss nicht" - -#: templates/questionnaire/questionset.html:72 -msgid "Continue" -msgstr "Weiter" diff --git a/questionnaire/locale/fr/LC_MESSAGES/django.po b/questionnaire/locale/fr/LC_MESSAGES/django.po deleted file mode 100644 index 0a9204f2..00000000 --- a/questionnaire/locale/fr/LC_MESSAGES/django.po +++ /dev/null @@ -1,160 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-06-04 10:11+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: models.py:16 -msgid "Active" -msgstr "" - -#: models.py:17 -msgid "Inactive" -msgstr "" - -#: models.py:22 -msgid "State" -msgstr "" - -#: models.py:24 -msgid "Surname" -msgstr "" - -#: models.py:26 -msgid "Given name" -msgstr "" - -#: models.py:27 -msgid "Email" -msgstr "" - -#: models.py:29 -msgid "Gender" -msgstr "" - -#: models.py:30 -msgid "Unset" -msgstr "" - -#: models.py:31 -msgid "Male" -msgstr "" - -#: models.py:32 -msgid "Female" -msgstr "" - -#: models.py:35 -msgid "Next Run" -msgstr "" - -#: models.py:37 -msgid "Form Type" -msgstr "" - -#: models.py:39 -msgid "Subject receives emails" -msgstr "" - -#: models.py:40 -msgid "Subject is sent paper form" -msgstr "" - -#: models.py:43 -msgid "Language" -msgstr "" - -#: qprocessors/choice.py:38 qprocessors/simple.py:66 -msgid "You must select an option" -msgstr "Veuillez choisir une option!" - -#: qprocessors/choice.py:42 qprocessors/simple.py:70 qprocessors/simple.py:72 -#: qprocessors/simple.py:74 qprocessors/simple.py:77 -#: qprocessors/timeperiod.py:56 -msgid "Field cannot be blank" -msgstr "" -"Merci de donner une réponse à cette question; ce champs ne peut rester vide." - -#: qprocessors/choice.py:46 -#, fuzzy -msgid "Invalid option!" -msgstr "Option non valable" - -#: qprocessors/choice.py:107 -#, python-format -msgid "You must select at least %d option" -msgid_plural "You must select at least %d options" -msgstr[0] "Vous devez cocher au moins %d option" -msgstr[1] "Vous devez cocher au moins %d options" - -#: qprocessors/custom.py:27 -msgid "Processor not defined for this question" -msgstr "" - -#: qprocessors/range.py:35 -msgid "Out of range" -msgstr "" - -#: qprocessors/timeperiod.py:5 -msgid "second(s)" -msgstr "seconde(s)" - -#: qprocessors/timeperiod.py:6 -msgid "minute(s)" -msgstr "minute(s)" - -#: qprocessors/timeperiod.py:7 -msgid "hour(s)" -msgstr "heure(s)" - -#: qprocessors/timeperiod.py:8 -msgid "day(s)" -msgstr "jour(s)" - -#: qprocessors/timeperiod.py:9 -msgid "week(s)" -msgstr "semaine(s)" - -#: qprocessors/timeperiod.py:10 -msgid "month(s)" -msgstr "mois" - -#: qprocessors/timeperiod.py:11 -msgid "year(s)" -msgstr "année(s)" - -#: qprocessors/timeperiod.py:42 qprocessors/timeperiod.py:58 -msgid "Invalid time period" -msgstr "Période non valable" - -#: qprocessors/timeperiod.py:48 -msgid "Time period must be a whole number" -msgstr "La période doit être un chiffre entier" - -#: templates/questionnaire/choice-yesnocomment.html:3 -msgid "Yes" -msgstr "Oui" - -#: templates/questionnaire/choice-yesnocomment.html:5 -msgid "No" -msgstr "Non" - -#: templates/questionnaire/choice-yesnocomment.html:8 -msgid "Don't Know" -msgstr "Ne sais pas" - -#: templates/questionnaire/questionset.html:72 -msgid "Continue" -msgstr "Continuer" diff --git a/questionnaire/locale/it/LC_MESSAGES/django.po b/questionnaire/locale/it/LC_MESSAGES/django.po deleted file mode 100644 index 9e30f644..00000000 --- a/questionnaire/locale/it/LC_MESSAGES/django.po +++ /dev/null @@ -1,174 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-11-29 15:51+0100\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: models.py:16 -msgid "Active" -msgstr "Attivo" - -#: models.py:17 -msgid "Inactive" -msgstr "Inattivo" - -#: models.py:22 -msgid "State" -msgstr "Stato" - -#: models.py:24 -msgid "Surname" -msgstr "Cognome" - -#: models.py:26 -msgid "Given name" -msgstr "Nome" - -#: models.py:27 -msgid "Email" -msgstr "Email" - -#: models.py:29 -msgid "Gender" -msgstr "Sesso" - -#: models.py:30 -msgid "Unset" -msgstr "Nessun parere" - -#: models.py:31 -msgid "Male" -msgstr "Maschio" - -#: models.py:32 -msgid "Female" -msgstr "Femmina" - -#: models.py:35 -msgid "Next Run" -msgstr "Prossimo" - -#: models.py:37 -msgid "Form Type" -msgstr "Tipo di domanda" - -#: models.py:39 -msgid "Subject receives emails" -msgstr "Persona contattata via email" - -#: models.py:40 -msgid "Subject is sent paper form" -msgstr "Persona contattata via questionario cartaceo" - -#: models.py:43 -msgid "Language" -msgstr "Lingua" - -#: views.py:608 templates/questionnaire/choice-yesnocomment.html:2 -msgid "Yes" -msgstr "Si" - -#: views.py:608 templates/questionnaire/choice-yesnocomment.html:3 -msgid "No" -msgstr "No" - -#: views.py:610 templates/questionnaire/choice-yesnocomment.html:5 -msgid "Don't Know" -msgstr "Non so" - -#: qprocessors/choice.py:39 qprocessors/simple.py:67 -msgid "You must select an option" -msgstr "Devi scegliere un'opzione" - -#: qprocessors/choice.py:43 qprocessors/simple.py:71 qprocessors/simple.py:73 -#: qprocessors/simple.py:75 qprocessors/simple.py:78 -#: qprocessors/timeperiod.py:56 -msgid "Field cannot be blank" -msgstr "Domanda richiesta" - -#: qprocessors/choice.py:48 -msgid "Invalid option!" -msgstr "Opzione non valida" - -#: qprocessors/choice.py:110 -#, python-format -msgid "You must select at least %d option" -msgid_plural "You must select at least %d options" -msgstr[0] "Devi sciegliere almeno %d opzione" -msgstr[1] "Devi sciegliere almeno %d opzioni" - -#: qprocessors/custom.py:27 -msgid "Processor not defined for this question" -msgstr "" - -#: qprocessors/range.py:36 -msgid "Out of range" -msgstr "" - -#: qprocessors/timeperiod.py:5 -msgid "second(s)" -msgstr "secondi" - -#: qprocessors/timeperiod.py:6 -msgid "minute(s)" -msgstr "minuti" - -#: qprocessors/timeperiod.py:7 -msgid "hour(s)" -msgstr "ora(e)" - -#: qprocessors/timeperiod.py:8 -msgid "day(s)" -msgstr "giorno(i)" - -#: qprocessors/timeperiod.py:9 -msgid "week(s)" -msgstr "settimana(e)" - -#: qprocessors/timeperiod.py:10 -msgid "month(s)" -msgstr "mese(i)" - -#: qprocessors/timeperiod.py:11 -msgid "year(s)" -msgstr "anno(i)" - -#: qprocessors/timeperiod.py:42 qprocessors/timeperiod.py:58 -msgid "Invalid time period" -msgstr "Intervallo di tempo non valido" - -#: qprocessors/timeperiod.py:48 -msgid "Time period must be a whole number" -msgstr "Angabe muss aus einer ganzen Zahl bestehen" - -#: templates/admin/questionnaire/question/change_form.html:10 -msgid "Choices" -msgstr "" - -#: templates/admin/questionnaire/question/change_form.html:12 -msgid "Sortid determines the choice order." -msgstr "" - -#: templates/admin/questionnaire/question/change_form.html:13 -msgid "" -"Short values will appear in exported data and are \n" -"referenced in 'Additional checks' fields. Numbers, letters \n" -"or single words are valid." -msgstr "" - -#: templates/questionnaire/questionset.html:77 -msgid "Continue" -msgstr "Continua" diff --git a/questionnaire/locale/ru/LC_MESSAGES/django.mo b/questionnaire/locale/ru/LC_MESSAGES/django.mo deleted file mode 100644 index b4442f43a03881e1168e1bcc45c135eb441e6f22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3375 zcmb`IUu+y#6^AcvC}dj-v_PSMZy<>sk}gJSmv{4Bf(H^a;A`Rh>Z--WXNckq+&kMMr@m-f8cq~uR+<{@_XLJ8#ocn^FK zcEAq!3LJ-Dg6~0z+zRFU5D&Ieqwovx88`@!La|?llE)gvmAc-Z ze+NoFzkw3hAE4~>r}q4ZP}bkcV&UEJJ+!l9I2?@>BO!`i=c!V1nU0+F0$<@(Pe#~ z%YJxN4MuTAPaLlrHDtn)iPaEJLmm1RqlQDjwa0Kc>z9L)j;d)8g zsH8^xaJuGC8#OAMjhSPqK3EIYSfs{lsg9;}jDb-H;)rOIDAp22$xH>IDd{Q3=}eI5 z7iuPvJ=CF@C{8uoFrnvya#{P;s_|nTgxVad@{wgFKlQaAmb4!mor}$siA`AK14bSF zrBWcS{IV|2nBvi-Lr;kWNtf1RwaTQ4lU=%O(v%mSBY-3br^`mqMR6%{9$k`M>JXce ze92&0A>4#e4L(J8jj@TbN&VEQL$%50O)=H6DH>!CY4V^~18k^Z5swKKA^-fGN3QJ-!XUtLIaq1+b)*^>D zT=JepWNOi)ySwtagGTD-jV9AU$@_Y3I`Jl=9{p@kOsT>le=3f`U^Xbu=-%1HjUpL6 zJuPB(5%u2Of$<4%Uu=A-ueTrRahxx7d->g7_v1SMWKZFVo%yfj^B8&u30C%Q+Z`F` zKj@8)d;9zKH^zHLhj)H!d~6^$f_&ZtEt-^lqWIsU*=T)l!uXXQJ<>lmbhv+LK=+P} zJY5dDqIi05ZghBb;D!nXRFDIU{GJ@X9-VSvzEUmwLAZz3@?*N7@9@N+xBG^jL`R2v z17R^L(W^ar_hgXf4wP%LU-sl6Cp|i>x?$4y)jhiP+SeIwE9Cq73VQo?EwA}4eT9O4 zO6N7^jQ93+Z+z>0b3owTcV*^H^teNxWWl$C0VyBY7pi; z4#{8HU)aldTvPUZwqP&0>@ZaJq7!F@3|`MpBju8lf_=yh1(1W_vXi2-%YOyeb=0aO zW0R@6<^^P@-1bhfb7Zijv)Ay@w7;}XO%P2NdXtS=;XJiw8WgDEVz^4SXe#-=B}K&J zss#LoOu1lIr2x0=)($sYvdh^LOHRndvUWvB3zB$=I1u}UEATvS>Rmc#&$)P9)!2k8 zY1s{{E4IE%D!V}L%hF9$!>&q+=ZUFRJOsF?M8g{R+C6y%@f}WpVn@w zCqtU^V#_JdB}5@V=^rU2BC!%37uv!~U7eKIBu*Lx8)birSnI7ArMJ!!<$rDjkw)5? z7Pbh!(ZbowQUqz>8$vXtn<>8Qpi6|uVLKWKwrr3*L?dcKQQi?NegmXkXlabX*sbpBFp8(pk4NI YwjdqVVBZBMuv9K0cfiDV;{X5v diff --git a/questionnaire/locale/ru/LC_MESSAGES/django.po b/questionnaire/locale/ru/LC_MESSAGES/django.po deleted file mode 100644 index d767c84f..00000000 --- a/questionnaire/locale/ru/LC_MESSAGES/django.po +++ /dev/null @@ -1,190 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# Victor Safronivich , 2012. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: 2.0\n" -"Report-Msgid-Bugs-To: Victor Safronivich \n" -"POT-Creation-Date: 2012-08-24 09:15+0600\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Victor Safronivich \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" - -#: .\models.py:16 -msgid "Active" -msgstr "Активно" - -#: .\models.py:17 -msgid "Inactive" -msgstr "Не активно" - -#: .\models.py:22 -msgid "State" -msgstr "Состояние" - -#: .\models.py:24 -msgid "Surname" -msgstr "Фамилия" - -#: .\models.py:26 -msgid "Given name" -msgstr "Имя" - -#: .\models.py:27 -msgid "Email" -msgstr "Эл. почта" - -#: .\models.py:29 -msgid "Gender" -msgstr "Пол" - -#: .\models.py:30 -msgid "Unset" -msgstr "Неважно" - -#: .\models.py:31 -msgid "Male" -msgstr "Мужской" - -#: .\models.py:32 -msgid "Female" -msgstr "Женский" - -#: .\models.py:35 -msgid "Next Run" -msgstr "Следующая попытка" - -#: .\models.py:37 -msgid "Form Type" -msgstr "Тип формы" - -#: .\models.py:39 -msgid "Subject receives emails" -msgstr "Тема полученного письма" - -#: .\models.py:40 -msgid "Subject is sent paper form" -msgstr "" - -#: .\models.py:43 -msgid "Language" -msgstr "Язык" - -#: .\views.py:805 .\templates\questionnaire\choice-yesnocomment.html.py:10 -msgid "Yes" -msgstr "Да" - -#: .\views.py:805 .\templates\questionnaire\choice-yesnocomment.html.py:18 -msgid "No" -msgstr "Нет" - -#: .\views.py:807 .\templates\questionnaire\choice-yesnocomment.html.py:27 -msgid "Don't Know" -msgstr "Не известно" - -#: .\qprocessors\choice.py:38 .\qprocessors\simple.py:68 -msgid "You must select an option" -msgstr "Вы должны выбрать ответ" - -#: .\qprocessors\choice.py:42 .\qprocessors\simple.py:72 -#: .\qprocessors\simple.py:74 .\qprocessors\simple.py:76 -#: .\qprocessors\simple.py:79 .\qprocessors\timeperiod.py:56 -msgid "Field cannot be blank" -msgstr "Поле не может быть пустым" - -#: .\qprocessors\choice.py:47 -msgid "Invalid option!" -msgstr "Не правильный ответ!" - -#: .\qprocessors\choice.py:108 -#, python-format -msgid "You must select at least %d option" -msgid_plural "You must select at least %d options" -msgstr[0] "Вы должны выбрать как минимум %d ответ" -msgstr[1] "Вы должны выбрать как минимум %d ответа" -msgstr[2] "Вы должны выбрать как минимум %d ответов" - -#: .\qprocessors\custom.py:27 -msgid "Processor not defined for this question" -msgstr "Для этого вопроса не определен обработчик" - -#: .\qprocessors\range.py:41 -msgid "Out of range" -msgstr "Вне диапазона значений" - -#: .\qprocessors\timeperiod.py:5 -msgid "second(s)" -msgstr "Секунды" - -#: .\qprocessors\timeperiod.py:6 -msgid "minute(s)" -msgstr "Минуты" - -#: .\qprocessors\timeperiod.py:7 -msgid "hour(s)" -msgstr "часов" - -#: .\qprocessors\timeperiod.py:8 -msgid "day(s)" -msgstr "дней" - -#: .\qprocessors\timeperiod.py:9 -msgid "week(s)" -msgstr "недель" - -#: .\qprocessors\timeperiod.py:10 -msgid "month(s)" -msgstr "месяцев" - -#: .\qprocessors\timeperiod.py:11 -msgid "year(s)" -msgstr "лет" - -#: .\qprocessors\timeperiod.py:42 .\qprocessors\timeperiod.py:58 -msgid "Invalid time period" -msgstr "Неправильный временной интервал" - -#: .\qprocessors\timeperiod.py:48 -msgid "Time period must be a whole number" -msgstr "Временной интервал должен быть целым числом" - -#: .\templates\admin\questionnaire\question\change_form.html.py:10 -msgid "Choices" -msgstr "Варианты ответов" - -#: .\templates\admin\questionnaire\question\change_form.html.py:12 -msgid "Sortid determines the choice order." -msgstr "Поле обозначает порядок ответов" - -#: .\templates\admin\questionnaire\question\change_form.html.py:13 -msgid "" -"Short values will appear in exported data and are \n" -"referenced in 'Additional checks' fields. Numbers, letters \n" -"or single words are valid." -msgstr "" -"Краткие значения появятся в данных экспорта. \n" -"Допустимы числа, буквы или простые слова." - -#: .\templates\questionnaire\choice-yesnocomment.html.py:35 -msgid "comment" -msgstr "комментарий" - -#: .\templates\questionnaire\questionset.html.py:58 -msgid "edit" -msgstr "редактировать" - -#: .\templates\questionnaire\questionset.html.py:95 -msgid "Continue" -msgstr "далее" - -#: .\templates\questionnaire\questionset.html.py:100 -msgid "return to previous page" -msgstr "вернуть на предыдущую страницу" diff --git a/questionnaire/management/__init__.py b/questionnaire/management/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/questionnaire/management/commands/__init__.py b/questionnaire/management/commands/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/questionnaire/management/commands/make_survey_nonces.py b/questionnaire/management/commands/make_survey_nonces.py deleted file mode 100644 index 10867392..00000000 --- a/questionnaire/management/commands/make_survey_nonces.py +++ /dev/null @@ -1,14 +0,0 @@ -from django.core.management.base import BaseCommand -from ...models import Landing - - -class Command(BaseCommand): - help = "make survey nonces with the specified label" - args = "