feat: add promotional image support to notifications and expose thumbnails via API
This commit is contained in:
parent
8737c8a661
commit
e7685c38c8
@ -26,7 +26,10 @@ class AppNotificationController(http.Controller):
|
|||||||
def fetch_notifications(self, **kw):
|
def fetch_notifications(self, **kw):
|
||||||
"""
|
"""
|
||||||
Endpoint for the Flutter app Background Task and In-App notification center.
|
Endpoint for the Flutter app Background Task and In-App notification center.
|
||||||
|
Returns image_128 (base64 thumbnail) for list display.
|
||||||
|
The Flutter detail screen loads the full image via /web/image/ with session cookie.
|
||||||
"""
|
"""
|
||||||
|
import base64 as b64mod
|
||||||
user = request.env.user
|
user = request.env.user
|
||||||
partner = user.partner_id
|
partner = user.partner_id
|
||||||
|
|
||||||
@ -42,11 +45,20 @@ class AppNotificationController(http.Controller):
|
|||||||
|
|
||||||
notifications = request.env['mapan.app.notification'].sudo().search_read(
|
notifications = request.env['mapan.app.notification'].sudo().search_read(
|
||||||
domain,
|
domain,
|
||||||
['id', 'title', 'body', 'create_date'],
|
['id', 'title', 'body', 'create_date', 'image_128'],
|
||||||
order='create_date desc',
|
order='create_date desc',
|
||||||
limit=50
|
limit=50
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Normalize image_128 bytes → base64 string for JSON transport
|
||||||
|
for notif in notifications:
|
||||||
|
img = notif.get('image_128')
|
||||||
|
if img and isinstance(img, bytes):
|
||||||
|
notif['image_128'] = b64mod.b64encode(img).decode('utf-8')
|
||||||
|
elif not img:
|
||||||
|
notif['image_128'] = None
|
||||||
|
notif['has_image'] = bool(notif['image_128'])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'data': notifications
|
'data': notifications
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from odoo import models, fields
|
from odoo import models, fields, api
|
||||||
|
|
||||||
class AppNotification(models.Model):
|
class AppNotification(models.Model):
|
||||||
_name = 'mapan.app.notification'
|
_name = 'mapan.app.notification'
|
||||||
@ -8,6 +8,22 @@ class AppNotification(models.Model):
|
|||||||
title = fields.Char(string='Notification Title', required=True)
|
title = fields.Char(string='Notification Title', required=True)
|
||||||
body = fields.Text(string='Notification Body', required=True)
|
body = fields.Text(string='Notification Body', required=True)
|
||||||
|
|
||||||
|
# Optional promotional image — Odoo auto-generates image_128 thumbnail
|
||||||
|
image = fields.Image(
|
||||||
|
string='Notification Image',
|
||||||
|
max_width=1920,
|
||||||
|
max_height=1920,
|
||||||
|
help='Optional image shown in the notification detail screen.'
|
||||||
|
)
|
||||||
|
image_128 = fields.Image(
|
||||||
|
string='Thumbnail',
|
||||||
|
related='image',
|
||||||
|
max_width=128,
|
||||||
|
max_height=128,
|
||||||
|
store=True,
|
||||||
|
readonly=True,
|
||||||
|
)
|
||||||
|
|
||||||
# If no partner_ids are selected, it is broadcast to everyone logically
|
# If no partner_ids are selected, it is broadcast to everyone logically
|
||||||
partner_ids = fields.Many2many(
|
partner_ids = fields.Many2many(
|
||||||
'res.partner',
|
'res.partner',
|
||||||
@ -21,6 +37,7 @@ class AppNotification(models.Model):
|
|||||||
store=True
|
store=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@api.depends('partner_ids')
|
||||||
def _compute_is_global(self):
|
def _compute_is_global(self):
|
||||||
for rec in self:
|
for rec in self:
|
||||||
rec.is_global = not bool(rec.partner_ids)
|
rec.is_global = not bool(rec.partner_ids)
|
||||||
|
|||||||
@ -7,6 +7,12 @@ class PushNotificationWizard(models.TransientModel):
|
|||||||
|
|
||||||
title = fields.Char(string='Notification Title', required=True)
|
title = fields.Char(string='Notification Title', required=True)
|
||||||
body = fields.Text(string='Notification Body', required=True)
|
body = fields.Text(string='Notification Body', required=True)
|
||||||
|
image = fields.Image(
|
||||||
|
string='Notification Image (optional)',
|
||||||
|
max_width=1920,
|
||||||
|
max_height=1920,
|
||||||
|
help='Upload a promotional image to display in the notification detail.'
|
||||||
|
)
|
||||||
recipient_type = fields.Selection([
|
recipient_type = fields.Selection([
|
||||||
('all', 'All Activated Members'),
|
('all', 'All Activated Members'),
|
||||||
('specific', 'Specific Members')
|
('specific', 'Specific Members')
|
||||||
@ -26,6 +32,7 @@ class PushNotificationWizard(models.TransientModel):
|
|||||||
self.env['mapan.app.notification'].create({
|
self.env['mapan.app.notification'].create({
|
||||||
'title': self.title,
|
'title': self.title,
|
||||||
'body': self.body,
|
'body': self.body,
|
||||||
|
'image': self.image,
|
||||||
})
|
})
|
||||||
target_msg = 'all activated app members'
|
target_msg = 'all activated app members'
|
||||||
else:
|
else:
|
||||||
@ -33,6 +40,7 @@ class PushNotificationWizard(models.TransientModel):
|
|||||||
self.env['mapan.app.notification'].create({
|
self.env['mapan.app.notification'].create({
|
||||||
'title': self.title,
|
'title': self.title,
|
||||||
'body': self.body,
|
'body': self.body,
|
||||||
|
'image': self.image,
|
||||||
'partner_ids': [(6, 0, self.partner_ids.ids)],
|
'partner_ids': [(6, 0, self.partner_ids.ids)],
|
||||||
})
|
})
|
||||||
target_msg = f'{len(self.partner_ids)} selected member(s)'
|
target_msg = f'{len(self.partner_ids)} selected member(s)'
|
||||||
|
|||||||
@ -8,6 +8,8 @@
|
|||||||
<group>
|
<group>
|
||||||
<field name="title"/>
|
<field name="title"/>
|
||||||
<field name="body"/>
|
<field name="body"/>
|
||||||
|
<field name="image" widget="image" options="{'size': [0, 200]}"
|
||||||
|
help="Optional promotional image (JPG/PNG). Displayed in the notification detail screen."/>
|
||||||
<field name="recipient_type" widget="radio" options="{'horizontal': true}"/>
|
<field name="recipient_type" widget="radio" options="{'horizontal': true}"/>
|
||||||
</group>
|
</group>
|
||||||
<group string="Recipients" invisible="recipient_type != 'specific'">
|
<group string="Recipients" invisible="recipient_type != 'specific'">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user