# HG changeset patch # User bsw # Date 1459881637 -7200 # Node ID c0fd12b97d656daa652c72c8d248f1ee2a078771 # Parent 9578cef4018a05f7c6e14ae4c5993f250819049b Changes on notifications system, newsletter support added diff -r 9578cef4018a -r c0fd12b97d65 app/main/_prefork/10_init.lua --- a/app/main/_prefork/10_init.lua Wed Jan 27 11:16:26 2016 +0100 +++ b/app/main/_prefork/10_init.lua Tue Apr 05 20:40:37 2016 +0200 @@ -134,8 +134,20 @@ proto = "interval", name = "send_pending_notifications", delay = 5, - handler = function() - Event:send_pending_notifications() + handler = function() + while true do + local did_work = false + local tmp + tmp = Newsletter:send_next_newsletter() + if tmp then did_work = true end + tmp = Event:send_next_notification() + if tmp then did_work = true end + tmp = InitiativeForNotification:notify_next_member() + if tmp then did_work = true end + if not did_work then + break + end + end end }, min_fork = 1, diff -r 9578cef4018a -r c0fd12b97d65 app/main/admin/_action/newsletter_update.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/main/admin/_action/newsletter_update.lua Tue Apr 05 20:40:37 2016 +0200 @@ -0,0 +1,29 @@ +local id = param.get_id() + +local newsletter + +if id then + newsletter = Newsletter:by_id(id) + if newsletter.sent then + slot.select("error", function() + ui.tag{ content = _"Newsletter has already been sent out" } + end) + return false + end +else + newsletter = Newsletter:new() +end + +newsletter.published = param.get("published") +if newsletter.published == nil or newsletter.published == "" then + newsletter.published = "now" +end +newsletter.unit_id = param.get("unit_id", atom.integer) +if newsletter.unit_id == 0 then + newsletter.unit_id = nil +end +newsletter.include_all_members = param.get("include_all_members", atom.boolean) +newsletter.subject = param.get("subject") +newsletter.content = param.get("content") + +newsletter:save() diff -r 9578cef4018a -r c0fd12b97d65 app/main/admin/index.lua --- a/app/main/admin/index.lua Wed Jan 27 11:16:26 2016 +0100 +++ b/app/main/admin/index.lua Tue Apr 05 20:40:37 2016 +0200 @@ -38,6 +38,27 @@ ui.sidebar( "tab-whatcanido", function() ui.sidebarHead( function() + ui.heading { level = 2, content = _"Newsletter" } + end ) + + ui.sidebarSection( "moreLink", function() + ui.link{ + text = _"Create a newsletter", + module = "admin", + view = "newsletter_edit" + } + end ) + ui.sidebarSection( "moreLink", function() + ui.link{ + text = _"Manage newsletters", + module = "admin", + view = "newsletter_list" + } + end ) +end ) + +ui.sidebar( "tab-whatcanido", function() + ui.sidebarHead( function() ui.heading { level = 2, content = _"Cancel issue" } end ) diff -r 9578cef4018a -r c0fd12b97d65 app/main/admin/newsletter_edit.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/main/admin/newsletter_edit.lua Tue Apr 05 20:40:37 2016 +0200 @@ -0,0 +1,59 @@ +local id = param.get_id() + +local newsletter = {} + +if id then + newsletter = Newsletter:by_id(id) +end + +ui.titleAdmin(_"Newsletter") + +ui.form{ + attr = { class = "vertical section" }, + module = "admin", + action = "newsletter_update", + id = newsletter and newsletter.id, + record = newsletter, + routing = { + default = { + mode = "redirect", + modules = "admin", + view = "newsletter_list" + } + }, + content = function() + + ui.sectionHead( function() + ui.heading { level = 1, content = newsletter and (newsletter.subject) or _"New newsletter" } + end ) + + ui.sectionRow( function() + local units = { + { id = 0, name = _"All members" }, + { id = "_", name = _"" }, + } + for i, unit in ipairs(Unit:get_flattened_tree()) do + units[#units+1] = unit + end + ui.field.text{ label = _"Date", name = "published" } + ui.field.select{ + label = "Recipient", + name = "unit_id", + foreign_records = units, + foreign_id = "id", + foreign_name = "name", + disabled_records = { ["_"] = true }, + value = newsletter.unit_id + } + ui.field.boolean{ label = _"Override disable notifications?", name = "include_all_members" } + slot.put("
") + ui.field.text{ label = _"Subject", name = "subject" } + ui.field.text{ label = _"Content", name = "content", multiline = true, attr = { rows = "20" } } + + ui.submit{ text = _"create newsletter" } + slot.put(" ") + ui.link { module = "admin", view = "index", content = _"cancel" } + end ) + end +} + diff -r 9578cef4018a -r c0fd12b97d65 app/main/admin/newsletter_list.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/main/admin/newsletter_list.lua Tue Apr 05 20:40:37 2016 +0200 @@ -0,0 +1,32 @@ +local newsletter = Newsletter:new_selector() + :add_order_by("published DESC") + :exec() + +ui.titleAdmin(_"Newsletter") + +ui.section( function() + + ui.sectionHead( function() + ui.heading { level = 1, content = _"Newsletter list" } + end ) + + ui.sectionRow( function () + + ui.list{ + records = newsletter, + columns = { + { label = _"Unit", content = function(r) ui.tag{ content = r.unit and r.unit.name or _"All members" } end }, + { name = "published", label = _"Published" }, + { name = "subject", label = _"Subject" }, + { label = _"sent", content = function(r) + if not r.sent then + ui.link{ text = _"Edit", module = "admin", view = "newsletter_edit", id = r.id } + else + ui.tag{ content = format.timestamp(r.sent) } + end + end } + } + } + + end) +end) diff -r 9578cef4018a -r c0fd12b97d65 app/main/index/_index_member.lua --- a/app/main/index/_index_member.lua Wed Jan 27 11:16:26 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ - -local tabs = { - module = "index", - view = "index" -} - -tabs[#tabs+1] = { - name = "areas", - label = _"Home", - icon = { static = "icons/16/package.png" }, - module = "index", - view = "_member_home", - params = { member = app.session.member } -} - -tabs[#tabs+1] = { - name = "timeline", - label = _"Latest events", - module = "event", - view = "_list", - params = { } -} - - -tabs[#tabs+1] = { - name = "open", - label = _"Open issues", - module = "issue", - view = "_list", - params = { - for_state = "open", - issues_selector = Issue:new_selector() - :add_where("issue.closed ISNULL") - :add_order_by("coalesce(issue.fully_frozen + issue.voting_time, issue.half_frozen + issue.verification_time, issue.accepted + issue.discussion_time, issue.created + issue.max_admission_time) - now()") - } -} - -tabs[#tabs+1] = { - name = "closed", - label = _"Closed issues", - module = "issue", - view = "_list", - params = { - for_state = "closed", - issues_selector = Issue:new_selector() - :add_where("issue.closed NOTNULL") - :add_order_by("issue.closed DESC") - - } -} - -tabs[#tabs+1] = { - name = "members", - label = _"Members", - module = 'member', - view = '_list', - params = { members_selector = Member:new_selector():add_where("active") } -} - -if not param.get("tab") then - execute.view{ - module = "index", view = "_notifications" - } -end - -ui.tabs(tabs) diff -r 9578cef4018a -r c0fd12b97d65 app/main/index/_notifications.lua --- a/app/main/index/_notifications.lua Wed Jan 27 11:16:26 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -local notification_links = {} - -if app.session.member.notify_email_unconfirmed then - notification_links[#notification_links+1] = { - module = "index", view = "email_unconfirmed", - text = _"Please confirm your email address" - } -end - -if app.session.member.notify_level == nil then - notification_links[#notification_links+1] = { - module = "member", view = "settings_notification", - text = _"Please select your preferred notification level" - } -end - -if config.check_delegations_interval_soft then - local member = Member:new_selector() - :add_where({ "id = ?", app.session.member_id }) - :add_field({ "now() > COALESCE(last_delegation_check, activated) + ?::interval", config.check_delegations_interval_soft }, "needs_delegation_check_soft") - :single_object_mode() - :exec() - - - if member.needs_delegation_check_soft then - - local delegations = Delegation:delegations_to_check_for_member_id(member.id) - - if #delegations > 0 then - notification_links[#notification_links+1] = { - module = "index", view = "check_delegations", - text = _"Check your delegations!" - } - end - - end -end - -local broken_delegations_count = Delegation:selector_for_broken(app.session.member_id):count() - -if broken_delegations_count > 0 then - notification_links[#notification_links+1] = { - module = "index", view = "broken_delegations", - text = _("#{count} of your outgoing delegation(s) are broken", { count = broken_delegations_count }) - } - -end - -local selector = Issue:new_selector() - :join("area", nil, "area.id = issue.area_id") - :join("privilege", nil, { "privilege.unit_id = area.unit_id AND privilege.member_id = ? AND privilege.voting_right", app.session.member_id }) - :left_join("direct_voter", nil, { "direct_voter.issue_id = issue.id AND direct_voter.member_id = ?", app.session.member.id }) - :left_join("non_voter", nil, { "non_voter.issue_id = issue.id AND non_voter.member_id = ?", app.session.member.id }) - :left_join("interest", nil, { "interest.issue_id = issue.id AND interest.member_id = ?", app.session.member.id }) - :add_where{ "direct_voter.member_id ISNULL" } - :add_where{ "non_voter.member_id ISNULL" } - :add_where{ "interest.member_id NOTNULL" } - :add_where{ "issue.fully_frozen NOTNULL" } - :add_where{ "issue.closed ISNULL" } - :add_order_by{ "issue.fully_frozen + issue.voting_time ASC" } - -local issues_to_vote_count = selector:count() -if issues_to_vote_count > 0 then - notification_links[#notification_links+1] = { - module = "index", view = "index", - params = { - tab = "open", filter = "frozen", filter_interest = "issue", filter_delegation = "direct", filter_voting = "not_voted" - }, - text = _("You have not voted #{count} issue(s) you were interested in", { count = issues_to_vote_count }) - } -end - -local initiator_invites_count = Initiator:selector_for_invites(app.session.member_id):count() - -if initiator_invites_count > 0 then - notification_links[#notification_links+1] = { - module = "index", view = "initiator_invites", - text = _("You are invited to #{count} initiative(s)", { count = initiator_invites_count }) - } -end - -updated_drafts_count = Initiative:selector_for_updated_drafts(app.session.member_id):count() - -if updated_drafts_count > 0 then - notification_links[#notification_links+1] = { - module = "index", view = "updated_drafts", - text = _("New drafts for #{count} initiative(s) you are supporting", { count = updated_drafts_count }) - } -end - -if #notification_links > 0 then - ui.container{ attr = { class = "notifications" }, content = function() - ui.tag{ tag = "ul", attr = { class = "notifications" }, content = function() - for i, notification_link in ipairs(notification_links) do - ui.tag{ tag = "li", content = function() - ui.link(notification_link) - end } - end - end } - end } -end - - diff -r 9578cef4018a -r c0fd12b97d65 app/main/index/_sidebar_notifications.lua --- a/app/main/index/_sidebar_notifications.lua Wed Jan 27 11:16:26 2016 +0100 +++ b/app/main/index/_sidebar_notifications.lua Tue Apr 05 20:40:37 2016 +0200 @@ -7,13 +7,6 @@ } end -if app.session.member.notify_level == nil then - notification_links[#notification_links+1] = { - module = "member", view = "settings_notification", - text = _"Select a notification level" - } -end - if config.check_delegations_interval_soft then local member = Member:new_selector() :add_where({ "id = ?", app.session.member_id }) diff -r 9578cef4018a -r c0fd12b97d65 app/main/member/_action/update_notify_level.lua --- a/app/main/member/_action/update_notify_level.lua Wed Jan 27 11:16:26 2016 +0100 +++ b/app/main/member/_action/update_notify_level.lua Tue Apr 05 20:40:37 2016 +0200 @@ -1,2 +1,2 @@ -app.session.member.notify_level = param.get("notify_level") +app.session.member.disable_notifications = param.get("disable_notifications") == "true" and true or false app.session.member:save() diff -r 9578cef4018a -r c0fd12b97d65 app/main/member/settings_notification.lua --- a/app/main/member/settings_notification.lua Wed Jan 27 11:16:26 2016 +0100 +++ b/app/main/member/settings_notification.lua Tue Apr 05 20:40:37 2016 +0200 @@ -36,8 +36,8 @@ tag = "input", attr = { id = "notify_level_all", - type = "radio", name = "notify_level", value = "all", - checked = app.session.member.notify_level == 'all' and "checked" or nil + type = "radio", name = "disable_notifications", value = "false", + checked = not app.session.member.disable_notifications and "checked" or nil } } ui.tag{ @@ -52,60 +52,9 @@ ui.tag{ tag = "input", attr = { - id = "notify_level_discussion", - type = "radio", name = "notify_level", value = "discussion", - checked = app.session.member.notify_level == 'discussion' and "checked" or nil - } - } - ui.tag{ - tag = "label", attr = { ['for'] = "notify_level_discussion" }, - content = _"Only for issues reaching the discussion phase" - } - end } - - slot.put("
") - - ui.container{ content = function() - ui.tag{ - tag = "input", - attr = { - id = "notify_level_verification", - type = "radio", name = "notify_level", value = "verification", - checked = app.session.member.notify_level == 'verification' and "checked" or nil - } - } - ui.tag{ - tag = "label", attr = { ['for'] = "notify_level_verification" }, - content = _"Only for issues reaching the verification phase" - } - end } - - slot.put("
") - - ui.container{ content = function() - ui.tag{ - tag = "input", - attr = { - id = "notify_level_voting", - type = "radio", name = "notify_level", value = "voting", - checked = app.session.member.notify_level == 'voting' and "checked" or nil - } - } - ui.tag{ - tag = "label", attr = { ['for'] = "notify_level_voting" }, - content = _"Only for issues reaching the voting phase" - } - end } - - slot.put("
") - - ui.container{ content = function() - ui.tag{ - tag = "input", - attr = { id = "notify_level_none", - type = "radio", name = "notify_level", value = "none", - checked = app.session.member.notify_level == 'none' and "checked" or nil + type = "radio", name = "disable_notifications", value = "true", + checked = app.session.member.disable_notifications and "checked" or nil } } ui.tag{ @@ -116,11 +65,6 @@ slot.put("
") - ui.container { content = _"Notifications are only send to you about events in the subject areas you subscribed, the issues you are interested in and the initiatives you are supporting." } - - - slot.put("
") - ui.tag{ tag = "input", attr = { diff -r 9578cef4018a -r c0fd12b97d65 model/event.lua --- a/model/event.lua Wed Jan 27 11:16:26 2016 +0100 +++ b/model/event.lua Tue Apr 05 20:40:37 2016 +0200 @@ -51,12 +51,12 @@ function Event.object:send_notification() local members_to_notify = Member:new_selector() - :join("event_seen_by_member", nil, { "event_seen_by_member.seen_by_member_id = member.id AND event_seen_by_member.notify_level <= member.notify_level AND event_seen_by_member.id = ?", self.id } ) - :add_where("member.activated NOTNULL AND member.notify_email NOTNULL") + :join("event_for_notification", nil, { "event_for_notification.recipient_id = member.id AND event_for_notification.id = ?", self.id } ) + --:add_where("member.activated NOTNULL AND member.notify_email NOTNULL") -- SAFETY FIRST, NEVER send notifications for events more then 3 days in past or future - :add_where("now() - event_seen_by_member.occurrence BETWEEN '-3 days'::interval AND '3 days'::interval") + :add_where("now() - event_for_notification.occurrence BETWEEN '-3 days'::interval AND '3 days'::interval") -- do not notify a member about the events caused by the member - :add_where("event_seen_by_member.member_id ISNULL OR event_seen_by_member.member_id != member.id") + :add_where("event_for_notification.member_id ISNULL OR event_for_notification.member_id != member.id") :exec() io.stderr:write("Sending notifications for event " .. self.id .. " to " .. (#members_to_notify) .. " members\n") @@ -71,32 +71,22 @@ { lang = member.lang or config.default_lang or 'en' }, function() - local suggestion - if self.suggestion_id then - suggestion = Suggestion:by_id(self.suggestion_id) - if not suggestion then - return - end - end - - subject = config.mail_subject_prefix .. " " .. self.event_name body = body .. _("[event mail] Unit: #{name}", { name = self.issue.area.unit.name }) .. "\n" body = body .. _("[event mail] Area: #{name}", { name = self.issue.area.name }) .. "\n" body = body .. _("[event mail] Issue: ##{id}", { id = self.issue_id }) .. "\n\n" body = body .. _("[event mail] Policy: #{policy}", { policy = self.issue.policy.name }) .. "\n\n" - body = body .. _("[event mail] Event: #{event}", { event = self.event_name }) .. "\n\n" body = body .. _("[event mail] Phase: #{phase}", { phase = self.state_name }) .. "\n\n" if self.initiative_id then url = request.get_absolute_baseurl() .. "initiative/show/" .. self.initiative_id .. ".html" - elseif self.suggestion_id then - url = request.get_absolute_baseurl() .. "suggestion/show/" .. self.suggestion_id .. ".html" else url = request.get_absolute_baseurl() .. "issue/show/" .. self.issue_id .. ".html" end body = body .. _("[event mail] URL: #{url}", { url = url }) .. "\n\n" + local leading_initiative + if self.initiative_id then local initiative = Initiative:by_id(self.initiative_id) body = body .. _("i#{id}: #{name}", { id = initiative.id, name = initiative.name }) .. "\n\n" @@ -110,6 +100,9 @@ :limit(3) :exec() for i, initiative in ipairs(initiatives) do + if i == 1 then + leading_initiative = initiative + end body = body .. _("i#{id}: #{name}", { id = initiative.id, name = initiative.name }) .. "\n" end if initiative_count - 3 > 0 then @@ -118,10 +111,14 @@ body = body .. "\n" end - if suggestion then - body = body .. _("#{name}\n\n", { name = suggestion.name }) + subject = config.mail_subject_prefix + + if self.event == "issue_state_changed" then + subject = subject .. _("State of #{issue} changed to #{state} / Leading: #{initiative}", { issue = self.issue.name, state = Issue:get_state_name_for_state(self.state), initiative = leading_initiative.display_name }) + elseif self.event == "initiative_revoked" then + subject = subject .. _("Initiative revoked: #{initiative_name}", { initiative_name = self.initiative.display_name }) end - + local success = net.send_mail{ envelope_from = config.mail_envelope_from, from = config.mail_from, @@ -175,23 +172,3 @@ end end - -function Event:send_pending_notifications() - while true do - if not Event:send_next_notification() then - break - end - end -end - -function Event:send_notifications_loop() - - while true do - local did_work = Event:send_next_notification() - if not did_work then - print "Sleeping 5 second" - os.execute("sleep 5") - end - end - -end \ No newline at end of file diff -r 9578cef4018a -r c0fd12b97d65 model/initiative_for_notification.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/model/initiative_for_notification.lua Tue Apr 05 20:40:37 2016 +0200 @@ -0,0 +1,178 @@ +InitiativeForNotification = mondelefant.new_class() +InitiativeForNotification.table = 'initiative_for_notification' + +InitiativeForNotification:add_reference{ + mode = 'm1', + to = "Initiative", + this_key = 'initiative_id', + that_key = 'id', + ref = 'initiative', +} + + +function InitiativeForNotification:notify_member_id(member_id) + + db:query("BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ") + + local member = Member:by_id(member_id) + locale.set{ lang = member.lang or config.default_lang } + + io.stderr:write("Sending digest #" .. member.notification_counter .. " to " .. member.notify_email .. "\n") + + if not member.notify_email then + return + end + + local selector = db:new_selector() + :add_field("*") + :from({ "get_initiatives_for_notification(?)", member_id }, "initiative_for_notification") + :join("initiative", nil, "initiative.id = initiative_for_notification.initiative_id") + :join("issue", nil, "issue.id = initiative.issue_id") + :join("member", nil, "member.id = initiative_for_notification.recipient_id") + :add_order_by("md5(initiative_for_notification.recipient_id || '-' || member.notification_counter || '-' || issue.area_id)") + :add_order_by("md5(initiative_for_notification.recipient_id || '-' || member.notification_counter || '-' || issue.id)") + selector._class = self + + local initiatives_for_notification = selector:exec() + + if #initiatives_for_notification < 1 then + return + end + + local initiatives = initiatives_for_notification:load("initiative") + local issues = initiatives:load("issue") + issues:load("area") + issues:load("policy") + + local last_area_id + local last_issue_id + + local draft_count = 0 + local suggestion_count = 0 + + local ms = {} + + for i, entry in ipairs(initiatives_for_notification) do + local initiative = entry.initiative + local issue = initiative.issue + local area = issue.area + local policy = issue.policy + + local m = {} + if last_area_id ~= area.id then + m[#m+1] = "*** " .. area.name .. " ***" + m[#m+1] = "" + last_area_id = area.id + end + if last_issue_id ~= issue.id then + local state_time_text + if string.sub(issue.state_time_left, 1, 1) == "-" then + state_time_text = _"Phase ends soon" + else + state_time_text = _( "#{interval} left", { + interval = format.interval_text(issue.state_time_left) + }) + end + m[#m+1] = "---" + m[#m+1] = policy.name .. " #" .. issue.id .. " - " .. issue.state_name .. " - " .. state_time_text + m[#m+1] = "" + last_issue_id = issue.id + end + m[#m+1] = initiative.display_name + local source + if entry.supported then + source = _"has my support" + local draft_info + if entry.new_draft then + draft_info = _"draft updated" + draft_count = draft_count + 1 + end + if draft_info then + source = source .. ", " .. draft_info + end + local info + if entry.new_suggestion_count then + if entry.new_suggestion_count == 1 then + info = _"new suggestion added" + elseif entry.new_suggestion_count > 1 then + info = _("#{count} suggestions added", { count = entry.new_suggestion_count }) + end + suggestion_count = suggestion_count + entry.new_suggestion_count + end + if info then + source = source .. ", " .. info + end + elseif entry.featured then + source = _"featured" + end + if entry.leading then + source = source and source .. ", " or "" + source = source .. "currently leading" + end + m[#m+1] = "(" .. source .. ")" + m[#m+1] = "" + if not initiatives_for_notification[i+1] or initiatives_for_notification[i+1].issue_id ~= issue.id then + m[#m+1] = _("more: #{url}", { url = request.get_absolute_baseurl() .. "issue/show/" .. issue.id .. ".html" }) + m[#m+1] = "" + end + ms[#ms+1] = table.concat(m, "\n") + end + + local info = {} + + if draft_count > 0 then + if draft_count == 1 then + info[#info+1] = _"draft updated for " .. initiatives_for_notification[1].initiative.display_name + else + info[#info+1] = _("drafts of #{draft_count} initiatives updated", { draft_count = draft_count }) + end + end + + if suggestion_count > 0 then + if suggestion_count == 1 then + info[#info+1] = _"new suggestion for " .. initiatives_for_notification[1].initiative.display_name + else + info[#info+1] = _("#{suggestion_count} suggestions added", { suggestion_count = suggestion_count }) + end + end + + if draft_count == 0 and suggestion_count == 0 then + info[#info+1] = _"featured initiatives" + end + + local subject = _("Digest #{id}: #{info}", { + id = member.notification_counter, info = table.concat(info, ", ") + }) + + + local template = config.notification_digest_template + + local message = _(template, { + name = member.name, + digest = table.concat(ms, "\n") + }) + + local success = net.send_mail{ + envelope_from = config.mail_envelope_from, + from = config.mail_from, + reply_to = config.mail_reply_to, + to = member.notify_email, + subject = subject, + content_type = "text/plain; charset=UTF-8", + content = message + } + + db:query("COMMIT") + +end + +function InitiativeForNotification:notify_next_member() + local scheduled_notification_to_send = ScheduledNotificationToSend:get_next() + if not scheduled_notification_to_send then + return false + end + InitiativeForNotification:notify_member_id(scheduled_notification_to_send.recipient_id) + return true +end + +ScheduledNotificationToSend:get_next() \ No newline at end of file diff -r 9578cef4018a -r c0fd12b97d65 model/newsletter.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/model/newsletter.lua Tue Apr 05 20:40:37 2016 +0200 @@ -0,0 +1,41 @@ +Newsletter = mondelefant.new_class() +Newsletter.table = 'newsletter' + +function Newsletter:send_next_newsletter() + local newsletter_to_send = NewsletterToSend:get_next() + if not newsletter_to_send then + return false + end + local newsletter = newsletter_to_send.newsletter + + local newsletter_to_send = NewsletterToSend:by_newsletter_id(newsletter.id) + newsletter_to_send:load("member") + + newsletter.sent = "now" + newsletter:save() + + io.stderr:write("Sending newsletter " .. newsletter.id .. " to " .. (#newsletter_to_send) .. " members\n") + + for i, n in ipairs(newsletter_to_send) do + + local member = newsletter_to_send.member + + if not member.notify_email then + return + end + + io.stderr:write("Sending newsletter " .. newsletter.id .. " to " .. member.notify_email .. "\n") + + local success = net.send_mail{ + envelope_from = config.mail_envelope_from, + from = config.mail_from, + reply_to = config.mail_reply_to, + to = member.notify_email, + subject = newsletter.subject, + content_type = "text/plain; charset=UTF-8", + content = newsletter.content + } + + end + +end \ No newline at end of file diff -r 9578cef4018a -r c0fd12b97d65 model/newsletter_to_send.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/model/newsletter_to_send.lua Tue Apr 05 20:40:37 2016 +0200 @@ -0,0 +1,34 @@ +NewsletterToSend = mondelefant.new_class() +NewsletterToSend.table = 'newsletter_to_send' + +NewsletterToSend:add_reference{ + mode = 'm1', + to = "Newsletter", + this_key = 'newsletter_id', + that_key = 'id', + ref = 'newsletter', +} + +NewsletterToSend:add_reference{ + mode = 'm1', + to = "Member", + this_key = 'recipient_id', + that_key = 'id', + ref = 'member', +} + +function NewsletterToSend:get_next() + return NewsletterToSend:new_selector() + :set_distinct("newsletter_id") + :add_order_by("newsletter_id") + :limit(1) + :optional_object_mode() + :exec() +end + +function NewsletterToSend:by_newsletter_id(id) + return NewsletterToSend:new_selector() + :add_where{ "newsletter_id = ?", id } + :optional_object_mode() + :exec() +end \ No newline at end of file diff -r 9578cef4018a -r c0fd12b97d65 model/scheduled_notification_to_send.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/model/scheduled_notification_to_send.lua Tue Apr 05 20:40:37 2016 +0200 @@ -0,0 +1,10 @@ +ScheduledNotificationToSend = mondelefant.new_class() +ScheduledNotificationToSend.table = 'scheduled_notification_to_send' + +function ScheduledNotificationToSend:get_next() + return self:new_selector() + :add_order_by("pending DESC") + :limit(1) + :optional_object_mode() + :exec() +end \ No newline at end of file