Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#5][Backend] As a User, I can sign up and sign in/out with a username and password #33

Merged
merged 57 commits into from Jun 16, 2021
Merged
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
c2aa3e5
[#4] Fix name of Heroku app and use GitHub token for Docker Registry
malparty Jun 8, 2021
6977569
[#4] Fix develop branch name for production test workflow
malparty Jun 8, 2021
9478cca
[#4] Update precompiled ENV variable to fix app crash on Heroku
malparty Jun 8, 2021
565cea9
[#4] Reset SECRET_KEY_BASE and add defaults for docker_build in datab…
malparty Jun 8, 2021
5e4c4b1
[#4] Add default route and empty controller-view to test deployment
malparty Jun 9, 2021
5962a2e
[#4] Remove unused tests and helpers
malparty Jun 9, 2021
5da306d
[#5] Edit default from email
malparty Jun 9, 2021
7175a1d
[#5] Add flash notice-alert in view layout
malparty Jun 9, 2021
50076a3
[#5] Generate basic User model from Devise
malparty Jun 9, 2021
10cbeea
[#5] Add firstname lastname to User
malparty Jun 9, 2021
b6ae354
[#5] Generate Devise views
malparty Jun 9, 2021
3b359ae
[#5] Add lastname and firstname to registration views
malparty Jun 9, 2021
f310bfd
[#4] Rename keyword controller to plural and use resources base route
malparty Jun 9, 2021
5699040
[#4] Re-add root route
malparty Jun 9, 2021
3d8c6f4
[#293] Merge from setup-deploy branch to get empty view
malparty Jun 9, 2021
7147cf9
[#293] Add logout button
malparty Jun 9, 2021
c2c642b
[#293] Add before_action authenticate_user
malparty Jun 9, 2021
d656a8d
[#293] Setup DoorKeeper to embbed OAuth2
malparty Jun 9, 2021
38e6db8
[#293] Setup DoorKeeper to embbed OAuth2
malparty Jun 9, 2021
95ba16a
Merge branch 'develop' into chore/setup-deployment
malparty Jun 10, 2021
8d72780
[#4] Add new line after root route
malparty Jun 10, 2021
158b80a
[#4] Remove new line after root route
malparty Jun 10, 2021
5047a67
[#4] Remove trailing space
malparty Jun 10, 2021
ce4f855
[#4] Pull from GitHub
malparty Jun 10, 2021
6854d81
[#4] Add staging/prod url in Readme.me
malparty Jun 10, 2021
b010fbd
[#4] Add aboud at the end of Readme.md
malparty Jun 10, 2021
145411b
[#5] Hide sign out button when not logged
malparty Jun 10, 2021
98a6af2
Merge pull request #32 from malparty/chore/setup-deployment
malparty Jun 10, 2021
b49d334
[#5] Edit default from email
malparty Jun 9, 2021
271ef92
[#5] Add flash notice-alert in view layout
malparty Jun 9, 2021
111bad2
[#5] Rebase from Config Deployment
malparty Jun 10, 2021
574b467
[#5] Add firstname lastname to User
malparty Jun 9, 2021
d150da1
[#5] Generate Devise views
malparty Jun 9, 2021
a57d6da
[#5] Add lastname and firstname to registration views
malparty Jun 9, 2021
3dbcb86
[#293] Add logout button
malparty Jun 9, 2021
bfe7091
[#293] Add before_action authenticate_user
malparty Jun 9, 2021
3131f03
[#293] Setup DoorKeeper to embbed OAuth2
malparty Jun 9, 2021
5fc126d
[#293] Setup DoorKeeper to embbed OAuth2
malparty Jun 9, 2021
f0a6257
[#5] Hide sign out button when not logged
malparty Jun 10, 2021
5d398cb
Merge branch 'feature/user-login-backend' of https://github.com/malpa…
malparty Jun 10, 2021
53ea9b7
[#5] Add user db seed for system tests
malparty Jun 10, 2021
e7389a9
[#5] Add login system tests
malparty Jun 10, 2021
ad3fab5
[#5] Fix missing password_confirmation param in sign_up request
malparty Jun 11, 2021
49e917b
[#5] Add login and signup system tests
malparty Jun 11, 2021
557c936
[#5] Update system tests to use faster sign_in method helper
malparty Jun 14, 2021
d9a84e0
[#5] Add FFaker to fabricate users
malparty Jun 14, 2021
a52174d
[#5] Fix english mistakes in tests
malparty Jun 14, 2021
7f93b22
[#5] Remove duplicated email validation rule
malparty Jun 14, 2021
3408c30
[#5] Add missing line break in tests
malparty Jun 14, 2021
220792f
root commit
malparty Jun 11, 2021
4d46c2d
[#5] Remove module prefix I18n in views
malparty Jun 14, 2021
99a488b
[#5] Update email db type to citext
malparty Jun 14, 2021
3471a43
[#5] Rename lastname/firstname into last_name first_name
malparty Jun 14, 2021
76dd4ee
[#5] Fix missing renaming for lastname firstname
malparty Jun 14, 2021
2c92306
[#5] Fix spacing for clarity in authentication helper
malparty Jun 14, 2021
39f17ff
[#5] Merge email (citext) and renaming names into previous db migrations
malparty Jun 14, 2021
ff83bd7
[#5] Merge email (citext) and renaming names into previous db migrations
malparty Jun 14, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/deploy_heroku.yml
Expand Up @@ -7,15 +7,15 @@ on:
branches:
- master
- main
- development
- develop
types:
- completed
workflow_dispatch:

env:
DOCKER_REGISTRY_HOST: ${{ secrets.DOCKER_REGISTRY_HOST }}
DOCKER_REGISTRY_USERNAME: ${{ github.repository_owner }}
DOCKER_REGISTRY_TOKEN: ${{ secrets.DOCKER_REGISTRY_TOKEN }}
DOCKER_REGISTRY_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DOCKER_IMAGE: ${{ github.repository }}
HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}

Expand All @@ -42,9 +42,9 @@ jobs:
run: |
if [[ $BRANCH_TAG = "latest" ]]
then
echo "HEROKU_APP=google_search_ruby" >> $GITHUB_ENV
echo "HEROKU_APP=google-search-ruby" >> $GITHUB_ENV
else
echo "HEROKU_APP=google_search_ruby-staging" >> $GITHUB_ENV
echo "HEROKU_APP=google-search-ruby-staging" >> $GITHUB_ENV
fi

- name: Login to Docker registry
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test_production_build.yml
Expand Up @@ -5,7 +5,7 @@ on:
branches-ignore:
- master
- main
- development
- develop

env:
DOCKER_REGISTRY_HOST: ${{ secrets.DOCKER_REGISTRY_HOST }}
Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Expand Up @@ -17,6 +17,7 @@ gem 'i18n-js', '3.5.1' # A library to provide the I18n translations on the Javas
# Authentications & Authorizations
gem 'devise' # Authentication solution for Rails with Warden
gem 'pundit' # Minimal authorization through OO design and pure Ruby classes
gem 'doorkeeper' # Awesome OAuth 2 provider for your Rails / Grape app
malparty marked this conversation as resolved.
Show resolved Hide resolved

# Assets
gem 'webpacker', '~>5.2.0' # Transpile app-like JavaScript
Expand Down Expand Up @@ -52,6 +53,7 @@ group :development, :test do
gem 'rubocop-rails', require: false # A RuboCop extension focused on enforcing Rails best practices and coding conventions.
gem 'rubocop-rspec', require: false # Code style checking for RSpec files
gem 'rubocop-performance', require: false # An extension of RuboCop focused on code performance checks.
gem 'ffaker' # used to easily generate fake data: names, addresses, phone numbers, etc.

gem 'undercover' # Report missing test coverage in new changes
gem 'danger' # Automated code review.
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Expand Up @@ -157,6 +157,8 @@ GEM
warden (~> 1.2.3)
diff-lcs (1.4.4)
docile (1.4.0)
doorkeeper (5.5.1)
railties (>= 5)
erubi (1.10.0)
erubis (2.7.0)
fabrication (2.22.0)
Expand Down Expand Up @@ -480,6 +482,7 @@ DEPENDENCIES
danger-undercover
database_cleaner
devise
doorkeeper
fabrication
ffaker
figaro
Expand Down
14 changes: 14 additions & 0 deletions README.md
Expand Up @@ -4,6 +4,12 @@
> Google Search Ruby is a Web app that extract large amounts of data from the Google search results page.
> Feed it with a CSV File containing your keywords, and the app will do the rest for you!

## Web Application

[Staging](https://google-search-ruby-staging.herokuapp.com/)

[Production](https://google-search-ruby.herokuapp.com/)

## Project Setup

### Prerequisites
Expand Down Expand Up @@ -114,3 +120,11 @@ rspec [rspec-params]

- Create a [Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token)
from bot account with `public_repo` scope, and set it as `DANGER_GITHUB_API_TOKEN` secret on the CI Environment Settings.


## About
![Nimble](https://assets.nimblehq.co/logo/dark/logo-dark-text-160.png)

This project is created to complete **Web Certification Path** using **Ruby** at [Nimble][nimble]

[nimble]: https://nimblehq.co
16 changes: 16 additions & 0 deletions app/controllers/application_controller.rb
Expand Up @@ -2,4 +2,20 @@

class ApplicationController < ActionController::Base
include Localization

protect_from_forgery with: :exception

before_action :authenticate_user!
before_action :update_allowed_parameters, if: :devise_controller?

protected

def update_allowed_parameters
devise_parameter_sanitizer.permit(:sign_up) do |u|
Copy link

@github-actions github-actions bot Jun 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Has the variable name 'u'

u.permit(:firstname, :lastname, :email, :password, :password_confirmation)
end
devise_parameter_sanitizer.permit(:account_update) do |u|
Copy link

@github-actions github-actions bot Jun 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Has the variable name 'u'

u.permit(:firstname, :lastname, :email, :password, :current_password)
end
end
end
5 changes: 5 additions & 0 deletions app/controllers/keywords_controller.rb
@@ -0,0 +1,5 @@
# frozen_string_literal: true

class KeywordsController < ApplicationController
def index; end
end
14 changes: 14 additions & 0 deletions app/models/user.rb
@@ -0,0 +1,14 @@
# frozen_string_literal: true

class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable

# the authenticate method from devise documentation
def self.authenticate(email, password)
malparty marked this conversation as resolved.
Show resolved Hide resolved
user = User.find_for_authentication(email: email)
user&.valid_password?(password) ? user : nil
malparty marked this conversation as resolved.
Show resolved Hide resolved
end
end
16 changes: 16 additions & 0 deletions app/views/devise/confirmations/new.html.erb
@@ -0,0 +1,16 @@
<h2>Resend confirmation instructions</h2>

<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>

<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %>
</div>

<div class="actions">
<%= f.submit "Resend confirmation instructions" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
5 changes: 5 additions & 0 deletions app/views/devise/mailer/confirmation_instructions.html.erb
@@ -0,0 +1,5 @@
<p>Welcome <%= @email %>!</p>

<p>You can confirm your account email through the link below:</p>

<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
7 changes: 7 additions & 0 deletions app/views/devise/mailer/email_changed.html.erb
@@ -0,0 +1,7 @@
<p>Hello <%= @email %>!</p>

<% if @resource.try(:unconfirmed_email?) %>
<p>We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.</p>
<% else %>
<p>We're contacting you to notify you that your email has been changed to <%= @resource.email %>.</p>
<% end %>
3 changes: 3 additions & 0 deletions app/views/devise/mailer/password_change.html.erb
@@ -0,0 +1,3 @@
<p>Hello <%= @resource.email %>!</p>

<p>We're contacting you to notify you that your password has been changed.</p>
8 changes: 8 additions & 0 deletions app/views/devise/mailer/reset_password_instructions.html.erb
@@ -0,0 +1,8 @@
<p>Hello <%= @resource.email %>!</p>

<p>Someone has requested a link to change your password. You can do this through the link below.</p>

<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>

<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>
7 changes: 7 additions & 0 deletions app/views/devise/mailer/unlock_instructions.html.erb
@@ -0,0 +1,7 @@
<p>Hello <%= @resource.email %>!</p>

<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>

<p>Click the link below to unlock your account:</p>

<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %></p>
25 changes: 25 additions & 0 deletions app/views/devise/passwords/edit.html.erb
@@ -0,0 +1,25 @@
<h2>Change your password</h2>

<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<%= f.hidden_field :reset_password_token %>

<div class="field">
<%= f.label :password, "New password" %><br />
<% if @minimum_password_length %>
<em>(<%= @minimum_password_length %> characters minimum)</em><br />
<% end %>
<%= f.password_field :password, autofocus: true, autocomplete: "new-password" %>
</div>

<div class="field">
<%= f.label :password_confirmation, "Confirm new password" %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>

<div class="actions">
<%= f.submit "Change my password" %>
</div>
<% end %>

<%= render "devise/shared/links" %>
16 changes: 16 additions & 0 deletions app/views/devise/passwords/new.html.erb
@@ -0,0 +1,16 @@
<h2>Forgot your password?</h2>

<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>

<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>

<div class="actions">
<%= f.submit "Send me reset password instructions" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
53 changes: 53 additions & 0 deletions app/views/devise/registrations/edit.html.erb
@@ -0,0 +1,53 @@
<h2>Edit <%= resource_name.to_s.humanize %></h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>

<div class="field">
<%= f.label :firstname %><br />
<%= f.text_field :firstname, autofocus: true %>
</div>

<div class="field">
<%= f.label :lastname %><br />
<%= f.text_field :lastname %>
</div>

<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autocomplete: "email" %>
</div>

<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>

<div class="field">
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, autocomplete: "new-password" %>
<% if @minimum_password_length %>
<br />
<em><%= @minimum_password_length %> characters minimum</em>
<% end %>
</div>

<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>

<div class="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password, autocomplete: "current-password" %>
</div>

<div class="actions">
<%= f.submit "Update" %>
</div>
<% end %>

<h3>Cancel my account</h3>

<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>

<%= link_to "Back", :back %>
39 changes: 39 additions & 0 deletions app/views/devise/registrations/new.html.erb
@@ -0,0 +1,39 @@
<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>

<div class="field">
<%= f.label :firstname %><br />
<%= f.text_field :firstname, autofocus: true %>
</div>

<div class="field">
<%= f.label :lastname %><br />
<%= f.text_field :lastname %>
</div>

<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autocomplete: "email" %>
</div>

<div class="field">
<%= f.label :password %>
<% if @minimum_password_length %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "new-password" %>
</div>

<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>

<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>

<%= render "devise/shared/links" %>
26 changes: 26 additions & 0 deletions app/views/devise/sessions/new.html.erb
@@ -0,0 +1,26 @@
<h2>Log in</h2>

<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>

<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password, autocomplete: "current-password" %>
</div>

<% if devise_mapping.rememberable? %>
<div class="field">
<%= f.check_box :remember_me %>
<%= f.label :remember_me %>
</div>
<% end %>

<div class="actions">
<%= f.submit "Log in" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
15 changes: 15 additions & 0 deletions app/views/devise/shared/_error_messages.html.erb
@@ -0,0 +1,15 @@
<% if resource.errors.any? %>
<div id="error_explanation">
<h2>
<%= I18n.t("errors.messages.not_saved",
malparty marked this conversation as resolved.
Show resolved Hide resolved
count: resource.errors.count,
resource: resource.class.model_name.human.downcase)
%>
</h2>
<ul>
<% resource.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
25 changes: 25 additions & 0 deletions app/views/devise/shared/_links.html.erb
@@ -0,0 +1,25 @@
<%- if controller_name != 'sessions' %>
<%= link_to "Log in", new_session_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
<%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post %><br />
<% end %>
<% end %>