| 1 | #!/usr/bin/env ruby |
|---|
| 2 | # cybozu_client.rb - cybozu client interface |
|---|
| 3 | # |
|---|
| 4 | # Author: MIZOGUCHI Coji <mizoguchi.coji at gmail.com> |
|---|
| 5 | # |
|---|
| 6 | # $Id$ |
|---|
| 7 | # |
|---|
| 8 | require 'kconv' |
|---|
| 9 | require 'uri' |
|---|
| 10 | require 'net/http' |
|---|
| 11 | require 'csv' |
|---|
| 12 | |
|---|
| 13 | Net::HTTP.version_1_2 |
|---|
| 14 | |
|---|
| 15 | # ユーザ |
|---|
| 16 | class CybozuUser |
|---|
| 17 | attr_reader :user_id, :name |
|---|
| 18 | |
|---|
| 19 | def initialize(user_id, name) |
|---|
| 20 | @user_id = user_id |
|---|
| 21 | @name = name |
|---|
| 22 | end |
|---|
| 23 | |
|---|
| 24 | def hash |
|---|
| 25 | @user_id |
|---|
| 26 | end |
|---|
| 27 | |
|---|
| 28 | def eql?(obj) |
|---|
| 29 | obj.user_id == @user_id |
|---|
| 30 | end |
|---|
| 31 | end |
|---|
| 32 | |
|---|
| 33 | # グループ |
|---|
| 34 | class CybozuGroup |
|---|
| 35 | attr_reader :group_id, :name, :members |
|---|
| 36 | |
|---|
| 37 | def initialize(group_id, name, members = nil) |
|---|
| 38 | @group_id = group_id |
|---|
| 39 | @name = name |
|---|
| 40 | @members = members |
|---|
| 41 | end |
|---|
| 42 | |
|---|
| 43 | def hash |
|---|
| 44 | @group_id |
|---|
| 45 | end |
|---|
| 46 | |
|---|
| 47 | def eql?(obj) |
|---|
| 48 | obj.group_id == @group_id |
|---|
| 49 | end |
|---|
| 50 | end |
|---|
| 51 | |
|---|
| 52 | # クライアント |
|---|
| 53 | class CybozuClient |
|---|
| 54 | attr_reader :server_uri |
|---|
| 55 | attr_reader :cookie |
|---|
| 56 | |
|---|
| 57 | public |
|---|
| 58 | # コンストラクタ |
|---|
| 59 | def initialize(server_uri) |
|---|
| 60 | @server_uri = URI.parse(server_uri) |
|---|
| 61 | @cookie = nil |
|---|
| 62 | end |
|---|
| 63 | |
|---|
| 64 | # ログイン |
|---|
| 65 | def login(user_id, password) |
|---|
| 66 | params = { |
|---|
| 67 | '_System' => 'login', |
|---|
| 68 | '_Login' => '1', |
|---|
| 69 | '_ID' => user_id, |
|---|
| 70 | 'Password' => password, |
|---|
| 71 | } |
|---|
| 72 | |
|---|
| 73 | web = Net::HTTP.new(@server_uri.host) |
|---|
| 74 | res = web.post(@server_uri.request_uri, CybozuClient.build_params(params)) |
|---|
| 75 | @cookie = parse_cookies(res.get_fields('set-cookie')) |
|---|
| 76 | |
|---|
| 77 | if @cookie.nil? |
|---|
| 78 | return false |
|---|
| 79 | end |
|---|
| 80 | |
|---|
| 81 | begin |
|---|
| 82 | yield |
|---|
| 83 | logout |
|---|
| 84 | rescue LocalJumpError => evar |
|---|
| 85 | ensure |
|---|
| 86 | end |
|---|
| 87 | |
|---|
| 88 | return true |
|---|
| 89 | end |
|---|
| 90 | |
|---|
| 91 | # ログアウト |
|---|
| 92 | def logout |
|---|
| 93 | @cookie = nil |
|---|
| 94 | end |
|---|
| 95 | |
|---|
| 96 | def login? |
|---|
| 97 | return !@cookie.nil? |
|---|
| 98 | end |
|---|
| 99 | |
|---|
| 100 | def get_session_id |
|---|
| 101 | if @cookie.nil? |
|---|
| 102 | nil |
|---|
| 103 | else |
|---|
| 104 | @cookie['Login'] |
|---|
| 105 | end |
|---|
| 106 | end |
|---|
| 107 | |
|---|
| 108 | def set_session_id(session_id) |
|---|
| 109 | @cookie = Hash.new |
|---|
| 110 | @cookie['Login'] = session_id.dup |
|---|
| 111 | end |
|---|
| 112 | |
|---|
| 113 | # グループリスト |
|---|
| 114 | def get_group_list() |
|---|
| 115 | groups = Array.new |
|---|
| 116 | p request('ExternalAPIGroupsList') |
|---|
| 117 | csv = CSV.parse(CybozuClient.real_request(@server_uri, 'ExternalAPIGroupsList')) |
|---|
| 118 | csv.each do |line| |
|---|
| 119 | groups.push CybozuGroup.new(line[1].to_i, line[2], line[3..-1].collect{|elem| elem.to_i}) |
|---|
| 120 | end |
|---|
| 121 | |
|---|
| 122 | groups |
|---|
| 123 | end |
|---|
| 124 | |
|---|
| 125 | # ユーザリスト |
|---|
| 126 | def get_user_list() |
|---|
| 127 | users = Array.new |
|---|
| 128 | csv = CSV.parse(request('ExternalAPIGroupsList')) |
|---|
| 129 | csv.each do |line| |
|---|
| 130 | users.push CybozuUser.new(line[1].to_i, line[2], line[3..-1].collect{|elem| elem.to_i}) |
|---|
| 131 | end |
|---|
| 132 | |
|---|
| 133 | users |
|---|
| 134 | end |
|---|
| 135 | |
|---|
| 136 | # スケジュールデータ取得 |
|---|
| 137 | def get_schedule() |
|---|
| 138 | if @cookie.nil? |
|---|
| 139 | return |
|---|
| 140 | end |
|---|
| 141 | return CSV.parse(request('ExternalAPISchedule').toutf8) |
|---|
| 142 | end |
|---|
| 143 | |
|---|
| 144 | # システム情報取得 |
|---|
| 145 | def get_system_info() |
|---|
| 146 | if @cookie.nil? |
|---|
| 147 | return |
|---|
| 148 | end |
|---|
| 149 | return CSV.parse(request('ExternalAPISystemInfo').toutf8) |
|---|
| 150 | end |
|---|
| 151 | |
|---|
| 152 | # 移動先情報取得 |
|---|
| 153 | def get_where() |
|---|
| 154 | if @cookie.nil? |
|---|
| 155 | return |
|---|
| 156 | end |
|---|
| 157 | return CSV.parse(request('ExternalAPIWhere').toutf8) |
|---|
| 158 | end |
|---|
| 159 | |
|---|
| 160 | # タイムカード取得 |
|---|
| 161 | def get_timecard(date_start, date_end) |
|---|
| 162 | params = { |
|---|
| 163 | 'Page' => 'PersonalTimeCardEx', |
|---|
| 164 | 'uid' => @cookie['User'], |
|---|
| 165 | 'SetDate.Year' => 2006, |
|---|
| 166 | 'SetDate.Month' => 5, |
|---|
| 167 | 'SetDate.Day' => 1, |
|---|
| 168 | 'EndDate.Year' => 2006, |
|---|
| 169 | 'EndDate.Month' => 5, |
|---|
| 170 | 'EndDate.Day' => 31, |
|---|
| 171 | } |
|---|
| 172 | end |
|---|
| 173 | |
|---|
| 174 | private |
|---|
| 175 | # リクエスト |
|---|
| 176 | def request(func, request_params=nil) |
|---|
| 177 | CybozuClient.real_request(@server_uri, func, request_params, @cookie) |
|---|
| 178 | end |
|---|
| 179 | |
|---|
| 180 | def self.real_request(server_uri, func, request_params = nil, cookie = nil) |
|---|
| 181 | params = request_params.dup unless request_params.nil? |
|---|
| 182 | params ||= Hash.new |
|---|
| 183 | params['page'] = func |
|---|
| 184 | |
|---|
| 185 | headers = CybozuClient.build_params(cookie, ';') unless cookie.nil? |
|---|
| 186 | |
|---|
| 187 | uri = server_uri.dup |
|---|
| 188 | uri.query = CybozuClient.build_params(params) |
|---|
| 189 | |
|---|
| 190 | |
|---|
| 191 | res = Net::HTTP.get(uri.host, uri.request_uri, headers) |
|---|
| 192 | |
|---|
| 193 | res.body[0..res.body.index('<font size=')-1].dup.untaint |
|---|
| 194 | end |
|---|
| 195 | |
|---|
| 196 | # パラメータ文字列の生成 |
|---|
| 197 | def self.build_params(params, param_separator = '&') |
|---|
| 198 | ret = '' |
|---|
| 199 | params.each_pair do |key,value| |
|---|
| 200 | unless ret == '' |
|---|
| 201 | ret.concat param_separator |
|---|
| 202 | end |
|---|
| 203 | ret.concat "#{key}=#{value}" |
|---|
| 204 | end |
|---|
| 205 | ret |
|---|
| 206 | end |
|---|
| 207 | |
|---|
| 208 | # set-cookieの解析 |
|---|
| 209 | def parse_cookies(cookies) |
|---|
| 210 | if cookies.nil? |
|---|
| 211 | return nil |
|---|
| 212 | end |
|---|
| 213 | |
|---|
| 214 | # cookies are array |
|---|
| 215 | ret = {} |
|---|
| 216 | cookies.each do |c| |
|---|
| 217 | cookie_elem = c.split(/;/) |
|---|
| 218 | key,value = cookie_elem[0].split(/=/) |
|---|
| 219 | ret[key] = value |
|---|
| 220 | end |
|---|
| 221 | ret |
|---|
| 222 | end |
|---|
| 223 | end |
|---|
| 224 | |
|---|
| 225 | # テスト |
|---|
| 226 | if __FILE__ == $0 |
|---|
| 227 | server_uri = 'http://cybozu.example.com/cgi-bin/ag.cgi' |
|---|
| 228 | if ARGV.length < 2 |
|---|
| 229 | puts "usage: cybozu_client.rb <user_id> <password>" |
|---|
| 230 | exit |
|---|
| 231 | else |
|---|
| 232 | user_id = ARGV[0].to_i |
|---|
| 233 | password = ARGV[1] |
|---|
| 234 | end |
|---|
| 235 | |
|---|
| 236 | client = CybozuClient.new(server_uri) |
|---|
| 237 | |
|---|
| 238 | begin |
|---|
| 239 | client.login(user_id, password) do |
|---|
| 240 | client.get_group_list().each do |elem| |
|---|
| 241 | puts "#{elem.group_id}\t#{elem.name}\t#{elem.members.join(',')}" |
|---|
| 242 | end |
|---|
| 243 | puts client.get_system_info() |
|---|
| 244 | puts |
|---|
| 245 | puts client.get_where() |
|---|
| 246 | puts |
|---|
| 247 | puts client.get_schedule() |
|---|
| 248 | end |
|---|
| 249 | rescue =>e |
|---|
| 250 | puts "Login failure: #{e}" |
|---|
| 251 | end |
|---|
| 252 | end |
|---|