Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Huey async #186

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,4 @@ docs/Makefile
/docs/_build
/venv311
/.python-version
/huey.log
10 changes: 10 additions & 0 deletions base.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ parts =
i18ndude
omelette
robot
huey
plone-helper-scripts


develop = .
src/collective.taskqueue2


[instance]
Expand All @@ -26,10 +28,13 @@ user = admin:admin
http-address = 8080
environment-vars =
zope_i18n_compile_mo_files true
HUEY_CONSUMER True
HUEY_LOG_LEVEL WARNING
eggs =
Plone
Pillow
pdbpp
huey
Products.EasyNewsletter [test]

[vscode]
Expand Down Expand Up @@ -90,6 +95,10 @@ eggs = zest.releaser
recipe = zc.recipe.egg
eggs = i18ndude

[huey]
recipe = zc.recipe.egg
eggs = huey


[plone-helper-scripts]
recipe = zc.recipe.egg
Expand All @@ -99,6 +108,7 @@ eggs =
interpreter = zopepy
scripts =
zopepy
huey_consumer
plone-compile-resources


Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ ignore =
C813,
C101,
E203
F401
# E203, E266
exclude = bootstrap.py,docs,*.egg.,omelette
max-line-length = 88
Expand Down
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
"html2text",
"email-validator>=1.1.2",
"six",
"collective.taskqueue2",
# "huey",
# "gevent",
],
extras_require=dict(
test=[
Expand Down
2 changes: 2 additions & 0 deletions src/Products/EasyNewsletter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
# avoid circular import
# from Products.EasyNewsletter import config # noqa
from zope.i18nmessageid import MessageFactory
import logging

log = logging.getLogger("Products.EasyNewsletter")

EasyNewsletterMessageFactory = MessageFactory("Products.EasyNewsletter")
_ = EasyNewsletterMessageFactory
1 change: 1 addition & 0 deletions src/Products/EasyNewsletter/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

<include package=".browser" />
<include package=".content" />
<include package=".global_utilities" />
<include package=".portlets" />
<include package=".queue" />
<include package=".utils" />
Expand Down
3 changes: 2 additions & 1 deletion src/Products/EasyNewsletter/content/newsletter_issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ class NewsletterIssue(Container):
context_property("content_aggregation_sources")

def get_newsletter(self):
return self.__parent__
return self.aq_inner.aq_parent
# return self.__parent__

# bbb to support ATCT way, needs to be removed in v5.x:
getNewsletter = get_newsletter
Expand Down
4 changes: 3 additions & 1 deletion src/Products/EasyNewsletter/issuedatafetcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ def _render_output_html(self, preview=False):
with header+body+footer (raw html).
"""
output_tmpl_id = self.issue.output_template
issue_tmpl = self.issue.restrictedTraverse(str(output_tmpl_id))
issue_tmpl = self.issue.restrictedTraverse(str(output_tmpl_id), None)
if not issue_tmpl:
import pdb; pdb.set_trace() # NOQA: E702
output_html = issue_tmpl.render()
return output_html

Expand Down
5 changes: 4 additions & 1 deletion src/Products/EasyNewsletter/queue/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
/>
<include
package=".taskqueue"
zcml:condition="installed collective.taskqueue"
zcml:condition="installed collective.taskqueue2"
/>
<!-- <include
package=".huey"
/> -->
</configure>
1 change: 1 addition & 0 deletions src/Products/EasyNewsletter/queue/huey/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# -*- coding: utf-8 -*-
14 changes: 14 additions & 0 deletions src/Products/EasyNewsletter/queue/huey/configure.zcml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<configure
i18n_domain="Products.EasyNewsletter"
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:zcml="http://namespaces.zope.org/zcml">
<utility factory=".handler.IssueQueue" />
<browser:page
class=".view.ProcessQueue"
for="Products.EasyNewsletter.content.newsletter_issue.INewsletterIssue"
layer="Products.EasyNewsletter.interfaces.IProductsEasyNewsletterLayer"
name="enl_taskqueue_sendout"
permission="cmf.ReviewPortalContent"
/>
</configure>
11 changes: 11 additions & 0 deletions src/Products/EasyNewsletter/queue/huey/handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from zope.interface import implementer
from Products.EasyNewsletter.queue.interfaces import IIssueQueue
from .huey_tasks import send_newsletters


@implementer(IIssueQueue)
class IssueQueue(object):
def start(self, context):
"""Queues issue for sendout through huey-mini task queue"""
task_res = send_newsletters(context.UID())
return task_res
25 changes: 25 additions & 0 deletions src/Products/EasyNewsletter/queue/huey/huey_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import tempfile

from huey import SqliteHuey
from plone import api
from Products.EasyNewsletter import log

QUEUE_NAME = "Products.EasyNewsletter.queue"
# VIEW_NAME = "enl_taskqueue_sendout"

huey_db_name = tempfile.NamedTemporaryFile(suffix=".db", delete=False).name
huey = SqliteHuey(filename=huey_db_name)
log.info(f"Huey SQLite DB: {huey_db_name}")


@huey.task()
def send_newsletters(uid):
""" resolve the context object by given uid and triggers
generation and sending of the newsletter issue.
"""
# from zope.component import getGlobalSiteManager
# gsm = getGlobalSiteManager()
# import pdb; pdb.set_trace() # NOQA: E702
context = api.content.get(UID=uid)
send_view = api.content.get_view(name="send-issue", context=context)
send_view.send()
16 changes: 16 additions & 0 deletions src/Products/EasyNewsletter/queue/huey/view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
from plone import api
from plone.protect.interfaces import IDisableCSRFProtection
from Products.Five.browser import BrowserView
from zope.interface import alsoProvides

from Products.EasyNewsletter import log


class ProcessQueue(BrowserView):
def __call__(self):
alsoProvides(self.request, IDisableCSRFProtection)
log.info("generating and sending newsletter issue emails")
send_view = api.content.get_view(name="send-issue", context=self.context)
send_view.send()
log.info("sending done ;)")
6 changes: 3 additions & 3 deletions src/Products/EasyNewsletter/queue/taskqueue/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
<utility factory=".handler.TCIssueQueue" />
<browser:page
class=".view.ProcessQueue"
for="Products.EasyNewsletter.interfaces.IENLIssue"
layer="collective.taskqueue.interfaces.ITaskQueueLayer"
for="Products.EasyNewsletter.content.newsletter_issue.INewsletterIssue"
name="enl_taskqueue_sendout"
permission="cmf.ReviewPortalContent"
permission="cmf.ModifyPortalContent"
/>
<!-- layer="Products.EasyNewsletter.interfaces.IProductsEasyNewsletterLayer" -->
</configure>
26 changes: 21 additions & 5 deletions src/Products/EasyNewsletter/queue/taskqueue/handler.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
# -*- coding: utf-8 -*-
from collective.taskqueue import taskqueue
from plone import api
from collective.taskqueue2.huey_tasks import schedule_browser_view
from Products.EasyNewsletter.queue.interfaces import IIssueQueue
from zope.interface import implementer


QUEUE_NAME = "Products.EasyNewsletter.queue"
VIEW_NAME = "enl_taskqueue_sendout"
ENL_VIEW_NAME = "enl_taskqueue_sendout"


@implementer(IIssueQueue)
class TCIssueQueue(object):
def start(self, context):
"""Queues issue for sendout through collective.taskqueue"""
jobid = taskqueue.add(
"/".join(context.getPhysicalPath() + (VIEW_NAME,)), queue=QUEUE_NAME
# import pdb; pdb.set_trace() # NOQA: E702
result = schedule_browser_view(
view_name=ENL_VIEW_NAME,
context_path="/".join(context.getPhysicalPath()),
site_path="/".join(api.portal.get().getPhysicalPath()),
username=api.user.get_current().getId(),
params=dict(
base=context.REQUEST.base,
layers=context.REQUEST.__provides__,
cookies=context.REQUEST.cookies,
form=dict(),
_plonebrowserlayer_=context.REQUEST._plonebrowserlayer_,
_plonetheme_=context.REQUEST._plonetheme_,
),
)
return jobid
# jobid = taskqueue.add(
# "/".join(context.getPhysicalPath() + (VIEW_NAME,)), queue=QUEUE_NAME
# )
return result
10 changes: 9 additions & 1 deletion src/Products/EasyNewsletter/queue/taskqueue/view.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
# -*- coding: utf-8 -*-
from plone import api
from plone.protect.interfaces import IDisableCSRFProtection
from Products.Five.browser import BrowserView
from zope.interface import alsoProvides

from Products.EasyNewsletter import log


class ProcessQueue(BrowserView):
def __call__(self):
alsoProvides(self.request, IDisableCSRFProtection)
self.context.send()
log.info("start sending:\n")
import pdb; pdb.set_trace() # NOQA: E702`c`
# send_view = api.content.get_view(name="send-issue", context=self.context)
send_view = self.context.restrictedTraverse("send-issue")
send_view.send()
log.info("sending done ;)\n")
3 changes: 2 additions & 1 deletion src/Products/EasyNewsletter/views/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
name="send-issue"
for="Products.EasyNewsletter.content.newsletter_issue.INewsletterIssue"
class=".newsletter_issue_send.NewsletterIssueSend"
permission="cmf.ModifyPortalContent"
permission="zope2.View"
/>
<!-- permission="cmf.ModifyPortalContent" -->

<browser:page
name="send-issue-form"
Expand Down
81 changes: 53 additions & 28 deletions src/Products/EasyNewsletter/views/newsletter_issue_send.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
# -*- coding: utf-8 -*-

import logging
import re
from datetime import datetime

import emails
import emails.loader
import transaction
from plone import api
from plone.namedfile.scaling import ImageScale
from plone.namedfile.scaling import ImageScaling
from plone.namedfile.scaling import ImageScale, ImageScaling
from plone.protect import PostOnly
from Products.Five.browser import BrowserView
from Products.MailHost.interfaces import IMailHost
from zope.component import getMultiAdapter, getUtility, queryUtility, subscribers
from zope.component.hooks import getSite
from zope.interface import alsoProvides
from plone.protect.interfaces import IDisableCSRFProtection

from Products.EasyNewsletter import EasyNewsletterMessageFactory as _
from Products.EasyNewsletter.behaviors.plone_user_group_recipients import (
IPloneUserGroupRecipients,
)
from Products.EasyNewsletter.content.newsletter_issue import ISendStatus
from Products.EasyNewsletter.interfaces import IIssueDataFetcher
from Products.EasyNewsletter.interfaces import IReceiversPostSendingFilter
from Products.Five.browser import BrowserView
from Products.MailHost.interfaces import IMailHost
from zope.component import getMultiAdapter
from zope.component import getUtility
from zope.component import subscribers
from zope.component.hooks import getSite

import emails
import emails.loader
import logging
import re
import transaction

from Products.EasyNewsletter.interfaces import (
IIssueDataFetcher,
IReceiversPostSendingFilter,
)
from Products.EasyNewsletter.queue.interfaces import IIssueQueue

log = logging.getLogger("Products.EasyNewsletter")

Expand Down Expand Up @@ -63,7 +65,8 @@ class Message(


class LocalLoader(object):
""" """
""" local emails loader for transform Plone image url's
"""

def __getitem__(self, uri):
image_file = None
Expand Down Expand Up @@ -129,25 +132,46 @@ def __call__(self):
)
return self.request.response.redirect(self.context.absolute_url())

# XXX implement this:
# if self.context.issue_queue is not None:
# self._send_issue_prepare()
# self.context.queue_issue_for_sendout()
# api.portal.show_message(
# message=_("The issue sending has been initiated in the background."),
# request=self.request,
# )
# return self.request.response.redirect(self.context.absolute_url())
if self.issue_queue is not None:
self._send_issue_prepare()
self.queue_issue_for_sendout()
api.portal.show_message(
message=_("The issue sending has been initiated in the background."),
request=self.request,
)
return self.request.response.redirect(self.context.absolute_url())

# No queuing but direct send
# self._send_issue_prepare()
self.send_issue_immediately()
api.portal.show_message(
message=_("The issue has been generated and sent to the mail server."),
request=self.request,
)
return self.request.response.redirect(self.context.absolute_url())

@property
def issue_queue(self):
return queryUtility(IIssueQueue)

def queue_issue_for_sendout(self):
"""queues this issue for sendout using async queue
"""
queue = self.issue_queue
if queue is None:
raise NotImplementedError(
'One need to install and configure a queue in '
'order to use the feature of a queued sendout.'
)

# check for workflow
current_state = api.content.get_state(obj=self.context)
if current_state != 'sending':
raise ValueError(
'Executed queue issue for sendout in wrong review state!'
)
res = queue.start(self.context)
log.info(f"queue runner results: {res}")

def _send_issue_prepare(self):
self.request["enlwf_guard"] = True
api.content.transition(obj=self.context, transition="send")
Expand All @@ -162,6 +186,7 @@ def send_issue_immediately(self):
never call this from UI - needs a way to protect
currently manager only
"""
alsoProvides(self.request, IDisableCSRFProtection)
self._send_issue_prepare()
self.send()

Expand Down
Loading
Loading