Commit 15f96a1e by Ba Toi Dang

Merge branch 'features/create_admin_page' into 'master'

Create admin page

See merge request !8
parents df28a349 14fbc146
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
//= require_tree . //= require_tree .
//= require javascripts/jquery-3.2.1.min.js //= require javascripts/jquery-3.2.1.min.js
//= require javascripts/bootstrap.min.js //= require javascripts/bootstrap.min.js
//= require javascripts/bootstrap.min.js
//= require bootstrap-datetimepicker.min.js
$(document).ready(function(){ $(document).ready(function(){
$('.message').delay(5000).fadeOut('slow'); $('.message').delay(5000).fadeOut('slow');
...@@ -21,4 +23,21 @@ $(document).ready(function(){ ...@@ -21,4 +23,21 @@ $(document).ready(function(){
event.preventDefault(); event.preventDefault();
$('#apply').removeAttr('disabled') $('#apply').removeAttr('disabled')
}); });
$('.form_date').datetimepicker({
language: 'en',
weekStart: 1,
todayBtn: 1,
autoclose: 1,
todayHighlight: 1,
startView: 2,
minView: 2,
forceParse: 0
});
// set min-height css for content
windowHeight = $(document).height();
menuHeight = $('.navbar').height();
footHeight = $('.footer').height();
$('.content').css("min-height", windowHeight - (menuHeight + footHeight))
}); });
@import "stylesheets/bootstrap-theme.min.css"; @import "bootstrap-theme.min.css";
@import "stylesheets/bootstrap.min.css"; @import "bootstrap.min.css";
@import "stylesheets/font-awesome.css"; @import "stylesheets/font-awesome.css";
@import "bootstrap-datetimepicker.min.css";
body{ body{
...@@ -36,6 +37,9 @@ body{ ...@@ -36,6 +37,9 @@ body{
.wid80{ .wid80{
width: 80% !important; width: 80% !important;
} }
.mt-20{
margin-top: 20px;
}
.mrTop5{ .mrTop5{
margin-top: 5px; margin-top: 5px;
......
require 'rsolr'
require "csv"
class Admins::AppliesController < ApplicationController class Admins::AppliesController < ApplicationController
before_action :authenticate_admin!
def index def index
if params[:commit]
condition = get_condition
response = query(condition)
job_ids = response["response"]["docs"].pluck("id")
application_count = response["response"]["numFound"]
applications = ApplyJob.where(job_id: job_ids).includes(:job, :user)
@applications = Kaminari.paginate_array(applications, total_count: application_count).page(params[:page])
if params[:commit].eql? 'Down csv'
down_csv(@applications)
return
end
else
# get applications
@applications = ApplyJob.includes(:job, :user).page(params[:page])
end
end
def down_csv(applications)
send_data ApplyJob.to_csv(applications), filename: "applications-#{Date.today}.csv"
end
def down_cv_candidate
user = User.find(params[:user_id])
if user.cv.file.exists?
send_file user.cv.path
else
flash[:notice] = 'File not exist!'
redirect_back(fallback_location: root_path)
end
end
private
def solr_connect
@solr ||= RSolr.connect url: Settings.rsolr.url
end
def query(condition)
# use get method to query
response = solr_connect.get 'select', params: condition
response
end
def get_condition
condition = {}
filter_query = []
date_from = '*'
date_to = 'NOW'
condition[:fl] = "id"
start = params[:page].to_i > 1 ? params[:page].to_i - 1 : 0
# get condition
condition[:q] = "email:[* TO *]"
condition[:start] = Settings.top.job_per_history_page * start
condition[:rows] = Settings.top.job_per_history_page
filter_query << "email:\"#{params[:email]}\"" if params[:email]
filter_query << "city_name:\"#{params[:city]}\"" unless params[:city].blank?
filter_query << "industry:\"#{params[:industry]}\"" unless params[:industry].blank?
# generate condition from params[:date]
date_from = "#{params[:dtp_input1]}T00:00:00Z" unless params[:dtp_input1].blank?
date_to = "#{params[:dtp_input2]}T00:00:00Z" unless params[:dtp_input2].blank?
filter_query << "applied_at:[#{date_from} TO #{date_to}]"
condition[:fq] = filter_query
condition
end end
end end
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
protect_from_forgery with: :exception protect_from_forgery with: :exception
helper_method :clear_session_candidate
def clear_session_candidate def clear_session_candidate
session[:candidate] = {} session[:candidate] = {}
...@@ -14,4 +13,11 @@ class ApplicationController < ActionController::Base ...@@ -14,4 +13,11 @@ class ApplicationController < ActionController::Base
super super
end end
end end
def admin_can_not_do_this
if current_admin
flash[:notice] = "Admin can't do this"
redirect_back(fallback_location: root_path)
end
end
end end
class AppliesController < ApplicationController class AppliesController < ApplicationController
before_action :admin_can_not_do_this
before_action :authenticate_user! before_action :authenticate_user!
def apply def apply
session[:job_id] = params[:job_id] if params[:job_id] session[:job_id] = params[:job_id] if params[:job_id]
......
class FavoritesController < ApplicationController class FavoritesController < ApplicationController
before_action :admin_can_not_do_this
before_action :authenticate_user! before_action :authenticate_user!
def index def index
@jobs = current_user.liked_jobs.includes(:company) @jobs = current_user.liked_jobs.includes(:company)
......
require './app/models/settings.rb'
class JobsController < ApplicationController class JobsController < ApplicationController
before_action :set_job, only: [:show] before_action :set_job, only: [:show]
def index def index
@jobs = Job.top_list.includes(:company) @jobs = Job.top_list.includes(:company).check_expiration_date
@cities = City.top_cities.includes(:country) @cities = City.top_cities.includes(:country)
@industries = Industry.top_industries @industries = Industry.top_industries
@jobs_count = @jobs.count @jobs_count = @jobs.count
...@@ -14,7 +16,7 @@ class JobsController < ApplicationController ...@@ -14,7 +16,7 @@ class JobsController < ApplicationController
def city def city
city = City.find(params[:city_id]) city = City.find(params[:city_id])
@jobs = city.jobs.includes(:company) @jobs = city.jobs.includes(:company).check_expiration_date
@jobs_count = @jobs.count @jobs_count = @jobs.count
@jobs = @jobs.page(params[:page]) @jobs = @jobs.page(params[:page])
@result = "jobs/City/#{city.name}" @result = "jobs/City/#{city.name}"
...@@ -23,7 +25,7 @@ class JobsController < ApplicationController ...@@ -23,7 +25,7 @@ class JobsController < ApplicationController
def industry def industry
industry = Industry.find(params[:industry_id]) industry = Industry.find(params[:industry_id])
@jobs = industry.jobs.includes(:company) @jobs = industry.jobs.includes(:company).check_expiration_date
@jobs_count = @jobs.count @jobs_count = @jobs.count
@jobs = @jobs.page(params[:page]) @jobs = @jobs.page(params[:page])
@result = "jobs/Industry/#{industry.name}" @result = "jobs/Industry/#{industry.name}"
...@@ -32,7 +34,7 @@ class JobsController < ApplicationController ...@@ -32,7 +34,7 @@ class JobsController < ApplicationController
def company def company
company = Company.find(params[:company_id]) company = Company.find(params[:company_id])
@jobs = company.jobs @jobs = company.jobs.check_expiration_date
@jobs_count = @jobs.count @jobs_count = @jobs.count
@jobs = @jobs.page(params[:page]) @jobs = @jobs.page(params[:page])
@result = "jobs/Company/#{company.name}" @result = "jobs/Company/#{company.name}"
...@@ -40,12 +42,12 @@ class JobsController < ApplicationController ...@@ -40,12 +42,12 @@ class JobsController < ApplicationController
end end
def search def search
# byebug
condition = get_condition condition = get_condition
response = query(condition) response = query(condition)
job_ids = response["response"]["docs"].pluck("id") job_ids = response["response"]["docs"].pluck("id")
@jobs = Job.where(id: job_ids).includes(:company).page(params[:page]) @jobs_count = response["response"]["numFound"]
@jobs_count = job_ids.count jobs = Job.where(id: job_ids).check_expiration_date.includes(:company)
@jobs = Kaminari.paginate_array(jobs, total_count: @jobs_count).page(params[:page])
@result = params[:search] @result = params[:search]
render template: "jobs/job_lists" render template: "jobs/job_lists"
end end
...@@ -56,29 +58,27 @@ class JobsController < ApplicationController ...@@ -56,29 +58,27 @@ class JobsController < ApplicationController
@job = Job.find(params[:id]) @job = Job.find(params[:id])
end end
def connect def solr_connect
url = 'http://localhost:8983/solr/my_solr_collection' @solr ||= RSolr.connect url: Settings.rsolr.url
@solr = RSolr.connect url: url
end end
def query(condition) def query(condition)
# Direct connection
connect
# use get method to query # use get method to query
response = @solr.get 'select', :params => condition response = solr_connect.get 'select', params: condition
response response
end end
def get_condition def get_condition
condition = {} condition = {}
filter_query = [] filter_query = []
start = params[:page].to_i > 1 ? params[:page].to_i - 1 : 0
# get condition # get condition
condition[:q] = "*:*" condition[:q] = "*:*"
condition[:fl] = "id" condition[:fl] = "id"
condition[:start] = 0 condition[:start] = Settings.top.job_per_history_page * start
condition[:rows] = Job.count condition[:rows] = Settings.top.job_per_history_page
unless params[:search].blank? if params[:search].present?
filter_query << "name:\"#{params[:search]}\" || filter_query << "name:\"#{params[:search]}\" ||
company_name:\"#{params[:search]}\" || company_name:\"#{params[:search]}\" ||
city_name:\"#{params[:search]}\" || city_name:\"#{params[:search]}\" ||
......
...@@ -7,4 +7,25 @@ class ApplyJob < ApplicationRecord ...@@ -7,4 +7,25 @@ class ApplyJob < ApplicationRecord
# CarrierWave # CarrierWave
mount_uploader :cv, CvUploader mount_uploader :cv, CvUploader
def self.to_csv(applications)
data_csv = []
applications.each do |application|
candidate = {}
candidate[:job] = application.job.name
candidate[:name] = application.name
candidate[:email] = application.email
candidate[:cv] = application.cv
candidate[:applied_at] = application.created_at
data_csv << candidate
end
column_names = data_csv.first.keys
CSV.generate do |csv|
csv << column_names
data_csv.each do |item|
csv << item.values
end
end
end
end end
...@@ -11,7 +11,8 @@ class Job < ApplicationRecord ...@@ -11,7 +11,8 @@ class Job < ApplicationRecord
has_many :view_jobs has_many :view_jobs
has_many :users_has_viewed, through: :view_jobs, class_name: 'User', source: :user has_many :users_has_viewed, through: :view_jobs, class_name: 'User', source: :user
scope :top_list, -> { order(updated_date: :desc).limit(Settings.top.job_per_page) } scope :top_list, -> { order(updated_date: :desc).check_expiration_date.limit(Settings.top.job_per_page) }
scope :check_expiration_date, -> { where('expiry_date > ?', Time.current + 1.day) }
def self.create_new_jobs(arr_jobs) def self.create_new_jobs(arr_jobs)
arr_jobs.each do |item| arr_jobs.each do |item|
......
<% applications.each do |application| %>
<div class="job-intro well mr0 mrBot20">
<h4 class="mr0"><%= link_to application.job.name, job_path(application.job) %></h4>
<p> Candidate Name: <%= application.user.name %></p>
<p> Candidate CV: <%= link_to application.user.cv.file.filename, admins_download_cv_path(user_id: application.user_id) %></p>
<p>
<span>Candidate Email: <%= "#{application.user.email}" %></span>
<span class="navbar-right">Applied at: <%= l application.created_at, format: :default %></span>
</p>
</div>
<% end %>
<h1>Admins::Applies#index</h1> <div class="row content">
<p>Find me in app/views/admins/applies/index.html.erb</p> <div class="container">
<div class="col-md-12 search mt-20">
<%= form_tag admins_applies_path, method: :get, class: "search-form" do %>
<div class="field form-group">
<%= text_field_tag(:search, params[:search], placeholder: "Email", class: "form-control") %>
</div>
<div class="field form-group">
<%= select_tag :city, options_for_select(City.pluck(:name)), include_blank: "City", class: "form-control"%>
</div>
<div class="field form-group">
<%= select_tag :industry, options_for_select(Industry.pluck(:name)), include_blank: "Industry", class: "form-control"%>
</div>
<div class="form-group form-inline">
<div class="input-group date form_date col-md-5" data-date="" data-date-format="dd MM yyyy" data-link-field="dtp_input1" data-link-format="yyyy-mm-dd">
<input class="form-control" size="16" type="text" value="" readonly>
<span class="input-group-addon"><span class="glyphicon glyphicon-remove fa fa-trash-o"></span></span>
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar fa fa-calendar"></span></span>
</div>
<!-- <input type="hidden" id="dtp_input1" value="" /> -->
<%= hidden_field_tag('dtp_input1', params[:date_from], value: '') %>
<strong>&nbsp;~&nbsp;</strong>
<div class="input-group date form_date col-md-5" data-date="" data-date-format="dd MM yyyy" data-link-field="dtp_input2" data-link-format="yyyy-mm-dd">
<input class="form-control" size="16" type="text" value="" readonly>
<span class="input-group-addon"><span class="glyphicon glyphicon-remove fa fa-trash-o"></span></span>
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar fa fa-calendar"></span></span>
</div>
<%= hidden_field_tag('dtp_input2', params[:date_to], value: '') %>
</div>
<div class="field form-group form-inline text-center">
<%= submit_tag "search", class: "btn btn-default" %>
<%= submit_tag "Down csv", class: "btn btn-default" %>
</div>
<% end %>
</div>
<div class="col-md-12 jobs">
<div class="panel border_bot clearfix">
<%= render "admins/applies/application", applications: @applications %>
</div>
</div>
<div class="pagination navbar-right">
<%= paginate @applications %>
</div>
</div>
</div>
...@@ -24,16 +24,17 @@ ...@@ -24,16 +24,17 @@
</div> </div>
<% end %> <% end %>
<div class="col-md-9"> <div class="col-md-9">
<h1>2.<%= @job.name %></h1> <h1><%= @job.name %></h1>
<p>3.<%= link_to @job.company.name, company_jobs_path(@job.company) %></p> <p><%= link_to @job.company.name, company_jobs_path(@job.company) %></p>
<p>4. Location: <p>Location:
<%- @job.cities.each_with_index do |city, index| -%> <%- @job.cities.each_with_index do |city, index| -%>
<%= "#{index > 0 ? ',' : ''}" %> <%= "#{index > 0 ? ',' : ''}" %>
<%= link_to city.name, city_jobs_path(city) %> <%= link_to city.name, city_jobs_path(city) %>
<%- end -%> <%- end -%>
</p> </p>
<p>5. Salary: <%= @job.salary %></p> <p>Salary: <%= @job.salary %></p>
<p>6 Long Description: <p>Deadline to apply: <%= l @job.expiry_date, format: :default %></p>
<p>Long Description:
<%= @job.description.html_safe %> <%= @job.description.html_safe %>
</p> </p>
</div> </div>
......
...@@ -19,6 +19,12 @@ ...@@ -19,6 +19,12 @@
<i class="fa fa-sign-out" aria-hidden="true"></i>Logout <i class="fa fa-sign-out" aria-hidden="true"></i>Logout
<% end %> <% end %>
</li> </li>
<%- elsif current_admin -%>
<li>
<%= link_to destroy_admin_session_path, method: :delete do %>
<i class="fa fa-sign-out" aria-hidden="true"></i>Logout
<% end %>
</li>
<%- else -%> <%- else -%>
<li> <li>
<%= link_to new_user_session_path do %> <%= link_to new_user_session_path do %>
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
<body> <body>
<%= render "layouts/menu" %> <%= render "layouts/menu" %>
<%= render "layouts/flash" %> <%= render "layouts/flash" %>
<%= yield %> <div class="content">
<%= yield %>
</div>
<%= render "layouts/footer" %> <%= render "layouts/footer" %>
</body> </body>
</html> </html>
# Files in the config/locales directory are used for internationalization
# and are automatically loaded by Rails. If you want to use locales other
# than English, add the necessary files in this directory.
#
# To use the locales, use `I18n.t`:
#
# I18n.t 'hello'
#
# In views, this is aliased to just `t`:
#
# <%= t('hello') %>
#
# To use a different locale, set it with `I18n.locale`:
#
# I18n.locale = :es
#
# This would use the information in config/locales/es.yml.
#
# The following keys must be escaped otherwise they will not be retrieved by
# the default I18n backend:
#
# true, false, on, off, yes, no
#
# Instead, surround them with single quotes.
#
# en:
# 'true': 'foo'
#
# To learn more, please read the Rails Internationalization guide
# available at http://guides.rubyonrails.org/i18n.html.
en: en:
hello: "Hello world" activerecord:
errors:
messages:
record_invalid: "Validation failed: %{errors}"
restrict_dependent_destroy:
has_one: "Cannot delete record because a dependent %{record} exists"
has_many: "Cannot delete record because dependent %{record} exist"
date:
abbr_day_names:
- Sun
- Mon
- Tue
- Wed
- Thu
- Fri
- Sat
abbr_month_names:
-
- Jan
- Feb
- Mar
- Apr
- May
- Jun
- Jul
- Aug
- Sep
- Oct
- Nov
- Dec
day_names:
- Sunday
- Monday
- Tuesday
- Wednesday
- Thursday
- Friday
- Saturday
formats:
default: "%Y-%m-%d"
long: "%B %d, %Y"
short: "%b %d"
month_names:
-
- January
- February
- March
- April
- May
- June
- July
- August
- September
- October
- November
- December
order:
- :year
- :month
- :day
datetime:
distance_in_words:
about_x_hours:
one: about 1 hour
other: about %{count} hours
about_x_months:
one: about 1 month
other: about %{count} months
about_x_years:
one: about 1 year
other: about %{count} years
almost_x_years:
one: almost 1 year
other: almost %{count} years
half_a_minute: half a minute
less_than_x_minutes:
one: less than a minute
other: less than %{count} minutes
less_than_x_seconds:
one: less than 1 second
other: less than %{count} seconds
over_x_years:
one: over 1 year
other: over %{count} years
x_days:
one: 1 day
other: "%{count} days"
x_minutes:
one: 1 minute
other: "%{count} minutes"
x_months:
one: 1 month
other: "%{count} months"
x_years:
one: 1 year
other: "%{count} years"
x_seconds:
one: 1 second
other: "%{count} seconds"
prompts:
day: Day
hour: Hour
minute: Minute
month: Month
second: Seconds
year: Year
errors:
format: "%{attribute} %{message}"
messages:
accepted: must be accepted
blank: can't be blank
present: must be blank
confirmation: doesn't match %{attribute}
empty: can't be empty
equal_to: must be equal to %{count}
even: must be even
exclusion: is reserved
greater_than: must be greater than %{count}
greater_than_or_equal_to: must be greater than or equal to %{count}
inclusion: is not included in the list
invalid: is invalid
less_than: must be less than %{count}
less_than_or_equal_to: must be less than or equal to %{count}
model_invalid: "Validation failed: %{errors}"
not_a_number: is not a number
not_an_integer: must be an integer
odd: must be odd
required: must exist
taken: has already been taken
too_long:
one: is too long (maximum is 1 character)
other: is too long (maximum is %{count} characters)
too_short:
one: is too short (minimum is 1 character)
other: is too short (minimum is %{count} characters)
wrong_length:
one: is the wrong length (should be 1 character)
other: is the wrong length (should be %{count} characters)
other_than: must be other than %{count}
template:
body: 'There were problems with the following fields:'
header:
one: 1 error prohibited this %{model} from being saved
other: "%{count} errors prohibited this %{model} from being saved"
helpers:
select:
prompt: Please select
submit:
create: Create %{model}
submit: Save %{model}
update: Update %{model}
number:
currency:
format:
delimiter: ","
format: "%u%n"
precision: 2
separator: "."
significant: false
strip_insignificant_zeros: false
unit: "$"
format:
delimiter: ","
precision: 3
separator: "."
significant: false
strip_insignificant_zeros: false
human:
decimal_units:
format: "%n %u"
units:
billion: Billion
million: Million
quadrillion: Quadrillion
thousand: Thousand
trillion: Trillion
unit: ''
format:
delimiter: ''
precision: 3
significant: true
strip_insignificant_zeros: true
storage_units:
format: "%n %u"
units:
byte:
one: Byte
other: Bytes
gb: GB
kb: KB
mb: MB
tb: TB
percentage:
format:
delimiter: ''
format: "%n%"
precision:
format:
delimiter: ''
support:
array:
last_word_connector: ", and "
two_words_connector: " and "
words_connector: ", "
time:
am: am
formats:
default: "%a, %d %b %Y %H:%M:%S"
long: "%B %d, %Y %H:%M"
short: "%d %b %H:%M"
pm: pm
...@@ -3,6 +3,7 @@ Rails.application.routes.draw do ...@@ -3,6 +3,7 @@ Rails.application.routes.draw do
devise_for :admins devise_for :admins
namespace :admins do namespace :admins do
resources :applies, only: [:index] resources :applies, only: [:index]
get 'download_cv' => 'applies#down_cv_candidate'
root 'applies#index' root 'applies#index'
end end
root 'jobs#index' root 'jobs#index'
......
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