twimock 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +125 -0
- data/Rakefile +6 -0
- data/db/.gitkeep +0 -0
- data/lib/twimock/access_token.rb +31 -0
- data/lib/twimock/api/account/verify_credentials.rb +40 -0
- data/lib/twimock/api/application.rb +29 -0
- data/lib/twimock/api/intent/sessions.rb +60 -0
- data/lib/twimock/api/oauth/access_token.rb +65 -0
- data/lib/twimock/api/oauth/authenticate.rb +51 -0
- data/lib/twimock/api/oauth/request_token.rb +49 -0
- data/lib/twimock/api/oauth.rb +83 -0
- data/lib/twimock/api.rb +35 -0
- data/lib/twimock/application.rb +21 -0
- data/lib/twimock/auth_hash.rb +8 -0
- data/lib/twimock/config.rb +90 -0
- data/lib/twimock/database/table.rb +359 -0
- data/lib/twimock/database.rb +133 -0
- data/lib/twimock/errors.rb +13 -0
- data/lib/twimock/omniauth/strategies/twitter.rb +28 -0
- data/lib/twimock/omniauth_twitter.rb +36 -0
- data/lib/twimock/request_token.rb +23 -0
- data/lib/twimock/user.rb +58 -0
- data/lib/twimock/version.rb +3 -0
- data/lib/twimock.rb +39 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/api_spec_helper.rb +30 -0
- data/spec/support/omniauth_twitter_helper.rb +26 -0
- data/spec/support/tables_helper.rb +54 -0
- data/spec/support/test_application_helper.rb +9 -0
- data/spec/twimock/access_token_spec.rb +128 -0
- data/spec/twimock/api/account/verify_credentials_spec.rb +125 -0
- data/spec/twimock/api/application_spec.rb +27 -0
- data/spec/twimock/api/intent/sessions_spec.rb +184 -0
- data/spec/twimock/api/oauth/access_token_spec.rb +185 -0
- data/spec/twimock/api/oauth/authenticate_spec.rb +96 -0
- data/spec/twimock/api/oauth/request_token_spec.rb +123 -0
- data/spec/twimock/api_spec.rb +81 -0
- data/spec/twimock/application_spec.rb +120 -0
- data/spec/twimock/auth_hash_spec.rb +7 -0
- data/spec/twimock/config_spec.rb +192 -0
- data/spec/twimock/database/table_spec.rb +769 -0
- data/spec/twimock/database_spec.rb +261 -0
- data/spec/twimock/omniauth_twitter_spec.rb +129 -0
- data/spec/twimock/request_token_spec.rb +140 -0
- data/spec/twimock/user_spec.rb +271 -0
- data/spec/twimock_spec.rb +76 -0
- data/twimock.gemspec +38 -0
- data/view/authenticate.html.erb +23 -0
- metadata +343 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'hashie'
|
3
|
+
require 'twimock/errors'
|
4
|
+
require 'twimock/database'
|
5
|
+
require 'active_support'
|
6
|
+
|
7
|
+
module Twimock
|
8
|
+
module Config
|
9
|
+
mattr_accessor :host
|
10
|
+
mattr_accessor :port
|
11
|
+
mattr_accessor :callback_url
|
12
|
+
|
13
|
+
@@host = "api.twimock.com"
|
14
|
+
@@port = 443
|
15
|
+
@@callback_url = "http://localhost/auth/twiter/callback"
|
16
|
+
|
17
|
+
extend self
|
18
|
+
|
19
|
+
def default_database
|
20
|
+
Twimock::Database.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def database
|
24
|
+
default_database
|
25
|
+
end
|
26
|
+
|
27
|
+
def reset_database
|
28
|
+
db = Twimock::Database.new
|
29
|
+
db.disconnect!
|
30
|
+
db.drop
|
31
|
+
end
|
32
|
+
|
33
|
+
def load_users(ymlfile)
|
34
|
+
load_data = YAML.load_file(ymlfile)
|
35
|
+
raise Twimock::Errors::IncorrectDataFormat.new "data is not Array" unless load_data.kind_of?(Array)
|
36
|
+
|
37
|
+
load_data.each do |app_data|
|
38
|
+
data = Hashie::Mash.new(app_data)
|
39
|
+
app_id = data.id
|
40
|
+
api_key = data.api_key
|
41
|
+
api_secret = data.api_secret
|
42
|
+
users = data.users
|
43
|
+
|
44
|
+
# Validate data format
|
45
|
+
[:id, :api_key, :api_secret, :users].each {|key| validate_format(key, data.send(key)) }
|
46
|
+
users.each do |user|
|
47
|
+
[:id, :name, :password].each {|key| validate_format(key, user.send(key)) }
|
48
|
+
end
|
49
|
+
|
50
|
+
# Create application and user record
|
51
|
+
app = Twimock::Application.create!({ id: app_id, api_key: api_key, api_secret: api_secret })
|
52
|
+
users.each do |options|
|
53
|
+
access_token = AccessToken.new
|
54
|
+
access_token.string = options.delete(:access_token)
|
55
|
+
access_token.secret = options.delete(:access_token_secret)
|
56
|
+
user = Twimock::User.new(options)
|
57
|
+
user.save! unless Twimock::User.find_by_id(user.id)
|
58
|
+
unless Twimock::AccessToken.find_by_string(access_token.string)
|
59
|
+
access_token.user_id = user.id
|
60
|
+
access_token.application_id = app_id
|
61
|
+
access_token.save!
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
AVAILABLE_TYPE = { id: [String, Integer],
|
70
|
+
api_key: [String],
|
71
|
+
api_secret: [String],
|
72
|
+
users: [Array],
|
73
|
+
name: [String],
|
74
|
+
password: [String] }
|
75
|
+
|
76
|
+
def available?(key, value)
|
77
|
+
return false unless AVAILABLE_TYPE[key].any? { |t| value.kind_of?(t) }
|
78
|
+
case value
|
79
|
+
when String, Array
|
80
|
+
value.present?
|
81
|
+
when Integer
|
82
|
+
value >= 0
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def validate_format(key, value)
|
87
|
+
raise Twimock::Errors::IncorrectDataFormat.new "format of #{key} is incorrect" unless available?(key, value)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,359 @@
|
|
1
|
+
require 'twimock/database'
|
2
|
+
require 'sqlite3'
|
3
|
+
require 'hashie'
|
4
|
+
|
5
|
+
module Twimock
|
6
|
+
class Database
|
7
|
+
class Table
|
8
|
+
# 以下は継承先でオーバーライド必須
|
9
|
+
# * TABLE_NAME, COLUMN_NAMES
|
10
|
+
# * initialize()
|
11
|
+
TABLE_NAME = :tables
|
12
|
+
COLUMN_NAMES = [:id, :text, :active, :number, :created_at]
|
13
|
+
CHILDREN = []
|
14
|
+
|
15
|
+
def initialize(options={})
|
16
|
+
opts = Hashie::Mash.new(options)
|
17
|
+
self.id = opts.id
|
18
|
+
self.text = opts.text
|
19
|
+
self.active = opts.active || false
|
20
|
+
self.number = opts.number
|
21
|
+
self.created_at = opts.created_at
|
22
|
+
end
|
23
|
+
|
24
|
+
def save!(options={})
|
25
|
+
persisted? ? update!(options) : insert!(options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def update_attributes!(options)
|
29
|
+
# カラムに含まれるかどうかの確認。なければNoMethodError
|
30
|
+
options.each_key {|key| self.send(key) }
|
31
|
+
persisted? ? update!(options) : insert!(options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def destroy
|
35
|
+
raise unless persisted?
|
36
|
+
self.class.children.each do |klass|
|
37
|
+
klass_last_name = self.class.name.split("::").last.downcase
|
38
|
+
find_method_name = "find_all_by_#{klass_last_name}_id"
|
39
|
+
objects = klass.send(find_method_name, self.id)
|
40
|
+
objects.each{|object| object.destroy }
|
41
|
+
end
|
42
|
+
|
43
|
+
execute "DELETE FROM #{table_name} WHERE ID = #{self.id};"
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def fetch
|
48
|
+
if persisted?
|
49
|
+
sql = "SELECT * FROM #{table_name} WHERE ID = #{self.id} LIMIT 1;"
|
50
|
+
records = execute sql
|
51
|
+
return nil unless record = records.first
|
52
|
+
set_attributes_from_record(record)
|
53
|
+
self
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def method_missing(name, *args)
|
58
|
+
method_name = name.to_s.include?("=") ? name.to_s[0...-1].to_sym : name
|
59
|
+
case name
|
60
|
+
when :identifier then return send(:id)
|
61
|
+
when :identifier= then return send(:id=, *args)
|
62
|
+
else
|
63
|
+
if column_names.include?(method_name) && args.size <= 1
|
64
|
+
if !name.to_s.include?("=") && args.empty?
|
65
|
+
define_column_getter(name)
|
66
|
+
return send(name)
|
67
|
+
else
|
68
|
+
define_column_setter(name)
|
69
|
+
return send(name, args.first)
|
70
|
+
end
|
71
|
+
else
|
72
|
+
super
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.create!(options={})
|
78
|
+
instance = self.new(options)
|
79
|
+
instance.save!
|
80
|
+
instance
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.all
|
84
|
+
records = execute "SELECT * FROM #{table_name};"
|
85
|
+
records_to_objects(records)
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.first
|
89
|
+
records = execute "SELECT * FROM #{table_name} LIMIT 1;"
|
90
|
+
record_to_object(records.first)
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.last
|
94
|
+
records = execute "SELECT * FROM #{table_name} ORDER BY ID DESC LIMIT 1 ;"
|
95
|
+
record_to_object(records.first)
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.where(column)
|
99
|
+
column_name = column.keys.first
|
100
|
+
value = column.values.first
|
101
|
+
column_value = (value.kind_of?(String)) ? "'" + value + "'" : value.to_s
|
102
|
+
|
103
|
+
records = execute "SELECT * FROM #{table_name} WHERE #{column_name} = #{column_value};"
|
104
|
+
records_to_objects(records)
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.method_missing(name, *args)
|
108
|
+
if ((name =~ /^find_by_(.+)/ || name =~ /^find_all_by_(.+)/) &&
|
109
|
+
(column_name = $1) && column_names.include?(column_name.to_sym))
|
110
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" unless args.size == 1
|
111
|
+
define_find_method(name, column_name) ? send(name, args.first) : super
|
112
|
+
else
|
113
|
+
super
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def table_name
|
118
|
+
self.class.table_name
|
119
|
+
end
|
120
|
+
|
121
|
+
def column_names
|
122
|
+
self.class.column_names
|
123
|
+
end
|
124
|
+
|
125
|
+
def persisted?
|
126
|
+
!!(self.id && !(self.class.find_by_id(self.id).nil?))
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.table_name
|
130
|
+
self::TABLE_NAME
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.column_names
|
134
|
+
self::COLUMN_NAMES
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.children
|
138
|
+
self::CHILDREN
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.column_type(column_name)
|
142
|
+
return nil unless column_names.include?(column_name.to_s.to_sym)
|
143
|
+
table_info.send(column_name).type
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.table_info
|
147
|
+
sql = "PRAGMA TABLE_INFO(#{table_name});"
|
148
|
+
records = execute sql
|
149
|
+
info = Hashie::Mash.new
|
150
|
+
records.each do |record|
|
151
|
+
column_info = Hashie::Mash.new(
|
152
|
+
{ cid: record[0],
|
153
|
+
name: record[1].to_sym,
|
154
|
+
type: record[2],
|
155
|
+
notnull: (record[3] == 1),
|
156
|
+
dflt_value: record[4],
|
157
|
+
pk: (record[5] == 1) }
|
158
|
+
)
|
159
|
+
info.send(record[1] + "=", column_info)
|
160
|
+
end
|
161
|
+
info
|
162
|
+
end
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
def execute(sql)
|
167
|
+
self.class.execute(sql)
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.execute(sql)
|
171
|
+
database = Twimock::Database.new
|
172
|
+
records = database.connection.execute sql
|
173
|
+
if records.empty? && sql =~ /^INSERT /
|
174
|
+
records = database.connection.execute <<-SQL
|
175
|
+
SELECT * FROM #{table_name} WHERE ROWID = last_insert_rowid();
|
176
|
+
SQL
|
177
|
+
end
|
178
|
+
database.disconnect!
|
179
|
+
records
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.record_to_object(record)
|
183
|
+
return nil unless record
|
184
|
+
self.new(record_to_hash(record))
|
185
|
+
end
|
186
|
+
|
187
|
+
def self.records_to_objects(records)
|
188
|
+
records.inject([]) do |objects, record|
|
189
|
+
objects << record_to_object(record)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def record_to_hash(record)
|
194
|
+
self.class.record_to_hash(record)
|
195
|
+
end
|
196
|
+
|
197
|
+
# 以下の形式のHashが返される
|
198
|
+
# { id: x, ..., created_at: yyyy-mm-dd :hh:mm +xxxx }
|
199
|
+
def self.record_to_hash(record)
|
200
|
+
hash = Hashie::Mash.new
|
201
|
+
column_names.each_with_index do |column_name, index|
|
202
|
+
value = (record[index] == "") ? nil : record[index]
|
203
|
+
parsed_value = case column_type(column_name)
|
204
|
+
when "BOOLEAN" then eval(value)
|
205
|
+
when "DATETIME" then Time.parse(value)
|
206
|
+
else value
|
207
|
+
end
|
208
|
+
hash.send(column_name.to_s + "=", parsed_value)
|
209
|
+
end
|
210
|
+
hash
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.define_find_method(method_name, column_name)
|
214
|
+
case method_name
|
215
|
+
when /^find_by_(.+)/ then define_find_by_column(column_name)
|
216
|
+
when /^find_all_by_(.+)/ then define_find_all_by_column(column_name)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def self.define_find_by_column(column_name)
|
221
|
+
self.class_eval <<-EOF
|
222
|
+
def self.find_by_#{column_name}(value)
|
223
|
+
return nil if value.nil?
|
224
|
+
|
225
|
+
column_value = case value
|
226
|
+
when String then "'" + value + "'"
|
227
|
+
when Time then "'" + value.to_s + "'"
|
228
|
+
else value.to_s
|
229
|
+
end
|
230
|
+
|
231
|
+
sql = "SELECT * FROM #{table_name} WHERE #{column_name} = "
|
232
|
+
sql += column_value + " LIMIT 1;"
|
233
|
+
records = execute sql
|
234
|
+
record_to_object(records.first)
|
235
|
+
end
|
236
|
+
EOF
|
237
|
+
true
|
238
|
+
end
|
239
|
+
|
240
|
+
def self.define_find_all_by_column(column_name)
|
241
|
+
self.class_eval <<-EOF
|
242
|
+
def self.find_all_by_#{column_name}(value)
|
243
|
+
return [] if value.nil?
|
244
|
+
|
245
|
+
column_value = case value
|
246
|
+
when String then "'" + value + "'"
|
247
|
+
when Time then "'" + value.to_s + "'"
|
248
|
+
else value.to_s
|
249
|
+
end
|
250
|
+
|
251
|
+
sql = "SELECT * FROM #{table_name} WHERE #{column_name} = "
|
252
|
+
sql += column_value + ";"
|
253
|
+
records = execute sql
|
254
|
+
records_to_objects(records)
|
255
|
+
end
|
256
|
+
EOF
|
257
|
+
true
|
258
|
+
end
|
259
|
+
|
260
|
+
def define_column_getter(name)
|
261
|
+
self.class.class_eval <<-EOF
|
262
|
+
def #{name}
|
263
|
+
self.instance_variable_get(:@#{name})
|
264
|
+
end
|
265
|
+
EOF
|
266
|
+
end
|
267
|
+
|
268
|
+
def define_column_setter(name)
|
269
|
+
self.class.class_eval <<-EOF
|
270
|
+
def #{name}(value)
|
271
|
+
instance_variable_set(:@#{name.to_s.gsub("=", "")}, value)
|
272
|
+
end
|
273
|
+
EOF
|
274
|
+
end
|
275
|
+
|
276
|
+
# DatabaseへのINSERTが成功してからインスタンスのフィールド値を更新する
|
277
|
+
def insert!(options={})
|
278
|
+
opts = Hashie::Mash.new(options)
|
279
|
+
instance = self.class.new
|
280
|
+
column_names.each do |column_name|
|
281
|
+
next if column_name == :created_at
|
282
|
+
notnull_check(column_name)
|
283
|
+
instance.send(column_name.to_s + "=", self.send(column_name))
|
284
|
+
|
285
|
+
if opts.send(column_name)
|
286
|
+
instance.send(column_name.to_s + "=", opts.send(column_name))
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
target_column_names = if instance.id
|
291
|
+
column_names
|
292
|
+
else
|
293
|
+
column_names.select{|name| name != :id}
|
294
|
+
end
|
295
|
+
instance.created_at = Time.now
|
296
|
+
target_column_values = target_column_names.inject([]) do |ary, column_name|
|
297
|
+
ary << "'#{instance.send(column_name)}'"
|
298
|
+
end
|
299
|
+
values = target_column_values.join(", ")
|
300
|
+
columns = target_column_names.join(', ')
|
301
|
+
|
302
|
+
sql = "INSERT INTO #{table_name}(#{columns}) VALUES ( #{values} );"
|
303
|
+
records = execute sql
|
304
|
+
set_attributes_from_record(records.first)
|
305
|
+
true
|
306
|
+
end
|
307
|
+
|
308
|
+
def update!(options={})
|
309
|
+
if options.empty?
|
310
|
+
column_names.each do |column_name|
|
311
|
+
if (value = self.send(column_name)) && column_name != :id
|
312
|
+
options[column_name] = value unless options.nil?
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
unless options.empty?
|
318
|
+
target_key_values = options.inject([]) do |ary, (key, value)|
|
319
|
+
ary << (value.kind_of?(Integer) ? "#{key} = #{value}" : "#{key} = '#{value}'")
|
320
|
+
end
|
321
|
+
sql = "UPDATE #{table_name} SET #{target_key_values.join(', ')} WHERE ID = #{self.id};"
|
322
|
+
execute sql
|
323
|
+
end
|
324
|
+
fetch
|
325
|
+
true
|
326
|
+
end
|
327
|
+
|
328
|
+
def set_attributes_from_record(record)
|
329
|
+
hash = record_to_hash(record)
|
330
|
+
column_names.each do |column_name|
|
331
|
+
method_name = column_name.to_s + "="
|
332
|
+
self.send(method_name, hash.send(column_name))
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def column_is_empty?(column_name)
|
337
|
+
return true if self.send(column_name).nil?
|
338
|
+
|
339
|
+
return case self.class.column_type(column_name)
|
340
|
+
when "TEXT", "DATETIME", "BOOLEAN"
|
341
|
+
true if self.send(column_name) == ""
|
342
|
+
else
|
343
|
+
false
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def self.column_notnull(column_name)
|
348
|
+
return nil unless column_names.include?(column_name.to_s.to_sym)
|
349
|
+
table_info.send(column_name).notnull
|
350
|
+
end
|
351
|
+
|
352
|
+
def notnull_check(column_name)
|
353
|
+
if self.class.column_notnull(column_name) && column_is_empty?(column_name)
|
354
|
+
raise Twimock::Errors::ColumnTypeNotNull, "#{column_name} is null"
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'sqlite3'
|
2
|
+
require 'twimock/database/table'
|
3
|
+
|
4
|
+
module Twimock
|
5
|
+
class Database
|
6
|
+
ADAPTER = "sqlite3"
|
7
|
+
DB_DIRECTORY = File.expand_path("../../../db", __FILE__)
|
8
|
+
DEFAULT_DB_NAME = "twimock"
|
9
|
+
TABLE_NAMES = [:applications, :users, :access_tokens, :request_tokens]
|
10
|
+
|
11
|
+
attr_reader :name
|
12
|
+
attr_reader :connection
|
13
|
+
|
14
|
+
def initialize(name=nil)
|
15
|
+
@name = DEFAULT_DB_NAME
|
16
|
+
connect
|
17
|
+
create_tables
|
18
|
+
end
|
19
|
+
|
20
|
+
def connect
|
21
|
+
@connection = SQLite3::Database.new filepath
|
22
|
+
@state = :connected
|
23
|
+
@connection
|
24
|
+
end
|
25
|
+
|
26
|
+
def disconnect!
|
27
|
+
@connection.close
|
28
|
+
@state = :disconnected
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def connected?
|
33
|
+
@state == :connected
|
34
|
+
end
|
35
|
+
|
36
|
+
def drop
|
37
|
+
disconnect!
|
38
|
+
File.delete(filepath) if File.exist?(filepath)
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def clear
|
43
|
+
drop_tables
|
44
|
+
create_tables
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_tables
|
48
|
+
TABLE_NAMES.each do |table_name|
|
49
|
+
self.send "create_#{table_name}_table" unless table_exists?(table_name)
|
50
|
+
end
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
def drop_table(table_name)
|
55
|
+
return false unless File.exist?(filepath) && table_exists?(table_name)
|
56
|
+
@connection.execute "drop table #{table_name};"
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
def drop_tables
|
61
|
+
return false unless File.exist?(filepath)
|
62
|
+
TABLE_NAMES.each{|table_name| drop_table(table_name) }
|
63
|
+
true
|
64
|
+
end
|
65
|
+
|
66
|
+
def filepath
|
67
|
+
name ||= @name
|
68
|
+
File.join(DB_DIRECTORY, "#{@name}.#{ADAPTER}")
|
69
|
+
end
|
70
|
+
|
71
|
+
def table_exists?(table_name)
|
72
|
+
tables = @connection.execute "select * from sqlite_master"
|
73
|
+
tables.each do |table|
|
74
|
+
return true if table[1].to_s == table_name.to_s
|
75
|
+
end
|
76
|
+
false
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def create_applications_table
|
82
|
+
@connection.execute <<-SQL
|
83
|
+
CREATE TABLE applications (
|
84
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
85
|
+
api_key TEXT NOT NULL,
|
86
|
+
api_secret TEXT NOT NULL,
|
87
|
+
created_at DATETIME NOT NULL,
|
88
|
+
UNIQUE(api_secret)
|
89
|
+
);
|
90
|
+
SQL
|
91
|
+
end
|
92
|
+
|
93
|
+
def create_users_table
|
94
|
+
@connection.execute <<-SQL
|
95
|
+
CREATE TABLE users (
|
96
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
97
|
+
name TEXT NOT NULL,
|
98
|
+
twitter_id TEXT NOT NULL,
|
99
|
+
email TEXT NOT NULL,
|
100
|
+
password TEXT NOT NULL,
|
101
|
+
created_at DATETIME NOT NULL,
|
102
|
+
UNIQUE(twitter_id, email));
|
103
|
+
SQL
|
104
|
+
end
|
105
|
+
|
106
|
+
def create_access_tokens_table
|
107
|
+
@connection.execute <<-SQL
|
108
|
+
CREATE TABLE access_tokens (
|
109
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
110
|
+
string TEXT NOT NULL,
|
111
|
+
secret TEXT NOT NULL,
|
112
|
+
application_id INTEGER,
|
113
|
+
user_id INTEGER NOT NULL,
|
114
|
+
created_at DATETIME NOT NULL,
|
115
|
+
UNIQUE(string, secret));
|
116
|
+
SQL
|
117
|
+
end
|
118
|
+
|
119
|
+
def create_request_tokens_table
|
120
|
+
@connection.execute <<-SQL
|
121
|
+
CREATE TABLE request_tokens (
|
122
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
123
|
+
string TEXT NOT NULL,
|
124
|
+
secret TEXT NOT NULL,
|
125
|
+
verifier TEXT NOT NULL,
|
126
|
+
application_id INTEGER NOT NULL,
|
127
|
+
user_id INTEGER,
|
128
|
+
created_at DATETIME NOT NULL,
|
129
|
+
UNIQUE(string, secret, verifier));
|
130
|
+
SQL
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Twimock
|
2
|
+
module Errors
|
3
|
+
class Error < StandardError; end
|
4
|
+
class ColumnTypeNotNull < Error; end
|
5
|
+
class IncorrectDataFormat < Error; end
|
6
|
+
class InvalidRequestToken < Error; end
|
7
|
+
class InvalidConsumerKey < Error; end
|
8
|
+
class InvalidAccessToken < Error; end
|
9
|
+
class InvalidUsernameOrEmail < Error; end
|
10
|
+
class InvalidPassword < Error; end
|
11
|
+
class ApplicationNotFound < Error; end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Twimock
|
4
|
+
module OmniAuth
|
5
|
+
module Strategies
|
6
|
+
module Twitter
|
7
|
+
def request_phase
|
8
|
+
status, header, body = __request_phase
|
9
|
+
location = URI.parse(header["Location"])
|
10
|
+
|
11
|
+
if status == 302 && location.host == "api.twitter.com"
|
12
|
+
location.host = Twimock::Config.host
|
13
|
+
case Twimock::Config.port
|
14
|
+
when 443 then location.scheme = "https"
|
15
|
+
when 80 then location.scheme = "http"
|
16
|
+
else
|
17
|
+
location.scheme = "http"
|
18
|
+
location.port = Twimock::Config.port
|
19
|
+
end
|
20
|
+
header["Location"] = location.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
[ status, header, body ]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'twimock/omniauth/strategies/twitter'
|
2
|
+
require 'omniauth-twitter'
|
3
|
+
|
4
|
+
module Twimock
|
5
|
+
module OmniAuthTwitter
|
6
|
+
extend self
|
7
|
+
@@enable = false
|
8
|
+
|
9
|
+
def on?
|
10
|
+
@@enable
|
11
|
+
end
|
12
|
+
|
13
|
+
def on
|
14
|
+
unless Twimock::OmniAuthTwitter.on?
|
15
|
+
::OmniAuth::Strategies::Twitter.class_eval do
|
16
|
+
alias_method :__request_phase, :request_phase
|
17
|
+
remove_method :request_phase
|
18
|
+
include Twimock::OmniAuth::Strategies::Twitter
|
19
|
+
end
|
20
|
+
@@enable = true
|
21
|
+
end
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def off
|
26
|
+
if Twimock::OmniAuthTwitter.on?
|
27
|
+
::OmniAuth::Strategies::Twitter.class_eval do
|
28
|
+
alias_method :request_phase, :__request_phase
|
29
|
+
remove_method :__request_phase
|
30
|
+
end
|
31
|
+
@@enable = false
|
32
|
+
end
|
33
|
+
true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'faker'
|
2
|
+
require 'twimock/database/table'
|
3
|
+
|
4
|
+
module Twimock
|
5
|
+
class RequestToken < Database::Table
|
6
|
+
TABLE_NAME = :request_tokens
|
7
|
+
COLUMN_NAMES = [:id, :string, :secret, :verifier, :application_id, :user_id, :created_at]
|
8
|
+
|
9
|
+
def initialize(options={})
|
10
|
+
opts = Hashie::Mash.new(options)
|
11
|
+
id = opts.id.to_i
|
12
|
+
@id = id if id > 0
|
13
|
+
@string = opts.string || Faker::Lorem.characters(32)
|
14
|
+
@secret = opts.secret || Faker::Lorem.characters(32)
|
15
|
+
@verifier = opts.verifier || Faker::Lorem.characters(32)
|
16
|
+
app_id = opts.application_id.to_i
|
17
|
+
@application_id = app_id if app_id > 0
|
18
|
+
user_id = opts.user_id.to_i
|
19
|
+
@user_id = user_id if user_id > 0
|
20
|
+
@created_at = opts.created_at
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|