@josephyan/qingflow-cli 0.2.0-beta.69 → 0.2.0-beta.71

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.
@@ -139,21 +139,28 @@ class WorkspaceTools(ToolBase):
139
139
  qf_version=workspace_qf_version,
140
140
  qf_version_source="workspace_system_version",
141
141
  )
142
+ active_context = BackendRequestContext(
143
+ base_url=session_profile.base_url,
144
+ token=context.token,
145
+ ws_id=session_profile.selected_ws_id,
146
+ qf_version=session_profile.qf_version,
147
+ qf_version_source=session_profile.qf_version_source,
148
+ )
149
+ workspace_version = self._workspace_version_summary(
150
+ self._fetch_workspace_account_info(active_context),
151
+ workspace_base_info=self._fetch_workspace_base_info(active_context),
152
+ workspace_detail=result,
153
+ )
142
154
  return {
143
155
  "profile": profile,
144
156
  "selected_ws_id": session_profile.selected_ws_id,
145
157
  "selected_ws_name": session_profile.selected_ws_name,
146
158
  "workspace": result,
159
+ "workspace_version": workspace_version,
147
160
  "qf_version": session_profile.qf_version,
148
161
  "qf_version_source": session_profile.qf_version_source,
149
162
  "request_route": self.backend.describe_route(
150
- BackendRequestContext(
151
- base_url=session_profile.base_url,
152
- token=context.token,
153
- ws_id=session_profile.selected_ws_id,
154
- qf_version=session_profile.qf_version,
155
- qf_version_source=session_profile.qf_version_source,
156
- )
163
+ active_context
157
164
  ),
158
165
  }
159
166
 
@@ -189,6 +196,116 @@ class WorkspaceTools(ToolBase):
189
196
  normalized = str(value).strip()
190
197
  return normalized or None
191
198
 
199
+ def _fetch_workspace_base_info(self, context: BackendRequestContext) -> dict[str, Any] | None:
200
+ try:
201
+ payload = self.backend.request("GET", context, "/ws/baseInfo")
202
+ except QingflowApiError:
203
+ return None
204
+ return payload if isinstance(payload, dict) else None
205
+
206
+ def _fetch_workspace_account_info(self, context: BackendRequestContext) -> dict[str, Any] | None:
207
+ try:
208
+ payload = self.backend.request("GET", context, "/ws/account")
209
+ except QingflowApiError:
210
+ return None
211
+ return payload if isinstance(payload, dict) else None
212
+
213
+ def _workspace_version_summary(
214
+ self,
215
+ payload: Any,
216
+ *,
217
+ workspace_base_info: Any,
218
+ workspace_detail: Any,
219
+ ) -> dict[str, Any]:
220
+ account_info = payload if isinstance(payload, dict) else {}
221
+ base_info = workspace_base_info if isinstance(workspace_base_info, dict) else {}
222
+ detail_info = workspace_detail if isinstance(workspace_detail, dict) else {}
223
+ level_code = self._first_present_int(
224
+ account_info.get("accountLevel"),
225
+ base_info.get("accountLevel"),
226
+ detail_info.get("accountLevel"),
227
+ )
228
+ level_name = self._account_level_name(level_code)
229
+ return {
230
+ "level_code": level_code,
231
+ "level_name": level_name,
232
+ "display_name": self._account_level_display_name(level_name),
233
+ "being_trial": self._first_present_bool(
234
+ account_info.get("trial"),
235
+ base_info.get("trial"),
236
+ detail_info.get("trial"),
237
+ ),
238
+ "expire_date": self._first_present_value(
239
+ account_info.get("expireDate"),
240
+ base_info.get("expireDate"),
241
+ detail_info.get("expireDate"),
242
+ ),
243
+ }
244
+
245
+ def _account_level_name(self, level_code: int | None) -> str | None:
246
+ mapping = {
247
+ 0: "FREE",
248
+ 10: "AIR",
249
+ 20: "BASIC",
250
+ 30: "TEAM",
251
+ 35: "PROFESSIONAL",
252
+ 40: "ENTERPRISE",
253
+ }
254
+ return mapping.get(level_code)
255
+
256
+ def _account_level_display_name(self, level_name: str | None) -> str | None:
257
+ mapping = {
258
+ "FREE": "免费版",
259
+ "AIR": "Air版",
260
+ "BASIC": "Pro版",
261
+ "TEAM": "团队版",
262
+ "PROFESSIONAL": "专业版",
263
+ "ENTERPRISE": "企业版",
264
+ }
265
+ return mapping.get(level_name)
266
+
267
+ def _coerce_int(self, value: Any) -> int | None:
268
+ if isinstance(value, bool) or value is None:
269
+ return None
270
+ if isinstance(value, int):
271
+ return value
272
+ try:
273
+ return int(str(value).strip())
274
+ except (TypeError, ValueError):
275
+ return None
276
+
277
+ def _coerce_bool(self, value: Any) -> bool | None:
278
+ if isinstance(value, bool):
279
+ return value
280
+ if value is None:
281
+ return None
282
+ normalized = str(value).strip().lower()
283
+ if normalized in {"true", "1"}:
284
+ return True
285
+ if normalized in {"false", "0"}:
286
+ return False
287
+ return None
288
+
289
+ def _first_present_int(self, *values: Any) -> int | None:
290
+ for value in values:
291
+ coerced = self._coerce_int(value)
292
+ if coerced is not None:
293
+ return coerced
294
+ return None
295
+
296
+ def _first_present_bool(self, *values: Any) -> bool | None:
297
+ for value in values:
298
+ coerced = self._coerce_bool(value)
299
+ if coerced is not None:
300
+ return coerced
301
+ return None
302
+
303
+ def _first_present_value(self, *values: Any) -> Any:
304
+ for value in values:
305
+ if value is not None:
306
+ return value
307
+ return None
308
+
192
309
  def workspace_set_plugin_status(
193
310
  self,
194
311
  *,