jpsclient 2.2.0 → 2.3.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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jpsclient/api/android_jks.rb +7 -70
  3. data/lib/jpsclient/api/app_level.rb +6 -60
  4. data/lib/jpsclient/api/app_resource.rb +7 -70
  5. data/lib/jpsclient/api/apple_account.rb +6 -60
  6. data/lib/jpsclient/api/apple_bundle_id.rb +1 -11
  7. data/lib/jpsclient/api/apple_cert.rb +1 -11
  8. data/lib/jpsclient/api/apple_profile.rb +1 -11
  9. data/lib/jpsclient/api/application.rb +12 -121
  10. data/lib/jpsclient/api/application_income.rb +2 -20
  11. data/lib/jpsclient/api/application_sales.rb +2 -20
  12. data/lib/jpsclient/api/application_version.rb +3 -30
  13. data/lib/jpsclient/api/archived_outdated/app_resource_version.rb +2 -20
  14. data/lib/jpsclient/api/archived_outdated/application_category.rb +5 -50
  15. data/lib/jpsclient/api/archived_outdated/application_design.rb +5 -50
  16. data/lib/jpsclient/api/archived_outdated/assets_category.rb +5 -50
  17. data/lib/jpsclient/api/archived_outdated/experience.rb +6 -60
  18. data/lib/jpsclient/api/archived_outdated/experience_category.rb +4 -40
  19. data/lib/jpsclient/api/archived_outdated/icon_and_snapshot.rb +2 -20
  20. data/lib/jpsclient/api/archived_outdated/publisher_category.rb +6 -60
  21. data/lib/jpsclient/api/archived_outdated/publisher_group_category.rb +5 -50
  22. data/lib/jpsclient/api/archived_outdated/requirements_category.rb +4 -40
  23. data/lib/jpsclient/api/archived_outdated/resource_category.rb +5 -50
  24. data/lib/jpsclient/api/archived_outdated/sketch_category.rb +4 -40
  25. data/lib/jpsclient/api/archived_outdated/survey_category.rb +4 -40
  26. data/lib/jpsclient/api/archived_outdated/tool_category.rb +5 -50
  27. data/lib/jpsclient/api/bug.rb +6 -60
  28. data/lib/jpsclient/api/category.rb +6 -60
  29. data/lib/jpsclient/api/cert.rb +1 -12
  30. data/lib/jpsclient/api/collect.rb +2 -20
  31. data/lib/jpsclient/api/collection.rb +7 -70
  32. data/lib/jpsclient/api/commit_log.rb +5 -52
  33. data/lib/jpsclient/api/creative.rb +2 -20
  34. data/lib/jpsclient/api/custom_application.rb +10 -100
  35. data/lib/jpsclient/api/custom_application_web.rb +2 -20
  36. data/lib/jpsclient/api/design.rb +5 -50
  37. data/lib/jpsclient/api/document_text.rb +1 -10
  38. data/lib/jpsclient/api/fgui_export.rb +2 -20
  39. data/lib/jpsclient/api/file.rb +4 -41
  40. data/lib/jpsclient/api/game_assets.rb +6 -60
  41. data/lib/jpsclient/api/healthy.rb +1 -10
  42. data/lib/jpsclient/api/idea.rb +5 -50
  43. data/lib/jpsclient/api/image_search.rb +2 -20
  44. data/lib/jpsclient/api/js_sdk.rb +1 -10
  45. data/lib/jpsclient/api/lark_bitable.rb +1 -10
  46. data/lib/jpsclient/api/lark_card_message.rb +1 -10
  47. data/lib/jpsclient/api/lark_chat_group.rb +1 -10
  48. data/lib/jpsclient/api/lark_comment.rb +5 -50
  49. data/lib/jpsclient/api/lark_department.rb +1 -10
  50. data/lib/jpsclient/api/lark_file.rb +1 -10
  51. data/lib/jpsclient/api/lark_leave_approval.rb +1 -10
  52. data/lib/jpsclient/api/lark_message.rb +1 -10
  53. data/lib/jpsclient/api/lark_task.rb +6 -60
  54. data/lib/jpsclient/api/lark_task_list.rb +5 -50
  55. data/lib/jpsclient/api/lark_task_section.rb +3 -30
  56. data/lib/jpsclient/api/lark_user.rb +1 -10
  57. data/lib/jpsclient/api/lark_wiki_node.rb +1 -10
  58. data/lib/jpsclient/api/lark_wiki_space.rb +1 -10
  59. data/lib/jpsclient/api/lazy_client.rb +39 -39
  60. data/lib/jpsclient/api/login.rb +4 -40
  61. data/lib/jpsclient/api/m3u8.rb +1 -10
  62. data/lib/jpsclient/api/menu.rb +6 -60
  63. data/lib/jpsclient/api/modular_client.rb +38 -38
  64. data/lib/jpsclient/api/nuget.rb +1 -10
  65. data/lib/jpsclient/api/permission.rb +5 -50
  66. data/lib/jpsclient/api/project.rb +2 -22
  67. data/lib/jpsclient/api/project_package.rb +9 -121
  68. data/lib/jpsclient/api/publisher.rb +7 -70
  69. data/lib/jpsclient/api/publisher_group.rb +5 -50
  70. data/lib/jpsclient/api/requirements.rb +6 -60
  71. data/lib/jpsclient/api/role.rb +7 -70
  72. data/lib/jpsclient/api/simple_search.rb +7 -70
  73. data/lib/jpsclient/api/sketch.rb +3 -30
  74. data/lib/jpsclient/api/sov.rb +1 -10
  75. data/lib/jpsclient/api/statistics.rb +1 -10
  76. data/lib/jpsclient/api/store.rb +1 -10
  77. data/lib/jpsclient/api/survey.rb +6 -60
  78. data/lib/jpsclient/api/tag.rb +6 -60
  79. data/lib/jpsclient/api/template.rb +5 -50
  80. data/lib/jpsclient/api/tool.rb +5 -50
  81. data/lib/jpsclient/api/trending.rb +1 -10
  82. data/lib/jpsclient/api/ud_id.rb +5 -50
  83. data/lib/jpsclient/api/user.rb +4 -40
  84. data/lib/jpsclient/api/util.rb +1 -10
  85. data/lib/jpsclient/api/video_cover.rb +1 -10
  86. data/lib/jpsclient/api/webhook.rb +5 -50
  87. data/lib/jpsclient/api/workflow.rb +5 -50
  88. data/lib/jpsclient/auth/auth.rb +21 -31
  89. data/lib/jpsclient/auth/token.rb +49 -95
  90. data/lib/jpsclient/base/client.rb +43 -38
  91. data/lib/jpsclient/http/http_client.rb +18 -2
  92. data/lib/jpsclient/version.rb +1 -1
  93. metadata +15 -1
@@ -14,16 +14,7 @@ module JPSClient
14
14
 
15
15
  path = config["url"]
16
16
 
17
- response = @http_client.post(path, body: params)
18
- result = JPSClient::Response.new(response)
19
-
20
- if result.need_login?
21
- do_login(force_login: true)
22
- response = @http_client.post(path, body: params)
23
- result = JPSClient::Response.new(response)
24
- end
25
-
26
- return result.to_h
17
+ return request_with_auth(:post, path, body: params)
27
18
  end
28
19
 
29
20
  # Create Sort
@@ -36,16 +27,7 @@ module JPSClient
36
27
 
37
28
  path = config["url"]
38
29
 
39
- response = @http_client.post(path, body: params)
40
- result = JPSClient::Response.new(response)
41
-
42
- if result.need_login?
43
- do_login(force_login: true)
44
- response = @http_client.post(path, body: params)
45
- result = JPSClient::Response.new(response)
46
- end
47
-
48
- return result.to_h
30
+ return request_with_auth(:post, path, body: params)
49
31
  end
50
32
 
51
33
  # Create Delete
@@ -58,16 +40,7 @@ module JPSClient
58
40
 
59
41
  path = config["url"]
60
42
 
61
- response = @http_client.post(path, body: params)
62
- result = JPSClient::Response.new(response)
63
-
64
- if result.need_login?
65
- do_login(force_login: true)
66
- response = @http_client.post(path, body: params)
67
- result = JPSClient::Response.new(response)
68
- end
69
-
70
- return result.to_h
43
+ return request_with_auth(:post, path, body: params)
71
44
  end
72
45
 
73
46
  # Create Create
@@ -80,16 +53,7 @@ module JPSClient
80
53
 
81
54
  path = config["url"]
82
55
 
83
- response = @http_client.post(path, body: params)
84
- result = JPSClient::Response.new(response)
85
-
86
- if result.need_login?
87
- do_login(force_login: true)
88
- response = @http_client.post(path, body: params)
89
- result = JPSClient::Response.new(response)
90
- end
91
-
92
- return result.to_h
56
+ return request_with_auth(:post, path, body: params)
93
57
  end
94
58
 
95
59
  # Get List
@@ -102,16 +66,7 @@ module JPSClient
102
66
 
103
67
  path = config["url"]
104
68
 
105
- response = @http_client.get(path, params: params)
106
- result = JPSClient::Response.new(response)
107
-
108
- if result.need_login?
109
- do_login(force_login: true)
110
- response = @http_client.get(path, params: params)
111
- result = JPSClient::Response.new(response)
112
- end
113
-
114
- return result.to_h
69
+ return request_with_auth(:get, path, params: params)
115
70
  end
116
71
 
117
72
  # 获取指定项目的工作流列表
@@ -18,8 +18,8 @@ module JPSClient
18
18
  # JPS 登录配置类
19
19
  class LoginConfig
20
20
  attr_accessor :client_id, :feishu_auth_url, :redirect_uri, :api_endpoint, :state, :server_port
21
- attr_accessor :aes_key, :token_verify_endpoint
22
- attr_accessor :token_dir, :token_file_name # 新增 token 存储路径配置
21
+ attr_accessor :aes_key
22
+ attr_accessor :token_dir, :token_file_name
23
23
 
24
24
  def initialize
25
25
  # 所有配置必须从外部配置文件加载,不提供硬编码的默认值
@@ -30,7 +30,6 @@ module JPSClient
30
30
  @state = 'client_login' # 仅此项可有默认值
31
31
  @server_port = 8898 # 仅此项可有默认值
32
32
  @aes_key = nil # AES 加密密钥,必需配置
33
- @token_verify_endpoint = nil # Token 验证端点,必需配置
34
33
  @token_dir = nil # Token 存储目录,可选配置
35
34
  @token_file_name = nil # Token 文件名,可选配置
36
35
  end
@@ -49,7 +48,6 @@ module JPSClient
49
48
  config.api_endpoint = data['api_endpoint'] if data['api_endpoint']
50
49
  config.state = data['state'] if data['state']
51
50
  config.server_port = data['server_port'] if data['server_port']
52
- config.token_verify_endpoint = data['token_verify_endpoint'] if data['token_verify_endpoint']
53
51
  config.aes_key = data['aes_key'] if data['aes_key']
54
52
  config.token_dir = data['token_dir'] if data['token_dir'] # 加载 token 目录配置
55
53
  config.token_file_name = data['token_file_name'] if data['token_file_name'] # 加载 token 文件名配置
@@ -65,7 +63,8 @@ module JPSClient
65
63
  end
66
64
 
67
65
  class Auth
68
- attr_reader :access_token, :username, :expires_at
66
+ attr_reader :access_token, :username
67
+ attr_reader :user_id, :permissions, :lark_user_id, :tenant_manager
69
68
 
70
69
  def initialize(config = nil)
71
70
  # 只接受 LoginConfig 对象或默认配置
@@ -103,7 +102,10 @@ module JPSClient
103
102
 
104
103
  @access_token = nil
105
104
  @username = nil
106
- @expires_at = nil
105
+ @user_id = nil
106
+ @permissions = nil
107
+ @lark_user_id = nil
108
+ @tenant_manager = false
107
109
 
108
110
  # 调试模式,通过环境变量控制
109
111
  @verbose = ENV['PINDO_DEBUG'] == 'true'
@@ -137,7 +139,10 @@ module JPSClient
137
139
  {
138
140
  'token' => @access_token,
139
141
  'username' => @username,
140
- 'expires_at' => @expires_at
142
+ 'user_id' => @user_id,
143
+ 'permissions' => @permissions,
144
+ 'lark_user_id' => @lark_user_id,
145
+ 'tenant_manager' => @tenant_manager
141
146
  }
142
147
  end
143
148
 
@@ -251,26 +256,6 @@ module JPSClient
251
256
  end
252
257
  end
253
258
 
254
- # 检查 token 是否有效
255
- def validate_token(token = nil)
256
- token_to_check = token || @access_token
257
- return false unless token_to_check
258
-
259
- # 检查过期时间
260
- if @expires_at && Time.now.to_i > @expires_at
261
- puts "Token 已过期,需要重新登录"
262
- return false
263
- end
264
-
265
- # 简单验证(实际项目中可以调用 API 验证)
266
- return true
267
- end
268
-
269
- # 验证Pgyer令牌(保留兼容性)
270
- def validate_pgyer_token(token = nil, expires_at = nil)
271
- validate_token(token)
272
- end
273
-
274
259
  # 使用授权码换取 token
275
260
  def exchange_code_for_token(code)
276
261
  begin
@@ -312,10 +297,13 @@ module JPSClient
312
297
 
313
298
  if result['meta'] && result['meta']['code'] == 0 && result['data']
314
299
  data = result['data']
300
+ # 兼容 snake_case 和 camelCase 两种响应格式
315
301
  @access_token = data['token'] if data['token']
316
302
  @username = data['username'] if data['username']
317
- # 设置过期时间为 6 天后
318
- @expires_at = Time.now.to_i + 6 * 24 * 60 * 60
303
+ @user_id = data['user_id'] || data['userId']
304
+ @permissions = data['permissions']
305
+ @lark_user_id = data['lark_user_id'] || data['larkUserId']
306
+ @tenant_manager = data['tenant_manager'] || data['tenantManager'] || false
319
307
 
320
308
  return true if @access_token
321
309
  else
@@ -452,8 +440,8 @@ module JPSClient
452
440
  end
453
441
  end
454
442
 
455
- # 捕获 Ctrl+C
456
- trap('INT') { server.shutdown }
443
+ # 捕获 Ctrl+C,结束后恢复默认行为
444
+ previous_trap = trap('INT') { server.shutdown }
457
445
 
458
446
  # 在线程中运行服务器,最多等待 3 分钟
459
447
  thread = Thread.new { server.start }
@@ -462,6 +450,8 @@ module JPSClient
462
450
  rescue => e
463
451
  puts "服务器等待超时"
464
452
  server.shutdown
453
+ ensure
454
+ trap('INT', previous_trap || 'DEFAULT')
465
455
  end
466
456
 
467
457
  code
@@ -2,17 +2,17 @@
2
2
 
3
3
  require 'json'
4
4
  require 'fileutils'
5
- require 'net/http'
6
- require 'uri'
7
5
  require 'jpsclient/utils/aes'
8
- require 'jpsclient/base/exception'
9
6
  require 'jpsclient/utils/logger'
10
7
 
11
8
  module JPSClient
12
9
 
13
10
  # Token 管理类
11
+ # 负责 token 的本地存储、加载和清除
12
+ # token 有效性由服务端 401 响应判断,本地不做过期检查
14
13
  class Token
15
- attr_reader :token, :username, :expires_at
14
+ attr_reader :token, :username
15
+ attr_reader :user_id, :permissions, :lark_user_id, :tenant_manager
16
16
 
17
17
  def initialize(config)
18
18
  @config = config
@@ -35,8 +35,10 @@ module JPSClient
35
35
  # token 数据
36
36
  @token = nil
37
37
  @username = nil
38
- @expires_at = nil
39
- @created_at = nil
38
+ @user_id = nil
39
+ @permissions = nil
40
+ @lark_user_id = nil
41
+ @tenant_manager = false
40
42
 
41
43
  # 调试模式
42
44
  @verbose = ENV['PINDO_DEBUG'] == 'true'
@@ -66,10 +68,19 @@ module JPSClient
66
68
 
67
69
  @token = token_data['token']
68
70
  @username = token_data['username']
69
- @expires_at = token_data['expires_at'].to_i if token_data['expires_at']
70
- @created_at = token_data['created_at'].to_i if token_data['created_at']
71
+ @user_id = token_data['user_id']
72
+ @permissions = token_data['permissions']
73
+ @lark_user_id = token_data['lark_user_id']
74
+ @tenant_manager = token_data.key?('tenant_manager') ? token_data['tenant_manager'] : false
75
+
76
+ # 旧版 token 文件缺少 user_id,视为无效,需重新登录获取完整字段
77
+ unless @token && @user_id
78
+ puts "Token 文件缺少必要字段,需要重新登录" if @verbose
79
+ clear
80
+ return false
81
+ end
71
82
 
72
- return true if @token
83
+ return true
73
84
  rescue => e
74
85
  puts "读取 token 失败: #{e.message}" if @verbose
75
86
  clear_corrupted_file
@@ -79,30 +90,35 @@ module JPSClient
79
90
  end
80
91
 
81
92
  # 保存 token
82
- def save(token, username, expires_at)
83
- return false unless token
93
+ # 传入完整数据 Hash
94
+ def save(token_data)
95
+ return false unless token_data.is_a?(Hash) && token_data['token']
84
96
 
85
- @token = token
86
- @username = username
87
- @expires_at = expires_at.to_i
88
- @created_at = Time.now.to_i
97
+ @token = token_data['token']
98
+ @username = token_data['username']
99
+ @user_id = token_data['user_id']
100
+ @permissions = token_data['permissions']
101
+ @lark_user_id = token_data['lark_user_id']
102
+ @tenant_manager = token_data.key?('tenant_manager') ? token_data['tenant_manager'] : false
89
103
 
90
104
  # 确保目录存在
91
105
  FileUtils.mkdir_p(@token_dir) unless Dir.exist?(@token_dir)
92
106
 
93
- token_data = {
107
+ save_data = {
94
108
  'token' => @token,
95
109
  'username' => @username,
96
- 'expires_at' => @expires_at,
97
- 'created_at' => @created_at
110
+ 'user_id' => @user_id,
111
+ 'permissions' => @permissions,
112
+ 'lark_user_id' => @lark_user_id,
113
+ 'tenant_manager' => @tenant_manager
98
114
  }
99
115
 
100
116
  # 根据是否有 AES 密钥决定加密方式
101
117
  content = if @aes_key
102
118
  aes = AES.new(@aes_key)
103
- aes.encrypt(token_data.to_json)
119
+ aes.encrypt(save_data.to_json)
104
120
  else
105
- token_data.to_json
121
+ save_data.to_json
106
122
  end
107
123
 
108
124
  File.write(@token_file, content)
@@ -114,106 +130,44 @@ module JPSClient
114
130
  false
115
131
  end
116
132
 
117
- # 验证 token 有效性
118
- def valid?
119
- return false unless @token
120
-
121
- # 1. 检查本地时间过期
122
- if expired?
123
- puts "Token 已过期 (本地时间检查)" if @verbose
124
- return false
125
- end
126
-
127
- # 2. 可选:API 验证
128
- # 为了避免频繁调用,只在接近过期时验证
129
- if should_verify_with_api?
130
- return verify_with_api
131
- end
132
-
133
- true
134
- end
135
-
136
- # 检查是否过期
137
- def expired?
138
- return true unless @expires_at
139
- Time.now.to_i > @expires_at
140
- end
141
-
142
- # API 验证 token
143
- def verify_with_api
144
- return false unless @token && @config
145
-
146
- begin
147
- # 使用配置中的验证端点
148
- base_url = @config.api_endpoint.split('/api/')[0] # 获取基础 URL
149
- verify_endpoint = @config.respond_to?(:token_verify_endpoint) ? @config.token_verify_endpoint : '/api/user/profile'
150
- uri = URI("#{base_url}#{verify_endpoint}")
151
-
152
- request = Net::HTTP::Get.new(uri)
153
- request['Authorization'] = "Bearer #{@token}"
154
-
155
- response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
156
- http.request(request)
157
- end
158
-
159
- if response.code == '200'
160
- puts "Token API 验证成功" if @verbose
161
- return true
162
- else
163
- puts "Token API 验证失败: #{response.code}" if @verbose
164
- return false
165
- end
166
- rescue => e
167
- puts "Token API 验证出错: #{e.message}" if @verbose
168
- # API 验证失败时,回退到本地验证
169
- return !expired?
170
- end
133
+ # token 是否已加载
134
+ def loaded?
135
+ !@token.nil? && !@token.empty?
171
136
  end
172
137
 
173
138
  # 清除 token
174
139
  def clear
175
140
  @token = nil
176
141
  @username = nil
177
- @expires_at = nil
178
- @created_at = nil
142
+ @user_id = nil
143
+ @permissions = nil
144
+ @lark_user_id = nil
145
+ @tenant_manager = false
179
146
 
180
147
  FileUtils.rm_f(@token_file) if File.exist?(@token_file)
181
148
  puts "✓ Token 已清除" if @verbose
182
149
  end
183
150
 
184
- # 转换为 Hash(兼容旧代码)
151
+ # 转换为 Hash
185
152
  def to_h
186
153
  return nil unless @token
187
154
 
188
155
  {
189
156
  'token' => @token,
190
157
  'username' => @username,
191
- 'expires_at' => @expires_at
158
+ 'user_id' => @user_id,
159
+ 'permissions' => @permissions,
160
+ 'lark_user_id' => @lark_user_id,
161
+ 'tenant_manager' => @tenant_manager
192
162
  }
193
163
  end
194
164
 
195
- # 从 Auth 实例更新 token
196
- def update_from_auth(auth)
197
- return false unless auth.access_token
198
-
199
- save(auth.access_token, auth.username, auth.expires_at)
200
- end
201
-
202
165
  private
203
166
 
204
- # 是否应该通过 API 验证
205
- def should_verify_with_api?
206
- return false unless @expires_at
207
-
208
- # 策略:最后 24 小时内进行 API 验证
209
- remaining_time = @expires_at - Time.now.to_i
210
- remaining_time > 0 && remaining_time < 24 * 60 * 60
211
- end
212
-
213
167
  # 清除损坏的文件
214
168
  def clear_corrupted_file
215
169
  FileUtils.rm_f(@token_file) if File.exist?(@token_file)
216
170
  puts "已清除损坏的 token 文件" if @verbose
217
171
  end
218
172
  end
219
- end
173
+ end
@@ -226,7 +226,7 @@ module JPSClient
226
226
  @token_manager = Token.new(@jps_config)
227
227
 
228
228
  # 尝试加载已保存的 token
229
- if @token_manager.load && @token_manager.valid?
229
+ if @token_manager.load && @token_manager.loaded?
230
230
  @token = @token_manager.to_h
231
231
  end
232
232
 
@@ -258,50 +258,55 @@ module JPSClient
258
258
  end
259
259
 
260
260
  # 核心登录功能
261
- def do_login(force_login:false)
262
- # 使用 token 管理器统一处理
261
+ # token 有效性由服务端 401 响应判断,本地不做过期检查
262
+ def do_login(force_login: false)
263
263
  if force_login
264
- # 强制重新登录
265
- @token_manager.clear # 清除旧 token
266
- auth = Auth.new(@jps_config)
267
- result = auth.login
268
-
269
- if result == :user_cancelled
270
- Logger.instance.fancyinfo_error("用户取消了登录操作")
271
- return false
272
- elsif result == true
273
- # 保存新 token
274
- @token_manager.save(auth.access_token, auth.username, auth.expires_at)
275
- update_token_everywhere()
264
+ @token_manager.clear
265
+ else
266
+ # 本地存在 token,直接使用
267
+ if @token_manager.load && @token_manager.loaded?
268
+ update_token_everywhere
276
269
  return true
277
- else
278
- Logger.instance.fancyinfo_error("登录失败,未能获取有效token")
279
- return false
280
270
  end
271
+ end
272
+
273
+ # 需要重新登录
274
+ auth = Auth.new(@jps_config)
275
+ result = auth.login
276
+
277
+ if result == :user_cancelled
278
+ Logger.instance.fancyinfo_error("用户取消了登录操作")
279
+ return false
280
+ elsif result == true
281
+ unless @token_manager.save(auth.get_token_data)
282
+ Logger.instance.fancyinfo_error("Token 保存失败,下次启动需要重新登录")
283
+ end
284
+ update_token_everywhere
285
+ return true
281
286
  else
282
- # 尝试加载并验证现有 token
283
- if @token_manager.load && @token_manager.valid?
284
- update_token_everywhere()
285
- return true
286
- else
287
- # Token 无效或不存在,需要重新登录
288
- auth = Auth.new(@jps_config)
289
- result = auth.login
287
+ Logger.instance.fancyinfo_error("登录失败,未能获取有效token")
288
+ return false
289
+ end
290
+ end
291
+
292
+ # 401 重试的统一请求方法
293
+ # 所有 API 模块应使用此方法发送请求
294
+ # @param method [Symbol] HTTP 方法 (:get, :post, :put, :delete)
295
+ # @param path [String] 请求路径
296
+ # @param opts [Hash] 传递给 http_client 的参数 (params:, body:, timeout: 等)
297
+ # @return [Hash] 响应数据
298
+ def request_with_auth(method, path, **opts)
299
+ response = @http_client.send(method, path, **opts)
300
+ result = JPSClient::Response.new(response)
290
301
 
291
- if result == :user_cancelled
292
- Logger.instance.fancyinfo_error("用户取消了登录操作")
293
- return false
294
- elsif result == true
295
- # 保存新 token
296
- @token_manager.save(auth.access_token, auth.username, auth.expires_at)
297
- update_token_everywhere()
298
- return true
299
- else
300
- Logger.instance.fancyinfo_error("登录失败,未能获取有效token")
301
- return false
302
- end
302
+ if result.need_login?
303
+ if do_login(force_login: true)
304
+ response = @http_client.send(method, path, **opts)
305
+ result = JPSClient::Response.new(response)
303
306
  end
304
307
  end
308
+
309
+ result.to_h
305
310
  end
306
311
 
307
312
  private
@@ -101,6 +101,16 @@ module JPSClient
101
101
  request(:post, path, body: body, timeout: timeout)
102
102
  end
103
103
 
104
+ # PUT 请求
105
+ def put(path, body: nil, timeout: nil)
106
+ request(:put, path, body: body, timeout: timeout)
107
+ end
108
+
109
+ # DELETE 请求
110
+ def delete(path, params: nil, timeout: nil)
111
+ request(:delete, path, params: params, timeout: timeout)
112
+ end
113
+
104
114
  # 更新 token
105
115
  def update_token(new_token)
106
116
  @token = new_token
@@ -128,7 +138,7 @@ module JPSClient
128
138
  req.headers['Content-Type'] = 'application/json'
129
139
  req.headers['token'] = @token if @token
130
140
  req.params = params if params
131
- req.body = body.to_json if body && method == :post
141
+ req.body = body.to_json if body && [:post, :put, :patch].include?(method)
132
142
  req.options.timeout = actual_timeout if actual_timeout
133
143
  end
134
144
 
@@ -243,8 +253,14 @@ module JPSClient
243
253
  @success && (@code.to_s == '0' || @code.to_s == '200')
244
254
  end
245
255
 
256
+ # 20001: 登录token失效
246
257
  def need_login?
247
- @need_login || @code.to_s == '401'
258
+ @need_login || @code.to_s == '20001'
259
+ end
260
+
261
+ # 20011: 没有权限访问项目
262
+ def no_permission?
263
+ @code.to_s == '20011'
248
264
  end
249
265
 
250
266
  def to_h
@@ -1,3 +1,3 @@
1
1
  module JPSClient
2
- VERSION = '2.2.0'
2
+ VERSION = '2.3.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jpsclient
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Your Name
@@ -79,6 +79,20 @@ dependencies:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0.2'
82
+ - !ruby/object:Gem::Dependency
83
+ name: logger
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
82
96
  - !ruby/object:Gem::Dependency
83
97
  name: bundler
84
98
  requirement: !ruby/object:Gem::Requirement