Commit 163f2be9 by Tô Ngọc Ánh

Merge branch 'ID12-8-9' into 'master'

create ID12  - ID8 - ID9

See merge request !13
parents a88e34a0 41d94cb7
Pipeline #1014 failed with stages
in 0 seconds
.fa-file-upload {
cursor: pointer;
}
\ No newline at end of file
......@@ -20,3 +20,7 @@
border-right: 20px solid white;
border-left: 20px solid transparent;
}
.fa-file-upload {
cursor: pointer;
}
class ApplicationController < ActionController::Base
before_action :store_user_location!, if: :storable_location?
before_action :configure_permitted_parameters, if: :devise_controller?
protected
......@@ -7,4 +8,15 @@ class ApplicationController < ActionController::Base
devise_parameter_sanitizer.permit(:sign_up, keys: [:full_name, :curriculum_vitae])
devise_parameter_sanitizer.permit(:account_update, keys: [:full_name, :curriculum_vitae])
end
private
def storable_location?
request.get? && is_navigational_format? && !devise_controller? && !request.xhr?
end
def store_user_location!
# :user is the scope we are authenticating
store_location_for(:user, request.fullpath)
end
end
class AppliedJobsController < ApplicationController
before_action :authenticate_user!
def index
@applied_jobs = Job.applied_jobs_of(current_user.id).includes(:locations).order(created_at: :asc).page(params[:page])
end
def new
job = Job.find_by(id: params[:job_id])
return redirect_to root_path if job.nil?
......
class FavoritesController < ApplicationController
before_action :authenticate_user!
def index
favorites = current_user.favorites.pluck(:job_id)
@jobs = Job.where(id: favorites).includes(:company, :locations).page(params[:page])
end
def create
@job = Job.find_by(id: params[:job_id])
@favorite = @job.favorites.new(user_id: current_user.id)
@favorite.save
respond_to :js
end
def destroy
@favorite = current_user.favorites.find_by(job_id: params[:job_id])
@favorite.destroy
respond_to :js
end
end
class HistoriesController < ApplicationController
before_action :authenticate_user!
def index
histories = current_user.histories.order(updated_at: :desc).take(History::NUMBER_STORED_HISTORIES).pluck(:job_id)
@jobs = Job.where(id: histories).includes(:company, :locations).sort_by { |job| histories.index(job.id) }
end
end
......@@ -4,13 +4,22 @@ class JobsController < ApplicationController
@industries = Industry.select(:id, :name)
object = params[:model].classify.constantize.find_by_slug(params[:slug])
@keyword = object.try(:name) || object.try(:city)
@jobs = object.jobs.all.includes(:company, :locations, :industries).page(params[:page])
@jobs = object.jobs.all.includes(:company, :locations).page(params[:page])
end
def show
@job = Job.find_by(id: params[:id])
return redirect_to root_path if @job.nil?
return @is_not_applied = true unless user_signed_in?
@is_not_applied = user_signed_in? ? current_user.applied_jobs.find_by(job_id: @job.id).blank? : true
@is_not_applied = current_user.applied_jobs.find_by(job_id: @job.id).blank?
save_history(@job.id)
end
private
def save_history(job_id)
history = current_user.histories.find_or_create_by(job_id: job_id)
history.update_attributes(updated_at: Time.now)
end
end
......@@ -7,7 +7,7 @@ class AppliedJob < ApplicationRecord
validates :full_name, presence: true, length: { maximum: 200 }
validates :email, presence: true, format: { with: EMAIL_REGEXN }
validates :curriculum_vitae, presence: true
validates :user, uniqueness: { scope: :job, message: 'has already applied this job' }
validates :user, uniqueness: { scope: :job, message: 'have already applied this job.' }
mount_uploader :curriculum_vitae, CurriculumVitaeUploader
end
class Favorite < ApplicationRecord
belongs_to :user
belongs_to :job
validates :user, uniqueness: { scope: :job, message: 'have already favorited this job.' }
end
class History < ApplicationRecord
NUMBER_STORED_HISTORIES = 20
belongs_to :user
belongs_to :job
end
class Job < ApplicationRecord
scope :applied_jobs_of, ->(user_id) do
joins(:applied_jobs)
.where("applied_jobs.user_id = #{user_id}")
.select('jobs.*, applied_jobs.created_at as applied_at')
end
NUMBER_LATEST_JOB = 6
WORDS_SHORT_DESCRIPTION = 250
......
......@@ -11,4 +11,8 @@ class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:confirmable
def favorited?(job_id)
favorites.find_by(job_id: job_id).present?
end
end
<div class= "card my-2">
<div class="row">
<div class = "col-lg-10">
<div class='card-body'>
<%= link_to job.title, job_path(job), class: 'card-title font-weight-bold text-decoration-none' %>
<p class='mb-0'>
<strong>Work place:</strong>
<% job.locations.each do |location| %>
<%= location.city %>
<% end %>
</p>
<p><strong>Salary: </strong><%= job.salary %></p>
<p class='card-text'><%= strip_tags(job.description).truncate(Job::WORDS_SHORT_DESCRIPTION) %></p>
</div>
</div>
<div class = "col-lg-2 py-4">
<p><strong>Applied at: </strong></p>
<span><%= job.applied_at.localtime.strftime('%d/%m/%y - %H:%M') %></span>
</div>
</div>
</div>
<div class="my-4">
<h3 class='text-center'>Applied Jobs</h3>
<hr class="divider">
<div class='content'>
<% if @applied_jobs.any? %>
<%= paginate @applied_jobs %>
<%= render partial: 'applied_jobs/applied_job', collection: @applied_jobs, as: :job %>
<%= paginate @applied_jobs %>
<% else %>
<h4 class="text-center">Sorry! We can't found your applied job!</h4>
<% end %>
</div>
</div>
<div id="favorited-<%= job.id %>" class="form-item">
<div class='card flex-md-row align-items-center my-2 p-2'>
<%= radio_button_tag :job_id, job.id %>
<%= render 'shared/job_body', job: job %>
<%= link_to 'Remove', job_favorite_path(job.id),
method: :delete, class: 'btn btn-danger btn-lg', remote: true,
data: { disable_with: '<i class="fa fa-spinner fa-spin"></i>'.html_safe } %>
</div>
</div>
<% if user_signed_in? && current_user.favorited?(job_id) %>
<%= link_to 'Unfavorite', job_favorite_path(job_id),
method: :delete, class: 'btn btn-danger btn-lg', remote: true,
data: { disable_with: '<i class="fa fa-spinner fa-spin"></i>'.html_safe } %>
<% else %>
<%= link_to 'Favorite', job_favorites_path(job_id: job_id),
method: :post, class: 'btn btn-outline-danger btn-lg', remote: true,
data: { disable_with: '<i class="fa fa-spinner fa-spin"></i>'.html_safe } %>
<% end %>
$('#favorite-<%= @job.id %>')
.html("<%= j render 'favorites/link_favorite', job_id: @job.id %>")
$('#sum-favorited').html("<%= current_user.favorites.size %>")
$('#favorite-<%= @favorite.job_id %>')
.html("<%= j render 'favorites/link_favorite', job_id: @favorite.job_id %>")
$('#sum-favorited').html("<%= current_user.favorites.size %>")
$('#favorited-<%= @favorite.job_id %>').remove()
var num_child = $('.form-group .form-item').length
if (num_child == 0) {
var prev = $('a[rel=prev]')
if (prev.length > 0) {
window.location = prev.attr('href')
}
else {
window.location = '<%= favorites_path %>'
}
}
<div class="my-4">
<h3 class='text-center'>Favorited Jobs</h3>
<hr class="divider">
<div class='content'>
<% if @jobs.any? %>
<%= paginate @jobs %>
<%= form_tag new_applied_job_path, method: :get, enforce_utf8: false, class: 'form-group' do %>
<%= render partial: 'favorites/job', collection: @jobs %>
<div class="actions text-center">
<%= submit_tag 'Apply Now', name: nil, class: 'btn btn-outline-success btn-lg' %>
</div>
<% end %>
<%= paginate @jobs %>
<% else %>
<h4 class="text-center">Sorry! We can't found what you want!</h4>
<% end %>
</div>
</div>
<div class='card flex-md-row align-items-center my-2 p-2'>
<%= radio_button_tag :job_id, job.id %>
<%= render 'shared/job_body', job: job %>
</div>
<div class="my-4">
<h3 class='text-center'>History Jobs</h3>
<hr class="divider">
<div class='content'>
<% if @jobs.any? %>
<%= form_tag new_applied_job_path, method: :get, enforce_utf8: false do %>
<%= render partial: 'histories/job', collection: @jobs %>
<div class="actions text-center">
<%= submit_tag 'Apply Now', name: nil, class: 'btn btn-outline-success btn-lg' %>
</div>
<% end %>
<% else %>
<h4 class="text-center">Sorry! We can't found your history job!</h4>
<% end %>
</div>
</div>
<div class='card flex-md-row align-items-center my-2'>
<div class='card-body'>
<%= link_to job.title, job_path(job), class: 'card-title font-weight-bold text-decoration-none' %>
<p class='card-text'><%= job.company.name %></p>
<p class='mb-0'>
<strong>Work place:</strong>
<% job.locations.each do |location| %>
<%= location.city %>
<% end %>
</p>
<p><strong>Salary: </strong><%= job.salary %></p>
<p class='card-text'><%= strip_tags(job.description).truncate(Job::WORDS_SHORT_DESCRIPTION) %></p>
</div>
<div class='btn-favorite p-2'>
<%= link_to 'Favorite', '#', class: 'btn btn-outline-danger btn-lg' %>
<%= render 'shared/job_body', job: job %>
<div id="favorite-<%= job.id %>" class='p-2'>
<%= render 'favorites/link_favorite', job_id: job.id %>
</div>
</div>
<div class='px-5'>
<%= render 'shared/searchbar', my_class: 'd-flex flex-column flex-md-row' %>
</div>
<div>
<div class='content'>
<% if @jobs.any? %>
<div class='message text-center'>
<h3>We found <%= pluralize(@jobs.total_count, 'result') %> for "<%= @keyword %>" </h3>
</div>
<hr>
<div class='content'>
<%= paginate @jobs %>
<%= render partial: 'jobs/job', collection: @jobs %>
<%= paginate @jobs %>
</div>
<% else %>
<h4 class="text-center">Sorry! We can't found what you want!</h4>
<% end %>
</div>
......@@ -32,17 +32,17 @@
</div>
<div class="col-2">
<%= link_to_if @is_not_applied, 'Apply Now', new_applied_job_path(job_id: @job.id), class: 'btn btn-outline-success btn-lg' do %>
<%= link_to 'Apply Now', '#', class: 'btn btn-outline-secondary btn-lg disabled' %>
<%= link_to 'Applied', '#', class: 'btn btn-outline-secondary btn-lg disabled' %>
<% end %>
</div>
</div>
<div class="row my-3">
<div class="col-6 text-right">
<%= link_to_if @is_not_applied, 'Apply Now', new_applied_job_path(job_id: @job.id), class: 'btn btn-outline-success btn-lg' do %>
<%= link_to 'Apply Now', '#', class: 'btn btn-outline-secondary btn-lg disabled' %>
<%= link_to 'Applied', '#', class: 'btn btn-outline-secondary btn-lg disabled' %>
<% end %>
</div>
<div class="col-6 text-left">
<%= link_to 'Favorite', '#', class: 'btn btn-outline-danger btn-lg' %>
<div id="favorite-<%= @job.id %>" class="col-6 text-left">
<%= render 'favorites/link_favorite', job_id: @job.id %>
</div>
</div>
......@@ -10,12 +10,13 @@
<ul class='navbar-nav ml-auto'>
<% if user_signed_in? %>
<li class="nav-item">
<%= link_to '#', class: 'nav-link text-white', title: 'Favorite' do %>
<%= link_to favorites_path, class: 'nav-link text-white', title: 'Favorite' do %>
<small id="sum-favorited"><%= current_user.favorites.size %></small>
<i class="fas fa-heart"></i>
<% end %>
</li>
<li class="nav-item">
<%= link_to '#', class: 'nav-link text-white', title: 'History' do %>
<%= link_to histories_path, class: 'nav-link text-white', title: 'History' do %>
<i class="fas fa-history"></i>
<% end %>
</li>
......
<div class='card-body'>
<%= link_to job.title, job_path(job), class: 'card-title font-weight-bold text-decoration-none' %>
<p class='card-text'><%= job.company.name %></p>
<p class='mb-0'>
<strong>Work place:</strong>
<% job.locations.each do |location| %>
<%= location.city %>
<% end %>
</p>
<p><strong>Salary: </strong><%= job.salary %></p>
<p class='card-text'><%= strip_tags(job.description).truncate(Job::WORDS_SHORT_DESCRIPTION) %></p>
</div>
......@@ -27,7 +27,7 @@
<%= link_to 'Update', edit_user_registration_path, class: 'btn btn-outline-primary btn-lg' %>
</div>
<div class="col text-left">
<%= link_to 'My Jobs', '#', class: 'btn btn-outline-primary btn-lg' %>
<%= link_to 'My Jobs', my_applied_jobs_path, class: 'btn btn-outline-primary btn-lg' %>
</div>
</div>
<% end %>
......
......@@ -73,7 +73,7 @@ Devise.setup do |config|
# config.http_authenticatable = false
# If 401 status code should be returned for AJAX requests. True by default.
# config.http_authenticatable_on_xhr = true
config.http_authenticatable_on_xhr = false
# The realm used in Http Basic Authentication. 'Application' by default.
# config.http_authentication_realm = 'Application'
......@@ -251,7 +251,7 @@ Devise.setup do |config|
# should add them to the navigational formats lists.
#
# The "*/*" below is required to match Internet Explorer requests.
# config.navigational_formats = ['*/*', :html]
config.navigational_formats = ['*/*', :html, :json, :js]
# The default HTTP method used to sign out a resource. Default is :delete.
config.sign_out_via = :delete
......
......@@ -8,10 +8,16 @@ Rails.application.routes.draw do
get 'jobs/:model/:slug', to: 'jobs#index', as: :jobs
get 'my', to: 'users#my_page', as: :my_page
get 'my/jobs', to: 'applied_jobs#index', as: :my_applied_jobs
post 'jobs/:job_id/favorites', to: 'favorites#create', as: :job_favorites
delete 'jobs/:job_id/favorites', to: 'favorites#destroy', as: :job_favorite
resources :favorites, only: :index
resources :histories, only: :index
resources :users, only: :show
get 'apply', to: 'applied_jobs#new', as: :new_applied_job
post 'confirm', to: 'applied_jobs#confirm', as: :confirm_applied_job
post 'finish', to: 'applied_jobs#finish', as: :finish_applied_job
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
namespace :delete_record do
desc 'Delete history when total greater than default limit'
task histories: :environment do
users = User.joins(:histories)
.group(:user_id)
.select('users.id')
.having("count(histories.id) > #{History::NUMBER_STORED_HISTORIES}")
users.each do |user|
break if user.histories.size <= History::NUMBER_STORED_HISTORIES
lastest = user.histories.order(updated_at: :desc).take(History::NUMBER_STORED_HISTORIES).pluck(:id)
user.histories.where.not(id: lastest).delete_all
end
end
end
window.location = '/users/sign_in';
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment