# 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