googletastic 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -38,6 +38,8 @@ If this is for Google Apps, you must go to Google Docs Settings in the Admin Pan
38
38
  h2. Top 10 Things I Need the Google Data API to Have
39
39
 
40
40
  "Submit Your Ideas to Google!!!":http://productideas.appspot.com/#15/e=220cb&t=2192a&f=22150
41
+ http://productideas.appspot.com/#15/e=220cb&t=cabc1
42
+
41
43
 
42
44
  # Partial Responses for everything.
43
45
  So we can get only the data we need. This way we can poll our google docs for any changes and run processes on them.
data/Rakefile CHANGED
@@ -17,9 +17,6 @@ def files(path, from = __FILE__, &block)
17
17
  Dir.glob(File.join(File.dirname(from), path)) {|file| yield file}
18
18
  end
19
19
 
20
- APP_ROOT = defined?(RAILS_ROOT) ? RAILS_ROOT : File.dirname(__FILE__)
21
- RAILS_ROOT = File.dirname(__FILE__)
22
-
23
20
  # http://docs.rubygems.org/read/chapter/20
24
21
  spec = Gem::Specification.new do |s|
25
22
  s.name = "googletastic"
@@ -9,6 +9,7 @@ require 'active_support'
9
9
  require 'active_record'
10
10
  require 'gdata'
11
11
  require 'liquid'
12
+ require 'mechanize'
12
13
 
13
14
  GOOGLETASTIC_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(GOOGLETASTIC_ROOT)
14
15
 
@@ -58,7 +59,7 @@ end
58
59
 
59
60
  module Googletastic
60
61
  # :stopdoc:
61
- VERSION = '0.0.1'
62
+ VERSION = '0.0.3'
62
63
  # :startdoc
63
64
  class << self; attr_accessor :keys, :clients, :options; end
64
65
 
@@ -69,7 +70,7 @@ module Googletastic
69
70
  raise "Sorry, you must have #{config_file}" unless File.exists?(config_file)
70
71
  self.keys = YAML.load_file(config_file).symbolize_keys
71
72
  end
72
-
73
+
73
74
  def self.client_for(model)
74
75
  self.clients ||= {}
75
76
  model = model.to_sym
@@ -0,0 +1,34 @@
1
+ module Googletastic::Analytics
2
+ # https://www.google.com/accounts/ServiceLoginBox?service=analytics&nui=1&hl=en-US&continue=https://www.google.com/analytics/settings/?et=reset&hl=en&et=reset&hl=en-US
3
+
4
+ def create(options = {})
5
+ agent = WWW::Mechanize.new
6
+ agent.cookie_jar.load(options[:cookies])
7
+ scid = "15601175" # one of the options options[:profile]
8
+ form.fields_with("scid").first.value = scid
9
+ next_page = agent.submit(form)
10
+ new_analytics = "https://www.google.com/analytics/settings/add_profile?scid=#{scid}"
11
+ # ucpr_protocol
12
+ form = next_page.forms_with(:name => "mform").first
13
+ form.ucpr_url = options[:domain]
14
+ tracking = agent.submit(form)
15
+ tracking_code = tracking.parser.xpath("//script").to_s.match(/getTracker\(["|']([^"|']+)["|']\)/).captures.first
16
+ end
17
+
18
+ # returns an array of account names you can use
19
+ def login(options = {})
20
+ agent = WWW::Mechanize.new
21
+ url = "https://www.google.com/accounts/ServiceLoginBox?service=analytics&nui=1&hl=en-US&continue=https://www.google.com/analytics/settings/?et=reset&hl=en&et=reset&hl=en-US"
22
+ page = agent.get(url)
23
+ login_form = page.forms.first
24
+ login_form.Email = options[:email]
25
+ login_form.Passwd = options[:password]
26
+
27
+ # agent.cookie_jar.save_as("something.yml")
28
+
29
+ next_page = agent.submit(login_form)
30
+ home = next_page.links.first.click
31
+
32
+ form = home.forms_with("account_selector").first
33
+ end
34
+ end
@@ -83,6 +83,9 @@ module GData
83
83
  output.write("#{password}\n")
84
84
  end
85
85
  while ((str = input.gets) != nil)
86
+ if str =~ /Checking if new version is ready to serve/
87
+
88
+ end
86
89
  puts str
87
90
  end
88
91
  rescue Exception => e
@@ -98,6 +101,6 @@ module GData
98
101
  end
99
102
  end
100
103
 
101
- module Googletastic::AppEngine
104
+ class Googletastic::AppEngine < Googletastic::Base
102
105
 
103
106
  end
@@ -0,0 +1,62 @@
1
+ class Googletastic::Apps < Googletastic::Base
2
+
3
+ class << self
4
+
5
+ def new_url
6
+ "http://www.google.com/a/cpanel/domain/new"
7
+ end
8
+
9
+ # follow_meta_refresh for FORMS!!!
10
+ # might have to save cookiejar between requests as captcha is presented
11
+ # domain, first_name, last_name, email, phone, country, username, password, password_confirmation
12
+ def create(options = {})
13
+ # precaptcha and postcaptcha
14
+ agent = WWW::Mechanize.new
15
+ page = agent.get(new_url)
16
+ # fill out domain name (must already have)
17
+ form = page.forms_with("domainEntry").first
18
+ form.radiobuttons.first.check
19
+ form.fields_with("existingDomain").first.value = options[:domain]
20
+ second_page = agent.submit(form)
21
+ # fill out profile
22
+ form = second_page.forms.first
23
+ form.firstName = options[:first_name]
24
+ form.lastName = options[:last_name]
25
+ form.email = options[:email]
26
+ form.phone = options[:phone]
27
+ #form.jobTitle = ""
28
+ #form.orgName = ""
29
+ # default value is "US"
30
+ form.country = options[:country] || "US"
31
+ # form.orgType = ""
32
+ # form.orgSize
33
+ # DO YOU AGREE???
34
+ form.checkboxes_with("domainAdminCheck").first.check
35
+ # third page must be filled out within about a minute it seems
36
+ third_page = agent.submit(form)
37
+ form = last_page.forms.first
38
+ # sample CAPTCHA URL (or "format=audio")
39
+ # form.captchaToken
40
+ # https://www.google.com/a/cpanel/captcha?format=image&captchaToken=crazy-token
41
+ form.captchaAnswer = "progshi"
42
+ form.newUserName = options[:username]
43
+ # minimum 6 chars
44
+ form.fields_with("newPassword.alpha").first.value = options[:password]
45
+ form.fields_with("newPassword.beta").first.value = options[:password_confirmation]
46
+ last_page = agent.submit(form)
47
+
48
+ # now you have your account
49
+ form = last_page.forms_with(:action => "VerifyDomainOwnership").first
50
+ form.radiobuttons_with(:value => "htmlVer").first.check
51
+
52
+ verify_page = agent.submit(form)
53
+ form = verify_page.forms_with(:action => "VerifyDomainOwnership") # or "id => 'verificationPages'"
54
+ # upload file "googlehostedservice.html" with special text, and let google know it's okay
55
+ special_text = verify_page.parser.xpath("//span[@class='callout']").first.text
56
+ # upload to http://tinker.heroku.com/googlehostedservice.html
57
+ apps_home = agent.submit(form)
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -1,6 +1,6 @@
1
1
  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
2
2
  <xsl:output method="html" indent="yes" encoding="ISO-8859-1"/>
3
-
3
+
4
4
  <xsl:param name="indent-increment" select="' '"/>
5
5
 
6
6
  <xsl:template name="newline">
@@ -2,9 +2,38 @@
2
2
  module Googletastic::PrettyPrint
3
3
  class << self
4
4
  def xml(xml)
5
+ return "" if xml.nil?
6
+ raise "will throw segmentation error if not an Nokogiri::XML::Document" unless xml.is_a?(Nokogiri::XML::Document)
5
7
  pretty_printer = File.join(File.dirname(__FILE__), "pretty_print.xsl")
6
8
  xsl = Nokogiri::XSLT(IO.read(pretty_printer))
7
9
  xsl.transform(xml).children.to_xml.gsub(/\t/, "")
8
10
  end
11
+
12
+ def pretty_html(html)
13
+ return "" if html.nil?
14
+ raise "will throw segmentation error if not an Nokogiri::HTML::Document" unless xml.is_a?(Nokogiri::HTML::Document)
15
+ pretty_printer = File.join(File.dirname(__FILE__), "pretty_print.xsl")
16
+ xsl = Nokogiri::XSLT(IO.read(pretty_printer))
17
+ # they get erased
18
+ top_level_attributes = []
19
+ elements = html.is_a?(Nokogiri::XML::NodeSet) ? html : [html]
20
+ puts "ELEMENTS: #{elements[0].class}"
21
+ elements.each do |element|
22
+ top_level_attributes.push(element.attributes)
23
+ end
24
+ top_level_attributes.reverse!
25
+ puts "??"
26
+ children = xsl.transform(html)
27
+ #.children
28
+ # reapply top-level attributes
29
+ puts "TOP ATTRIBUTES: #{top_level_attributes.inspect}"
30
+ children.each do |child|
31
+ attributes = top_level_attributes.pop
32
+ attributes.each do |k,v|
33
+ child[k] = v
34
+ end unless attributes.nil?
35
+ end
36
+ children.to_html.gsub(/\t/, "")
37
+ end
9
38
  end
10
39
  end
@@ -1,7 +1,9 @@
1
1
  # from http://github.com/mocra/custom_google_forms
2
2
  class Googletastic::Form < Googletastic::Base
3
3
 
4
- attr_accessor :title, :body, :redirect_to, :form_key, :form_only
4
+ FORM_KEY_EXPRESSION = /formkey["|']\s*:["|']\s*([^"|']+)"/ unless defined?(FORM_KEY_EXPRESSION)
5
+
6
+ attr_accessor :title, :body, :redirect_to, :form_key, :form_only, :authenticity_token
5
7
 
6
8
  def body(options = {}, &block)
7
9
  @body ||= get(options, &block)
@@ -36,7 +38,11 @@ class Googletastic::Form < Googletastic::Base
36
38
 
37
39
  def unmarshall(xml)
38
40
  records = xml.xpath("//atom:entry", ns_tag("atom")).collect do |record|
39
- id = record.xpath("atom:id", ns_tag("atom")).first.text.gsub("http://spreadsheets.google.com/feeds/spreadsheets/", "")
41
+ #id = record.xpath("atom:id", ns_tag("atom")).first.text.gsub("http://spreadsheets.google.com/feeds/spreadsheets/", "")
42
+ id = record.xpath("atom:link[@rel='alternate']", ns_tag("atom")).first
43
+ if id
44
+ id = id["href"].gsub("http://spreadsheets.google.com/ccc?key=", "")
45
+ end
40
46
  title = record.xpath("atom:title", ns_tag("atom")).first.text
41
47
  created_at = record.xpath("atom:published", ns_tag("atom")).text
42
48
  updated_at = record.xpath("atom:updated", ns_tag("atom")).text
@@ -53,13 +59,44 @@ class Googletastic::Form < Googletastic::Base
53
59
 
54
60
  end
55
61
 
56
- def submit(form_key, params)
57
- action = submit_url(form_key)
58
- uri = URI.parse(action)
62
+ def get_form_key
63
+ begin
64
+ agent = WWW::Mechanize.new
65
+ # google wants recent browsers!
66
+ # http://docs.google.com/support/bin/answer.py?answer=37560&hl=en
67
+ 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"
68
+ url = "http://spreadsheets.google.com/"
69
+ # for spreadsheet, we need the domain!
70
+ if Googletastic.credentials[:domain]
71
+ url << "a/#{Googletastic.credentials[:domain]}/"
72
+ end
73
+ url << "ccc?key=#{self.id}&hl=en&pli=1"
74
+ login_form = agent.get(url).forms.first
75
+ login_form.Email = Googletastic.credentials[:username].split("@").first # don't want emails
76
+ login_form.Passwd = Googletastic.credentials[:password]
77
+ page = agent.submit(login_form)
78
+ match = page.body.match(FORM_KEY_EXPRESSION)
79
+ if page.meta.first and (page.title == "Redirecting" || match.nil?)
80
+ page = page.meta.first.click
81
+ match = page.body.match(FORM_KEY_EXPRESSION)
82
+ end
83
+ formkey = match.captures.first if match
84
+ rescue Exception => e
85
+ puts "ERROR: #{e.to_s}"
86
+ nil
87
+ end
88
+ end
89
+
90
+ def submit(form_key, params, options)
91
+ uri = URI.parse(submit_url)
59
92
  req = Net::HTTP::Post.new("#{uri.path}?#{uri.query}")
60
93
  req.form_data = params
61
94
  response = Net::HTTP.new(uri.host).start {|h| h.request(req)}
62
- response
95
+ if response.is_a?(Net::HTTPSuccess) || response.is_a?(GData::HTTP::Response)
96
+ unmarshall(Nokogiri::HTML(response.body), options).to_html
97
+ else
98
+ response.body
99
+ end
63
100
  end
64
101
 
65
102
  # get(:redirect => {:url => "/our-forms", :params => {:one => "hello"}})
@@ -3,7 +3,6 @@ module Googletastic::Helpers
3
3
  base.extend(ClassMethods)
4
4
  end
5
5
 
6
-
7
6
  module ClassMethods
8
7
 
9
8
  def googletastic(model, options = {})
@@ -15,12 +15,16 @@ class Googletastic::Spreadsheet < Googletastic::Base
15
15
 
16
16
  def unmarshall(xml)
17
17
  records = xml.xpath("//atom:entry", ns_tag("atom")).collect do |record|
18
- id = record.xpath("atom:id", ns_tag("atom")).first.text.gsub("http://spreadsheets.google.com/feeds/spreadsheets/", "")
18
+ #id = record.xpath("atom:id", ns_tag("atom")).first.text.gsub("http://spreadsheets.google.com/feeds/spreadsheets/", "")
19
+ id = record.xpath("atom:link[@rel='alternate']", ns_tag("atom")).first
20
+ if id
21
+ id = id["href"].gsub("http://spreadsheets.google.com/ccc?key=", "")
22
+ end
19
23
  title = record.xpath("atom:title", ns_tag("atom")).first.text
20
24
  content = record.xpath("atom:content", ns_tag("atom")).first.text
21
25
  created_at = record.xpath("atom:published", ns_tag("atom")).text
22
26
  updated_at = record.xpath("atom:updated", ns_tag("atom")).text
23
-
27
+
24
28
  Googletastic::Spreadsheet.new(
25
29
  :id => id,
26
30
  :title => title,
@@ -8,7 +8,9 @@ describe Googletastic::Form do
8
8
 
9
9
  describe "find" do
10
10
  it "should list all spreadsheets as forms" do
11
-
11
+ Googletastic::Form.all.each do |form|
12
+ form.should be_an_instance_of(Googletastic::Form)
13
+ end
12
14
  end
13
15
  end
14
16
 
@@ -23,21 +25,22 @@ describe Googletastic::Form do
23
25
  end
24
26
  end
25
27
 
26
- describe "unmarshalling" do
27
- it "should strip the html page down to a form (unmarshall)" do
28
- @html = Nokogiri::HTML(IO.read(File.join(FIXTURES_DIR, "data/form.html")))
29
- form = Googletastic::Form.unmarshall(@html)
30
- form.redirect = "/forms/my-custom-id"
28
+ describe "mechanize" do
29
+ it "it should get the formkey via mechanize" do
30
+ form = Googletastic::Form.first
31
+ formkey = form.get_form_key
32
+ puts "FORMKEY: #{formkey}"
33
+ formkey.should_not be_nil
31
34
  end
32
- end
33
-
34
- describe "redirecting" do
35
- it "should add generic redirect" do
36
- Googletastic::Form.redirect_to = "/my-generic-redirect"
37
- @html = Nokogiri::HTML(IO.read(File.join(FIXTURES_DIR, "data/form.html")))
38
- form = Googletastic::Form.unmarshall(@html)
39
- Nokogiri::HTML(form.body).xpath("//form").first["action"].should == "/my-generic-redirect"
35
+
36
+ it "should remove unnecessary html from form" do
37
+ form = Googletastic::Form.first
38
+ form.form_key = form.get_form_key
39
+ body = form.body
40
+ puts "BODY!: #{body.to_s}"
41
+ body.should_not == nil
40
42
  end
41
43
  end
42
44
 
45
+
43
46
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Lance Pollard
@@ -82,7 +82,9 @@ files:
82
82
  - Rakefile
83
83
  - lib/googletastic/access_rule.rb
84
84
  - lib/googletastic/album.rb
85
+ - lib/googletastic/analytics.rb
85
86
  - lib/googletastic/app_engine.rb
87
+ - lib/googletastic/apps.rb
86
88
  - lib/googletastic/attendee.rb
87
89
  - lib/googletastic/base.rb
88
90
  - lib/googletastic/calendar.rb