20120726

Cannot re-execute Tx25-Anfrage #9 with non-empty ticket

Alicia hatte auf einer bereits ausgeführten Tx25 (die mit disable_editing komplett schreibgeschützt ist) auf “Speichern” geklickt. Sie bekam dann “AJAX communication failed” als Antwort, und der Server machte einen Traceback “Cannot re-execute Tx25-Anfrage #9 with non-empty ticket.”.

Der Fehler war, dass der Speichern-Button trotz disable_editing aktiv war. Das lag an einem Bug in lino.core.actors.Actor.disabled_actions(): die rief a.get_action_permission(ar.get_user(),obj,state) statt obj.get_row_permission(u,state,a). Behoben.

Aber dann fiel mir auf: dadurch wurden nicht nur die Buttons “Speichern” und “Löschen” disabled, sondern auch “Neu”. Das war logisch aber falsch: logisch, weil InsertRow.readonly False war und Tx25.get_row_permission folglich Veto erhebt, falsch weil man hier ja doch auf “Neu” klicken können soll. Die Bedeutung von Action.readonly muss sein: ob diese Aktion im gegebenen Objekt etwas ändert. So gesehen ist InsertRow keine verändernde Aktion.

Also: InsertRow hat ab jetzt readonly=True, und damit readonly-Benutzer jetzt nicht plötzlich einfügen können, überschreiben wir ihre get_action_permission:

def get_action_permission(self,user,obj,state):
    if user.profile.readonly:
        return False
    return super(InsertRow,self).get_action_permission(oser,obj,state)

Forced update did not affect any rows

Ein anderer Traceback auf dem Server gestern war “Forced update did not affect any rows”. Der kommt, wenn man auf einem JobProvider “Speichern” klickt, obwohl man gar nichts verändert hat. Kommt nur mit MySQL (nicht mit SQLite). Kommt nur auf einer MTI-Tabelle.

Um das zu verhindern, mache ich in form2obj_and_save jetzt einen Test ähnlich wie lino.utils.dblogger.DiffingMixin, und wenn sich nichts verändert hat, kommt jetzt “%s : nothing to save.”, und before_ui_save und full_clean werden dann auch gar nicht erst aufgerufen. Das gilt bei allen Records, nicht nur in MTI-Tabellen.

Konvention #270 : Aufgabenbereich wird nicht gedruckt

Hier der Text, der in Contract.responsibilities steht:

<p><span style="font-family: Verdana;">Arbeitszeiten:</span></p>
<p><span style="font-family: Verdana;">Montag-Dienstag von 11:00-18:30 (1Stunde Mittagspause)</span></p>
<p><span style="font-size: 7.5pt; font-family: Verdana; color: black;">Mittwoch: frei</span></p>
<p><span style="font-size: 7.5pt; font-family: Verdana; color: black;">Donnerstag: 12:00-19:30 (1 Stunde Mittagspause)</span></p>
<p><span style="font-size: 7.5pt; font-family: Verdana; color: black;">Freitag: 13:00-20:30 (1 Stunde Mittagspause)</span></p>
<p><span style="font-size: 7.5pt; font-family: Verdana; color: black;">Samstag: 8:00-14:30 (1/2 Stunde Mittagspause)</span></p>
<p><span style="font-size: 7.5pt; font-family: Verdana; color: black;">Sonntag: frei&nbsp;</span></p>
<p><span style="font-size: 7.5pt; font-family: Verdana; color: black;"><!--[if !supportEmptyParas]-->&nbsp;<!--[endif]--></span></p>
<p><span style="font-size: 7.5pt; font-family: Verdana; color: black;">Aufgabenbereiche:&nbsp;</span></p>
<p><span style="font-family: Verdana; font-size: 7.5pt;">* Truck wash (lavage des camions)</span></p>
<p><span style="font-size: 7.5pt; font-family: Verdana; color: black; mso-ansi-language: FR;"><span style="font-size: 7.5pt; font-family: Verdana; color: black; mso-ansi-language: FR;" lang="FR">* Aide au niveau du garage (r&eacute;paration de planchers de camions, &eacute;clairage de remorques, remplacement de pi&egrave;ces de carrosserie,...)</span></span></p>
<p><span style="font-size: 7.5pt; font-family: Verdana; color: black; mso-ansi-language: FR;"><span style="font-size: 7.5pt; font-family: Verdana; color: black; mso-ansi-language: FR;" lang="FR">* Entretien des abords (plantations, tonde des herbes et des hailles,...)</span></span></p>
<p><span style="font-size: 7.5pt; font-family: Verdana; color: black; mso-ansi-language: FR;"><span style="font-size: 7.5pt; font-family: Verdana; color: black; mso-ansi-language: FR;" lang="FR">* Service b&acirc;timents (Petits travaux &eacute;lectriques, maintenance,...)</span></span></p>
<p><span style="font-size: 7.5pt; font-family: Verdana; mso-fareast-font-family: &quot;Times New Roman&quot;; mso-bidi-font-family: &quot;Times New Roman&quot;; color: black; mso-ansi-language: FR; mso-fareast-language: DE; mso-bidi-language: AR-SA;" lang="FR"><span style="font-size: 7.5pt; font-family: Verdana; mso-fareast-font-family: &quot;Times New Roman&quot;; mso-bidi-font-family: &quot;Times New Roman&quot;; color: black; mso-ansi-language: FR; mso-fareast-language: DE; mso-bidi-language: AR-SA;">* Nettoyage et rangement dans l'entrep&ocirc;t.</span></span></p>
<p><span style="font-size: 7.5pt; font-family: Verdana; mso-fareast-font-family: &quot;Times New Roman&quot;; mso-bidi-font-family: &quot;Times New Roman&quot;; color: black; mso-ansi-language: FR; mso-fareast-language: DE; mso-bidi-language: AR-SA;" lang="FR"><span style="font-size: 7.5pt; font-family: Verdana; mso-fareast-font-family: &quot;Times New Roman&quot;; mso-bidi-font-family: &quot;Times New Roman&quot;; color: black; mso-ansi-language: FR; mso-fareast-language: DE; mso-bidi-language: AR-SA;"><br /></span></span></p>

Hier die Fehlermeldung im Dokument (nur sichtbar, nachdem ich Druckmethode von AppyPdf nach AppyOdt umgeschaltet habe):

Error while evaluating the expression "html(self.responsibilities)" defined in the "from" part of a statement.
File "<string>", line 1, in <module>
File "/var/snapshots/lino/lino/utils/appy_pod.py", line 189, in html_func
return self.renderXhtml(html,**kw)
File "/var/snapshots/appy-current/appy/pod/renderer.py", line 242, in renderXhtml
stylesMapping, ns).run()
File "/var/snapshots/appy-current/appy/pod/xhtml2odt.py", line 497, in run
self.xhtmlParser.parse(self.xhtmlString)
File "/var/snapshots/appy-current/appy/shared/xml_parser.py", line 193, in parse
self.parser.parse(inputSource)
File "/usr/lib/python2.6/xml/sax/expatreader.py", line 107, in parse
xmlreader.IncrementalParser.parse(self, source)
File "/usr/lib/python2.6/xml/sax/xmlreader.py", line 123, in parse
self.feed(buffer)
File "/usr/lib/python2.6/xml/sax/expatreader.py", line 211, in feed
self._err_handler.fatalError(exc)
File "/usr/lib/python2.6/xml/sax/handler.py", line 38, in fatalError
raise exception
<class 'xml.sax._exceptions.SAXParseException'>: <unknown>:14:82: not well-formed (invalid token)

12 Uhr : Ich vermute, dass es an den Gänsefüßchen in family: "Times New Roman" liegt:

----------------------------------------------------------------------------------
<p><span style="font-size: 7.5pt; font-family: Verdana; mso-fareast-font-family: "Times New Roman"; mso-bidi-font-family
: "Times New Roman"; color: black; mso-ansi-language: FR; mso-fareast-language: DE; mso-bidi-language: AR-SA;" lang="FR"
><span style="font-size: 7.5pt; font-family: Verdana; mso-fareast-font-family: "Times New Roman"; mso-bidi-font-family:
"Times New Roman"; color: black; mso-ansi-language: FR; mso-fareast-language: DE; mso-bidi-language: AR-SA;">* Nettoyage
 et rangement dans l'entrepôt.</span></span></p>

13.10 Uhr : Da! Ich habs! Mein Modul lino.utils.html2xhtml produzierte ungültigen XHTML, wenn im HTML Attribute mit Gänsefüßen waren:

def attrs2xml(attrs):
    return ' '.join(['%s="%s"' % a for a in attrs])

So ist es besser:

from xml.sax.saxutils import quoteattr
def attrs2xml(attrs):
    return ' '.join(['%s=%s' % (k,quoteattr(v)) for k,v in attrs])

Im Docstring des Moduls mach ich jetzt auch einen test case dafür:

>>> html = '''\
... <p style="font-family: &quot;Verdana&quot;;">Verdana</p>'''
>>> print repr(html2xhtml(html))
u'<p style=\'font-family: "Verdana";\'>Verdana</p>'