ubiquitously 0.0.1.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data/README.markdown +224 -19
  2. data/Rakefile +12 -4
  3. data/bin/u.me +4 -0
  4. data/lib/ubiquitously.rb +56 -7
  5. data/lib/ubiquitously/commands/base.rb +118 -0
  6. data/lib/ubiquitously/commands/post.rb +108 -0
  7. data/lib/ubiquitously/commands/user.rb +111 -0
  8. data/lib/ubiquitously/extensions/callbacks.rb +62 -0
  9. data/lib/ubiquitously/extensions/core.rb +88 -0
  10. data/lib/ubiquitously/extensions/mechanize.rb +35 -0
  11. data/lib/ubiquitously/models/base.rb +18 -0
  12. data/lib/ubiquitously/models/page.rb +28 -0
  13. data/lib/ubiquitously/models/post.rb +66 -0
  14. data/lib/ubiquitously/models/service.rb +1 -0
  15. data/lib/ubiquitously/models/service/account.rb +57 -0
  16. data/lib/ubiquitously/models/service/account/authorizable.rb +58 -0
  17. data/lib/ubiquitously/models/service/account/loggable.rb +50 -0
  18. data/lib/ubiquitously/models/service/account/restful.rb +21 -0
  19. data/lib/ubiquitously/models/service/post.rb +59 -0
  20. data/lib/ubiquitously/models/service/post/loggable.rb +64 -0
  21. data/lib/ubiquitously/models/service/post/ownable.rb +31 -0
  22. data/lib/ubiquitously/models/service/post/postable.rb +73 -0
  23. data/lib/ubiquitously/models/service/post/restful.rb +52 -0
  24. data/lib/ubiquitously/models/user.rb +128 -0
  25. data/lib/ubiquitously/services/blogger_den.rb +68 -0
  26. data/lib/ubiquitously/services/chetzit.rb +37 -0
  27. data/lib/ubiquitously/services/code_project.rb +21 -0
  28. data/lib/ubiquitously/services/delicious.rb +54 -0
  29. data/lib/ubiquitously/services/design_bump.rb +41 -0
  30. data/lib/ubiquitously/services/designgizer.rb +21 -0
  31. data/lib/ubiquitously/services/designr_fix.rb +21 -0
  32. data/lib/ubiquitously/services/digg.rb +151 -0
  33. data/lib/ubiquitously/services/digzign.rb +25 -0
  34. data/lib/ubiquitously/services/diigo.rb +68 -0
  35. data/lib/ubiquitously/services/dzone.rb +132 -0
  36. data/lib/ubiquitously/services/dzone_snippets.rb +39 -0
  37. data/lib/ubiquitously/services/facebook.rb +42 -0
  38. data/lib/ubiquitously/services/faves.rb +81 -0
  39. data/lib/ubiquitously/services/favshare.rb +78 -0
  40. data/lib/ubiquitously/services/flikode.rb +38 -0
  41. data/lib/ubiquitously/services/friendfeed.rb +21 -0
  42. data/lib/ubiquitously/services/gist.rb +52 -0
  43. data/lib/ubiquitously/services/google_buzz.rb +15 -0
  44. data/lib/ubiquitously/services/identica.rb +15 -0
  45. data/lib/ubiquitously/services/jump_tags.rb +21 -0
  46. data/lib/ubiquitously/services/kailoon.rb +27 -0
  47. data/lib/ubiquitously/services/meta_filter.rb +26 -0
  48. data/lib/ubiquitously/services/mixx.rb +94 -0
  49. data/lib/ubiquitously/services/mmo.rb +22 -0
  50. data/lib/ubiquitously/services/mvc_forge.rb +37 -0
  51. data/lib/ubiquitously/services/my_space.rb +25 -0
  52. data/lib/ubiquitously/services/nestdev.rb +36 -0
  53. data/lib/ubiquitously/services/newsvine.rb +76 -0
  54. data/lib/ubiquitously/services/pixel_groovy.rb +22 -0
  55. data/lib/ubiquitously/services/posterous.rb +24 -0
  56. data/lib/ubiquitously/services/programmers_heaven.rb +21 -0
  57. data/lib/ubiquitously/{propeller.rb → services/propeller.rb} +17 -26
  58. data/lib/ubiquitously/services/queness.rb +38 -0
  59. data/lib/ubiquitously/services/reddit.rb +62 -0
  60. data/lib/ubiquitously/services/scribd.rb +21 -0
  61. data/lib/ubiquitously/services/script_and_style.rb +23 -0
  62. data/lib/ubiquitously/services/sharebrain.rb +19 -0
  63. data/lib/ubiquitously/services/shoutwire.rb +34 -0
  64. data/lib/ubiquitously/services/slideshare.rb +70 -0
  65. data/lib/ubiquitously/services/smipple.rb +21 -0
  66. data/lib/ubiquitously/services/snipplr.rb +67 -0
  67. data/lib/ubiquitously/services/snipt.rb +49 -0
  68. data/lib/ubiquitously/services/sphinn.rb +24 -0
  69. data/lib/ubiquitously/services/stumble_upon.rb +67 -0
  70. data/lib/ubiquitously/services/stumpedia.rb +13 -0
  71. data/lib/ubiquitously/services/tumblr.rb +28 -0
  72. data/lib/ubiquitously/services/tweako.rb +53 -0
  73. data/lib/ubiquitously/services/twitter.rb +60 -0
  74. data/lib/ubiquitously/services/web_blend.rb +25 -0
  75. data/lib/ubiquitously/services/webdev5.rb +32 -0
  76. data/lib/ubiquitously/services/who_freelance.rb +21 -0
  77. data/lib/ubiquitously/services/wordtaps.rb +36 -0
  78. data/lib/ubiquitously/services/yahoo_buzz.rb +64 -0
  79. data/lib/ubiquitously/services/youblr.rb +15 -0
  80. data/lib/ubiquitously/services/zabox.rb +22 -0
  81. data/lib/ubiquitously/support/active_record.rb +25 -0
  82. data/lib/ubiquitously/support/storage.rb +71 -0
  83. data/test/config/cookies.yml +111 -0
  84. data/test/config/credentials.yml +7 -0
  85. data/test/config/secrets.yml +33 -0
  86. data/test/config/tokens.yml +30 -0
  87. data/test/meta.html +19 -0
  88. data/test/test_delicious.rb +37 -0
  89. data/test/test_digg.rb +57 -0
  90. data/test/test_dzone.rb +23 -18
  91. data/test/test_facebook.rb +40 -0
  92. data/test/test_faves.rb +18 -20
  93. data/test/test_helper.rb +8 -1
  94. data/test/test_newsvine.rb +3 -3
  95. data/test/test_page.rb +21 -0
  96. data/test/test_post.rb +55 -0
  97. data/test/test_propeller.rb +2 -2
  98. data/test/test_reddit.rb +26 -4
  99. data/test/test_stumble_upon.rb +23 -3
  100. data/test/test_twitter.rb +33 -0
  101. data/test/test_user.rb +22 -0
  102. metadata +199 -24
  103. data/lib/ext.rb +0 -37
  104. data/lib/ubiquitously/base.rb +0 -56
  105. data/lib/ubiquitously/dzone.rb +0 -111
  106. data/lib/ubiquitously/faves.rb +0 -43
  107. data/lib/ubiquitously/mister_wong.rb +0 -11
  108. data/lib/ubiquitously/mixins/resourceful.rb +0 -50
  109. data/lib/ubiquitously/mixx.rb +0 -66
  110. data/lib/ubiquitously/newsvine.rb +0 -54
  111. data/lib/ubiquitously/reddit.rb +0 -46
  112. data/lib/ubiquitously/sphinn.rb +0 -11
  113. data/lib/ubiquitously/stumble_upon.rb +0 -61
  114. data/test/config.yml +0 -18
@@ -0,0 +1,52 @@
1
+ module Ubiquitously
2
+ module Restful
3
+ module Post
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ base.restful
7
+ base.send :include, InstanceMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ def restful
12
+ subclassable_callbacks :create, :update, :destroy
13
+ end
14
+
15
+ def create(attributes = {})
16
+ record = new(attributes)
17
+ record.save
18
+ record
19
+ end
20
+
21
+ def create!(attributes = {})
22
+ record = new(attributes)
23
+ record.save!
24
+ record
25
+ end
26
+
27
+ def find(options = {})
28
+ nil
29
+ end
30
+ end
31
+
32
+ module InstanceMethods
33
+
34
+ def save
35
+ create_or_update
36
+ end
37
+
38
+ def create_or_update
39
+ new_record? ? create : update
40
+ end
41
+
42
+ def save!
43
+ save || raise(Ubiquitously::RecordInvalid.new("Record is invalid: #{self.errors.full_messages}"))
44
+ end
45
+
46
+ def new_record?
47
+ self.remote.blank?
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,128 @@
1
+ module Ubiquitously
2
+ class User < Base
3
+ attr_accessor :username, :name, :email
4
+ attr_accessor :agent, :cookies, :accounts, :storage
5
+
6
+ def initialize(attributes = {})
7
+ attributes = attributes.symbolize_keys
8
+
9
+ raise "Please define 'storage'" unless attributes[:storage]
10
+
11
+ unless attributes[:agent]
12
+ attributes[:agent] = Mechanize.new
13
+ #attributes[:agent].log = Logger.new(STDOUT)
14
+ attributes[:agent].user_agent = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; ru-ru) AppleWebKit/533.2+ (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10"
15
+ end
16
+
17
+ if attributes[:storage].is_a?(String)
18
+ attributes[:storage] = Ubiquitously::Storage::FileSystem.new(attributes[:storage])
19
+ end
20
+
21
+ apply attributes
22
+ end
23
+
24
+ def accounts
25
+ @accounts ||= []
26
+ end
27
+
28
+ def accountables(*items, &block)
29
+ services = items.flatten.map(&:to_s)
30
+ services.each do |service|
31
+ next if self.accounts.detect { |account| account.service == service }
32
+ clazz = "Ubiquitously::#{service.camelize}::Account".constantize
33
+ if block_given?
34
+ self.accounts << yield(clazz)
35
+ else
36
+ self.accounts << clazz.new(:user => self)
37
+ end
38
+ end
39
+ self.accounts.select { |account| services.include?(account.service) }
40
+ end
41
+
42
+ def account_classes(*items)
43
+ services = items.flatten.map(&:to_s)
44
+ services.map do |service|
45
+ "Ubiquitously::#{service.camelize}::Account".constantize
46
+ end.select { |account| services.include?(account.service) }
47
+ end
48
+
49
+ def login(*services)
50
+ load
51
+ accountables(*services).map(&:login)
52
+ save
53
+ true
54
+ end
55
+
56
+ def load
57
+ apply storage.load
58
+ end
59
+
60
+ def save
61
+ storage.save(cookies, credentials)
62
+ end
63
+
64
+ def cookies
65
+ self.agent.cookie_jar.jar
66
+ end
67
+
68
+ def cookies=(hash)
69
+ agent.cookie_jar.jar = hash
70
+ end
71
+
72
+ def credentials
73
+ self.accounts.inject({}) do |hash, account|
74
+ hash[account.service] = account.credentials.stringify_keys
75
+ hash
76
+ end
77
+ end
78
+
79
+ def credentials=(hash)
80
+ accountables(hash.keys).each do |account|
81
+ account.credentials.merge!(hash[account.service])
82
+ end
83
+ end
84
+
85
+ def cookies_for(service)
86
+ name = service_cookie_name(service.to_s)
87
+ result = cookies.keys.detect { |domain| domain.downcase =~ /#{name}/ }
88
+ return nil if result.blank?
89
+ uri = URI.parse("http://#{result}")
90
+ unless agent.cookie_jar.empty?(uri)
91
+ cookies = agent.cookie_jar.cookies(uri)
92
+ cookie = cookies.length > 0 ? cookies.join("; ") : nil
93
+ else
94
+ cookie = nil
95
+ end
96
+ end
97
+
98
+ def cookies_for?(service)
99
+ !cookies_for(service).blank?
100
+ end
101
+
102
+ def credentials_for(service)
103
+ credentials[service.to_s]
104
+ end
105
+
106
+ def credentials_for?(service)
107
+ !credentials_for(service).blank?
108
+ end
109
+
110
+ def service_cookie_name(service)
111
+ return service.gsub("_", "_?") unless service == "dzone_snippets"
112
+ return "dzone"
113
+ end
114
+
115
+ def username_for(service)
116
+ account_for(service).username
117
+ end
118
+
119
+ def password_for(service)
120
+ account_for(service).password
121
+ end
122
+
123
+ def account_for(service)
124
+ service = service.service unless service.is_a?(String)
125
+ accountables(*service).detect { |account| account.service == service }
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,68 @@
1
+ module Ubiquitously
2
+ module BloggerDen
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://www.bloggerden.com/login")
6
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
7
+ form["username"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorized?(page.title =~ /Like Digg/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ # title max length == 120
17
+ submit_to "http://digg.com/submit?phase=2&url=:url&title=:title&bodytext=:description&topic=26"
18
+
19
+ def tokenize
20
+ super.merge(:title => self.title[0..120])
21
+ end
22
+
23
+ def create
24
+ # url
25
+ page = agent.get("http://www.bloggerden.com/submit/")
26
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
27
+
28
+ form["url"] = url
29
+
30
+ page = form.submit
31
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
32
+
33
+ form["title"] = title
34
+ form["bodytext"] = description # 350 chars max
35
+ form.radiobuttons_with(:name => "category").each do |button|
36
+ button.check if button.value.to_s == "38"
37
+ end
38
+
39
+ iframe_url = page.parser.css("noscript iframe").first["src"]
40
+ params = iframe_url.split("?").last
41
+ captcha_iframe = agent.click(page.iframes.first)
42
+ captcha_form = captcha_iframe.forms.first
43
+ captcha_image = captcha_iframe.parser.css("img").first["src"]
44
+ # open browser with captcha image
45
+ system("open", "http://api.recaptcha.net/#{captcha_image}")
46
+ # enter captcha response in terminal
47
+ captcha_says = ask("Enter Captcha from Browser Image: ") { |q| q.echo = true }
48
+ captcha_form["recaptcha_response_field"] = captcha_says
49
+ # submit captcha
50
+ captcha_form.action = "http://www.google.com/recaptcha/api/noscript?#{params}"
51
+ captcha_response = captcha_form.submit
52
+ # grab secret
53
+ captcha_response = captcha_response.parser.css("textarea").first.text
54
+
55
+ form["recaptcha_challenge_field"] = captcha_response
56
+ form["recaptcha_response_field"] = "manual_challenge"
57
+
58
+ page = form.submit
59
+ unless debug?
60
+ form = page.forms.detect {|form| form.form_node["id"] == "thisform"}
61
+ page = form.submit
62
+ end
63
+ # has captcha, not done with this
64
+ true
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,37 @@
1
+ module Ubiquitously
2
+ module Chetzit
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://chetzit.com/login/")
6
+ form = page.forms.first
7
+ form["login"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorized?(page.title !~ /^Login/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("http://chetzit.com/link/add/")
18
+ form = page.forms.detect do |form|
19
+ !form.form_node.css("input[name=security_ls_key]").first.blank?
20
+ end
21
+
22
+ form.field_with(:name => "blog_id").options.first.select
23
+
24
+ form["topic_title"] = token[:title]
25
+ form["topic_link_url"] = token[:url]
26
+ # max 500 chars
27
+ form["topic_text"] = token[:description]
28
+ form["topic_tags"] = token[:tags]
29
+ form["submit_topic_publish"] = "Submit New"
30
+
31
+ page = form.submit(form.buttons.first)
32
+
33
+ true
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ module Ubiquitously
2
+ module CodeProject
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://www.codeproject.com/script/Articles/Submit.aspx")
6
+ form = page.form_with(:name => "subForm")
7
+ form["Email"] = email
8
+ form["Password"] = password
9
+ page = form.submit
10
+
11
+ authorized?(page.title =~ /Article Submission/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("http://www.codeproject.com/script/Articles/SubmitStep1.aspx")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,54 @@
1
+ module Ubiquitously
2
+ module Delicious
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ true
6
+ end
7
+ end
8
+
9
+ class Post < Ubiquitously::Service::Post
10
+ include HTTParty
11
+ base_uri 'https://api.del.icio.us/v1'
12
+ submit_to "http://del.icio.us/post/?url=:url&title=:title&notes=:description&tags=:tags"
13
+
14
+ def tokenize
15
+ super.merge(:tags => tags.taggify("-", " "))
16
+ end
17
+
18
+ def create
19
+ puts "CREATE #{@auth.inspect}"
20
+ res = self.class.get(
21
+ "/posts/add",
22
+ :query => {
23
+ :url => url,
24
+ :description => title,
25
+ :extended => description,
26
+ :tags => tags.map { |tag| tag.downcase.gsub(/[^a-z0-9]/, "-").squeeze("-") }.join(" ")
27
+ },
28
+ :basic_auth => @auth
29
+ )
30
+ puts "RESPONSE: #{res.inspect}"
31
+ true
32
+ end
33
+
34
+ def remote(options = {})
35
+ return nil
36
+ raise "what url to do want" if self.url.nil?
37
+ @remote ||= self.class.find(options.merge(
38
+ :query => {
39
+ :url => CGI.escape(self.url)
40
+ },
41
+ :basic_auth => @auth
42
+ ))
43
+ end
44
+
45
+ class << self
46
+ def find(options = {})
47
+ options[:result] = options.delete(:count) unless options[:count].nil?
48
+ raise "enter ':basic_auth => {:username => x, :password => y}'" unless options[:basic_auth]
49
+ self.get('/posts/get', options)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,41 @@
1
+ module Ubiquitously
2
+ module DesignBump
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://designbump.com/login")
6
+ form = page.forms.detect { |form| form.form_node["id"] == "user-login-form" }
7
+ form["name"] = username
8
+ form["pass"] = password
9
+ page = form.submit
10
+
11
+ authorize!(page.uri != "http://designbump.com/user?destination=login")
12
+ end
13
+ end
14
+
15
+ # drupal
16
+ class Post < Ubiquitously::Service::Post
17
+
18
+ def tokenize
19
+ super.merge(:tags => tags.taggify(" ", :quote => true))
20
+ end
21
+
22
+ def create
23
+ page = agent.get("http://designbump.com/submit")
24
+ form = page.form_with(:action => "/submit")
25
+
26
+ form["url"] = token[:url]
27
+ form["title"] = token[:title]
28
+ form["body"] = token[:description]
29
+ form.field_with(:name => "taxonomy[1]").options.each do |option|
30
+ option.select if option.value.to_s == "21"
31
+ end
32
+ form["taxonomy[tags][2]"] = token[:tags]
33
+ form["op"] = "Save"
34
+
35
+ page = form.submit
36
+
37
+ true
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ module Ubiquitously
2
+ module Designgizer
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://service.com/login")
6
+ form = page.form_with(:name => "loginform")
7
+ form["username"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorized?(page.title =~ /Some title/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module Ubiquitously
2
+ module DesignrFix
3
+ class Account < Ubiquitously::Service::Account
4
+ def login
5
+ page = agent.get("http://service.com/login")
6
+ form = page.form_with(:name => "loginform")
7
+ form["username"] = username
8
+ form["password"] = password
9
+ page = form.submit
10
+
11
+ authorized?(page.title =~ /Some title/i)
12
+ end
13
+ end
14
+
15
+ class Post < Ubiquitously::Service::Post
16
+ def create
17
+ page = agent.get("")
18
+ end
19
+ end
20
+ end
21
+ end