|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +require "securerandom" |
| 4 | +require "faker" |
| 5 | + |
| 6 | +module Dev |
| 7 | + class EmailSimulator |
| 8 | + DEFAULT_EXISTING_ALIAS_PROB = 0.9 |
| 9 | + DEFAULT_EXISTING_TOPIC_PROB = 0.9 |
| 10 | + |
| 11 | + def initialize(existing_alias_prob: DEFAULT_EXISTING_ALIAS_PROB, existing_topic_prob: DEFAULT_EXISTING_TOPIC_PROB) |
| 12 | + @existing_alias_prob = existing_alias_prob |
| 13 | + @existing_topic_prob = existing_topic_prob |
| 14 | + end |
| 15 | + |
| 16 | + def generate_mail(sent_at: Time.current) |
| 17 | + from_alias = pick_alias |
| 18 | + topic, reply_to = pick_topic |
| 19 | + |
| 20 | + mail = Mail.new |
| 21 | + mail.date = sent_at |
| 22 | + mail.message_id = "<sim-#{SecureRandom.hex}@hackorum.dev>" |
| 23 | + mail.from = "#{from_alias.name} <#{from_alias.email}>" |
| 24 | + mail.to = to_addresses(reply_to, topic) |
| 25 | + mail.subject = subject_for(topic, reply_to) |
| 26 | + |
| 27 | + if reply_to&.message_id.present? |
| 28 | + mail.in_reply_to = reply_to.message_id |
| 29 | + mail.references = reply_to.message_id |
| 30 | + end |
| 31 | + |
| 32 | + mail.body = body_for(reply_to) |
| 33 | + mail |
| 34 | + end |
| 35 | + |
| 36 | + def ingest!(mail) |
| 37 | + EmailIngestor.new.ingest_raw(mail.to_s) |
| 38 | + end |
| 39 | + |
| 40 | + def generate_and_ingest!(sent_at: Time.current) |
| 41 | + ingest!(generate_mail(sent_at: sent_at)) |
| 42 | + end |
| 43 | + |
| 44 | + private |
| 45 | + |
| 46 | + def pick_alias |
| 47 | + use_existing = rand < @existing_alias_prob |
| 48 | + existing = Alias.order("RANDOM()").first if use_existing |
| 49 | + return existing if existing |
| 50 | + |
| 51 | + Alias.create!( |
| 52 | + name: Faker::Name.name, |
| 53 | + email: Faker::Internet.email, |
| 54 | + primary_alias: false, |
| 55 | + verified_at: Time.current |
| 56 | + ) |
| 57 | + end |
| 58 | + |
| 59 | + def pick_topic |
| 60 | + use_existing = rand < @existing_topic_prob |
| 61 | + existing_topic = Topic.joins(:messages).order("RANDOM()").first if use_existing |
| 62 | + return [existing_topic, existing_topic&.messages&.order("RANDOM()")&.first] if existing_topic |
| 63 | + |
| 64 | + [nil, nil] |
| 65 | + end |
| 66 | + |
| 67 | + def subject_for(topic, reply_to) |
| 68 | + return "Re: #{topic.title}" if topic && reply_to |
| 69 | + return topic.title if topic |
| 70 | + Faker::Hacker.say_something_smart.capitalize |
| 71 | + end |
| 72 | + |
| 73 | + def body_for(reply_to) |
| 74 | + paragraphs = Faker::Lorem.paragraphs(number: rand(2..5)) |
| 75 | + body = paragraphs.join("\n\n") |
| 76 | + if reply_to |
| 77 | + quoted = reply_to.body.to_s.lines.first(4).map { |l| "> #{l.chomp}" }.join("\n") |
| 78 | + body = "#{quoted}\n\n#{body}" |
| 79 | + end |
| 80 | + body |
| 81 | + end |
| 82 | + |
| 83 | + def to_addresses(reply_to, topic) |
| 84 | + recipients = [] |
| 85 | + if reply_to |
| 86 | + recipients << reply_to.sender.email |
| 87 | + elsif topic |
| 88 | + recipients << topic.creator.email |
| 89 | + else |
| 90 | + recipients << Faker::Internet.email |
| 91 | + end |
| 92 | + recipients |
| 93 | + end |
| 94 | + end |
| 95 | +end |
0 commit comments