Skip to content

[FIX] portal_backend: let the chatter load followers and attachments - #449

Closed
lef-adhoc wants to merge 1 commit into
ingadhoc:18.0from
adhoc-dev:18.0-h-128749-lef
Closed

lef-adhoc wants to merge 1 commit into
ingadhoc:18.0from
adhoc-dev:18.0-h-128749-lef

Conversation

@lef-adhoc

@lef-adhoc lef-adhoc commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Ticket: https://www.adhoc.inc/odoo/helpdesk.ticket/128749

Qué duele

Un usuario portal backend abre un registro con chatter (una venta, por ejemplo) y los íconos de Seguidores y Adjuntos quedan en "Cargando..." para siempre.

El controlador del core /mail/thread/data vacía el request_list cuando el usuario no es interno, así que la respuesta no trae followersCount ni attachments. El chatter muestra el spinner justamente mientras followersCount === undefined y los adjuntos no cargaron, así que nunca deja de girar. El corte pasa antes de mirar permisos: no es un problema de ACL.

Qué cambia

  • Se pisa /mail/thread/data para setear portal_bypass cuando el usuario es portal backend. Es el mismo contexto que el módulo ya usa para que _is_internal() devuelva True (ver models/res_users.py y models/ir_attachment.py), así que no se introduce un mecanismo nuevo. El core sigue chequeando acceso de lectura sobre el registro antes de contestar.
  • Se borra el override de _get_mail_thread_data: ese método no existe más en Odoo 18, donde lo reemplazó _thread_to_store. Era código muerto que quedó de la migración. Sacaba followers para esquivar un error cuando un usuario interno seguía el registro; ese error ya no aparece, verificado en pantalla abriendo el desplegable con un interno en la lista.

Sin tests: en 18 no los queremos en este módulo.

Cómo se probó

Base 18 local con sale + portal_backend, sobre una venta con un seguidor interno y un adjunto.

En la pantalla (navegador, sesión real del usuario portal backend, mismo registro antes y después, cambiando solo el código):

antes después
spinners girando en el topbar 2 0
contador de seguidores vacío 3
contador de adjuntos vacío 1
botón de seguir Follow Following

Abriendo el desplegable de seguidores se ven los tres, incluido el usuario interno, sin errores en consola.

En el request /mail/thread/data:

usuario registro antes después
portal backend venta que puede leer sin followersCount ni attachments followersCount=4, 1 adjunto
interno la misma venta datos completos datos completos (sin cambios)
portal backend venta de otro partner sin datos (hasReadAccess=False) sin datos (hasReadAccess=False)
portal común venta que puede leer sin datos sin datos

Las dos últimas filas son las que importan del lado de la seguridad: el cambio no alcanza a un registro que el usuario no puede leer, ni a un portal común.

Fuera de alcance

El ticket también pregunta si el portal backend tiene que poder agregar seguidores. No entra acá porque son permisos nuevos, no un bug: hoy falla por dos motivos distintos, y el segundo es una decisión de producto.

mail.wizard.invite create: AccessError: You are not allowed to create 'Invite wizard' (mail.wizard.invite) records.
message_subscribe: AccessError: You are not allowed to modify 'Sales Order' (sale.order) records.

O sea: además de la ACL del wizard, message_subscribe pide permiso de escritura sobre el registro. Darle write sobre las ventas a un portal backend es bastante más que destrabar un contador.

Queda abierto también qué datos de los seguidores internos puede ver un portal backend. Hoy, con el request destrabado, recibe lo mismo que cualquier usuario que pasa ese gate: nombre, avatar y email del seguidor. El core oculta el email a los no internos en res.partner._to_store, pero lo publica igual en mail.followers._to_store, que no tiene ese gate. Filtrar solo una de las dos vías daba una falsa sensación de control, así que no se filtró nada: si hay que limitar campos, es una decisión de producto y va en un cambio aparte.

Nota aparte, para quien revise

Con portal_backend solo, un usuario portal backend no llega a abrir el form de una venta: el web_read corta con AccessError en modelos auxiliares de la vista (sale.order.option, product.pricelist, product.attribute.custom.value, …), antes de cualquier tema de chatter. Para poder mirar el chatter en pantalla hubo que darle lectura sobre esos modelos en la base de prueba. Es ruido ambiental para este PR —no toca el gate de _is_internal, que es donde está el bug— pero sugiere que donde se reportó el problema hay algo más que ya le da esos accesos.

bump

@roboadhoc

Copy link
Copy Markdown
Contributor

Pull request status dashboard

The core /mail/thread/data controller empties request_list when the user is
not internal, so the response carries neither followersCount nor attachments.
The chatter keeps its spinner while followersCount is undefined and the
attachments are not loaded, so both counters spin forever for a portal backend
user. The cut happens before any permission check, so it is not an ACL issue.

Override the controller to set portal_bypass for portal backend users, which
is the context this module already uses to make _is_internal return True. Core
still checks read access on the record before answering, so a portal backend
user without access to the record gets nothing, and plain portal users are
unaffected.

Also drop the _get_mail_thread_data override: that method no longer exists in
Odoo 18, where _thread_to_store replaced it. It was dead code left over from
the migration, and it used to strip "followers" to dodge an error on records
followed by an internal user. That error does not show up anymore.
@gal-adhoc

Copy link
Copy Markdown
Contributor

@roboadhoc r+ bump

roboadhoc pushed a commit that referenced this pull request Sep 25, 2026
The core /mail/thread/data controller empties request_list when the user is
not internal, so the response carries neither followersCount nor attachments.
The chatter keeps its spinner while followersCount is undefined and the
attachments are not loaded, so both counters spin forever for a portal backend
user. The cut happens before any permission check, so it is not an ACL issue.

Override the controller to set portal_bypass for portal backend users, which
is the context this module already uses to make _is_internal return True. Core
still checks read access on the record before answering, so a portal backend
user without access to the record gets nothing, and plain portal users are
unaffected.

Also drop the _get_mail_thread_data override: that method no longer exists in
Odoo 18, where _thread_to_store replaced it. It was dead code left over from
the migration, and it used to strip "followers" to dodge an error on records
followed by an internal user. That error does not show up anymore.

closes #449

Signed-off-by: Guido Galetto <gal@adhoc.inc>
roboadhoc added a commit that referenced this pull request Sep 25, 2026
@roboadhoc roboadhoc closed this Sep 25, 2026
@roboadhoc
roboadhoc deleted the 18.0-h-128749-lef branch September 25, 2026 11:34

This branch was previously deployed

1 inactive deployment
merge — ab8ad5ab Deployed Sep 25, 2026 by roboadhoc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants