Skip to content

Organization

toggl_api.OrganizationEndpoint

Bases: TogglCachedEndpoint[TogglOrganization]

Endpoint to do with handling organization specific details.

Official Documentation

Examples:

>>> org_endpoint = OrganizationEndpoint(BasicAuth(...), SqliteCache(...))

Parameters:

  • auth (BasicAuth) –

    Authentication for the client.

  • cache (TogglCache[TogglOrganization]) –

    Cache object where trackers are stored.

  • timeout (int, default: 10 ) –

    How long it takes for the client to timeout. Keyword Only. Defaults to 10 seconds.

  • re_raise (bool, default: False ) –

    Whether to raise HTTPStatusError errors and not handle them internally. Keyword Only.

  • retries (int, default: 3 ) –

    Max retries to attempt if the server returns a 5xx status_code. Has no effect if re_raise is True. Keyword Only.

Source code in toggl_api/organization.py
 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
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
146
147
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
185
186
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
227
228
229
class OrganizationEndpoint(TogglCachedEndpoint[TogglOrganization]):
    """Endpoint to do with handling organization specific details.

    [Official Documentation](https://engineering.toggl.com/docs/api/organizations)

    Examples:
        >>> org_endpoint = OrganizationEndpoint(BasicAuth(...), SqliteCache(...))

    Params:
        auth: Authentication for the client.
        cache: Cache object where trackers are stored.
        timeout: How long it takes for the client to timeout. Keyword Only.
            Defaults to 10 seconds.
        re_raise: Whether to raise HTTPStatusError errors and not handle them
            internally. Keyword Only.
        retries: Max retries to attempt if the server returns a *5xx* status_code.
            Has no effect if re_raise is `True`. Keyword Only.
    """

    def __init__(
        self,
        auth: BasicAuth,
        cache: TogglCache[TogglOrganization],
        *,
        timeout: int = 10,
        re_raise: bool = False,
        retries: int = 3,
    ) -> None:
        super().__init__(
            0,
            auth,
            cache,
            timeout=timeout,
            re_raise=re_raise,
            retries=retries,
        )

    def get(
        self,
        organization: TogglOrganization | int,
        *,
        refresh: bool = False,
    ) -> TogglOrganization | None:
        """Creates a new organization with a single workspace and assigns
        current user as the organization owner

        [Official Documentation](https://engineering.toggl.com/docs/api/organizations#get-organization-data)

        Args:
            organization: Organization to retrieve.
            refresh: Whether to ignore cache completely.

        Raises:
            HTTPStatusError: If any error except a '404' was received.

        Returns:
            Organization object that was retrieve or None if not found.
        """

        if isinstance(organization, TogglOrganization):
            organization = organization.id

        if not refresh:
            return self.cache.find_entry({"id": organization})  # type: ignore[return-value]

        try:
            response = self.request(f"organizations/{organization}", refresh=refresh)
        except HTTPStatusError as err:
            if not self.re_raise and err.response.status_code in {codes.NOT_FOUND, codes.FORBIDDEN}:
                log.warning(err)
                return None
            raise

        return response

    def add(self, name: str, workspace_name: str = "Default-Workspace") -> TogglOrganization:
        """Creates a new organization with a single workspace and assigns
        current user as the organization owner

        [Official Documentation](https://engineering.toggl.com/docs/api/organizations#post-creates-a-new-organization)

        Examples:
            >>> org = organization_endpoint.add("New-Workspace")
            >>> org.name
            "New-Workspace"

        Args:
            name: Name of the new orgnization.
            workspace_name: Name of the default workspace in the organization.
                No space characters allowed.

        Raises:
            NamingError: If any of the names are invalid or the wrong length.
            HTTPStatusError: If the request is not a success.

        Returns:
            The newly created organization.
        """

        TogglOrganization.validate_name(name)
        TogglWorkspace.validate_name(workspace_name)

        return self.request(
            "organizations",
            body={"name": name, "workspace_name": workspace_name},
            method=RequestMethod.POST,
            refresh=True,
        )

    def edit(self, organization: TogglOrganization | int, name: str) -> TogglOrganization:
        """Updates an existing organization.

        [Official Documentation](https://engineering.toggl.com/docs/api/organizations#put-updates-an-existing-organization)

        Args:
            organization: The id of the organization to edit.
            name: What name to change the org to.

        Raises:
            NamingError: If the new name is invalid.
            HTTPStatusError: If the request is not a success.

        Returns:
            The newly edited organization.
        """

        TogglOrganization.validate_name(name)

        if isinstance(organization, TogglOrganization):
            organization = organization.id

        self.request(
            f"organizations/{organization}",
            body={"name": name},
            refresh=True,
            method=RequestMethod.PUT,
        )

        edit = TogglOrganization(organization, name)
        self.cache.update_entries(edit)
        self.cache.commit()

        return edit

    def collect(self, *, refresh: bool = False) -> list[TogglOrganization]:
        """Get all organizations a given user is part of.

        [Official Documentation](https://engineering.toggl.com/docs/api/me#get-organizations-that-a-user-is-part-of)

        Args:
            refresh: Whether to use cache or not.

        Raises:
            HTTPStatusError: If the request is not a success.

        Returns:
            A list of organization objects or empty if none found.
        """
        return self.request("me/organizations", refresh=refresh)

    def delete(self, organization: TogglOrganization | int) -> None:
        """Leaves organization, effectively delete user account in org and
        delete organization if it is last user.

        Deletion might not be instant on the API end and might take a few
        seconds to propogate, so the object might appear in the 'get' or
        'collect' method.

        [Official Documentation](https://engineering.toggl.com/docs/api/organizations#delete-leaves-organization)

        Args:
            organization: Organization to delete.

        Raises:
            HTTPStatusError: If the response status_code is not '200' or '404'.
        """
        org_id = organization if isinstance(organization, int) else organization.id
        try:
            self.request(
                f"organizations/{org_id}/users/leave",
                method=RequestMethod.DELETE,
                refresh=True,
            )
        except HTTPStatusError as err:
            if self.re_raise or err.response.status_code != codes.NOT_FOUND:
                raise
            log.exception("%s")
            log.warning(
                "Organization with id %s was either already deleted or did not exist in the first place!",
                org_id,
            )

        if isinstance(organization, int):
            org = self.cache.find_entry({"id": organization})
            if not isinstance(org, TogglOrganization):
                return
            organization = org

        self.cache.delete_entries(organization)
        self.cache.commit()

    @property
    def model(self) -> type[TogglOrganization]:
        return TogglOrganization

    @property
    def endpoint(self) -> str:
        return ""

get(organization: TogglOrganization | int, *, refresh: bool = False) -> TogglOrganization | None

Creates a new organization with a single workspace and assigns current user as the organization owner

Official Documentation

Parameters:

  • organization (TogglOrganization | int) –

    Organization to retrieve.

  • refresh (bool, default: False ) –

    Whether to ignore cache completely.

Raises:

  • HTTPStatusError

    If any error except a '404' was received.

Returns:

  • TogglOrganization | None

    Organization object that was retrieve or None if not found.

Source code in toggl_api/organization.py
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
def get(
    self,
    organization: TogglOrganization | int,
    *,
    refresh: bool = False,
) -> TogglOrganization | None:
    """Creates a new organization with a single workspace and assigns
    current user as the organization owner

    [Official Documentation](https://engineering.toggl.com/docs/api/organizations#get-organization-data)

    Args:
        organization: Organization to retrieve.
        refresh: Whether to ignore cache completely.

    Raises:
        HTTPStatusError: If any error except a '404' was received.

    Returns:
        Organization object that was retrieve or None if not found.
    """

    if isinstance(organization, TogglOrganization):
        organization = organization.id

    if not refresh:
        return self.cache.find_entry({"id": organization})  # type: ignore[return-value]

    try:
        response = self.request(f"organizations/{organization}", refresh=refresh)
    except HTTPStatusError as err:
        if not self.re_raise and err.response.status_code in {codes.NOT_FOUND, codes.FORBIDDEN}:
            log.warning(err)
            return None
        raise

    return response

add(name: str, workspace_name: str = 'Default-Workspace') -> TogglOrganization

Creates a new organization with a single workspace and assigns current user as the organization owner

Official Documentation

Examples:

>>> org = organization_endpoint.add("New-Workspace")
>>> org.name
"New-Workspace"

Parameters:

  • name (str) –

    Name of the new orgnization.

  • workspace_name (str, default: 'Default-Workspace' ) –

    Name of the default workspace in the organization. No space characters allowed.

Raises:

  • NamingError

    If any of the names are invalid or the wrong length.

  • HTTPStatusError

    If the request is not a success.

Returns:

Source code in toggl_api/organization.py
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
def add(self, name: str, workspace_name: str = "Default-Workspace") -> TogglOrganization:
    """Creates a new organization with a single workspace and assigns
    current user as the organization owner

    [Official Documentation](https://engineering.toggl.com/docs/api/organizations#post-creates-a-new-organization)

    Examples:
        >>> org = organization_endpoint.add("New-Workspace")
        >>> org.name
        "New-Workspace"

    Args:
        name: Name of the new orgnization.
        workspace_name: Name of the default workspace in the organization.
            No space characters allowed.

    Raises:
        NamingError: If any of the names are invalid or the wrong length.
        HTTPStatusError: If the request is not a success.

    Returns:
        The newly created organization.
    """

    TogglOrganization.validate_name(name)
    TogglWorkspace.validate_name(workspace_name)

    return self.request(
        "organizations",
        body={"name": name, "workspace_name": workspace_name},
        method=RequestMethod.POST,
        refresh=True,
    )

edit(organization: TogglOrganization | int, name: str) -> TogglOrganization

Updates an existing organization.

Official Documentation

Parameters:

  • organization (TogglOrganization | int) –

    The id of the organization to edit.

  • name (str) –

    What name to change the org to.

Raises:

  • NamingError

    If the new name is invalid.

  • HTTPStatusError

    If the request is not a success.

Returns:

Source code in toggl_api/organization.py
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
def edit(self, organization: TogglOrganization | int, name: str) -> TogglOrganization:
    """Updates an existing organization.

    [Official Documentation](https://engineering.toggl.com/docs/api/organizations#put-updates-an-existing-organization)

    Args:
        organization: The id of the organization to edit.
        name: What name to change the org to.

    Raises:
        NamingError: If the new name is invalid.
        HTTPStatusError: If the request is not a success.

    Returns:
        The newly edited organization.
    """

    TogglOrganization.validate_name(name)

    if isinstance(organization, TogglOrganization):
        organization = organization.id

    self.request(
        f"organizations/{organization}",
        body={"name": name},
        refresh=True,
        method=RequestMethod.PUT,
    )

    edit = TogglOrganization(organization, name)
    self.cache.update_entries(edit)
    self.cache.commit()

    return edit

collect(*, refresh: bool = False) -> list[TogglOrganization]

Get all organizations a given user is part of.

Official Documentation

Parameters:

  • refresh (bool, default: False ) –

    Whether to use cache or not.

Raises:

  • HTTPStatusError

    If the request is not a success.

Returns:

Source code in toggl_api/organization.py
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
def collect(self, *, refresh: bool = False) -> list[TogglOrganization]:
    """Get all organizations a given user is part of.

    [Official Documentation](https://engineering.toggl.com/docs/api/me#get-organizations-that-a-user-is-part-of)

    Args:
        refresh: Whether to use cache or not.

    Raises:
        HTTPStatusError: If the request is not a success.

    Returns:
        A list of organization objects or empty if none found.
    """
    return self.request("me/organizations", refresh=refresh)

delete(organization: TogglOrganization | int) -> None

Leaves organization, effectively delete user account in org and delete organization if it is last user.

Deletion might not be instant on the API end and might take a few seconds to propogate, so the object might appear in the 'get' or 'collect' method.

Official Documentation

Parameters:

Raises:

  • HTTPStatusError

    If the response status_code is not '200' or '404'.

Source code in toggl_api/organization.py
182
183
184
185
186
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
def delete(self, organization: TogglOrganization | int) -> None:
    """Leaves organization, effectively delete user account in org and
    delete organization if it is last user.

    Deletion might not be instant on the API end and might take a few
    seconds to propogate, so the object might appear in the 'get' or
    'collect' method.

    [Official Documentation](https://engineering.toggl.com/docs/api/organizations#delete-leaves-organization)

    Args:
        organization: Organization to delete.

    Raises:
        HTTPStatusError: If the response status_code is not '200' or '404'.
    """
    org_id = organization if isinstance(organization, int) else organization.id
    try:
        self.request(
            f"organizations/{org_id}/users/leave",
            method=RequestMethod.DELETE,
            refresh=True,
        )
    except HTTPStatusError as err:
        if self.re_raise or err.response.status_code != codes.NOT_FOUND:
            raise
        log.exception("%s")
        log.warning(
            "Organization with id %s was either already deleted or did not exist in the first place!",
            org_id,
        )

    if isinstance(organization, int):
        org = self.cache.find_entry({"id": organization})
        if not isinstance(org, TogglOrganization):
            return
        organization = org

    self.cache.delete_entries(organization)
    self.cache.commit()