wtforum 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .ruby-version
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ spec/support/credentials.rb
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in wtforum.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Micah Geisel
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # WTForum
2
+
3
+ Ruby library that wraps Website Toolbox's Forum API.
4
+
5
+ Useful for folks looking to embed the forum into their site, while maintaining
6
+ a user-facing appearance of a single user account.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'wtforum'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install wtforum
21
+
22
+ ## Features
23
+
24
+ WTForum has the following features:
25
+
26
+ * CRUD (create, read, update, & delete) user accounts
27
+ ```ruby
28
+ # modeled after ActiveRecord API
29
+ user = WTForum::User.create username: "wtforum_test_user", email: "wtforum_test_user@example.com"
30
+ user = WTForum::User.find(user.id)
31
+ user.update_attributes! username: "wtforum_test_user_2", email: "wtforum_test_user_2@example.com"
32
+ user.destroy
33
+ ```
34
+
35
+ * Log in your user via their Single Sign On (SSO) API
36
+ ```ruby
37
+ session = WTForum::Session.create(user.id)
38
+ session.token # => REiB6U5SkxB
39
+ ```
40
+
41
+ ## Configuration
42
+
43
+ Before using WTForum, you need to give it administrator credentials. It
44
+ needs four pieces of information:
45
+ 1) Where the forum is hosted.
46
+ 2) The API key that Website Toolbox provides.
47
+ 3) Username of an admin account.
48
+ 4) Password for said admin account.
49
+
50
+ Example Rails config:
51
+ ```ruby
52
+ # config/initializers/wtforum_credentials.rb
53
+ WTForum.domain = "forum.example.com"
54
+ WTForum.api_key = "TEgPYR4Zapz"
55
+ WTForum.admin_username = "__admin_api_dont_delete__"
56
+ WTForum.admin_password = "s0m3p4ssw0rd"
57
+ ```
58
+
59
+ ## Why do we need to specify an admin user account in the credentials?
60
+
61
+ Unfortunately, Website Toolbox's Forum API is missing some functionality.
62
+ Specifically, you can only create a new forum user account. Need to read,
63
+ update, or delete an existing user via the API? You're out of luck! As a
64
+ workaround, this library uses an admin account and Mechanize to sign into
65
+ the website and manually fill out forms and screenscrape the results. I hope
66
+ that the API's breadth of functionality improves in the future.
67
+
68
+ ## Contributing
69
+
70
+ 1. Fork it
71
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
72
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
73
+ 4. Push to the branch (`git push origin my-new-feature`)
74
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ module WTForum
4
+ class Session
5
+ def self.create user_id
6
+ uri = create_uri(user_id)
7
+ page = Mechanize.new.get(uri)
8
+ auth_token = WTForum.extract_value(:authtoken, :from => page.body)
9
+ new(auth_token)
10
+ end
11
+
12
+ def initialize token
13
+ @token = token
14
+ end
15
+
16
+ attr_reader :token
17
+
18
+ private
19
+
20
+ def self.create_uri user_id
21
+ uri = WTForum.base_api_uri(userid: user_id)
22
+ uri.path = "/register/setauthtoken"
23
+ uri
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,153 @@
1
+ # encoding: utf-8
2
+
3
+ require "securerandom"
4
+
5
+ module WTForum
6
+ class User
7
+ class NotFound < StandardError; end
8
+
9
+ def self.create attributes
10
+ defaults = { pw: SecureRandom.hex(10) }
11
+ attributes[:member] ||= attributes.delete(:username)
12
+ attributes.reverse_merge! defaults
13
+ uri = create_uri attributes
14
+
15
+ page = agent.get(uri)
16
+ user_id = WTForum.extract_value(:userid, :from => page.body)
17
+ attributes[:id] = user_id.to_i
18
+ new(attributes)
19
+ end
20
+
21
+ def self.find user_id
22
+ page = authorized_agent.get(find_uri(user_id))
23
+ raise NotFound if page.body.include?("Error: The specified account was not found")
24
+
25
+ body = Nokogiri::HTML.parse(page.body)
26
+ attributes = {
27
+ id: user_id,
28
+ member: body.css(".tables td:contains('Username:') + td input").first["value"],
29
+ email: body.css(".tables td:contains('Email Address:') + td").first.text.split(" - ").first,
30
+ }
31
+ new(attributes)
32
+ end
33
+
34
+ def self.update user_id, attributes
35
+ find(user_id).update_attributes!(attributes)
36
+ end
37
+
38
+ def self.delete user_id
39
+ authorized_agent.get delete_uri(user_id)
40
+ true
41
+ end
42
+
43
+ def self.count
44
+ page = agent.get(count_uri)
45
+ count = page.body.match(/Members \(([\d,]+)\)/)[1]
46
+ count.gsub(",", "").to_i
47
+ end
48
+
49
+ def initialize attributes
50
+ self.attributes = attributes
51
+ end
52
+
53
+ def update_attributes! attributes
54
+ self.attributes = attributes
55
+ save!
56
+ end
57
+
58
+ def save!
59
+ self.class.authorized_agent.get(self.class.edit_username_uri(id)) do |page|
60
+ form = page.forms.first
61
+ form["new_username"] = username
62
+ form.submit
63
+ end
64
+ self.class.authorized_agent.get(self.class.edit_email_uri(id)) do |page|
65
+ form = page.forms.first
66
+ form["email"] = email
67
+ form.submit
68
+ end
69
+ end
70
+
71
+ def destroy
72
+ self.class.delete id
73
+ end
74
+
75
+ attr_accessor :id, :member, :email
76
+ attr_writer :pw, :apikey
77
+
78
+ def username
79
+ member
80
+ end
81
+
82
+ def username= value
83
+ self.member = value
84
+ end
85
+
86
+ private
87
+
88
+ def attributes=(attributes={})
89
+ attributes.each do |key, value|
90
+ send :"#{key}=", value
91
+ end
92
+ end
93
+
94
+ def self.agent
95
+ Mechanize.new
96
+ end
97
+
98
+ def self.authorized_agent
99
+ @authorized_agent ||= begin
100
+ a = agent
101
+ a.get(login_uri)
102
+ a
103
+ end
104
+ end
105
+
106
+ def self.login_uri
107
+ uri = WTForum.base_uri
108
+ uri.path = "/register/dologin"
109
+ uri.query = "member=#{WTForum.admin_username}&pw=#{WTForum.admin_password}&remember=checked"
110
+ uri
111
+ end
112
+
113
+ def self.create_uri attributes
114
+ uri = WTForum.base_api_uri(attributes)
115
+ uri.path = "/register/create_account"
116
+ uri
117
+ end
118
+
119
+ def self.find_uri user_id
120
+ uri = WTForum.base_uri
121
+ uri.path = "/register/register"
122
+ uri.query = "edit=1&userid=#{user_id}"
123
+ uri
124
+ end
125
+
126
+ def self.edit_username_uri user_id
127
+ uri = WTForum.base_uri
128
+ uri.path = "/register/edit_username"
129
+ uri.query = "userid=#{user_id}"
130
+ uri
131
+ end
132
+
133
+ def self.edit_email_uri user_id
134
+ uri = WTForum.base_uri
135
+ uri.path = "/register/edit_password"
136
+ uri.query = "userid=#{user_id}"
137
+ uri
138
+ end
139
+
140
+ def self.count_uri
141
+ uri = WTForum.base_uri
142
+ uri.path = "/register/members"
143
+ uri
144
+ end
145
+
146
+ def self.delete_uri user_id
147
+ uri = WTForum.base_uri
148
+ uri.path = "/register/delete"
149
+ uri.query = "mem_userid=#{user_id}"
150
+ uri
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ module WTForum
4
+ VERSION = "0.0.1"
5
+ end
data/lib/wtforum.rb ADDED
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ require "uri"
4
+ require "active_support/core_ext/object"
5
+ require "mechanize"
6
+ require "nokogiri"
7
+
8
+ require "wtforum/user"
9
+ require "wtforum/session"
10
+
11
+ module WTForum
12
+ class << self
13
+ attr_accessor :domain, :api_key, :admin_username, :admin_password
14
+
15
+ def base_uri
16
+ URI("http://#{domain}")
17
+ end
18
+
19
+ def base_api_uri attributes
20
+ attributes[:apikey] = api_key
21
+ uri = base_uri
22
+ uri.query = attributes.to_param
23
+ uri
24
+ end
25
+
26
+ def extract_value key, options
27
+ xml = Nokogiri::XML.parse(options[:from])
28
+ node = xml.css(key.to_s)
29
+ if node.present?
30
+ node.text
31
+ else
32
+ raise xml.css("error, .errorMsg").text
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe WTForum::Session do
6
+ let(:user) do
7
+ WTForum::User.create username: "wtforum_test_user", email: "wtforum_test_user@example.com"
8
+ end
9
+ after { user.destroy }
10
+
11
+ it "can log in users" do
12
+ session = WTForum::Session.create(user.id)
13
+ session.token.should match(/^[a-z0-9]{11}$/i)
14
+ end
15
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe WTForum::User do
6
+ it "can CRUD users" do
7
+ begin
8
+ user = nil
9
+
10
+ lambda {
11
+ user = WTForum::User.create username: "wtforum_test_user", email: "wtforum_test_user@example.com"
12
+ }.should change(WTForum::User, :count).by(1)
13
+
14
+ user = WTForum::User.find(user.id)
15
+ user.username.should == "wtforum_test_user"
16
+ user.email.should == "wtforum_test_user@example.com"
17
+
18
+ user.update_attributes! username: "wtforum_test_user_2", email: "wtforum_test_user_2@example.com"
19
+
20
+ user = WTForum::User.find(user.id)
21
+ user.username.should == "wtforum_test_user_2"
22
+ user.email.should == "wtforum_test_user_2@example.com"
23
+
24
+ ensure
25
+ lambda {
26
+ user.destroy
27
+ }.should change(WTForum::User, :count).by(-1)
28
+ end
29
+ end
30
+
31
+ it "raises an exception when a user is not found" do
32
+ lambda {
33
+ WTForum::User.find(0)
34
+ }.should raise_exception(WTForum::User::NotFound)
35
+ end
36
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ require "wtforum"
4
+
5
+ begin
6
+ require "./spec/support/credentials.rb"
7
+ rescue LoadError
8
+ puts %(
9
+ To run the tests, you must create a login credentials file at spec/support/credentials.rb. Example:
10
+
11
+ WTForum.domain = "forum.example.com"
12
+ WTForum.api_key = "TEgPYR4Zapz"
13
+ WTForum.admin_username = "__admin_api_dont_delete__"
14
+ WTForum.admin_password = "s0m3p4ssw0rd"
15
+ )
16
+ exit
17
+ end
18
+
data/wtforum.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wtforum/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "wtforum"
8
+ spec.version = WTForum::VERSION
9
+ spec.authors = ["Micah Geisel"]
10
+ spec.email = ["micah@botandrose.com"]
11
+ spec.description = %q{Ruby library that wraps Website Toolbox's forum API.}
12
+ spec.summary = %q{Ruby library that wraps Website Toolbox's forum API.}
13
+ spec.homepage = "https://github.com/botandrose/wtforum"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activesupport"
22
+ spec.add_dependency "mechanize"
23
+ spec.add_dependency "nokogiri"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec"
28
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wtforum
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Micah Geisel
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ type: :runtime
16
+ prerelease: false
17
+ name: activesupport
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ none: false
24
+ requirement: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ! '>='
27
+ - !ruby/object:Gem::Version
28
+ version: '0'
29
+ none: false
30
+ - !ruby/object:Gem::Dependency
31
+ type: :runtime
32
+ prerelease: false
33
+ name: mechanize
34
+ version_requirements: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ none: false
40
+ requirement: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ none: false
46
+ - !ruby/object:Gem::Dependency
47
+ type: :runtime
48
+ prerelease: false
49
+ name: nokogiri
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ none: false
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ none: false
62
+ - !ruby/object:Gem::Dependency
63
+ type: :development
64
+ prerelease: false
65
+ name: bundler
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ version: '1.3'
71
+ none: false
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: '1.3'
77
+ none: false
78
+ - !ruby/object:Gem::Dependency
79
+ type: :development
80
+ prerelease: false
81
+ name: rake
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ none: false
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ none: false
94
+ - !ruby/object:Gem::Dependency
95
+ type: :development
96
+ prerelease: false
97
+ name: rspec
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ none: false
104
+ requirement: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ none: false
110
+ description: Ruby library that wraps Website Toolbox's forum API.
111
+ email:
112
+ - micah@botandrose.com
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - .gitignore
118
+ - Gemfile
119
+ - LICENSE.txt
120
+ - README.md
121
+ - Rakefile
122
+ - lib/wtforum.rb
123
+ - lib/wtforum/session.rb
124
+ - lib/wtforum/user.rb
125
+ - lib/wtforum/version.rb
126
+ - spec/integration/wtforum_session_spec.rb
127
+ - spec/integration/wtforum_user_spec.rb
128
+ - spec/spec_helper.rb
129
+ - wtforum.gemspec
130
+ homepage: https://github.com/botandrose/wtforum
131
+ licenses:
132
+ - MIT
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ hash: 1995096068077646637
142
+ segments:
143
+ - 0
144
+ version: '0'
145
+ none: false
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ! '>='
149
+ - !ruby/object:Gem::Version
150
+ hash: 1995096068077646637
151
+ segments:
152
+ - 0
153
+ version: '0'
154
+ none: false
155
+ requirements: []
156
+ rubyforge_project:
157
+ rubygems_version: 1.8.25
158
+ signing_key:
159
+ specification_version: 3
160
+ summary: Ruby library that wraps Website Toolbox's forum API.
161
+ test_files:
162
+ - spec/integration/wtforum_session_spec.rb
163
+ - spec/integration/wtforum_user_spec.rb
164
+ - spec/spec_helper.rb