Skip to content

Commit 80b3500

Browse files
Refactor merchant proposal Github issue template
- Create a new `MerchantProposal#to_osm` method to match model keys to OSM ones. - Use JSON instead of YAML to render data as OSM keys uses ":" and YAML keys were confused. - Add a new description section that renders formatted content (eg: \n) and allows easy copy/paste. - Refactor the way proposer email is sent to the mailer to separate it from merchant data.
1 parent afa5cee commit 80b3500

File tree

9 files changed

+158
-115
lines changed

9 files changed

+158
-115
lines changed

app/controllers/merchant_proposals_controller.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ def create
4848
end
4949

5050
MerchantMailer
51-
.with(data: merchant_proposal_params)
51+
.with(
52+
data: @merchant_proposal.to_osm,
53+
proposition_from: @merchant_proposal.proposition_from
54+
)
5255
.send_new_merchant
5356
.deliver_later
5457

app/mailers/merchant_mailer.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ class MerchantMailer < ApplicationMailer
33

44
def send_new_merchant
55
@data = params[:data]
6+
@proposition_from = params[:proposition_from]
67

78
# Store a TXT copy version of the mail in backup waiting
89
# to have a working SMTP configuration.
@@ -11,7 +12,7 @@ def send_new_merchant
1112
data: @data
1213
)
1314

14-
mail reply_to: @data['proposition_from']
15+
mail reply_to: @proposition_from
1516
end
1617

1718
def send_report_merchant

app/models/merchant_proposal.rb

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,76 @@ def other_category_selected?
6868
def decorate
6969
MerchantProposalDecorator.new(self)
7070
end
71+
72+
# Match model attributes to OSM keys
73+
def to_osm
74+
model = decorate
75+
76+
extra_keys = {}
77+
properties = {
78+
name: name,
79+
category: other_category_selected? ? other_category : I18n.t(category, scope: 'categories', default: category),
80+
description: description&.squish
81+
}
82+
83+
# Address and geolocation
84+
properties['addr:street'] = street if street
85+
properties['addr:postcode'] = postcode if postcode
86+
properties['addr:city'] = city if city
87+
88+
if country
89+
properties['addr:country'] = country
90+
extra_keys['country'] = model.pretty_country(show_flag: true)
91+
end
92+
93+
extra_keys['latitude'] = latitude if latitude
94+
extra_keys['longitude'] = longitude if longitude
95+
96+
# Contact
97+
properties[:email] = email if email
98+
properties[:phone] = phone if phone
99+
properties[:website] = website if website
100+
properties[:opening_hours] = opening_hours if opening_hours
101+
102+
# Coins
103+
if 'bitcoin'.in?(coins)
104+
properties['currency:XBT'] = 'yes'
105+
properties['payment:onchain'] = 'yes'
106+
end
107+
108+
properties['currency:XMR'] = 'yes' if 'monero'.in?(coins)
109+
properties['payment:lightning'] = 'yes' if 'lightning'.in?(coins)
110+
properties['payment:lightning_contactless'] = 'yes' if 'contact_less'.in?(coins)
111+
properties['payment:silver'] = 'yes' if 'silver'.in?(coins)
112+
properties['payment:gold'] = 'yes' if 'gold'.in?(coins)
113+
114+
properties['payment:XG1'] = 'yes' if 'june'.in?(coins)
115+
properties['payment:kyc'] = 'yes' if ask_kyc
116+
117+
# Social networks
118+
properties['contact:facebook'] = contact_facebook if contact_facebook
119+
properties['contact:twitter'] = contact_twitter if contact_twitter
120+
properties['contact:telegram'] = contact_telegram if contact_telegram
121+
properties['contact:signal'] = contact_signal if contact_signal
122+
properties['contact:session'] = contact_session if contact_session
123+
properties['contact:odysee'] = contact_odysee if contact_odysee
124+
properties['contact:crowdbunker'] = contact_crowdbunker if contact_crowdbunker
125+
properties['contact:francelibretv'] = contact_francelibretv if contact_francelibretv
126+
properties['contact:tripadvisor'] = contact_tripadvisor if contact_tripadvisor
127+
properties['contact:matrix'] = contact_matrix if contact_matrix
128+
properties['contact:jabber'] = contact_jabber if contact_jabber
129+
properties['contact:youtube'] = contact_youtube if contact_youtube
130+
properties['contact:linkedin'] = contact_linkedin if contact_linkedin
131+
properties['contact:instagram'] = contact_instagram if contact_instagram
132+
properties['contact:tiktok'] = contact_tiktok if contact_tiktok
133+
134+
# Other
135+
properties[:delivery] = 'yes' if delivery
136+
properties[:delivery_zone] = delivery_zone if delivery_zone
137+
properties['survey:date'] = last_survey_on if last_survey_on
138+
139+
properties[:_extra_keys] = extra_keys if extra_keys.present?
140+
141+
properties.as_json.compact_blank
142+
end
71143
end
Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,4 @@
11
class MerchantProposalIssue < ApplicationService
2-
ALLOWED_ATTRIBUTES = %w[
3-
name category other_category
4-
street postcode city country
5-
latitude longitude
6-
phone website description coins ask_kyc
7-
contact_facebook contact_twitter contact_telegram
8-
contact_signal contact_session contact_tripadvisor
9-
contact_matrix contact_jabber contact_youtube
10-
contact_linkedin contact_instagram contact_tiktok
11-
contact_odysee contact_crowdbunker contact_francelibretv
12-
delivery delivery_zone last_survey_on
13-
].freeze
14-
152
attr_reader :merchant_proposal
163

174
def initialize(merchant_proposal)
@@ -36,8 +23,13 @@ def body
3623
<<~MARKDOWN
3724
A new proposition for a merchant has been submitted. Please take a look and add it to OpenStreetMap if relevant:
3825
39-
```yaml
40-
#{attributes.compact.to_yaml}
26+
```json
27+
#{JSON.pretty_generate(merchant_proposal.to_osm)}
28+
```
29+
30+
Description:
31+
```
32+
#{merchant_proposal.description}
4133
```
4234
4335
---
@@ -53,17 +45,4 @@ def labels
5345
I18n.t(I18n.locale, scope: 'languages', locale: :en)
5446
]
5547
end
56-
57-
def attributes
58-
hash = merchant_proposal.attributes.slice(*ALLOWED_ATTRIBUTES)
59-
60-
hash['category'] = if merchant_proposal.other_category_selected?
61-
merchant_proposal.other_category
62-
else
63-
I18n.t(merchant_proposal.category, scope: 'categories', default: merchant_proposal.category)
64-
end
65-
66-
hash['country'] = merchant_proposal.pretty_country if merchant_proposal.country.present?
67-
hash
68-
end
6948
end

app/views/merchant_mailer/send_new_merchant.html.slim

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,7 @@ p Bonjour,
44

55
p Un nouveau commerçant vient d'être proposé depuis le site. Voici les informations renseignées:
66

7-
ul style="background-color: #EEE; padding: 20px; border-radius: 10px"
8-
- @data.each do |data|
9-
- next if data.first == 'nickname'
10-
- next if data.first == 'category' && @data['other_category'].present?
11-
12-
li
13-
strong
14-
= I18n.t(data.first, scope: i18n_scope)
15-
|> :
16-
17-
- if data.first == 'ask_kyc'
18-
- if data.last == 'on'
19-
span style="color: red" Oui
20-
- else
21-
span style="color: green" Non
22-
- else
23-
- case data.last
24-
- when '0'
25-
span style="color: red"= 'Non'
26-
- when '1'
27-
span style="color: green"= 'Oui'
28-
- else
29-
- if data.first == 'coins'
30-
span style="color: green"
31-
= data.last.map { |coin| I18n.t(coin, scope: i18n_scope).delete_suffix(' ?') }.join(', ')
32-
- elsif data.first == 'category'
33-
= I18n.t(data.last, scope: 'categories')
34-
- elsif data.first == 'country'
35-
= pretty_country_html(data.last, show_flag: true)
36-
- else
37-
= data.last
7+
pre= JSON.pretty_generate(@data)
388

399
p style="font-size: 12px; font-style: italic"
4010
| Ce message a été auto-généré par Rails, merci de ne pas y répondre

app/views/merchant_mailer/send_new_merchant.text.slim

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,7 @@
55
| Un nouveau commerçant vient d'être proposé depuis le site. Voici les informations renseignées:
66
= "\n\n"
77

8-
- @data.each do |data|
9-
- next if data.first == 'nickname'
10-
- next if data.first == 'category' && @data['other_category'].present?
11-
12-
= I18n.t(data.first, scope: i18n_scope)
13-
|> :
14-
15-
- case data.last
16-
- when '0'
17-
= 'Non'
18-
- when '1', 'on'
19-
= 'Oui'
20-
- else
21-
- if data.first == 'coins'
22-
= data.last.map { |coin| I18n.t(coin, scope: i18n_scope).delete_suffix(' ?') }.join(', ')
23-
- elsif data.first == 'category'
24-
= I18n.t(data.last, scope: 'categories')
25-
- elsif data.first == 'country'
26-
= pretty_country_html(data.last)
27-
- else
28-
= data.last
29-
= "\n"
8+
== JSON.pretty_generate(@data)
309

3110
= "\n\n"
3211
| Ce message a été auto-généré par Rails, merci de ne pas y répondre

spec/mailers/merchant_mailer_spec.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@
1010
describe '#send_new_merchant' do
1111
subject(:mail) do
1212
described_class
13-
.with(data: merchant_data)
13+
.with(
14+
data: merchant_proposal.to_osm,
15+
proposition_from: 'foobar@example.com'
16+
)
1417
.send_new_merchant
1518
end
1619

17-
let(:merchant_data) do
18-
{
19-
name: 'Great merchant XMR',
20-
proposition_from: 'foobar@example.com'
21-
}.as_json
20+
let(:merchant_proposal) do
21+
build :merchant_proposal,
22+
name: 'Great merchant XMR',
23+
proposition_from: 'foobar@example.com'
2224
end
2325

2426
it 'renders the headers', :aggregate_failures do

spec/mailers/previews/merchant_mailer_preview.rb

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
class MerchantMailerPreview < ActionMailer::Preview
22
def send_new_merchant
3-
data = {
3+
merchant_proposal = MerchantProposal.new(
44
name: 'Carla Wolfe',
55
category: 'jewelry',
66
# category: 'other',
@@ -11,31 +11,36 @@ def send_new_merchant
1111
country: 'CH',
1212
latitude: '46.232192999999995',
1313
longitude: '2.209666999999996',
14-
description: 'Eos est harum archit',
14+
description: "Eos est harum archit\nMy second line",
1515
coins: MerchantProposal::ALLOWED_COINS,
1616
website: 'https://mywebsite.com',
1717
phone: '0102030405',
18-
contact_session: 'Aut esse quis atque',
19-
contact_signal: 'Eum lorem ipsum adi',
20-
contact_matrix: 'Qui et ut neque quis',
21-
contact_jabber: 'Nisi voluptatem Pos',
22-
contact_telegram: 'Nemo Nam magna velit',
23-
contact_facebook: 'Ipsa quisquam iusto',
24-
contact_instagram: 'Nulla asperiores ali',
25-
contact_twitter: 'Alias ut ut ipsam om',
26-
contact_youtube: 'Pariatur Et qui num',
27-
contact_tiktok: 'Quaerat sit libero ',
28-
contact_linkedin: 'Unde quae quia quos ',
29-
contact_tripadvisor: 'Architecto sit simi',
30-
delivery: '0',
18+
contact_session: Faker::Internet.url,
19+
contact_signal: Faker::Internet.url,
20+
contact_matrix: Faker::Internet.url,
21+
contact_jabber: Faker::Internet.url,
22+
contact_telegram: Faker::Internet.url,
23+
contact_facebook: Faker::Internet.url,
24+
contact_instagram: Faker::Internet.url,
25+
contact_twitter: Faker::Internet.url,
26+
contact_youtube: Faker::Internet.url,
27+
contact_tiktok: Faker::Internet.url,
28+
contact_linkedin: Faker::Internet.url,
29+
contact_tripadvisor: Faker::Internet.url,
30+
delivery: '1',
3131
delivery_zone: 'Consequatur sunt se',
3232
last_survey_on: '1993-03-16',
3333
nickname: 'Bot',
3434
ask_kyc: '1',
3535
proposition_from: 'johndoe@example.com'
36-
}.as_json
36+
)
3737

38-
MerchantMailer.with(data: data).send_new_merchant
38+
MerchantMailer
39+
.with(
40+
data: merchant_proposal.to_osm,
41+
proposition_from: 'johndoe@example.com'
42+
)
43+
.send_new_merchant
3944
end
4045

4146
def send_report_merchant

spec/requests/merchant_proposals_spec.rb

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@
3434
let(:params) do
3535
{
3636
merchant_proposal: {
37-
name: 'Foobar name',
38-
street: 'Foobar',
39-
postcode: 'Foobar',
40-
city: 'Foobar',
37+
name: 'Bonhomme de Bois',
38+
street: '1 Toys street',
39+
postcode: '1234',
40+
city: 'Toyzz',
4141
country: 'FR',
42-
category: 'dentist',
43-
description: 'Foobar description',
42+
category: 'toys',
43+
description: "Best toys.\nSolid.\nKids and olders.",
4444
coins: %w[bitcoin monero],
45-
contact_odysee: 'https://www.odysee.com/JohnDoe'
45+
contact_odysee: 'https://www.odysee.com/WoodToys'
4646
}
4747
}
4848
end
@@ -51,8 +51,40 @@
5151
before do
5252
stub_request(:post, /api.github.com/)
5353
.with(body: {
54-
title: 'Proposal for a new merchant: `Foobar name`',
55-
body: "A new proposition for a merchant has been submitted. Please take a look and add it to OpenStreetMap if relevant:\n\n```yaml\n---\nname: Foobar name\ncategory: Dentist\nstreet: Foobar\npostcode: Foobar\ncity: Foobar\ncountry: France\ndescription: Foobar description\ncoins:\n- bitcoin\n- monero\nask_kyc: false\ncontact_odysee: https://www.odysee.com/JohnDoe\ndelivery: false\n\n```\n\n---\n\n*Note: this issue has been automatically opened from bank-exit website using the Github API.*\n",
54+
title: 'Proposal for a new merchant: `Bonhomme de Bois`',
55+
body: <<~MARKDOWN,
56+
A new proposition for a merchant has been submitted. Please take a look and add it to OpenStreetMap if relevant:
57+
58+
```json
59+
{
60+
"name": "Bonhomme de Bois",
61+
"category": "Toy",
62+
"description": "Best toys. Solid. Kids and olders.",
63+
"addr:street": "1 Toys street",
64+
"addr:postcode": "1234",
65+
"addr:city": "Toyzz",
66+
"addr:country": "FR",
67+
"currency:XBT": "yes",
68+
"payment:onchain": "yes",
69+
"currency:XMR": "yes",
70+
"contact:odysee": "https://www.odysee.com/WoodToys",
71+
"_extra_keys": {
72+
"country": "🇫🇷 France"
73+
}
74+
}
75+
```
76+
77+
Description:
78+
```
79+
Best toys.
80+
Solid.
81+
Kids and olders.
82+
```
83+
84+
---
85+
86+
*Note: this issue has been automatically opened from bank-exit website using the Github API.*
87+
MARKDOWN
5688
labels: %w[merchant proposal english]
5789
}.to_json)
5890
end

0 commit comments

Comments
 (0)