POC: HTML Descriptions for Products


This days I got a call from clients asking me if there is a way to add html descriptions to product templates. After reading a bit source code of the richtext widget and searching for gtk browser widgets I have deicided to write a quick and dirty proof of concept for an external editor. Lot of people know TinyMCE which already does the job. So why not use that?

What I have done yet:

Added a route to the external editor.
Added fields to Producttemplate:

description (fields.Text - the description)
edit_path (fields.Function - the path to the external editor which opens in a browser)

It has two configuration fields in product.configuration:

editor_path (fields.Char - absolute path to a tinymce editor js-file)
content_css (fields.Char - absolute path to a css file to format the content)

TODO: add support for translations

As this is a tiny contribution but possibly helpful for others I ask for review of the security:
How to secure a route? You can see my approach here link

Greetings from Leipzig

Why not use the richtext widget?

Indeed passing the user session as parameter is not the safest design. It will probably more secure to use a “session” dedicated to only this feature (maybe a user_application?). Or to have the template embedding a session management but it will require some javascript.

Mostly because it is removing unknown tags and offers a limited set of tags. The description of products in shopping carts is nowadays a lot of styling and I want to show the rendered result using the custom css.

Yes - I know. My shopping cart itself using authentication against tryton in the background.

I was reading the code of user_application but there is a point I did not understand: If I use a user_application there is a key which is trusted from Tryton. I have to sign my request with this key to get a trusted connection. So if the external application knows the key, there is no way to check if a ‘trusted user’ instead of a ‘trusted app’ is calling tryton. For example: If I have installed chronos, every person using my computer can encode timesheet in my name. And if the external editor is knowing the key, everybody can call the url. Am I right?

So I decided to use the users session key - if he logs out from tryton, the session is not valid anymore and a other person can find the link in the browser history but it will not work any longer.

So the most secure solution is to have a login at the template, call user.login() with given credentials and store the newly created session key in a server side session. werkzeug has a simple session management to do this. Since I wrote the POC this morning it has to be implemented - the session key was the quick and dirty approach (but possibly not so unsecure if the link isn’t shared and the logged in user closes Tryton if leaving the office :).

Yes but the key should be stored in a “secure” place. But at least, it gives access to only this API, nothing more.

Too much “if’s” to be secure. For me, the main concern is the session as URL argument. You can not rely on the user to close his session.

Probably. It could try to reuse the sao credential stored in localStorage to avoid too much authentication.

If the key is stored in local storage, each subsequent request from the ‘machine’ is trusted . Right?

No, the key is validated on each request.

Yes - this I know. But in general: The machine is validated as trusted until user deletes localStorage (via any way provided) or revokes the key from Tryton. This was my concern why I did not use user_application.

I’m agree that actual richtext widget is not best tool to WYSWYG.
In eSale projects, we active wiki tags to render HTML content in Flask webpages or sync product descriptions to Magento, Prestashop, …

A nice feature in SAO is allow custom define which WYSIWYG you prefer.

For example:

  • In trytond configuration file, a section configure a WYSIWYG to render in “richtext widget”.
  • In SAO client, render your favorite WYSIWYG depend section in trytond configuration file.

In custom SAO client project, we could add new dependencies in *.json about WYSIWYG. For example:

And GTK, continue to default “richtext” from GTK.

As first approach I did the same: Asking to write markdown in the description and render it to html in the frontend. This was not flexible enough to style products in a webshop with a lot of soft informations which can not handled by attributes or dedicated fields on the product

Possibly I can ask to use SAO for the edition of descriptions. Thanks! But I prefer to enable WYSIWYG only in SAO because saving a product with complex html in the gtk client with richtext enabled will ‘clean up’ all the work done.

The contract of Tryton is to have the same behavior between clients. So we can not support more tags in sao than in tryton.

I think it will be good to list what are the minimal missing feature of the richtext to see if it would be doable to implement them.

For me mostly tables and div with class attributes applied (eg. .warning .hint etc) - and the prerendering based on a custom css file.

I was reading source code of richtext widget. It seems a lot of work (and we all know who’s mostly working :slight_smile: ) to implement all that stuff and styling itself is a very individual task. I don’t think it is the job of an ERP to mimic WYSIWYG and all the html-editors are huge projects it self.
For me a embedded browser would be a nice feature. But I did’nt find anything cross plattform and well maintained for gtk. So I decided to open a browser window - which works fine in both SAO and gtk. Beside the editor link I provide a link to the rendered result in the web project and customer is satisfied.

So we should separate two use cases:

  • richtext to format something in generated documents (which should be a set of tags supported by libreoffice)
  • a way to open an external editor and send changes back to tryton (with a (nice to have) preview widget in tryton)

Some CMS allow with addons or extra components to select a custom UI (global configuration or user preferences). For example, select a WYSIWYG.

Why not allow SAO or GTK decide which WYSIWYG render?

At the moment, we not active “RichText widget” because it does not render the desired HTML…

My 2 ct

With complex product descriptions, we add new attributes or new fields (video, images, sections…) in the product.

After, in the template, we control the position to render those fields. The advantage is when you change the template, you could control those fields to render in other place in the template (div).

Impossible and total overload in some cases :slight_smile: . I’m just programming a shop for funsports. There are so much attributes and possible combinations - I don’t want to work all my live to maintain all the crazy variations such products can have. A lot of attributes are mostly story telling. For me as the dev it is enough to know the id of the product the user is adding to the cart - and I only maintain the needed attributes to identify the variant. For this I added the html description to the template - for me it is a marketing and not a functional field.

You can create your own addon for the GTK client and for sao in order to use the customer WYSIWYG widget for both clients.

But the main problem is to have something for the gtk client:

And we should respect the client behavior contract:

Althought I must admit that I like the idea of opening an external editor in a web browser I think that we should focus on improving the clients html widget.

1 Like

Because the richtext widget is not an HTML widget.

1 Like

… and some projects require a HTML widget (websites, HTML reports, etc)

My 2ct.

What about using just the classic Basic authentication? (trytond may need to be modified to set a ‘WWW-Authenticate’ header).

Yes - why not. I read Example here. So the route can have a decorator @auth_required and we can check against trytond it self.

But Basic-Auth has no logout - so in my other projects I prefer a session which can be invalidated without closing the browser.
And setting a session in werkzeug is simple as well. We only need a general route to a login with a reference to the requested route