mooset 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1c1dd100f51b3643d324c7003d9a7ee5be2c2cf0
4
+ data.tar.gz: 050188451cc9fc0a22c32c86036d3d55a665ea38
5
+ SHA512:
6
+ metadata.gz: 3b01c6cf1a52ba47895c6e2f01eb3b31bc60fc4340b9e6d9078830b26121f10eb74a0e93e06c0337cd215519d78e41d509e248425c0409af472c6339c8b2f139
7
+ data.tar.gz: 681efd27a6ed58b68b3fd352612854367c9bb54c54cdc9e4e3b3a9c7d8414e8f4b38c0de34aafdac718895998e4a09ac385ff7f1eb1b6b95e5e35d45dd783158
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Alexandru Keszeg
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,31 @@
1
+ # Mooset
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'mooset'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install mooset
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/mooset/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ require "bundler/gem_tasks"
2
+
3
+
4
+ task :default do
5
+ p "User: rake gitlab:login"
6
+ end
7
+
8
+ task :environment do
9
+ require 'bundler'
10
+ Bundler.require :default
11
+
12
+ require 'highline/import'
13
+ end
14
+
15
+ namespace :gitlab do
16
+ desc "Login to a gitlab server and get the users private token"
17
+ task :login => :environment do
18
+ require 'pry'; binding.pry
19
+ ENV["GITLAB_URL"] ||= 'http://gitlab-dev'
20
+
21
+ username = ask("Username? ")
22
+ password = ask("Pasword? ") { |q| q.echo = '*' }
23
+
24
+ client = Gitlab.client(endpoint: ENV["GITLAB_URL"] + '/api/v3/')
25
+ response = client.session(username, password)
26
+
27
+ if response
28
+ p response.to_hash["private_token"]
29
+ else
30
+ STDOUT.puts "Login failed"
31
+ end
32
+ end
33
+ end
34
+
data/bin/mooset ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ lib = File.expand_path('../../lib', __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+ require 'mooset'
7
+
8
+ Mooset::Application.run(ARGV)
data/config/sample ADDED
@@ -0,0 +1,18 @@
1
+ # vi:syntax=ruby
2
+
3
+ define :origin, :null, {
4
+ host: 'localhost',
5
+ port: 389,
6
+ bind_dn: 'CN=user,OU=users,DC=domain,DC=com',
7
+ bind_password: '',
8
+ treebase: 'DC=domain,DC=com'
9
+ }
10
+
11
+ define :gitlab_dev, :gitlab, {
12
+ endpoint: 'http://gitlab',
13
+ private_token: ''
14
+ }
15
+
16
+ define :out, :console_logger
17
+
18
+ synchronize_users from: :origin, to: :output, query: '(&(memberof=CN=Users,DC=domain,DC=com)(!(useraccountcontrol:1.2.840.113556.1.4.803:=2)))'
@@ -0,0 +1,57 @@
1
+ require 'optparse'
2
+
3
+ module Mooset
4
+ class Application
5
+ attr_accessor :config_filename
6
+
7
+ def define(endpoint_name, factory, *args)
8
+ Mooset.define_singleton_method(endpoint_name) do
9
+ Mooset::Endpoints::Endpoint.create(factory, endpoint_name, *args)
10
+ end
11
+ end
12
+
13
+ def instances
14
+ @instances ||= {}
15
+ end
16
+
17
+ def synchronize_users(from:, to:, **opts)
18
+ connections << { from: from, to: to, opts: opts }
19
+ end
20
+
21
+ def connections
22
+ @connection ||= []
23
+ end
24
+
25
+ def run!
26
+ connections.each do |event|
27
+ from = instances[event[:from]]
28
+ to = instances[event[:to]]
29
+ opts = event[:opts]
30
+
31
+ Mooset::SynchronizeUsers.call(from, to, opts)
32
+ end
33
+ end
34
+
35
+ def read_config
36
+ instance_eval File.read(config_filename), config_filename
37
+ end
38
+
39
+ def configure(&block)
40
+ yield self
41
+ end
42
+
43
+ def self.run(argv)
44
+ s = self.new
45
+
46
+ OptionParser.new do |opts|
47
+ opts.banner = "Usage: #{$0} [options]"
48
+ opts.on("-c", "--config FILE", "Config file", s.method(:config_filename=))
49
+ opts.parse!(argv)
50
+ end
51
+
52
+ s.read_config
53
+ s.run!
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,21 @@
1
+ module Mooset
2
+ class Configuration
3
+ attr_reader :definitions, :tasks, :config_filename
4
+
5
+ def initialize(config_filename)
6
+ @config_filename = config_filename
7
+ @definitions = {}
8
+ @tasks = []
9
+
10
+ instance_eval File.read(@config_filename), @config_filename
11
+ end
12
+
13
+ def define(name, factory, *args)
14
+ @definitions[name] = Mooset::Endpoints::Endpoint.create(factory, *args)
15
+ end
16
+
17
+ def synchronize_users(from: nil, to: nil, query: nil)
18
+ @tasks << { from: from, to: to, query: query }
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module Mooset
2
+ module Endpoints
3
+ class ConsoleLogger < Endpoint
4
+ def write(user)
5
+ p user
6
+ end
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,40 @@
1
+ require 'virtus'
2
+
3
+ module Mooset
4
+ module Endpoints
5
+ class Endpoint
6
+ include Virtus.model
7
+
8
+ attr_reader :endpoint_name
9
+
10
+ def initialize(endpoint_name, *args)
11
+ @endpoint_name = endpoint_name
12
+
13
+ super(*args)
14
+ end
15
+
16
+ def self.inherited(klass)
17
+ super
18
+
19
+ name = underscore(klass.name.split('::').last)
20
+ descendants[name.to_sym] = klass
21
+ end
22
+
23
+ def self.descendants
24
+ @descendants ||= {}
25
+ end
26
+
27
+ def self.underscore(camel_cased_word)
28
+ camel_cased_word.to_s.gsub(/::/, '/').
29
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
30
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
31
+ tr("-", "_").
32
+ downcase
33
+ end
34
+
35
+ def self.create(name, endpoint_name, *args)
36
+ descendants[name].new(endpoint_name, *args)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,35 @@
1
+ module Mooset
2
+ module Endpoints
3
+ class Gitlab
4
+ class Group < Models::Group
5
+ GUEST = 10
6
+ REPORTER = 20
7
+ DEVELOPER = 30
8
+ MASTER = 40
9
+ OWNER = 50
10
+
11
+ attribute :path
12
+ attribute :owner_id
13
+ attribute :provider, String, default: "gitlab"
14
+
15
+ def self.build(endpoint_name, group)
16
+ new(
17
+ endpoint_name: endpoint_name,
18
+ id: group.id,
19
+ name: group.name,
20
+ path: group.path,
21
+ owner_id: group.owner_id
22
+ )
23
+ end
24
+
25
+ def members
26
+ endpoint.users.memberof(id)
27
+ end
28
+
29
+ def <<(user)
30
+ endpoint.groups.add_group_member(id, user.id, DEVELOPER)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,60 @@
1
+ module Mooset
2
+ module Endpoints
3
+ class Gitlab
4
+ class GroupSearch
5
+ attr_reader :endpoint
6
+
7
+ def initialize(endpoint)
8
+ @endpoint = endpoint
9
+ end
10
+
11
+ def all
12
+ page = 1
13
+ objects = []
14
+
15
+ while (o = connection.groups(page: page)).length > 0 do
16
+ objects += o
17
+ page += 1
18
+ end
19
+
20
+ objects.collect do |object|
21
+ Group.build(endpoint.endpoint_name, object)
22
+ end
23
+ end
24
+
25
+ def find(id)
26
+ Group.build(endpoint.endpoint_name, connection.group(id))
27
+ end
28
+
29
+ def members(id)
30
+ page = 1
31
+ objects = []
32
+
33
+ while (o = connection.group_members(id, page: page)).length > 0 do
34
+ objects += o
35
+ page += 1
36
+ end
37
+
38
+ objects.collect do |object|
39
+ User.build(endpoint.endpoint_name, object)
40
+ end
41
+ end
42
+
43
+ def create(name, path)
44
+ Group.build(endpoint.endpoint_name, connection.create_group(name, path))
45
+ end
46
+
47
+ def add_group_member(team_id, user_id, access_level = 50)
48
+ connection.add_group_member(team_id, user_id, access_level)
49
+ end
50
+
51
+ private
52
+
53
+ def connection
54
+ endpoint.connection
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,24 @@
1
+ module Mooset
2
+ module Endpoints
3
+ class Gitlab
4
+ class User < Models::User
5
+ attribute :state
6
+ attribute :access_level
7
+ attribute :provider, String, default: "gitlab"
8
+
9
+ def self.build(endpoint_name, user)
10
+ self.new(
11
+ endpoint_name: endpoint_name,
12
+ id: user.id,
13
+ username: user.username,
14
+ full_name: user.name,
15
+ state: user.state,
16
+ email: user.email,
17
+ access_level: user.access_level
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,52 @@
1
+ module Mooset
2
+ module Endpoints
3
+ class Gitlab
4
+ class UserSearch
5
+ attr_reader :endpoint
6
+
7
+ def initialize(endpoint)
8
+ @endpoint = endpoint
9
+ end
10
+
11
+ def all
12
+ page = 1
13
+ objects = []
14
+
15
+ while (o = connection.users(page: page)).length > 0 do
16
+ objects += o
17
+ page += 1
18
+ end
19
+
20
+ objects.collect do |object|
21
+ User.build(endpoint.endpoint_name, object)
22
+ end
23
+ end
24
+
25
+ def find(id)
26
+ User.build(endpoint.endpoint_name, connection.user(id))
27
+ end
28
+
29
+ def memberof(id)
30
+ page = 1
31
+ objects = []
32
+
33
+ while (o = connection.group_members(id, page: page)).length > 0 do
34
+ objects += o
35
+ page += 1
36
+ end
37
+
38
+ objects.collect do |object|
39
+ User.build(endpoint.endpoint_name, object)
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def connection
46
+ endpoint.connection
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+
@@ -0,0 +1,39 @@
1
+ require 'gitlab'
2
+
3
+ module Mooset
4
+ module Endpoints
5
+ class Gitlab < Endpoint
6
+
7
+ attribute :endpoint, String
8
+ attribute :private_token, String
9
+ attribute :connection, Object, default: Proc.new { |gitlab, attribute|
10
+ ::Gitlab.client({
11
+ endpoint: "#{gitlab.endpoint}/api/v3/",
12
+ private_token: gitlab.private_token,
13
+ })
14
+ }
15
+
16
+ attribute :storage, Object, default: Proc.new {
17
+ Storage::Memory.new(name)
18
+ }
19
+
20
+ def users
21
+ @users ||= UserSearch.new(self)
22
+ end
23
+
24
+ def groups
25
+ @groups ||= GroupSearch.new(self)
26
+ end
27
+
28
+ def write(user)
29
+ unless storage.exists?(user)
30
+ connection.create_user(user.email, '123123123',{
31
+ extern_uid: user.extern_uid,
32
+ username: user.username,
33
+ provider: 'ldap',
34
+ })
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,27 @@
1
+ module Mooset
2
+ module Endpoints
3
+ class Ldap
4
+ class Group < Models::Group
5
+ attribute :provider, String, default: "ldap"
6
+
7
+ def self.build(endpoint_name, params)
8
+ group = Optional.new(params)
9
+ new(
10
+ endpoint_name: endpoint_name,
11
+ id: group[:dn].value,
12
+ name: group[:cn].first.value,
13
+ member: group[:member].within do |users|
14
+ users_from(endpoint_name, Many.new(users)).values
15
+ end.value,
16
+ )
17
+ end
18
+
19
+ def self.users_from(endpoint_name, users)
20
+ users.within do |user|
21
+ Ldap::User.build(endpoint_name, id: user)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,31 @@
1
+ module Mooset
2
+ module Endpoints
3
+ class Ldap
4
+ class GroupSearch
5
+ GROUP_FILTER = "(objectClass=group)"
6
+
7
+ attr_reader :endpoint
8
+
9
+ def initialize(endpoint)
10
+ @endpoint = endpoint
11
+ end
12
+
13
+ def query(filter = GROUP_FILTER, base: endpoint.treebase)
14
+ connection.search(base: base, filter: filter).collect do |object|
15
+ Group.build(endpoint.endpoint_name, object)
16
+ end
17
+ end
18
+
19
+ def all
20
+ query(GROUP_FILTER)
21
+ end
22
+
23
+ private
24
+
25
+ def connection
26
+ @endpoint.connection
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,69 @@
1
+ module Mooset
2
+ module Endpoints
3
+ class Ldap
4
+ module AccountControl
5
+ SCRIPT = 0x0001
6
+ ACCOUNTDISABLE = 0x0002
7
+ HOMEDIR_REQUIRED = 0x0008
8
+ LOCKOUT = 0x0010
9
+ PASSWD_NOTREQD = 0x0020
10
+ PASSWD_CANT_CHANGE = 0x0040
11
+ ENCRYPTED_TEXT_PWD_ALLOWED = 0x0080
12
+ TEMP_DUPLICATE_ACCOUNT = 0x0100
13
+ NORMAL_ACCOUNT = 0x0200
14
+ INTERDOMAIN_TRUST_ACCOUNT = 0x0800
15
+ WORKSTATION_TRUST_ACCOUNT = 0x1000
16
+ SERVER_TRUST_ACCOUNT = 0x2000
17
+ DONT_EXPIRE_PASSWORD = 0x10000
18
+ MNS_LOGON_ACCOUNT = 0x20000
19
+ SMARTCARD_REQUIRED = 0x40000
20
+ TRUSTED_FOR_DELEGATION = 0x80000
21
+ NOT_DELEGATED = 0x100000
22
+ USE_DES_KEY_ONLY = 0x200000
23
+ DONT_REQ_PREAUTH = 0x400000
24
+ PASSWORD_EXPIRED = 0x800000
25
+ TRUSTED_TO_AUTH_FOR_DELEGATION = 0x1000000
26
+ PARTIAL_SECRETS_ACCOUNT = 0x04000000
27
+
28
+ class << self
29
+ def decode(value)
30
+ value.within do |int|
31
+ result = OpenStruct.new
32
+
33
+ AccountControl.constants(false).each do |name|
34
+ result[name.to_s.downcase] = (int & AccountControl.const_get(name)) > 0
35
+ end
36
+
37
+ result
38
+ end.value
39
+ end
40
+ end
41
+ end
42
+
43
+ class User < Models::User
44
+ attribute :provider, String, default: "ldap"
45
+
46
+ def self.groups_from(endpoint_name, groups)
47
+ groups.within do |group|
48
+ Ldap::Group.build(endpoint_name, id: group)
49
+ end
50
+ end
51
+
52
+ def self.build(endpoint_name, params)
53
+ user = Optional.new(params)
54
+
55
+ self.new(
56
+ endpoint_name: endpoint_name,
57
+ id: user[:dn].value,
58
+ dn: user[:dn].value,
59
+ email: user[:mail].first.value,
60
+ full_name: user[:cn].first.value,
61
+ username: user[:sAMAccountName].value,
62
+ memberof: user[:memberof].within { |groups| groups_from(endpoint_name, Many.new(groups)).values }.value,
63
+ useraccountcontrol: AccountControl.decode(user[:useraccountcontrol][0].to_i),
64
+ )
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,31 @@
1
+ module Mooset
2
+ module Endpoints
3
+ class Ldap
4
+ class UserSearch
5
+ USER_FILTER = "(objectClass=person)"
6
+
7
+ attr_reader :endpoint
8
+
9
+ def initialize(endpoint)
10
+ @endpoint = endpoint
11
+ end
12
+
13
+ def query(filter = USER_FILTER, base: endpoint.treebase)
14
+ connection.search(base: base, filter: filter).collect do |object|
15
+ User.build(endpoint.endpoint_name, object)
16
+ end
17
+ end
18
+
19
+ def all
20
+ query(USER_FILTER)
21
+ end
22
+
23
+ private
24
+
25
+ def connection
26
+ @endpoint.connection
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ require 'net/ldap'
2
+
3
+ module Mooset
4
+ module Endpoints
5
+ class Ldap < Endpoint
6
+ USER_FILTER = "(objectClass=person)"
7
+ GROUP_FILTER = "(objectClass=group)"
8
+
9
+ attribute :host, String
10
+ attribute :port, Integer
11
+ attribute :bind_dn, String
12
+ attribute :bind_password, String
13
+ attribute :treebase, String
14
+ attribute :connection, Object, default: Proc.new { |ldap, attribute|
15
+ connection = Net::LDAP.new
16
+ connection.host = ldap.host
17
+ connection.port = ldap.port
18
+ connection.auth ldap.bind_dn, ldap.bind_password
19
+ connection
20
+ }
21
+
22
+ attribute :storage, Object, default: Proc.new { Storage::Memory.new(name) }
23
+
24
+ def write(*user)
25
+ raise "Read only endpoint"
26
+ end
27
+
28
+ def users(query = USER_FILTER)
29
+ UserSearch.new(self)
30
+ end
31
+
32
+ def find(dn)
33
+ Many.new(query("(objectClass=*)", base: dn)).within do |data|
34
+ if data[:objectclass] && data[:objectclass].include?("group")
35
+ Group.build(connection, data)
36
+ elsif data[:objectclass] && data[:objectclass].include?("user")
37
+ User.build(connection, data)
38
+ else
39
+ raise "Unknown objectclass"
40
+ end
41
+ end.values.first
42
+ end
43
+
44
+ def groups(query = GROUP_FILTER)
45
+ GroupSearch.new(self)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,14 @@
1
+ module Mooset
2
+ module Endpoints
3
+ class Null < Endpoint
4
+ def users(query)
5
+ [OpenStruct.new]
6
+ end
7
+
8
+ def groups(query)
9
+ []
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,18 @@
1
+ require 'mooset/endpoints/endpoint'
2
+ require 'mooset/endpoints/gitlab'
3
+ require 'mooset/endpoints/gitlab/user'
4
+ require 'mooset/endpoints/gitlab/group'
5
+ require 'mooset/endpoints/gitlab/user_search'
6
+ require 'mooset/endpoints/gitlab/group_search'
7
+ require 'mooset/endpoints/ldap'
8
+ require 'mooset/endpoints/ldap/user'
9
+ require 'mooset/endpoints/ldap/group'
10
+ require 'mooset/endpoints/ldap/user_search'
11
+ require 'mooset/endpoints/ldap/group_search'
12
+ require 'mooset/endpoints/console_logger'
13
+ require 'mooset/endpoints/null'
14
+
15
+ module Mooset
16
+ module Endpoints
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ module Mooset
2
+ module Models
3
+ class Group < Resource
4
+ attribute :id
5
+ attribute :name
6
+ attribute :members
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,13 @@
1
+ module Mooset
2
+ module Models
3
+ class User < Resource
4
+ attribute :id
5
+ attribute :username
6
+ attribute :email
7
+ attribute :full_name
8
+ attribute :memberof
9
+ attribute :useraccountcontrol
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,76 @@
1
+ module Mooset
2
+ module Monad
3
+ def within(&block)
4
+ and_then do |value|
5
+ self.class.from_value(block.call(value))
6
+ end
7
+ end
8
+
9
+ def method_missing(*args, &block)
10
+ within do |value|
11
+ begin
12
+ value.public_send(*args, &block)
13
+ rescue
14
+ require 'pry'; binding.pry
15
+ end
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def ensure_monadic_result(&block)
22
+ acceptable_result_type = self.class
23
+
24
+ ->(*a, &b) do
25
+ block.call(*a, &b).tap do |result|
26
+ unless result.is_a?(acceptable_result_type)
27
+ raise TypeError, "block must return #{acceptable_result_type.name}"
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ class Optional
35
+ include Monad
36
+
37
+ attr_reader :value
38
+ def initialize(value)
39
+ @value = value
40
+ end
41
+
42
+ def and_then(&block)
43
+ block = ensure_monadic_result(&block)
44
+
45
+ if value.nil?
46
+ self
47
+ else
48
+ block.call(value)
49
+ end
50
+ end
51
+
52
+ def self.from_value(value)
53
+ Optional.new(value)
54
+ end
55
+ end
56
+
57
+ class Many
58
+ include Monad
59
+
60
+ attr_reader :values
61
+
62
+ def initialize(values)
63
+ @values = values
64
+ end
65
+
66
+ def and_then(&block)
67
+ block = ensure_monadic_result(&block)
68
+
69
+ Many.new(values.map(&block).flat_map(&:values))
70
+ end
71
+
72
+ def self.from_value(value)
73
+ Many.new([value])
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,16 @@
1
+ module Mooset
2
+ class Resource
3
+ include Virtus.model
4
+
5
+ attribute :raw
6
+ attribute :endpoint_name
7
+
8
+ def endpoint
9
+ Mooset.public_send(endpoint_name)
10
+ end
11
+
12
+ def initialize(*args)
13
+ super(*args)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,34 @@
1
+ module Mooset
2
+ module Storage
3
+ class Memory
4
+ attr_reader :name
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ @objects = {}
9
+ end
10
+
11
+ def set(id, object)
12
+ @objects[id] = object
13
+ end
14
+
15
+ def exists?(id)
16
+ !@objects[id].nil?
17
+ end
18
+
19
+ def get(id)
20
+ @objects[id]
21
+ end
22
+
23
+ def fetch(id, &block)
24
+ if exists?(id)
25
+ get(id)
26
+ else
27
+ object = block.call
28
+ set(id, object)
29
+ object
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,6 @@
1
+ require 'mooset/storage/memory'
2
+
3
+ module Mooset
4
+ module Storage
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ module Mooset
2
+ class SynchronizeUsers
3
+ def self.call(from, to, opts)
4
+ from.users(opts[:query]).each do |user|
5
+ to.write(user)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module Mooset
2
+ VERSION = "0.0.2"
3
+ end
data/lib/mooset.rb ADDED
@@ -0,0 +1,15 @@
1
+ module Mooset
2
+ end
3
+
4
+ require "virtus"
5
+ require "mooset/version"
6
+ require "mooset/monads"
7
+
8
+ require "mooset/resource"
9
+ require "mooset/models/user"
10
+ require "mooset/models/group"
11
+
12
+ require "mooset/endpoints"
13
+ require "mooset/storage/memory"
14
+ require "mooset/application"
15
+ require "mooset/synchronize_users"
data/mooset.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mooset/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mooset"
8
+ spec.version = Mooset::VERSION
9
+ spec.authors = ["Alexandru Keszeg"]
10
+ spec.email = ["akeszeg@gmail.com"]
11
+ spec.summary = %q{A Ruby library and client for user migration.}
12
+ spec.description = %q{Ruby library and client for user migration.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
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 "gitlab", "~> 3.3.0"
22
+ spec.add_dependency "virtus", "~> 1.0.3"
23
+ spec.add_dependency "net-ldap", "~> 0.10"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.7"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "rspec", "~> 3.1.0"
28
+ spec.add_development_dependency "pry"
29
+ spec.add_development_dependency "highline"
30
+ end
31
+
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mooset::Endpoints::Gitlab do
4
+ let(:storage) { double(exists?: false) }
5
+ let(:connection) { double }
6
+ let(:command) { Mooset::Endpoints::Gitlab.new(:gitlab, connection: connection, storage: storage) }
7
+
8
+ describe '#write' do
9
+ let(:user) do
10
+ double({
11
+ email: 'email',
12
+ extern_uid: '1',
13
+ username: 'username',
14
+ provider: 'ldap',
15
+ })
16
+ end
17
+
18
+ it "calls the create user api" do
19
+ expect(connection).to receive(:create_user).with(user.email, anything,{
20
+ extern_uid: user.extern_uid,
21
+ username: user.username,
22
+ provider: 'ldap',
23
+ })
24
+
25
+ command.write(user)
26
+ end
27
+
28
+ context 'when the user is already imported' do
29
+ let(:storage) { double }
30
+
31
+ it "doesn't create duplicate users" do
32
+ expect(storage).to receive(:exists?).with(user).and_return(true)
33
+ expect(connection).not_to receive(:create_user)
34
+
35
+ command.write(user)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,20 @@
1
+ require "spec_helper"
2
+
3
+ describe Mooset::Endpoints::Ldap do
4
+ let(:bind_password) { double }
5
+ let(:bind_dn) { double }
6
+ let(:port) { double }
7
+ let(:host) { double }
8
+ let(:ldap) { Mooset::Endpoints::Ldap.new(:ldap, host: host, port: port, bind_dn: bind_dn, bind_password: bind_password) }
9
+
10
+ describe "#connection" do
11
+ subject(:connection) { ldap.connection }
12
+
13
+ it "creates a connection to the ldap server" do
14
+ expect(connection).to be_a(Net::LDAP)
15
+ expect(connection.host).to eq(host)
16
+ expect(connection.port).to eq(port)
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+
4
+ ROOT = Pathname(File.expand_path(File.join(File.dirname(__FILE__), '..')))
5
+ $LOAD_PATH << File.join(ROOT, 'lib')
6
+
7
+ require 'mooset'
metadata ADDED
@@ -0,0 +1,196 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mooset
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Alexandru Keszeg
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gitlab
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.3.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.3.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: virtus
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: net-ldap
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.10'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.10'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.7'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.7'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 3.1.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 3.1.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: highline
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Ruby library and client for user migration.
126
+ email:
127
+ - akeszeg@gmail.com
128
+ executables:
129
+ - mooset
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".gitignore"
134
+ - Gemfile
135
+ - LICENSE.txt
136
+ - README.md
137
+ - Rakefile
138
+ - bin/mooset
139
+ - config/sample
140
+ - lib/mooset.rb
141
+ - lib/mooset/application.rb
142
+ - lib/mooset/configuration.rb
143
+ - lib/mooset/endpoints.rb
144
+ - lib/mooset/endpoints/console_logger.rb
145
+ - lib/mooset/endpoints/endpoint.rb
146
+ - lib/mooset/endpoints/gitlab.rb
147
+ - lib/mooset/endpoints/gitlab/group.rb
148
+ - lib/mooset/endpoints/gitlab/group_search.rb
149
+ - lib/mooset/endpoints/gitlab/user.rb
150
+ - lib/mooset/endpoints/gitlab/user_search.rb
151
+ - lib/mooset/endpoints/ldap.rb
152
+ - lib/mooset/endpoints/ldap/group.rb
153
+ - lib/mooset/endpoints/ldap/group_search.rb
154
+ - lib/mooset/endpoints/ldap/user.rb
155
+ - lib/mooset/endpoints/ldap/user_search.rb
156
+ - lib/mooset/endpoints/null.rb
157
+ - lib/mooset/models/group.rb
158
+ - lib/mooset/models/user.rb
159
+ - lib/mooset/monads.rb
160
+ - lib/mooset/resource.rb
161
+ - lib/mooset/storage.rb
162
+ - lib/mooset/storage/memory.rb
163
+ - lib/mooset/synchronize_users.rb
164
+ - lib/mooset/version.rb
165
+ - mooset.gemspec
166
+ - spec/mooset/endpoints/gitlab_spec.rb
167
+ - spec/mooset/endpoints/ldap_spec.rb
168
+ - spec/spec_helper.rb
169
+ homepage: ''
170
+ licenses:
171
+ - MIT
172
+ metadata: {}
173
+ post_install_message:
174
+ rdoc_options: []
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ required_rubygems_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ requirements: []
188
+ rubyforge_project:
189
+ rubygems_version: 2.2.2
190
+ signing_key:
191
+ specification_version: 4
192
+ summary: A Ruby library and client for user migration.
193
+ test_files:
194
+ - spec/mooset/endpoints/gitlab_spec.rb
195
+ - spec/mooset/endpoints/ldap_spec.rb
196
+ - spec/spec_helper.rb