source: trunk/ExerciseMaterial.py @ 2038

Revision 2038, 12.2 KB checked in by pjotr, 12 years ago (diff)

Modified the sendAnswers method to actualy send e-mails, we are now using secureSend instead of just send, the message id now uncoded proper utf-8 and readable, also added messaging part to the fullscreen_template so that the messages would be shown

Line 
1# Copyright 2006 by the LeMill Team (see AUTHORS)
2#
3# This file is part of LeMill.
4#
5# LeMill is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# LeMill is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with LeMill; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1
18
19from AccessControl import ClassSecurityInfo, getSecurityManager
20from Products.Archetypes.public import *
21from Products.CMFCore.utils import getToolByName
22
23from config import PROJECTNAME, MODIFY_CONTENT, VIEW, to_unicode
24from FieldsWidgets import ChapterField, ChapterWidget, StringWidget
25from SharedMetadata import *
26from Material import Material
27from permissions import MODIFY_CONTENT
28from random import shuffle
29from Products.LeMill import LeMillMessageFactory as _
30
31import re
32
33schema = BaseSchema + Schema((
34   ChapterField('bodyText',
35        accessor="getBodyText",
36        edit_accessor = 'getRawBodyText',
37        mutator = "setBodyText",
38        index='ZCTextIndex:schema',
39        index_method = 'getOnlyText',
40        searchable = True,
41        deleteEmptyChapters = False,
42        allowable_content_types = ['text/html',],
43        allow_file_upload = False,
44        default_output_type = 'text/x-html-captioned',
45        default_content_type = 'text/html',
46        default=[('','guidelines'),],
47        widget=ExerciseWidget(label = "Body text",
48            label_msgid = "label_bodytext",
49            i18n_domain = "lemill",
50            ),
51    ),
52))
53
54schema = schema + tags + language_schema + group_sharing + subject_area_schema + target_group_schema + license_schema + coverImage + lemill_metadata_mods + no_description + author_schema + deletionReason + version_schema + translation_schema + ieee_lom_lre_ap + latest_edit_schema + score
55
56schema = schema.copy()
57schema.moveField('rights', pos='bottom')
58schema.moveField('language', after='bodyText')
59schema['title'].required = True
60
61fill_in_the_blanks=re.compile(r"""(?P<filler>({.*?})+)""",  re.IGNORECASE)
62
63class ExerciseMaterial(Material):
64    """Exercise page"""
65
66    schema = schema
67
68    meta_type = "ExerciseMaterial"
69    archetype_name = "ExerciseMaterial"
70
71    security = ClassSecurityInfo()
72    security.declareObjectPublic()
73
74    security.declarePrivate('manage_afterAdd')
75    def manage_afterAdd(self, item, container):
76        Material.manage_afterAdd(self, item, container)
77
78        if not hasattr(item.aq_base, 'left_slots'):
79            self._setProperty('left_slots', ['here/portlet_material_actions/macros/portlet',], 'lines')
80        else:
81            self._updateProperty('left_slots', ['here/portlet_material_actions/macros/portlet',])
82
83    def getOnlyText(self):
84        field=self.getField('bodyText')
85        values = field.get(self)
86        dump= '\n'.join([x[0] for x in values if not x[1]!='piece'])
87        return dump
88
89    def isCorrectAnswer(self, chapter, answer_index):
90        """ given a chapter having a multiple choice question, is this answer in correct answers? """
91        return answer_index < len(chapter[1])
92       
93
94    security.declareProtected(MODIFY_CONTENT,'delChapter')
95    def delChapter(self, REQUEST):
96        """ delete chapter """
97        field = self.getField('bodyText')
98        field.delChapter(self, int(REQUEST.get('delete')))
99        return REQUEST.RESPONSE.redirect(self.absolute_url()+'/edit')
100
101    def getAllAnswers(self, chapter):
102        """ Will return the list of the shuffled combined correct and incorrect answers """
103        # Chapter should have the structure: [question,correct_list,incorrect_list]
104        all_answers = chapter[1] + chapter[2]
105        extended_answers = []
106        for numerated_answer in enumerate(all_answers):
107            extended_answers.append(numerated_answer)
108        shuffle(extended_answers)
109        return extended_answers
110
111    def get_values_from_fitbs(self, chapter_index):
112        """ find words in {}:s and return them as dict """
113       
114        text=self.getBodyText()
115        text=text[chapter_index][0]
116        matches=fill_in_the_blanks.findall(text)
117        results={}
118        index=0
119        for m in matches:
120            answer=m[0]
121            answer=answer.strip(' {}')
122            answer=answer.split('}{')
123            results['exercise_%s_answer_%s' % (chapter_index, index)]=answer
124            index=index+1
125        return results
126           
127    def replace_blanks_with_input_tag(self, chapter_index, answers=True, readonly=True):
128        """ find words in { } and replace them with input boxes """
129        replacement="""<input type="text" value="%s"%s name="exercise_%s_answer_%s" id="exercise_%s_answer_%s" />"""
130        self.iterator=0
131       
132        def rep(match):
133            answer_index=self.iterator
134            if answers:
135                value=match.group('filler').strip(' {}')
136                value=value.replace('}{','/')
137            else:
138                value=""
139            self.iterator+=1
140            return replacement % (value, readonly, chapter_index, answer_index, chapter_index, answer_index)
141
142        if readonly:
143            readonly=' readonly="1"'
144        else:
145            readonly=''           
146        text=self.getBodyText()
147        text=text[chapter_index][0]
148        text=fill_in_the_blanks.sub(rep, text)
149        del self.iterator
150        return text
151
152    def replace_blanks_with_your_answers(self, text, your_answerdict, i):
153        """ find braces {text} and add own answers before them in brackets [mytext]{text} """
154        self.iterator=0
155       
156        def rep(match):
157            value=match.group('filler')           
158            your_answer=your_answerdict.get('exercise_%s_answer_%s' % (i, self.iterator), '')
159            self.iterator+=1
160            return '[%s]%s' % (your_answer, value)
161        text=fill_in_the_blanks.sub(rep, text)
162        del self.iterator
163        return text
164
165
166
167    def sendAnswers(self, REQUEST):
168        """ Send e-mail to a teacher """
169        putils = getToolByName(self,'plone_utils')
170        mhost = putils.getMailHost()
171        mbody = u''
172        students_name = REQUEST.get('your_name','')
173        students_email = REQUEST.get('students_email','')
174        teachers_email = REQUEST.get('teachers_email','')
175
176        if not students_email or (teachers_email and not students_name):
177            msg = _(u"You have not provided enough information to send an e-mail.")
178            putils.addPortalMessage(msg, type='warn')
179            return REQUEST.RESPONSE.redirect(self.absolute_url())
180        exercise_body = self.getBodyText()
181
182
183        # Now we should compose the message body       
184        if teachers_email:
185            mbody += _(u"""
186Hello,
187
188%(name)s has completed the LeMill exercise '%(exercise_title)s' at %(exercise_url)s.
189""") % {'name':to_unicode(students_name), 'exercise_title':to_unicode(self.Title()), 'exercise_url':to_unicode(self.absolute_url())}
190        else:
191            mbody += _(u"""
192Hello %(name)s,
193
194You have completed the LeMill exercise '%(exercise_title)s' at %(exercise_url)s.
195""") % {'name':to_unicode(students_name), 'exercise_title':to_unicode(self.Title()), 'exercise_url':to_unicode(self.absolute_url())}
196
197        mbody += _(u"If you are surprised by getting this e-mail, you can simply ignore and delete it as someone may have accidentally inserted your address as a recipient.")
198        # Message body is composed chapter by chapter
199        i=0
200        for (chapter_text, chapter_type) in exercise_body:
201            if chapter_type=='multiple_choices':
202                answered_right = 0
203                answered_wrong = 0
204                question = chapter_text[0]
205                correct_answers = chapter_text[1]
206                answers_total = correct_answers+chapter_text[2]
207                my_answers=[]
208                # Correct answers have small index number
209                for a in range(len(correct_answers)):
210                    answer_value = REQUEST.get('exercise_%s_checkbox_%s' % (i,a),'')
211                    if answer_value:
212                        my_answers.append(answers_total[a])
213                        answered_right+=1
214                    else:
215                        answered_wrong+=1
216                # These are all wrong answers
217                for a in range(len(correct_answers),len(answers_total)):
218                    answer_value = REQUEST.get('exercise_%s_checkbox_%s' % (i,a),'')
219                    if answer_value:
220                        my_answers.append(answers_total[a])
221                        answered_wrong+=1
222                    else:
223                        answered_right+=1
224                percentage=int((float(answered_right)/(answered_wrong+answered_right))*100)
225                mbody += _(u"""
226
227Your answer to question '%(question)s' was:
228%(my_answers)s
229The correct answer is:
230%(correct_answers)s
231You got %(percentage)s%% correct!
232""") % {'question':question, 'my_answers':to_unicode(', '.join(my_answers)), 'correct_answers':to_unicode(', '.join(correct_answers)), 'percentage':percentage}
233
234            elif chapter_type == 'fill_in_the_blanks':
235                correct_answer_dict=self.get_values_from_fitbs(i)
236                correct_answers_n=0
237                my_answer_dict={}
238                all_answers_n=len(correct_answer_dict.keys())
239                for it in range(all_answers_n):
240                    my_answer=REQUEST.get('exercise_%s_answer_%s' % (i,it),'')
241                    correct_answer=[to_unicode(c.strip()) for c in correct_answer_dict['exercise_%s_answer_%s' % (i,it)]]
242                    if to_unicode(my_answer.strip()) in correct_answer:
243                        correct_answers_n+=1
244                    my_answer_dict['exercise_%s_answer_%s' % (i,it)]=my_answer
245                exercise_text=self.replace_blanks_with_your_answers(chapter_text, my_answer_dict, i)
246                mbody += _(u"""
247In the following fill-in-the-blanks exercise your answers and correct answers were:
248%(exercise_text)s
249
250You got %(correct_answers_n)s/%(all_answers_n)s correct!
251""") % {'exercise_text':to_unicode(exercise_text), 'correct_answers_n':correct_answers_n, 'all_answers_n':all_answers_n}           
252
253            elif chapter_type == 'open_ended':
254                students_answer = REQUEST.get('exercise_%s_answer' % i, '')
255                mbody += _(u"""
256Your answer to question '%(question)s' was:
257%(answer)s
258
259Your teacher will give you feedback on your answer.
260""") % {'question':to_unicode(chapter_text), 'answer':to_unicode(students_answer)}
261            i+=1 # <--- remember to increase index
262           
263        mbody += _(u"\n\nBest regards, LeMill")
264        mbody = mbody.encode('utf-8')
265
266        if teachers_email:
267            message_from = "%s <%s>" % (students_name, students_email)
268            message_subject = "LeMill exercise '%s' by %s" % (self.Title(),students_name)
269            try:
270                mhost.secureSend(mbody, mto=teachers_email, mfrom=message_from, subject=message_subject, charset='utf-8')
271                msg = _(u"The e-mail has been sent to a teacher.")
272                putils.addPortalMessage(msg)
273                return REQUEST.RESPONSE.redirect(self.absolute_url())
274            except:
275                msg = _(u"The e-mail could not be sent.")
276                putils.addPortalMessage(msg, type='warn')
277                return REQUEST.RESPONSE.redirect(self.absolute_url())
278        else:
279            message_from = "%s <%s>" % ('LeMill', students_email)
280            message_subject = "LeMill exercise '%s' feedback" % (self.Title())
281            try:
282                mhost.secureSend(mbody, mto=students_email, mfrom=message_from, subject=message_subject, charset='utf-8')
283                msg = _(u"The e-mail has been sent to you.")
284                putils.addPortalMessage(msg)
285                return REQUEST.RESPONSE.redirect(self.absolute_url())
286            except:
287                msg = _(u"The e-mail could not be sent.")
288                putils.addPortalMessage(msg, type='warn')
289                return REQUEST.RESPONSE.redirect(self.absolute_url())
290
291
292registerType(ExerciseMaterial, PROJECTNAME)
Note: See TracBrowser for help on using the repository browser.