hap-cli 0.8.30__tar.gz → 0.8.31__tar.gz

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 (296) hide show
  1. {hap_cli-0.8.30 → hap_cli-0.8.31}/PKG-INFO +2 -1
  2. {hap_cli-0.8.30/hap_cli → hap_cli-0.8.31}/README.md +1 -0
  3. {hap_cli-0.8.30 → hap_cli-0.8.31/hap_cli}/README.md +1 -0
  4. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/README_CN.md +1 -0
  5. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/__init__.py +1 -1
  6. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/calendar_cmd.py +36 -1
  7. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/calendar_mod.py +65 -1
  8. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/global_meta.py +15 -0
  9. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/record.py +8 -3
  10. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/locale/messages.json +17 -1
  11. hap_cli-0.8.31/hap_cli/tests/test_calendar_discussion_cli.py +89 -0
  12. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_core.py +75 -0
  13. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli.egg-info/PKG-INFO +2 -1
  14. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli.egg-info/SOURCES.txt +1 -0
  15. {hap_cli-0.8.30 → hap_cli-0.8.31}/MANIFEST.in +0 -0
  16. {hap_cli-0.8.30 → hap_cli-0.8.31}/app_live_tests/__init__.py +0 -0
  17. {hap_cli-0.8.30 → hap_cli-0.8.31}/app_live_tests/__main__.py +0 -0
  18. {hap_cli-0.8.30 → hap_cli-0.8.31}/app_live_tests/config.py +0 -0
  19. {hap_cli-0.8.30 → hap_cli-0.8.31}/app_live_tests/harness.py +0 -0
  20. {hap_cli-0.8.30 → hap_cli-0.8.31}/app_live_tests/smoke.py +0 -0
  21. {hap_cli-0.8.30 → hap_cli-0.8.31}/app_live_tests/state.py +0 -0
  22. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/__main__.py +0 -0
  23. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/__init__.py +0 -0
  24. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/app_cmd.py +0 -0
  25. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/app_creator_cmd.py +0 -0
  26. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/app_editor_cmd.py +0 -0
  27. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/attachment_cmd.py +0 -0
  28. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/auth_cmd.py +0 -0
  29. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/chart_cmd.py +0 -0
  30. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/chat_cmd.py +0 -0
  31. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/chatbot_cmd.py +0 -0
  32. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/config_cmd.py +0 -0
  33. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/contact_cmd.py +0 -0
  34. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/department_cmd.py +0 -0
  35. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/group_cmd.py +0 -0
  36. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/guide_cmd.py +0 -0
  37. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/icon_cmd.py +0 -0
  38. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/instance_cmd.py +0 -0
  39. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/node_cmd.py +0 -0
  40. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/optionset_cmd.py +0 -0
  41. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/page_cmd.py +0 -0
  42. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/post_cmd.py +0 -0
  43. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/record_cmd.py +0 -0
  44. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/region_cmd.py +0 -0
  45. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/role_cmd.py +0 -0
  46. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/update_cmd.py +0 -0
  47. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/upload_cmd.py +0 -0
  48. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/v3_registry.py +0 -0
  49. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/workflow_cmd.py +0 -0
  50. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/commands/worksheet_cmd.py +0 -0
  51. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/context.py +0 -0
  52. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/__init__.py +0 -0
  53. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/action_spec_adapter.py +0 -0
  54. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app.py +0 -0
  55. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/__init__.py +0 -0
  56. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/_hapmeta/__init__.py +0 -0
  57. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/_hapmeta/control_type_codes.py +0 -0
  58. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/_hapmeta/worksheet_templates.py +0 -0
  59. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/charts.py +0 -0
  60. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/cleanup.py +0 -0
  61. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/compiler.py +0 -0
  62. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/config.py +0 -0
  63. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/design/design.schema.json +0 -0
  64. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/errors.py +0 -0
  65. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/examples/minimal.design.json +0 -0
  66. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/executor.py +0 -0
  67. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/fields.py +0 -0
  68. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/hap.py +0 -0
  69. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/merge.py +0 -0
  70. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/recording/__init__.py +0 -0
  71. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/recording/console.py +0 -0
  72. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/recording/jsonl.py +0 -0
  73. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/recording/mirror.py +0 -0
  74. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/recording/report.py +0 -0
  75. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/schema.py +0 -0
  76. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/seed/INSTRUCTIONS.md +0 -0
  77. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/seed/__init__.py +0 -0
  78. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/seed/cli.py +0 -0
  79. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/seed/executor.py +0 -0
  80. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/seed/resources/attachments.json +0 -0
  81. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/seed/resources/sample.docx +0 -0
  82. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/seed/resources/sample.pdf +0 -0
  83. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/seed/resources/sample_images.json +0 -0
  84. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/seed/template.py +0 -0
  85. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/selftest.py +0 -0
  86. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/smoke.py +0 -0
  87. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/steps.py +0 -0
  88. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/store.py +0 -0
  89. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/validate.py +0 -0
  90. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/app_creator/workflow_dsl.py +0 -0
  91. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/attachment.py +0 -0
  92. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/auth.py +0 -0
  93. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/chart.py +0 -0
  94. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/chat.py +0 -0
  95. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/chatbot.py +0 -0
  96. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/cli_access.py +0 -0
  97. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/contact.py +0 -0
  98. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/control_type_codes.py +0 -0
  99. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/department.py +0 -0
  100. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/__init__.py +0 -0
  101. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/_hapmeta/__init__.py +0 -0
  102. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/_hapmeta/control_type_codes.py +0 -0
  103. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/apply.py +0 -0
  104. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/componentlower.py +0 -0
  105. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/editspec/component.schema.json +0 -0
  106. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/editspec/custom-action.schema.json +0 -0
  107. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/editspec/envelope.schema.json +0 -0
  108. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/editspec/field.schema.json +0 -0
  109. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/editspec.py +0 -0
  110. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/errors.py +0 -0
  111. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/fieldlower.py +0 -0
  112. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/jsonschema_mini.py +0 -0
  113. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/models.py +0 -0
  114. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/ops.py +0 -0
  115. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/planner.py +0 -0
  116. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/editor/reader.py +0 -0
  117. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/field_normalizer.py +0 -0
  118. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/field_spec_adapter.py +0 -0
  119. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/filter_translator.py +0 -0
  120. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/flow_node.py +0 -0
  121. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/group.py +0 -0
  122. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/guide.py +0 -0
  123. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/icon_index.py +0 -0
  124. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/instance.py +0 -0
  125. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/logger.py +0 -0
  126. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/optionset.py +0 -0
  127. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/page.py +0 -0
  128. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/post.py +0 -0
  129. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/response_crypto.py +0 -0
  130. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/role.py +0 -0
  131. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/role_perm_builder.py +0 -0
  132. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/session.py +0 -0
  133. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/token_crypto.py +0 -0
  134. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/update.py +0 -0
  135. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/upload.py +0 -0
  136. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/v3/__init__.py +0 -0
  137. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/v3/dispatcher.py +0 -0
  138. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/v3/render.py +0 -0
  139. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/v3/schema.py +0 -0
  140. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/view_spec_adapter.py +0 -0
  141. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/workflow.py +0 -0
  142. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/workflow_node_dsl.py +0 -0
  143. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/worksheet.py +0 -0
  144. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/core/worksheet_templates.py +0 -0
  145. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/en/approval.md +0 -0
  146. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/en/chart.md +0 -0
  147. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/en/messages.md +0 -0
  148. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/en/overview.md +0 -0
  149. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/en/post.md +0 -0
  150. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/en/record.md +0 -0
  151. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/en/setup.md +0 -0
  152. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/en/skills.md +0 -0
  153. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/index.json +0 -0
  154. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/zh-Hans/approval.md +0 -0
  155. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/zh-Hans/chart.md +0 -0
  156. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/zh-Hans/messages.md +0 -0
  157. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/zh-Hans/overview.md +0 -0
  158. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/zh-Hans/post.md +0 -0
  159. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/zh-Hans/record.md +0 -0
  160. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/zh-Hans/setup.md +0 -0
  161. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/guide/zh-Hans/skills.md +0 -0
  162. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/hap_cli.py +0 -0
  163. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/i18n.py +0 -0
  164. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/locale/__init__.py +0 -0
  165. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/locale/messages.schema.json +0 -0
  166. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/__init__.py +0 -0
  167. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/conftest.py +0 -0
  168. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_app_creator.py +0 -0
  169. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_app_editor.py +0 -0
  170. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_app_export_usage.py +0 -0
  171. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_approval_submit_fill_cli.py +0 -0
  172. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_attachment_share.py +0 -0
  173. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_auth_prerelease.py +0 -0
  174. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_bug_036430.py +0 -0
  175. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_bug_036750.py +0 -0
  176. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_chart.py +0 -0
  177. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_chat_attachment_send.py +0 -0
  178. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_chat_recall_cli.py +0 -0
  179. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_cli_access.py +0 -0
  180. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_config_cmd.py +0 -0
  181. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_content_language.py +0 -0
  182. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_control_lookup_guard.py +0 -0
  183. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_destructive_confirm_cli.py +0 -0
  184. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_full_e2e.py +0 -0
  185. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_global_meta.py +0 -0
  186. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_guide.py +0 -0
  187. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_i18n.py +0 -0
  188. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_instance_history_cli.py +0 -0
  189. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_integration.py +0 -0
  190. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_integration_approval.py +0 -0
  191. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_integration_approval_actions.py +0 -0
  192. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_integration_calendar.py +0 -0
  193. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_integration_destructive.py +0 -0
  194. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_integration_misc.py +0 -0
  195. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_integration_post.py +0 -0
  196. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_integration_social.py +0 -0
  197. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_integration_v3.py +0 -0
  198. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_integration_workflow.py +0 -0
  199. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_integration_worksheet_extra.py +0 -0
  200. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_member_relation_array_wrap.py +0 -0
  201. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_multi_profile.py +0 -0
  202. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_no_workflow_unsupported.py +0 -0
  203. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_org_approval_v3_semantic_cli.py +0 -0
  204. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_org_id_cli.py +0 -0
  205. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_org_id_docs.py +0 -0
  206. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_parameter_conventions.py +0 -0
  207. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_parameter_mapping_registry.py +0 -0
  208. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_post_scope_cli.py +0 -0
  209. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_record_batch_v3_semantic_cli.py +0 -0
  210. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_record_field_alias.py +0 -0
  211. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_record_v3_semantic_cli.py +0 -0
  212. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_record_write_fixes.py +0 -0
  213. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_select_add_option.py +0 -0
  214. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_select_rejects_relation_value.py +0 -0
  215. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_semantic_types_registry.py +0 -0
  216. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_update.py +0 -0
  217. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_update_mode.py +0 -0
  218. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_upload_allow_down.py +0 -0
  219. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_upload_host_resolution.py +0 -0
  220. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_v3_api_schema_loader.py +0 -0
  221. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_v3_dispatcher.py +0 -0
  222. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_v3_registry_coverage.py +0 -0
  223. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_v3_session.py +0 -0
  224. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_v3_yaml_translation.py +0 -0
  225. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_workflow_envelope_errors.py +0 -0
  226. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_workflow_list_cli.py +0 -0
  227. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_workflow_read_write_keys.py +0 -0
  228. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_workflow_v3_semantic_cli.py +0 -0
  229. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_worksheet_create_section.py +0 -0
  230. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_worksheet_crud_cli.py +0 -0
  231. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_worksheet_switch.py +0 -0
  232. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/tests/test_worksheet_v3_semantic_cli.py +0 -0
  233. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/utils/__init__.py +0 -0
  234. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/utils/formatting.py +0 -0
  235. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/utils/options.py +0 -0
  236. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli/utils/parameter_mapping.py +0 -0
  237. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli.egg-info/dependency_links.txt +0 -0
  238. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli.egg-info/entry_points.txt +0 -0
  239. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli.egg-info/requires.txt +0 -0
  240. {hap_cli-0.8.30 → hap_cli-0.8.31}/hap_cli.egg-info/top_level.txt +0 -0
  241. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/__init__.py +0 -0
  242. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/__main__.py +0 -0
  243. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/_wftest.py +0 -0
  244. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/charts.py +0 -0
  245. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/cleanup.py +0 -0
  246. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/compiler.py +0 -0
  247. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/config.py +0 -0
  248. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/errors.py +0 -0
  249. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/executor.py +0 -0
  250. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/fields.py +0 -0
  251. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/hap.py +0 -0
  252. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/recording/__init__.py +0 -0
  253. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/recording/console.py +0 -0
  254. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/recording/jsonl.py +0 -0
  255. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/recording/mirror.py +0 -0
  256. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/recording/report.py +0 -0
  257. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/schema.py +0 -0
  258. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/seed/__init__.py +0 -0
  259. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/seed/cli.py +0 -0
  260. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/seed/executor.py +0 -0
  261. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/seed/template.py +0 -0
  262. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/selftest.py +0 -0
  263. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/smoke.py +0 -0
  264. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/step.py +0 -0
  265. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/steps.py +0 -0
  266. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/store.py +0 -0
  267. {hap_cli-0.8.30 → hap_cli-0.8.31}/live_tests/workflow_dsl.py +0 -0
  268. {hap_cli-0.8.30 → hap_cli-0.8.31}/setup.cfg +0 -0
  269. {hap_cli-0.8.30 → hap_cli-0.8.31}/setup.py +0 -0
  270. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/INDEX.json +0 -0
  271. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/add_member_to_role.yaml +0 -0
  272. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/batch_delete_records.yaml +0 -0
  273. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/create_optionset.yaml +0 -0
  274. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/create_role.yaml +0 -0
  275. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/delete_optionset.yaml +0 -0
  276. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/delete_record.yaml +0 -0
  277. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/delete_role.yaml +0 -0
  278. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/delete_worksheet.yaml +0 -0
  279. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_app_info.yaml +0 -0
  280. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_app_knowledge_list.yaml +0 -0
  281. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_app_worksheets_list.yaml +0 -0
  282. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_optionset_list.yaml +0 -0
  283. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_record_details.yaml +0 -0
  284. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_record_discussions.yaml +0 -0
  285. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_record_list.yaml +0 -0
  286. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_record_logs.yaml +0 -0
  287. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_record_pivot_data.yaml +0 -0
  288. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_record_relations.yaml +0 -0
  289. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_record_share_link.yaml +0 -0
  290. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_regions.yaml +0 -0
  291. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_role_details.yaml +0 -0
  292. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/get_role_list.yaml +0 -0
  293. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/knowledge_search.yaml +0 -0
  294. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/leave_all_roles.yaml +0 -0
  295. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/remove_member_from_role.yaml +0 -0
  296. {hap_cli-0.8.30 → hap_cli-0.8.31}/sources/v3-api-schema/update_optionset.yaml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hap-cli
3
- Version: 0.8.30
3
+ Version: 0.8.31
4
4
  Summary: CLI harness for Mingdao HAP - Enterprise no-code platform
5
5
  Author: hap-cli
6
6
  License: Apache-2.0
@@ -264,6 +264,7 @@ discover every subcommand.
264
264
  | `calendar list / get / create / update / delete` | Event lifecycle |
265
265
  | `calendar categories` | Built-in categories |
266
266
  | `calendar add-member / remove-member` | Membership |
267
+ | `calendar add-discussion` | Comment on an event (attachments supported) |
267
268
 
268
269
  ### chat — chat & messaging
269
270
 
@@ -235,6 +235,7 @@ discover every subcommand.
235
235
  | `calendar list / get / create / update / delete` | Event lifecycle |
236
236
  | `calendar categories` | Built-in categories |
237
237
  | `calendar add-member / remove-member` | Membership |
238
+ | `calendar add-discussion` | Comment on an event (attachments supported) |
238
239
 
239
240
  ### chat — chat & messaging
240
241
 
@@ -235,6 +235,7 @@ discover every subcommand.
235
235
  | `calendar list / get / create / update / delete` | Event lifecycle |
236
236
  | `calendar categories` | Built-in categories |
237
237
  | `calendar add-member / remove-member` | Membership |
238
+ | `calendar add-discussion` | Comment on an event (attachments supported) |
238
239
 
239
240
  ### chat — chat & messaging
240
241
 
@@ -218,6 +218,7 @@ hap --json worksheet record list WORKSHEET_ID
218
218
  | `calendar list / get / create / update / delete` | 日程生命周期 |
219
219
  | `calendar categories` | 内置分类 |
220
220
  | `calendar add-member / remove-member` | 成员管理 |
221
+ | `calendar add-discussion` | 在日程下发表评论(可带附件) |
221
222
 
222
223
  ### chat — 聊天与消息
223
224
 
@@ -1,3 +1,3 @@
1
1
  """CLI harness for Mingdao HAP (hap-cli)."""
2
2
 
3
- __version__ = "0.8.30"
3
+ __version__ = "0.8.31"
@@ -543,4 +543,39 @@ def calendar_categories(ctx):
543
543
  summary = _simplify_categories_result(raw)
544
544
  ctx.output(summary, _render_categories)
545
545
  except Exception as e:
546
- ctx.handle_error(e)
546
+ ctx.handle_error(e)
547
+
548
+ @calendar.command("add-discussion")
549
+ @click.argument("calendar_id")
550
+ @click.option("--message", "-m", required=True, help="Comment text")
551
+ @click.option("--reply-id", default="", help="ID of the comment being replied to")
552
+ @click.option("--file", "-f", "files", multiple=True,
553
+ help="Attach a file to the comment (repeatable). Accepts a local "
554
+ "path or an http(s) URL.")
555
+ @pass_context
556
+ def calendar_add_discussion(ctx, calendar_id, message, reply_id, files):
557
+ """Post a comment on a calendar event.
558
+
559
+ Everyone invited to the event can see the comment. Attached files are
560
+ downloadable by every participant.
561
+ """
562
+ try:
563
+ session = ctx.get_session()
564
+ attachments = None
565
+ if files:
566
+ from hap_cli.core import upload as up_mod
567
+ attachments = up_mod.upload_files(
568
+ session, up_mod.source_descriptors(list(files)))
569
+ raw = cal_mod.add_discussion(
570
+ session, calendar_id, message,
571
+ reply_id=reply_id, attachments=attachments,
572
+ )
573
+ data = raw.get("data") if isinstance(raw, dict) else None
574
+ summary = {
575
+ "success": True,
576
+ "discussion_id": (data or {}).get("discussionId", ""),
577
+ "calendar_id": calendar_id,
578
+ }
579
+ ctx.output(summary, lambda d: click.echo("Comment posted."))
580
+ except Exception as e:
581
+ ctx.handle_error(e)
@@ -13,9 +13,12 @@ Enum re-exports (`FREQUENCY_*`, `REMIND_TYPE_*`) mirror
13
13
  `src/pages/calendar/modules/calendarDetail/constant.js`.
14
14
  """
15
15
 
16
+ import json
16
17
  from typing import Any, Optional
17
18
 
18
- from hap_cli.core.session import Session
19
+ from hap_cli.core import global_meta as gm
20
+ from hap_cli.core import record as rec_mod
21
+ from hap_cli.core.session import Session, SessionError
19
22
 
20
23
 
21
24
  # ── Enums (pd-openweb constants) ─────────────────────────────────────────
@@ -327,3 +330,64 @@ def remove_member(
327
330
  def get_categories(session: Session) -> dict[str, Any]:
328
331
  """Get all calendar categories (`Calendar.GetUserAllCalCategories`)."""
329
332
  return session.api_call("Calendar", "GetUserAllCalCategories", {})
333
+
334
+
335
+ # ── Discussions (comments on an event) ────────────────────────────────────
336
+
337
+
338
+ def add_discussion(
339
+ session: Session,
340
+ calendar_id: str,
341
+ message: str,
342
+ reply_id: str = "",
343
+ attachments: Optional[list[dict[str, Any]]] = None,
344
+ ) -> dict[str, Any]:
345
+ """Post a comment on a calendar event (`Discussion.AddDiscussion`).
346
+
347
+ Traced from `src/pages/calendar/modules/calendarDetail/container/
348
+ CalendarCommenter.jsx`, which configures the shared commenter
349
+ (`src/components/comment/commenter.jsx`) with:
350
+
351
+ - `sourceType` = SOURCE_TYPE.CALENDAR (3, comment/config.js)
352
+ - `sourceId` = the bare calendar id (no composite form, unlike the
353
+ worksheet-row case's ``{worksheetId}|{rowId}``)
354
+ - `appId` = md.global.APPInfo.calendarAppID, and *no*
355
+ `fromAppId` — a calendar event has no owning app
356
+
357
+ Two props of CalendarCommenter deliberately do **not** reach this
358
+ payload. `remark` is only consumed when the comment is additionally
359
+ shared to a post (`postAjax.addPost`), and `AddDiscussionRequest`
360
+ (sources/main_api/schemas/…AddDiscussionRequest.json) has no such
361
+ field. `extendsId` is documented "扩展ID(工作表:appId|viewId)" and the
362
+ calendar commenter never sets it.
363
+
364
+ ``attachments`` carries uploaded-file descriptors from
365
+ ``hap_cli.core.upload``; the frontend sends them JSON-encoded, and
366
+ each descriptor's ``allowDown`` is what lets anyone but the uploader
367
+ download the file (see upload._download_permission).
368
+ """
369
+ app_id = gm.calendar_app_id(session.get_global_meta())
370
+ if not app_id:
371
+ # Guessing an app id here would produce a discussion the calendar
372
+ # UI cannot render, which is worse than refusing.
373
+ raise SessionError(
374
+ "This server did not publish the calendar application, so the "
375
+ "comment cannot be posted. Check that you are signed in to the "
376
+ "right server, then try again."
377
+ )
378
+ data: dict[str, Any] = {
379
+ "sourceId": calendar_id,
380
+ "sourceType": rec_mod.DISCUSSION_SOURCE_CALENDAR,
381
+ "message": message,
382
+ "appId": app_id,
383
+ # commenter.jsx: `forReacordDiscussion && entityType === 2 ? 2 : 0`
384
+ # — a calendar comment is always the plain kind.
385
+ "entityType": 0,
386
+ }
387
+ if reply_id:
388
+ data["replyId"] = reply_id
389
+ if attachments:
390
+ data["attachments"] = json.dumps(attachments, ensure_ascii=False)
391
+ result = session.api_call("Discussion", "AddDiscussion", data)
392
+ rec_mod.ensure_discussion_ok(result, "add comment")
393
+ return result
@@ -156,6 +156,21 @@ def worksheet_row_app_id(meta: Any) -> str:
156
156
  return str(_app_info(meta).get("worksheetRowAppID") or "")
157
157
 
158
158
 
159
+ def calendar_app_id(meta: Any) -> str:
160
+ """Return ``md.global.APPInfo.calendarAppID``.
161
+
162
+ The internal "application" id HAP uses for **calendar-event**
163
+ discussions (``sourceType`` 3 / ``Commenter.TYPES.CALENDAR`` in
164
+ pd-openweb ``src/components/comment/config.js``). ``AddDiscussion``
165
+ must carry it as ``appId`` — see
166
+ ``src/pages/calendar/modules/calendarDetail/container/CalendarCommenter.jsx``.
167
+ Unlike the worksheet-row case there is no separate ``fromAppId``:
168
+ a calendar event has no owning app. Returns empty string when the
169
+ deployment does not expose it.
170
+ """
171
+ return str(_app_info(meta).get("calendarAppID") or "")
172
+
173
+
159
174
  def worksheet_app_id(meta: Any) -> str:
160
175
  """Return ``md.global.APPInfo.worksheetAppID`` (whole-worksheet
161
176
  discussions, ``sourceType`` 7). Empty string when absent."""
@@ -12,10 +12,15 @@ from hap_cli.core import global_meta as gm
12
12
  logger = logging.getLogger("hap_cli.record")
13
13
 
14
14
  # Discussion source types — pd-openweb src/components/comment/config.js
15
+ # CALENDAR = 3 calendar-event discussion
15
16
  # WORKSHEET = 7 whole-worksheet discussion
16
17
  # WORKSHEETROW = 8 single record/row discussion
17
18
  # Record-scoped discussions (add/get/delete on a row) are always type 8,
18
19
  # and their sourceId is "{worksheetId}|{rowId}" — NOT the bare rowId.
20
+ # The whole enum lives here because this module owns the Discussion
21
+ # endpoint primitives; other modules (calendar) import from it rather
22
+ # than redeclaring their own copy.
23
+ DISCUSSION_SOURCE_CALENDAR = 3
19
24
  DISCUSSION_SOURCE_WORKSHEET = 7
20
25
  DISCUSSION_SOURCE_WORKSHEET_ROW = 8
21
26
 
@@ -1050,7 +1055,7 @@ def _discussion_source_id(worksheet_id: str, row_id: str) -> str:
1050
1055
  return f"{worksheet_id}|{row_id}"
1051
1056
 
1052
1057
 
1053
- def _ensure_discussion_ok(result: Any, action: str) -> None:
1058
+ def ensure_discussion_ok(result: Any, action: str) -> None:
1054
1059
  """Raise if the Discussion endpoint reported failure.
1055
1060
 
1056
1061
  Discussion endpoints return ``{code: 1, data: ...}`` on success and a
@@ -1138,7 +1143,7 @@ def add_discussion(
1138
1143
  if attachments:
1139
1144
  data["attachments"] = json.dumps(attachments, ensure_ascii=False)
1140
1145
  result = session.api_call("Discussion", "AddDiscussion", data)
1141
- _ensure_discussion_ok(result, "add discussion")
1146
+ ensure_discussion_ok(result, "add discussion")
1142
1147
  return result
1143
1148
 
1144
1149
 
@@ -1157,7 +1162,7 @@ def remove_discussion(
1157
1162
  "Discussion", "RemoveDiscussion",
1158
1163
  {"discussionId": discussion_id, "sourceType": source_type},
1159
1164
  )
1160
- _ensure_discussion_ok(result, "delete discussion")
1165
+ ensure_discussion_ok(result, "delete discussion")
1161
1166
  return result
1162
1167
 
1163
1168
 
@@ -2217,6 +2217,22 @@
2217
2217
  "en": "Calendar and schedule management.",
2218
2218
  "zh-Hans": "日程与日历管理"
2219
2219
  },
2220
+ "calendar add-discussion": {
2221
+ "en": "Post a comment on a calendar event.\n\nEveryone invited to the event can see the comment. Attached files are\ndownloadable by every participant.",
2222
+ "zh-Hans": "在日程下发表评论。\n\n日程的所有参与者都能看到这条评论;随评论上传的附件,参与者均可下载。"
2223
+ },
2224
+ "calendar add-discussion --file": {
2225
+ "en": "Attach a file to the comment (repeatable). Accepts a local path or an http(s) URL.",
2226
+ "zh-Hans": "为评论添加附件(可重复指定)。可传本地路径或 http(s) 链接。"
2227
+ },
2228
+ "calendar add-discussion --message": {
2229
+ "en": "Comment text",
2230
+ "zh-Hans": "评论内容"
2231
+ },
2232
+ "calendar add-discussion --reply-id": {
2233
+ "en": "ID of the comment being replied to",
2234
+ "zh-Hans": "被回复的评论 ID"
2235
+ },
2220
2236
  "calendar add-member": {
2221
2237
  "en": "Add members to a calendar event.",
2222
2238
  "zh-Hans": "向日程事件添加成员"
@@ -4890,4 +4906,4 @@
4890
4906
  "zh-Hans": "应用到现有视图的高层视图 JSON(格式与 'view create --view-spec' 相同)。规格中表达的内容全部更新;其他设置保持不变。字段引用可为名称、别名或 controlId。提供时忽略其他选项"
4891
4907
  }
4892
4908
  }
4893
- }
4909
+ }
@@ -0,0 +1,89 @@
1
+ """`hap calendar add-discussion` — commenting on a calendar event.
2
+
3
+ Until this command existed, attaching a file to a calendar event's
4
+ comment thread had no CLI path at all: the only `Discussion/AddDiscussion`
5
+ caller in the codebase was the worksheet-record one, pinned to
6
+ `sourceType` 8. Anyone who needed it had to assemble the request by hand
7
+ against the raw session — which is how a calendar comment attachment
8
+ first shipped without its download permission (see
9
+ test_upload_allow_down.py).
10
+
11
+ Payload traced from pd-openweb
12
+ `src/pages/calendar/modules/calendarDetail/container/CalendarCommenter.jsx`
13
+ → `src/components/comment/commenter.jsx`, cross-checked against
14
+ `sources/main_api/schemas/MD.Web.Ajax.Request.Discussion.AddDiscussionRequest.json`.
15
+ """
16
+
17
+ from unittest.mock import patch
18
+
19
+ from click.testing import CliRunner
20
+
21
+ from hap_cli.hap_cli import cli
22
+
23
+
24
+ class TestAddDiscussionCli:
25
+
26
+ def test_message_reaches_the_core_call(self):
27
+ runner = CliRunner()
28
+ with patch("hap_cli.context.Context.get_session"), \
29
+ patch("hap_cli.core.calendar_mod.add_discussion",
30
+ return_value={"code": 1, "data": {"discussionId": "d1"}}) as m:
31
+ res = runner.invoke(cli, ["calendar", "add-discussion", "cal1",
32
+ "-m", "会前看下资料"])
33
+ assert res.exit_code == 0, res.output
34
+ assert m.call_args[0][1:] == ("cal1", "会前看下资料")
35
+ assert m.call_args[1]["reply_id"] == ""
36
+ assert m.call_args[1]["attachments"] is None
37
+
38
+ def test_reply_id_is_forwarded(self):
39
+ runner = CliRunner()
40
+ with patch("hap_cli.context.Context.get_session"), \
41
+ patch("hap_cli.core.calendar_mod.add_discussion",
42
+ return_value={"code": 1, "data": {}}) as m:
43
+ res = runner.invoke(cli, ["calendar", "add-discussion", "cal1",
44
+ "-m", "收到", "--reply-id", "d0"])
45
+ assert res.exit_code == 0, res.output
46
+ assert m.call_args[1]["reply_id"] == "d0"
47
+
48
+ def test_files_are_uploaded_and_attached(self, tmp_path):
49
+ runner = CliRunner()
50
+ f = tmp_path / "proto.zip"
51
+ f.write_bytes(b"zip")
52
+ descriptor = {"fileID": "o_1", "fileExt": ".zip", "allowDown": True}
53
+ with patch("hap_cli.context.Context.get_session"), \
54
+ patch("hap_cli.core.upload.upload_files",
55
+ return_value=[descriptor]) as up, \
56
+ patch("hap_cli.core.calendar_mod.add_discussion",
57
+ return_value={"code": 1, "data": {}}) as m:
58
+ res = runner.invoke(cli, ["calendar", "add-discussion", "cal1",
59
+ "-m", "原型包", "-f", str(f)])
60
+ assert res.exit_code == 0, res.output
61
+ assert up.call_args[0][1] == [{"path": str(f)}]
62
+ assert m.call_args[1]["attachments"] == [descriptor]
63
+
64
+ def test_an_http_source_is_fetched_rather_than_opened_as_a_path(self):
65
+ runner = CliRunner()
66
+ with patch("hap_cli.context.Context.get_session"), \
67
+ patch("hap_cli.core.upload.upload_files",
68
+ return_value=[{"fileID": "o_2"}]) as up, \
69
+ patch("hap_cli.core.calendar_mod.add_discussion",
70
+ return_value={"code": 1, "data": {}}):
71
+ res = runner.invoke(cli, ["calendar", "add-discussion", "cal1",
72
+ "-m", "链接", "-f",
73
+ "https://example.com/a.pdf"])
74
+ assert res.exit_code == 0, res.output
75
+ assert up.call_args[0][1] == [{"url": "https://example.com/a.pdf"}]
76
+
77
+ def test_message_is_required(self):
78
+ runner = CliRunner()
79
+ with patch("hap_cli.context.Context.get_session"):
80
+ res = runner.invoke(cli, ["calendar", "add-discussion", "cal1"])
81
+ assert res.exit_code != 0
82
+
83
+ def test_help_is_end_user_copy(self):
84
+ runner = CliRunner()
85
+ res = runner.invoke(cli, ["calendar", "add-discussion", "--help"])
86
+ assert res.exit_code == 0
87
+ for leak in ("AddDiscussion", "Discussion/", "sourceType", "pd-openweb",
88
+ "calendarAppID", "commenter", "endpoint"):
89
+ assert leak not in res.output
@@ -4022,6 +4022,81 @@ class TestCalendar:
4022
4022
  assert body["isAllCalendar"] is True
4023
4023
 
4024
4024
 
4025
+ class TestCalendarDiscussions:
4026
+ """Comments on a calendar event.
4027
+
4028
+ Traced from pd-openweb
4029
+ `src/pages/calendar/modules/calendarDetail/container/CalendarCommenter.jsx`,
4030
+ which feeds the shared `src/components/comment/commenter.jsx`:
4031
+ `sourceType` = SOURCE_TYPE.CALENDAR (3, config.js) and `appId` =
4032
+ `md.global.APPInfo.calendarAppID`. The commenter's `remark` prop is
4033
+ *not* part of the AddDiscussion payload — it is only used when the
4034
+ comment is additionally shared to a post (`postAjax.addPost`), and
4035
+ `AddDiscussionRequest` has no such field. `extendsId` is documented
4036
+ "扩展ID(工作表:appId|viewId)" and the calendar commenter never sets it.
4037
+ """
4038
+
4039
+ _META = {"md.global": {"APPInfo": {"calendarAppID": "cal-app-id"}}}
4040
+
4041
+ def _session(self):
4042
+ session = MagicMock()
4043
+ session.get_global_meta.return_value = self._META
4044
+ session.api_call.return_value = {"code": 1, "data": {"discussionId": "d1"}}
4045
+ return session
4046
+
4047
+ def test_payload_shape(self):
4048
+ from hap_cli.core import calendar_mod
4049
+ session = self._session()
4050
+ calendar_mod.add_discussion(session, "cal1", "看下这个附件")
4051
+ controller, action, payload = session.api_call.call_args[0][:3]
4052
+ assert (controller, action) == ("Discussion", "AddDiscussion")
4053
+ assert payload["sourceId"] == "cal1" # the bare calendar id
4054
+ assert payload["sourceType"] == 3 # SOURCE_TYPE.CALENDAR
4055
+ assert payload["appId"] == "cal-app-id" # APPInfo.calendarAppID
4056
+ assert payload["message"] == "看下这个附件"
4057
+ assert payload["entityType"] == 0
4058
+ # Worksheet-only / post-only fields must not leak in.
4059
+ assert "extendsId" not in payload
4060
+ assert "remark" not in payload
4061
+ assert "fromAppId" not in payload
4062
+
4063
+ def test_reply_id_is_sent_only_when_given(self):
4064
+ from hap_cli.core import calendar_mod
4065
+ session = self._session()
4066
+ calendar_mod.add_discussion(session, "cal1", "收到")
4067
+ assert "replyId" not in session.api_call.call_args[0][2]
4068
+ calendar_mod.add_discussion(session, "cal1", "收到", reply_id="d0")
4069
+ assert session.api_call.call_args[0][2]["replyId"] == "d0"
4070
+
4071
+ def test_attachments_are_json_encoded(self):
4072
+ from hap_cli.core import calendar_mod
4073
+ session = self._session()
4074
+ calendar_mod.add_discussion(
4075
+ session, "cal1", "原型包",
4076
+ attachments=[{"fileID": "o_1", "fileExt": ".zip", "allowDown": True}],
4077
+ )
4078
+ payload = session.api_call.call_args[0][2]
4079
+ sent = json.loads(payload["attachments"])
4080
+ assert sent[0]["fileID"] == "o_1"
4081
+ # The download permission must survive the hop — see
4082
+ # test_upload_allow_down.py for why it exists at all.
4083
+ assert sent[0]["allowDown"] is True
4084
+
4085
+ def test_failure_code_raises_instead_of_reporting_success(self):
4086
+ from hap_cli.core import calendar_mod
4087
+ session = self._session()
4088
+ session.api_call.return_value = {"code": 7} # 没有权限操作
4089
+ with pytest.raises(APIError):
4090
+ calendar_mod.add_discussion(session, "cal1", "hi")
4091
+
4092
+ def test_missing_calendar_app_id_is_an_error_not_a_guess(self):
4093
+ from hap_cli.core import calendar_mod
4094
+ session = self._session()
4095
+ session.get_global_meta.return_value = {"md.global": {"APPInfo": {}}}
4096
+ with pytest.raises(SessionError):
4097
+ calendar_mod.add_discussion(session, "cal1", "hi")
4098
+
4099
+
4025
4100
  # ── Chat Tests ────────────────────────────────────────────────────────────
4026
4101
 
4027
4102
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hap-cli
3
- Version: 0.8.30
3
+ Version: 0.8.31
4
4
  Summary: CLI harness for Mingdao HAP - Enterprise no-code platform
5
5
  Author: hap-cli
6
6
  License: Apache-2.0
@@ -264,6 +264,7 @@ discover every subcommand.
264
264
  | `calendar list / get / create / update / delete` | Event lifecycle |
265
265
  | `calendar categories` | Built-in categories |
266
266
  | `calendar add-member / remove-member` | Membership |
267
+ | `calendar add-discussion` | Comment on an event (attachments supported) |
267
268
 
268
269
  ### chat — chat & messaging
269
270
 
@@ -175,6 +175,7 @@ hap_cli/tests/test_attachment_share.py
175
175
  hap_cli/tests/test_auth_prerelease.py
176
176
  hap_cli/tests/test_bug_036430.py
177
177
  hap_cli/tests/test_bug_036750.py
178
+ hap_cli/tests/test_calendar_discussion_cli.py
178
179
  hap_cli/tests/test_chart.py
179
180
  hap_cli/tests/test_chat_attachment_send.py
180
181
  hap_cli/tests/test_chat_recall_cli.py
File without changes
File without changes
File without changes
File without changes