twimock 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|