Compare commits
5 Commits
b05502fedf
...
99c1495d3f
Author | SHA1 | Date |
---|---|---|
Arthur POULET | 99c1495d3f | |
Arthur POULET | ea02fe40ca | |
Arthur POULET | f9a0648264 | |
Arthur POULET | 43accadaf3 | |
Arthur POULET | 87002a9571 |
|
@ -3,6 +3,8 @@
|
||||||
$LOAD_PATH << File.join(Dir.pwd, "lib")
|
$LOAD_PATH << File.join(Dir.pwd, "lib")
|
||||||
|
|
||||||
require "app"
|
require "app"
|
||||||
|
require "protocols"
|
||||||
|
require "models"
|
||||||
require "pry"
|
require "pry"
|
||||||
|
|
||||||
# mailinglist1 = Mailinglist.build(name: "FreeML", suffix: "free", strategy: "free").save
|
# mailinglist1 = Mailinglist.build(name: "FreeML", suffix: "free", strategy: "free").save
|
||||||
|
|
|
@ -5,6 +5,8 @@ $LOAD_PATH << File.join(Dir.pwd, "lib")
|
||||||
require "app"
|
require "app"
|
||||||
require "optparse"
|
require "optparse"
|
||||||
require "uuid"
|
require "uuid"
|
||||||
|
require "protocols"
|
||||||
|
require "models"
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
name: UUID.generate,
|
name: UUID.generate,
|
||||||
|
@ -21,8 +23,17 @@ OptionParser.new do |opts|
|
||||||
opts.on("-n=NAME", "--name=NAME", "Define the name of the option") do |v|
|
opts.on("-n=NAME", "--name=NAME", "Define the name of the option") do |v|
|
||||||
options[:name] = v
|
options[:name] = v
|
||||||
end
|
end
|
||||||
|
|
||||||
|
opts.on("-e=EMAIL", "--email=EMAIL", "Initialize the list with some emails, separated with ,") do |email|
|
||||||
|
options[:emails] ||= []
|
||||||
|
options[:emails] << email
|
||||||
|
end
|
||||||
end.parse!
|
end.parse!
|
||||||
|
|
||||||
options[:suffix] = options[:name].gsub(/[^a-zA-Z0-9]+/, '-')
|
options[:suffix] = options[:name].gsub(/[^a-zA-Z0-9]+/, '-')
|
||||||
mailinglist = Mailinglist.build(name: options[:name], suffix: options[:suffix], strategy: options[:strategy]).save
|
mailinglist = Mailinglist.build(name: options[:name], suffix: options[:suffix], strategy: options[:strategy]).save
|
||||||
pp mailinglist
|
pp mailinglist
|
||||||
|
|
||||||
|
options[:emails].each do |email|
|
||||||
|
pp Email.register!(name: email, email: email, mailinglist: mailinglist)
|
||||||
|
end
|
||||||
|
|
|
@ -3,12 +3,12 @@
|
||||||
$LOAD_PATH << File.join(Dir.pwd, "lib")
|
$LOAD_PATH << File.join(Dir.pwd, "lib")
|
||||||
|
|
||||||
require "app"
|
require "app"
|
||||||
|
require "protocols"
|
||||||
|
require "models"
|
||||||
|
|
||||||
|
mailinglist0 = Mailinglist.build(name: "AutoReg", suffix: "autoreg", strategy: "autoregister").save
|
||||||
mailinglist1 = Mailinglist.build(name: "FreeML", suffix: "free", strategy: "free").save
|
mailinglist1 = Mailinglist.build(name: "FreeML", suffix: "free", strategy: "free").save
|
||||||
mailinglist2 = Mailinglist.build(name: "ValidatedML", suffix: "validated", strategy: "validated").save
|
mailinglist2 = Mailinglist.build(name: "ValidatedML", suffix: "validated", strategy: "validated").save
|
||||||
mailinglist3 = Mailinglist.build(name: "ClosedML", suffix: "closed", strategy: "closed").save
|
mailinglist3 = Mailinglist.build(name: "ClosedML", suffix: "closed", strategy: "closed").save
|
||||||
pp mailinglist1, mailinglist2, mailinglist3
|
|
||||||
|
|
||||||
# email1 = Email.register!(name: "AP", email: "arthur.poulet.hunk@sceptique.eu", mailinglist: mailinglist)
|
pp mailinglist0, mailinglist1, mailinglist2, mailinglist3
|
||||||
# email2 = Email.register!(name: "AP2", email: "arthur.poulet.hunk2@sceptique.eu", mailinglist: mailinglist)
|
|
||||||
# pp email1, email2
|
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
$LOAD_PATH << File.join(Dir.pwd, "lib")
|
$LOAD_PATH << File.join(Dir.pwd, "lib")
|
||||||
|
|
||||||
require "app"
|
require "app"
|
||||||
|
require "protocols"
|
||||||
|
require "models"
|
||||||
require "distributor"
|
require "distributor"
|
||||||
|
|
||||||
Signal.trap("SIGINT") do
|
Signal.trap("SIGINT") do
|
||||||
|
|
3
bin/http
3
bin/http
|
@ -2,7 +2,10 @@
|
||||||
$LOAD_PATH << File.join(Dir.pwd, "lib")
|
$LOAD_PATH << File.join(Dir.pwd, "lib")
|
||||||
|
|
||||||
require "app"
|
require "app"
|
||||||
|
require "protocols"
|
||||||
|
require "models"
|
||||||
require "sinatra"
|
require "sinatra"
|
||||||
|
|
||||||
set :views, File.expand_path(File.join(settings.root + "/../lib/web/views"))
|
set :views, File.expand_path(File.join(settings.root + "/../lib/web/views"))
|
||||||
|
|
||||||
require "web"
|
require "web"
|
||||||
|
|
|
@ -8,5 +8,3 @@ require "sequel"
|
||||||
$db = Sequel.connect(ENV["DB_URL"])
|
$db = Sequel.connect(ENV["DB_URL"])
|
||||||
|
|
||||||
require_relative "logger"
|
require_relative "logger"
|
||||||
require_relative "protocols"
|
|
||||||
require_relative "models" rescue nil
|
|
||||||
|
|
|
@ -36,12 +36,13 @@ class Distributor
|
||||||
$logger.info "incoming email from #{mail.from} | #{mail.subject}"
|
$logger.info "incoming email from #{mail.from} | #{mail.subject}"
|
||||||
list = Mailinglist.search_mail(mail)
|
list = Mailinglist.search_mail(mail)
|
||||||
if list
|
if list
|
||||||
# TODO: create list from mail ?
|
|
||||||
subject, subject_attributes = mail.subject.split(",", 2)
|
subject, subject_attributes = mail.subject.split(",", 2)
|
||||||
attributes = Attributes.parse(subject: subject_attributes, body: mail.body)
|
attributes = Attributes.parse(subject: subject_attributes, body: mail.body)
|
||||||
handler = @handlers[subject] || @handlers[:default]
|
handler = @handlers[subject] || @handlers[:default]
|
||||||
$logger.info "#{handler.class}#handle on #{list.email} for #{mail.from}"
|
$logger.info "#{handler.class}#handle on #{list.email} for #{mail.from}"
|
||||||
handler.handle(list:, to: mail, attributes:)
|
handler.handle(list: list, mail: mail, attributes: attributes)
|
||||||
|
else
|
||||||
|
$logger.warn "list #{mail.to} do not exist (asked by #{mail.from})"
|
||||||
end
|
end
|
||||||
mail.seen!(imap_client: @imap_client)
|
mail.seen!(imap_client: @imap_client)
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,31 +4,31 @@ class Distributor
|
||||||
class SetPermissions < Action
|
class SetPermissions < Action
|
||||||
SET_PERMISSIONS_TEMPLATE = Actions.template("set_permissions.success")
|
SET_PERMISSIONS_TEMPLATE = Actions.template("set_permissions.success")
|
||||||
|
|
||||||
def handle(list:, to:, attributes:)
|
def handle(list:, mail:, attributes:)
|
||||||
return if attributes["user-email"].nil? # drop missing param
|
return if attributes["user-email"].nil? # drop missing param
|
||||||
return if attributes["permissions"].nil? # drop missing param
|
return if attributes["permissions"].nil? # drop missing param
|
||||||
|
|
||||||
modo = Email.first(mailinglist: list, email: to.from)
|
modo = Email.first(mailinglist: list, email: mail.from)
|
||||||
if !modo&.modo? && !modo&.op?
|
if !modo&.modo? && !modo&.op?
|
||||||
$logger.warn "SECU <#{to.from}> failed to set-permissions <#{list.email}> modo"
|
$logger.warn "SECU <#{mail.from}> failed to set-permissions <#{list.email}> modo"
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
user_email = attributes["user-email"]
|
user_email = attributes["user-email"]
|
||||||
user = Email.first(mailinglist: list, email: user_email)
|
user = Email.first(mailinglist: list, email: user_email)
|
||||||
if user.nil?
|
if user.nil?
|
||||||
$logger.warn "SECU <#{to.from}> failed to set-permissions on non-existing email <#{user_email}>"
|
$logger.warn "SECU <#{mail.from}> failed to set-permissions on non-existing email <#{user_email}>"
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if user.op? && !modo.op?
|
if user.op? && !modo.op?
|
||||||
$logger.warn "SECU <#{to.from}> failed to set-permissions on op email <#{user_email}>"
|
$logger.warn "SECU <#{mail.from}> failed to set-permissions on op email <#{user_email}>"
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
permissions = attributes["permissions"].to_i
|
permissions = attributes["permissions"].to_i
|
||||||
if Email::Permissions.op?(permissions) && !modo.op?
|
if Email::Permissions.op?(permissions) && !modo.op?
|
||||||
$logger.warn "SECU <#{to.from}> failed to set op permissions on email <#{user_email}>"
|
$logger.warn "SECU <#{mail.from}> failed to set op permissions on email <#{user_email}>"
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,81 +7,86 @@ class Distributor
|
||||||
WAIT_USER_TEMPLATE = Actions.template("subscribe.wait_user")
|
WAIT_USER_TEMPLATE = Actions.template("subscribe.wait_user")
|
||||||
WAIT_MODO_TEMPLATE = Actions.template("subscribe.wait_modo")
|
WAIT_MODO_TEMPLATE = Actions.template("subscribe.wait_modo")
|
||||||
|
|
||||||
def handle(list:, to:, attributes:)
|
def handle(list:, mail:, attributes:)
|
||||||
register =
|
register =
|
||||||
begin
|
begin
|
||||||
Email.register!(mailinglist: list, name: to.from_name, email: to.from).save
|
Email.register!(mailinglist: list, name: mail.from_name, email: mail.from).save
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
$logger.error e.message
|
$logger.error e.message
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
if register
|
if register
|
||||||
if !register.reader?
|
if !register.reader?
|
||||||
handle_wait_validation(list:, to:, register:)
|
handle_wait_validation(list: list, mail: mail, register: register)
|
||||||
else
|
else
|
||||||
handle_subscribed(list:, to:, register:)
|
handle_subscribed(list: list, mail: mail, register: register)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
handle_403(list:, to:)
|
handle_403(list: list, mail: mail)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_wait_validation(list:, to:, register:)
|
def handle_wait_validation(list:, mail:, register:)
|
||||||
$logger.debug "Subscribe#handle_wait_validation on #{list.email} for #{to.from}"
|
$logger.debug "Subscribe#handle_wait_validation on #{list.email} for #{to.from}"
|
||||||
body = WAIT_USER_TEMPLATE.result binding
|
body = WAIT_USER_TEMPLATE.result binding
|
||||||
@distributor.distribute(to.to_response(list:, to:, body:))
|
@distributor.distribute(mail.to_response(list: list, mail: mail, body: body))
|
||||||
|
|
||||||
modo = list.enabled_modos.first
|
modo = list.enabled_modos.first
|
||||||
body = WAIT_MODO_TEMPLATE.result binding
|
body = WAIT_MODO_TEMPLATE.result binding
|
||||||
@distributor.distribute(
|
@distributor.distribute(
|
||||||
Protocols::Mail.build(
|
Protocols::Mail.build(
|
||||||
subject: "ML #{list.name} requires validaton for #{to.from}", list:, to: modo.email, body:,
|
subject: "ML #{list.name} requires validaton for #{mail.from}", list: list, to: modo.email, body: body,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_subscribed(list:, to:, register:)
|
def handle_subscribed(list:, mail:, register:)
|
||||||
$logger.debug "Subscribe#handle_subscribed on #{list.email} for #{to.from}"
|
$logger.debug "Subscribe#handle_subscribed on #{list.email} for #{mail.from}"
|
||||||
$logger.debug register.inspect
|
$logger.debug register.inspect
|
||||||
body = SUCCESS_TEMPLATE.result binding
|
body = SUCCESS_TEMPLATE.result binding
|
||||||
@distributor.distribute(to.to_response(list:, to:, body:))
|
@distributor.distribute(mail.to_response(list: list, mail: mail, body: body))
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_403(list:, to:)
|
def handle_403(list:, mail:)
|
||||||
$logger.debug "Subscribe#handle_403 on #{list.email} for #{to.from}"
|
$logger.debug "Subscribe#handle_403 on #{list.email} for #{mail.from}"
|
||||||
body = FORBIDDEN_TEMPLATE.result binding
|
body = FORBIDDEN_TEMPLATE.result binding
|
||||||
@distributor.distribute(to.to_response(list:, to:, body:))
|
@distributor.distribute(mail.to_response(list: list, mail: mail, body: body))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Unsubscribe < Action
|
class Unsubscribe < Action
|
||||||
SUCCESS_TEMPLATE = Actions.template("unsubscribe.success")
|
SUCCESS_TEMPLATE = Actions.template("unsubscribe.success")
|
||||||
|
|
||||||
def handle(list:, to:, attributes:)
|
def handle(list:, mail:, attributes:)
|
||||||
Email.unregister!(mailinglist: list, email: to.from)
|
Email.unregister!(mailinglist: list, email: mail.from)
|
||||||
body = SUCCESS_TEMPLATE.result binding
|
body = SUCCESS_TEMPLATE.result binding
|
||||||
@distributor.distribute(to.to_response(list:, to:, body:))
|
@distributor.distribute(mail.to_response(list: list, mail: mail, body: body))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Help < Action
|
class Help < Action
|
||||||
HELP_TEMPLATE = Actions.template("help")
|
HELP_TEMPLATE = Actions.template("help")
|
||||||
def handle(list:, to:, attributes:)
|
|
||||||
|
def handle(list:, mail:, attributes:)
|
||||||
body = HELP_TEMPLATE.result binding
|
body = HELP_TEMPLATE.result binding
|
||||||
@distributor.distribute(to.to_response(list:, to:, body:))
|
@distributor.distribute(mail.to_response(list: list, mail: mail, body: body))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# This distribute the mail among the readers
|
# This distribute the mail among the readers
|
||||||
class Distribute < Action
|
class Distribute < Action
|
||||||
def handle(list:, to:, attributes:)
|
def handle(list:, mail:, attributes:)
|
||||||
if !list
|
if !list.enabled_writers.find { _1.email == mail.from }
|
||||||
$logger.warn "invalid email writer for #{mail.from} on #{mail.to}"
|
if list.registration?("autoregister")
|
||||||
return nil
|
Email.register!(mailinglist: list, name: mail.from_name, email: mail.from).save
|
||||||
|
else
|
||||||
|
$logger.warn "invalid email writer for #{mail.from} on #{mail.to}"
|
||||||
|
return nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
list.enabled_readers.each do |reader|
|
list.enabled_readers.each do |reader|
|
||||||
to_distrib = to.to_redistribute(list:, dest: reader)
|
to_distrib = mail.to_redistribute(list: list, dest: reader)
|
||||||
@distributor.distribute(to_distrib)
|
@distributor.distribute(to_distrib)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
You have subscribed to <%= list.name %> <<%= list.email %>>
|
You have subscribed to <%= list.name %> <<%= list.email %>>
|
||||||
|
|
||||||
Your current permissions are <%= register.permissions.to_s(2).rjust(8, "0") %>
|
Your current permissions are <%= register.permissions_words.join(', ') %>
|
|
@ -6,8 +6,8 @@ class Mailinglist < Sequel::Model($db)
|
||||||
HOST = ENV["MAILINGLIST_HOST"]
|
HOST = ENV["MAILINGLIST_HOST"]
|
||||||
|
|
||||||
STRATEGIES = {
|
STRATEGIES = {
|
||||||
registration: %w[free validated closed],
|
registration: %w[autoregister free validated closed],
|
||||||
moderate: %w[freewrite restrictedwrite],
|
moderation: %w[freewrite restrictedwrite],
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
one_to_many :emails
|
one_to_many :emails
|
||||||
|
@ -23,7 +23,7 @@ class Mailinglist < Sequel::Model($db)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.build(name:, aliasing: nil, suffix: nil, strategy: "closed")
|
def self.build(name:, aliasing: nil, suffix: nil, strategy: "closed")
|
||||||
email = "#{BASE_USER}"
|
email = BASE_USER.dup
|
||||||
email << SUFFIX_SEPARATOR << suffix if suffix
|
email << SUFFIX_SEPARATOR << suffix if suffix
|
||||||
aliasing = UUID.generate if !suffix && !aliasing
|
aliasing = UUID.generate if !suffix && !aliasing
|
||||||
email << aliasing if aliasing
|
email << aliasing if aliasing
|
||||||
|
@ -48,27 +48,35 @@ class Mailinglist < Sequel::Model($db)
|
||||||
end
|
end
|
||||||
|
|
||||||
def registration
|
def registration
|
||||||
strategy.split("|").select { STRATEGIES[:registration].include(_1) }
|
strategy.split("|").filter { STRATEGIES[:registration].include?(_1) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def registration?(find)
|
||||||
|
registration.include?(find)
|
||||||
end
|
end
|
||||||
|
|
||||||
def moderation
|
def moderation
|
||||||
strategy.split("|").select { STRATEGIES[:registration].include(_1) }
|
strategy.split("|").filter { STRATEGIES[:moderation].include?(_1) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def moderation?(find)
|
||||||
|
moderation.include?(find)
|
||||||
end
|
end
|
||||||
|
|
||||||
def enabled_readers
|
def enabled_readers
|
||||||
emails.filter{ _1.permissions & Email::Permissions::READ != 0 }
|
emails.filter { _1.permissions & Email::Permissions::READ != 0 }
|
||||||
end
|
end
|
||||||
|
|
||||||
def enabled_writers
|
def enabled_writers
|
||||||
emails.filter{ _1.permissions & Email::Permissions::WRITE != 0 }
|
emails.filter { _1.permissions & Email::Permissions::WRITE != 0 }
|
||||||
end
|
end
|
||||||
|
|
||||||
def enabled_admins
|
def enabled_admins
|
||||||
emails.filter{ _1.permissions & Email::Permissions::ADMIN != 0 }
|
emails.filter { _1.permissions & Email::Permissions::ADMIN != 0 }
|
||||||
end
|
end
|
||||||
|
|
||||||
def enabled_modos
|
def enabled_modos
|
||||||
emails.filter{ _1.permissions & Email::Permissions::MODO != 0 }
|
emails.filter { _1.permissions & Email::Permissions::MODO != 0 }
|
||||||
end
|
end
|
||||||
|
|
||||||
def actions_emails
|
def actions_emails
|
||||||
|
@ -100,9 +108,7 @@ class Mailinglist < Sequel::Model($db)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_permissions_email(*permissions_symbols, user_email: nil, permissions: nil)
|
def set_permissions_email(*permissions_symbols, user_email: nil, permissions: nil)
|
||||||
if permissions.nil?
|
permissions = Email::Permissions.from_symbols(*permissions_symbols) if permissions.nil?
|
||||||
permissions = Email::Permissions.from_symbols(*permissions_symbols)
|
|
||||||
end
|
|
||||||
user_part = user_email ? ",user-email=#{user_email}" : ""
|
user_part = user_email ? ",user-email=#{user_email}" : ""
|
||||||
permissions_part = ",permissions=#{permissions}"
|
permissions_part = ",permissions=#{permissions}"
|
||||||
"#{email}?subject=set-permissions#{user_part}#{permissions_part}"
|
"#{email}?subject=set-permissions#{user_part}#{permissions_part}"
|
||||||
|
@ -112,5 +118,4 @@ class Mailinglist < Sequel::Model($db)
|
||||||
"#{email}?subject=list-users"
|
"#{email}?subject=list-users"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -78,7 +78,7 @@ class Protocols::Mail
|
||||||
["List-Post", "<mailto:#{list.post_email}>"],
|
["List-Post", "<mailto:#{list.post_email}>"],
|
||||||
["List-Owner", "<mailto:#{list.owner_email}>"],
|
["List-Owner", "<mailto:#{list.owner_email}>"],
|
||||||
["In-Reply-To", @message_id],
|
["In-Reply-To", @message_id],
|
||||||
["Precedence", "list"],
|
%w[Precedence list],
|
||||||
# ["Precedence", "bulk"],
|
# ["Precedence", "bulk"],
|
||||||
["Message-Id", "<#{UUID.generate}@#{ENV['SENDER_HOST']}>"],
|
["Message-Id", "<#{UUID.generate}@#{ENV['SENDER_HOST']}>"],
|
||||||
["X-Sequence", (@seq + 1).to_s],
|
["X-Sequence", (@seq + 1).to_s],
|
||||||
|
@ -124,8 +124,8 @@ class Protocols::Mail
|
||||||
# Create a response email for an existing one.
|
# Create a response email for an existing one.
|
||||||
#
|
#
|
||||||
# @param list [Mailinglist]
|
# @param list [Mailinglist]
|
||||||
# @param to [Protocols::Mail]
|
# @param mail [Protocols::Mail]
|
||||||
def to_response(list:, to:, body:)
|
def to_response(list:, mail:, body:)
|
||||||
new = clone
|
new = clone
|
||||||
new.replace_headers!(
|
new.replace_headers!(
|
||||||
["User-Agent", USER_AGENT],
|
["User-Agent", USER_AGENT],
|
||||||
|
@ -139,7 +139,7 @@ class Protocols::Mail
|
||||||
["Message-Id", "<#{UUID.generate}@#{ENV['SENDER_HOST']}>"],
|
["Message-Id", "<#{UUID.generate}@#{ENV['SENDER_HOST']}>"],
|
||||||
)
|
)
|
||||||
|
|
||||||
new.to = to.from
|
new.to = mail.from
|
||||||
new.from = list.email
|
new.from = list.email
|
||||||
new.body = "#{body}#{list.signature}"
|
new.body = "#{body}#{list.signature}"
|
||||||
new
|
new
|
||||||
|
|
Loading…
Reference in New Issue