feat: add blog.post inverse relationship and simplify email template
This commit is contained in:
parent
fb89605191
commit
f160f1c476
3 changed files with 54 additions and 88 deletions
|
|
@ -5,111 +5,54 @@
|
||||||
<record id="email_template_blog_published" model="mail.template">
|
<record id="email_template_blog_published" model="mail.template">
|
||||||
<field name="name">Blog Publisher — Post Published Notification</field>
|
<field name="name">Blog Publisher — Post Published Notification</field>
|
||||||
<field name="model_id" ref="model_itsulu_blog_generation_log"/>
|
<field name="model_id" ref="model_itsulu_blog_generation_log"/>
|
||||||
<field name="subject">[${object.blog_post_id.blog_id.name or 'ITSulu Insights'}] Blog Post Published: ${object.blog_post_id.name or 'New Post'} - ${format_date(object.create_date, date_format='MMMM dd, yyyy')}</field>
|
<field name="subject">Blog Post Published: ${object.blog_post_id.name or 'New Post'}</field>
|
||||||
<field name="email_from">${user.email_formatted}</field>
|
<field name="email_from">${user.email_formatted}</field>
|
||||||
<field name="auto_delete">True</field>
|
<field name="auto_delete">True</field>
|
||||||
<field name="body_html"><![CDATA[
|
<field name="body_html"><![CDATA[
|
||||||
<div dir="ltr" style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 700px;">
|
<div style="font-family: Arial, sans-serif; line-height: 1.6;">
|
||||||
|
|
||||||
<h2 style="color: #0066cc;">Today's ${object.blog_post_id.blog_id.name or 'ITSulu Insights'} Blog Post Published</h2>
|
<h2>Blog Post Published</h2>
|
||||||
|
|
||||||
<p><strong>Date:</strong> ${format_date(object.create_date, date_format='MMMM dd, yyyy (EEEE)')}</p>
|
<p><strong>Title:</strong> ${object.blog_post_id.name or 'N/A'}</p>
|
||||||
<p><strong>Title:</strong> ${object.blog_post_id.name or ''}</p>
|
<p><strong>Blog:</strong> ${object.blog_post_id.blog_id.name or 'N/A'}</p>
|
||||||
% set post_url = object.blog_post_id.website_url and ('https://itsulu.com' + object.blog_post_id.website_url) or ''
|
|
||||||
<p><strong>URL:</strong> <a href="${post_url}" target="_blank">${post_url}</a></p>
|
|
||||||
|
|
||||||
<h3 style="margin-top: 30px; color: #0066cc;">Post Details</h3>
|
<h3>Social Media Posts — Ready to Post</h3>
|
||||||
<ul>
|
|
||||||
<li><strong>LLM Provider:</strong> ${object.llm_provider or ''} / ${object.llm_model or ''}</li>
|
|
||||||
<li><strong>Tokens Used:</strong> ${object.tokens_used or 0}</li>
|
|
||||||
<li><strong>Generation Time:</strong> ${'{:.1f}'.format(object.duration_seconds or 0)}s</li>
|
|
||||||
<li><strong>Tags:</strong>
|
|
||||||
% for tag in object.blog_post_id.tag_ids:
|
|
||||||
${tag.name}${' | ' if not loop.last else ''}
|
|
||||||
% endfor
|
|
||||||
</li>
|
|
||||||
<li><strong>Publication Status:</strong> ${'Published' if object.blog_post_id.is_published else 'Draft'}</li>
|
|
||||||
<li><strong>Blog:</strong> ${object.blog_post_id.blog_id.name or ''}</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
% set social = object.blog_post_id.itsulu_social_id
|
% for social in object.blog_post_id.itsulu_social_id:
|
||||||
% if social
|
|
||||||
|
|
||||||
<h3 style="margin-top: 30px; color: #0066cc;">Social Media Posts — Ready to Post</h3>
|
% if social.twitter_post_a or social.twitter_post_b:
|
||||||
|
<h4>Twitter</h4>
|
||||||
<hr style="margin: 20px 0; border: none; border-top: 2px solid #ddd;"/>
|
% if social.twitter_post_a:
|
||||||
|
<p><strong>Post A:</strong> ${social.twitter_post_a}</p>
|
||||||
% if social.twitter_enabled and (social.twitter_post_a or social.twitter_post_b)
|
% endif
|
||||||
<h4>🐦 X (Twitter) Post A:</h4>
|
% if social.twitter_post_b:
|
||||||
<p style="background-color: #f5f5f5; padding: 15px; border-left: 4px solid #1da1f2; font-size: 14px;">
|
<p><strong>Post B:</strong> ${social.twitter_post_b}</p>
|
||||||
${social.twitter_post_a or ''}
|
% endif
|
||||||
</p>
|
|
||||||
|
|
||||||
<h4>🐦 X (Twitter) Post B:</h4>
|
|
||||||
<p style="background-color: #f5f5f5; padding: 15px; border-left: 4px solid #1da1f2; font-size: 14px;">
|
|
||||||
${social.twitter_post_b or ''}
|
|
||||||
</p>
|
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
<hr style="margin: 20px 0; border: none; border-top: 2px solid #ddd;"/>
|
% if social.bluesky_post_a or social.bluesky_post_b:
|
||||||
|
<h4>BlueSky</h4>
|
||||||
% if social.bluesky_enabled and (social.bluesky_post_a or social.bluesky_post_b)
|
% if social.bluesky_post_a:
|
||||||
<h4>🌐 BlueSky Posts:</h4>
|
<p><strong>Post A:</strong> ${social.bluesky_post_a}</p>
|
||||||
<p style="background-color: #f5f5f5; padding: 15px; border-left: 4px solid #1185fe; font-size: 14px;">
|
% endif
|
||||||
<strong>BlueSky A:</strong><br/>
|
% if social.bluesky_post_b:
|
||||||
${social.bluesky_post_a or ''}
|
<p><strong>Post B:</strong> ${social.bluesky_post_b}</p>
|
||||||
</p>
|
% endif
|
||||||
<p style="background-color: #f5f5f5; padding: 15px; border-left: 4px solid #1185fe; font-size: 14px;">
|
|
||||||
<strong>BlueSky B:</strong><br/>
|
|
||||||
${social.bluesky_post_b or ''}
|
|
||||||
</p>
|
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
<hr style="margin: 20px 0; border: none; border-top: 2px solid #ddd;"/>
|
% if social.mastodon_post:
|
||||||
|
<h4>Mastodon</h4>
|
||||||
% if social.mastodon_enabled and social.mastodon_post
|
<p>${social.mastodon_post}</p>
|
||||||
<h4>🦣 Fediverse/Mastodon Post:</h4>
|
|
||||||
<p style="background-color: #f5f5f5; padding: 15px; border-left: 4px solid #563acc; font-size: 14px;">
|
|
||||||
${social.mastodon_post or ''}
|
|
||||||
</p>
|
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
<hr style="margin: 20px 0; border: none; border-top: 2px solid #ddd;"/>
|
% if social.linkedin_post:
|
||||||
|
<h4>LinkedIn</h4>
|
||||||
% if social.linkedin_enabled and social.linkedin_post
|
<p>${social.linkedin_post}</p>
|
||||||
<h4>💼 LinkedIn Post:</h4>
|
|
||||||
<p style="background-color: #f5f5f5; padding: 15px; border-left: 4px solid #0a66c2; font-size: 14px;">
|
|
||||||
${social.linkedin_post or ''}
|
|
||||||
</p>
|
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
% if social.sources_referenced
|
<p><strong>URL:</strong> https://itsulu.com${object.blog_post_id.website_url or ''}</p>
|
||||||
<hr style="margin: 30px 0; border: none; border-top: 2px solid #ddd;"/>
|
|
||||||
<h3 style="color: #0066cc;">News Sources Referenced:</h3>
|
|
||||||
<ul>
|
|
||||||
% for line in (social.sources_referenced or '').splitlines():
|
|
||||||
% if line.strip()
|
|
||||||
% set parts = line.split(' — ', 1)
|
|
||||||
% if parts|length == 2
|
|
||||||
<li><a href="${parts[1].strip()}" target="_blank">${parts[0].strip()}</a></li>
|
|
||||||
% else
|
|
||||||
<li>${line.strip()}</li>
|
|
||||||
% endif
|
|
||||||
% endif
|
|
||||||
% endfor
|
|
||||||
</ul>
|
|
||||||
% endif
|
|
||||||
|
|
||||||
% endif <!-- end social block -->
|
% endfor
|
||||||
|
|
||||||
<hr style="margin: 30px 0; border: none; border-top: 2px solid #ddd;"/>
|
|
||||||
|
|
||||||
<p style="margin-top: 40px; font-size: 12px; color: #999;">
|
|
||||||
<strong>Generated:</strong> ${format_date(object.create_date, date_format='MMMM dd, yyyy')} |
|
|
||||||
<strong>Service:</strong> ITSulu Blog Publisher<br/>
|
|
||||||
This email contains all social media post variations ready for posting
|
|
||||||
across X, BlueSky, Fediverse, and LinkedIn.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
]]></field>
|
]]></field>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
"""
|
"""
|
||||||
itsulu_blog_publisher models.
|
itsulu_blog_publisher models.
|
||||||
"""
|
"""
|
||||||
|
from . import blog_post
|
||||||
from . import blog_topic
|
from . import blog_topic
|
||||||
from . import blog_schedule
|
from . import blog_schedule
|
||||||
from . import blog_generation_log
|
from . import blog_generation_log
|
||||||
|
|
@ -9,6 +10,7 @@ from . import blog_post_social
|
||||||
from . import res_config_settings
|
from . import res_config_settings
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
'blog_post',
|
||||||
'blog_topic',
|
'blog_topic',
|
||||||
'blog_schedule',
|
'blog_schedule',
|
||||||
'blog_generation_log',
|
'blog_generation_log',
|
||||||
|
|
|
||||||
21
addons/itsulu_blog_publisher/models/blog_post.py
Normal file
21
addons/itsulu_blog_publisher/models/blog_post.py
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Extend blog.post to add reverse relationship to itsulu.blog.post.social.
|
||||||
|
"""
|
||||||
|
from odoo import fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class BlogPost(models.Model):
|
||||||
|
_inherit = 'blog.post'
|
||||||
|
|
||||||
|
itsulu_social_id = fields.One2many(
|
||||||
|
comodel_name='itsulu.blog.post.social',
|
||||||
|
inverse_name='blog_post_id',
|
||||||
|
string='Social Media Copy',
|
||||||
|
help='Social media copy generated for this post.',
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_social_copy(self):
|
||||||
|
"""Return the single social copy record, or False if none exists."""
|
||||||
|
self.ensure_one()
|
||||||
|
return self.itsulu_social_id[0] if self.itsulu_social_id else False
|
||||||
Loading…
Reference in a new issue