rgroups 0.1.0 → 0.2.0

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.
Files changed (5) hide show
  1. data/README.rdoc +25 -0
  2. data/VERSION +1 -1
  3. data/lib/rgroups.rb +114 -2
  4. data/rgroups.gemspec +65 -0
  5. metadata +5 -4
@@ -2,6 +2,31 @@
2
2
 
3
3
  Ruby API for accessing/updating Google Groups - based on Mechanize. This essentially just screen-scrapes Google Groups and automates clicking on things. It's not entirely efficient, but it sure beats having to script it yourself.
4
4
 
5
+ == Usage
6
+ Setup is easy!
7
+ require 'rgroups'
8
+ rg = RGroup.new
9
+ rg.login('username', 'password')
10
+
11
+ Or, if you're using Google Apps for your Domain (GAFYD):
12
+ rg = RGroup.new('mydomain.com')
13
+ rg.login('username', 'password')
14
+
15
+ Adding a user to a group:
16
+ rg.add_user('address@domain.com', 'group', :message => 'message to send to invitees')
17
+
18
+ Adding a user directly (only for GAFYD accounts):
19
+ rg.add_user('address@mydomain.com', 'group', :mode => 'direct', :notify => true, :message => 'message to send to people', :delivery => 'digest')
20
+
21
+ Modifying a user's delivery options:
22
+ rg.update_user('address@domain.com', 'group', 'set_delivery', :value => 'summary')
23
+
24
+ Modifying a user's membership type:
25
+ rg.update_user('address@domain.com', 'group', 'set_member', :value => 'manager')
26
+
27
+ == Notes
28
+ This relies on the 'old style' Google Groups. Please ensure that your group is using the old style before reporting a bug. Support for the new style should come soon...
29
+
5
30
  == Contributing to rgroups
6
31
 
7
32
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -6,6 +6,10 @@ class RGroup
6
6
  @@DIRECT_ADD = '/manage_members_add'
7
7
  @@INVITE_ADD = '/members_invite'
8
8
  @@GROUP_SETTINGS = '/manage_general'
9
+ @@ACCESS_SETTINGS = '/manage_access'
10
+ @@POST_SETTINGS = '/manage_post'
11
+ @@ADV_SETTINGS = '/manage_advanced'
12
+ @@SPAM_SETTINGS = '/manage_spam'
9
13
 
10
14
  def initialize(*gafyd)
11
15
  @scraper = Mechanize.new
@@ -19,7 +23,8 @@ class RGroup
19
23
  @GAFYD = true
20
24
  end
21
25
  end
22
-
26
+
27
+ # login to google apps
23
28
  def login(username, password)
24
29
  page = @scraper.get(@LOGIN_URL)
25
30
  f = page.forms[0]
@@ -28,6 +33,14 @@ class RGroup
28
33
  @scraper.submit(f, f.buttons.first)
29
34
  end
30
35
 
36
+ # add a user
37
+ # email = email address to add
38
+ # group = group name
39
+ # :mode => direct (only for gafyd accounts)
40
+ # :notify => true/false to notify users they've been added (only for gafyd)
41
+ # :delivery => only for gafyd
42
+ # - none, email, summary, one
43
+ # :message => message to send to person when being added
31
44
  def add_user(email, group, opts={})
32
45
  if (opts[:mode] && opts[:mode].downcase == "direct")
33
46
  raise "direct add mode is only available for gafyd accounts" unless @GAFYD
@@ -73,6 +86,13 @@ class RGroup
73
86
  @scraper.submit(member_form, member_form.button_with(:name => 'Action.InitialAddMembers'))
74
87
  end
75
88
 
89
+ # update a user
90
+ # email = email address to update
91
+ # group = group name
92
+ # action = set_member, set_email
93
+ # :value => depends on what you're doing.
94
+ # - set_member: regular, manager, owner, unsubscribe, ban
95
+ # - set_email: none, email, summary, one
76
96
  def update_user(email, group, action, opts={})
77
97
  page = @scraper.get(@BASE_URL + group + @@MANAGE)
78
98
  member_set = page.search('//table[@class="memlist"]//td')
@@ -120,9 +140,99 @@ class RGroup
120
140
 
121
141
  end
122
142
 
143
+ # return a hash of group settings
144
+ def settings(group)
145
+ settings = {}
146
+
147
+ page = @scraper.get(@BASE_URL + group + @@GROUP_SETTINGS)
148
+ settings['group_name'] = page.search('//div[@id="name_view"]').text.strip
149
+ settings['group_description'] = page.search('//div[@id="desc_view"]').text.strip
150
+ settings['group_website'] = page.search('//div[@id="info_url_view"]').text.strip
151
+
152
+
153
+ page = @scraper.get(@BASE_URL + group + @@ACCESS_SETTINGS)
154
+ form = page.form_with(:id => "GM_form")
155
+ if (@GAFYD)
156
+ settings['allow_external'] = form.checkbox_with(:name => 'param.allow_external_members').checked?
157
+ end
158
+ form.radiobuttons_with(:name => 'param.archive_view').each do |r|
159
+ settings['archive_view'] = r.value if r.checked?
160
+ end
161
+ form.radiobuttons_with(:name => 'param.members_view').each do |r|
162
+ settings['member_view'] = r.value if r.checked?
163
+ end
164
+ form.radiobuttons_with(:name => 'param.who_can_join').each do |r|
165
+ settings['can_join'] = r.value if r.checked?
166
+ end
167
+ settings['join_question'] = form.field_with(:name => 'param.join_question').value.strip
168
+ form.radiobuttons_with(:name => 'param.who_can_post').each do |r|
169
+ settings['who_can_post'] = "managers" if r.checked? && r.value == 'm'
170
+ settings['who_can_post'] = "members" if r.checked? && r.value == 's'
171
+ settings['who_can_post'] = "domain" if r.checked? && r.value == 'd'
172
+ settings['who_can_post'] = "anyone" if r.checked? && r.value == 'p'
173
+ end
174
+ settings['mod_non_members'] = form.checkbox_with(:name => 'param.mod_non_members').checked?
175
+ settings['web_posting'] = form.checkbox_with(:name => 'param.allow_web_posting').checked?
176
+ form.radiobuttons_with(:name => 'param.who_can_invite').each do |r|
177
+ settings['who_can_invite'] = r.value if r.checked?
178
+ end
179
+ form.radiobuttons_with(:name => 'param.msg_moderation').each do |r|
180
+ settings['msg_moderation'] = r.value if r.checked?
181
+ end
182
+ settings['mod_new_members'] = form.checkbox_with(:name => 'param.mod_new_members').checked?
183
+
184
+
185
+ page = @scraper.get(@BASE_URL + group + @@POST_SETTINGS)
186
+ form = page.form_with(:id => "GM_form")
187
+ if (@GAFYD)
188
+ settings['custom_reply_to'] = form.field_with(:name => 'param.custom_reply_to').value.strip
189
+ form.field_with(:name => 'param.max_size').options.each do |s|
190
+ settings['max_size'] = s.value if s.selected?
191
+ end
192
+ settings['reply_with_bounce_list'] = form.checkbox_with(:name => 'param.reply_with_bounce_list').checked?
193
+ end
194
+ settings['subject_tag'] = form.field_with(:name => 'param.subject_tag').value.strip
195
+ form.radiobuttons_with(:name => 'param.footer').each do |r|
196
+ settings['message_footer'] = "none" if r.checked? && r.value == 'n'
197
+ settings['message_footer'] = "default" if r.checked? && r.value == 'd'
198
+ settings['message_footer'] = "custom" if r.checked? && r.value == 'c'
199
+ end
200
+ settings['reply_to'] = form.field_with(:name => 'param.footer_text').value.strip
201
+ form.radiobuttons_with(:name => 'param.reply_to').each do |r|
202
+ settings['reply_to'] = "whole_group" if r.checked? && r.value == 'l'
203
+ settings['reply_to'] = "author" if r.checked? && r.value == 'a'
204
+ settings['reply_to'] = "owner" if r.checked? && r.value == 'o'
205
+ settings['reply_to'] = "user_decide" if r.checked? && r.value == 'n'
206
+ settings['reply_to'] = "custom" if r.checked? && r.value == 'c'
207
+ end
208
+ settings['posting_as_group'] = form.checkbox_with(:name => 'param.posting_as_group').checked?
209
+ settings['moderation_notify'] = form.checkbox_with(:name => 'param.moderation_notify').checked?
210
+ settings['moderation_message_text'] = form.field_with(:name => 'param.footer_text').value.strip
211
+
212
+ page = @scraper.get(@BASE_URL + group + @@ADV_SETTINGS)
213
+ form = page.form_with(:id => "GM_form")
214
+ form.field_with(:name => 'param.lang').options.each do |s|
215
+ settings['primary_language'] = s.value if s.selected?
216
+ end
217
+ settings['fixed_font'] = form.checkbox_with(:name => 'param.font_type').checked?
218
+ settings['no_archive_msgs'] = form.checkbox_with(:name => 'param.no_archive').checked?
219
+ settings['group_is_archived'] = form.checkbox_with(:name => 'param.status_archive').checked?
220
+ settings['google_contact'] = form.checkbox_with(:name => 'param.can_contact').checked?
221
+
222
+ page = @scraper.get(@BASE_URL + group + @@SPAM_SETTINGS)
223
+ form = page.form_with(:id => "GM_form")
224
+ form.radiobuttons_with(:name => 'param.spam_mode').each do |r|
225
+ settings['spam_mode'] = "post" if r.checked? && r.value == '0'
226
+ settings['spam_mode'] = "mod" if r.checked? && r.value == '1'
227
+ settings['spam_mode'] = "mod_quiet" if r.checked? && r.value == '3'
228
+ settings['spam_mode'] = "reject" if r.checked? && r.value == '2'
229
+ end
230
+ return settings
231
+ end
232
+
123
233
  end
124
234
 
125
- # monkey-patch Mechanize so we can't reuse ssl sessions
235
+ # monkey-patch Mechanize::HTTP::Agent so we can't reuse ssl sessions
126
236
  # as that seems to break things
127
237
  class Mechanize::HTTP::Agent
128
238
  def reuse_ssl_sessions
@@ -134,6 +244,8 @@ class Mechanize::HTTP::Agent
134
244
  end
135
245
  end
136
246
 
247
+ # monkey-patch Mechanize so we can't reuse ssl sessions
248
+ # as that seems to break things
137
249
  class Mechanize
138
250
  def reuse_ssl_sessions
139
251
  @agent.reuse_ssl_sessions
@@ -0,0 +1,65 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "rgroups"
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Andrew Hayworth"]
12
+ s.date = "2012-06-18"
13
+ s.description = "This is a Ruby API for accessing and updating Google Groups. It's based on Mechanize, which means it's essentially screen-scraping."
14
+ s.email = "ahayworth@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE.txt",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "lib/rgroups.rb",
28
+ "rgroups.gemspec",
29
+ "test/helper.rb",
30
+ "test/test_rgroups.rb"
31
+ ]
32
+ s.homepage = "http://github.com/ahayworth/rgroups"
33
+ s.licenses = ["MIT"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = "1.8.24"
36
+ s.summary = "Ruby API for accessing/updating Google Groups - based on Mechanize"
37
+
38
+ if s.respond_to? :specification_version then
39
+ s.specification_version = 3
40
+
41
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
42
+ s.add_runtime_dependency(%q<mechanize>, [">= 0"])
43
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
44
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
45
+ s.add_development_dependency(%q<bundler>, [">= 0"])
46
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
47
+ s.add_development_dependency(%q<rcov>, [">= 0"])
48
+ else
49
+ s.add_dependency(%q<mechanize>, [">= 0"])
50
+ s.add_dependency(%q<shoulda>, [">= 0"])
51
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
52
+ s.add_dependency(%q<bundler>, [">= 0"])
53
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
54
+ s.add_dependency(%q<rcov>, [">= 0"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<mechanize>, [">= 0"])
58
+ s.add_dependency(%q<shoulda>, [">= 0"])
59
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
60
+ s.add_dependency(%q<bundler>, [">= 0"])
61
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
62
+ s.add_dependency(%q<rcov>, [">= 0"])
63
+ end
64
+ end
65
+
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rgroups
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Andrew Hayworth
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-06-17 00:00:00 Z
18
+ date: 2012-06-18 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  requirement: &id001 !ruby/object:Gem::Requirement
@@ -122,6 +122,7 @@ files:
122
122
  - Rakefile
123
123
  - VERSION
124
124
  - lib/rgroups.rb
125
+ - rgroups.gemspec
125
126
  - test/helper.rb
126
127
  - test/test_rgroups.rb
127
128
  homepage: http://github.com/ahayworth/rgroups