aproxacs-storyq_client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2008-07-09
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,10 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ lib/storyq_client.rb
5
+ lib/storyq_client/base.rb
6
+ lib/storyq_client/box.rb
7
+ lib/storyq_client/photo.rb
8
+ lib/storyq_client/resource.rb
9
+ lib/storyq_client/token.rb
10
+ lib/storyq_client/upload.rb
data/README.txt ADDED
@@ -0,0 +1,115 @@
1
+ = storyq_client
2
+
3
+ * Homepage: http://www.aproxacs.com/166
4
+ * Author: aproxacs
5
+
6
+ == DESCRIPTION:
7
+ StoryQ client Library
8
+ This library makes it easy to use storyq's Open API.
9
+ You can easily upload documents and photos to the storyq and convert them to the flash slide with this library.
10
+ This follows the restful style but not uses active_resource.
11
+
12
+ This is mainly refered to the active_resource and springnote_client gem.
13
+ Specially thanks to the springnote_client.
14
+
15
+ == FEATURES/PROBLEMS:
16
+
17
+
18
+ == SYNOPSIS:
19
+
20
+ # create a storyq instance
21
+ storyq = Storyq(
22
+ :consumer_token => "CONSUMER_TOKEN",
23
+ :consumer_secret => "CONSUMER_SECRET",
24
+ :access_key => "ACCESS_TOKEN",
25
+ :access_secret => "ACCESS_SECRET")
26
+
27
+ # Get all boxes
28
+ boxes = storyq.boxes.find :all # returns 20 recent boxes
29
+ boxes = storyq.boxes.find :all :page => 2 # returns 21-40 boxes
30
+ boxes = storyq.boxes.find :all :page => 2, :per_page=>3 # returns 21-23 boxes
31
+ boxes = storyq.slide_boxes.find :all # returns 20 recent slide boxes
32
+ boxes = storyq.photo_boxes.find :all # returns 20 recent photo boxes
33
+
34
+ # Get my boxes
35
+ boxes = storyq.boxes.find :mine # returns 5 boxes belongs to the current authenticated user.
36
+ boxes = storyq.slide_boxes.find :mine
37
+
38
+ # Get a box
39
+ box = storyq.boxes.find 1234 # returns a box whose id is 1234
40
+ puts box.title
41
+
42
+ # Update a box
43
+ box.title = "my world"
44
+ box.tags = "some, tags"
45
+ box.save
46
+
47
+ # Destory a box
48
+ box.destory
49
+
50
+ # Create a slide box
51
+ storyq.slide_boxes.create(
52
+ "filename" => "A_FILE.ppt",
53
+ "title" => "TITLE",
54
+ "description" => "DESCRIPTION",
55
+ "tags" => "SOME, TAGS",
56
+ "category" => "����",
57
+ "permission" => "public")
58
+
59
+ # Create a photo box
60
+ pbox = storyq.photo_boxes.create(
61
+ "title" => "TITLE",
62
+ "description" => "DESCRIPTION",
63
+ "tags" => "SOME, TAGS",
64
+ "category" => "����",
65
+ "permission" => "public")
66
+
67
+ # Add a photo to photo box
68
+ photo = pbox.add_photo(
69
+ "filename" => "A_IMAGE.jpg",
70
+ "title" => "TITLE",
71
+ "note" => "SOME NOTES FOR THE PICTURE")
72
+
73
+ # get photo box's photos
74
+ photos = pbox.photos
75
+
76
+ # update a photo
77
+ photo.title = "NEW TITLE"
78
+ photo.note = "NEW NOTE"
79
+ photo.save
80
+
81
+ # delete a photo
82
+ photo.destory
83
+
84
+ == REQUIREMENTS:
85
+ * active_support
86
+ * oauth
87
+
88
+ == INSTALL:
89
+
90
+ * sudo gem install storyq_client
91
+
92
+ == LICENSE:
93
+
94
+ (The MIT License)
95
+
96
+ Copyright (c) 2008 Bryan Kang
97
+
98
+ Permission is hereby granted, free of charge, to any person obtaining
99
+ a copy of this software and associated documentation files (the
100
+ 'Software'), to deal in the Software without restriction, including
101
+ without limitation the rights to use, copy, modify, merge, publish,
102
+ distribute, sublicense, and/or sell copies of the Software, and to
103
+ permit persons to whom the Software is furnished to do so, subject to
104
+ the following conditions:
105
+
106
+ The above copyright notice and this permission notice shall be
107
+ included in all copies or substantial portions of the Software.
108
+
109
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
110
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
111
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
112
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
113
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
114
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
115
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,63 @@
1
+ require 'storyq_client/upload'
2
+ require 'storyq_client/token'
3
+ require 'storyq_client/resource'
4
+ require 'storyq_client/box'
5
+ require 'storyq_client/photo'
6
+
7
+ def StoryQ(*params)
8
+ Storyq::Base.new(*params)
9
+ end
10
+
11
+ module Storyq
12
+ class Base
13
+ include Token
14
+
15
+ def initialize(config)
16
+ config[:site] ||= "http://www.storyq.net"
17
+ self.config = config
18
+ end
19
+
20
+ def slide_boxes
21
+ CallProxy.new(SlideBox, self)
22
+ end
23
+ def photo_boxes
24
+ CallProxy.new(PhotoBox, self)
25
+ end
26
+ def boxes
27
+ CallProxy.new(Box, self)
28
+ end
29
+
30
+ def post url, body, headers={}
31
+ headers["content-type"] ||= 'application/x-www-form-urlencoded' unless body.blank?
32
+ access_token.request(:post, url, body, header(headers)).body
33
+ end
34
+ def put url, body, headers={}
35
+ headers["content-type"] ||= 'application/x-www-form-urlencoded' unless body.blank?
36
+ access_token.request(:put, url, body, header(headers)).body
37
+ end
38
+ def delete url, headers={}
39
+ access_token.request(:delete, url, header(headers)).body
40
+ end
41
+ def get url, headers={}
42
+ access_token.request(:get, url, header(headers)).body
43
+ end
44
+
45
+ def header headers
46
+ default_header.merge(headers)
47
+ end
48
+
49
+ def default_header
50
+ { "accept" => 'application/xml' }
51
+ end
52
+
53
+ end
54
+
55
+ class CallProxy
56
+ def initialize(callee, *params)
57
+ @callee, @params = callee, params
58
+ end
59
+ def method_missing(method, *params, &block)
60
+ @callee.send(method, *(params+@params), &block)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,71 @@
1
+ module Storyq
2
+ class Box < Storyq::Resource
3
+ class << self
4
+ def save_params
5
+ %w(title category description tags permission)
6
+ end
7
+ def prefix(type = :url)
8
+ ""
9
+ end
10
+ def collection_name(type = :url)
11
+ prefix(type) + "boxes"
12
+ end
13
+ def singular_name(type = :url)
14
+ prefix(type) + "box"
15
+ end
16
+ end
17
+ end
18
+
19
+ class PhotoBox < Storyq::Box
20
+ class << self
21
+ def save_params
22
+ %w(title category description tags permission bgm_url play_interval play_effect, photo_array)
23
+ end
24
+ def prefix(type = :url)
25
+ type == :url ? "photo_" : ""
26
+ end
27
+ end
28
+
29
+ attr_reader :holder
30
+ def photos
31
+ Storyq::Photo.instantiate_resources(Hash.from_xml(@holder.get("/photo_boxes/#{id}/photos?")), self)
32
+ end
33
+
34
+ def add_photo attributes
35
+ Storyq::Photo.create attributes, self
36
+ end
37
+ end
38
+
39
+ class SlideBox < Storyq::Box
40
+ include Storyq::Upload
41
+
42
+ class << self
43
+ def save_params
44
+ %w(title category description tags permission)
45
+ end
46
+ def prefix(type = :url)
47
+ type == :url ? "slide_" : ""
48
+ end
49
+ end
50
+
51
+ def parameters
52
+ parameters = super
53
+ if @hash["filename"]
54
+ parameters["slide_box[uploaded_data]"] = uploaded_file(@hash["filename"])
55
+ end
56
+ parameters
57
+ end
58
+
59
+ def save
60
+ if new?
61
+ xml = @holder.post("/slide_boxes", multipart_body(parameters, boundary),
62
+ "content-type" => "multipart/form-data; boundary=#{boundary}")
63
+ @hash["filename"] = nil
64
+ else
65
+ xml = @holder.put("/slide_boxes/#{id}", parameters.to_query)
66
+ end
67
+ @hash = Hash.from_xml(xml)["box"]
68
+ self
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,51 @@
1
+ module Storyq
2
+ class Photo < Storyq::Resource
3
+ include Storyq::Upload
4
+
5
+ class << self
6
+ def save_params
7
+ %w(title note)
8
+ end
9
+
10
+ def collection_name(type = :url)
11
+ "photos"
12
+ end
13
+ def singular_name(type = :url)
14
+ "photo"
15
+ end
16
+ end
17
+
18
+ def initialize(*args)
19
+ @photo_box = args.pop
20
+ @holder = @photo_box.holder
21
+ @hash = args.shift
22
+ end
23
+
24
+ def parameters
25
+ parameters = super
26
+ if @hash["filename"]
27
+ parameters["photo[uploaded_data]"] = uploaded_file(@hash["filename"])
28
+ end
29
+ parameters
30
+ end
31
+
32
+ def save
33
+ if new?
34
+ p parameters
35
+ xml = @holder.post("/photo_boxes/#{@photo_box.id}/photos", multipart_body(parameters, boundary),
36
+ "content-type" => "multipart/form-data; boundary=#{boundary}")
37
+ @hash["filename"] = nil
38
+ else
39
+ xml = @holder.put("/photo_boxes/#{@photo_box.id}/photos/#{id}", parameters.to_query)
40
+ end
41
+ @hash = Hash.from_xml(xml)["photo"]
42
+ self
43
+ end
44
+
45
+ def destroy
46
+ puts "hey"
47
+ xml = @holder.delete("/photo_boxes/#{@photo_box.id}/photos/#{id}")
48
+ @hash = Hash.from_xml(xml)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,89 @@
1
+ module Storyq
2
+ class Resource
3
+ class << self
4
+ def instantiate_resource hash, holder
5
+ new(hash, holder)
6
+ end
7
+
8
+ def instantiate_resources hash, holder
9
+ hash[collection_name(:xml)].collect {|res| instantiate_resource(res, holder)}
10
+ end
11
+
12
+ def create *args
13
+ returning(self.new(*args)) { |res| res.save }
14
+ end
15
+
16
+ def find(*args)
17
+ holder = args.pop
18
+ scope = args.shift
19
+ options = args.shift || {}
20
+
21
+ case scope
22
+ when :all then find_every(options, holder)
23
+ when :mine then find_mine(options, holder)
24
+ when :first then find_every(options, holder).first
25
+ else find_single(scope, options, holder)
26
+ end
27
+ end
28
+
29
+ def find_every(options, holder)
30
+ instantiate_resources(Hash.from_xml(holder.get("/#{collection_name}?" + options.to_query)), holder)
31
+ end
32
+
33
+ def find_mine(options, holder)
34
+ instantiate_resources(Hash.from_xml(holder.get("/#{collection_name}/mine?" + options.to_query)), holder)
35
+ end
36
+
37
+ def find_single(scope, options, holder)
38
+ instantiate_resource(Hash.from_xml(holder.get("/#{collection_name}/#{scope}?" + options.to_query))[singular_name(:xml)], holder)
39
+ end
40
+ end # end of class methods of Resource
41
+
42
+ def initialize(*args)
43
+ @holder = args.pop
44
+ @hash = args.shift
45
+ end
46
+
47
+ def update(attributes)
48
+ @hash.update(attributes)
49
+ save
50
+ end
51
+
52
+ def id
53
+ @hash["identifier"]
54
+ end
55
+
56
+ def new?
57
+ @hash["identifier"].blank?
58
+ end
59
+
60
+ def parameters
61
+ returning({}) do |params|
62
+ self.class.save_params.each do |key|
63
+ params["#{self.class.singular_name}[#{key}]"] = @hash[key].to_s unless @hash[key].blank?
64
+ end
65
+ end
66
+ end
67
+
68
+ def save
69
+ if new?
70
+ xml = @holder.post("/#{self.class.collection_name}/#{id}", parameters)
71
+ else
72
+ xml = @holder.put("/#{self.class.collection_name}/#{id}", parameters)
73
+ end
74
+
75
+ @hash = Hash.from_xml(xml)[self.class.singular_name(:xml)]
76
+ self
77
+ end
78
+
79
+ def destroy
80
+ xml = @holder.delete("/#{self.class.collection_name}/#{id}")
81
+ @hash = Hash.from_xml(xml)
82
+ end
83
+
84
+ def method_missing(method, *args)
85
+ str = method.to_s
86
+ (str[-1] == ?=)? @hash[str[0..-2]] = args[0] : @hash[str]
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,60 @@
1
+ module Storyq
2
+ module Token
3
+ def access_token
4
+ @access_token ||= create_access_token
5
+ end
6
+
7
+ def access_token=(token)
8
+ @access_toke = token
9
+ end
10
+
11
+ def config=(config)
12
+ @config = config
13
+ end
14
+
15
+ def create_access_token
16
+ if access_key and access_secret
17
+ OAuth::AccessToken.new consumer, access_key, access_secret
18
+ else
19
+ authorize
20
+ end
21
+ end
22
+
23
+ def access
24
+ {"key" => access_key, "secret" => access_secret}
25
+ end
26
+
27
+ def access=(access)
28
+ @config[:access_key] = access["key"]
29
+ @config[:access_secret] = access["secret"]
30
+ end
31
+
32
+ def access_key
33
+ @config[:access_key]
34
+ end
35
+
36
+ def access_secret
37
+ @config[:access_secret]
38
+ end
39
+
40
+ def consumer
41
+ @consumer ||= OAuth::Consumer.new(
42
+ @config[:consumer_token], @config[:consumer_secret],
43
+ :site=>@config[:site])
44
+ end
45
+
46
+ def authenticate
47
+ req_token = consumer.get_request_token
48
+ puts "Authorize yourself using the following URL and press any key"
49
+ puts req_token.authorize_url
50
+ gets
51
+ acc_token = req_token.get_access_token
52
+ @config[:access_key] = acc_token.token
53
+ @config[:access_secret] = acc_token.secret
54
+ acc_token
55
+ rescue Exception => e
56
+ puts e
57
+ return nil
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,46 @@
1
+ require "tempfile"
2
+ require "fileutils"
3
+
4
+ module Storyq
5
+ module Upload
6
+ def boundary
7
+ @boundary ||= "----------STORYQ#{rand(1000000000000)}"
8
+ end
9
+
10
+ def multipart_body(params, boundary)
11
+ params.map do |key, value|
12
+ if value.respond_to?(:original_filename)
13
+ File.open(value.path) do |f|
14
+ f.binmode
15
+ <<-EOF
16
+ --#{boundary}\r
17
+ Content-Disposition: form-data; name="#{key}"; filename="#{CGI.escape(value.original_filename)}"\r
18
+ Content-Type: #{value.content_type}\r
19
+ \r
20
+ #{f.read}\r
21
+ EOF
22
+ end
23
+ else
24
+ <<-EOF
25
+ --#{boundary}\r
26
+ Content-Disposition: form-data; name="#{key}"\r
27
+ \r
28
+ #{value}\r
29
+ EOF
30
+ end
31
+ end.join("")+"--#{boundary}--\r"
32
+ end
33
+
34
+ def uploaded_file(path, content_type="application/octet-stream", filename=nil)
35
+ filename ||= File.basename(path)
36
+ t = Tempfile.new(filename)
37
+ FileUtils.copy_file(path, t.path)
38
+ (class << t; self; end;).class_eval do
39
+ alias local_path path
40
+ define_method(:original_filename) { filename }
41
+ define_method(:content_type) { content_type }
42
+ end
43
+ return t
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,16 @@
1
+ %w(rubygems oauth oauth/consumer activesupport yaml).each {|l| require l}
2
+
3
+ $:.unshift(File.dirname(__FILE__)) unless
4
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
5
+
6
+ require "storyq_client/base"
7
+
8
+ module OAuth::RequestProxy::Net
9
+ module HTTP
10
+ class HTTPRequest < OAuth::RequestProxy::Base
11
+ def post_params
12
+ request.body if request.content_type == "application/x-www-form-urlencoded"
13
+ end
14
+ end
15
+ end
16
+ end
data/test/base_spec.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'storyq/base'
2
+
3
+ describe StoryQ::Base, "" do
4
+ before(:each) do
5
+ end
6
+ end
7
+
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aproxacs-storyq_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - aproxacs
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-07-06 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">"
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.2
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: oauth
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">"
30
+ - !ruby/object:Gem::Version
31
+ version: 0.2.4
32
+ version:
33
+ description: StoryQ client Library. This library makes it easy to use storyq's Open API. You can easily upload documents and photos to the storyq and convert them to the flash slide with this library. This follows the restful style but not use active_resource.
34
+ email: aproxacs@gmail.com
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files:
40
+ - History.txt
41
+ - Manifest.txt
42
+ - README.txt
43
+ files:
44
+ - History.txt
45
+ - Manifest.txt
46
+ - README.txt
47
+ - lib/storyq_client.rb
48
+ - lib/storyq_client/base.rb
49
+ - lib/storyq_client/box.rb
50
+ - lib/storyq_client/photo.rb
51
+ - lib/storyq_client/resource.rb
52
+ - lib/storyq_client/token.rb
53
+ - lib/storyq_client/upload.rb
54
+ has_rdoc: true
55
+ homepage: http://www.aproxacs.com/166
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --main
59
+ - README.txt
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ requirements: []
75
+
76
+ rubyforge_project:
77
+ rubygems_version: 1.2.0
78
+ signing_key:
79
+ specification_version: 2
80
+ summary: StoryQ client
81
+ test_files:
82
+ - test/base_spec.rb