Skip to content

ZiplineApi

This module contains the ZiplineApi class, which is the main class used to interact with the Zipline API.

Classes:

Name Description
ZiplineApi

Represents an instance of the Zipline API.

ZiplineApi

Represents an instance of the Zipline API.

All API requests should be made through this class.

Parameters:

Name Type Description Default
config ZiplineApiConfig

Configuration object for the ZiplineApi class

required

Methods:

Name Description
check_user_exists

Check if a user exists by username

create_invite

Create an invite code

delete_invite

Delete an invite code

get_exif

Get the EXIF data for a file

get_files

Get a list of the files uploaded by the authenticated user

get_invites

Get a list of invites

get_password_protected_file

Get a password protected file

get_self

Get the currently authenticated user

get_stats

Get statistics about the Zipline instance

get_user

Get a user by ID

get_users

Get a list of users

get_version

Get the version of the Zipline instance

register_user

Register a new user

shorten

Shorten a URL

Source code in pyzipline/zipline.py
 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
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
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
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
288
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
315
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
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
375
376
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
410
411
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
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
class ZiplineApi:
    """Represents an instance of the Zipline API.

    All API requests should be made through this class.

    Args:
        config (ZiplineApiConfig): Configuration object for the ZiplineApi class
    """
    def __init__(
        self,
        config: ZiplineApiConfig
    ):
        self._rest_adapter = RestAdapter(config)

    def create_invite(self, expiry: timedelta = timedelta(days=1), count: int = 1) -> Union[Invite, List[Invite]]:
        """Create an invite code

        /// admonition | Requires Authentication
            type: warning
        ///

        /// admonition | Requires Administrator
            type: danger
        ///

        Args:
            expiry (timedelta): Timedelta object representing when the invite should expire
            count (int): Number of invites to create

        Raises:
            FeatureDisabledError: Raised when invites are disabled on the Zipline instance
            Forbidden: Raised if the authenticated user is not an administrator
            PyZiplineError: Raised if the API changes, causing a breaking change in this method
            ValueError: Raised when the expiry datetime is invalid or the count is less than 1

        Returns:
            Invite: The newly created invite code(s)
        """
        json = {'expiresAt': 'date=' + convert_datetime_to_str(datetime.now() + expiry), 'count': count}
        result: Result = self._rest_adapter.post(endpoint="auth/invite", json=json)
        if result.status_code == 200:
            if count > 1:
                invite_list = []
                for invite in result.data:
                    i = Invite(**invite)
                    invite_list.append(i)
                return invite_list
            data = result.data[0] if isinstance(result.data, list) else result.data
            return Invite(**data)
        if result.message == 'invites are disabled':
            raise FeatureDisabledError(result.message)
        if result.message == 'invalid date':
            raise ValueError(f"{result.status_code}: {result.message}\n{result.data}\n{json}")
        if result.message == 'not an administrator':
            raise Forbidden(result.message)
        raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

    def register_user(self, username: str, password: str, invite: str = None, admin: bool = False) -> User:
        """Register a new user

        /// admonition | Requires Authentication
            type: warning
        ///

        /// admonition | Parameter Requires Super Administrator
            type: danger
        The authenticated user must be a Super Administrator to use the `admin` parameter.
        ///

        /// admonition | Conditionally Requires Administrator
            type: danger
        The authenticated user must be an Administrator to register a user when registration is disabled.
        ///

        Args:
            username (str): Username to register
            password (str): Password for the new user
            invite (str): Invite code to register the new user with, only required if registration without invites is disabled and the authenticated user is not an administrator
            admin (bool): Whether or not the new user should be an administrator, authenticated user must be a super administrator to create an administrator

        Raises:
            FeatureDisabledError: Raised when:\n
                - registration or invites are disabled on the Zipline instance and the authenticated user is not an administrator
                - invite code is provided and invites are disabled
            Forbidden: Raised if the authenticated user is not an super administrator and attempts to create an administrator
            PyZiplineError: Raised if the API changes, causing a breaking change in this method
            ValueError: Raised when the username is already taken or if the invite code is invalid/expired

        Returns:
            User: The newly created user
        """
        json = {'username': username, 'password': password}
        if invite is not None:
            json['code'] = invite
        if admin:
            json['admin'] = True

        result: Result = self._rest_adapter.post(endpoint="auth/register", json=json)
        if result.status_code == 200:
            return User(**result.data)

        if result.message == 'This endpoint is unavailable due to current configurations':
            raise FeatureDisabledError('user registration or invites are disabled')

        if result.message =='Bad Username/Password':
            if self.check_user_exists(username):
                raise ValueError('username already taken')
            raise FeatureDisabledError('invite code is provided and invites are disabled')

        if result.message == 'Bad invite':
            raise ValueError('invite code is invalid or expired')

        if result.message == 'not an administrator':
            raise Forbidden(result.message)

        raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

    def check_user_exists(self, username: str, invite: str = None) -> bool:
        """Check if a user exists by username

        Args:
            username (str): Username to check
            invite (str): Invite code to use, only required if registration without invites is disabled

        Raises:
            FeatureDisabledError: Raised when registration or invites are disabled on the Zipline instance
            PyZiplineError: Raised if the API changes, causing a breaking change in this method
            ValueError: Raised when the username is not present, or the invite code is invalid/not present and invites are enabled

        Returns:
            bool: True if user exists, False if not
        """
        json = {'username': username} if invite is None else {'username': username, 'code': invite}
        result: Result = self._rest_adapter.post(endpoint="user/check", json=json)
        if result.status_code == 200:
            return False
        if result.message == 'username already exists':
            return True
        if result.message == 'user registration is disabled':
            raise FeatureDisabledError('user registration or invites are disabled')
        if result.message == 'invalid invite code':
            raise ValueError(result.message + "(most likely doesn't exist)")
        if result.message == 'no code':
            raise ValueError('invite code not provided')
        if result.message == 'no username':
            raise ValueError('username not provided')
        raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

    def delete_invite(self, code: str) -> Invite:
        """Delete an invite code

        /// admonition | Requires Authentication
            type: warning
        ///

        /// admonition | Requires Administrator
            type: danger
        ///

        Args:
            code (str): Invite code to delete

        Raises:
            Forbidden: Raised if the authenticated user is not an administrator
            NotFound: Raised if the invite code does not exist
            PyZiplineError: Raised if the API changes, causing a breaking change in this method

        Returns:
            Invite: An object containing the deleted invite
        """
        result: Result = self._rest_adapter.delete(endpoint="auth/invite", params={'code': code})
        if result.status_code == 200:
            return Invite(**result.data)
        if result.message == 'invite not found':
            raise NotFound(result.message)
        if result.message == 'not an administrator':
            raise Forbidden(result.message)
        raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

    def get_exif(self, file_id: int) -> dict:
        """Get the EXIF data for a file

        /// admonition | Requires Authentication
            type: warning
        ///

        Args:
            file_id (int): ID of the file to get EXIF data for

        Raises:
            Forbidden: The user is not authenticated
            NotFound: The file does not exist
            PyZiplineError: Raised if the API changes, causing a breaking change in this method

        Returns:
            dict: EXIF data for the file
        """
        result: Result = self._rest_adapter.get(endpoint="/exif", params={'id': file_id})
        if result.status_code == 200:
            return result.data
        if result.status_code == 401:
            raise Forbidden(result.message)
        if result.message == 'image not found':
            raise NotFound(result.message)
        if result.message == 'image not found on fs':
            raise NotFound('image not found on filesystem')
        raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

    def get_files(self, favorite: bool = False, media_only: bool = False) -> list[File]:
        """Get a list of the files uploaded by the authenticated user

        /// admonition | Requires Authentication
            type: warning
        ///

        Args:
            favorite (bool): Whether or not to return only favorite files
            media_only (bool): Whether or not to return only media files

        Raises:
            Forbidden: The user is not authenticated
            PyZiplineError: Raised if the API changes, causing a breaking change in this method

        Returns:
            File: List of files uploaded by the authenticated user
        """
        params = {}
        if favorite:
            params['favorite'] = favorite
        if media_only:
            params['media_only'] = media_only
        result: Result = self._rest_adapter.get(endpoint="/user/files", params=params)
        if result.status_code == 200:
            files = []
            for file in result.data:
                f = File(**file)
                files.append(f)
            return files
        if result.status_code == 401:
            raise Forbidden(result.message)

    def get_password_protected_file(self, file_id: int, password: str) -> bytes:
        """Get a password protected file

        Args:
            file_id (int): ID of the file to get
            password (str): Password for the file

        Raises:
            Forbidden: The password is incorrect
            NotFound: The file does not exist
            PyZiplineError: Raised if the API changes, causing a breaking change in this method

        Returns:
            bytes: The file, in bytes
        """
        result: Result = self._rest_adapter.get(endpoint="auth/image", params={'id': file_id, 'password': password})
        if result.status_code == 200:
            return result.data
        if result.message == 'image not found':
            raise NotFound(result.message)
        if result.message == 'wrong password':
            raise Forbidden(result.message)
        raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

    def get_invites(self) -> list[Invite]:
        """Get a list of invites

        /// admonition | Requires Authentication
            type: warning
        ///

        /// admonition | Requires Administrator
            type: danger
        ///

        Raises:
            Forbidden: The user is not authenticated
            FeatureDisabledError: Invites are disabled on the Zipline instance
            PyZiplineError: Raised if the API changes, causing a breaking change in this method

        Returns:
            Invite: List of invites
        """
        result = self._rest_adapter.get(endpoint="auth/invite")
        if result.status_code == 200:
            return [Invite(**invite) for invite in result.data]
        if result.status_code == 401:
            raise Forbidden(result.message)
        if result.message == 'invites are disabled':
            raise FeatureDisabledError(result.message)
        raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")


    def get_self(self) -> User:
        """Get the currently authenticated user

        /// admonition | Requires Authentication
            type: warning
        ///

        Raises:
            Forbidden: The user is not authenticated
            PyZiplineError: Raised if the API changes, causing a breaking change in this method

        Returns:
            User: The currently authenticated user
        """
        result = self._rest_adapter.get(endpoint="user")
        if result.status_code == 200:
            return User(**result.data)
        if result.status_code == 401:
            raise Forbidden(result.message)
        raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

    def shorten(self, url: str, vanity: str = None, max_views: int = None, zero_width: bool = False) -> str:
        """Shorten a URL

        /// admonition | Requires Authentication
            type: warning
        ///

        Args:
            url (str): URL to shorten
            vanity (str): Vanity string to use
            max_views (int): Maximum number of views before the URL expires
            zero_width (bool): Whether or not to use zero width characters in the shortened URL

        Raises:
            Forbidden: The user is not authenticated
            PyZiplineError: Raised if the API changes, causing a breaking change in this method
            ValueError: Raised if the vanity string already exists, if the vanity string is empty, or if the max views is invalid (less than 0)

        Returns:
            str: The shortened URL
        """
        headers = {}
        if max_views is not None:
            headers['Max-Views'] = max_views
        if zero_width:
            headers['Zws'] = True

        json = {'url': url} if not vanity else {'url': url, 'vanity': vanity}

        result = self._rest_adapter.post(endpoint="shorten", json=json, headers=headers)

        if result.status_code == 200:
            return result.data['url']

        if result.status_code == 400:
            raise ValueError(result.message)

        if result.status_code == 401:
            raise Forbidden(result.message)

        raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

    def get_user(self, user_id: int) -> User:
        """Get a user by ID

        /// admonition | Requires Administrator
            type: danger
        ///

        Args:
            user_id (int): Integer ID of the user to retrieve

        Raises:
            Forbidden: Raised if the authenticated user is not an administrator
            PyZiplineError: Raised if the API changes, causing a breaking change in this method

        Returns:
            User: The user with the given ID
        """
        result = self._rest_adapter.get(endpoint=f"user/{user_id}")
        if result.status_code == 200:
            return User(**result.data)
        if result.status_code == 403:
            raise Forbidden(result.message)
        raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

    def get_users(self) -> list[User]:
        """Get a list of users

        /// admonition | Requires Administrator
            type: danger
        ///

        Raises:
            Forbidden: Raised if the authenticated user is not an administrator
            PyZiplineError: Raised if the API changes, causing a breaking change in this method

        Returns:
            list[User]: List of users
        """
        result = self._rest_adapter.get(endpoint="users")
        if result.status_code == 200:
            return [User(**user) for user in result.data]
        if result.status_code == 403:
            raise Forbidden(result.message)
        raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

    def get_stats(self, amount: int = 1, force_update: bool = False) -> Union[Stats, List[Stats]]:
        """Get statistics about the Zipline instance

        /// admonition | Requires Authentication
            type: warning
        ///

        /// admonition | Parameter Requires Administrator
            type: danger
        The authenticated user must be an administrator to use the `force_update` argument.
        ///

        /// admonition | Configuration Varies
            type: note
        The endpoint this method uses, `/api/stats`, relies a lot on Zipline's [configuration](https://zipline.diced.sh/docs/config/website#website_show_files_per_user) to determine who can access the endpoint and what the endpoint returns depending on permission level.
        Please bear this in mind when using this method.
        ///

        Args:
            amount (int): Number of stats to retrieve
            force_update (bool): Force the Zipline instance to update its statistics before returning them, requires administrator

        Raises:
            Forbidden: The user is not authenticated, or the user is not an administrator and `force_update` is True
            PyZiplineError: Raised if the API changes, causing a breaking change in this method
            ValueError: Raised if amount is less than 1

        Returns:
            Stats: Statistics about the Zipline instance
        """
        if amount < 1:
            raise ValueError('amount must be greater than 0')
        if force_update:
            result = self._rest_adapter.post(endpoint="stats", params={'amount': amount})
        else:
            result = self._rest_adapter.get(endpoint="stats", params={'amount': amount})
        if result.status_code == 200:
            return [Stats(**stats) for stats in result.data]
        if result.status_code in (401, 403):
            raise Forbidden(result.message)
        raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

    def get_version(self) -> Version:
        """Get the version of the Zipline instance

        /// admonition | Requires Authentication
            type: warning
        ///

        Raises:
            Forbidden: The user is not authenticated
            PyZiplineError: Raised if the API changes, causing a breaking change in this method

        Returns:
            Version: The version of the Zipline instance
        """
        result = self._rest_adapter.get(endpoint="version")
        if result.status_code == 200:
            return Version(**result.data)
        if result.status_code == 401:
            raise Forbidden(result.message)
        raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

check_user_exists(username, invite=None)

Check if a user exists by username

Parameters:

Name Type Description Default
username str

Username to check

required
invite str

Invite code to use, only required if registration without invites is disabled

None

Raises:

Type Description
FeatureDisabledError

Raised when registration or invites are disabled on the Zipline instance

PyZiplineError

Raised if the API changes, causing a breaking change in this method

ValueError

Raised when the username is not present, or the invite code is invalid/not present and invites are enabled

Returns:

Name Type Description
bool bool

True if user exists, False if not

Source code in pyzipline/zipline.py
def check_user_exists(self, username: str, invite: str = None) -> bool:
    """Check if a user exists by username

    Args:
        username (str): Username to check
        invite (str): Invite code to use, only required if registration without invites is disabled

    Raises:
        FeatureDisabledError: Raised when registration or invites are disabled on the Zipline instance
        PyZiplineError: Raised if the API changes, causing a breaking change in this method
        ValueError: Raised when the username is not present, or the invite code is invalid/not present and invites are enabled

    Returns:
        bool: True if user exists, False if not
    """
    json = {'username': username} if invite is None else {'username': username, 'code': invite}
    result: Result = self._rest_adapter.post(endpoint="user/check", json=json)
    if result.status_code == 200:
        return False
    if result.message == 'username already exists':
        return True
    if result.message == 'user registration is disabled':
        raise FeatureDisabledError('user registration or invites are disabled')
    if result.message == 'invalid invite code':
        raise ValueError(result.message + "(most likely doesn't exist)")
    if result.message == 'no code':
        raise ValueError('invite code not provided')
    if result.message == 'no username':
        raise ValueError('username not provided')
    raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

create_invite(expiry=timedelta(days=1), count=1)

Create an invite code

Requires Authentication

Requires Administrator

Parameters:

Name Type Description Default
expiry timedelta

Timedelta object representing when the invite should expire

timedelta(days=1)
count int

Number of invites to create

1

Raises:

Type Description
FeatureDisabledError

Raised when invites are disabled on the Zipline instance

Forbidden

Raised if the authenticated user is not an administrator

PyZiplineError

Raised if the API changes, causing a breaking change in this method

ValueError

Raised when the expiry datetime is invalid or the count is less than 1

Returns:

Name Type Description
Invite Union[Invite, List[Invite]]

The newly created invite code(s)

Source code in pyzipline/zipline.py
def create_invite(self, expiry: timedelta = timedelta(days=1), count: int = 1) -> Union[Invite, List[Invite]]:
    """Create an invite code

    /// admonition | Requires Authentication
        type: warning
    ///

    /// admonition | Requires Administrator
        type: danger
    ///

    Args:
        expiry (timedelta): Timedelta object representing when the invite should expire
        count (int): Number of invites to create

    Raises:
        FeatureDisabledError: Raised when invites are disabled on the Zipline instance
        Forbidden: Raised if the authenticated user is not an administrator
        PyZiplineError: Raised if the API changes, causing a breaking change in this method
        ValueError: Raised when the expiry datetime is invalid or the count is less than 1

    Returns:
        Invite: The newly created invite code(s)
    """
    json = {'expiresAt': 'date=' + convert_datetime_to_str(datetime.now() + expiry), 'count': count}
    result: Result = self._rest_adapter.post(endpoint="auth/invite", json=json)
    if result.status_code == 200:
        if count > 1:
            invite_list = []
            for invite in result.data:
                i = Invite(**invite)
                invite_list.append(i)
            return invite_list
        data = result.data[0] if isinstance(result.data, list) else result.data
        return Invite(**data)
    if result.message == 'invites are disabled':
        raise FeatureDisabledError(result.message)
    if result.message == 'invalid date':
        raise ValueError(f"{result.status_code}: {result.message}\n{result.data}\n{json}")
    if result.message == 'not an administrator':
        raise Forbidden(result.message)
    raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

delete_invite(code)

Delete an invite code

Requires Authentication

Requires Administrator

Parameters:

Name Type Description Default
code str

Invite code to delete

required

Raises:

Type Description
Forbidden

Raised if the authenticated user is not an administrator

NotFound

Raised if the invite code does not exist

PyZiplineError

Raised if the API changes, causing a breaking change in this method

Returns:

Name Type Description
Invite Invite

An object containing the deleted invite

Source code in pyzipline/zipline.py
def delete_invite(self, code: str) -> Invite:
    """Delete an invite code

    /// admonition | Requires Authentication
        type: warning
    ///

    /// admonition | Requires Administrator
        type: danger
    ///

    Args:
        code (str): Invite code to delete

    Raises:
        Forbidden: Raised if the authenticated user is not an administrator
        NotFound: Raised if the invite code does not exist
        PyZiplineError: Raised if the API changes, causing a breaking change in this method

    Returns:
        Invite: An object containing the deleted invite
    """
    result: Result = self._rest_adapter.delete(endpoint="auth/invite", params={'code': code})
    if result.status_code == 200:
        return Invite(**result.data)
    if result.message == 'invite not found':
        raise NotFound(result.message)
    if result.message == 'not an administrator':
        raise Forbidden(result.message)
    raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

get_exif(file_id)

Get the EXIF data for a file

Requires Authentication

Parameters:

Name Type Description Default
file_id int

ID of the file to get EXIF data for

required

Raises:

Type Description
Forbidden

The user is not authenticated

NotFound

The file does not exist

PyZiplineError

Raised if the API changes, causing a breaking change in this method

Returns:

Name Type Description
dict dict

EXIF data for the file

Source code in pyzipline/zipline.py
def get_exif(self, file_id: int) -> dict:
    """Get the EXIF data for a file

    /// admonition | Requires Authentication
        type: warning
    ///

    Args:
        file_id (int): ID of the file to get EXIF data for

    Raises:
        Forbidden: The user is not authenticated
        NotFound: The file does not exist
        PyZiplineError: Raised if the API changes, causing a breaking change in this method

    Returns:
        dict: EXIF data for the file
    """
    result: Result = self._rest_adapter.get(endpoint="/exif", params={'id': file_id})
    if result.status_code == 200:
        return result.data
    if result.status_code == 401:
        raise Forbidden(result.message)
    if result.message == 'image not found':
        raise NotFound(result.message)
    if result.message == 'image not found on fs':
        raise NotFound('image not found on filesystem')
    raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

get_files(favorite=False, media_only=False)

Get a list of the files uploaded by the authenticated user

Requires Authentication

Parameters:

Name Type Description Default
favorite bool

Whether or not to return only favorite files

False
media_only bool

Whether or not to return only media files

False

Raises:

Type Description
Forbidden

The user is not authenticated

PyZiplineError

Raised if the API changes, causing a breaking change in this method

Returns:

Name Type Description
File list[File]

List of files uploaded by the authenticated user

Source code in pyzipline/zipline.py
def get_files(self, favorite: bool = False, media_only: bool = False) -> list[File]:
    """Get a list of the files uploaded by the authenticated user

    /// admonition | Requires Authentication
        type: warning
    ///

    Args:
        favorite (bool): Whether or not to return only favorite files
        media_only (bool): Whether or not to return only media files

    Raises:
        Forbidden: The user is not authenticated
        PyZiplineError: Raised if the API changes, causing a breaking change in this method

    Returns:
        File: List of files uploaded by the authenticated user
    """
    params = {}
    if favorite:
        params['favorite'] = favorite
    if media_only:
        params['media_only'] = media_only
    result: Result = self._rest_adapter.get(endpoint="/user/files", params=params)
    if result.status_code == 200:
        files = []
        for file in result.data:
            f = File(**file)
            files.append(f)
        return files
    if result.status_code == 401:
        raise Forbidden(result.message)

get_invites()

Get a list of invites

Requires Authentication

Requires Administrator

Raises:

Type Description
Forbidden

The user is not authenticated

FeatureDisabledError

Invites are disabled on the Zipline instance

PyZiplineError

Raised if the API changes, causing a breaking change in this method

Returns:

Name Type Description
Invite list[Invite]

List of invites

Source code in pyzipline/zipline.py
def get_invites(self) -> list[Invite]:
    """Get a list of invites

    /// admonition | Requires Authentication
        type: warning
    ///

    /// admonition | Requires Administrator
        type: danger
    ///

    Raises:
        Forbidden: The user is not authenticated
        FeatureDisabledError: Invites are disabled on the Zipline instance
        PyZiplineError: Raised if the API changes, causing a breaking change in this method

    Returns:
        Invite: List of invites
    """
    result = self._rest_adapter.get(endpoint="auth/invite")
    if result.status_code == 200:
        return [Invite(**invite) for invite in result.data]
    if result.status_code == 401:
        raise Forbidden(result.message)
    if result.message == 'invites are disabled':
        raise FeatureDisabledError(result.message)
    raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

get_password_protected_file(file_id, password)

Get a password protected file

Parameters:

Name Type Description Default
file_id int

ID of the file to get

required
password str

Password for the file

required

Raises:

Type Description
Forbidden

The password is incorrect

NotFound

The file does not exist

PyZiplineError

Raised if the API changes, causing a breaking change in this method

Returns:

Name Type Description
bytes bytes

The file, in bytes

Source code in pyzipline/zipline.py
def get_password_protected_file(self, file_id: int, password: str) -> bytes:
    """Get a password protected file

    Args:
        file_id (int): ID of the file to get
        password (str): Password for the file

    Raises:
        Forbidden: The password is incorrect
        NotFound: The file does not exist
        PyZiplineError: Raised if the API changes, causing a breaking change in this method

    Returns:
        bytes: The file, in bytes
    """
    result: Result = self._rest_adapter.get(endpoint="auth/image", params={'id': file_id, 'password': password})
    if result.status_code == 200:
        return result.data
    if result.message == 'image not found':
        raise NotFound(result.message)
    if result.message == 'wrong password':
        raise Forbidden(result.message)
    raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

get_self()

Get the currently authenticated user

Requires Authentication

Raises:

Type Description
Forbidden

The user is not authenticated

PyZiplineError

Raised if the API changes, causing a breaking change in this method

Returns:

Name Type Description
User User

The currently authenticated user

Source code in pyzipline/zipline.py
def get_self(self) -> User:
    """Get the currently authenticated user

    /// admonition | Requires Authentication
        type: warning
    ///

    Raises:
        Forbidden: The user is not authenticated
        PyZiplineError: Raised if the API changes, causing a breaking change in this method

    Returns:
        User: The currently authenticated user
    """
    result = self._rest_adapter.get(endpoint="user")
    if result.status_code == 200:
        return User(**result.data)
    if result.status_code == 401:
        raise Forbidden(result.message)
    raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

get_stats(amount=1, force_update=False)

Get statistics about the Zipline instance

Requires Authentication

Parameter Requires Administrator

The authenticated user must be an administrator to use the force_update argument.

Configuration Varies

The endpoint this method uses, /api/stats, relies a lot on Zipline's configuration to determine who can access the endpoint and what the endpoint returns depending on permission level. Please bear this in mind when using this method.

Parameters:

Name Type Description Default
amount int

Number of stats to retrieve

1
force_update bool

Force the Zipline instance to update its statistics before returning them, requires administrator

False

Raises:

Type Description
Forbidden

The user is not authenticated, or the user is not an administrator and force_update is True

PyZiplineError

Raised if the API changes, causing a breaking change in this method

ValueError

Raised if amount is less than 1

Returns:

Name Type Description
Stats Union[Stats, List[Stats]]

Statistics about the Zipline instance

Source code in pyzipline/zipline.py
def get_stats(self, amount: int = 1, force_update: bool = False) -> Union[Stats, List[Stats]]:
    """Get statistics about the Zipline instance

    /// admonition | Requires Authentication
        type: warning
    ///

    /// admonition | Parameter Requires Administrator
        type: danger
    The authenticated user must be an administrator to use the `force_update` argument.
    ///

    /// admonition | Configuration Varies
        type: note
    The endpoint this method uses, `/api/stats`, relies a lot on Zipline's [configuration](https://zipline.diced.sh/docs/config/website#website_show_files_per_user) to determine who can access the endpoint and what the endpoint returns depending on permission level.
    Please bear this in mind when using this method.
    ///

    Args:
        amount (int): Number of stats to retrieve
        force_update (bool): Force the Zipline instance to update its statistics before returning them, requires administrator

    Raises:
        Forbidden: The user is not authenticated, or the user is not an administrator and `force_update` is True
        PyZiplineError: Raised if the API changes, causing a breaking change in this method
        ValueError: Raised if amount is less than 1

    Returns:
        Stats: Statistics about the Zipline instance
    """
    if amount < 1:
        raise ValueError('amount must be greater than 0')
    if force_update:
        result = self._rest_adapter.post(endpoint="stats", params={'amount': amount})
    else:
        result = self._rest_adapter.get(endpoint="stats", params={'amount': amount})
    if result.status_code == 200:
        return [Stats(**stats) for stats in result.data]
    if result.status_code in (401, 403):
        raise Forbidden(result.message)
    raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

get_user(user_id)

Get a user by ID

Requires Administrator

Parameters:

Name Type Description Default
user_id int

Integer ID of the user to retrieve

required

Raises:

Type Description
Forbidden

Raised if the authenticated user is not an administrator

PyZiplineError

Raised if the API changes, causing a breaking change in this method

Returns:

Name Type Description
User User

The user with the given ID

Source code in pyzipline/zipline.py
def get_user(self, user_id: int) -> User:
    """Get a user by ID

    /// admonition | Requires Administrator
        type: danger
    ///

    Args:
        user_id (int): Integer ID of the user to retrieve

    Raises:
        Forbidden: Raised if the authenticated user is not an administrator
        PyZiplineError: Raised if the API changes, causing a breaking change in this method

    Returns:
        User: The user with the given ID
    """
    result = self._rest_adapter.get(endpoint=f"user/{user_id}")
    if result.status_code == 200:
        return User(**result.data)
    if result.status_code == 403:
        raise Forbidden(result.message)
    raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

get_users()

Get a list of users

Requires Administrator

Raises:

Type Description
Forbidden

Raised if the authenticated user is not an administrator

PyZiplineError

Raised if the API changes, causing a breaking change in this method

Returns:

Type Description
list[User]

list[User]: List of users

Source code in pyzipline/zipline.py
def get_users(self) -> list[User]:
    """Get a list of users

    /// admonition | Requires Administrator
        type: danger
    ///

    Raises:
        Forbidden: Raised if the authenticated user is not an administrator
        PyZiplineError: Raised if the API changes, causing a breaking change in this method

    Returns:
        list[User]: List of users
    """
    result = self._rest_adapter.get(endpoint="users")
    if result.status_code == 200:
        return [User(**user) for user in result.data]
    if result.status_code == 403:
        raise Forbidden(result.message)
    raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

get_version()

Get the version of the Zipline instance

Requires Authentication

Raises:

Type Description
Forbidden

The user is not authenticated

PyZiplineError

Raised if the API changes, causing a breaking change in this method

Returns:

Name Type Description
Version Version

The version of the Zipline instance

Source code in pyzipline/zipline.py
def get_version(self) -> Version:
    """Get the version of the Zipline instance

    /// admonition | Requires Authentication
        type: warning
    ///

    Raises:
        Forbidden: The user is not authenticated
        PyZiplineError: Raised if the API changes, causing a breaking change in this method

    Returns:
        Version: The version of the Zipline instance
    """
    result = self._rest_adapter.get(endpoint="version")
    if result.status_code == 200:
        return Version(**result.data)
    if result.status_code == 401:
        raise Forbidden(result.message)
    raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

register_user(username, password, invite=None, admin=False)

Register a new user

Requires Authentication

Parameter Requires Super Administrator

The authenticated user must be a Super Administrator to use the admin parameter.

Conditionally Requires Administrator

The authenticated user must be an Administrator to register a user when registration is disabled.

Parameters:

Name Type Description Default
username str

Username to register

required
password str

Password for the new user

required
invite str

Invite code to register the new user with, only required if registration without invites is disabled and the authenticated user is not an administrator

None
admin bool

Whether or not the new user should be an administrator, authenticated user must be a super administrator to create an administrator

False

Raises:

Type Description
FeatureDisabledError

Raised when:

  • registration or invites are disabled on the Zipline instance and the authenticated user is not an administrator
  • invite code is provided and invites are disabled
Forbidden

Raised if the authenticated user is not an super administrator and attempts to create an administrator

PyZiplineError

Raised if the API changes, causing a breaking change in this method

ValueError

Raised when the username is already taken or if the invite code is invalid/expired

Returns:

Name Type Description
User User

The newly created user

Source code in pyzipline/zipline.py
def register_user(self, username: str, password: str, invite: str = None, admin: bool = False) -> User:
    """Register a new user

    /// admonition | Requires Authentication
        type: warning
    ///

    /// admonition | Parameter Requires Super Administrator
        type: danger
    The authenticated user must be a Super Administrator to use the `admin` parameter.
    ///

    /// admonition | Conditionally Requires Administrator
        type: danger
    The authenticated user must be an Administrator to register a user when registration is disabled.
    ///

    Args:
        username (str): Username to register
        password (str): Password for the new user
        invite (str): Invite code to register the new user with, only required if registration without invites is disabled and the authenticated user is not an administrator
        admin (bool): Whether or not the new user should be an administrator, authenticated user must be a super administrator to create an administrator

    Raises:
        FeatureDisabledError: Raised when:\n
            - registration or invites are disabled on the Zipline instance and the authenticated user is not an administrator
            - invite code is provided and invites are disabled
        Forbidden: Raised if the authenticated user is not an super administrator and attempts to create an administrator
        PyZiplineError: Raised if the API changes, causing a breaking change in this method
        ValueError: Raised when the username is already taken or if the invite code is invalid/expired

    Returns:
        User: The newly created user
    """
    json = {'username': username, 'password': password}
    if invite is not None:
        json['code'] = invite
    if admin:
        json['admin'] = True

    result: Result = self._rest_adapter.post(endpoint="auth/register", json=json)
    if result.status_code == 200:
        return User(**result.data)

    if result.message == 'This endpoint is unavailable due to current configurations':
        raise FeatureDisabledError('user registration or invites are disabled')

    if result.message =='Bad Username/Password':
        if self.check_user_exists(username):
            raise ValueError('username already taken')
        raise FeatureDisabledError('invite code is provided and invites are disabled')

    if result.message == 'Bad invite':
        raise ValueError('invite code is invalid or expired')

    if result.message == 'not an administrator':
        raise Forbidden(result.message)

    raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")

shorten(url, vanity=None, max_views=None, zero_width=False)

Shorten a URL

Requires Authentication

Parameters:

Name Type Description Default
url str

URL to shorten

required
vanity str

Vanity string to use

None
max_views int

Maximum number of views before the URL expires

None
zero_width bool

Whether or not to use zero width characters in the shortened URL

False

Raises:

Type Description
Forbidden

The user is not authenticated

PyZiplineError

Raised if the API changes, causing a breaking change in this method

ValueError

Raised if the vanity string already exists, if the vanity string is empty, or if the max views is invalid (less than 0)

Returns:

Name Type Description
str str

The shortened URL

Source code in pyzipline/zipline.py
def shorten(self, url: str, vanity: str = None, max_views: int = None, zero_width: bool = False) -> str:
    """Shorten a URL

    /// admonition | Requires Authentication
        type: warning
    ///

    Args:
        url (str): URL to shorten
        vanity (str): Vanity string to use
        max_views (int): Maximum number of views before the URL expires
        zero_width (bool): Whether or not to use zero width characters in the shortened URL

    Raises:
        Forbidden: The user is not authenticated
        PyZiplineError: Raised if the API changes, causing a breaking change in this method
        ValueError: Raised if the vanity string already exists, if the vanity string is empty, or if the max views is invalid (less than 0)

    Returns:
        str: The shortened URL
    """
    headers = {}
    if max_views is not None:
        headers['Max-Views'] = max_views
    if zero_width:
        headers['Zws'] = True

    json = {'url': url} if not vanity else {'url': url, 'vanity': vanity}

    result = self._rest_adapter.post(endpoint="shorten", json=json, headers=headers)

    if result.status_code == 200:
        return result.data['url']

    if result.status_code == 400:
        raise ValueError(result.message)

    if result.status_code == 401:
        raise Forbidden(result.message)

    raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")