lux-fw 0.1.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/.version +1 -0
  3. data/bin/cli/am +250 -0
  4. data/bin/cli/assets +37 -0
  5. data/bin/cli/console +50 -0
  6. data/bin/cli/dev +1 -0
  7. data/bin/cli/eval +15 -0
  8. data/bin/cli/exceptions +62 -0
  9. data/bin/cli/generate +82 -0
  10. data/bin/cli/get +5 -0
  11. data/bin/cli/nginx +28 -0
  12. data/bin/cli/production +1 -0
  13. data/bin/cli/routes +12 -0
  14. data/bin/cli/server +1 -0
  15. data/bin/cli/stat +1 -0
  16. data/bin/forever +65 -0
  17. data/bin/job_que +39 -0
  18. data/bin/lux +87 -0
  19. data/bin/txt/nginx.conf +29 -0
  20. data/bin/txt/siege-and-puma.txt +3 -0
  21. data/lib/common/base32.rb +47 -0
  22. data/lib/common/before_and_after.rb +71 -0
  23. data/lib/common/class_attributes.rb +66 -0
  24. data/lib/common/class_method_params.rb +94 -0
  25. data/lib/common/crypt.rb +66 -0
  26. data/lib/common/folder_model.rb +50 -0
  27. data/lib/common/generic_model.rb +62 -0
  28. data/lib/common/policy.rb +54 -0
  29. data/lib/common/string_base.rb +49 -0
  30. data/lib/common/url.rb +171 -0
  31. data/lib/lux/api/api.rb +150 -0
  32. data/lib/lux/api/lib/application_api.rb +19 -0
  33. data/lib/lux/api/lib/doc_builder.rb +18 -0
  34. data/lib/lux/api/lib/dsl.rb +73 -0
  35. data/lib/lux/api/lib/model_api.rb +145 -0
  36. data/lib/lux/api/lib/rescue.rb +18 -0
  37. data/lib/lux/cache/cache.rb +71 -0
  38. data/lib/lux/cache/lib/memcached.rb +3 -0
  39. data/lib/lux/cache/lib/null.rb +23 -0
  40. data/lib/lux/cache/lib/ram.rb +38 -0
  41. data/lib/lux/cell/cell.rb +260 -0
  42. data/lib/lux/config/config.rb +88 -0
  43. data/lib/lux/controller/controller.rb +185 -0
  44. data/lib/lux/controller/lib/nav.rb +77 -0
  45. data/lib/lux/controller/lib/plugs.rb +10 -0
  46. data/lib/lux/delayed_job/delayed_job.rb +44 -0
  47. data/lib/lux/delayed_job/lib/memory.rb +14 -0
  48. data/lib/lux/delayed_job/lib/nsq.rb +3 -0
  49. data/lib/lux/delayed_job/lib/postgre.rb +6 -0
  50. data/lib/lux/delayed_job/lib/redis.rb +19 -0
  51. data/lib/lux/error/error.rb +75 -0
  52. data/lib/lux/helper/helper.rb +109 -0
  53. data/lib/lux/html/html.rb +3 -0
  54. data/lib/lux/html/lib/form.rb +81 -0
  55. data/lib/lux/html/lib/input.rb +71 -0
  56. data/lib/lux/html/lib/input_types.rb +277 -0
  57. data/lib/lux/lux.rb +164 -0
  58. data/lib/lux/mailer/mailer.rb +73 -0
  59. data/lib/lux/page/lib/encrypt_params.rb +44 -0
  60. data/lib/lux/page/lib/flash.rb +49 -0
  61. data/lib/lux/page/lib/static_file.rb +97 -0
  62. data/lib/lux/page/page.rb +271 -0
  63. data/lib/lux/rescue_from/rescue_from.rb +61 -0
  64. data/lib/lux/template/template.rb +95 -0
  65. data/lib/lux-fw.rb +48 -0
  66. data/lib/overload/array.rb +52 -0
  67. data/lib/overload/blank.rb +62 -0
  68. data/lib/overload/date.rb +58 -0
  69. data/lib/overload/file.rb +14 -0
  70. data/lib/overload/hash.rb +86 -0
  71. data/lib/overload/hash_wia.rb +282 -0
  72. data/lib/overload/inflections.rb +199 -0
  73. data/lib/overload/integer.rb +19 -0
  74. data/lib/overload/module.rb +10 -0
  75. data/lib/overload/nil.rb +8 -0
  76. data/lib/overload/object.rb +77 -0
  77. data/lib/overload/string.rb +89 -0
  78. data/lib/overload/string_inflections.rb +7 -0
  79. data/lib/overload/struct.rb +5 -0
  80. data/lib/plugins/assets/assets_plug.rb +26 -0
  81. data/lib/plugins/assets/helper_module_adapter.rb +49 -0
  82. data/lib/plugins/assets/init.rb +4 -0
  83. data/lib/plugins/db_helpers/array_and_hstore.rb +64 -0
  84. data/lib/plugins/db_helpers/arrays_and_tags.rb +23 -0
  85. data/lib/plugins/db_helpers/before_save.rb +44 -0
  86. data/lib/plugins/db_helpers/cached_find_by.rb +45 -0
  87. data/lib/plugins/db_helpers/class_and_instance.rb +120 -0
  88. data/lib/plugins/db_helpers/dataset_plugin.rb +101 -0
  89. data/lib/plugins/db_helpers/filter_wrappers.rb +21 -0
  90. data/lib/plugins/db_helpers/link_plugin.rb +95 -0
  91. data/lib/plugins/db_helpers/localize_plugin.rb +57 -0
  92. data/lib/plugins/db_helpers/primary_keys.rb +36 -0
  93. data/lib/plugins/db_helpers/typero_attributes.rb +69 -0
  94. data/lib/plugins/db_logger/init.rb +18 -0
  95. data/lib/plugins/db_logger/lux_response_adapter.rb +9 -0
  96. data/lib/plugins/paginate/helper.rb +32 -0
  97. data/lib/plugins/paginate/sequel_adapter.rb +18 -0
  98. data/lib/vendor/mini_assets/mini_asset/base.rb +167 -0
  99. data/lib/vendor/mini_assets/mini_asset/css.rb +38 -0
  100. data/lib/vendor/mini_assets/mini_asset/js.rb +38 -0
  101. data/lib/vendor/mini_assets/mini_asset.rb +31 -0
  102. data/lib/vendor/oauth/lib/facebook.rb +35 -0
  103. data/lib/vendor/oauth/lib/github.rb +37 -0
  104. data/lib/vendor/oauth/lib/google.rb +41 -0
  105. data/lib/vendor/oauth/lib/linkedin.rb +41 -0
  106. data/lib/vendor/oauth/lib/stackexchange.rb +37 -0
  107. data/lib/vendor/oauth/lib/twitter.rb +41 -0
  108. data/lib/vendor/oauth/oauth.rb +46 -0
  109. metadata +334 -0
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'typero'
4
+
5
+ module Sequel::Plugins::TyperoAttributes
6
+ module ClassMethods
7
+ def attributes(&block)
8
+ self.instance_variable_set :@typero_rule, Typero.new(&block)
9
+ end
10
+
11
+ def typero_schema
12
+ self.instance_variable_get :@typero_rule
13
+ end
14
+ end
15
+
16
+ module InstanceMethods
17
+ # calling typero! on any object will validate all fields
18
+ def typero! field_name=nil
19
+ typero = self.class.typero_schema || return
20
+
21
+ typero.validate(self) { |name, err| errors.add(name, err) unless (errors.on(name) || []).include?(err) }
22
+
23
+ # this are rules unique to database, so we check them here
24
+ typero.rules.each do |field, rule|
25
+ # check uniqe fields
26
+ if rule[:uniq]
27
+ id = self[:id] || 0
28
+ value = self[field]
29
+
30
+ # we only check if field is changed
31
+ if column_changed?(field) && self.class.xwhere('LOWER(%s)=LOWER(?) and id<>?' % field, value, id).first
32
+ error = rule[:uniq].class == TrueClass ? %[Value '"#{value}"' for #{field} allready exists] : rule[:uniq]
33
+ errors.add(field, error) unless (errors.on(field) || []).include?(error)
34
+ end
35
+ end
36
+
37
+ # check protected fields
38
+ if rule[:protected] && self[:id]
39
+ if column_changed?(field)
40
+ error = rule[:protected].class == TrueClass ? "value once defined can't be overwritten." : rule[:protected]
41
+ errors.add(field, error) unless (errors.on(field) || []).include?(error)
42
+ end
43
+ end
44
+ end
45
+
46
+ # check single field if single field given
47
+ if field_name
48
+ raise ArgumentError.new 'Field :%s not found in %s' % [field_name, self] unless self[field_name]
49
+ return unless errors.on(field_name)
50
+
51
+ errors.on(field_name).join(', ')
52
+ end
53
+
54
+ true
55
+ end
56
+
57
+ def validate
58
+ typero!
59
+ super
60
+ end
61
+ end
62
+
63
+ module DatasetMethods
64
+
65
+ end
66
+ end
67
+
68
+ Sequel::Model.plugin :typero_attributes
69
+
@@ -0,0 +1,18 @@
1
+ # Logs DB queries in console
2
+ # to active just load the file
3
+ logger = Logger.new(STDOUT)
4
+
5
+ logger.formatter = proc { |severity, datetime, progname, msg|
6
+ elms = msg.split(/\(|s\)\s/, 3)
7
+ time = (elms[1].to_f * 1000).round(1)
8
+ if Thread.current[:db_q]
9
+ Thread.current[:db_q][:time] += elms[1].to_f
10
+ Thread.current[:db_q][:cnt] += 1
11
+
12
+ # append debug=true as query-string to see database queries
13
+ Lux.log(" #{Thread.current[:db_q][:cnt].to_s.rjust(2)}. #{time} : #{elms[2].cyan}\n") if Thread.current[:db_q]
14
+ end
15
+ }
16
+
17
+ DB.loggers << logger
18
+
@@ -0,0 +1,9 @@
1
+ class Lux::Page
2
+ before do
3
+ Thread.current[:db_q] = { time: 0.0, cnt: 0 }
4
+ end
5
+
6
+ after do
7
+ Lux.log " #{Thread.current[:db_q][:cnt]} DB queries, #{(Thread.current[:db_q][:time]*1000).round(1)} ms" if Thread.current[:db_q][:cnt] > 0
8
+ end
9
+ end
@@ -0,0 +1,32 @@
1
+ module DefaultHelper
2
+
3
+ def paginate list
4
+ return unless list.respond_to?(:paginate_size)
5
+ return nil if list.paginate_page == 1 && list.length < list.paginate_size
6
+
7
+ ret = ['<div class="paginate"><div>']
8
+
9
+ if list.paginate_page > 1
10
+ url = Url.current
11
+ list.paginate_page == 1 ? url.delete(list.paginate_param) : url.qs(list.paginate_param, list.paginate_page-1)
12
+ ret.push %[<a href="#{url.relative}">&larr;</a>]
13
+ else
14
+ ret.push %[<span>&larr;</span>]
15
+ end
16
+
17
+ ret.push %[<i>#{list.paginate_page == 1 ? '&bull;' : list.paginate_page}</i>]
18
+
19
+ if list.paginate_size == list.length
20
+ url = Url.current
21
+ url.qs(list.paginate_param, list.paginate_page+1)
22
+ ret.push %[<a href="#{url.relative}">&rarr;</a>]
23
+ else
24
+ ret.push %[<span>&rarr;</span>]
25
+ end
26
+
27
+ ret.push '</div></div>'
28
+ ret.join('')
29
+ end
30
+
31
+ end
32
+
@@ -0,0 +1,18 @@
1
+ module Sequel::Plugins::LuxSimplePaginate
2
+ module DatasetMethods
3
+ def page size: 20, param: :page, page: nil
4
+ page = (page || Lux.page.params[param]).to_i
5
+ page = 1 if page < 1
6
+
7
+ ret = paginate(page, size).all
8
+ ret.define_singleton_method(:paginate_param) do; param ;end
9
+ ret.define_singleton_method(:paginate_page) do; page ;end
10
+ ret.define_singleton_method(:paginate_size) do; size ;end
11
+
12
+ ret
13
+ end
14
+ end
15
+ end
16
+
17
+ Sequel::Model.db.extension :pagination
18
+ Sequel::Model.plugin :lux_simple_paginate
@@ -0,0 +1,167 @@
1
+ class MiniAsset::Base
2
+ attr_reader :error
3
+
4
+ def initialize source, opts={}
5
+ @source = source
6
+ @opts = opts
7
+
8
+ raise 'Bad source: %s' % source unless File.exist?(local_file)
9
+ end
10
+
11
+ def run! what
12
+ puts what.yellow
13
+
14
+ stdin, stdout, stderr, wait_thread = Open3.popen3(what)
15
+
16
+ error = stderr.gets
17
+ while line = stderr.gets do
18
+ error += line
19
+ end
20
+
21
+ # node-sass prints to stderror on complete
22
+ error = nil if error && error.index('Rendering Complete, saving .css file...')
23
+
24
+ if error
25
+ File.unlink(cache_file) if File.exists?(cache_file)
26
+ @error = error
27
+ end
28
+ end
29
+
30
+ def production?
31
+ !!@opts[:production]
32
+ end
33
+
34
+ def create file, opts=nil
35
+ MiniAsset.create file, opts || @opts
36
+ end
37
+
38
+ def content
39
+ File.read local_file
40
+ end
41
+
42
+ def ext
43
+ @source.split('.').last.to_sym
44
+ end
45
+
46
+ def asset_join_string
47
+ "\n"
48
+ end
49
+
50
+ def local_file
51
+ 'app/assets/%s' % @source
52
+ end
53
+
54
+ def production_file
55
+ file = MiniAsset.manifest['files'][@source] || raise('Production file not found')
56
+
57
+ 'public%s' % file
58
+ end
59
+
60
+ def cache_file
61
+ 'tmp/assets/%s' % @source.gsub('/', '-')
62
+ end
63
+
64
+ def base_dir
65
+ list = @source.split('/')
66
+ list.pop
67
+ 'app/assets/' + list.join('/')
68
+ end
69
+
70
+ def resolve_file files
71
+ files = files.sub(/^\.\//,'')
72
+ files += '/*' unless files.include?('*')
73
+
74
+ path = '%s/%s' % [base_dir, files]
75
+ @files += Dir[path].sort.map{ |f| f.split('app/assets/', 2).last }
76
+ end
77
+
78
+ def files
79
+ return @files if @files
80
+
81
+ @files = []
82
+
83
+ for line in content.split($/)
84
+ test = line.split(/^[\/\/#]=\s*req\w*\s+/)
85
+ resolve_file test[1] if test[1]
86
+ end
87
+
88
+ @files.push @source
89
+ @files
90
+ end
91
+
92
+ def path_for_comment
93
+ '/* Source: %s */' % @source
94
+ end
95
+
96
+ def do_compile?
97
+ return true unless File.exists?(cache_file)
98
+ return true if File.mtime(cache_file).to_i <= File.mtime(local_file).to_i
99
+ false
100
+ end
101
+
102
+ # compiles all the files, allways for production
103
+ def compile args=[]
104
+ data = []
105
+
106
+ for file in files
107
+ asset = create file, production: true
108
+ data.push asset.path_for_comment
109
+ data.push asset.compiled_data
110
+ end
111
+
112
+ data = data.join(asset_join_string)
113
+ pfile = update_manifest(data)
114
+
115
+ unless File.exists? pfile
116
+ File.write(pfile, data)
117
+ minify!
118
+ end
119
+
120
+ if args.include?('gzip')
121
+ gzip!
122
+ else
123
+ gzip_file = '%s.gz' % pfile
124
+ File.unlink gzip_file if File.exists?(gzip_file)
125
+ end
126
+
127
+ fix_created_times!
128
+
129
+ pfile
130
+ end
131
+
132
+ # compiles single current file
133
+ def compiled_data
134
+ content
135
+ end
136
+
137
+ def minify!
138
+ true
139
+ end
140
+
141
+ def gzip!
142
+ f = production_file
143
+ run! "gzip -f -c -1 '%{f}' > '%{f}.gz'" % { f: f } unless File.exists?('%s.gz' % f)
144
+ end
145
+
146
+ def fix_created_times!
147
+ touch_file = 'public/touch.ref'
148
+ `touch '#{touch_file}'` unless File.exists?(touch_file)
149
+
150
+ # touch and fix reference
151
+ `touch -r '#{touch_file}' #{production_file}`
152
+ `touch -r '#{touch_file}' #{production_file}.gz` if File.exists?("#{production_file}.gz")
153
+ end
154
+
155
+ def update_manifest data
156
+ digest = Digest::SHA1.hexdigest(data.to_s)
157
+ json = MiniAsset.manifest
158
+
159
+ pfile = cache_file.sub('tmp/assets/', 'public/assets/')
160
+ pfile = pfile.sub(/\.(\w+)/, "-#{digest}.\\1")
161
+
162
+ json['files'][@source] = pfile.sub('public/', '/')
163
+ MiniAsset.manifest json
164
+ pfile
165
+ end
166
+
167
+ end
@@ -0,0 +1,38 @@
1
+ class MiniAsset::Css < MiniAsset::Base
2
+
3
+ def content_type
4
+ 'text/css'
5
+ end
6
+
7
+ def cache_file
8
+ super.sub(/\.(\w+)/, "#{production? ? '-p' : ''}.\\1").sub('.scss', '.css')
9
+ end
10
+
11
+ def update_cache
12
+ node_sass = './node_modules/node-sass/bin/node-sass'
13
+ node_opts = production? ? '--output-style compressed' : '--source-comments'
14
+ run! "#{node_sass} #{node_opts} '#{local_file}' '#{cache_file}'"
15
+ end
16
+
17
+ def compiled_data
18
+ if do_compile?
19
+ update_cache
20
+ else
21
+ # extract linked files from css cache and compile if needed
22
+ data = File.read cache_file
23
+ files = []
24
+ data.gsub(%r{(app/assets/[\w\-\./]+)}) { files.push($1) unless files.include?($1) }
25
+
26
+ final_check = false
27
+ cache_time = File.mtime(cache_file).to_i
28
+ for file in files
29
+ final_check ||= true if cache_time <= File.mtime(file).to_i
30
+ end
31
+
32
+ update_cache if final_check
33
+ end
34
+
35
+ File.read cache_file
36
+ end
37
+
38
+ end
@@ -0,0 +1,38 @@
1
+ class MiniAsset::Js < MiniAsset::Base
2
+
3
+ def content_type
4
+ 'text/javascript'
5
+ end
6
+
7
+ def asset_join_string
8
+ ";\n"
9
+ end
10
+
11
+ def cache_file
12
+ super.sub('.coffee', '.js')
13
+ end
14
+
15
+ def compiled_data
16
+ return content if ext == :js
17
+
18
+ if ext == :coffee && do_compile?
19
+ coffee_path = './node_modules/coffee-script/bin/coffee'
20
+ coffee_opts = production? ? '-cp' : '-Mcp --no-header'
21
+
22
+ run! "#{coffee_path} #{coffee_opts} '#{local_file}' > '#{cache_file}'"
23
+
24
+ data = File.read cache_file
25
+ data.gsub!(%r{//#\ssourceURL=[\w\-\.\/]+/app/assets/}, '//# sourceURL=/raw_asset/')
26
+ File.write cache_file, data
27
+ end
28
+
29
+ File.read cache_file
30
+ end
31
+
32
+ def minify!
33
+ if [:coffee, :js].include?(ext)
34
+ run! `./node_modules/minifier/index.js --output '#{production_file}' '#{production_file}'`
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,31 @@
1
+ # asset = MiniAsset.create 'admin/index.scss'
2
+ # asset.files # find linked files
3
+ # asset.compile # compile for production and update public/maifest.json
4
+ # asset.content_type
5
+ # asset.compiled_data # get compiled data
6
+
7
+ module MiniAsset
8
+ extend self
9
+
10
+ def create file, opts={}
11
+ type = file.split('.').last.to_sym
12
+
13
+ klass = MiniAsset::Js if [:js, :coffee].include?(type)
14
+ klass = MiniAsset::Css if [:scss].include?(type)
15
+
16
+ raise 'Not supported %s' % type unless klass
17
+
18
+ klass.new file, opts
19
+ end
20
+
21
+ def manifest json=nil
22
+ @manifest ||= Pathname.new 'public/assets/manifest.json'
23
+ @manifest.write '{"files":{}}' unless @manifest.exist?
24
+ @manifest.write json.to_json if json
25
+ JSON.load @manifest.read
26
+ end
27
+ end
28
+
29
+ require_relative './mini_asset/base'
30
+ require_relative './mini_asset/js'
31
+ require_relative './mini_asset/css'
@@ -0,0 +1,35 @@
1
+ # https://developers.facebook.com
2
+ # https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow
3
+
4
+ class LuxOauth::Facebook < LuxOauth
5
+ def login
6
+ 'https://www.facebook.com/v2.8/dialog/oauth?scope=email&client_id=%s&redirect_uri=%s' % [@key, CGI::escape(redirect_url)]
7
+ end
8
+
9
+ def format_response opts
10
+ {
11
+ email: opts['email'],
12
+ avatar: '//graph.facebook.com/%s/picture?type=large' % opts['id'],
13
+ name: opts['name']
14
+ }
15
+ end
16
+
17
+ def callback(session_code)
18
+ result = RestClient.post('https://graph.facebook.com/v2.8/oauth/access_token', {
19
+ redirect_uri: redirect_url,
20
+ client_id: @key,
21
+ client_secret: @secret,
22
+ code: session_code
23
+ }, { :accept => :json })
24
+
25
+ access_token = JSON.parse(result)['access_token']
26
+
27
+ response = RestClient.get('https://graph.facebook.com/me', {
28
+ :accept => :json,
29
+ :params => { :access_token => access_token }
30
+ })
31
+
32
+ format_response JSON.parse response
33
+ end
34
+ end
35
+
@@ -0,0 +1,37 @@
1
+ # https://github.com/github/platform-samples/tree/master/api/ruby/basics-of-authentication
2
+ # https://github.com/settings/applications/404731
3
+
4
+ class LuxOauth::Github < LuxOauth
5
+ def login
6
+ "https://github.com/login/oauth/authorize?scope=user:email&client_id=#{@key}"
7
+ end
8
+
9
+ def format_response opts
10
+ {
11
+ email: opts['email'],
12
+ avatar: opts['avatar_url'],
13
+ github: opts['login'],
14
+ company: opts['company'],
15
+ location: opts['location'],
16
+ bio: opts['description'],
17
+ name: opts['name']
18
+ }
19
+ end
20
+
21
+ def callback session_code
22
+ result = RestClient.post('https://github.com/login/oauth/access_token', {
23
+ client_id: @key,
24
+ client_secret: @secret,
25
+ code: session_code
26
+ }, { :accept => :json })
27
+
28
+ # extract token and granted scopes
29
+ access_token = JSON.parse(result)['access_token']
30
+ # scopes = JSON.parse(result)['scope'].split(',')
31
+
32
+ opts = JSON.parse(RestClient.get('https://api.github.com/user', {:params => {:access_token => access_token}, :accept => :json}))
33
+
34
+ format_response opts
35
+ end
36
+ end
37
+
@@ -0,0 +1,41 @@
1
+ # https://console.developers.google.com
2
+ # https://developers.google.com/identity/protocols/googlescopes
3
+
4
+ class LuxOauth::Google < LuxOauth
5
+ def scope
6
+ [
7
+ 'https://www.googleapis.com/auth/userinfo.email',
8
+ 'https://www.googleapis.com/auth/userinfo.profile'
9
+ ]
10
+ end
11
+
12
+ def format_response opts
13
+ {
14
+ email: opts['email'],
15
+ name: opts['name'],
16
+ avatar: opts['picture'],
17
+ locale: opts['locale'],
18
+ gender: opts['gender']
19
+ }
20
+ end
21
+
22
+ def login
23
+ "https://accounts.google.com/o/oauth2/auth?client_id=#{@key}&redirect_uri=#{redirect_url}&scope=#{scope.join('%20')}&response_type=code"
24
+ end
25
+
26
+ def callback(session_code)
27
+ result = RestClient.post('https://www.googleapis.com/oauth2/v3/token', {
28
+ grant_type: 'authorization_code',
29
+ client_id: @key,
30
+ client_secret: @secret,
31
+ code: session_code,
32
+ redirect_uri: redirect_url
33
+ })
34
+
35
+ hash = JSON.parse(result)
36
+
37
+ user = JSON.parse RestClient.get('https://www.googleapis.com/oauth2/v1/userinfo', { :params => {:access_token => hash['access_token'], :alt=>:json }})
38
+
39
+ format_response user
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ # https://developer.linkedin.com/docs/oauth2
2
+ # https://developer.linkedin.com/docs/fields/basic-profile
3
+
4
+ class LuxOauth::Linkedin < LuxOauth
5
+ def scope
6
+ [
7
+ 'r_basicprofile',
8
+ 'r_emailaddress'
9
+ ]
10
+ end
11
+
12
+ def login
13
+ "https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=#{@key}&redirect_uri=#{redirect_url}&state=987654321&scope=#{scope.join('%20')}"
14
+ end
15
+
16
+ def format_response opts
17
+ {
18
+ email: opts['emailAddress'],
19
+ linkedin: opts['publicProfileUrl'],
20
+ description: opts['specialties'],
21
+ location: opts['location'],
22
+ avatar: opts['pictureUrl'],
23
+ name: "#{opts['firstName']} #{opts['lastName']}"
24
+ }
25
+ end
26
+
27
+ def callback(session_code)
28
+ result = RestClient.post('https://www.linkedin.com/oauth/v2/accessToken', {
29
+ grant_type: 'authorization_code',
30
+ client_id: @key,
31
+ client_secret: @secret,
32
+ code: session_code,
33
+ redirect_uri: redirect_url
34
+ })
35
+
36
+ access_token = JSON.parse(result)['access_token']
37
+ opts = JSON.parse RestClient::Request.execute(:method=>:get, :url=>'https://api.linkedin.com/v1/people/~:(id,picture-url,first-name,last-name,email-address,public-profile-url,specialties,location)?format=json', :headers => {'Authorization'=>"Bearer #{access_token}"})
38
+
39
+ format_response opts
40
+ end
41
+ end
@@ -0,0 +1,37 @@
1
+ # https://api.stackexchange.com/docs/authentication
2
+
3
+ class LuxOauth::Stackexchange < LuxOauth
4
+ def login
5
+ 'https://stackexchange.com/oauth?client_id=%d&redirect_uri=%s' % [ENV.fetch('STACKEXCHANGE_OAUTH_ID'), CGI::escape(redirect_url)]
6
+ end
7
+
8
+ def format_response
9
+ {
10
+ stackexchnage_user_id: opts['items'].first['user_id'],
11
+ user: opts['items'].first
12
+ }
13
+ end
14
+
15
+ def callback session_code
16
+ result = RestClient.post('https://stackexchange.com/oauth/access_token', {
17
+ redirect_uri: redirect_url,
18
+ client_id: ENV.fetch('STACKEXCHANGE_OAUTH_ID'),
19
+ client_secret: @secret,
20
+ code: session_code
21
+ }, { :accept => :json })
22
+
23
+ access_token = result.to_s.css_to_hash['access_token']
24
+
25
+ response = RestClient.get('https://api.stackexchange.com/2.2/me', {
26
+ accept: :json,
27
+ params: {
28
+ site: 'stackoverflow',
29
+ access_token: access_token,
30
+ key: @key
31
+ }
32
+ })
33
+
34
+ format_response JSON.parse response
35
+ end
36
+ end
37
+
@@ -0,0 +1,41 @@
1
+ # https://developer.linkedin.com/docs/oauth2
2
+ # https://developer.linkedin.com/docs/fields/basic-profile
3
+
4
+ class LuxOauth::Twitter < LuxOauth
5
+ # def scope
6
+ # [
7
+ # 'r_basicprofile',
8
+ # 'r_emailaddress'
9
+ # ]
10
+ # end
11
+
12
+ # def login
13
+ # 'https://api.twitter.com/oauth/authorize?oauth_token=%s' % @key
14
+ # end
15
+
16
+ # def format_response opts
17
+ # {
18
+ # email: opts['emailAddress'],
19
+ # linkedin: opts['publicProfileUrl'],
20
+ # description: opts['specialties'],
21
+ # location: opts['location'],
22
+ # avatar: opts['pictureUrl'],
23
+ # name: "#{opts['firstName']} #{opts['lastName']}"
24
+ # }
25
+ # end
26
+
27
+ # def callback(session_code)
28
+ # result = RestClient.post('https://www.linkedin.com/oauth/v2/accessToken', {
29
+ # grant_type: 'authorization_code',
30
+ # client_id: @key,
31
+ # client_secret: @secret,
32
+ # code: session_code,
33
+ # redirect_uri: redirect_url
34
+ # })
35
+
36
+ # access_token = JSON.parse(result)['access_token']
37
+ # opts = JSON.parse RestClient::Request.execute(:method=>:get, :url=>'https://api.linkedin.com/v1/people/~:(id,picture-url,first-name,last-name,email-address,public-profile-url,specialties,location)?format=json', :headers => {'Authorization'=>"Bearer #{access_token}"})
38
+
39
+ # format_response opts
40
+ # end
41
+ end