divendres, 30 de juny del 2017

"Màgia" amb els bits dels WebSockets

Per un projecte que estem desenvolupant a Amidasoft, he hagut d'implementar una comunicació entre Javascript i un servidor en Java via WebSockets. La veritat és que és senzill d'implementar (com tota comunicació via Sockets amb llenguatges d'alt nivell), però hi ha una particularitat que m'ha fet perdre algunes hores: l'alineament dels primers bits del frame de resposta des del servidor.

Segons la documentació, el frame és:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+

Això dóna a entrendre que, si estem parlant de paquets petits (menys de 128 bytes), el seu primer byte serà:
     10000001    => 0xA1
Ja que es tracta del darrer paquet i el seu opcode és 1. No sé per quina raó, amb aquest primer byte el navegador no és capaç d'interpretar bé el frame.

Al final, ho he solucionat canviant aquest byte per 0x81, tal com s'indica a l'exemple de http://bitsofgyan.com/index.php/2015/10/18/writing-a-simple-websocket-server-in-java/

No tinc clar perquè, però així funciona.

dimarts, 25 d’abril del 2017

Recaptcha "site-info-loading-failed"

Fa uns dies que un lloc web que vaig construir amb Wordpress ja fa temps té problemes amb els formularis de contacte.
Avui m'hi he pogut dedicar una mica i veig que el problema ve amb el reCAPTCHA de Google (v1), que sempre retorna:

false
site-info-loading-failed


No sé perquè ha començat a passar... El més sorprenent és que si es busca aquest error a Google, només troba 3 resultats, que són, precissament, aquest mateix missatge d'error, sense més explicació...

Què deu estar passant?

dimarts, 4 d’abril del 2017

Table './bdd_name/table_name' is marked as crashed and last (automatic?) repair failed

Avui m'ha aparegut aquest missatge en anar a fer una query a la base de dades MySql.
Segons he trobat a http://stackoverflow.com/questions/8843776/mysql-table-is-marked-as-crashed-and-last-automatic-repair-failed, el que cal fer és:

1. Aturar el servidor de MySql:
sudo service mysql stop

2. Anar al directori on està la base de dades (en el meu cas, només l'usuari root tenia permís per a accedir-hi):
cd /var/lib/mysql/$DATABASE_NAME

3. Reparar la taula:
myisamchk -r $TABLE_NAME

4. Tornar a iniciar la base de dades:
sudo service mysql stop

Amb això ja funciona correctament.

El que no sé és perquè ha passat...



dijous, 30 de març del 2017

Error a l'enviar un email des de Odoo v9.

Avui he trobat un problema en una instal·lació de Odoo 9 d'un client: en intentar enviar un email (amb el SMTP correctament configurat) dóna l'error:
Failed to render template <Template memory:7f001e0240d0> using values {'format_tz': <function <lambda> at 0x7efff4974f50>, 'ctx': {'record_name': False, u'uid': 1, 'button_access': None, 'thread_model': u'mail.message', 'safe': False, 'actions': [], 'not_followers': res.partner(11065,), u'params': {}, 'button_unfollow': False, u'lang': u'es_ES', 'tracking': [], u'tz': u'Europe/Andorra', u'active_model': u'mail.message', u'default_no_auto_thread': False, 'mail_post_autofollow': True, 'followers': res.partner(), 'company_name': u'XXXX, SL.', 'signature': u'<p><span>--<br></span></p><p></p><p>\nAdministrator</p>', 'button_follow': False, 'model_name': False, 'website_url': u'http://www.xxxx.com'}, 'user': res.users(1,), 'object': mail.message(32735,)}

Buscant una possible solució, he trobat https://groups.google.com/forum/#!topic/openerp-spain-users/cGNMjLRzEJY , on indiquen que el problema es corregeix posant l'idioma anglès... molt estrany, no?

Malhauradament, configurar l'Odoo per a que estigui en anglès no és una solució vàlida en el meu cas.
Afegint missatges de log a l'arxiu "/usr/lib/python2.7/dist-packages/openerp/addons/mail/models/mail_template.py", he vist que usa el següent text com a template:

<div itemscope itemtype="http://schema.org/EmailMessage">
  <div itemprop="potentialAction" itemscope itemtype="http://schema.org/ViewAction">
    % if ctx.get('button_access'):
      <link itemprop="target" href="${ctx['button_access']['url']}"/>
      <link itemprop="url" href="${ctx['button_access']['url']}"/>
    % endif
    <meta itemprop="name" content="Ver ${ctx['model_name']}"/>
  </div>
</div>
<div summary="o_mail_notification" style="padding:0px; width:600px; margin:0 auto; background: #FFFFFF repeat top /100%; color:#777777">
  <table cellspacing="0" cellpadding="0" style="width:600px; border-collapse:collapse; background:inherit; color:inherit">
    <tbody>
      <tr>
        <td valign="center" width="270" style="padding:5px 10px 5px 5px;font-size: 30px">
          % if ctx.get('button_access'):
            <a href="${ctx['button_access']['url']}" style="-webkit-user-select: none; padding: 5px 10px; font-size: 12px; line-height: 18px; color: #FFFFFF; border-color:#a24689; text-decoration: none; display: inline-block; margin-bottom: 0px; font-weight: 400; text-align: center; vertical-align: middle; cursor: pointer; white-space: nowrap; background-image: none; background-color: #a24689; border: 1px solid #a24689; border-radius:3px" class="o_default_snippet_text">
              ${ctx['button_access']['title']}
            </a>
          % endif
          % if ctx.get('button_follow'):
            <a href="${ctx['button_follow']['url']}" style="-webkit-user-select: none; padding: 5px 10px; font-size: 12px; line-height: 18px; color: #FFFFFF; border-color:#a24689; text-decoration: none; display: inline-block; margin-bottom: 0px; font-weight: 400; text-align: center; vertical-align: middle; cursor: pointer; white-space: nowrap; background-image: none; background-color: #a24689; border: 1px solid #a24689; border-radius:3px" class="o_default_snippet_text">
              ${ctx['button_follow']['title']}
            </a>
          % elif ctx.get('button_unfollow'):
            <a href="${ctx['button_unfollow']['url']}" style="-webkit-user-select: none; padding: 5px 10px; font-size: 12px; line-height: 18px; color: #FFFFFF; border-color:#a24689; text-decoration: none; display: inline-block; margin-bottom: 0px; font-weight: 400; text-align: center; vertical-align: middle; cursor: pointer; white-space: nowrap; background-image: none; background-color: #a24689; border: 1px solid #a24689; border-radius:3px" class="o_default_snippet_text">
              ${ctx['button_unfollow']['title']}
            </a>
          % endif
          % if not ctx.get('button_access') and not ctx.get('button_follow') and not ctx.get('button_unfollow') and ctx.get('model_name'):
            <p style="padding: 5px 10px; font-size: 12px;">
              Sobre <strong>${ctx['model_name']} % if ctx.get('record_name'): : ${ctx['record_name']} % endif </strong>
            </p>
          % endif
        </td>
        <td valign="center" align="right" width="270" style="padding:5px 15px 5px 10px; font-size: 12px;">
          <p>
            % if ctx.get('actions'):
              % for action in ctx['actions']:
                <a href="${action['url']}" style="text-decoration:none; color: #a24689;">
                  <strong>${action['title']}</strong>
                </a>
                %if cmp(len(ctx['actions']), 1) == 1 and cmp(len(ctx['actions']), loop.index) == 1:
                  |
                % endif
              % endfor
            % else:
                <strong>Enviado por</strong>
              % if ctx.get('website_url'):
                <a href="${ctx['website_url']}" style="text-decoration:none; color: #a24689;">
              % endif
              <strong>${ctx.get('company_name')}</strong>
              % if ctx.get('website_url'):
                </a>
              % endif
              <strong>usando</strong>
              <a href="https://www.odoo.com" style="text-decoration:none; color: #a24689;">
                <strong>Odoo</strong>
              </a>
            % endif
          </p>
        </td>
      </tr>
    </tbody>
  </table>
</div>
<div style="padding:0px; width:600px; margin:0 auto; background: #FFFFFF repeat top /100%; color:#777777">
  <table cellspacing="0" cellpadding="0" style="vertical-align:top; padding:0px; border-collapse:collapse; background:inherit; color:inherit">
    <tbody>
      <tr>
        <td valign="top" style="width:600px; padding:5px 10px 5px 5px;">
          <div>
            <hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0;margin:15px auto;padding:0">
          </div>
        </td>
      </tr>
    </tbody>
  </table>
</div>
<div style="padding:0px; width:600px; margin:0 auto; background: #FFFFFF repeat top /100%;color:#777777">
  <table cellspacing="0" cellpadding="0" border="0" style="margin: 0 auto; width:600px; border-collapse:collapse; background:inherit; color:inherit">
    <tbody>
      <tr>
        <td style="padding:5px 10px 5px 5px;font-size: 14px;">
          ${object.body | safe}
          % if ctx.get('tracking'):
            <ul>
              % for tracking in ctx['tracking']
                <li>${tracking[0]} : ${tracking[1]} -&gt; ${tracking[2]}</li>
              % endfor
            </ul>
          % endif
        </td>
      </tr>
    </tbody>
  </table>
</div>
% if ctx.get('signature'):
  <div style="padding:0px; width:600px;margin:0 auto; background: #FFFFFF repeat top /100%;color:#777777">
    <table cellspacing="0" cellpadding="0" border="0" style="margin: 0 auto; width:600px; border-collapse:collapse; background:inherit; color:inherit">
      <tbody>
        <tr>
          <td style="padding:5px 10px 5px 5px;font-size: 14px; text-align: left;">
            ${ctx['signature'] | safe}
          </td>
        </tr>
      </tbody>
    </table>
  </div>
% endif
Es correspon a la plantilla de mail amb nom "Notification Email". En canviar aquesta plantilla per només:
  ${object.body | safe}

El missatge s'envia correctament, pel que el problema està en el contingut de la plantilla.
L'he eliminat i he anat afegint fragments fins que... misteri! Ha funcionat amb tota la plantilla!

L'única diferència que hi sé veure és que inicialment estava tota en una sola línia, mentre que ara l'he partit tal com es veu més amunt, indentant els tags... Serà problema del buffer de línia?


Precisió decimal en un camp de Odoo (QWeb)

En afegir un camp a un mòdul d'Odoo, el sistema, per defecte, li assigna una precisió (a la vista) de dos decimals. És igual la precisió que tingui a la base de dades, sempre seran dos decimals.
Per a poder-ho modificar, cal indicar-ho al xml de la vista amb un atribut del tipus: digits="(16,7)"
Amb això tindrem que s'accepta un número de fins a 16 posicions, de les quals 7 són decimals.

Un exemple complet de la vista heretada:

<openerp>
    <data>

     <record model="ir.ui.view" id="add_field_partner_tree">
         <field name="name">res.partner.form.inherit</field>  
         <field name="model">res.partner</field>
         <field name="inherit_id" ref="base.view_partner_form"/>
         <field name="arch" type="xml">
           <xpath expr="//field[@name='lang']" position="after"> 
             <field name="descompte_defecte" />
           </xpath>
           <xpath expr="//field[@name='category_id']" position="after"> 
             <field name="factor_preus" digits="(16,7)" />
           </xpath>
         </field>
     </record>

    </data>

</openerp>