diff --git a/.gitignore b/.gitignore
index 9c2b7ba..f26e1e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,7 @@
db/*.sqlite3
log/*.log
tmp/**/*
-Gemfile.lock
+*.swp
CustomGemfile
config/initializers/globant_custom.rb
-
+tmp
diff --git a/Gemfile b/Gemfile
index 000808e..882a8fd 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,12 +1,12 @@
source 'http://rubygems.org'
-gem 'rails', '3.0.3'
+gem 'rails', '~> 3.0.3'
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'sqlite3-ruby', :require => 'sqlite3'
-
+gem 'will_paginate', '3.0.pre2'
# Use unicorn as the web server
# gem 'unicorn'
@@ -27,7 +27,9 @@ gem 'sqlite3-ruby', :require => 'sqlite3'
gem 'couchrest_model', :git => 'https://github.com/couchrest/couchrest_model.git'
gem 'memories'
#gem 'linkedin', :git => "git@github.com:boolean/linkedin.git"
-gem 'omniauth', ">= 0.1.6"
+gem 'omniauth'
+gem 'indextank'
+gem 'faraday-stack'
#gem "acts_as_audited", "2.0.0.rc2"
@@ -37,10 +39,15 @@ gem 'omniauth', ">= 0.1.6"
# group :development, :test do
# gem 'webrat'
# end
-gem 'ruby-debug19', :require => 'ruby-debug'
-group :development, :test do
- gem 'rspec-rails', ">= 2.0.0.beta"
+group :test, :development do
+ gem 'ruby-debug19', :require => 'ruby-debug'
+ gem 'rspec-rails', "~> 2.4"
+ gem 'rr'
+end
+
+group :development do
+ gem 'heroku'
end
if File.exist?(file = File.expand_path('../CustomGemfile',__FILE__))
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..8973ac6
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,206 @@
+GIT
+ remote: https://github.com/couchrest/couchrest_model.git
+ revision: a6becd730568577f97669b79e099ce2780439f87
+ specs:
+ couchrest_model (1.1.0.beta2)
+ activemodel (~> 3.0.0)
+ couchrest (= 1.1.0.pre2)
+ mime-types (~> 1.15)
+ railties (~> 3.0.0)
+ tzinfo (~> 0.3.22)
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ abstract (1.0.0)
+ actionmailer (3.0.6)
+ actionpack (= 3.0.6)
+ mail (~> 2.2.15)
+ actionpack (3.0.6)
+ activemodel (= 3.0.6)
+ activesupport (= 3.0.6)
+ builder (~> 2.1.2)
+ erubis (~> 2.6.6)
+ i18n (~> 0.5.0)
+ rack (~> 1.2.1)
+ rack-mount (~> 0.6.14)
+ rack-test (~> 0.5.7)
+ tzinfo (~> 0.3.23)
+ activemodel (3.0.6)
+ activesupport (= 3.0.6)
+ builder (~> 2.1.2)
+ i18n (~> 0.5.0)
+ activerecord (3.0.6)
+ activemodel (= 3.0.6)
+ activesupport (= 3.0.6)
+ arel (~> 2.0.2)
+ tzinfo (~> 0.3.23)
+ activeresource (3.0.6)
+ activemodel (= 3.0.6)
+ activesupport (= 3.0.6)
+ activesupport (3.0.6)
+ addressable (2.2.5)
+ archive-tar-minitar (0.5.2)
+ arel (2.0.9)
+ builder (2.1.2)
+ columnize (0.3.2)
+ configuration (1.2.0)
+ couchrest (1.1.0.pre2)
+ json (~> 1.5.1)
+ mime-types (~> 1.15)
+ rest-client (~> 1.6.1)
+ diff-lcs (1.1.2)
+ erubis (2.6.6)
+ abstract (>= 1.0.0)
+ faraday (0.6.1)
+ addressable (~> 2.2.4)
+ multipart-post (~> 1.1.0)
+ rack (< 2, >= 1.1.0)
+ faraday-stack (0.1.0)
+ faraday (~> 0.6)
+ heroku (2.1.0)
+ launchy (>= 0.3.2)
+ rest-client (~> 1.6.1)
+ term-ansicolor (~> 1.0.5)
+ i18n (0.5.0)
+ indextank (1.0.9.1)
+ faraday-stack
+ yajl-ruby (>= 0.7.7)
+ json (1.5.1)
+ launchy (0.4.0)
+ configuration (>= 0.0.5)
+ rake (>= 0.8.1)
+ linecache19 (0.5.12)
+ ruby_core_source (>= 0.1.4)
+ mail (2.2.16)
+ activesupport (>= 2.3.6)
+ i18n (>= 0.4.0)
+ mime-types (~> 1.16)
+ treetop (~> 1.4.8)
+ memories (0.3.2)
+ couchrest_model (>= 1.0.0.beta7)
+ mime-types (1.16)
+ multi_json (0.0.5)
+ multipart-post (1.1.0)
+ net-ldap (0.1.1)
+ nokogiri (1.4.4)
+ oa-basic (0.2.2)
+ multi_json (~> 0.0.2)
+ nokogiri (~> 1.4.2)
+ oa-core (= 0.2.2)
+ rest-client (~> 1.6.0)
+ oa-core (0.2.2)
+ rack (~> 1.1)
+ oa-enterprise (0.2.2)
+ net-ldap (~> 0.1.1)
+ nokogiri (~> 1.4.2)
+ oa-core (= 0.2.2)
+ pyu-ruby-sasl (~> 0.0.3.1)
+ rubyntlm (~> 0.1.1)
+ oa-more (0.2.2)
+ multi_json (~> 0.0.2)
+ oa-core (= 0.2.2)
+ rest-client (~> 1.6.0)
+ oa-oauth (0.2.2)
+ faraday (~> 0.6.1)
+ multi_json (~> 0.0.2)
+ nokogiri (~> 1.4.2)
+ oa-core (= 0.2.2)
+ oauth (~> 0.4.0)
+ oauth2 (~> 0.3.0)
+ oa-openid (0.2.2)
+ oa-core (= 0.2.2)
+ rack-openid (~> 1.2.0)
+ ruby-openid-apps-discovery
+ oauth (0.4.4)
+ oauth2 (0.3.0)
+ faraday (~> 0.6.0)
+ multi_json (~> 0.0.4)
+ omniauth (0.2.2)
+ oa-basic (= 0.2.2)
+ oa-core (= 0.2.2)
+ oa-enterprise (= 0.2.2)
+ oa-more (= 0.2.2)
+ oa-oauth (= 0.2.2)
+ oa-openid (= 0.2.2)
+ polyglot (0.3.1)
+ pyu-ruby-sasl (0.0.3.2)
+ rack (1.2.2)
+ rack-mount (0.6.14)
+ rack (>= 1.0.0)
+ rack-openid (1.2.0)
+ rack (>= 1.1.0)
+ ruby-openid (>= 2.1.8)
+ rack-test (0.5.7)
+ rack (>= 1.0)
+ rails (3.0.6)
+ actionmailer (= 3.0.6)
+ actionpack (= 3.0.6)
+ activerecord (= 3.0.6)
+ activeresource (= 3.0.6)
+ activesupport (= 3.0.6)
+ bundler (~> 1.0)
+ railties (= 3.0.6)
+ railties (3.0.6)
+ actionpack (= 3.0.6)
+ activesupport (= 3.0.6)
+ rake (>= 0.8.7)
+ thor (~> 0.14.4)
+ rake (0.8.7)
+ rest-client (1.6.1)
+ mime-types (>= 1.16)
+ rr (1.0.2)
+ rspec (2.5.0)
+ rspec-core (~> 2.5.0)
+ rspec-expectations (~> 2.5.0)
+ rspec-mocks (~> 2.5.0)
+ rspec-core (2.5.1)
+ rspec-expectations (2.5.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.5.0)
+ rspec-rails (2.5.0)
+ actionpack (~> 3.0)
+ activesupport (~> 3.0)
+ railties (~> 3.0)
+ rspec (~> 2.5.0)
+ ruby-debug-base19 (0.11.25)
+ columnize (>= 0.3.1)
+ linecache19 (>= 0.5.11)
+ ruby_core_source (>= 0.1.4)
+ ruby-debug19 (0.11.6)
+ columnize (>= 0.3.1)
+ linecache19 (>= 0.5.11)
+ ruby-debug-base19 (>= 0.11.19)
+ ruby-openid (2.1.8)
+ ruby-openid-apps-discovery (1.2.0)
+ ruby-openid (>= 2.1.7)
+ ruby_core_source (0.1.5)
+ archive-tar-minitar (>= 0.5.2)
+ rubyntlm (0.1.1)
+ sqlite3 (1.3.3)
+ sqlite3-ruby (1.3.3)
+ sqlite3 (>= 1.3.3)
+ term-ansicolor (1.0.5)
+ thor (0.14.6)
+ treetop (1.4.9)
+ polyglot (>= 0.3.1)
+ tzinfo (0.3.26)
+ will_paginate (3.0.pre2)
+ yajl-ruby (0.8.2)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ couchrest_model!
+ faraday-stack
+ heroku
+ indextank
+ memories
+ omniauth
+ rails (~> 3.0.3)
+ rr
+ rspec-rails (~> 2.4)
+ ruby-debug19
+ sqlite3-ruby
+ will_paginate (= 3.0.pre2)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 68ca47b..d3c6c75 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,4 +1,6 @@
class ApplicationController < ActionController::Base
+ before_filter :authenticate_user!
+
protect_from_forgery
protected
@@ -10,12 +12,29 @@ def current_user
def signed_in?
!!current_user
end
-
+
helper_method :current_user, :signed_in?
def current_user=(user)
@current_user = user
session[:user_id] = user.id
end
+
+ def authenticate_user!
+ Rails.logger.debug("session is: #{session.inspect}")
+ if Linkedin.first.nil?
+ # redirect to error page
+ render :status => 500, :file => File.join(Rails.root, 'public', '500.html')
+ else
+ redirect_to('/login') unless signed_in?
+ # redirect_to('/auth/linked_in') unless signed_in?
+ end
+
+ end
+
+ def handle_unverified_request
+ #TODO save the user_id stored on the session after call super
+ #super
+ end
end
diff --git a/app/controllers/employees_controller.rb b/app/controllers/employees_controller.rb
index bc1b3d7..784ad45 100644
--- a/app/controllers/employees_controller.rb
+++ b/app/controllers/employees_controller.rb
@@ -1,24 +1,36 @@
-class EmployeesController < ApplicationController
- before_filter :find_employee, :only => [:show, :edit, :update, :resume]
+require_dependency 'employee'
- def index
- @employees = Employee.all
- end
+class EmployeesController < ApplicationController
+ before_filter :find_employee, :only => [:show, :edit, :update, :resume, :bio]
+ before_filter :validate_current_user, :only => [:edit, :update]
def show
end
def edit
+ @skill_tags_names = @employee.skill_tags_names
+ @industry_tags_names = @employee.industry_tags_names
+ @product_tags_names = @employee.product_tags_names
+
end
def update
- if params[:resume]
- @employee.store_resume(params[:resume].tempfile, params[:resume].original_filename)
- end
+ @employee.store_resume(params[:resume].tempfile, params[:resume].original_filename) if params[:resume]
+ @employee.store_bio(params[:bio].tempfile, params[:bio].original_filename) if params[:bio]
+
+ #TODO need refactor
+ @employee.skill_tags = []
+# params[:employee]["skill_tags"].each{|tag| @employee.skill_tags << {:name => tag.name.downcase, :rate => tag.rate } }
+ @employee.industry_tags = []
+ params["industry_tags"].split(", ").each{|tag| @employee.industry_tags << {:name => tag.downcase } }
+ @employee.product_tags = []
+ params["product_tags"].split(", ").each{|tag| @employee.product_tags << {:name => tag.downcase } }
- if @employee.update_attributes(params[:employee])
- redirect_to(@employee, :notice => 'Employee was successfully updated.')
+ # Guard to make sure employee isn't bulk updated, per story #10758361. We use an array of positive values in case we want to add more later.
+ updateable_employee_params = params[:employee].select{|key, val| ['email', 'professional_info', 'give_gets', 'interesting_facts'].include? key}
+ if @employee.update_attributes(updateable_employee_params)
+ redirect_to(root_path, :notice => 'Employee was successfully updated.')
else
render :action => "edit"
end
@@ -28,10 +40,124 @@ def resume
send_data(@employee.resume_data, :filename => @employee.resume)
end
+ def search
+ # Search index based on query
+ @index_results = EmployeeIndexer.search(params[:query]) if params[:query]
+
+ # Save the search query in couch
+ @search = Search.new(:employee => self.current_user, :search => params[:query])
+ if !@search.save
+ raise "Error saving search"
+ end
+
+ # Search DB based on index results.
+ @ids = []
+ @index_results['results'].each { |doc| @ids << doc['docid'] }
+ @results = []
+ #by now I'm hitting the DB one by one. I haven't found a better way yet.
+ @ids.each do |id|
+ @results << Employee.find(id)
+ end
+ @matches = @results.compact.count
+ @results.compact!
+
+ # Create has set of skills, locations, products, industry - TODO: Move this to couchdb map/reduce if possible!!!!
+ logger.debug "Creating locations filter"
+ @locations_filter = @results.collect(&:location).uniq.compact
+
+ logger.debug "Creating skills filter"
+ @skills_filter = []
+ @results.collect(&:skill_tags).each do |skill_tag|
+ skill_tag.each do |skill|
+ @skills_filter << skill.name.downcase
+ end
+ end
+ @skills_filter.uniq!
+
+ logger.debug "Creating products filter"
+ @products_filter = []
+ @results.collect(&:product_tags).each do |product_tag|
+ product_tag.each do |product|
+ @products_filter << product.name.downcase
+ end
+ end
+ @products_filter.uniq!
+
+ logger.debug "Creating industry filter"
+ @industry_filter = []
+ @results.collect(&:industry_tags).each do |industry_tag|
+ industry_tag.each do |industry|
+ @industry_filter << industry.name.downcase
+ end
+ end
+ @industry_filter.uniq!
+
+ # Paginate the search results
+ @results = @results.paginate(:page => params[:page], :per_page => 3)
+ end
+
+ def refine_search
+ logger.debug "Refining results"
+
+ # Create the query string for searching our index
+ query_string = ""
+ query_string += "__any:(#{params[:query]}) " if params[:query]
+ query_string += "skill_tags:(#{params[:skill]})" if params[:skill]
+
+ logger.debug "The query string is #{query_string}"
+
+ @index_results = EmployeeIndexer.search_by_query(query_string)
+
+ logger.debug "Results match type is #{@index_results['results'].class.name}"
+
+ @index_results.each do |result|
+ logger.debug "Result is #{result}"
+ end
+
+ logger.debug("Index contains #{@index_results['matches']} results")
+
+ render :nothing => true
+ end
+
+ def bio
+ send_data(@employee.bio_data, :filename => @employee.bio)
+ end
+
private
def find_employee
@employee = Employee.find_by_permalink(params[:id])
+
+ # Increment the view counter to track 'most viewed' employees
+ if (@employee && @employee != current_user)
+ @employee.update_attributes(:num_views => @employee.num_views + 1)
+ end
+
+ @similar_employees = []
+ # find similar employees to the one we're viewing
+ if (@employee && @employee.skill_tags && !@employee.skill_tags.empty?)
+ @skill_tag_query = ""
+ @employee.skill_tags.each_with_index do |tag, index|
+ @skill_tag_query << tag.name
+ if (index < @employee.skill_tags.length - 1)
+ @skill_tag_query << " OR "
+ end
+ end
+
+ # Copied from the search method above...there's gotta be a better way to pull these folks.
+ @similar_employees_results = EmployeeIndexer.search(@skill_tag_query) if @skill_tag_query
+ @ids = []
+ @similar_employees_results['results'].each { |doc| @ids << doc['docid'] }
+ @ids.each do |id|
+ @similar_employees << Employee.find(id) unless (id == @employee.id)
+ end
+ @similar_employees.compact!
+ end
+
+ end
+
+ def validate_current_user
+ redirect_to root_path, :notice => "You don't have permission to complete this task" unless @employee == current_user
end
end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 4160ef9..e2af134 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -1,7 +1,15 @@
class SessionsController < ApplicationController
+ skip_filter :authenticate_user!, :only => [:create]
+
+ def new
+ @title = "Sign in"
+ end
+
def create
- auth = request.env['rack.auth']
- unless @auth = Authorization.find_from_hash(auth).first
+ auth = request.env['omniauth.auth']
+ if @auth = Authorization.find_from_hash(auth)
+ @auth.employee.update_from_linkedin(auth)
+ else
# Create a new user or add an auth to existing user, depending on
# whether there is already a user signed in.
@auth = Authorization.create_from_hash(auth, current_user)
@@ -11,14 +19,16 @@ def create
# Log the authorizing user in.
self.current_user = @auth.employee
else
- flash[:notice] = 'You must work on Razorfish or Globant'
+ flash[:notice] = 'You must work at Razorfish or Globant'
end
redirect_to root_path
end
def destroy
- session[:user_id] = nil
+ # @auth = current_user.
+ Rails.logger.debug("session is: #{session.inspect}")
+ session[:user_id] = ''
redirect_to root_url, :notice => "Signed out!"
end
end
diff --git a/app/controllers/taggings_controller.rb b/app/controllers/taggings_controller.rb
index 2d2b7a2..d5b3e3a 100644
--- a/app/controllers/taggings_controller.rb
+++ b/app/controllers/taggings_controller.rb
@@ -1,10 +1,10 @@
class TaggingsController < ApplicationController
- def tag_query
+
#params skill_tags
- #e.g /taggings/product_tags/ruby
- # /taggings/product_tags/ruby.json
- # /taggings/product_tags/ruby.xml
+ #e.g /taggings/skill_tags/ruby
+ # /taggings/skill_tags/ruby.json
+ # /taggings/skill_tags/ruby.xml
#params product_tags
@@ -16,33 +16,72 @@ def tag_query
#e.g /taggings/industry_tags/chemicals
# /taggings/industry_tags/chemicals.json
# /taggings/industry_tags/chemicals.xml
+
def tag_query
- @employees = Employee.send('by_' + params[:tags_type], :key => params[:tag_name])
+ #bad behavior on will_paginate, its works but needs a review
+ @employees = Employee.send('by_' + params[:tags_type], :key => params[:tag_name]).paginate :page => params[:page], :order => 'updated_at DESC',:per_page => 36
+
+# the position in the array indicates the group_by
+# @skills_groups[4] 80 - 100
+# @skills_groups[3] 60 - 80
+# @skills_groups[2] 40 - 60
+# @skills_groups[1] 20 - 40
+# @skills_groups[0] 0 - 20
+ @skills_rate_groups = Employee.skill_rate_groups(params[:tag_name])
+# @skills_name_groups = [0,0,0,0,0]
+ @skills_name_groups = Employee.skill_names_group(params[:tag_name])
+ @skills_name_groups = @skills_name_groups[0..9]
+
+ @tag = params[:tag_name]
+
respond_to do |format|
+
format.json {render :json => @employees.to_json}
format.xml {render :xml => @employees.to_xml}
- format.html {render 'employees/index'}
+ format.html {render 'skill_tag_show'}
+# format.html {render 'skill_tag_show'}
+
end
+
end
- def skill_tags_cloud
- @tag_cloud = Employee.by_skill_tags( :reduce => true, :group => true)
+ def autocomplete
+
+ #By now i haven't found how wildcard works on couch_db then we try with start and end_key
+ #Employee.by_skill_tags( :startkey => 'ru' , :endkey => 'ruzzz', :reduce => true, :group => true)
+
+ #@employees = Employee.send('by_' + params[:tags_type], {:startkey => params[:term] , :endkey => params[:term] + 'ZZZ', :reduce => true, :group => true}).map{|t| t.last}.flatten.map{ |t| t['key']}
+ @tags = Employee.send('by_' + params[:tags_type], { :reduce => true, :group => true}).map{|t| t.last}.flatten.map{ |t| t['key']}
+
respond_to do |format|
- format.json {render :json => @tag_cloud.to_json}
+ format.json {render :json => @tags.to_json}
end
end
- def product_tags_cloud
- @tag_cloud = Employee.by_product_tags( :reduce => true, :group => true)
+ def skill_tags_cloud
+ #this method resolve the data needed in our skills tag graphic representation
+ limit = params[:limit] || 100
+ @tag_cloud = Employee.by_skill_tags( :reduce => true, :group => true, :limit => limit)
+
+ total_employee = Employee.count.to_f
+ @tag_cloud['rows'].each{ |x| x['value'] = x['value'] / total_employee }
respond_to do |format|
format.json {render :json => @tag_cloud.to_json}
+ format.html {render "employees/skills"}
end
end
- def industry_tags_cloud
- @tag_cloud = Employee.by_industry_tags( :reduce => true, :group => true)
+
+ #params
+ #e.g /taggings/count/skill_tags
+ #e.g /taggings/count/industry_tags
+ #e.g /taggings/count/product_tags
+
+ def tags_count
+ #is the flat count of tags
+ @tag_group = Employee.send('by_' + params[:tags_type], :reduce => true, :group => true)
respond_to do |format|
- format.json {render :json => @tag_cloud.to_json}
+ format.json {render :json => @tag_group.to_json}
end
end
diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb
index c6eb95d..e3159b6 100644
--- a/app/controllers/welcome_controller.rb
+++ b/app/controllers/welcome_controller.rb
@@ -1,6 +1,16 @@
class WelcomeController < ApplicationController
+ skip_filter :authenticate_user!, :only => [:login]
def index
- @events = EmployeeEvent.all
+ Rails.logger.error('index action started')
+ @title = 'Welcome'
+ @events = EmployeeEvent.by_created_at(:limit => 10)
+ @recent_searches = Search.by_created_at(:limit => 5)
+ @most_viewed = Employee.by_num_views(:descending => true)
+ Rails.logger.error('index action done, rendering')
end
+
+ def login
+ end
+
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index de6be79..c6a776e 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -1,2 +1,69 @@
module ApplicationHelper
+# def remove_child_link(name, f)
+# f.hidden_field(:_delete) + link_to(name, "javascript:void(0)", :class => "remove_child")
+# end
+
+# def add_child_link(name, association)
+# link_to(name, "javascript:void(0)", :class => "add_child", :"data-association" => association)
+# end
+
+# def new_child_fields_template(form_builder, association, options = {})
+# options[:object] ||= form_builder.object.class.reflect_on_association(association).klass.new
+# options[:partial] ||= association.to_s.singularize
+# options[:form_builder_local] ||= :f
+
+# content_tag(:div, :id => "#{association}_fields_template", :style => "display: none") do
+# form_builder.fields_for(association, options[:object], :child_index => "new_#{association}") do |f|
+# render(:partial => options[:partial], :locals => {options[:form_builder_local] => f})
+# end
+# end
+# end
+
+ # creates a link to an employee detail page
+ # @employee_object = contains the employee's first_name, last_name, and job_title
+ def employee_link(employee_object)
+ link_to(employee_object.first_name + ' ' + employee_object.last_name + ' // ' + employee_object.job_title, employee_path(employee_object))
+ end
+
+ # creates a link to an employee detail page
+ # @employee_object = contains the employee's first_name, last_name
+ def employee_link_short(employee_object)
+ link_to(employee_object.first_name + ' ' + employee_object.last_name, employee_path(employee_object))
+ end
+
+ # displays read only version of ratings list
+ def ratings_readonly(rating)
+ if (rating.is_a?(Integer) )
+ rating = Integer(rating)
+ else
+ rating = 1
+ end
+ if(rating <= 5)
+ items = ['one','two','three','four','five']
+ content = ""
+ items.each_with_index do |item, i|
+ text = i + 1
+ content << content_tag('li', content_tag('a', text, :href => '#' ), :class => item) + " "
+ end
+ content_tag(:ul, content.html_safe, :class => "ratings read-only " + items[rating - 1])
+ else
+ content_tag(:span,"error: rating out of range");
+ end
+ end
+
+ # displays editable version of ratings list
+ def ratings_edit(rating)
+ rating = Integer(rating)
+ if(rating <= 5)
+ items = ['one','two','three','four','five']
+ content = ""
+ items.each_with_index do |item, i|
+ text = i + 1
+ content << content_tag('li', content_tag('a', text, :href => '#' ), :class => item) + " "
+ end
+ content_tag(:ul, content.html_safe, :class => "ratings " + items[rating - 1])
+ else
+ content_tag(:span,"error: rating out of range");
+ end
+ end
end
diff --git a/app/helpers/employees_helper.rb b/app/helpers/employees_helper.rb
new file mode 100644
index 0000000..119ff6a
--- /dev/null
+++ b/app/helpers/employees_helper.rb
@@ -0,0 +1,5 @@
+module EmployeesHelper
+ def non_editable_employee_field(fieldname)
+ content_tag(:span, @employee.send(fieldname), :class=>"noneditable-field" )
+ end
+end
diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb
index 309f8b2..370c3d0 100644
--- a/app/helpers/sessions_helper.rb
+++ b/app/helpers/sessions_helper.rb
@@ -1,2 +1,5 @@
module SessionsHelper
+ def sign_in_out_link
+ current_user ? link_to("Sign Out", signout_url, :class => 'signout-link') : link_to("Sign In with LinkedIn", "/auth/linked_in", :class => "signout-link")
+ end
end
diff --git a/app/models/authorization.rb b/app/models/authorization.rb
index 561101e..4981b73 100644
--- a/app/models/authorization.rb
+++ b/app/models/authorization.rb
@@ -21,7 +21,7 @@ class Authorization < BaseCouchDocument
# Class Methods
###############
def self.find_from_hash(hash)
- by_provider_and_uid :provider => [hash['provider']], :uid => [hash['uid']]
+ find_by_provider_and_uid [hash['provider'], hash['uid']]
end
def self.create_from_hash(hash, user = nil)
diff --git a/app/models/employee.rb b/app/models/employee.rb
index ab24ec9..7a6809e 100644
--- a/app/models/employee.rb
+++ b/app/models/employee.rb
@@ -11,11 +11,31 @@ class Employee < BaseCouchDocument
property :industry
property :linkedin_url
property :picture_url
+ property :industry_tags do |industry_tag|
+ industry_tag.property :name, String
+ end
+
+ property :skill_tags do |skill_tag|
+ skill_tag.property :name, String
+ skill_tag.property :rate, Integer
+ end
+
+ property :product_tags do |product_tag|
+ product_tag.property :name, String
+ end
+
+
property :phone_number
property :email
- property :tags, [Tag], :cast_as => 'Tag'
+
property :resume
+ property :bio
property :permalink
+ property :professional_info
+ property :give_gets
+ property :interesting_facts
+ property :location
+ property :num_views, Integer, :default => 0
timestamps!
@@ -26,29 +46,113 @@ class Employee < BaseCouchDocument
view_by :updated_at, :descending => true
view_by :id
view_by :permalink
+ view_by :num_views
+
+# Get all employee that have ruby Skills
+# Employee.by_skill_tags( :key => 'ruby')
+# Get all count of ruby Skills_tag
+# Employee.by_skill_tags(:reduce => true, :key => 'ruby')
+# Get the count of each Skill tag (Tag Cloud)
+# Employee.by_skill_tags( :reduce => true, :group => true)
+
+ view_by :skill_tags, :map =>
+ "function(doc){
+ if (doc['couchrest-type'] == 'Employee' && doc['skill_tags']){
+ doc.skill_tags.forEach(
+ function(skill_tag){
+ emit(skill_tag.name, 1);
+ }
+ );
+ }
+ };",
+ :reduce =>
+ "function(keys, values, rereduce){
+ return sum(values);
+ };"
+
+ view_by :industry_tags, :map =>
+ "function(doc){
+ if (doc['couchrest-type'] == 'Employee' && doc['industry_tags']){
+ doc.industry_tags.forEach(
+ function(industry_tag){
+ emit(industry_tag.name, 1);
+ }
+ );
+ }
+ };",
+ :reduce =>
+ "function(keys, values, rereduce){
+ return sum(values);
+ };"
+
+ view_by :product_tags, :map =>
+ "function(doc){
+ if (doc['couchrest-type'] == 'Employee' && doc['product_tags']){
+ doc.product_tags.forEach(
+ function(product_tag){
+ emit(product_tag.name, 1);
+ }
+ );
+ }
+ };",
+ :reduce =>
+ "function(keys, values, rereduce){
+ return sum(values);
+ };"
- view_by :tags, :map => "
- function(doc) {
- if(doc['couchrest-type'] == 'Employee' && doc['tags'] != null && doc.tags.length > 0){
- for(var tag in doc.tags) {
- emit(doc.tags[tag].name, {first_name: doc.first_name, last_name: doc.last_name});
+#Employee.by_skill_group_tags(:raw => true)
+
+ view_by :skill_group_tags, :map =>
+ "function(doc){
+ if (doc['couchrest-type'] == 'Employee' && doc['skill_tags']){
+ doc.skill_tags.forEach(
+ function(skill_tag){
+ rate = skill_tag.rate;
+ tag = skill_tag.name;
+ if (rate <= 2)
+ {
+ rate = 'vlow';
+ }
+ else if (rate >=2 && rate<4)
+ {
+ rate = 'low';
+ }
+ else if (rate>=4 && rate<6)
+ {
+ rate = 'med';
+ }
+ else if (rate>=6 && rate<8)
+ {
+ rate = 'high';
+ }
+ else
+ {
+ rate = 'vhigh';
+ }
+
+ emit([tag,rate], 1);
}
- }
- }"
+ );
+ }
+ };",
+ :reduce =>
+ "function(keys, values, rereduce){
+ return sum(values);
+ };"
################
# Observers
################
- before_save :generate_permalink
+ before_save :generate_permalink, :validate_skill_tags
def generate_permalink
self.permalink ||= self.full_name.parameterize
end
- after_save :extract_differences
+ after_save :extract_differences, :save_index
def extract_differences
- useless_properties = ['created_at', 'updated_at']
+ useless_properties = ['created_at', 'updated_at', 'num_views']
if self.current_version == 1
EmployeeEvent.create(:employee => self, :event_type => 'new_employee')
@@ -59,11 +163,16 @@ def extract_differences
self.properties.reject{|property| useless_properties.include? property.to_s}.each do |property|
changes << property unless self[property] == previous_instance[property]
end
-
- EmployeeEvent.create(:employee => self, :changes => changes, :event_type => 'update_profile')
+ if (!changes.empty?)
+ EmployeeEvent.create(:employee => self, :changes => changes, :event_type => 'update_profile')
+ end
end
end
+ def save_index
+ EmployeeIndexer.add_document(self)
+ end
+
################
# class Methods
################
@@ -78,22 +187,95 @@ def self.create_from_hash!(hash)
################
# public Methods
################
+ def validate_skill_tags
+ self.skill_tags.map!{|x| x unless x.name.blank? }.compact!
+
+ end
+
+ def update_from_linkedin(hash)
+ employee = hash['user_info'][:employee]
+ Rails.logger.debug(employee)
+ self.first_name = employee['first_name']
+ self.last_name = employee['last_name']
+ self.picture_url = employee['picture_url']
+ self.location = employee['location']
+ self.industry = employee['industry']
+ self.job_title = employee['description']
+ save
+ end
def to_param
self.permalink
end
+ def skill_tags_names(join_str = ', ')
+ tags_name_to_s(self.skill_tags,join_str)
+ end
+
+ def industry_tags_names(join_str = ', ')
+ tags_name_to_s(self.industry_tags,join_str)
+ end
+
+ def product_tags_names(join_str = ', ')
+ tags_name_to_s(self.product_tags,join_str)
+ end
+
def full_name
"#{self.first_name} #{self.last_name}".strip
end
+ def skill_tags_cloud
+
+ tag_cloud = self.skill_tags.select{|x| !x['rate'].blank? }
+ tag_cloud.each{ |x| x['rate'] = x['rate'] / 10.0 }
+
+ end
+ def self.skill_rate_groups(skill_name)
+
+ vhigh = Employee.by_skill_group_tags(:raw => true, :key => [skill_name,'vhigh'],:reduce => true)
+ high = Employee.by_skill_group_tags(:raw => true, :key => [skill_name,'high'],:reduce => true)
+ med = Employee.by_skill_group_tags(:raw => true, :key => [skill_name,'med'],:reduce => true)
+ low = Employee.by_skill_group_tags(:raw => true, :key => [skill_name,'low'],:reduce => true)
+ vlow = Employee.by_skill_group_tags(:raw => true, :key => [skill_name,'vlow'],:reduce => true)
+
+ result = [vlow,low,med,high,vhigh]
+
+ result.map! do |elem|
+ !(elem["rows"].empty?)? elem = elem["rows"].first["value"] : elem = 0;
+ end
+
+ end
+ def self.skill_names_group(skill_name)
+ self.by_skill_tags( :key => skill_name).map{|e| e.skill_tags.reject{|t| t[:name] == skill_name }}.flatten.group_by{|x| x[:name]}.map{|k,v| {:name => k,:count => v.count}}.sort{|x,y| y[:count] <=> x[:count]}
+ end
+
+ #TODO dry attachments code
def store_resume(file, filename)
self.create_attachment({:file => file , :name => filename})
self.resume = filename
end
+ def store_bio(file, filename)
+ self.create_attachment({:file => file , :name => filename})
+ self.bio = filename
+ end
+
def resume_data
self.read_attachment(self.resume)
end
+
+ def bio_data
+ self.read_attachment(self.bio)
+ end
+
+ #################
+ # private Methods
+ #################
+ private
+
+ def tags_name_to_s(tags_arr, join_str)
+ tags_arr.map{|tag| tag["name"] }.join(join_str) unless tags_arr.blank?
+ end
+
end
diff --git a/app/models/employee_event.rb b/app/models/employee_event.rb
index 0277fba..ee525de 100644
--- a/app/models/employee_event.rb
+++ b/app/models/employee_event.rb
@@ -5,5 +5,7 @@ class EmployeeEvent < BaseCouchDocument
belongs_to :employee
timestamps!
+
+ view_by :created_at, :descending => true
end
diff --git a/app/models/employee_indexer.rb b/app/models/employee_indexer.rb
new file mode 100644
index 0000000..6c3d981
--- /dev/null
+++ b/app/models/employee_indexer.rb
@@ -0,0 +1,62 @@
+class EmployeeIndexer
+ # Define all the properties of Employee.rb that we want to index
+ @@keys_to_index = ['first_name', 'last_name', 'job_title', 'industry', 'picture_url', 'industry_tags', 'skill_tags', 'product_tags', 'email', 'professional_info', 'give_gets', 'interesting_facts', 'location', 'description' ]
+
+ # Defines a property on class that represents our IndexTank's index
+ def self.index
+ @api ||= IndexTank::Client.new(INDEXTANK_API_URL)
+ @index ||= @api.indexes(INDEXTANK_INDEX_NAME)
+ @index
+ end
+
+ # Creates the IndexTank index - Currently being used by Rake Tasks for management of the index.
+ def self.create_index
+ index.add
+ while not index.running?
+ puts 'waiting for index to start'
+ sleep 1
+ end
+ end
+
+ # Deletes this index - Currently being used by Rake Tasks for management of the index
+ def self.delete_index
+ index.delete
+ end
+
+ # Facilitates the searching of our index via IndexTank. The query string passed in will
+ # search all text portion of our documents defined by the aggregation of our @@keys_to_index
+ def self.search(query)
+ # Searches over __any key
+ #@@keys_to_index.each do |value|
+ # query_to_search << "#{value}:(#{query})"
+ #end
+ index.search("__any:(#{query.to_s})")
+ end
+
+ # Facilitates the searching of our index by any specific property defined in the class constant
+ # array above '@@keys_to_index
+ def self.search_by_property(name, value)
+ index.search("#{name}:(#{value})")
+ end
+
+ # Adds the Employee model to our index.
+ # This is called from the after_save filter within our Employee model as well as our Rake Tasks
+ # This loops over each property within the employee and indexes each field. It also appends
+ # our properties names into one giant string separated by '.' if we simply want to do a free text search
+ def self.add_document(employee)
+ filters = {}
+ any = []
+ employee.each do |name, value|
+ unless !@@keys_to_index.include?(name)
+ value = value.join "," if value.kind_of?(Array)
+ if (!value.nil? and !value.empty?)
+ filters[name] = value
+ any << value
+ end
+ end
+ end
+ filters[:__any] = any.join(" . ")
+ index.document(employee.id).add(filters)
+ end
+
+end
diff --git a/app/models/search.rb b/app/models/search.rb
new file mode 100644
index 0000000..7b105c8
--- /dev/null
+++ b/app/models/search.rb
@@ -0,0 +1,9 @@
+class Search < BaseCouchDocument
+ property :search
+
+ belongs_to :employee
+
+ timestamps!
+
+ view_by :created_at, :descending => true
+end
diff --git a/app/views/employees/_form.html.erb b/app/views/employees/_form.html.erb
index 8b21e12..6b2d0b3 100644
--- a/app/views/employees/_form.html.erb
+++ b/app/views/employees/_form.html.erb
@@ -1,7 +1,22 @@
+<%= javascript_include_tag "autocomplete" %>
+
+
+
+
<%= form_for(@employee, :html => {:multipart => true}) do |f| %>
<% if @employee.errors.any? %>
-
-
<%= pluralize(@employee.errors.count, "error") %> prohibited this employee from being saved:
+
+
<%= pluralize(@employee.errors.count, "error") %> prohibited this employee from being saved:
<% @employee.errors.full_messages.each do |msg| %>
@@ -10,20 +25,58 @@
<% end %>
+
+
+
+
+ Personal Information
+ <%= f.label :first_name %> <%= non_editable_employee_field(:first_name)%>
+ <%= f.label :last_name %> <%= non_editable_employee_field(:last_name)%>
+ <%= f.label :job_title %> <%= non_editable_employee_field(:job_title)%>
+ <%= f.label :email %> <%= f.text_field :email %>
+ <%= f.label :location %> <%= non_editable_employee_field(:location)%>
+
-
- <%= f.label :first_name %>
- <%= f.text_field :first_name %>
-
-
- <%= f.label :email %>
- <%= f.text_field :email %>
-
-
- <%= file_field_tag :resume %>
-
-
- <%= f.submit %>
+
+ Skills
+
+ <%= render :partial => "skill_tag", :collection => @employee.skill_tags, :locals => {:form => f} %>
+
+ <%= link_to 'add skills','', :id => 'add-skill' %>
+
+
+ Industry Experience
+ <%= text_field_tag :industry_tags , @industry_tags_names, :class => "industry_tags tagautocomplete" %>
+
+
+
+ Product Experience
+ <%= text_field_tag :product_tags , @product_tags_names, :class => "product_tags tagautocomplete" %>
+
+
+
+ <%= f.label "Upload your resume" %>
+ <%= file_field_tag :resume %>
+ <%= f.label "Upload your bio" %>
+ <%= file_field_tag :bio %>
+
+
+
+
+ <%= f.label :professional_information %>
+ <%= f.text_area :professional_info %>
+
+
+ <%= f.label 'Give / Gets' %>
+ <%= f.text_area :give_gets %>
+
+
+ <%= f.label :interesting_facts %>
+ <%= f.text_area :interesting_facts %>
+
+
+
<%= f.submit %>
+
<% end %>
-
+
diff --git a/app/views/employees/_skill_tag.html.erb b/app/views/employees/_skill_tag.html.erb
new file mode 100644
index 0000000..ab56133
--- /dev/null
+++ b/app/views/employees/_skill_tag.html.erb
@@ -0,0 +1,14 @@
+<%= fields_for "employee[skill_tags]", skill_tag do |skill_tag_form| %>
+
+ <% stamp = Time.current.to_f.to_s.sub('.','') %>
+
+ <%= label_tag "employee[skill_tags]['#{stamp}'][name]", "Name:" %> <%= text_field_tag "employee[skill_tags]['#{stamp}'][name]", skill_tag['name'],:class => "skill_tags tagautocomplete" %>
+
+
+ Rate: <%= hidden_field_tag "employee[skill_tags]['#{stamp}'][rate]", skill_tag['rate'] %>
+ <%= ratings_edit(skill_tag['rate']) %>
+ <%= link_to 'remove','', :class => 'remove-skill' %>
+
+
+<% end %>
+
diff --git a/app/views/employees/edit.html.erb b/app/views/employees/edit.html.erb
index 0c29a6d..9c103c7 100644
--- a/app/views/employees/edit.html.erb
+++ b/app/views/employees/edit.html.erb
@@ -1,6 +1,8 @@
-Editing employee
+<%= javascript_include_tag 'skills.edit' %>
+Editing employee
<%= render 'form' %>
<%= link_to 'Show', @employee %> |
-<%= link_to 'Back', employee_path %>
+<%= link_to 'Back', root_path %>
+
diff --git a/app/views/employees/index.html.erb b/app/views/employees/index.html.erb
index 2659a44..e69de29 100644
--- a/app/views/employees/index.html.erb
+++ b/app/views/employees/index.html.erb
@@ -1,26 +0,0 @@
-Listing employees
-
-
-
- Name
- Email
-
-
-
-
-
-<% @employees.each do |employee| %>
-
- <%= employee.first_name %>
- <%= employee.email %>
- <%= link_to 'Show', employee %>
- <%= link_to 'Edit', edit_employee_path(employee) %>
- <%= link_to 'Destroy', employee, :confirm => 'Are you sure?', :method => :delete %>
-
-<% end %>
-
-
-
-
-<%= link_to 'New Employee', new_employee_path %>
-
diff --git a/app/views/employees/search.html.erb b/app/views/employees/search.html.erb
new file mode 100644
index 0000000..5f86001
--- /dev/null
+++ b/app/views/employees/search.html.erb
@@ -0,0 +1,77 @@
+
+
+
Search
+
Your search for "<%= params[:query] %>" returned <%= pluralize @matches, 'result' %>
+
+ <%= form_tag search_path, :method => :get do %>
+
+ <% end %>
+
+
+
Refine Search
+
+ Skills
+ <% @skills_filter.each do |skill| %>
+ <%=skill%> <%= check_box_tag "#{skill}", "#{skill}" %>
+ <% end %>
+ Locations
+ <% @locations_filter.each do |location| %>
+ <%=location%> <%= check_box_tag "#{location}", "#{location}" %>
+ <% end %>
+ Products
+ <% @products_filter.each do |products| %>
+ <%=products%> <%= check_box_tag "#{products}", "#{products}" %>
+ <% end %>
+ Industry
+ <% @industry_filter.each do |industry| %>
+ <%=industry%> <%= check_box_tag "#{industry}", "#{industry}" %>
+ <% end %>
+
+
+
+
+
Search Results
+ <% if @results %>
+
+ <% @results.each do |doc| %>
+ <% if doc %>
+
+
+ <%if doc['picture_url'] -%>
+ <%= link_to image_tag(doc['picture_url'], :size => "80x80", :class => "profile-img"), employee_path(doc) %>
+ <% else -%>
+ <%= link_to image_tag("generic.profile.gif", :size => "80x80", :class => "profile-img", :alt => "No Image Found"), employee_path(doc) %>
+ <% end -%>
+
+ <%= employee_link(doc) %>
+ <% if doc['skill_tags'] %>
+
+ <%= doc['skill_tags'].map { |tag| tag.name }.join(', ') %>
+
+
+ <%= params[:query] %>
+ <%= ratings_readonly(doc['skill_tags'].find { |skill| skill.name.downcase.eql? (params[:query].downcase) }.rate) %>
+
+ <% end %>
+
+
+
+ <% end %>
+ <% end %>
+ <%= will_paginate @results %>
+
+ <% else %>
+
Your search for "<%= params[:query] %>" returned no results"
+ <% end %>
+
+
+
+
+
+
+
diff --git a/app/views/employees/show.html.erb b/app/views/employees/show.html.erb
index 19cc36b..58dd377 100644
--- a/app/views/employees/show.html.erb
+++ b/app/views/employees/show.html.erb
@@ -1,26 +1,77 @@
-<%= notice %>
+
-
- Name:
- <%= @employee.first_name %>
-
+
+ <%= notice %>
+
+
Your Profile
+
+ <%if @employee.picture_url -%>
+
+ <% else -%>
+
+ <% end -%>
+
+ <%= @employee.full_name %> // <%= @employee.job_title %>
+
+ Industry: <%= @employee.industry_tags_names %>
+ Skills: <%= @employee.skill_tags_names %>
+ Products: <%= @employee.product_tags_names %>
+ Email: <%= @employee.email %>
+ Location: <%= @employee.location %>
+ <% if @employee.resume -%>
+ Resume: <%= link_to "View Resume", resume_path(@employee), :class => 'attach' %>
+ <% end -%>
+ <% if @employee.bio -%>
+ Bio: <%= link_to @employee.bio, bio_path(@employee), :class => 'attach' %>
+ <% end -%>
+
+
+
+
Professional Information
+
<%= @employee.professional_info.html_safe if @employee.professional_info %>
+
Give / Gets
+
<%= @employee.give_gets.html_safe if @employee.give_gets %>
+
Interesting Facts
+
<%= @employee.interesting_facts.html_safe if @employee.interesting_facts %>
+
+ <% if current_user == @employee -%>
+ <%= link_to 'Edit', edit_employee_path(@employee) %> |
+ <% end -%>
-
- Name:
- <%= @employee.last_name %>
-
-
-
- Email:
- <%= @employee.email %>
-
-<% if current_user.resume -%>
-
- Resume:
- <%= link_to @employee.resume, resume_path(@employee) %>
-
-<% end -%>
-
-<%= link_to 'Edit', edit_employee_path(@employee) %> |
-<%= link_to 'Back', employees_path %>
+ <%= link_to 'Back', root_path %>
+
+
+
Your Skills
+
+ <% if (!@similar_employees.empty?) %>
+
People like You
+
+
+ <%if @similar_employees.first.picture_url -%>
+ <%= link_to image_tag("#{@similar_employees.first.picture_url}", :size => "80x80", :class => "profile-img", :alt => "#{@similar_employees.first.first_name} #{@similar_employees.first.last_name}"), edit_employee_path(@similar_employees.first) %>
+ <% else -%>
+ <%= link_to image_tag("generic.profile.gif", :size => "80x80", :class => "profile-img", :alt => "No Image Found"), employee_path(@similar_employees.first) %>
+ <% end -%>
+ <%= @similar_employees.first.first_name %> <%= @similar_employees.first.last_name %>
+ <%= @similar_employees.first.job_title %>
+
+ <% if (@similar_employees[1]) %>
+
+ <%if @similar_employees[1].picture_url -%>
+ <%= link_to image_tag("#{@similar_employees[1].picture_url}", :size => "80x80", :class => "profile-img", :alt => "#{@similar_employees[1].first_name} #{@similar_employees[1].last_name}"), edit_employee_path(@similar_employees[1]) %>
+ <% else -%>
+ <%= link_to image_tag("generic.profile.gif", :size => "80x80", :class => "profile-img", :alt => "No Image Found"), employee_path(@similar_employees[1]) %>
+ <% end -%>
+ <%= @similar_employees[1].first_name %> <%= @similar_employees[1].last_name %>
+ <%= @similar_employees[1].job_title %>
+
+ <% end %>
+
+ <% end %>
+
+
diff --git a/app/views/employees/skill.html.erb b/app/views/employees/skill.html.erb
new file mode 100644
index 0000000..90b0a5c
--- /dev/null
+++ b/app/views/employees/skill.html.erb
@@ -0,0 +1,47 @@
+
+
+
Top <%= @tag.upcase %>
+ <% for i in 0..7 #faking this for now %>
+
+
+
+ <%= current_user.first_name %> <%= current_user.last_name %> // <%= current_user.job_title %>
+ Skills:
+ Products:
+ Industry: <%= current_user.industry %>
+
+
+ <% end %>
+
+
+
+
Skills / <%= @tag.upcase %>
+
+
+ <%= link_to(@tag.upcase, "#") %>
+
+ 100 - 80 % (15)
+ 80 - 60 % (20)
+ 60 - 40 % (10)
+ 40 - 20 % (5)
+ 20 - 0 % (5)
+
+
+
+
Interesting Facts
+
+ <%= link_to("Skills","#") %>
+
+ 100% ruby - 90% java
+ 80% ruby - 10% .net
+ 70% ruby - 1% C#
+ 60% ruby - 5% flash
+ 50% ruby - 90% SQL
+ 40% ruby - 90% php
+ 10% ruby - 90% php
+
+
+
+
\ No newline at end of file
diff --git a/app/views/employees/skills.html.erb b/app/views/employees/skills.html.erb
new file mode 100644
index 0000000..03ca372
--- /dev/null
+++ b/app/views/employees/skills.html.erb
@@ -0,0 +1,12 @@
+
+
+ <% @tag_cloud['rows'].each do |tag|
+ percent = tag['value'] * 100 * 3
+ p = percent.to_s
+ styleString = 'width: ' + p + 'px; height: ' + p + 'px; -webkit-border-radius: ' + p + 'px; -moz-border-radius: ' + p + 'px; border-radius: ' + p + 'px; line-height: ' + p + 'px;'
+ %>
+ <%=h tag['key'] %>
+ <% end %>
+
+
+
diff --git a/app/views/events/_new_employee.html.erb b/app/views/events/_new_employee.html.erb
index aac3ad8..06eb6f3 100644
--- a/app/views/events/_new_employee.html.erb
+++ b/app/views/events/_new_employee.html.erb
@@ -1,2 +1,2 @@
-<%= event.employee.full_name %> registered <%= distance_of_time_in_words_to_now(event.created_at) %> ago
+<%= link_to event.employee.full_name, event.employee %> registered <%= distance_of_time_in_words_to_now(event.created_at) %> ago
diff --git a/app/views/events/_update_profile.html.erb b/app/views/events/_update_profile.html.erb
index ddbaa3c..2121fb7 100644
--- a/app/views/events/_update_profile.html.erb
+++ b/app/views/events/_update_profile.html.erb
@@ -1,2 +1,2 @@
-<%= event.employee.full_name %> update her <%= event.changes.join(', ').strip %> <%= distance_of_time_in_words_to_now(event.created_at) %> ago
+<%= link_to event.employee.full_name, event.employee %> updated <%= event.changes.map{|event| t(event) }.join(', ').strip %> <%= distance_of_time_in_words_to_now(event.created_at) %> ago
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 75902c7..e907163 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -1,5 +1,4 @@
-
@@ -7,17 +6,24 @@
- Skills Database
-
+ <%= render "shared/scripts" %>
+ Skills Database <%= @title %>
<%= render "shared/head" %>
- <%= yield %>
+
+
+ <%= render "shared/header" %>
+
+
+ <%= yield %>
+
- <%= render "shared/scripts" %>
+ <%= render "shared/footer" %>
+