linkedin2cv 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.buildpacks +2 -0
  3. data/.bundle/config +1 -0
  4. data/.gitignore +7 -0
  5. data/.node +1 -0
  6. data/.travis.yml +21 -0
  7. data/Gemfile +5 -0
  8. data/Gemfile.lock +119 -0
  9. data/Procfile +3 -0
  10. data/README.md +32 -0
  11. data/Rakefile +6 -0
  12. data/Vagrantfile +16 -0
  13. data/app/routes/api.rb +101 -0
  14. data/app/routes/web.rb +132 -0
  15. data/app/views/hello.erb +36 -0
  16. data/app/views/home.erb +12 -0
  17. data/app/views/index.haml +11 -0
  18. data/app.rb +26 -0
  19. data/config.ru +6 -0
  20. data/config.yml +31 -0
  21. data/lib/linkedin2cv/cli/command.rb +46 -0
  22. data/lib/linkedin2cv/converter.rb +116 -0
  23. data/lib/linkedin2cv/logging.rb +35 -0
  24. data/lib/linkedin2cv/renderer/latex_renderer.rb +64 -0
  25. data/lib/linkedin2cv/version.rb +3 -0
  26. data/linkedin2cv.gemspec +49 -0
  27. data/public/.bowerrc +3 -0
  28. data/public/.editorconfig +21 -0
  29. data/public/.gitattributes +1 -0
  30. data/public/.gitignore +5 -0
  31. data/public/.jshintrc +24 -0
  32. data/public/.travis.yml +7 -0
  33. data/public/Gruntfile.js +487 -0
  34. data/public/app/.buildignore +1 -0
  35. data/public/app/.htaccess +543 -0
  36. data/public/app/404.html +157 -0
  37. data/public/app/favicon.ico +0 -0
  38. data/public/app/images/yeoman.png +0 -0
  39. data/public/app/index.html +73 -0
  40. data/public/app/robots.txt +3 -0
  41. data/public/app/scripts/app.js +20 -0
  42. data/public/app/scripts/controllers/main.js +21 -0
  43. data/public/app/scripts/services/linkedin2cv.js +93 -0
  44. data/public/app/styles/main.scss +95 -0
  45. data/public/app/views/main.html +23 -0
  46. data/public/bower.json +19 -0
  47. data/public/karma-e2e.conf.js +54 -0
  48. data/public/karma.conf.js +56 -0
  49. data/public/package.json +41 -0
  50. data/public/test/.jshintrc +36 -0
  51. data/public/test/runner.html +10 -0
  52. data/public/test/spec/controllers/main.js +22 -0
  53. data/public/test/spec/services/happyapi.js +18 -0
  54. data/public/test/spec/services/happyservice.js +18 -0
  55. data/spec/converter_spec.rb +83 -0
  56. data/spec/mocks/config.yml +31 -0
  57. data/spec/mocks/profile.json +866 -0
  58. data/spec/spec_helper.rb +13 -0
  59. data/templates/cv.erb +327 -0
  60. data/templates/foo.asciidoc +11 -0
  61. data/templates/foo.latex +230 -0
  62. data/test.rb +109 -0
  63. data/test.sh +6 -0
  64. data/teust.rb +75 -0
  65. metadata +434 -0
@@ -0,0 +1,116 @@
1
+ require 'linkedin-oauth2'
2
+ require 'asciidoctor'
3
+ require 'launchy'
4
+ require 'tempfile'
5
+ require 'tilt'
6
+ require 'yaml'
7
+ require 'erb'
8
+ require 'net/http'
9
+
10
+
11
+ module Linkedin2CV
12
+
13
+ class Converter
14
+ include Logging
15
+
16
+ TOKEN_WAIT_TIME = 15
17
+ API_KEY = ENV['LINKEDIN_API_KEY']
18
+ API_SECRET = ENV["LINKEDIN_API_SECRET"]
19
+
20
+ def initialize
21
+ @display_fields = ["company", "publication", "patent", "language", "skills", "certification", "education", "course", "volunteer", "recommendations"]
22
+ @profile_fields = ["projects:(start-date,end-date,description,id,name,url),main-address,phone-numbers,email-address,first-name,last-name,maiden-name,formatted-name,phonetic-first-name,phonetic-last-name,formatted-phonetic-name,headline,location:(name,country:(code)),industry,current-status,current-share,num-connections,num-connections-capped,summary,specialties,positions,picture-url,api-standard-profile-request:(url,headers),public-profile-url,last-modified-timestamp,proposal-comments,associations,interests,publications:(id,title,publisher:(name),authors:(id,name,person),date,url,summary),patents,languages:(id,language:(name),proficiency:(level,name)),skills:(id,skill:(name)),certifications:(id,name,authority:(name),number,start-date,end-date),educations:(id,school-name,field-of-study,start-date,end-date,degree,activities,notes),courses:(id,name,number),three-current-positions:(id,title,summary,start-date,end-date,is-current,company),three-past-positions:(id,title,summary,start-date,end-date,is-current,company),num-recommenders,recommendations-received:(id,recommendation-type,recommendation-text,recommender),mfeed-rss-url,following,job-bookmarks,suggestions,date-of-birth,member-url-resources:(url,name),related-profile-views,honors-awards"]
23
+
24
+ # Confirm API keys setup
25
+
26
+ # Setup default options to be merged with supplied ones
27
+ end
28
+
29
+ # Public: Create a resume given a LinkedIn Profile
30
+ #
31
+ # Takes
32
+ def create_resume(options = {})
33
+
34
+ # Get Profile
35
+ profile = get_profile
36
+
37
+ # Find stylist (LaTeX / Asciidoc etc.)
38
+ # Find output factory/plugin (fetch from Github?)
39
+ case options['format']
40
+ when 'latex'
41
+ require 'linkedin2cv/renderer/latex_renderer'
42
+
43
+ # Currently only supports one LaTeX template
44
+ renderer = Linkedin2CV::LatexRenderer.new
45
+ renderer.latex_pdf(profile, options)
46
+ else
47
+ puts "Sorry mate, I don't yet support the '#{options['format']}' format'"
48
+ end
49
+ end
50
+
51
+ def auth
52
+ thread = nil
53
+ if !File.exists?('.token')
54
+ auth_thread = prompt_user_authorisation
55
+
56
+ puts "Waiting to retrieve LinkedIn OAuth token"
57
+ sleep 1 until auth_thread.thread_variable?('access_token')
58
+ end
59
+
60
+ # Get Token from environment
61
+ token = fetch_token_from_tempfile
62
+ puts "I have a token for you: #{token}"
63
+ token
64
+ end
65
+
66
+ # Public: Fetch Profile Data
67
+ #
68
+ #
69
+ def get_profile
70
+
71
+ # Auth
72
+ token = auth
73
+
74
+ # Get Client info based on fields provided
75
+ client = LinkedIn::Client.new(API_KEY, API_SECRET, token)
76
+ user = client.profile(:fields => @profile_fields)
77
+
78
+ end
79
+
80
+ # Public: Fetches a template for rendering via Asciidoctor
81
+ #
82
+ #
83
+ def lookup_template
84
+
85
+ end
86
+
87
+ # Public: Invoke the API and browser session for end user authentication.
88
+ #
89
+ # Returns a sub-process containing the API session.
90
+ #
91
+ def prompt_user_authorisation
92
+
93
+ require './app/routes/web'
94
+
95
+ # Start local API
96
+ Launchy.open("http://localhost:5000/cli/auth")
97
+
98
+ auth_thread = Thread.new do
99
+ Linkedin2CV::Routes::Web.run!
100
+ end
101
+
102
+ auth_thread
103
+ end
104
+
105
+ # Public: Fetch the token from a temporary oauth token file.
106
+ #
107
+ #
108
+ def fetch_token_from_tempfile
109
+ # Store in env for command line!
110
+ file = File.new('.token', 'r')
111
+ token = file.read
112
+ file.close
113
+ token
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,35 @@
1
+ require 'log4r'
2
+
3
+ # Public: Logging module to mixin with classes.
4
+ #
5
+ #
6
+ module Logging
7
+
8
+ def log
9
+ @log ||= Logging.logger_for(self.class.name)
10
+ end
11
+
12
+ # Use a hash class-ivar to cache a unique Logger per class:
13
+ @loggers = {}
14
+
15
+ class << self
16
+ include Log4r
17
+
18
+ def logger_for(classname)
19
+ @loggers[classname] ||= configure_logger_for(classname)
20
+ end
21
+
22
+ def configure_logger_for(classname)
23
+ logger = Logger.new classname.to_s.gsub(/[^a-zA-Z0-9]/, '.').downcase.gsub(/\.+/, '.')
24
+
25
+ # Log to file or stdout?
26
+ if (ENV['LOG_OUTPUT_FILENAME'] && !ENV['LOG_OUTPUT_FILENAME'].empty?)
27
+ puts ENV['LOG_OUTPUT_FILENAME']
28
+ logger.outputters << Log4r::FileOutputter.new('linkedin2cvlog', :filename => ENV['LOG_OUTPUT_FILENAME'])
29
+ elsif
30
+ logger.outputters << Log4r::StdoutOutputter.new('linkedin2cvlog')
31
+ end
32
+ logger
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,64 @@
1
+ module Linkedin2CV
2
+ class LatexRenderer
3
+
4
+ # Public: Produce a Latex PDF
5
+ #
6
+ #
7
+ def latex_pdf(profile, options)
8
+
9
+ def clean_latex(s)
10
+ # Clean &
11
+ s = s.gsub(/(?<!\\)\&(?!\\)/, '\\\&')
12
+
13
+ # Clean $
14
+ s = s.gsub(/(?<!\\)\$(?!\\)/, '\\\$')
15
+
16
+ # Clean %
17
+ s = s.gsub(/(?<!\\)%(?!\\)/, '\\\%')
18
+
19
+ # # Clean ~
20
+ s = s.gsub(/\~/, '\\\textasciitilde')
21
+
22
+ # # Clean >
23
+ s = s.gsub(/\>/, '\\\textgreater')
24
+
25
+ # # Clean <
26
+ s = s.gsub(/\</, '\\\textless')
27
+
28
+ s
29
+ end
30
+
31
+ require 'tilt/erb'
32
+ output_filename = "#{options['output_file']}.latex"
33
+ template = Tilt.new('templates/cv.erb')
34
+
35
+ output = template.render(self, :profile => profile, :options => options)
36
+
37
+ output_file = File.new(output_filename, 'w')
38
+ output_file.write(output)
39
+ output_file.close
40
+
41
+ # Make sure this variable is escaped, clearly.....
42
+ exec("pdflatex #{output_filename}")
43
+ end
44
+
45
+ # Public: Produce a Latex
46
+ #
47
+ #
48
+ def latex
49
+
50
+ end
51
+ end
52
+ end
53
+
54
+ # Monkey patching jiggery-pokery to escape special LaTeX chars
55
+ # automatically from ERB <%= %> statements
56
+ class ERB::Compiler
57
+ alias_method :old_add_insert_cmd, :add_insert_cmd
58
+ alias_method :old_add_put_cmd, :add_put_cmd
59
+
60
+ def add_insert_cmd(out, content)
61
+ out.push("#{@insert_cmd}(clean_latex( (#{content}).to_s ))")
62
+ end
63
+
64
+ end
@@ -0,0 +1,3 @@
1
+ module Linkedin2CV
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,49 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'linkedin2cv/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "linkedin2cv"
8
+ spec.version = Linkedin2CV::VERSION
9
+ spec.authors = ["mefellows"]
10
+ spec.email = ["matt.fellows@onegeek.com.au"]
11
+ spec.summary = "Linkedin2CV"
12
+ spec.description = "Turn your LinkedIn Profile into a professional resume in many formats (PDF / HTML5 / LaTeX / Asciidoc)"
13
+ spec.homepage = "https://github.com/mefellows/linkedin2cv"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+
25
+ # Needs to be runtime for deployment on Heroku
26
+ spec.add_runtime_dependency "rspec"
27
+ spec.add_runtime_dependency "rake"
28
+ spec.add_runtime_dependency "clamp"
29
+ spec.add_runtime_dependency "json"
30
+ spec.add_runtime_dependency "log4r"
31
+ spec.add_runtime_dependency "sinatra"
32
+ spec.add_runtime_dependency "sinatra-contrib"
33
+ spec.add_runtime_dependency "sinatra-param"
34
+ spec.add_runtime_dependency "eventmachine"
35
+ spec.add_runtime_dependency "em-websocket", '=0.3.6'
36
+ spec.add_runtime_dependency "thin"
37
+ spec.add_runtime_dependency "foreman"
38
+ spec.add_runtime_dependency "dotenv"
39
+ spec.add_runtime_dependency "sinatra-websocket"
40
+
41
+ # Specific App dependencies
42
+ spec.add_runtime_dependency "linkedin-oauth2"
43
+ spec.add_runtime_dependency "haml"
44
+ spec.add_runtime_dependency "asciidoctor"
45
+ spec.add_runtime_dependency "launchy"
46
+ spec.add_runtime_dependency "tilt"
47
+ # spec.add_development_dependency "pact"
48
+ spec.add_development_dependency "webmock"
49
+ end
data/public/.bowerrc ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "directory": "app/bower_components"
3
+ }
@@ -0,0 +1,21 @@
1
+ # EditorConfig helps developers define and maintain consistent
2
+ # coding styles between different editors and IDEs
3
+ # editorconfig.org
4
+
5
+ root = true
6
+
7
+
8
+ [*]
9
+
10
+ # Change these settings to your own preference
11
+ indent_style = space
12
+ indent_size = 2
13
+
14
+ # We recommend you to keep these unchanged
15
+ end_of_line = lf
16
+ charset = utf-8
17
+ trim_trailing_whitespace = true
18
+ insert_final_newline = true
19
+
20
+ [*.md]
21
+ trim_trailing_whitespace = false
@@ -0,0 +1 @@
1
+ * text=auto
data/public/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ node_modules
2
+ dist
3
+ .tmp
4
+ .sass-cache
5
+ app/bower_components
data/public/.jshintrc ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "node": true,
3
+ "browser": true,
4
+ "esnext": true,
5
+ "bitwise": true,
6
+ "camelcase": true,
7
+ "curly": true,
8
+ "eqeqeq": true,
9
+ "immed": true,
10
+ "indent": 2,
11
+ "latedef": true,
12
+ "newcap": true,
13
+ "noarg": true,
14
+ "quotmark": "single",
15
+ "regexp": true,
16
+ "undef": true,
17
+ "unused": true,
18
+ "strict": true,
19
+ "trailing": true,
20
+ "smarttabs": true,
21
+ "globals": {
22
+ "angular": false
23
+ }
24
+ }
@@ -0,0 +1,7 @@
1
+ language: node_js
2
+ node_js:
3
+ - '0.8'
4
+ - '0.10'
5
+ before_script:
6
+ - 'npm install -g bower grunt-cli'
7
+ - 'bower install'