synrp 0.16.4
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/Gemfile +4 -0
- data/Gemfile.lock +18 -0
- data/Rakefile +1 -0
- data/bin/synrp +18 -0
- data/lib/synrp/cli.rb +190 -0
- data/lib/synrp/synrp.rb +131 -0
- data/lib/synrp/version.rb +3 -0
- data/lib/synrp.rb +19 -0
- data/synrp.gemspec +25 -0
- metadata +106 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/synrp
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Try loading bundler if it's possible
|
4
|
+
begin
|
5
|
+
require 'rubygems'
|
6
|
+
require 'bundler/setup'
|
7
|
+
rescue LoadError
|
8
|
+
# no problem
|
9
|
+
end
|
10
|
+
|
11
|
+
# Add lib to load path
|
12
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
|
13
|
+
|
14
|
+
require 'synrp'
|
15
|
+
require 'synrp/cli'
|
16
|
+
|
17
|
+
Synrp::CLI.run(ARGV)
|
18
|
+
|
data/lib/synrp/cli.rb
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'cri'
|
2
|
+
|
3
|
+
module Synrp::CLI
|
4
|
+
|
5
|
+
synRP = Synrp::SynRP.new
|
6
|
+
|
7
|
+
@cmd = Cri::Command.define do
|
8
|
+
name 'rpt'
|
9
|
+
usage 'rpt [options] [command] [options]'
|
10
|
+
summary 'to access ressourceplanning via commandline'
|
11
|
+
description <<-DESC
|
12
|
+
For --site, --username and --passwort parameters you can
|
13
|
+
also use a yaml config file.
|
14
|
+
|
15
|
+
To do so, just
|
16
|
+
|
17
|
+
cp config.yaml.sample ~/.synRP_config.yaml
|
18
|
+
|
19
|
+
DESC
|
20
|
+
|
21
|
+
flag :h, :help, 'show help for this command' do |value, cmd|
|
22
|
+
puts @cmd.help
|
23
|
+
exit 0
|
24
|
+
end
|
25
|
+
|
26
|
+
required :s, :site, 'domain name of respt system (without http://)'
|
27
|
+
required :u, :username, 'username at given site'
|
28
|
+
required :p, :password, 'password at given site'
|
29
|
+
end
|
30
|
+
|
31
|
+
@cmd.add_command Cri::Command.new_basic_help
|
32
|
+
|
33
|
+
@cmd.define_command do
|
34
|
+
name 'req'
|
35
|
+
aliases :request, :allocation_request
|
36
|
+
usage 'req [options]'
|
37
|
+
summary 'requests ressources'
|
38
|
+
|
39
|
+
required :k, :kw, 'yyyy-Wn (e. g. 2012-W6)'
|
40
|
+
required :P, :project, 'project id or name'
|
41
|
+
required :e, :person, 'person id or display name (find id via "persons")'
|
42
|
+
required :m, :minutes, 'request time in minutes'
|
43
|
+
required :c, :comment, 'comment to the request'
|
44
|
+
|
45
|
+
run do |opts, args|
|
46
|
+
|
47
|
+
synRP.verify_opts_present(opts, [ :site, :username, :password, :kw, :project, :person, :minutes ])
|
48
|
+
|
49
|
+
synRP.connect(opts[:site], opts[:username], opts[:password])
|
50
|
+
|
51
|
+
project_id = synRP.find_project_id_by_project_name(opts[:project]) || opts[:project]
|
52
|
+
person_id = synRP.find_person_id_by_displayname(opts[:person]) || opts[:person]
|
53
|
+
|
54
|
+
synRP.request_res(opts[:kw], project_id, person_id, opts[:minutes], opts[:comment])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
@cmd.define_command do
|
59
|
+
name 'availabilities'
|
60
|
+
usage 'availabilities [options]'
|
61
|
+
summary 'check who is available in given week'
|
62
|
+
|
63
|
+
required :k, :kw, 'yyyy-Wn (e. g. 2012-W6)'
|
64
|
+
|
65
|
+
run do |opts, args|
|
66
|
+
|
67
|
+
synRP.verify_opts_present(opts, [ :site, :username, :password, :kw ])
|
68
|
+
|
69
|
+
synRP.connect(opts[:site], opts[:username], opts[:password])
|
70
|
+
|
71
|
+
puts JSON.pretty_generate synRP.get_availabilities_persons(opts[:kw])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
@cmd.define_command do
|
76
|
+
name 'allocation_requests'
|
77
|
+
usage 'allocation_requests [options]'
|
78
|
+
summary 'get all allocation requests of a given week'
|
79
|
+
|
80
|
+
required :k, :kw, 'yyyy-Wn (e. g. 2012-W6)'
|
81
|
+
|
82
|
+
run do |opts, args|
|
83
|
+
|
84
|
+
synRP.verify_opts_present(opts, [ :site, :username, :password, :kw ])
|
85
|
+
|
86
|
+
synRP.connect(opts[:site], opts[:username], opts[:password])
|
87
|
+
|
88
|
+
puts JSON.pretty_generate synRP.get_allocation_requests(opts[:kw])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
@cmd.define_command do
|
93
|
+
name 'remaining_availabilities'
|
94
|
+
usage 'remaining_availabilities [options]'
|
95
|
+
summary 'remaining_availabilities of a given week'
|
96
|
+
|
97
|
+
required :k, :kw, 'yyyy-Wn (e. g. 2012-W6)'
|
98
|
+
|
99
|
+
run do |opts, args|
|
100
|
+
|
101
|
+
synRP.verify_opts_present(opts, [ :site, :username, :password, :kw ])
|
102
|
+
|
103
|
+
synRP.connect(opts[:site], opts[:username], opts[:password])
|
104
|
+
|
105
|
+
puts JSON.pretty_generate synRP.calculate_remaining_availabilities(opts[:kw])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
@cmd.define_command do
|
110
|
+
name 'reqs_of_person'
|
111
|
+
usage 'reqs_of_person [options]'
|
112
|
+
summary 'get all allocation requests of a given week of a person'
|
113
|
+
|
114
|
+
required :k, :kw, 'yyyy-Wn (e. g. 2012-W6)'
|
115
|
+
required :e, :person, 'person id or display name (find id via "persons")'
|
116
|
+
|
117
|
+
run do |opts, args|
|
118
|
+
|
119
|
+
synRP.verify_opts_present(opts, [ :site, :username, :password, :kw, :person ])
|
120
|
+
|
121
|
+
synRP.connect(opts[:site], opts[:username], opts[:password])
|
122
|
+
|
123
|
+
person_id = synRP.find_person_id_by_displayname(opts[:person]) || opts[:person]
|
124
|
+
|
125
|
+
puts JSON.pretty_generate synRP.get_allocation_requests_of_person(opts[:kw], person_id)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
@cmd.define_command do
|
130
|
+
name 'req_all_meta'
|
131
|
+
usage 'req_all_meta [options]'
|
132
|
+
summary 'request meta ressources for all available employees'
|
133
|
+
|
134
|
+
required :k, :kw, 'yyyy-Wn (e. g. 2012-W6)'
|
135
|
+
|
136
|
+
run do |opts, args|
|
137
|
+
|
138
|
+
synRP.verify_opts_present(opts, [ :site, :username, :password, :kw ])
|
139
|
+
|
140
|
+
synRP.connect(opts[:site], opts[:username], opts[:password])
|
141
|
+
|
142
|
+
project_id = synRP.find_project_id_by_project_name("Meta")
|
143
|
+
|
144
|
+
all_persons = synRP.get_persons
|
145
|
+
|
146
|
+
synRP.get_availabilities(opts[:kw]).each do |person_id, minutes|
|
147
|
+
person = all_persons.find {|p| p["id"] == person_id.to_i }
|
148
|
+
if minutes > 0 && person["visible"]
|
149
|
+
synRP.request_res(opts[:kw], project_id, person_id, 120, 'Default Meta')
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
@cmd.define_command do
|
156
|
+
name 'persons'
|
157
|
+
usage 'persons [options]'
|
158
|
+
summary 'get all persons as json'
|
159
|
+
|
160
|
+
run do |opts, args|
|
161
|
+
|
162
|
+
synRP.verify_opts_present(opts, [ :site, :username, :password ])
|
163
|
+
|
164
|
+
synRP.connect(opts[:site], opts[:username], opts[:password])
|
165
|
+
|
166
|
+
puts JSON.pretty_generate synRP.get_persons
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
@cmd.define_command do
|
171
|
+
name 'projects'
|
172
|
+
usage 'projects [options]'
|
173
|
+
summary 'get all projects as json'
|
174
|
+
|
175
|
+
run do |opts, args|
|
176
|
+
|
177
|
+
synRP.verify_opts_present(opts, [ :site, :username, :password ])
|
178
|
+
|
179
|
+
synRP.connect(opts[:site], opts[:username], opts[:password])
|
180
|
+
|
181
|
+
puts JSON.pretty_generate synRP.get_projects
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def self.run(args)
|
186
|
+
@cmd.run(ARGV)
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
data/lib/synrp/synrp.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Library to use SynRP REST API
|
4
|
+
#
|
5
|
+
# Author
|
6
|
+
#
|
7
|
+
# Fabian Buch
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'net/http'
|
11
|
+
require 'json'
|
12
|
+
require 'yaml'
|
13
|
+
|
14
|
+
module Synrp
|
15
|
+
class SynRP
|
16
|
+
|
17
|
+
def setup(opts)
|
18
|
+
opts = verify_opts_present(opts, [ :site, :username, :password ])
|
19
|
+
end
|
20
|
+
|
21
|
+
def verify_opts_present(opts, req_opts)
|
22
|
+
config_opts = read_config
|
23
|
+
req_opts.each do |r_opt|
|
24
|
+
unless opts[r_opt]
|
25
|
+
if config_opts[r_opt.to_s]
|
26
|
+
opts[r_opt] = config_opts[r_opt.to_s]
|
27
|
+
else
|
28
|
+
$stderr.puts "--#{r_opt} option is required"
|
29
|
+
exit 1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
opts
|
34
|
+
end
|
35
|
+
|
36
|
+
def read_config
|
37
|
+
begin
|
38
|
+
return YAML.load_file(File.expand_path("~/.synRP_config.yaml"))
|
39
|
+
rescue
|
40
|
+
begin
|
41
|
+
current_dir = File.dirname(File.expand_path(__FILE__))
|
42
|
+
return YAML.load_file(current_dir + "/config.yaml")
|
43
|
+
rescue
|
44
|
+
end
|
45
|
+
end
|
46
|
+
return {}
|
47
|
+
end
|
48
|
+
|
49
|
+
def connect(site, username, password)
|
50
|
+
$conn = Net::HTTP.new(site, 80)
|
51
|
+
resp, data = $conn.post("/web/j_spring_security_check", "j_username=#{username}&j_password=#{password}", {})
|
52
|
+
cookie = resp.response['set-cookie']
|
53
|
+
$headers = { "Cookie" => cookie }
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_persons
|
57
|
+
resp, data = $conn.get("/web/persons.json", $headers)
|
58
|
+
JSON.parse data
|
59
|
+
end
|
60
|
+
|
61
|
+
def find_project_id_by_project_name(pname)
|
62
|
+
project = get_projects.find {|p| p["name"] == pname }
|
63
|
+
project_id = project ? project["id"] : nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def find_person_id_by_displayname(person_name)
|
67
|
+
person = get_persons.find { |p|
|
68
|
+
# replace weird whitespace with new one before comparing
|
69
|
+
p["displayName"].gsub(/\302\240/, ' ').match(person_name)
|
70
|
+
}
|
71
|
+
person_id = person ? person["id"] : nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def find_person_by_id(id)
|
75
|
+
get_persons.find {|p| p["id"].to_s == id.to_s }
|
76
|
+
end
|
77
|
+
|
78
|
+
def get_projects
|
79
|
+
resp, data = $conn.get("/web/projects.json", $headers)
|
80
|
+
JSON.parse data
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_availabilities(yearWeek)
|
84
|
+
resp, data = $conn.get("/web/availabilities.json?yearWeek=#{yearWeek}", $headers)
|
85
|
+
av = JSON.parse data
|
86
|
+
without_invisible = av.reject { |k,v| !find_person_by_id(k)["visible"] }
|
87
|
+
end
|
88
|
+
|
89
|
+
# get availabilities with resolved person, not their IDs
|
90
|
+
def get_availabilities_persons(yearWeek)
|
91
|
+
avails = get_availabilities(yearWeek)
|
92
|
+
avails.map { |k,v| { find_person_by_id(k)["displayName"], "#{v / 60.0} h" } }.inject(&:merge)
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_allocation_requests(yearWeek)
|
96
|
+
resp, data = $conn.get("/web/allocation-requests.json?yearWeek=#{yearWeek}", $headers)
|
97
|
+
JSON.parse data
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_allocation_requests_of_person(yearWeek, person_id)
|
101
|
+
reqs = get_allocation_requests(yearWeek)
|
102
|
+
reqs.find_all { |req| req["person"]["id"].to_s == person_id.to_s }
|
103
|
+
end
|
104
|
+
|
105
|
+
def calculate_remaining_availabilities(yearWeek)
|
106
|
+
avails = get_availabilities(yearWeek)
|
107
|
+
avails_minus_requests = avails.map do |person_id, minutes|
|
108
|
+
person = find_person_by_id(person_id)
|
109
|
+
reqs_of_person = get_allocation_requests_of_person(yearWeek, person_id)
|
110
|
+
remaining_minutes = minutes - sum_minutes_of_requests(reqs_of_person)
|
111
|
+
{ person, remaining_minutes }
|
112
|
+
end.inject(&:merge)
|
113
|
+
avails_minus_requests.to_a.sort_by { |av| -av[1] }
|
114
|
+
end
|
115
|
+
|
116
|
+
def sum_minutes_of_requests(reqs)
|
117
|
+
sum = 0
|
118
|
+
reqs.each do |req|
|
119
|
+
sum += req["minutes"]
|
120
|
+
end
|
121
|
+
sum
|
122
|
+
end
|
123
|
+
|
124
|
+
def request_res(yearWeek, project, person, minutes, comment='')
|
125
|
+
puts "Requesting yearWeek=#{yearWeek}&project=#{project}&person=#{person}&minutes=#{minutes}&comment=#{comment}"
|
126
|
+
$conn.post("/web/allocation-requests/", "yearWeek=#{yearWeek}&project=#{project}&person=#{person}&minutes=#{minutes}&comment=#{comment}", $headers)
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
data/lib/synrp.rb
ADDED
data/synrp.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "synrp/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "synrp"
|
7
|
+
s.version = Synrp::VERSION
|
8
|
+
s.authors = ["Fabian Buch"]
|
9
|
+
s.email = ["buch@synyx.de"]
|
10
|
+
s.homepage = "https://github.com/Synyx/synRP"
|
11
|
+
s.summary = %q{Commandline Client for Synyx Resource Planner (synRP)}
|
12
|
+
s.description = %q{The synyx Resource Planner is a web application for managing work assignments. See https://github.com/Synyx/synRP for more information. This is a commandline client that uses its REST service.}
|
13
|
+
|
14
|
+
s.files = Dir['[A-Z]*'] + Dir['{bin,lib,tasks,test}/**/*'] + [ 'synrp.gemspec' ]
|
15
|
+
s.executables = [ 'synrp' ]
|
16
|
+
s.require_paths = [ 'lib' ]
|
17
|
+
|
18
|
+
s.add_runtime_dependency "cri", '~> 2.2'
|
19
|
+
s.add_runtime_dependency "json"
|
20
|
+
|
21
|
+
s.post_install_message = %q{------------------------------------------------------------------------------
|
22
|
+
run "synrp help" for usage information
|
23
|
+
------------------------------------------------------------------------------
|
24
|
+
}
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: synrp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 87
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 16
|
9
|
+
- 4
|
10
|
+
version: 0.16.4
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Fabian Buch
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-04-11 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: cri
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 7
|
29
|
+
segments:
|
30
|
+
- 2
|
31
|
+
- 2
|
32
|
+
version: "2.2"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: json
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
description: The synyx Resource Planner is a web application for managing work assignments. See https://github.com/Synyx/synRP for more information. This is a commandline client that uses its REST service.
|
50
|
+
email:
|
51
|
+
- buch@synyx.de
|
52
|
+
executables:
|
53
|
+
- synrp
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files: []
|
57
|
+
|
58
|
+
files:
|
59
|
+
- Gemfile.lock
|
60
|
+
- Gemfile
|
61
|
+
- Rakefile
|
62
|
+
- bin/synrp
|
63
|
+
- lib/synrp.rb
|
64
|
+
- lib/synrp/cli.rb
|
65
|
+
- lib/synrp/synrp.rb
|
66
|
+
- lib/synrp/version.rb
|
67
|
+
- synrp.gemspec
|
68
|
+
homepage: https://github.com/Synyx/synRP
|
69
|
+
licenses: []
|
70
|
+
|
71
|
+
post_install_message: |
|
72
|
+
------------------------------------------------------------------------------
|
73
|
+
run "synrp help" for usage information
|
74
|
+
------------------------------------------------------------------------------
|
75
|
+
|
76
|
+
rdoc_options: []
|
77
|
+
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
hash: 3
|
95
|
+
segments:
|
96
|
+
- 0
|
97
|
+
version: "0"
|
98
|
+
requirements: []
|
99
|
+
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 1.8.10
|
102
|
+
signing_key:
|
103
|
+
specification_version: 3
|
104
|
+
summary: Commandline Client for Synyx Resource Planner (synRP)
|
105
|
+
test_files: []
|
106
|
+
|