otf-api 0.9.0__py3-none-any.whl → 0.9.1__py3-none-any.whl

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.
otf_api/__init__.py CHANGED
@@ -4,7 +4,7 @@ from otf_api.api import Otf
4
4
  from otf_api import models
5
5
  from otf_api.auth import OtfUser
6
6
 
7
- __version__ = "0.9.0"
7
+ __version__ = "0.9.1"
8
8
 
9
9
 
10
10
  __all__ = ["Otf", "OtfUser", "models"]
otf_api/api.py CHANGED
@@ -1007,14 +1007,58 @@ class Otf:
1007
1007
  res = self._telemetry_request("GET", path, params=params)
1008
1008
  return models.Telemetry(**res)
1009
1009
 
1010
- def get_sms_notification_settings(self):
1010
+ def get_sms_notification_settings(self) -> models.SmsNotificationSettings:
1011
+ """Get the member's SMS notification settings.
1012
+
1013
+ Returns:
1014
+ SmsNotificationSettings: The member's SMS notification settings.
1015
+ """
1011
1016
  res = self._default_request("GET", url="/sms/v1/preferences", params={"phoneNumber": self.member.phone_number})
1012
1017
 
1013
- return res["data"]
1018
+ return models.SmsNotificationSettings(**res["data"])
1019
+
1020
+ def update_sms_notification_settings(
1021
+ self, promotional_enabled: bool | None = None, transactional_enabled: bool | None = None
1022
+ ) -> models.SmsNotificationSettings:
1023
+ """Update the member's SMS notification settings. Arguments not provided will be left unchanged.
1024
+
1025
+ Args:
1026
+ promotional_enabled (bool | None): Whether to enable promotional SMS notifications.
1027
+ transactional_enabled (bool | None): Whether to enable transactional SMS notifications.
1028
+
1029
+ Returns:
1030
+ SmsNotificationSettings: The updated SMS notification settings.
1014
1031
 
1015
- def update_sms_notification_settings(self, promotional_enabled: bool, transactional_enabled: bool):
1032
+ Warning:
1033
+ ---
1034
+ This endpoint seems to accept almost anything, converting values to truthy/falsey and
1035
+ updating the settings accordingly. The one error I've gotten is with -1
1036
+
1037
+ ```
1038
+ ERROR - Response:
1039
+ {
1040
+ "code": "ER_WARN_DATA_OUT_OF_RANGE",
1041
+ "message": "An unexpected server error occurred, please try again.",
1042
+ "details": [
1043
+ {
1044
+ "message": "ER_WARN_DATA_OUT_OF_RANGE: Out of range value for column 'IsPromotionalSMSOptIn' at row 1",
1045
+ "additionalInfo": ""
1046
+ }
1047
+ ]
1048
+ }
1049
+ ```
1050
+ """
1016
1051
  url = "/sms/v1/preferences"
1017
1052
 
1053
+ current_settings = self.get_sms_notification_settings()
1054
+
1055
+ promotional_enabled = (
1056
+ promotional_enabled if promotional_enabled is not None else current_settings.is_promotional_sms_opt_in
1057
+ )
1058
+ transactional_enabled = (
1059
+ transactional_enabled if transactional_enabled is not None else current_settings.is_transactional_sms_opt_in
1060
+ )
1061
+
1018
1062
  body = {
1019
1063
  "promosms": promotional_enabled,
1020
1064
  "source": "OTF",
@@ -1022,11 +1066,45 @@ class Otf:
1022
1066
  "phoneNumber": self.member.phone_number,
1023
1067
  }
1024
1068
 
1025
- res = self._default_request("POST", url, json=body)
1069
+ self._default_request("POST", url, json=body)
1026
1070
 
1027
- return res["data"]
1071
+ # the response returns nothing useful, so we just query the settings again
1072
+ new_settings = self.get_sms_notification_settings()
1073
+ return new_settings
1074
+
1075
+ def get_email_notification_settings(self) -> models.EmailNotificationSettings:
1076
+ """Get the member's email notification settings.
1077
+
1078
+ Returns:
1079
+ EmailNotificationSettings: The member's email notification settings.
1080
+ """
1081
+ res = self._default_request("GET", url="/otfmailing/v2/preferences", params={"email": self.member.email})
1082
+
1083
+ return models.EmailNotificationSettings(**res["data"])
1084
+
1085
+ def update_email_notification_settings(
1086
+ self, promotional_enabled: bool | None = None, transactional_enabled: bool | None = None
1087
+ ) -> models.EmailNotificationSettings:
1088
+ """Update the member's email notification settings. Arguments not provided will be left unchanged.
1089
+
1090
+ Args:
1091
+ promotional_enabled (bool | None): Whether to enable promotional email notifications.
1092
+ transactional_enabled (bool | None): Whether to enable transactional email notifications.
1093
+
1094
+ Returns:
1095
+ EmailNotificationSettings: The updated email notification settings.
1096
+ """
1097
+ current_settings = self.get_email_notification_settings()
1098
+
1099
+ promotional_enabled = (
1100
+ promotional_enabled if promotional_enabled is not None else current_settings.is_promotional_email_opt_in
1101
+ )
1102
+ transactional_enabled = (
1103
+ transactional_enabled
1104
+ if transactional_enabled is not None
1105
+ else current_settings.is_transactional_email_opt_in
1106
+ )
1028
1107
 
1029
- def update_email_notification_settings(self, promotional_enabled: bool, transactional_enabled: bool):
1030
1108
  body = {
1031
1109
  "promotionalEmail": promotional_enabled,
1032
1110
  "source": "OTF",
@@ -1034,9 +1112,11 @@ class Otf:
1034
1112
  "email": self.member.email,
1035
1113
  }
1036
1114
 
1037
- res = self._default_request("POST", "/otfmailing/v2/preferences", json=body)
1115
+ self._default_request("POST", "/otfmailing/v2/preferences", json=body)
1038
1116
 
1039
- return res["data"]
1117
+ # the response returns nothing useful, so we just query the settings again
1118
+ new_settings = self.get_email_notification_settings()
1119
+ return new_settings
1040
1120
 
1041
1121
  def update_member_name(self, first_name: str | None = None, last_name: str | None = None) -> models.MemberDetail:
1042
1122
  """Update the member's name. Will return the original member details if no names are provided.
@@ -8,6 +8,7 @@ from .lifetime_stats import StatsResponse, TimeStats
8
8
  from .member_detail import MemberDetail
9
9
  from .member_membership import MemberMembership
10
10
  from .member_purchases import MemberPurchase
11
+ from .notifications import EmailNotificationSettings, SmsNotificationSettings
11
12
  from .out_of_studio_workout_history import OutOfStudioWorkoutHistory
12
13
  from .performance_summary_detail import PerformanceSummaryDetail
13
14
  from .performance_summary_list import PerformanceSummaryEntry
@@ -24,6 +25,7 @@ __all__ = [
24
25
  "ChallengeTracker",
25
26
  "ClassType",
26
27
  "DoW",
28
+ "EmailNotificationSettings",
27
29
  "EquipmentType",
28
30
  "FitnessBenchmark",
29
31
  "LatestAgreement",
@@ -34,6 +36,7 @@ __all__ = [
34
36
  "OutOfStudioWorkoutHistory",
35
37
  "PerformanceSummaryDetail",
36
38
  "PerformanceSummaryEntry",
39
+ "SmsNotificationSettings",
37
40
  "StatsResponse",
38
41
  "StatsTime",
39
42
  "StudioDetail",
@@ -0,0 +1,17 @@
1
+ from pydantic import Field
2
+
3
+ from otf_api.models.base import OtfItemBase
4
+
5
+
6
+ class SmsNotificationSettings(OtfItemBase):
7
+ is_promotional_sms_opt_in: bool | None = Field(None, alias="isPromotionalSmsOptIn")
8
+ is_transactional_sms_opt_in: bool | None = Field(None, alias="isTransactionalSmsOptIn")
9
+ is_promotional_phone_opt_in: bool | None = Field(None, alias="isPromotionalPhoneOptIn")
10
+ is_transactional_phone_opt_in: bool | None = Field(None, alias="isTransactionalPhoneOptIn")
11
+
12
+
13
+ class EmailNotificationSettings(OtfItemBase):
14
+ is_system_email_opt_in: bool | None = Field(None, alias="isSystemEmailOptIn")
15
+ is_promotional_email_opt_in: bool | None = Field(None, alias="isPromotionalEmailOptIn")
16
+ is_transactional_email_opt_in: bool | None = Field(None, alias="isTransactionalEmailOptIn")
17
+ email: str | None = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: otf-api
3
- Version: 0.9.0
3
+ Version: 0.9.1
4
4
  Summary: Python OrangeTheory Fitness API Client
5
5
  License: MIT
6
6
  Author: Jessica Smith
@@ -44,11 +44,20 @@ pip install otf-api
44
44
 
45
45
  ## Overview
46
46
 
47
- To use the API, you need to create an instance of the `Otf` class, providing your email address and password. This will authenticate you with the API and allow you to make requests. When the `Otf` object is created it automatically grabs your member details and home studio, to simplify the process of making requests.
47
+ To use the API, you need to create an instance of the `Otf` class. This will authenticate you with the API and allow you to make requests. When the `Otf` object is created it automatically grabs your member details and home studio, to simplify the process of making requests.
48
48
 
49
+ You can either pass an `OtfUser` object to the `OtfClass` or you can pass nothing and allow it to prompt you for your username and password.
49
50
 
50
- See the [examples](./examples) for more information on how to use the API.
51
+ You can also export environment variables `OTF_EMAIL` and `OTF_PASSWORD` to get these from the environment.
51
52
 
52
- Disclaimer:
53
- This project is in no way affiliated with OrangeTheory Fitness.
53
+ ```python
54
+ from otf_api import Otf, OtfUser
55
+
56
+ otf = Otf()
57
+
58
+ # OR
59
+
60
+ otf = Otf(user=OtfUser(<email_address>,<password>))
61
+
62
+ ```
54
63
 
@@ -1,5 +1,5 @@
1
- otf_api/__init__.py,sha256=pwX9albBmqssSx-TBlK4GFkWw-HSHWE__Miv-8nBelQ,204
2
- otf_api/api.py,sha256=IOC3QAL8jK-FgW1UJg2IOOtq0aE6gbr-7k2fSYJFdys,43573
1
+ otf_api/__init__.py,sha256=dGgyclSo165V_hZAl7Z5E06WQrs5NjO6fXtPcbo3RIg,204
2
+ otf_api/api.py,sha256=Ah6bheezsV-RLxPLGKZqqW77gotWkznLYmEeRhEwJaY,47006
3
3
  otf_api/auth/__init__.py,sha256=Pu6ugbEXhgjJEpYKr7K2CqEac53Wq9FRF3F16GLQ_ww,133
4
4
  otf_api/auth/auth.py,sha256=m9qzUn0hdAo6AZHm2Mn054nLqUWPxEyP3y3DOBVkvYA,9010
5
5
  otf_api/auth/user.py,sha256=HgggfneeVMnKFWSUMnlikfZyC__HE8vVaKSpBS4_sIg,2256
@@ -7,7 +7,7 @@ otf_api/auth/utils.py,sha256=jUH_A1-DU3KfY-XrymCuQoud79o9qfu5P9Ws9QA2aWs,3211
7
7
  otf_api/exceptions.py,sha256=mt0k0-2oNcpNhboYzkywpt535W6bHjx6gro7P3PpYzo,1463
8
8
  otf_api/filters.py,sha256=fk2bFGi3srjS96qZlaDx-ARZRaj93NUTUdMJ01TX420,3702
9
9
  otf_api/logging.py,sha256=PRZpCaJ1F1Xya3L9Efkt3mKS5_QNr3sXjEUERSxYjvE,563
10
- otf_api/models/__init__.py,sha256=na4JscryHHwNdIkefA6Eqoiny3PUEBgUa4tnv1-g5M0,1446
10
+ otf_api/models/__init__.py,sha256=czt_OYsU4igeudRAi8kqOQro6fjNrbE9aLr--FA76Sg,1588
11
11
  otf_api/models/base.py,sha256=KJlIxl_sRj6f-g5vKYPw4yV6fGDk-fwZ93EO0JGPYMw,202
12
12
  otf_api/models/body_composition_list.py,sha256=jGdR-9ScvIOtULJNB99aYh2INk2ihoHAnTWtbQCIea4,12202
13
13
  otf_api/models/bookings.py,sha256=8zgLnQ40ci0c7AimGeoAI-Raw8d2byvKoXkJXyW1xUE,4260
@@ -20,6 +20,7 @@ otf_api/models/member_detail.py,sha256=CDDZg3Ow07U57yRqbm3i-BVha0cvCNOZ8QhN0pliU
20
20
  otf_api/models/member_membership.py,sha256=jZwHzwtVyMUr8dWGlFbMYj9qveCbiOblWW5szXDUFFo,1338
21
21
  otf_api/models/member_purchases.py,sha256=Ne7ByEbGTqTJhuEyCgywWe8I3nc-D46qw09up7ys38s,1627
22
22
  otf_api/models/mixins.py,sha256=VR5EeweySHhzaiqqnCr853Cpe1uK97cxY0IFEdf5T8w,2262
23
+ otf_api/models/notifications.py,sha256=AkmIfiIiU6wox_7puyenbhCX10SFvBD5eBAovcurRgY,833
23
24
  otf_api/models/out_of_studio_workout_history.py,sha256=El5i0K2Td_sMReyfUKP-Iv1L1WgRx0ijjjnHzYvlCeY,1703
24
25
  otf_api/models/performance_summary_detail.py,sha256=HmtAJIKkekYy2rJOQBxfQGsKJxuFZm7gP4Dauae-PqM,2711
25
26
  otf_api/models/performance_summary_list.py,sha256=jv28jZJEOXOZtghhHhNR-4BPVBY3TpyiwHNKmnoTRcA,1692
@@ -28,7 +29,7 @@ otf_api/models/studio_services.py,sha256=aGLQMQmjGVpI6YxzAl-mcp3Y9cHPXuH9dIqrl6E
28
29
  otf_api/models/telemetry.py,sha256=_g-wtJDbaXENk1DqH0bbpJUsGepWDYraRIsIvpvDBU8,2531
29
30
  otf_api/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
31
  otf_api/utils.py,sha256=Af_Xg2QLoFqRzHOj4LtCIIqpRsdih-7HW1rJ8tUo8tE,3937
31
- otf_api-0.9.0.dist-info/LICENSE,sha256=UaPT9ynYigC3nX8n22_rC37n-qmTRKLFaHrtUwF9ktE,1071
32
- otf_api-0.9.0.dist-info/METADATA,sha256=0xUtxE1NRXvulEc_i34wWC5TbFnRJzO-ukPuqMVHNnY,2121
33
- otf_api-0.9.0.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
34
- otf_api-0.9.0.dist-info/RECORD,,
32
+ otf_api-0.9.1.dist-info/LICENSE,sha256=UaPT9ynYigC3nX8n22_rC37n-qmTRKLFaHrtUwF9ktE,1071
33
+ otf_api-0.9.1.dist-info/METADATA,sha256=SPUE5dzWt65jmeoSiWbCY-Tb84vO-x6kOg91kKlvlmg,2296
34
+ otf_api-0.9.1.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
35
+ otf_api-0.9.1.dist-info/RECORD,,