Skip to content

API Reference

User integrations module for third-party service OAuth management.

This module provides CRUD operations and data models for user integration settings including Strava and Garmin Connect OAuth tokens and synchronization preferences.

Exports
  • CRUD: get_user_integrations_by_user_id, create_user_integrations, edit_user_integrations, link_strava_account, unlink_strava_account, set_user_strava_client, set_user_strava_state, set_user_strava_sync_gear, link_garminconnect_account, unlink_garminconnect_account, set_user_garminconnect_sync_gear, get_user_integrations_by_strava_state
  • Schemas: UsersIntegrationsBase, UsersIntegrationsCreate, UsersIntegrationsRead, UsersIntegrationsUpdate
  • Models: UsersIntegrations (ORM model)

UsersIntegrationsBase

Bases: BaseModel

Base schema for user integrations.

Attributes:

Name Type Description
strava_client_id StrictStr | None

Encrypted Strava client ID.

strava_client_secret StrictStr | None

Encrypted Strava client secret.

strava_state StrictStr | None

Temporary state for Strava OAuth flow.

strava_token StrictStr | None

Encrypted Strava access token.

strava_refresh_token StrictStr | None

Encrypted Strava refresh token.

strava_token_expires_at datetime | None

Strava token expiration time.

strava_sync_gear StrictBool

Enable Strava gear synchronization.

garminconnect_oauth1 dict[str, Any] | None

Garmin Connect OAuth1 token data.

garminconnect_oauth2 dict[str, Any] | None

Garmin Connect OAuth2 token data.

garminconnect_sync_gear StrictBool

Enable Garmin Connect gear synchronization.

Source code in backend/app/users/users_integrations/schema.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
class UsersIntegrationsBase(BaseModel):
    """
    Base schema for user integrations.

    Attributes:
        strava_client_id: Encrypted Strava client ID.
        strava_client_secret: Encrypted Strava client secret.
        strava_state: Temporary state for Strava OAuth flow.
        strava_token: Encrypted Strava access token.
        strava_refresh_token: Encrypted Strava refresh token.
        strava_token_expires_at: Strava token expiration time.
        strava_sync_gear: Enable Strava gear synchronization.
        garminconnect_oauth1: Garmin Connect OAuth1 token
            data.
        garminconnect_oauth2: Garmin Connect OAuth2 token
            data.
        garminconnect_sync_gear: Enable Garmin Connect gear
            synchronization.
    """

    strava_client_id: StrictStr | None = Field(
        default=None,
        max_length=512,
        description=("Strava client ID encrypted at rest with Fernet key"),
    )
    strava_client_secret: StrictStr | None = Field(
        default=None,
        max_length=512,
        description=("Strava client secret encrypted at rest with Fernet key"),
    )
    strava_state: StrictStr | None = Field(
        default=None,
        max_length=45,
        description="Strava temporary state for link process",
    )
    strava_token: StrictStr | None = Field(
        default=None,
        max_length=512,
        description=(
            "Strava token after link process encrypted at rest with Fernet key"
        ),
    )
    strava_refresh_token: StrictStr | None = Field(
        default=None,
        max_length=512,
        description=(
            "Strava refresh token after link process "
            "encrypted at rest with Fernet key"
        ),
    )
    strava_token_expires_at: datetime | None = Field(
        default=None, description="Strava token expiration date"
    )
    strava_sync_gear: StrictBool = Field(
        default=False, description="Whether Strava gear is to be synced"
    )
    garminconnect_oauth1: dict[str, Any] | None = Field(
        default=None, description="Garmin OAuth1 token"
    )
    garminconnect_oauth2: dict[str, Any] | None = Field(
        default=None, description="Garmin OAuth2 token"
    )
    garminconnect_sync_gear: StrictBool = Field(
        default=False,
        description="Whether Garmin Connect gear is to be synced",
    )

    model_config = ConfigDict(
        from_attributes=True,
        extra="forbid",
        validate_assignment=True,
    )

UsersIntegrationsCreate

Bases: UsersIntegrationsBase

Pydantic model for creating user integrations.

Inherits all attributes from UsersIntegrationsBase.

Source code in backend/app/users/users_integrations/schema.py
89
90
91
92
93
94
class UsersIntegrationsCreate(UsersIntegrationsBase):
    """
    Pydantic model for creating user integrations.

    Inherits all attributes from UsersIntegrationsBase.
    """

UsersIntegrationsModel

Bases: Base

User third-party service integration settings.

Attributes:

Name Type Description
id Mapped[int]

Primary key.

user_id Mapped[int]

Foreign key to users table (unique).

strava_client_id Mapped[str | None]

Encrypted Strava client ID.

strava_client_secret Mapped[str | None]

Encrypted Strava client secret.

strava_state Mapped[str | None]

Temporary state for Strava OAuth flow.

strava_token Mapped[str | None]

Encrypted Strava access token.

strava_refresh_token Mapped[str | None]

Encrypted Strava refresh token.

strava_token_expires_at Mapped[datetime | None]

Strava token expiration timestamp.

strava_sync_gear Mapped[bool]

Enable Strava gear synchronization.

garminconnect_oauth1 Mapped[dict | None]

Garmin Connect OAuth1 token data.

garminconnect_oauth2 Mapped[dict | None]

Garmin Connect OAuth2 token data.

garminconnect_sync_gear Mapped[bool]

Enable Garmin Connect gear synchronization.

user Mapped[bool]

Relationship to Users model.

Source code in backend/app/users/users_integrations/models.py
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
class UsersIntegrations(Base):
    """
    User third-party service integration settings.

    Attributes:
        id: Primary key.
        user_id: Foreign key to users table (unique).
        strava_client_id: Encrypted Strava client ID.
        strava_client_secret: Encrypted Strava client secret.
        strava_state: Temporary state for Strava OAuth flow.
        strava_token: Encrypted Strava access token.
        strava_refresh_token: Encrypted Strava refresh token.
        strava_token_expires_at: Strava token expiration
            timestamp.
        strava_sync_gear: Enable Strava gear synchronization.
        garminconnect_oauth1: Garmin Connect OAuth1 token
            data.
        garminconnect_oauth2: Garmin Connect OAuth2 token
            data.
        garminconnect_sync_gear: Enable Garmin Connect gear
            synchronization.
        user: Relationship to Users model.
    """

    __tablename__ = "users_integrations"

    id: Mapped[int] = mapped_column(
        primary_key=True,
        autoincrement=True,
    )
    user_id: Mapped[int] = mapped_column(
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False,
        unique=True,
        index=True,
        comment="User ID that the integration belongs",
    )
    strava_client_id: Mapped[str | None] = mapped_column(
        String(length=512),
        default=None,
        nullable=True,
        comment=("Strava client ID encrypted at rest with Fernet key"),
    )
    strava_client_secret: Mapped[str | None] = mapped_column(
        String(length=512),
        default=None,
        nullable=True,
        comment=("Strava client secret encrypted at rest with Fernet key"),
    )
    strava_state: Mapped[str | None] = mapped_column(
        String(length=45),
        default=None,
        nullable=True,
        comment="Strava temporary state for link process",
    )
    strava_token: Mapped[str | None] = mapped_column(
        String(length=512),
        default=None,
        nullable=True,
        comment=("Strava token after link process encrypted at rest with Fernet key"),
    )
    strava_refresh_token: Mapped[str | None] = mapped_column(
        String(length=512),
        default=None,
        nullable=True,
        comment=(
            "Strava refresh token after link process encrypted at rest with Fernet key"
        ),
    )
    strava_token_expires_at: Mapped[datetime | None] = mapped_column(
        default=None,
        nullable=True,
        comment="Strava token expiration date",
    )
    strava_sync_gear: Mapped[bool] = mapped_column(
        nullable=False,
        default=False,
        comment="Whether Strava gear is to be synced",
    )
    garminconnect_oauth1: Mapped[dict | None] = mapped_column(
        JSON,
        default=None,
        nullable=True,
        comment="Garmin OAuth1 token",
    )
    garminconnect_oauth2: Mapped[dict | None] = mapped_column(
        JSON,
        default=None,
        nullable=True,
        comment="Garmin OAuth2 token",
    )
    garminconnect_sync_gear: Mapped[bool] = mapped_column(
        nullable=False,
        default=False,
        comment="Whether Garmin Connect gear is to be synced",
    )

    # Define a relationship to the Users model
    # TODO: Change to Mapped["User"] when all modules use mapped
    users = relationship("Users", back_populates="users_integrations")

UsersIntegrationsRead

Bases: UsersIntegrationsBase

Schema for reading user integrations.

Attributes:

Name Type Description
id StrictInt

Unique identifier for the integrations record.

user_id StrictInt

Foreign key reference to the user.

Source code in backend/app/users/users_integrations/schema.py
106
107
108
109
110
111
112
113
114
115
116
117
118
class UsersIntegrationsRead(UsersIntegrationsBase):
    """
    Schema for reading user integrations.

    Attributes:
        id: Unique identifier for the integrations record.
        user_id: Foreign key reference to the user.
    """

    id: StrictInt = Field(..., ge=1, description="Unique identifier for integrations")
    user_id: StrictInt = Field(
        ..., ge=1, description="Foreign key reference to the user"
    )

UsersIntegrationsUpdate

Bases: UsersIntegrationsBase

Schema for updating user integrations.

Inherits all validation from UsersIntegrationsBase. All fields are optional for partial updates.

Source code in backend/app/users/users_integrations/schema.py
 97
 98
 99
100
101
102
103
class UsersIntegrationsUpdate(UsersIntegrationsBase):
    """
    Schema for updating user integrations.

    Inherits all validation from UsersIntegrationsBase.
    All fields are optional for partial updates.
    """

create_user_integrations

create_user_integrations(user_id, db)

Create integration settings for a user.

Parameters:

Name Type Description Default
user_id int

The ID of the user to create integrations for.

required
db Session

SQLAlchemy database session.

required

Returns:

Type Description
UsersIntegrations

The created UsersIntegrations model.

Raises:

Type Description
HTTPException

409 error if integrations already exist.

HTTPException

500 error if database operation fails.

Source code in backend/app/users/users_integrations/crud.py
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
@core_decorators.handle_db_errors
def create_user_integrations(
    user_id: int, db: Session
) -> user_integrations_models.UsersIntegrations:
    """
    Create integration settings for a user.

    Args:
        user_id: The ID of the user to create integrations for.
        db: SQLAlchemy database session.

    Returns:
        The created UsersIntegrations model.

    Raises:
        HTTPException: 409 error if integrations already exist.
        HTTPException: 500 error if database operation fails.
    """
    try:
        # Create a new user integrations with model defaults
        user_integrations = user_integrations_models.UsersIntegrations(
            user_id=user_id,
        )

        # Add the user integrations to the database
        db.add(user_integrations)
        db.commit()
        db.refresh(user_integrations)

        # Return the user integrations
        return user_integrations
    except IntegrityError as integrity_error:
        # Rollback the transaction
        db.rollback()

        # Raise an HTTPException with a 409 Conflict status code
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="Integrations already exist for this user",
        ) from integrity_error

edit_user_integrations

edit_user_integrations(user_integrations, user_id, db)

Update user integration settings.

Parameters:

Name Type Description Default
user_integrations UsersIntegrationsUpdate

Schema with fields to update.

required
user_id int

The ID of the user to update.

required
db Session

SQLAlchemy database session.

required

Returns:

Type Description
UsersIntegrations

The updated UsersIntegrations model.

Raises:

Type Description
HTTPException

404 error if integrations not found.

HTTPException

500 error if database operation fails.

Source code in backend/app/users/users_integrations/crud.py
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
@core_decorators.handle_db_errors
def edit_user_integrations(
    user_integrations: user_integrations_schema.UsersIntegrationsUpdate,
    user_id: int,
    db: Session,
) -> user_integrations_models.UsersIntegrations:
    """
    Update user integration settings.

    Args:
        user_integrations: Schema with fields to update.
        user_id: The ID of the user to update.
        db: SQLAlchemy database session.

    Returns:
        The updated UsersIntegrations model.

    Raises:
        HTTPException: 404 error if integrations not found.
        HTTPException: 500 error if database operation fails.
    """
    # Get the user integrations from the database
    db_user_integrations = get_user_integrations_by_user_id(user_id, db)

    if db_user_integrations is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User integrations not found",
        )

    # Get fields to update
    user_integrations_data = user_integrations.model_dump(
        exclude_unset=True, exclude={"user_id", "id"}
    )
    # Update fields dynamically
    for key, value in user_integrations_data.items():
        setattr(db_user_integrations, key, value)

    # Commit the transaction
    db.commit()
    db.refresh(db_user_integrations)
    return db_user_integrations

get_user_integrations_by_strava_state

get_user_integrations_by_strava_state(strava_state, db)

Retrieve integrations by Strava OAuth state token.

Parameters:

Name Type Description Default
strava_state str

The Strava OAuth state to search for.

required
db Session

SQLAlchemy database session.

required

Returns:

Type Description
UsersIntegrations | None

The UsersIntegrations model if found, None otherwise.

Raises:

Type Description
HTTPException

500 error if database query fails.

Source code in backend/app/users/users_integrations/crud.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@core_decorators.handle_db_errors
def get_user_integrations_by_strava_state(
    strava_state: str, db: Session
) -> user_integrations_models.UsersIntegrations | None:
    """
    Retrieve integrations by Strava OAuth state token.

    Args:
        strava_state: The Strava OAuth state to search for.
        db: SQLAlchemy database session.

    Returns:
        The UsersIntegrations model if found, None otherwise.

    Raises:
        HTTPException: 500 error if database query fails.
    """
    # Get user integrations based on the strava state
    stmt = select(user_integrations_models.UsersIntegrations).where(
        user_integrations_models.UsersIntegrations.strava_state == strava_state
    )
    return db.execute(stmt).scalar_one_or_none()

get_user_integrations_by_user_id

get_user_integrations_by_user_id(user_id, db)

Retrieve integrations for a specific user.

Parameters:

Name Type Description Default
user_id int

The ID of the user to fetch integrations for.

required
db Session

SQLAlchemy database session.

required

Returns:

Type Description
UsersIntegrations | None

The UsersIntegrations model for the user.

Raises:

Type Description
HTTPException

404 error if integrations not found.

HTTPException

500 error if database query fails.

Source code in backend/app/users/users_integrations/crud.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@core_decorators.handle_db_errors
def get_user_integrations_by_user_id(
    user_id: int, db: Session
) -> user_integrations_models.UsersIntegrations | None:
    """
    Retrieve integrations for a specific user.

    Args:
        user_id: The ID of the user to fetch integrations for.
        db: SQLAlchemy database session.

    Returns:
        The UsersIntegrations model for the user.

    Raises:
        HTTPException: 404 error if integrations not found.
        HTTPException: 500 error if database query fails.
    """
    # Get the user integrations by the user id
    stmt = select(user_integrations_models.UsersIntegrations).where(
        user_integrations_models.UsersIntegrations.user_id == user_id
    )
    return db.execute(stmt).scalar_one_or_none()
link_garminconnect_account(user_id, oauth1_token, oauth2_token, db)

Link a Garmin Connect account by storing OAuth tokens.

Parameters:

Name Type Description Default
user_id int

The ID of the user.

required
oauth1_token dict

Garmin Connect OAuth1 token data.

required
oauth2_token dict

Garmin Connect OAuth2 token data.

required
db Session

SQLAlchemy database session.

required

Returns:

Type Description
None

None

Raises:

Type Description
HTTPException

404 error if integrations not found.

HTTPException

500 error if database operation fails.

Source code in backend/app/users/users_integrations/crud.py
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
@core_decorators.handle_db_errors
def link_garminconnect_account(
    user_id: int,
    oauth1_token: dict,
    oauth2_token: dict,
    db: Session,
) -> None:
    """
    Link a Garmin Connect account by storing OAuth tokens.

    Args:
        user_id: The ID of the user.
        oauth1_token: Garmin Connect OAuth1 token data.
        oauth2_token: Garmin Connect OAuth2 token data.
        db: SQLAlchemy database session.

    Returns:
        None

    Raises:
        HTTPException: 404 error if integrations not found.
        HTTPException: 500 error if database operation fails.
    """
    # Get the user integrations by the user id
    user_integrations = get_user_integrations_by_user_id(user_id, db)

    if user_integrations is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User integrations not found",
        )

    # Store Garmin Connect OAuth tokens
    user_integrations.garminconnect_oauth1 = oauth1_token
    user_integrations.garminconnect_oauth2 = oauth2_token

    # Commit the changes to the database
    db.commit()
    db.refresh(user_integrations)
link_strava_account(user_integrations, tokens, db)

Link a Strava account by storing OAuth tokens.

Parameters:

Name Type Description Default
user_integrations UsersIntegrations

The UsersIntegrations ORM model to update.

required
tokens dict

Dictionary containing access_token, refresh_token, and expires_at.

required
db Session

SQLAlchemy database session.

required

Returns:

Type Description
None

None

Raises:

Type Description
HTTPException

500 error if database operation fails.

Source code in backend/app/users/users_integrations/crud.py
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
@core_decorators.handle_db_errors
def link_strava_account(
    user_integrations: user_integrations_models.UsersIntegrations,
    tokens: dict,
    db: Session,
) -> None:
    """
    Link a Strava account by storing OAuth tokens.

    Args:
        user_integrations: The UsersIntegrations ORM model to
            update.
        tokens: Dictionary containing access_token,
            refresh_token, and expires_at.
        db: SQLAlchemy database session.

    Returns:
        None

    Raises:
        HTTPException: 500 error if database operation fails.
    """
    # Update the user integrations with the tokens
    user_integrations.strava_token = core_cryptography.encrypt_token_fernet(
        tokens["access_token"]
    )
    user_integrations.strava_refresh_token = core_cryptography.encrypt_token_fernet(
        tokens["refresh_token"]
    )
    user_integrations.strava_token_expires_at = datetime.fromtimestamp(
        tokens["expires_at"]
    )

    # Set the strava state to None
    user_integrations.strava_state = None

    # Commit the changes to the database
    db.commit()
    db.refresh(user_integrations)

set_user_garminconnect_sync_gear

set_user_garminconnect_sync_gear(user_id, garminconnect_sync_gear, db)

Set Garmin Connect gear synchronization preference.

Parameters:

Name Type Description Default
user_id int

The ID of the user.

required
garminconnect_sync_gear bool

Whether to sync gear from Garmin Connect.

required
db Session

SQLAlchemy database session.

required

Returns:

Type Description
None

None

Raises:

Type Description
HTTPException

404 error if integrations not found.

HTTPException

500 error if database operation fails.

Source code in backend/app/users/users_integrations/crud.py
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
@core_decorators.handle_db_errors
def set_user_garminconnect_sync_gear(
    user_id: int, garminconnect_sync_gear: bool, db: Session
) -> None:
    """
    Set Garmin Connect gear synchronization preference.

    Args:
        user_id: The ID of the user.
        garminconnect_sync_gear: Whether to sync gear from
            Garmin Connect.
        db: SQLAlchemy database session.

    Returns:
        None

    Raises:
        HTTPException: 404 error if integrations not found.
        HTTPException: 500 error if database operation fails.
    """
    # Get the user integrations by the user id
    user_integrations = get_user_integrations_by_user_id(user_id, db)

    if user_integrations is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User integrations not found",
        )

    # Set the Garmin Connect gear sync preference
    user_integrations.garminconnect_sync_gear = garminconnect_sync_gear

    # Commit the changes to the database
    db.commit()
    db.refresh(user_integrations)

set_user_strava_client

set_user_strava_client(user_id, client_id, client_secret, db)

Set Strava client credentials for a user.

Parameters:

Name Type Description Default
user_id int

The ID of the user.

required
client_id str

Strava client ID to encrypt and store.

required
client_secret str

Strava client secret to encrypt and store.

required
db Session

SQLAlchemy database session.

required

Returns:

Type Description
None

None

Raises:

Type Description
HTTPException

404 error if integrations not found.

HTTPException

500 error if database operation fails.

Source code in backend/app/users/users_integrations/crud.py
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
@core_decorators.handle_db_errors
def set_user_strava_client(
    user_id: int, client_id: str, client_secret: str, db: Session
) -> None:
    """
    Set Strava client credentials for a user.

    Args:
        user_id: The ID of the user.
        client_id: Strava client ID to encrypt and store.
        client_secret: Strava client secret to encrypt and store.
        db: SQLAlchemy database session.

    Returns:
        None

    Raises:
        HTTPException: 404 error if integrations not found.
        HTTPException: 500 error if database operation fails.
    """
    # Get the user integrations by the user id
    user_integrations = get_user_integrations_by_user_id(user_id, db)

    if user_integrations is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User integrations not found",
        )

    # Encrypt and store Strava client credentials
    user_integrations.strava_client_id = core_cryptography.encrypt_token_fernet(
        client_id
    )
    user_integrations.strava_client_secret = core_cryptography.encrypt_token_fernet(
        client_secret
    )

    # Commit the changes to the database
    db.commit()
    db.refresh(user_integrations)

set_user_strava_state

set_user_strava_state(user_id, state, db)

Set or clear Strava OAuth state for a user.

Parameters:

Name Type Description Default
user_id int

The ID of the user.

required
state str | None

Strava OAuth state to set, or None to clear.

required
db Session

SQLAlchemy database session.

required

Returns:

Type Description
None

None

Raises:

Type Description
HTTPException

404 error if integrations not found.

HTTPException

500 error if database operation fails.

Source code in backend/app/users/users_integrations/crud.py
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
@core_decorators.handle_db_errors
def set_user_strava_state(user_id: int, state: str | None, db: Session) -> None:
    """
    Set or clear Strava OAuth state for a user.

    Args:
        user_id: The ID of the user.
        state: Strava OAuth state to set, or None to clear.
        db: SQLAlchemy database session.

    Returns:
        None

    Raises:
        HTTPException: 404 error if integrations not found.
        HTTPException: 500 error if database operation fails.
    """
    # Get the user integrations by the user id
    user_integrations = get_user_integrations_by_user_id(user_id, db)

    if user_integrations is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User integrations not found",
        )

    # Set the user Strava state
    user_integrations.strava_state = None if state in ("null", None) else state

    # Commit the changes to the database
    db.commit()
    db.refresh(user_integrations)

set_user_strava_sync_gear

set_user_strava_sync_gear(user_id, strava_sync_gear, db)

Set Strava gear synchronization preference for a user.

Parameters:

Name Type Description Default
user_id int

The ID of the user.

required
strava_sync_gear bool

Whether to sync gear from Strava.

required
db Session

SQLAlchemy database session.

required

Returns:

Type Description
None

None

Raises:

Type Description
HTTPException

404 error if integrations not found.

HTTPException

500 error if database operation fails.

Source code in backend/app/users/users_integrations/crud.py
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
@core_decorators.handle_db_errors
def set_user_strava_sync_gear(
    user_id: int, strava_sync_gear: bool, db: Session
) -> None:
    """
    Set Strava gear synchronization preference for a user.

    Args:
        user_id: The ID of the user.
        strava_sync_gear: Whether to sync gear from Strava.
        db: SQLAlchemy database session.

    Returns:
        None

    Raises:
        HTTPException: 404 error if integrations not found.
        HTTPException: 500 error if database operation fails.
    """
    # Get the user integrations by the user id
    user_integrations = get_user_integrations_by_user_id(user_id, db)

    if user_integrations is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User integrations not found",
        )

    # Set the Strava gear sync preference
    user_integrations.strava_sync_gear = strava_sync_gear

    # Commit the changes to the database
    db.commit()
    db.refresh(user_integrations)
unlink_garminconnect_account(user_id, db)

Unlink a Garmin Connect account by clearing OAuth tokens.

Parameters:

Name Type Description Default
user_id int

The ID of the user to unlink.

required
db Session

SQLAlchemy database session.

required

Returns:

Type Description
None

None

Raises:

Type Description
HTTPException

404 error if integrations not found.

HTTPException

500 error if database operation fails.

Source code in backend/app/users/users_integrations/crud.py
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
@core_decorators.handle_db_errors
def unlink_garminconnect_account(user_id: int, db: Session) -> None:
    """
    Unlink a Garmin Connect account by clearing OAuth tokens.

    Args:
        user_id: The ID of the user to unlink.
        db: SQLAlchemy database session.

    Returns:
        None

    Raises:
        HTTPException: 404 error if integrations not found.
        HTTPException: 500 error if database operation fails.
    """
    # Get the user integrations by the user id
    user_integrations = get_user_integrations_by_user_id(user_id, db)

    if user_integrations is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User integrations not found",
        )

    # Clear all Garmin Connect integration data
    user_integrations.garminconnect_oauth1 = None
    user_integrations.garminconnect_oauth2 = None
    user_integrations.garminconnect_sync_gear = False

    # Commit the changes to the database
    db.commit()
    db.refresh(user_integrations)
unlink_strava_account(user_id, db)

Unlink a Strava account by clearing OAuth tokens.

Parameters:

Name Type Description Default
user_id int

The ID of the user to unlink.

required
db Session

SQLAlchemy database session.

required

Returns:

Type Description
None

None

Raises:

Type Description
HTTPException

404 error if integrations not found.

HTTPException

500 error if database operation fails.

Source code in backend/app/users/users_integrations/crud.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
@core_decorators.handle_db_errors
def unlink_strava_account(user_id: int, db: Session) -> None:
    """
    Unlink a Strava account by clearing OAuth tokens.

    Args:
        user_id: The ID of the user to unlink.
        db: SQLAlchemy database session.

    Returns:
        None

    Raises:
        HTTPException: 404 error if integrations not found.
        HTTPException: 500 error if database operation fails.
    """
    # Get the user integrations by the user id
    user_integrations = get_user_integrations_by_user_id(user_id, db)

    if user_integrations is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User integrations not found",
        )

    # Clear all Strava integration data
    user_integrations.strava_state = None
    user_integrations.strava_token = None
    user_integrations.strava_refresh_token = None
    user_integrations.strava_token_expires_at = None
    user_integrations.strava_sync_gear = False
    user_integrations.strava_client_id = None
    user_integrations.strava_client_secret = None

    # Commit the changes to the database
    db.commit()
    db.refresh(user_integrations)