linkedin2cv 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d62bfd1c1f730f996da843ce11a63b400f3c7cbb
4
- data.tar.gz: 72139b2c8f2d664429de8b33c876ade5463207ba
3
+ metadata.gz: c48a59e31c94af34237c92f71a6872892289589c
4
+ data.tar.gz: 1dccf11adb9d8481312779c47dd0ecba6a919d46
5
5
  SHA512:
6
- metadata.gz: d18f5df837e060d5b5fb79bff0ec69b2c50fda290e2f9027d2aa78e3e38355cb6f0e6f0f3494648194601943f0180bbe0d8e1f442b394000990781ed9d8d2f03
7
- data.tar.gz: 8f918db4c0368dcac90545a67222c7654bb6d0f66da04b1bb9827ac1ebc4667da39999c61dd0e844950671fbf4d0095dfa3a85d7308e7d17ab7600f6ff9614d7
6
+ metadata.gz: a286e40bdea56ddde934ead557fc7eff9e36ec3d6986a7642edb9a1e7d4a6a8408246a0388a731977ddf8d4c778171078567b3b528b0915b7e6edc5c33b0a6f1
7
+ data.tar.gz: 335e4ba1a22918848c0327021cb39babe78b6819c9d796243884b5cba8420207ecfbbfc67e070098994cf64bd193ab1c8b516300cb2cdf93f180fd6ded3c6623
@@ -1,2 +1,2 @@
1
1
  https://github.com/heroku/heroku-buildpack-ruby.git
2
- https://github.com/mefellows/heroku-buildpack-nodejs
2
+ https://github.com/mefellows/heroku-buildpack-tex.git
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  .sass-cache/
3
3
  *.gem
4
4
  bin/*
5
- !bin/placeholder
5
+ !bin/linkedin2cv
6
6
  .env
7
- .token
7
+ .token
8
+ vendor/
data/Procfile CHANGED
@@ -1,3 +1 @@
1
- # web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb
2
- web: bundle exec thin start -p $PORT
3
- #web: bundle exec puma -p $PORT
1
+ web: bundle exec thin start -p $PORT
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  LinkedIn 2 CV
2
2
  ==============
3
3
 
4
- Turn your LinkedIn Profile into a professional resume in many formats (PDF / HTML5 / Latex / Asciidoc)
4
+ Turn your LinkedIn Profile into a professional resume in many formats (PDF / HTML5 / LaTeX / Asciidoc)
5
5
 
6
6
  ## Motivations
7
7
 
@@ -11,7 +11,7 @@ Oh, and don't bother using the LinkedIn 'Export to PDF' feature - it sucks.
11
11
 
12
12
  ## Getting Started
13
13
 
14
- First, install [MacTex](http://www.tug.org/mactex/) so that you can produce LaTeX documents. Then, simply run the converter:
14
+ First, install a Tex distribution ([MacTex](http://www.tug.org/mactex/) or [TexLive](http://www.tug.org/texlive/)) so that you can produce LaTeX documents. Then, simply run the converter:
15
15
 
16
16
  gem install linkedin2resume
17
17
  linkedin2cv convert --format latex --options config.yml matt.fellows
@@ -6,6 +6,7 @@ require 'sinatra/param'
6
6
  require "sinatra/json"
7
7
  require "json"
8
8
  require "sinatra-websocket"
9
+ require "linkedin2cv/converter"
9
10
 
10
11
  #
11
12
  # Public: API for the Application
@@ -14,8 +15,16 @@ module Linkedin2CV
14
15
  module Routes
15
16
  class API < Sinatra::Application
16
17
  helpers Sinatra::Param
18
+ use Rack::Logger
17
19
 
18
20
  configure do
21
+ set :views, 'app/views'
22
+ set :public_folder, 'public/dist'
23
+ set :api, ENV['LINKEDIN_API_KEY']
24
+ set :secret, ENV["LINKEDIN_API_SECRET"]
25
+ set :logging, true
26
+ set :server, 'thin'
27
+ set :port, 5000
19
28
  set :json_encoder, :to_json
20
29
  set :sockets, []
21
30
  end
@@ -36,8 +45,23 @@ module Linkedin2CV
36
45
  # Public: Main API entry point to run the Linkedin2CV service
37
46
  #
38
47
  #
39
- get '/api/linkedin2cv /:uri' do
48
+ get '/api/cv/:name' do
40
49
 
50
+ param :format, String, default: 'latex'
51
+ param :name, String, required: true
52
+ param :access_token, String, required: true
53
+
54
+ logger.debug("Request received to create a CV. Format: #{params[:format]}, Name: #{params[:name]}, Token: #{params[:access_token]}")
55
+
56
+ options = {}
57
+ options['output_file'] = "/tmp/#{params[:name]}"
58
+ options['format'] = params[:format]
59
+
60
+ converter = Linkedin2CV::Converter.new(params[:access_token])
61
+ converter.create_resume(options)
62
+
63
+ content_type "application/pdf"
64
+ File.read("#{options['output_file']}.pdf")
41
65
  end
42
66
 
43
67
 
@@ -90,9 +114,9 @@ module Linkedin2CV
90
114
  # Override this for custom behaviour.
91
115
  #
92
116
  def checkPong(msg)
93
- log.debug("Checking ping pong for a ping: " + msg['message'])
117
+ logger.debug("Checking ping pong for a ping: " + msg['message'])
94
118
  if (msg['message'] == 'ping')
95
- log.debug("Ping hit!")
119
+ logger.debug("Ping hit!")
96
120
  response_obj = {'message' => 'pong'}
97
121
  end
98
122
  end
@@ -99,12 +99,13 @@ module Linkedin2CV
99
99
  token = client.request_access_token(code, redirect_uri: "http://#{request.host}:#{request.port}/auth/callback")
100
100
  session[:atoken] = token.token
101
101
 
102
- # Store in env for command line!
103
- file = File.new('.token', 'w')
104
- file.write(token.token)
105
- file.close
106
-
102
+ # CLI Only behaviour
107
103
  if !ENV['CLI_ONLY'].nil?
104
+ # Store in env for command line!
105
+ file = File.new('.token', 'w')
106
+ file.write(token.token)
107
+ file.close
108
+
108
109
  logger.info "Got access token, shutting down!: #{session[:atoken]}"
109
110
  Thread.current.thread_variable_set('access_token', token.token)
110
111
  Thread.kill(Thread.current)
@@ -1,5 +1,5 @@
1
- <!doctype html><!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]--><!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]--><!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]--><!--[if gt IE 8]><!--><html class="no-js"><!--<![endif]--><head><meta charset="utf-8"><title>Linkedin2CV Generator | Generate a Linkedin2CV for your website</title><meta name="description" content=""><meta name="viewport" content="width=device-width"><!-- Place favicon.ico and apple-touch-icon.png in the root directory --><link rel="stylesheet" href="styles/vendor.css"><link rel="stylesheet" href="styles/f24dfdad.main.css"><body ng-app="linkedin2cv GeneratorApp"><!--[if lt IE 7]>
2
- <p class="browselinkedin2cv ">You are using an <strong>outdated</strong> browser. Please <a href="http://browselinkedin2cv .com/">upgrade your browser</a> to improve your experience.</p>
1
+ <!doctype html><!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]--><!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]--><!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]--><!--[if gt IE 8]><!--><html class="no-js"><!--<![endif]--><head><meta charset="utf-8"><title>Linkedin2CV Generator | Generate a Linkedin2CV for your website</title><meta name="description" content=""><meta name="viewport" content="width=device-width"><!-- Place favicon.ico and apple-touch-icon.png in the root directory --><link rel="stylesheet" href="styles/vendor.css"><link rel="stylesheet" href="styles/f24dfdad.main.css"><body ng-app="linkedin2cvGeneratorApp"><!--[if lt IE 7]>
2
+ <p class="browselinkedin2cv">You are using an <strong>outdated</strong> browser. Please <a href="http://browselinkedin2cv.com/">upgrade your browser</a> to improve your experience.</p>
3
3
  <![endif]--><!-- Add your site or application content here --><div class="container" ng-view=""></div><!-- Google Analytics: change UA-XXXXX-X to be your site's ID --><script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
4
4
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
5
5
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
@@ -2,10 +2,8 @@
2
2
  %a{:href => "/auth/logout"} Logout
3
3
  %p= profile.headline
4
4
  %br
5
+ %a{:href => "/api/cv/#{session[:atoken]}?access_token=#{session[:atoken]}"} Download CV
5
6
  %div= "Your token is #{session[:atoken]}"
6
7
 
7
8
  -else
8
9
  %a{:href => "/auth"} Login using LinkedIn
9
-
10
- -if session[:authorize_url]
11
- %p="yo, auth url #{session[:authorize_url]}"
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+
5
+ $: << File.join(File.dirname(__FILE__), "..", "lib")
6
+ require 'linkedin2cv/cli/command'
7
+
8
+ # Setup the app to work from a base Runner/Command etc.
9
+ Linkedin2CV::MainCommand.run
@@ -1,4 +1,5 @@
1
1
  require 'linkedin-oauth2'
2
+ require 'linkedin2cv/logging'
2
3
  require 'asciidoctor'
3
4
  require 'launchy'
4
5
  require 'tempfile'
@@ -13,17 +14,20 @@ module Linkedin2CV
13
14
  class Converter
14
15
  include Logging
15
16
 
16
- TOKEN_WAIT_TIME = 15
17
17
  API_KEY = ENV['LINKEDIN_API_KEY']
18
18
  API_SECRET = ENV["LINKEDIN_API_SECRET"]
19
19
 
20
- def initialize
20
+ def initialize(token = nil)
21
21
  @display_fields = ["company", "publication", "patent", "language", "skills", "certification", "education", "course", "volunteer", "recommendations"]
22
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
+ @token = token
23
24
 
24
25
  # Confirm API keys setup
26
+ raise StandardError, "API_KEY not set" unless !API_KEY.nil?
27
+ raise StandardError, "API_SECRET not set" unless !API_SECRET.nil?
25
28
 
26
29
  # Setup default options to be merged with supplied ones
30
+
27
31
  end
28
32
 
29
33
  # Public: Create a resume given a LinkedIn Profile
@@ -42,25 +46,33 @@ module Linkedin2CV
42
46
 
43
47
  # Currently only supports one LaTeX template
44
48
  renderer = Linkedin2CV::LatexRenderer.new
45
- renderer.latex_pdf(profile, options)
49
+ renderer.render(profile, options)
46
50
  else
47
51
  puts "Sorry mate, I don't yet support the '#{options['format']}' format'"
48
52
  end
49
53
  end
50
54
 
55
+ # Public: Authenticate & Authorize the end user (via OAuth2) and fetch access token
56
+ #
57
+ #
51
58
  def auth
52
- thread = nil
53
- if !File.exists?('.token')
54
- auth_thread = prompt_user_authorisation
59
+ if @token.nil?
60
+ # If in CLI Mode, spawn a thread, run the API and open a browser window
61
+
62
+ thread = nil
63
+ if !File.exists?('.token')
64
+ auth_thread = prompt_user_authorisation
55
65
 
56
- puts "Waiting to retrieve LinkedIn OAuth token"
57
- sleep 1 until auth_thread.thread_variable?('access_token')
66
+ puts "Waiting to retrieve LinkedIn OAuth token"
67
+ sleep 1 until auth_thread.thread_variable?('access_token')
68
+ end
69
+
70
+ # Get Token from environment
71
+ @token = fetch_token_from_tempfile
72
+ puts "I have a token for you: #{@token}"
58
73
  end
59
74
 
60
- # Get Token from environment
61
- token = fetch_token_from_tempfile
62
- puts "I have a token for you: #{token}"
63
- token
75
+ @token
64
76
  end
65
77
 
66
78
  # Public: Fetch Profile Data
@@ -73,15 +85,7 @@ module Linkedin2CV
73
85
 
74
86
  # Get Client info based on fields provided
75
87
  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
-
88
+ client.profile(:fields => @profile_fields)
85
89
  end
86
90
 
87
91
  # Public: Invoke the API and browser session for end user authentication.
@@ -1,52 +1,35 @@
1
1
  module Linkedin2CV
2
2
  class LatexRenderer
3
3
 
4
- # Public: Produce a Latex PDF
4
+ # Public: Render a LaTeX document
5
5
  #
6
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'
7
+ def render(profile, options)
8
+ output = render_latex(profile, options)
32
9
  output_filename = "#{options['output_file']}.latex"
33
- template = Tilt.new('templates/cv.erb')
34
-
35
- output = template.render(self, :profile => profile, :options => options)
10
+ render_pdf(output, output_filename)
11
+ end
36
12
 
13
+ # Public: Produce a Latex PDF
14
+ #
15
+ #
16
+ def render_pdf(output, output_filename)
37
17
  output_file = File.new(output_filename, 'w')
38
18
  output_file.write(output)
39
19
  output_file.close
40
20
 
41
21
  # Make sure this variable is escaped, clearly.....
42
- exec("pdflatex #{output_filename}")
22
+ system("pdflatex -output-directory=/tmp/ #{output_filename}")
43
23
  end
44
24
 
45
- # Public: Produce a Latex
25
+ # Convert a LinkedIn Profile into a LaTeX source document.
46
26
  #
47
27
  #
48
- def latex
49
-
28
+ def render_latex(profile, options)
29
+ require 'tilt/erb'
30
+ template = Tilt.new('templates/cv.erb')
31
+ output = template.render(self, :profile => profile, :options => options)
32
+ output
50
33
  end
51
34
  end
52
35
  end
@@ -62,3 +45,28 @@ class ERB::Compiler
62
45
  end
63
46
 
64
47
  end
48
+
49
+ # Public: Prepare a string for LaTeX rendering.
50
+ #
51
+ # Escapes special chars, replaces etc.
52
+ def clean_latex(s)
53
+ # Clean &
54
+ s = s.gsub(/(?<!\\)\&(?!\\)/, '\\\&')
55
+
56
+ # Clean $
57
+ s = s.gsub(/(?<!\\)\$(?!\\)/, '\\\$')
58
+
59
+ # Clean %
60
+ s = s.gsub(/(?<!\\)%(?!\\)/, '\\\%')
61
+
62
+ # # Clean ~
63
+ s = s.gsub(/\~/, '\\\textasciitilde')
64
+
65
+ # # Clean >
66
+ s = s.gsub(/\>/, '\\\textgreater')
67
+
68
+ # # Clean <
69
+ s = s.gsub(/\</, '\\\textless')
70
+
71
+ s
72
+ end
@@ -1,3 +1,3 @@
1
1
  module Linkedin2CV
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["matt.fellows@onegeek.com.au"]
11
11
  spec.summary = "Linkedin2CV"
12
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"
13
+ spec.homepage = "http://linkedin2cv.herokuapp.com"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
@@ -17,9 +17,9 @@
17
17
  <link rel="stylesheet" href="styles/main.css">
18
18
  <!-- endbuild -->
19
19
  </head>
20
- <body ng-app="linkedin2cv App">
20
+ <body ng-app="linkedin2cvApp">
21
21
  <!--[if lt IE 7]>
22
- <p class="browselinkedin2cv ">You are using an <strong>outdated</strong> browser. Please <a href="http://browselinkedin2cv .com/">upgrade your browser</a> to improve your experience.</p>
22
+ <p class="browselinkedin2cv">You are using an <strong>outdated</strong> browser. Please <a href="http://browselinkedin2cv.com/">upgrade your browser</a> to improve your experience.</p>
23
23
  <![endif]-->
24
24
 
25
25
  <!-- Add your site or application content here -->
@@ -67,7 +67,7 @@
67
67
  <!-- build:js({.tmp,app}) scripts/scripts.js -->
68
68
  <script src="scripts/app.js"></script>
69
69
  <script src="scripts/controllers/main.js"></script>
70
- <script src="scripts/services/linkedin2cv api.js"></script>
70
+ <script src="scripts/services/linkedin2cvapi.js"></script>
71
71
  <!-- endbuild -->
72
72
  </body>
73
73
  </html>
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  angular
4
- .module('linkedin2cv App', [
4
+ .module('linkedin2cvApp', [
5
5
  'ngCookies',
6
6
  'ngResource',
7
7
  'ngSanitize',
8
8
  'ngRoute',
9
- 'linkedin2cv Services'
9
+ 'linkedin2cvServices'
10
10
  ])
11
11
  .config(function ($routeProvider) {
12
12
  $routeProvider
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- angular.module('linkedin2cv App')
3
+ angular.module('linkedin2cvApp')
4
4
  .controller('MainCtrl', ['$scope', '$http', 'Linkedin2CV', function ($scope, $http, Linkedin2CV) {
5
5
 
6
6
  // Default website
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var linkedin2cv Services = angular.module('linkedin2cv Services', ['ngResource']);
3
+ var linkedin2cvServices = angular.module('linkedin2cvServices', ['ngResource']);
4
4
 
5
- linkedin2cv Services.factory('Linkedin2CV', ['$q', '$rootScope', '$interval', function($q, $rootScope, $interval) {
5
+ linkedin2cvServices.factory('Linkedin2CV', ['$q', '$rootScope', '$interval', function($q, $rootScope, $interval) {
6
6
  // We return this object to anything injecting our service
7
7
  var Service = {};
8
8
 
@@ -6,7 +6,7 @@ $icon-font-path: "/bower_components/bootstrap-sass-official/vendor/assets/fonts/
6
6
  @import "../bower_components/bootstrap-sass-official/vendor/assets/stylesheets/bootstrap.scss";
7
7
  // endbower
8
8
 
9
- .browselinkedin2cv {
9
+ .browselinkedin2cv {
10
10
  margin: 0.2em 0;
11
11
  background: #ccc;
12
12
  color: #000;
@@ -1,7 +1,7 @@
1
1
  <div class="header">
2
2
  <ul class="nav nav-pills pull-right">
3
3
  <li class="active"><a ng-href="#">Home</a></li>
4
- <li><a ng-href="http://github.com/mefellows/linkedin2cv -generator">About</a></li>
4
+ <li><a ng-href="http://github.com/mefellows/linkedin2cv-generator">About</a></li>
5
5
  </ul>
6
6
  <h1 class="text-muted">Linkedin2CV App</h1>
7
7
  </div>
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "linkedin2cv -generator",
2
+ "name": "linkedin2cv",
3
3
  "version": "0.0.0",
4
4
  "dependencies": {
5
5
  "angular": "1.2.15",