wtforum 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.
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