simplepush 3.5.0__tar.gz → 3.6.1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: simplepush
3
- Version: 3.5.0
3
+ Version: 3.6.1
4
4
  Summary: Python client for Simplepush (tasks, notifications, events, end-to-end encryption).
5
5
  Project-URL: Homepage, https://simplepu.sh
6
6
  Project-URL: Documentation, https://simplepu.sh/guide/python-sdk
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "simplepush"
7
- version = "3.5.0"
7
+ version = "3.6.1"
8
8
  description = "Python client for Simplepush (tasks, notifications, events, end-to-end encryption)."
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -683,6 +683,7 @@ class _BaseClient:
683
683
  input: NotificationInput | None = None,
684
684
  image: "str | os.PathLike | None" = None,
685
685
  audio: "str | os.PathLike | None" = None,
686
+ link: str | None = None,
686
687
  password: str | None = None,
687
688
  tag: str | None = None,
688
689
  critical: bool = False,
@@ -725,6 +726,10 @@ class _BaseClient:
725
726
  audio: Optional single audio clip (URL or local path), like `image`.
726
727
  Plays inline on iOS; Android has no inline audio. Mutually
727
728
  exclusive with `image` (a notification shows at most one media).
729
+ link: Optional URL shown as an "Open link" button on the push. Any
730
+ scheme: an https URL opens the browser, an app's deep link
731
+ (`unifi-protect://...`) opens that app. Mutually exclusive
732
+ with `input` (the input's buttons take the action slots).
728
733
  password: Optional password to encrypt body fields with. Requires a
729
734
  topic (used as the salt for key derivation). Falls back to
730
735
  the client's default `password` when omitted. Not accepted
@@ -750,7 +755,7 @@ class _BaseClient:
750
755
  return self._create_notification(
751
756
  topic=topic, member=member, broadcast=broadcast,
752
757
  title=title, content=content, input=input,
753
- image=image, audio=audio,
758
+ image=image, audio=audio, link=link,
754
759
  password=password if password is not None else self._send_password(topic),
755
760
  tag=tag, critical=critical, shared=shared,
756
761
  )
@@ -966,7 +971,7 @@ class _BaseClient:
966
971
 
967
972
  def _create_notification(self, *, topic=None, member=None, broadcast=False,
968
973
  title=None, content=None, input=None, image=None, audio=None,
969
- password=None, tag=None, critical=False,
974
+ link=None, password=None, tag=None, critical=False,
970
975
  shared=False) -> "Notification | NotificationGroup":
971
976
  if not content and input is None:
972
977
  raise ValueError("Either content or an input must be provided")
@@ -990,6 +995,8 @@ class _BaseClient:
990
995
  _validate_actions(input.actions)
991
996
  if image is not None and audio is not None:
992
997
  raise ValueError("a notification can carry at most one media attachment (image or audio, not both)")
998
+ if link is not None and input is not None:
999
+ raise ValueError("a notification carries either an input or a link, not both: the input's buttons take the action slots, so the link would never be shown")
993
1000
 
994
1001
  # A notification carries at most one input, sent as `textInput {}` XOR
995
1002
  # `choiceInput {options}` XOR `actionInput {actions}`. For actions, both
@@ -1029,6 +1036,8 @@ class _BaseClient:
1029
1036
  tag = encrypt(tag, dk.symmetric_key)
1030
1037
  if choice_options is not None:
1031
1038
  choice_options = [encrypt(opt, dk.symmetric_key) for opt in choice_options]
1039
+ if link is not None:
1040
+ link = encrypt(link, dk.symmetric_key)
1032
1041
  if action_defs is not None:
1033
1042
  # Key AND label, exactly like a task's ActionsInput: the key
1034
1043
  # usually carries the same meaning as the label ("approve"), so
@@ -1053,6 +1062,8 @@ class _BaseClient:
1053
1062
  tag = encrypt(tag, key)
1054
1063
  if choice_options is not None:
1055
1064
  choice_options = [encrypt(opt, key) for opt in choice_options]
1065
+ if link is not None:
1066
+ link = encrypt(link, key)
1056
1067
  if action_defs is not None:
1057
1068
  for a in action_defs: # key AND label, as above
1058
1069
  a["key"] = encrypt(a["key"], key)
@@ -1069,6 +1080,8 @@ class _BaseClient:
1069
1080
  }
1070
1081
  if media_dict is not None:
1071
1082
  payload["media"] = media_dict
1083
+ if link is not None:
1084
+ payload["link"] = link
1072
1085
  if topic is not None:
1073
1086
  payload["topic"] = topic
1074
1087
  if member is not None:
@@ -1471,7 +1471,7 @@ class Task:
1471
1471
  def append(self, *, title: str | None = None, content: str | None = None,
1472
1472
  inputs=None, links: list[str] | None = None,
1473
1473
  files: "list[str | os.PathLike] | None" = None,
1474
- auto_commit: bool = True, critical: bool = False,
1474
+ auto_commit: bool = False, critical: bool = False,
1475
1475
  reply: "ReplyMode | Literal['one-shot', 'sticky', 'one-time-per-user'] | None" = None,
1476
1476
  content_format: "ContentFormat | Literal['plain', 'markdown'] | None" = None) -> "Subtask":
1477
1477
  """Append a subtask to this task's chain and return a `Subtask` handle.
@@ -1643,7 +1643,7 @@ class TaskGroup:
1643
1643
  inputs=None, links: "list[str] | None" = None,
1644
1644
  files: "list[str | os.PathLike] | None" = None,
1645
1645
  instances: "list[str | Task] | None" = None,
1646
- auto_commit: bool = True, critical: bool = False,
1646
+ auto_commit: bool = False, critical: bool = False,
1647
1647
  reply: "ReplyMode | Literal['one-shot', 'sticky', 'one-time-per-user'] | None" = None,
1648
1648
  content_format: "ContentFormat | Literal['plain', 'markdown'] | None" = None) -> "list[Subtask]":
1649
1649
  """Append a subtask to every member instance's chain atomically — or
File without changes
File without changes
File without changes