Skip to content

Commit

Permalink
Merge pull request #259 from kortirso/issue_250
Browse files Browse the repository at this point in the history
IS-250 added subscribing for newslist
  • Loading branch information
kortirso authored Feb 20, 2024
2 parents 697e84c + c87fc49 commit 9ad9130
Show file tree
Hide file tree
Showing 32 changed files with 476 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## Unreleased
### Added
- third pricing plan for enterprise clients
- subscribing for newslist

### Modified
- titles and descriptions for landing page
Expand Down
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ gem 'jsonapi-serializer', '2.2.0'
# notification layer
gem 'active_delivery'

# antibot captcha
gem 'recaptcha', require: 'recaptcha/rails'

group :development, :test do
gem 'bullet', git: 'https://github.com/flyerhzm/bullet', branch: 'main'
gem 'cypress-on-rails', '~> 1.0'
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ GEM
rake (13.1.0)
rdoc (6.6.2)
psych (>= 4.0.0)
recaptcha (5.16.0)
redis (5.1.0)
redis-client (>= 0.17.0)
redis-actionpack (5.4.0)
Expand Down Expand Up @@ -510,6 +511,7 @@ DEPENDENCIES
rackup (~> 2.1)
rails (~> 7.1)
rails-controller-testing (= 1.0.5)
recaptcha
redis (~> 5.0)
redis-rack!
redis-rails!
Expand Down
15 changes: 15 additions & 0 deletions app/contracts/subscribers/create_contract.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

module Subscribers
class CreateContract < ApplicationContract
config.messages.namespace = :subscriber

params do
required(:email).filled(:string)
end

rule(:email) do
key.failure(:invalid) unless /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i.match?(value)
end
end
end
29 changes: 29 additions & 0 deletions app/controllers/subscribers/unsubscribes_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

module Subscribers
class UnsubscribesController < ApplicationController
skip_before_action :authenticate
before_action :find_subscriber
before_action :check_unsubscribe_token

def show
# commento: subscribers.unsubscribe_token, subscribers.unsubscribed_at
@subscriber.update!(unsubscribe_token: nil, unsubscribed_at: DateTime.now)
end

private

def find_subscriber
@subscriber = Subscriber.find_by(email: params[:email])
return if @subscriber

redirect_to root_path, alert: 'Unsubscribing can not be done'
end

def check_unsubscribe_token
return if @subscriber.unsubscribe_token == params[:unsubscribe_token]

redirect_to root_path, alert: 'Unsubscribe token is invalid'
end
end
end
50 changes: 50 additions & 0 deletions app/controllers/subscribers_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

class SubscribersController < ApplicationController
include Deps[create_form: 'forms.subscribers.create']

skip_before_action :authenticate
before_action :check_recaptcha, only: %i[create]
before_action :check_double_subscribing, only: %i[create]
before_action :find_existing_subscriber, only: %i[create]

def create
# commento: subscribers.email
case create_form.call(params: subscriber_params)
in { errors: errors } then redirect_to root_path, alert: errors
else
set_subscriber_in_cookies
redirect_to root_path, notice: 'You are successfully subscribed for news'
end
end

private

def check_recaptcha
redirect_to root_path unless verify_recaptcha
end

def check_double_subscribing
return unless cookies[:pullmetry_subscriber_email]

redirect_to root_path, alert: 'You can not subscribe for news twice'
end

def find_existing_subscriber
return unless Subscriber.exists?(email: subscriber_params[:email])

redirect_to root_path, alert: 'This email can not subscribe for news'
end

# to avoid subscribing one visitor with many emails
def set_subscriber_in_cookies
cookies[:pullmetry_subscriber_email] = {
value: subscriber_params[:email],
expires: 1.month.from_now
}
end

def subscriber_params
params.require(:subscriber).permit(:email)
end
end
17 changes: 17 additions & 0 deletions app/forms/subscribers/create_form.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

module Subscribers
class CreateForm
include Deps[validator: 'validators.subscribers.create']

def call(params:)
errors = validator.call(params: params)
return { errors: errors } if errors.any?

result = Subscriber.create!(params)
SubscribersMailer.create_email(id: result.id).deliver_later

{ result: result }
end
end
end
13 changes: 13 additions & 0 deletions app/mailers/subscribers_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

class SubscribersMailer < ApplicationMailer
def create_email(args={})
@subscriber = Subscriber.find_by(id: args[:id])
return if @subscriber.nil?

mail(
to: @subscriber.email,
subject: 'PullKeeper: subscribing is confirmed'
)
end
end
7 changes: 7 additions & 0 deletions app/models/subscriber.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class Subscriber < ApplicationRecord
include ActiveModel::SecurePassword

has_secure_token :unsubscribe_token, length: 24
end
7 changes: 7 additions & 0 deletions app/validators/subscribers/create_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

module Subscribers
class CreateValidator < ApplicationValidator
include Deps[contract: 'contracts.subscribers.create']
end
end
5 changes: 5 additions & 0 deletions app/views/controllers/subscribers/unsubscribes/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<%= render PageWrappers::GuestComponent.new do %>
<div class="flex flex-1 justify-center items-center">
<p class="text-2xl uppercase">Subscription for newslist is canceled</p>
</div>
<% end %>
23 changes: 21 additions & 2 deletions app/views/controllers/welcome/index.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<%= render PageWrappers::GuestComponent.new do %>
<section class="grid grid-cols-1 xl:grid-cols-2 gap-8 mx-auto mt-16 mb-8 xl:mt-24 xl:mb-16">
<div class="flex-1 flex flex-col justify-center">
<div class="flex flex-col justify-center">
<h1 class="text-center lg:text-left">Get the PR statistics you always needed</h1>
<p class="text-lg leading-8 mb-4 text-center lg:text-left">Monitor pull requests for your repositories and get relevant statistics for reviewing and commenting on pull requests. Inspire developers to self-optimize and highlight their achievements and successes.</p>
<% unless Current.user %>
Expand All @@ -10,7 +10,7 @@
</div>
<% end %>
</div>
<div class="flex-1 flex justify-center">
<div class="flex justify-center">
<div class="welcome-image">
<%= image_tag 'screenshot.webp', width: 616, height: 355, alt: 'interface-example' %>
</div>
Expand Down Expand Up @@ -70,6 +70,25 @@
<p class="mb-4 text-lg">If you have any suggestions then you can create issue at <a href="https://github.com/kortirso/pullmetry/issues" target="_blank" rel="noopener noreferrer" class="simple-link">Github issues</a>.</p>
<p class="text-lg">You can fork repository, run it locally or even run it on your own production server.</p>
</section>
<% unless cookies[:pullmetry_subscriber_email] %>
<div class="flex justify-center items-center mb-24">
<div class="p-8 border border-stone-200 rounded flex flex-col items-center">
<h2>Join newslist</h2>
<p class="mb-4">Receive latest project news about releases and new features.</p>
<%= form_with model: Subscriber.new, url: subscribers_path, method: :post, class: 'form-block' do |form| %>
<div class="flex flex-row gap-4 mb-8">
<div class="form-field m-0">
<%= form.text_field :email, required: true, placeholder: 'Email', class: 'form-value', data: { 'test-id' => 'join-newslist-email-value' } %>
</div>
<%= form.submit 'Join', class: 'btn-primary btn-small', data: { 'test-id' => 'join-newslist-link' } %>
</div>
<div class="form-field m-0">
<%= recaptcha_tags %>
</div>
<% end %>
</div>
</div>
<% end %>
<section class="mx-auto mb-8 xl:mb-24">
<h2 class="text-center text-4xl mb-12">How it works</h2>
<div class="flex flex-col-reverse md:flex-row md:gap-20 mb-12">
Expand Down
4 changes: 4 additions & 0 deletions app/views/mailers/subscribers_mailer/create_email.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<p>Greeting, dear user!</p>
<p>Your subscription for our newslist is confirmed.</p>
<br />
<p>If it was not you or you would like to cancel subscription - please click <%= link_to 'link', subscribers_unsubscribe_url(email: @subscriber.email, unsubscribe_token: @subscriber.unsubscribe_token) %>.</p>
5 changes: 5 additions & 0 deletions app/views/mailers/subscribers_mailer/create_email.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Greeting, dear user!

Your subscription for our newslist is confirmed.

If it was not you or you would like to cancel subscription - please click <%= subscribers_unsubscribe_url(email: @subscriber.email, unsubscribe_token: @subscriber.unsubscribe_token) %>.
2 changes: 1 addition & 1 deletion config/credentials.yml.enc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
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--dPwYH4CXXMIagkU6--spNWWdNUJI2M8JoJrBNncQ==
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--kGuGn75gos6i8Qkq--OFfjuaIAiVFvVpdgVt0bSg==
3 changes: 3 additions & 0 deletions config/initializers/container.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def register(key)
register('contracts.notification') { NotificationContract.new }
register('contracts.excludes.rule') { Excludes::RuleContract.new }
register('contracts.invite') { InviteContract.new }
register('contracts.subscribers.create') { Subscribers::CreateContract.new }

# validators
register('validators.companies.create') { Companies::CreateValidator.new }
Expand All @@ -53,6 +54,7 @@ def register(key)
register('validators.notification') { NotificationValidator.new }
register('validators.excludes.rules.create') { Excludes::Rules::CreateValidator.new }
register('validators.invite') { InviteValidator.new }
register('validators.subscribers.create') { Subscribers::CreateValidator.new }

# forms
register('forms.companies.create') { Companies::CreateForm.new }
Expand All @@ -66,6 +68,7 @@ def register(key)
register('forms.notifications.create') { Notifications::CreateForm.new }
register('forms.excludes.groups.create') { Excludes::Groups::CreateForm.new }
register('forms.invites.create') { Invites::CreateForm.new }
register('forms.subscribers.create') { Subscribers::CreateForm.new }

# notifiers
register('notifiers.slack_webhooks.admin.job_execution_report_payload') {
Expand Down
6 changes: 6 additions & 0 deletions config/initializers/recaptcha.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

Recaptcha.configure do |config|
config.site_key = Rails.application.credentials.dig(:recaptcha, :public)
config.secret_key = Rails.application.credentials.dig(:recaptcha, :private)
end
4 changes: 4 additions & 0 deletions config/locales/errors.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ en:
excludes_rule: Exclude rule
link: Link
errors:
subscriber:
rules:
email:
invalid: has invalid format
company:
rules:
title:
Expand Down
4 changes: 4 additions & 0 deletions config/locales/errors.ru.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ ru:
excludes_rule: Исключение
link: Ссылка
errors:
subscriber:
rules:
email:
invalid: неверный формат
company:
rules:
title:
Expand Down
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
resource :profile, only: %i[show update destroy]
resource :achievements, only: %i[show]
resources :identities, only: %i[destroy]
resources :subscribers, only: %i[create]
namespace :subscribers do
resource :unsubscribe, only: %i[show]
end

post 'subscriptions/trial', to: 'subscriptions/trial#create'

Expand Down
10 changes: 10 additions & 0 deletions db/migrate/20240220110817_create_subscribers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateSubscribers < ActiveRecord::Migration[7.1]
def change
create_table :subscribers do |t|
t.string :email, null: false, index: { unique: true }
t.string :unsubscribe_token
t.datetime :unsubscribed_at
t.timestamps
end
end
end
Loading

0 comments on commit 9ad9130

Please sign in to comment.