# -*- coding: utf-8 -*- from django import forms from django.db.models import Q from django.http import Http404 from django.utils.translation import ugettext_lazy as _ from django.utils.encoding import force_unicode import settings from models import * from smadrill.game import relax import datetime from random import randint import sys # TODO: These should be accessible in the admin interface, not hardcoded. PRONOUNS_LIST = {'Sg1':'manne', 'Sg2':'datne', 'Sg3':'dïhte', 'Pl1':'mijjieh', 'Pl2':'dijjieh', 'Pl3':'dah', 'Du1':'månnoeh', 'Du2':'dåtnoeh', 'Du3':'dah guaktah'} POS_CHOICES = ( ('N', _('noun')), ('V', _('verb')), ('A', _('adjective')), ('Num', _('numeral')), ) CASE_CHOICES = ( ('NOMPL', _('plural')), ('N-ACC', _('accusative')), ('N-ILL', _('illative')), ('N-INE', _('inessive')), ('N-ELA', _('elative')), ('N-COM', _('comitative')), ('N-GEN', _('genitive')), ('N-ESS', _('essive')), ) CASE_CONTEXT_CHOICES = ( ('N-NOM-PL', _('plural')), ('N-ACC', _('accusative')), ('N-ILL', _('illative')), ('N-INE', _('inessive')), ('N-ELA', _('elative')), ('N-COM', _('comitative')), ('N-ESS', _('essive')), ) ADJCASE_CHOICES = ( ('NOMPL', _('plural')), ('ATTR', _('attributive')), ('N-ACC', _('accusative')), ('N-ILL', _('illative')), ('N-INE', _('inessive')), ('N-ELA', _('elative')), ('N-COM', _('comitative')), ('N-GEN', _('genitive')), ('N-ESS', _('essive')), ) ADJ_CONTEXT_CHOICES = ( ('ATTRPOS', _('attributive positive')), ('ATTRCOMP', _('attributive comparative')), ('ATTRSUP', _('attributive superlative')), ('PREDPOS', _('predicative positive')), ('PREDCOMP', _('predicative comparative')), ('PREDSUP', _('predicative superlative')), ) GRADE_CHOICES = ( ('POS', _('positive')), ('COMP', _('comparative')), ('SUPERL', _('superlative')), ) NUM_CONTEXT_CHOICES = ( ('NUM-ATTR', _('attributive')), ('NUM-NOM-PL', _('plural')), ('NUM-ACC', _('accusative')), ('NUM-ILL', _('illative')), ('NUM-LOC', _('locative')), ('NUM-COM', _('comitative')), ('COLL-NUM', _('collective')), ('ORD-NUM', _('ordinals')), ) NUM_BARE_CHOICES = ( ('NOMPL', _('plural')), ('N-ACC', _('accusative')), ('N-ILL', _('illative')), ('N-INE', _('inessive')), ('N-ELA', _('elative')), ('N-COM', _('comitative')), ) NUM_LEVEL_CHOICES = ( ('1', _('First level')), ('2', _('Second level')), ) VTYPE_CHOICES = ( ('PRS', _('present')), ('PRT', _('past')), # ('COND', _('conditional')), # ('IMPRT', _('imperative')), # ('POT', _('potential')), ) VTYPE_CONTEXT_CHOICES = ( ('PRS', _('present')), ('PRT', _('past')), ('V-COND', _('conditional')), ('V-IMPRT', _('imperative')), ('V-POT', _('potential')), ) LEVEL_CHOICES = ( ('l1', _('Level 1')), ('l2', _('Level 1-2')), ('l3', _('Level 1-3')), ('all', _('All')), ) FREQUENCY_CHOICES = ( ('rare', _('rare')), ('common', _('common')), ) GEOGRAPHY_CHOICES = ( ('world', _('world')), ('sápmi', _('sapmi')), ('suopma', _('suopma')), ) VASTA_LEVELS = ( ('1', _('First level')), ('2', _('Second level')), ('3', _('Third level')), ) TRANS_CHOICES = ( ('smanob', _('South Sami to Norwegian')), ('nobsma', _('Norwegian to South Sami')), # ('smasme', _('South Sami to North Sami')), # ('smesma', _('North Sami to South Sami')), # ('smaswe', _('South Sami to Swedish')), # ('swesma', _('Swedish to South Sami')), # ('smaeng', _('South Sami to English')), # ('engsma', _('English to South Sami')), # ('smadeu', _('South Sami to German')), # ('deusma', _('German to South Sami')), ) NUMLANGUAGE_CHOICES = ( ('sma', _('South Sami')), ) SEMTYPE_CHOICES = ( ('HUMAN', _('Human')), ('FOOD/DRINK', _('Food/drink')), ('ANIMAL', _('Animal')), ('OBJECT', _('Object')), ('CONCRETES', _('Concretes')), ('BODY', _('Body')), ('CLOTHES', _('Clothes')), ('BUILDINGS/ROOMS', _('Buildings/rooms')), ('NATUREWORDS', _('Nature words')), ('LEISURETIME/AT_HOME', _('Leisuretime/at home')), ('PLACES', _('Places')), ('ABSTRACTS', _('Abstracts')), ('WORK/ECONOMY/TOOLS', _('Work/economy/tools')), ('TIMEEXPRESSIONS', _('Timeexpressions')), ('LITERATURE/TEXT', _('Literature/text')), ('SCHOOL/EDUCATION', _('School/education')), ('REINDEER/HERDING', _('Reindeerherding')), ('TRADITIONAL', _('Traditional')), # ('YYY', _('YYY')), ('all', _('all')), ) NUM_CHOICES = ( ('10', _('0-10')), ('20', _('0-20')), ('100', _('0-100')), ('1000', _('0-1000')), # ('ALL', _('all')), ) NUMGAME_CHOICES = ( ('numeral', _('Numeral to string')), ('string', _('String to numeral')), ) DIALOGUE_CHOICES = ( ('firstmeeting', _('Firstmeeting')), ('firstmeeting_boy', _('Firstmeeting boy')), ('firstmeeting_girl', _('Firstmeeting girl')), ('firstmeeting_man', _('Firstmeeting man')), ('visit', _('Visit')), ('grocery', _('Grocery')), ('shopadj', _('Shopadj')), ) # # # # Morfa-S choices # # # BOOK_CHOICES = ( ('a1', _(u'Aalkoe')), ('dej', _(u'Dejpeladtje vætnoeh vuekieh')), ('s1', _(u'Saemesth amma 1')), ('s2', _(u'Saemesth amma 2')), ('s3', _(u'Saemesth amma 3')), ('s4', _(u'Saemesth amma 4')), ('åa1', _(u'Åarjel-saemien 1')), ('åa2', _(u'Åarjel-saemien 2')), ('åa3', _(u'Åarjel-saemien 3')), ('åa4', _(u'Åarjel-saemien 4')), ('åa5', _(u'Åarjel-saemien 5')), ('åa6', _(u'Åarjel-saemien 6')), ('all', _(u'All')), ) # BOOK_CHOICES = tuple( # [(source.name, source.name) for source in Source.objects.all()] + \ # [('all', _('ALL'))] # ) # # # # Form validation # # # ISO = { "fi": "fin", "ru": "rus", "en": "eng", "no": "nob", "de": "deu", "sma": "sma", } def switch_language_code(CODE): """ Switches language codes from ISO 639-1 to ISO 639-2. >>> switch_language_code("no") "nob" """ try: return ISO[CODE] except: # logger.warning("*** Unidentified language code %s." % CODE) # print >> sys.stdout, "*** Unidentified language code %s." % CODE return settings.LANGUAGE_CODE def is_correct(self, game, example=None): """ Determines if the given answer is correct (for a bound form). """ if not self.is_valid(): return False self.userans = self.cleaned_data['answer'] answer = self.userans.strip() if not game == "numra": answer = answer.rstrip('.!?,') self.error = "error" iscorrect = False if answer in set(self.correct_anslist) or \ answer.lower() in set(self.correct_anslist) or \ answer.upper() in set(self.correct_anslist): self.error = "correct" iscorrect = True # Log information about user answers. correctlist = ",".join(self.correct_anslist) today = datetime.date.today() log, c = Log.objects.get_or_create(userinput=answer,correct=correctlist,iscorrect=iscorrect,\ example=example,game=game,date=today) log.save() def set_correct(self): """ Adds correct wordforms to the question form. """ if self.correct_ans: self.correct_answers = self.correct_ans[:] def set_settings(self): # self.levels = { # 'l1': ['l1'], # 'l2': ['l2', 'l1'], # 'l3': ['l3', 'l2', 'l1'], # 'all': ['l3', 'l2', 'l1', 'all'], # } # Construct arrays for level choices. # Commenting this out because I don't see yet why this needs to be constructed this way. # If it's done automatically so that more levels can be added, the code here will still need # to be altered... So it seems easiest to just hard-code this for now. # self.levels = {} # self.levels['all'] = [] # for b in LEVEL_CHOICES: # if b[0] != 'all': # self.levels[b[0]] = [] # self.levels['all'].append(b[0]) # # self.levels[b[0]].append(b[0]) # # self.levels['l2'].append('l1') # for b in ['l1', 'l2']: # self.levels['l3'].append(b) # Turning these into dictionary type means there's no need to iterate to # get the first tuple item. Also makes it easier to read. And, there are # no many-to-many relationships in these tuples of tuples self.allsem = dict(SEMTYPE_CHOICES).keys() self.allcase = dict(CASE_CHOICES).keys() self.allcase_context = dict(CASE_CONTEXT_CHOICES).keys() self.allvtype_context = dict(VTYPE_CONTEXT_CHOICES).keys() self.alladj_context = dict(ADJ_CONTEXT_CHOICES).keys() self.allnum_context = dict(NUM_CONTEXT_CHOICES).keys() self.allnum_bare = dict(NUM_BARE_CHOICES).keys() self.sources = dict(BOOK_CHOICES).keys() # comment # DEBUG = open('/dev/ttys001', 'w') # DEBUG = open('/dev/null', 'w') def get_feedback(self, word, tag, wordform, language, dialect): feedbacks = None QUERY = Q(stem=word.stem) & Q(gradation=word.gradation) & \ Q(diphthong=word.diphthong) & Q(soggi=word.soggi) & \ Q(rime=word.rime) if tag.pos == "N" or tag.pos == "Num": FEEDBACK_Q = Q(case2=tag.case) & Q(pos=tag.pos) & Q(number = tag.number) elif tag.pos == "A": if tag.grade: grade = tag.grade else: grade = "Pos" if tag.attributive: attributive = "Attr" attrsuffix = word.attrsuffix else: attributive = "NoAttr" FEEDBACK_Q = Q(case2=tag.case) & \ Q(pos=tag.pos) & Q(grade=grade) &\ Q(attributive=attributive) & Q(attrsuffix=attrsuffix) & \ Q(number=tag.number) elif tag.pos == "V": FEEDBACK_Q = Q(mood=tag.mood) & Q(tense=tag.tense) & \ Q(personnumber=tag.personnumber) & Q(dialects__dialect=dialect) feedbacks = Feedback.objects.filter(QUERY & FEEDBACK_Q) # print >> DEBUG, feedbacks language = switch_language_code(language) if feedbacks: for f in feedbacks: msgs = f.messages.all() for m in msgs: if Feedbacktext.objects.filter(feedbackmsg=m,language=language).count()>0: text = Feedbacktext.objects.filter(feedbackmsg=m,language=language)[0] self.feedback = self.feedback + " " + text.message self.feedback = self.feedback.replace("WORDFORM", "\"" + wordform + "\"") #print "FEEDBACK", self.feedback def select_words(self, qwords, awords): """ Fetch words and tags from the database. Appears to not actually be in use, deprecated by other code? """ selected_awords = {} for syntax in awords.keys(): word = None tag = None selected_awords[syntax] = {} # Select answer words and fullforms for interface if awords.has_key(syntax) and len(awords[syntax]) > 0: aword = awords[syntax][randint(0,len(awords[syntax])-1)] if aword.has_key('tag'): selected_awords[syntax]['tag'] = aword['tag'] if aword.has_key('word') and aword['word']: selected_awords[syntax]['word'] = aword['word'] else: if aword.has_key('qelement') and selected_awords[syntax].has_key('tag'): form_list = None max=50 i=0 while not form_list and i0: wqel = WordQElement.objects.filter(qelement__id=aword['qelement'])[randint(0,word_count-1)] selected_awords[syntax]['word'] = wqel.word.id form_list = Form.objects.filter(Q(word__id=selected_awords[syntax]['word']) &\ Q(tag__id=selected_awords[syntax]['tag'])) if form_list: fullf=[] for f in form_list: fullf.append(f.fullform) selected_awords[syntax]['fullform'] = fullf[:] if not selected_awords[syntax].has_key('fullform'): if aword.has_key('fullform') and len(aword['fullform'])>0: selected_awords[syntax]['fullform'] = aword['fullform'][:] if not selected_awords[syntax].has_key('fullform'): if selected_awords[syntax].has_key('word') and selected_awords[syntax].has_key('tag'): form_list = Form.objects.filter(Q(word__id=selected_awords[syntax]['word']) &\ Q(tag__id=selected_awords[syntax]['tag'])) if form_list: fullf=[] for f in form_list: fullf.append(f.fullform) selected_awords[syntax]['fullform'] = fullf[:] # make sure that there is something to print if not selected_awords[syntax].has_key('fullform'): selected_awords[syntax]['fullform'] = [] selected_awords[syntax]['fullform'].append(syntax) return selected_awords # # # # Oahpa form meta-classes # # # class OahpaSettings(forms.Form): """ The metaform for game settings. Various games subclass from this form. """ set_settings = set_settings def set_default_data(self): self.default_data = {'language' : 'rus', 'syll' : ['bisyllabic'], 'level' : 'all', 'case': 'N-ILL', 'pos' : 'N', 'vtype' : 'PRS', 'adjcase' : 'ATTR', 'grade' : 'POS', 'case_context' : 'N-ILL', 'vtype_context' : 'PRS', 'num_context' : 'NUM-ATTR', 'num_level' : '1', 'num_bare' : 'N-ILL', 'adj_context' : 'ATTRPOS', 'source' : 'all'} # Link to grammatical explanation for each page self.grammarlinkssma = Grammarlinks.objects.filter(language="sma").order_by('id') self.grammarlinksno = Grammarlinks.objects.filter(language="no").order_by('id') class OahpaQuestion(forms.Form): """ Meta form for question/answer section. """ is_correct = is_correct set_correct = set_correct get_feedback = get_feedback # Set answer widget. Can this JS actually be moved to templates? KEYDOWN = 'javascript:return process(this, event, document.gameform);' answer_attrs = {'size': 45} # , 'onkeydown': KEYDOWN} answer = forms.CharField(max_length=45, widget=forms.TextInput(attrs=answer_attrs)) def __init__(self, *args, **kwargs): correct_val = kwargs.get('correct_val') kwargs.pop('correct_val') super(OahpaQuestion, self).__init__(*args, **kwargs) # set correct and error values if correct_val == "correct": self.error = "correct" def init_variables(self, correct, userans_val, fullforms): # Get lemma and feedback self.feedback = "" self.messages = [] self.correct_ans = correct self.correct_answers = "" self.case = "" self.userans = userans_val self.correct_anslist = [] self.error = "empty" self.problems = "error" self.pron = "" self.pron_imp = "" self.PronPNBase = PRONOUNS_LIST self.is_relaxed = "" forms = [] relaxings = [] if hasattr(self, 'translang'): if self.translang == 'sma': # Relax spellings. forms = sum([relax(force_unicode(item)) for item in fullforms], []) # need to subtract legal answers and make an only relaxed list. relaxings = [item for item in forms if item not in fullforms] # for f in forms: # print f self.correct_anslist = [force_unicode(item) for item in fullforms] + \ [force_unicode(f) for f in forms] self.relaxings = relaxings # # # # Leksa Forms # # # class LeksaSettings(OahpaSettings): semtype = forms.ChoiceField(initial='HUMAN', choices=SEMTYPE_CHOICES, widget=forms.Select(attrs={'onchange':'javascript:return SetIndex(document.gameform.level,this.value);',})) transtype = forms.ChoiceField(initial='smanob', choices=TRANS_CHOICES, widget=forms.Select) # For placename quizz common = forms.BooleanField(required=False, initial='1') rare = forms.BooleanField(required=False,initial=0) sapmi = forms.BooleanField(required=False, initial='1') world = forms.BooleanField(required=False,initial=0) suopma = forms.BooleanField(required=False,initial=0) source = forms.ChoiceField(initial='all', choices=BOOK_CHOICES, widget=forms.Select(attrs={'onchange':'javascript:return SetIndex(document.gameform.semtype,this.value);',})) # level = forms.ChoiceField(initial='all', choices=LEVEL_CHOICES, widget=forms.Select(attrs={'onchange':'javascript:return SetIndex(document.gameform.semtype,this.value);',})) default_data = {'gametype' : 'bare', 'language' : 'sma', 'dialogue' : 'GG', \ 'syll' : [], 'source': 'all', \ 'semtype' : 'HUMAN', \ 'frequency' : ['common'], 'geography' : ['sapmi'], \ 'transtype' : 'smanob' } # Link to grammatical explanation for each page grammarlinkssma = Grammarlinks.objects.filter(language="sma") grammarlinksno = Grammarlinks.objects.filter(language="no") def __init__(self, *args, **kwargs): self.set_settings() super(LeksaSettings, self).__init__(*args, **kwargs) class LeksaQuestion(OahpaQuestion): """ Questions for word quizz """ def __init__(self, transtype, word, correct, translations, question, userans_val, correct_val, *args, **kwargs): lemma_widget = forms.HiddenInput(attrs={'value' : word.id}) self.translang = transtype[-3::] kwargs['correct_val'] = correct_val super(LeksaQuestion, self).__init__(*args, **kwargs) # Initialize variables self.init_variables(correct, userans_val, translations) self.fields['word_id'] = forms.CharField(widget=lemma_widget, required=False) # Use definition, which picks amongst phrase, explanation and lemma # for non-Word objects if type(word) == Word: self.lemma = word.lemma else: self.lemma = word.definition if word.pos.upper() == 'V': if transtype=="engsma": self.lemma = u'to ' + force_unicode(self.lemma) if transtype=="nobsma": self.lemma = u'å ' + force_unicode(self.lemma) self.is_correct("leksa", self.lemma) # set correct and error values if correct_val: if correct_val == "correct": self.error="correct" # relax if userans_val in self.relaxings: self.is_relaxed = "relaxed" self.strict = 'Strict form' else: self.is_relaxed = "" # # # # Morfa Forms # # # class MorfaSettings(OahpaSettings): """ A form for the settings part of the game form, e.g., the form used to set case, stem and source books for quiz questions. This is a separate form from the one which validates questions and answers. """ case = forms.ChoiceField(initial='N-ILL', choices=CASE_CHOICES, widget=forms.Select) adjcase = forms.ChoiceField(initial='ATTR', choices=ADJCASE_CHOICES, widget=forms.Select) vtype = forms.ChoiceField(initial='PRS', choices=VTYPE_CHOICES, widget=forms.Select) num_bare = forms.ChoiceField(initial='N-ILL', choices=NUM_BARE_CHOICES, widget=forms.Select) num_level = forms.ChoiceField(initial='1', choices=NUM_LEVEL_CHOICES, widget=forms.Select) num_context = forms.ChoiceField(initial='NUM-ATTR', choices=NUM_CONTEXT_CHOICES, widget=forms.Select) case_context = forms.ChoiceField(initial='N-ILL', choices=CASE_CONTEXT_CHOICES, widget=forms.Select) adj_context = forms.ChoiceField(initial='ATTR', choices=ADJ_CONTEXT_CHOICES, widget=forms.Select) vtype_context = forms.ChoiceField(initial='PRS', choices=VTYPE_CONTEXT_CHOICES, widget=forms.Select) # Was BOOK_CHOICES book = forms.ChoiceField(initial='all', choices=BOOK_CHOICES, widget=forms.Select) bisyllabic = forms.BooleanField(required=False, initial='1') trisyllabic = forms.BooleanField(required=False,initial=0) contracted = forms.BooleanField(required=False,initial=0) grade = forms.ChoiceField(initial='POS', choices=GRADE_CHOICES, widget=forms.Select) def __init__(self, *args, **kwargs): self.set_settings() self.set_default_data() super(MorfaSettings, self).__init__(*args, **kwargs) class MorfaQuestion(OahpaQuestion): """ Questions for morphology game. """ def __init__(self, word, tag, baseform, correct, fullforms, translations, question, dialect, language, userans_val, correct_val, *args, **kwargs): lemma_widget = forms.HiddenInput(attrs={'value': word.id}) tag_widget = forms.HiddenInput(attrs={'value': tag.id}) self.translang = 'sma' kwargs['correct_val'] = correct_val super(MorfaQuestion, self).__init__(*args, **kwargs) # initialize variables self.init_variables(correct.fullform, userans_val, fullforms) self.fields['word_id'] = forms.CharField(widget=lemma_widget, required=False) self.fields['tag_id'] = forms.CharField(widget=tag_widget, required=False) self.lemma = baseform.fullform # print self.lemma, correct # print baseform.tag, correct.tag # Retrieve feedback information self.get_feedback(word=word, tag=tag, wordform=baseform.fullform, language=language, dialect=dialect) # Take only the first translation for the tooltip if len(translations) > 0: self.translations = translations[0] if tag.pos == "N": self.case = tag.case self.tag = tag.string if tag.pos=="V" and tag.personnumber and not tag.personnumber == "ConNeg": # print "gogo verb ", tag.pos, tag.personnumber pronbase = self.PronPNBase[tag.personnumber] # print "xxxx ", pronbase # pronoun = Form.objects.filter(Q(word__lemma=pronbase) & \ # Q(tag__string="Pron+Pers+" +tag.personnumber+ "+Nom")) pronoun = pronbase # if pronoun.count() == 0: # error = "MorfaQuestion.__init__ cannot find any pronouns in the database." # raise Http404(error) # self.pron = pronoun[0].fullform self.pron = pronoun if self.pron and tag.mood == "Imprt": self.pron_imp = "(" + self.pron + ")" self.pron = "" self.is_correct("morfa" + "_" + tag.pos, self.lemma + "+" + self.tag) # set correct and error values if correct_val: if correct_val == "correct": self.error="correct" # relax if userans_val in self.relaxings: self.is_relaxed = "relaxed" self.strict = 'Strict form' else: self.is_relaxed = "" # # # # Numra Forms # # # class NumSettings(OahpaSettings): maxnum = forms.ChoiceField(initial='10', choices=NUM_CHOICES, widget=forms.RadioSelect) numgame = forms.ChoiceField(initial='numeral', choices=NUMGAME_CHOICES, widget=forms.RadioSelect) numlanguage = forms.ChoiceField(initial='sma', choices=NUMLANGUAGE_CHOICES, widget=forms.RadioSelect) default_data = {'language' : 'nob', 'numlanguage' : 'sma', 'dialogue' : 'GG', 'maxnum' : '10', 'numgame': 'numeral'} grammarlinkssma = Grammarlinks.objects.filter(language="sma") grammarlinksno = Grammarlinks.objects.filter(language="no") def __init__(self, *args, **kwargs): self.set_settings super(NumSettings, self).__init__(*args, **kwargs) class NumQuestion(OahpaQuestion): """ Questions for numeral quizz """ def __init__(self, numeral, num_string, num_list, gametype, userans_val, correct_val, *args, **kwargs): numeral_widget = forms.HiddenInput(attrs={'value' : numeral}) kwargs['correct_val'] = correct_val self.userans_val = self.userans = userans_val super(NumQuestion, self).__init__(*args, **kwargs) wforms = [] self.relaxings = [] # Initialize variables if gametype == "string": self.init_variables(force_unicode(numeral), userans_val, [ numeral ]) example = num_string else: self.init_variables(force_unicode(num_list[0]), userans_val, num_list) wforms = sum([relax(force_unicode(item)) for item in num_list], []) # need to subtract legal answers and make an only relaxed list. self.relaxings = [item for item in wforms if item not in num_list] example = numeral self.correct_anslist = self.correct_anslist + [force_unicode(f) for f in wforms] self.fields['numeral_id'] = forms.CharField(widget=numeral_widget, required=False) if gametype == "string": self.numstring = num_string self.numeral = numeral self.is_correct("numra", example) if correct_val: if correct_val == "correct": self.error = "correct" # relax if userans_val in self.relaxings: self.is_relaxed = "relaxed" self.strict = 'Strict form' else: self.is_relaxed = ""