ucb_confluence 0.0.2
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/.svnignore +6 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +37 -0
- data/INTERNALS.md +12 -0
- data/README.md +41 -0
- data/Rakefile +21 -0
- data/TODO.md +8 -0
- data/bin/ucb_confluence +84 -0
- data/config/.svnignore +1 -0
- data/config/config.skel.yml +21 -0
- data/lib/confluence.rb +57 -0
- data/lib/confluence/config.rb +31 -0
- data/lib/confluence/conn.rb +35 -0
- data/lib/confluence/group.rb +56 -0
- data/lib/confluence/jobs/disable_expired_users.rb +87 -0
- data/lib/confluence/jobs/ist_ldap_sync.rb +154 -0
- data/lib/confluence/user.rb +312 -0
- data/lib/confluence/version.rb +3 -0
- data/spec/confluence/config_spec.rb +18 -0
- data/spec/confluence/confluence_spec.rb +21 -0
- data/spec/confluence/conn_spec.rb +9 -0
- data/spec/confluence/group_spec.rb +45 -0
- data/spec/confluence/jobs/disable_expired_users_spec.rb +51 -0
- data/spec/confluence/jobs/ist_ldap_sync_spec.rb +77 -0
- data/spec/confluence/user_spec.rb +221 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +12 -0
- data/ucb_confluence.gemspec +31 -0
- metadata +197 -0
data/.svnignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ucb_confluence (0.0.1)
|
5
|
+
rake (>= 0.8.7)
|
6
|
+
ucb_ldap (>= 1.4.2)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
columnize (0.3.4)
|
12
|
+
diff-lcs (1.1.2)
|
13
|
+
linecache (0.46)
|
14
|
+
rbx-require-relative (> 0.0.4)
|
15
|
+
rake (0.8.7)
|
16
|
+
rbx-require-relative (0.0.5)
|
17
|
+
rcov (0.9.9)
|
18
|
+
rspec (1.3.0)
|
19
|
+
ruby-debug (0.10.4)
|
20
|
+
columnize (>= 0.1)
|
21
|
+
ruby-debug-base (~> 0.10.4.0)
|
22
|
+
ruby-debug-base (0.10.4)
|
23
|
+
linecache (>= 0.3)
|
24
|
+
ruby-net-ldap (0.0.4)
|
25
|
+
ucb_ldap (1.4.2)
|
26
|
+
ruby-net-ldap (>= 0.0.4)
|
27
|
+
|
28
|
+
PLATFORMS
|
29
|
+
ruby
|
30
|
+
|
31
|
+
DEPENDENCIES
|
32
|
+
bundler (= 1.0.18)
|
33
|
+
diff-lcs (>= 1.1.2)
|
34
|
+
rcov (>= 0.9.9)
|
35
|
+
rspec (>= 1.3.0)
|
36
|
+
ruby-debug (>= 0.10.4)
|
37
|
+
ucb_confluence!
|
data/INTERNALS.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
UCB Confluence
|
2
|
+
============
|
3
|
+
|
4
|
+
UCB Confluence is a gem to assist with User and Group administration via
|
5
|
+
the Confluence xmlrpc API.
|
6
|
+
|
7
|
+
|
8
|
+
Overview
|
9
|
+
--------
|
10
|
+
|
11
|
+
Installation
|
12
|
+
------------
|
13
|
+
|
14
|
+
gem install ucb_confluence
|
15
|
+
|
16
|
+
|
17
|
+
Assumptions
|
18
|
+
-----------
|
19
|
+
|
20
|
+
General Configuration
|
21
|
+
---------------------
|
22
|
+
- Create the directory: $HOME/.ucb_confluence
|
23
|
+
- Create the file: $HOME/.ucb_confluence/config.yml
|
24
|
+
- Configure your config.yml file w/appropriate values, see sample config.yml below
|
25
|
+
|
26
|
+
server_url: https://<your-confluence-hostname>
|
27
|
+
ldap_url: ldap.berkeley.edu
|
28
|
+
username: <confluence-username>
|
29
|
+
password: <your-password>
|
30
|
+
user_default_password: <default-password-for-new-users>
|
31
|
+
|
32
|
+
|
33
|
+
Confluence Configuration
|
34
|
+
------------------------
|
35
|
+
|
36
|
+
Usage
|
37
|
+
-----
|
38
|
+
|
39
|
+
See all available commands with:
|
40
|
+
|
41
|
+
ucb_confluence -T
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
require 'spec/rake/verify_rcov'
|
4
|
+
|
5
|
+
Bundler::GemHelper.install_tasks()
|
6
|
+
|
7
|
+
Spec::Rake::SpecTask.new("spec:rcov") do |t|
|
8
|
+
t.spec_opts ||= []
|
9
|
+
t.spec_opts << "--options" << "spec/spec.opts"
|
10
|
+
t.rcov = true
|
11
|
+
end
|
12
|
+
|
13
|
+
Spec::Rake::SpecTask.new("spec") do |t|
|
14
|
+
t.spec_opts ||= []
|
15
|
+
t.spec_opts << "--options" << "spec/spec.opts"
|
16
|
+
end
|
17
|
+
|
18
|
+
RCov::VerifyTask.new(:rcov => "spec:rcov") do |t|
|
19
|
+
t.threshold = 100
|
20
|
+
end
|
21
|
+
|
data/TODO.md
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
|
2
|
+
* Make thread safe: put Conn and Config objects in an instance of Confluence class
|
3
|
+
instead of the class itself so if we use this class in a JRuby rails app where multiple
|
4
|
+
threads are used we will be happy.
|
5
|
+
|
6
|
+
- Add module for Spaces
|
7
|
+
|
8
|
+
- Add module for Permissions
|
data/bin/ucb_confluence
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'rake'
|
6
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
|
7
|
+
require 'confluence'
|
8
|
+
|
9
|
+
|
10
|
+
Rake.application.init("ucb_confluence")
|
11
|
+
|
12
|
+
namespace(:jobs) do
|
13
|
+
desc "Sync Confluence IST group with LDAP IST group."
|
14
|
+
task(:ist_ldap_sync) do
|
15
|
+
Confluence::Jobs::IstLdapSync.new.execute()
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Disable expired Confluence users."
|
19
|
+
task(:disable_expired_users) do
|
20
|
+
Confluence::Jobs::DisableExpiredUsers.new.execute()
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
namespace(:user) do
|
25
|
+
desc "List of all users in Confluence."
|
26
|
+
task(:all) do
|
27
|
+
$stdout.puts(Confluence::User.all)
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "List of all disabled confluence users."
|
31
|
+
task(:expired) do
|
32
|
+
$stdout.puts(Confluence::User.expired())
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "List of all active confluence users."
|
36
|
+
task(:active) do
|
37
|
+
$stdout.puts(Confluence::User.active())
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "Number of total users (both expired and active) in Confluence."
|
41
|
+
task(:total_count) do
|
42
|
+
$stdout.puts(Confluence::User.all.length)
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "Number of expired users in Confluence."
|
46
|
+
task(:expired_count) do
|
47
|
+
$stdout.puts(Confluence::User.expired.length)
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Number of active users in Confluence."
|
51
|
+
task(:active_count) do
|
52
|
+
$stdout.puts(Confluence::User.active.length)
|
53
|
+
end
|
54
|
+
|
55
|
+
desc "List of groups for a given user in Confluence."
|
56
|
+
task(:groups) do
|
57
|
+
user = Confluence::User.find_by_name(ENV["NAME"])
|
58
|
+
if user
|
59
|
+
$stdout.puts(user.groups)
|
60
|
+
else
|
61
|
+
$stdout.puts("[]")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
desc "Display info for a given user"
|
66
|
+
task(:find) do
|
67
|
+
$stdout.puts(Confluence::User.find_by_name(ENV["NAME"]))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
namespace(:group) do
|
72
|
+
desc "List of all groups in Confluence."
|
73
|
+
task(:all) do
|
74
|
+
$stdout.puts(Confluence::Group.all())
|
75
|
+
end
|
76
|
+
|
77
|
+
desc "Number of groups in Confluence."
|
78
|
+
task(:count) do
|
79
|
+
$stdout.puts(Confluence::Group.all.length)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
Rake.application.top_level
|
data/config/.svnignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
config.yml
|
@@ -0,0 +1,21 @@
|
|
1
|
+
dev:
|
2
|
+
server_url: https://wikihub-dev.berkeley.edu
|
3
|
+
ldap_host: ldap-test.berkeley.edu
|
4
|
+
username: <username>
|
5
|
+
password: <password>
|
6
|
+
user_default_password: <user_default_password>
|
7
|
+
|
8
|
+
qa:
|
9
|
+
server_url: https://wikihub-qa.berkeley.edu
|
10
|
+
ldap_host: ldap.berkeley.edu
|
11
|
+
username: <username>
|
12
|
+
password: <password>
|
13
|
+
user_default_password: <user_default_password>
|
14
|
+
|
15
|
+
prod:
|
16
|
+
server_url: https://wikihub.berkeley.edu
|
17
|
+
ldap_host: ldap.berkeley.edu
|
18
|
+
username: <username>
|
19
|
+
password: <password>
|
20
|
+
user_default_password: <user_default_password>
|
21
|
+
|
data/lib/confluence.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'logger'
|
3
|
+
require 'ucb_ldap'
|
4
|
+
require 'xmlrpc/client'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
require 'confluence/conn'
|
8
|
+
require 'confluence/user'
|
9
|
+
require 'confluence/group'
|
10
|
+
require 'confluence/config'
|
11
|
+
|
12
|
+
require 'confluence/jobs/ist_ldap_sync'
|
13
|
+
require 'confluence/jobs/disable_expired_users'
|
14
|
+
|
15
|
+
|
16
|
+
module Confluence
|
17
|
+
ROOT = File.expand_path(File.dirname(__FILE__) + '/../')
|
18
|
+
|
19
|
+
class << self
|
20
|
+
|
21
|
+
def conn()
|
22
|
+
unless @conn
|
23
|
+
@conn = Confluence::Conn.new(config())
|
24
|
+
end
|
25
|
+
@conn
|
26
|
+
end
|
27
|
+
|
28
|
+
def config()
|
29
|
+
unless @config
|
30
|
+
@config = Confluence::Config.new()
|
31
|
+
Confluence.logger.debug(@config.inspect())
|
32
|
+
end
|
33
|
+
@config
|
34
|
+
end
|
35
|
+
|
36
|
+
def config=(config)
|
37
|
+
@config = config
|
38
|
+
end
|
39
|
+
|
40
|
+
def logger()
|
41
|
+
unless @logger
|
42
|
+
@logger = Logger.new("#{config.home()}/log/ucb_confluence.log")
|
43
|
+
@logger.level = Logger::DEBUG
|
44
|
+
end
|
45
|
+
@logger
|
46
|
+
end
|
47
|
+
|
48
|
+
def logger=(logger)
|
49
|
+
@logger = logger
|
50
|
+
end
|
51
|
+
|
52
|
+
def root()
|
53
|
+
ROOT
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Confluence
|
2
|
+
class Config
|
3
|
+
|
4
|
+
def initialize(config_file = "#{home()}/config.yml")
|
5
|
+
init_home_dir()
|
6
|
+
config = YAML.load_file(config_file)
|
7
|
+
|
8
|
+
@config = {}
|
9
|
+
@config[:server_url] = config['server_url']
|
10
|
+
@config[:server_url].concat("/rpc/xmlrpc") unless @config[:server_url][-11..-1] == "/rpc/xmlrpc"
|
11
|
+
@config[:ldap_url] = config['ldap_url']
|
12
|
+
@config[:username] = config['username'].to_s
|
13
|
+
@config[:password] = config['password'].to_s
|
14
|
+
@config[:user_default_password] = config['user_default_password'].to_s
|
15
|
+
end
|
16
|
+
|
17
|
+
def [](key)
|
18
|
+
@config[key.to_sym]
|
19
|
+
end
|
20
|
+
|
21
|
+
def home()
|
22
|
+
"#{ENV['HOME']}/.ucb_confluence"
|
23
|
+
end
|
24
|
+
|
25
|
+
def init_home_dir()
|
26
|
+
FileUtils.mkdir(home()) unless File.exists?(home())
|
27
|
+
FileUtils.mkdir("#{home()}/log") unless File.exists?("#{home()}/log")
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Confluence
|
2
|
+
class Conn
|
3
|
+
|
4
|
+
def initialize(config)
|
5
|
+
@config = config
|
6
|
+
server = XMLRPC::Client.new2(@config[:server_url])
|
7
|
+
@conn = server.proxy("confluence1")
|
8
|
+
@token = "12345"
|
9
|
+
do_connect()
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(method_name, *args)
|
13
|
+
begin
|
14
|
+
@conn.send(method_name, *([@token] + args))
|
15
|
+
rescue XMLRPC::FaultException => e
|
16
|
+
if (e.faultString.include?("InvalidSessionException"))
|
17
|
+
do_connect
|
18
|
+
retry
|
19
|
+
else
|
20
|
+
raise(e.faultString)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def do_connect()
|
26
|
+
@token = @conn.login(@config[:username], @config[:password])
|
27
|
+
rescue XMLRPC::FaultException => e
|
28
|
+
raise(e.faultString)
|
29
|
+
rescue => e
|
30
|
+
Confluence.logger.debug("#{e.class}: #{e.message}")
|
31
|
+
raise(e)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Confluence
|
2
|
+
class Group
|
3
|
+
class << self
|
4
|
+
##
|
5
|
+
# Retrieve a list of all groups in Confluence.
|
6
|
+
#
|
7
|
+
# @return [Array<String>] names of all groups in our Confluence instance.
|
8
|
+
#
|
9
|
+
def all()
|
10
|
+
Confluence.conn.getGroups()
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Creates a new group in Confluence.
|
15
|
+
#
|
16
|
+
# @param [String] name of group to create.
|
17
|
+
# @return [true, false] result of whether group was successfully created.
|
18
|
+
#
|
19
|
+
def create(name)
|
20
|
+
if all.include?(name)
|
21
|
+
return false
|
22
|
+
else
|
23
|
+
result = Confluence.conn.addGroup(name)
|
24
|
+
Confluence.logger.debug("Created group: #{name}")
|
25
|
+
end
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Delete a group from Confluence.
|
31
|
+
#
|
32
|
+
# @param [String] name of group to delete.
|
33
|
+
# @return [true, false] result of whether group was successfully deleted.
|
34
|
+
#
|
35
|
+
def delete(name)
|
36
|
+
if all.include?(name)
|
37
|
+
result = Confluence.conn.removeGroup(name, Confluence::User::DEFAULT_GROUP)
|
38
|
+
Confluence.logger.debug("Deleted group: #{name}")
|
39
|
+
return result
|
40
|
+
else
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Predicate that indicates whether a given group exists in Confluence
|
47
|
+
#
|
48
|
+
# @param [String] the group name.
|
49
|
+
# @return [true,false]
|
50
|
+
#
|
51
|
+
def exists?(grp_name)
|
52
|
+
all.include?(grp_name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
|
2
|
+
##
|
3
|
+
# Disables a user's Confluence account if they are considered expired.
|
4
|
+
#
|
5
|
+
module Confluence
|
6
|
+
module Jobs
|
7
|
+
class DisableExpiredUsers
|
8
|
+
|
9
|
+
def initialize()
|
10
|
+
@disabled_users = []
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Run the job
|
15
|
+
#
|
16
|
+
def execute()
|
17
|
+
@disabled_users.clear()
|
18
|
+
disable_expired_users()
|
19
|
+
log_job()
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Disables any users that are expired in LDAP or are no longer in LDAP.
|
24
|
+
#
|
25
|
+
def disable_expired_users()
|
26
|
+
confluence_user_names.each do |name|
|
27
|
+
next if name == "conflusa"
|
28
|
+
ldap_person = find_in_ldap(name)
|
29
|
+
|
30
|
+
if ldap_person.nil? || !eligible_for_confluence?(ldap_person)
|
31
|
+
user = find_in_confluence(name)
|
32
|
+
user.disable()
|
33
|
+
@disabled_users << user
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def log_job()
|
39
|
+
msg = "#{self.class.name}\n\n"
|
40
|
+
msg.concat("Disabled the following Users:\n\n")
|
41
|
+
@disabled_users.each { |u| msg.concat(u) }
|
42
|
+
logger.info(msg)
|
43
|
+
end
|
44
|
+
|
45
|
+
def logger()
|
46
|
+
Confluence.logger
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# @return [Array<String>] confluence user names.
|
51
|
+
#
|
52
|
+
def confluence_user_names()
|
53
|
+
Confluence::User.active.map(&:name)
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# @param [String] user's confluence account name.
|
58
|
+
# @return [Confluence::User, nil]
|
59
|
+
#
|
60
|
+
def find_in_confluence(name)
|
61
|
+
Confluence::User.find_by_name(name)
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# @param [String] user's ldap uid
|
66
|
+
# @return [UCB::LDAP::Person, nil]
|
67
|
+
#
|
68
|
+
def find_in_ldap(ldap_uid)
|
69
|
+
UCB::LDAP::Person.find_by_uid(ldap_uid)
|
70
|
+
end
|
71
|
+
|
72
|
+
def eligible_for_confluence?(person)
|
73
|
+
valid_affiliations = person.affiliations.inject([]) do |accum, aff|
|
74
|
+
if aff =~ /AFFILIATE-TYPE.*(ALUMNUS|RETIREE|EXPIRED)/
|
75
|
+
accum
|
76
|
+
elsif aff =~ /AFFILIATE-TYPE.*/
|
77
|
+
accum << aff
|
78
|
+
end
|
79
|
+
accum
|
80
|
+
end
|
81
|
+
|
82
|
+
person.employee? || !valid_affiliations.empty?
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|