Skip to content

User

CLASS DESCRIPTION
User

Python interface for Planka Users

User

User(schema: Schema, session: Planka)

Bases: PlankaModel[User]

Python interface for Planka Users

METHOD DESCRIPTION
add_notification_service

Add/Copy an existing NotificationService to this User

add_to_board

Add the User to a board

add_to_card

Add the User to a Card

copy

Create a deepcopy of the model and its associated schema.

create_notification_service

Create a NEW Notification Service

delete

Delete the User

delete_notification_service

Deletes a NotificationService for a User

diff

Get a schema diff between two model schemas.

remove_from_board

Remove the User from a Board

remove_from_card

Remove the User from a Card

sync

Sync the User with the Planka server (Can only sync your own User)

update

Update the User

update_avatar

Update the User avatar

update_email

Update the current User's email

update_password

Update the User's password

ATTRIBUTE DESCRIPTION
__formatter__

Formatter func that allows overriding str behavior for models

TYPE: ModelFormatter[Self]

avatar

Avatar information for the user with generated URLs

TYPE: dict[str, Any]

created_at

When the user was created

TYPE: datetime

default_editor_mode

Default markdown editor mode (personal field)

TYPE: EditorMode

default_home_view

Default view mode for the home page (personal field)

TYPE: HomeView | None

default_projects_order

Default sort order for projects display (personal field)

TYPE: ProjectOrdering | None

email

Email address for login and notifications (private field)

TYPE: str | None

enable_favorites_by_default

Whether favorites are enabled by default (personal field)

TYPE: bool

gravatar_url

Gravatar URL for the user (conditionally added if configured)

TYPE: str | None

is_deactivated

Whether the user account is deactivated and cannot log in

TYPE: bool

is_default_admin

Whether the user is the default admin (visible only to current user or admin)

TYPE: bool

is_sso_user

Whether the user is SSO user (private field)

TYPE: bool

language

Preferred language for user interface and notifications (personal field)

TYPE: Language | None

locked_field_names

List of fields locked from editing (visible only to current user or admin)

TYPE: list[LockableField]

name

Full display name of the user

TYPE: str

notification_services

Get all User NotificationServices

TYPE: list[NotificationService]

organization

Organization or company name

TYPE: str

phone

Contact phone number

TYPE: str

role

User role defining access permissions

subscribe_to_card_when_commenting

Whether the user subscribes to cards when commenting (personal field)

TYPE: bool

subscribe_to_own_cards

Whether the user subscribes to their own cards (personal field)

TYPE: bool

terms_type

Type of terms applicable to the user based on role

TYPE: TermsType

turn_off_recent_card_highlighting

Whether recent card highlighting is disabled (personal field)

TYPE: bool

updated_at

When the user was last updated

TYPE: datetime

username

Unique username for user identification

TYPE: str

Source code in src/plankapy/v2/models/_base.py
30
31
32
33
34
35
36
def __init__(self, schema: Schema, session: Planka) -> None:
    self._schema = schema
    self.session = session
    self.endpoints = session.endpoints
    self.client = session.client
    self.current_role = session.current_role
    self.current_id = session.current_id

__formatter__ class-attribute instance-attribute

__formatter__: ModelFormatter[Self] = DEFAULT_FORMATTER

Formatter func that allows overriding str behavior for models

avatar property writable

avatar: dict[str, Any]

Avatar information for the user with generated URLs

created_at property

created_at: datetime

When the user was created

default_editor_mode property writable

default_editor_mode: EditorMode

Default markdown editor mode (personal field)

default_home_view property writable

default_home_view: HomeView | None

Default view mode for the home page (personal field)

default_projects_order property writable

default_projects_order: ProjectOrdering | None

Default sort order for projects display (personal field)

email property writable

email: str | None

Email address for login and notifications (private field)

enable_favorites_by_default property writable

enable_favorites_by_default: bool

Whether favorites are enabled by default (personal field)

gravatar_url property

gravatar_url: str | None

Gravatar URL for the user (conditionally added if configured)

is_deactivated property

is_deactivated: bool

Whether the user account is deactivated and cannot log in

is_default_admin property

is_default_admin: bool

Whether the user is the default admin (visible only to current user or admin)

is_sso_user property

is_sso_user: bool

Whether the user is SSO user (private field)

language property writable

language: Language | None

Preferred language for user interface and notifications (personal field)

locked_field_names property

locked_field_names: list[LockableField]

List of fields locked from editing (visible only to current user or admin)

name property writable

name: str

Full display name of the user

notification_services property

notification_services: list[NotificationService]

Get all User NotificationServices

organization property writable

organization: str

Organization or company name

phone property writable

phone: str

Contact phone number

role property writable

role

User role defining access permissions

subscribe_to_card_when_commenting property writable

subscribe_to_card_when_commenting: bool

Whether the user subscribes to cards when commenting (personal field)

subscribe_to_own_cards property writable

subscribe_to_own_cards: bool

Whether the user subscribes to their own cards (personal field)

terms_type property

terms_type: TermsType

Type of terms applicable to the user based on role

turn_off_recent_card_highlighting property writable

turn_off_recent_card_highlighting: bool

Whether recent card highlighting is disabled (personal field)

updated_at property

updated_at: datetime

When the user was last updated

username property

username: str

Unique username for user identification

add_notification_service

add_notification_service(notification_service: NotificationService, *, url: str | None = None, format: NotificationServiceFormat | None = None) -> NotificationService

Add/Copy an existing NotificationService to this User

PARAMETER DESCRIPTION

notificaiton_service

The NotificaitonService to add

TYPE: NotificaitonService

url

Optional url override (default: from notification_service)

TYPE: str | None DEFAULT: None

format

Optional format override (default: from notification_service)

TYPE: NotificationServiceFormat | None DEFAULT: None

Source code in src/plankapy/v2/models/user.py
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
def add_notification_service(self, notification_service: NotificationService, 
                             *, 
                             url: str|None=None, 
                             format: NotificationServiceFormat|None=None) -> NotificationService:
    """Add/Copy an existing NotificationService to this User

    Args:
        notificaiton_service (NotificaitonService): The NotificaitonService to add
        url (str | None): Optional url override (default: from notification_service)
        format (NotificationServiceFormat | None): Optional format override (default: from notification_service)
    """
    if notification_service not in self.notification_services:
        return self.create_notification_service(
            url=url or notification_service.url,
            format=format or notification_service.format
        )
    return notification_service

add_to_board

add_to_board(board: Board, *, role: BoardRole = 'viewer', can_comment: bool = False) -> None

Add the User to a board

PARAMETER DESCRIPTION

role

The role of the User in the Board (default: viewer)

TYPE: Literal['viewer', 'editor'] DEFAULT: 'viewer'

can_comment

The comment permission for the user if role is set to viewer (default: False)

TYPE: bool DEFAULT: False

Note

If the User is already a Board member, but the role or comment permission are different, the User role and comment permission will be updated

Source code in src/plankapy/v2/models/user.py
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
def add_to_board(self, board: Board, 
                 *,
                 role: BoardRole='viewer',
                 can_comment: bool=False) -> None:
    """Add the User to a board

    Args:
        role (Literal['viewer', 'editor']): The role of the User in the Board (default: `viewer`)
        can_comment (bool): The comment permission for the user if `role` is set to `viewer` (default: `False`)

    Note:
        If the User is already a Board member, but the role or comment permission are different, 
        the User role and comment permission will be updated
    """
    board.add_member(self, role=role, can_comment=can_comment)

add_to_card

add_to_card(card: Card) -> None

Add the User to a Card

PARAMETER DESCRIPTION

card

The Card to add the user to (must be a member of the Card's Board)

TYPE: Card

RAISES DESCRIPTION
PermissionError

If the User is not a member of the Card's Board

Note

If the User is already a Card member, no changes will be made

Source code in src/plankapy/v2/models/user.py
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
def add_to_card(self, card: Card) -> None:
    """Add the User to a Card

    Args:
        card (Card): The Card to add the user to (must be a member of the Card's Board)

    Raises:
        PermissionError: If the User is not a member of the Card's Board

    Note:
        If the User is already a Card member, no changes will be made
    """

    if self not in card.board.users:
        raise PermissionError(f'User is not a member of the Board')

    if self not in card.members:
        self.endpoints.createCardMembership(card.id, userId=self.id)

copy

copy() -> Self

Create a deepcopy of the model and its associated schema.

Note

Since the endpoints for both instances of the Model are the same, any calls to update will restore the state and bring both copies into sync. copies like this are meant more for comparing changes when running a sync or update/assignemnt operation.

Example:

    >>> card_copy = card.copy()
    >>> card.name = 'Updated Name'
    >>> card_copy.name
    'Original Name'
    >>> card.name
    'Updated Name'
    >>> # This update may have had side effects
    >>> print(card_copy.diff(card))
    {'name': ('Original Name', 'Updated Name'), 'updatedAt': ('...2:00pm', '...2:45pm'), ...}

Source code in src/plankapy/v2/models/_base.py
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
def copy(self) -> Self:
    """Create a deepcopy of the model and its associated schema.

    Note:
        Since the endpoints for both instances of the Model are the same, any 
        calls to update will restore the state and bring both copies into sync. 
        copies like this are meant more for comparing changes when running a sync 
        or update/assignemnt operation.

    Example:
    ```python
        >>> card_copy = card.copy()
        >>> card.name = 'Updated Name'
        >>> card_copy.name
        'Original Name'
        >>> card.name
        'Updated Name'
        >>> # This update may have had side effects
        >>> print(card_copy.diff(card))
        {'name': ('Original Name', 'Updated Name'), 'updatedAt': ('...2:00pm', '...2:45pm'), ...}
    ```
    """
    return copy.deepcopy(self)

create_notification_service

create_notification_service(**kwargs: Unpack[Request_createUserNotificationService]) -> NotificationService

Create a NEW Notification Service

PARAMETER DESCRIPTION

url

The webhook URL for the NotificationService

TYPE: str

format

The format of the NotificationService (default: text)

TYPE: NotificationServiceFormat

Source code in src/plankapy/v2/models/user.py
420
421
422
423
424
425
426
427
def create_notification_service(self, **kwargs: Unpack[paths.Request_createUserNotificationService]) -> NotificationService:
    """Create a NEW Notification Service

    Args:
        url (str): The webhook URL for the NotificationService
        format (NotificationServiceFormat): The format of the NotificationService (default: `text`)
    """
    return NotificationService(self.endpoints.createUserNotificationService(self.id, **kwargs)['item'], self.session)

delete

delete()

Delete the User

Source code in src/plankapy/v2/models/user.py
231
232
233
def delete(self):
    """Delete the User"""
    return self.endpoints.deleteUser(self.id)

delete_notification_service

delete_notification_service(notification_service: NotificationService) -> None

Deletes a NotificationService for a User

PARAMETER DESCRIPTION

notificaiton_service

The NotificaitonService to delete

TYPE: NotificaitonService

Source code in src/plankapy/v2/models/user.py
429
430
431
432
433
434
435
436
def delete_notification_service(self, notification_service: NotificationService) -> None:
    """Deletes a NotificationService for a User

    Args:
        notificaiton_service (NotificaitonService): The NotificaitonService to delete
    """
    if notification_service in self.notification_services:
        notification_service.delete()

diff

diff(other: PlankaModel[Schema]) -> Diff

Get a schema diff between two model schemas.

Note

Only matching keys are diffed. Any schema keys that are not in the source schema will not be checked in the target schema

Source code in src/plankapy/v2/models/_base.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def diff(self, other: PlankaModel[Schema]) -> Diff:
    """Get a schema diff between two model schemas.

    Note:
        Only matching keys are diffed. Any schema keys that are not in the source schema 
        will not be checked in the target schema
    """
    return {
        k: (source, delta) 
        for k, source in self.schema
        if k in other.schema
        and (delta := other.schema[k]) 
        and delta != source
    }

remove_from_board

remove_from_board(board: Board) -> None

Remove the User from a Board

Note

If the User is not a Board member, no change will be made

Source code in src/plankapy/v2/models/user.py
393
394
395
396
397
398
399
400
def remove_from_board(self, board: Board) -> None:
    """Remove the User from a Board

    Note:
        If the User is not a Board member, no change will be made
    """
    if self in board.users:
        board.remove_user(self)

remove_from_card

remove_from_card(card: Card) -> None

Remove the User from a Card

PARAMETER DESCRIPTION

card

The Card to remove the User from

TYPE: Card

Note

if the User is not a member of the Card, no change will be made

Source code in src/plankapy/v2/models/user.py
365
366
367
368
369
370
371
372
373
374
375
def remove_from_card(self, card: Card) -> None:
    """Remove the User from a Card

    Args:
        card (Card): The Card to remove the User from

    Note:
        if the User is not a member of the Card, no change will be made
    """
    if self in card.members:
        card.remove_member(self)

sync

sync()

Sync the User with the Planka server (Can only sync your own User)

Source code in src/plankapy/v2/models/user.py
222
223
224
225
def sync(self):
    """Sync the User with the Planka server (Can only sync your own User)"""
    if self.id == self.session.me.id:
        self.schema = self.session.me.schema

update

update(**kwargs: Unpack[Request_updateUser])

Update the User

Source code in src/plankapy/v2/models/user.py
227
228
229
def update(self, **kwargs: Unpack[paths.Request_updateUser]):
    """Update the User"""
    self.schema = self.endpoints.updateUser(self.id, **kwargs)['item']

update_avatar

update_avatar(avatar: str | bytes | None) -> User

Update the User avatar

You can pass a filepath, URL, raw bytes, or None to the avatar argument. Only Admins can update other User's avatars

PARAMETER DESCRIPTION

avatar

filepath/URL or file bytes or None to clear

TYPE: str | bytes | None

RETURNS DESCRIPTION
User

The updated User

TYPE: User

Source code in src/plankapy/v2/models/user.py
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
261
262
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
def update_avatar(self, avatar: str | bytes | None) -> User:
    """Update the User avatar

    You can pass a filepath, URL, raw bytes, or None to the avatar argument. 
    Only Admins can update other User's avatars

    Args:
        avatar (str | bytes | None): filepath/URL or file bytes or None to clear

    Returns:
        User: The updated User
    """
    # Force a PermissionError early if this user isn't the current user or an admin
    if self.id != self.session.current_id and self.session.current_role != 'admin':
        self.endpoints.updateUserAvatar(self.id, **{'file': b'NO_PERMISSION'})

    if avatar is None:
        self.avatar = None
        return self

    # Deferred import of mimetypes that is only used here
    # This function takes so long anyways so the import delay 
    # isn't noticable
    import mimetypes

    # Handle filepath or URL
    mime_type = None
    if isinstance(avatar, str):
        # Guess URL file type
        if avatar.startswith('http'):
            mime_type, *_ = mimetypes.guess_type(avatar)
            mime_type = mime_type or 'application/octet-stream'
            try:
                req = self.client.get(avatar)
                req.raise_for_status()
                avatar = req.content
            except HTTPStatusError as status_error:
                status_error.add_note(f'Unable to download attachment from {avatar}')
                raise
        # Guess local file type
        # And read Bytes
        else:
            mime_type, *_ = mimetypes.guess_file_type(avatar)
            mime_type = mime_type or 'application/octet-stream'
            avatar = open(avatar, 'rb').read()

    mime_type = mime_type or 'application/octet-stream'
    self.endpoints.updateUserAvatar(
        self.id, 
        file=bytes(avatar), 
        mime_type=mime_type,
    )
    return self

update_email

update_email(email: str, *, password: str | None = None) -> None

Update the current User's email

PARAMETER DESCRIPTION

password

The User's password (required if not admin)

TYPE: str DEFAULT: None

RAISES DESCRIPTION
PermissionError

If the current user is not admin and attempts to set another user's password

PermissionError

If the current user is not admin and the password arg is not set

HTTPStatusError

If the password is wrong or the update operation fails

Source code in src/plankapy/v2/models/user.py
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
def update_email(self, email: str, 
                 *, 
                 password: str|None=None) -> None:
    """Update the current User's email

    Args:
        password (str): The User's password (required if not admin)

    Raises:
        PermissionError: If the current user is not admin and attempts to set another user's password
        PermissionError: If the current user is not admin and the `password` arg is not set
        HTTPStatusError: If the password is wrong or the update operation fails
    """

    # Allow Admins to set user email directly or ignore password kwarg
    if self.current_role == 'admin':
        self.endpoints.updateUserEmail(self.id, email=email)
        return

    if self.current_id != self.id:
        raise PermissionError(f'Cannot set other User emails unless admin')

    if not password:
        raise PermissionError(f'User password required to update email!')

    self.endpoints.updateUserEmail(self.id, email=email, currentPassword=password)

update_password

update_password(*, new_password: str, current_password: str | None = None) -> None

Update the User's password

PARAMETER DESCRIPTION

new_password

The new password to use

TYPE: str

current_password

The User's current password (required for non-admin)

TYPE: str DEFAULT: None

RAISES DESCRIPTION
PermissionError

If a non-admin attempts to update another user's password

PermissionError

If a user attempts to update their own password without passing a current_password

HTTPStatusError

If the password is wrong or the update operation fails

Source code in src/plankapy/v2/models/user.py
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
def update_password(self, 
                    *, 
                    new_password: str, 
                    current_password: str|None=None) -> None:
    """Update the User's password

    Args:
        new_password (str): The new password to use
        current_password (str): The User's current password (required for non-admin)

    Raises:
        PermissionError: If a non-admin attempts to update another user's password
        PermissionError: If a user attempts to update their own password without passing a `current_password`
        HTTPStatusError: If the password is wrong or the update operation fails
    """
    # Admins can set any User password
    if self.current_role == 'admin':
        self.endpoints.updateUserPassword(self.id, password=new_password)
        return

    # Users's cannot set other user's passwords
    if self.current_id != self.id:
        raise PermissionError(f"Cannot set another User's password! (must be admin)")

    # Password change required current password
    if not current_password:
        raise PermissionError(f'Cannot set other User passwords unless admin')

    self.endpoints.updateUserPassword(self.id, password=new_password, currentPassword=current_password)