zammad_py 3.2.0__py3-none-any.whl → 3.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zammad_py/__init__.py +1 -1
- zammad_py/api.py +457 -31
- zammad_py/enums.py +8 -0
- zammad_py/exceptions.py +34 -0
- zammad_py-3.2.1.dist-info/AUTHORS.md +9 -0
- zammad_py-3.2.1.dist-info/METADATA +182 -0
- zammad_py-3.2.1.dist-info/RECORD +9 -0
- {zammad_py-3.2.0.dist-info → zammad_py-3.2.1.dist-info}/WHEEL +1 -1
- zammad_py-3.2.0.dist-info/METADATA +0 -138
- zammad_py-3.2.0.dist-info/RECORD +0 -7
- {zammad_py-3.2.0.dist-info → zammad_py-3.2.1.dist-info}/LICENSE +0 -0
zammad_py/__init__.py
CHANGED
zammad_py/api.py
CHANGED
|
@@ -8,9 +8,24 @@ from typing import Any, Generator, List, Optional, Tuple
|
|
|
8
8
|
import requests
|
|
9
9
|
from requests.exceptions import HTTPError
|
|
10
10
|
|
|
11
|
-
from zammad_py.
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
from zammad_py.enums import KnowledgeBaseAnswerPublicity
|
|
12
|
+
from zammad_py.exceptions import (
|
|
13
|
+
ConfigException,
|
|
14
|
+
InvalidTypeError,
|
|
15
|
+
MissingParameterError,
|
|
16
|
+
UnusedResourceError,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"ZammadAPI",
|
|
21
|
+
# Exceptions
|
|
22
|
+
"ConfigException",
|
|
23
|
+
"UnusedResourceError",
|
|
24
|
+
"MissingParameterError",
|
|
25
|
+
"InvalidTypeError",
|
|
26
|
+
# Enums
|
|
27
|
+
"KnowledgeBaseAnswerPublicity",
|
|
28
|
+
]
|
|
14
29
|
|
|
15
30
|
|
|
16
31
|
class ZammadAPI:
|
|
@@ -110,7 +125,7 @@ class ZammadAPI:
|
|
|
110
125
|
return Ticket(connection=self)
|
|
111
126
|
|
|
112
127
|
@property
|
|
113
|
-
def link(self):
|
|
128
|
+
def link(self) -> "Link":
|
|
114
129
|
"""Return a `Link` instance"""
|
|
115
130
|
return Link(connection=self)
|
|
116
131
|
|
|
@@ -150,10 +165,25 @@ class ZammadAPI:
|
|
|
150
165
|
return TagList(connection=self)
|
|
151
166
|
|
|
152
167
|
@property
|
|
153
|
-
def ticket_tag(self):
|
|
168
|
+
def ticket_tag(self) -> "TicketTag":
|
|
154
169
|
"""Return a `TicketTag` instance"""
|
|
155
170
|
return TicketTag(connection=self)
|
|
156
171
|
|
|
172
|
+
@property
|
|
173
|
+
def knowledge_bases(self) -> "KnowledgeBases":
|
|
174
|
+
"""Return a `KnowledgeBases` instance"""
|
|
175
|
+
return KnowledgeBases(connection=self)
|
|
176
|
+
|
|
177
|
+
@property
|
|
178
|
+
def knowledge_bases_answers(self) -> "KnowledgeBasesAnswers":
|
|
179
|
+
"""Return an `KnowledgeBasesAnswers` instance"""
|
|
180
|
+
return KnowledgeBasesAnswers(connection=self)
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def knowledge_bases_categories(self) -> "KnowledgeBasesCategories":
|
|
184
|
+
"""Return an `KnowledgeBasesCategories` instance"""
|
|
185
|
+
return KnowledgeBasesCategories(connection=self)
|
|
186
|
+
|
|
157
187
|
|
|
158
188
|
class Pagination:
|
|
159
189
|
def __init__(
|
|
@@ -312,7 +342,7 @@ class Resource(ABC):
|
|
|
312
342
|
page=params["page"],
|
|
313
343
|
)
|
|
314
344
|
|
|
315
|
-
def find(self, id):
|
|
345
|
+
def find(self, id: int) -> Any:
|
|
316
346
|
"""Return the resource associated with the id
|
|
317
347
|
|
|
318
348
|
:param id: Resource id
|
|
@@ -320,7 +350,7 @@ class Resource(ABC):
|
|
|
320
350
|
response = self._connection.session.get(self.url + "/%s" % id)
|
|
321
351
|
return self._raise_or_return_json(response)
|
|
322
352
|
|
|
323
|
-
def create(self, params):
|
|
353
|
+
def create(self, params: Any) -> Any:
|
|
324
354
|
"""Create the requested resource
|
|
325
355
|
|
|
326
356
|
:param params: Resource data for creating
|
|
@@ -328,7 +358,7 @@ class Resource(ABC):
|
|
|
328
358
|
response = self._connection.session.post(self.url, json=params)
|
|
329
359
|
return self._raise_or_return_json(response)
|
|
330
360
|
|
|
331
|
-
def update(self, id, params):
|
|
361
|
+
def update(self, id: int, params: Any) -> Any:
|
|
332
362
|
"""Update the requested resource
|
|
333
363
|
|
|
334
364
|
:param id: Resource id
|
|
@@ -337,7 +367,7 @@ class Resource(ABC):
|
|
|
337
367
|
response = self._connection.session.put(self.url + "/%s" % id, json=params)
|
|
338
368
|
return self._raise_or_return_json(response)
|
|
339
369
|
|
|
340
|
-
def destroy(self, id):
|
|
370
|
+
def destroy(self, id: int) -> Any:
|
|
341
371
|
"""Delete the resource associated with the id
|
|
342
372
|
|
|
343
373
|
:param id: Resource id
|
|
@@ -361,7 +391,7 @@ class Organization(Resource):
|
|
|
361
391
|
class Ticket(Resource):
|
|
362
392
|
path_attribute = "tickets"
|
|
363
393
|
|
|
364
|
-
def articles(self, id):
|
|
394
|
+
def articles(self, id: int) -> Any:
|
|
365
395
|
"""Returns all the articles associated with the ticket id
|
|
366
396
|
|
|
367
397
|
:param id: Ticket id
|
|
@@ -371,7 +401,7 @@ class Ticket(Resource):
|
|
|
371
401
|
)
|
|
372
402
|
return self._raise_or_return_json(response)
|
|
373
403
|
|
|
374
|
-
def tags(self, id):
|
|
404
|
+
def tags(self, id: int) -> Any:
|
|
375
405
|
"""Returns all the tags associated with the ticket id
|
|
376
406
|
|
|
377
407
|
:param id: Ticket id
|
|
@@ -381,7 +411,7 @@ class Ticket(Resource):
|
|
|
381
411
|
)
|
|
382
412
|
return self._raise_or_return_json(response)
|
|
383
413
|
|
|
384
|
-
def merge(self, id, number):
|
|
414
|
+
def merge(self, id: int, number: int) -> Any:
|
|
385
415
|
"""Merges two tickets, (undocumented in Zammad Docs)
|
|
386
416
|
If the objects are already merged, it will return "Object already exists!"
|
|
387
417
|
Attention: Must use password to authenticate to Zammad, otherwise this will not work!
|
|
@@ -400,12 +430,12 @@ class Link(Resource):
|
|
|
400
430
|
|
|
401
431
|
def add(
|
|
402
432
|
self,
|
|
403
|
-
link_object_target_value,
|
|
404
|
-
link_object_source_number,
|
|
405
|
-
link_type="normal",
|
|
406
|
-
link_object_target="Ticket",
|
|
407
|
-
link_object_source="Ticket",
|
|
408
|
-
):
|
|
433
|
+
link_object_target_value: int,
|
|
434
|
+
link_object_source_number: int,
|
|
435
|
+
link_type: str = "normal",
|
|
436
|
+
link_object_target: str = "Ticket",
|
|
437
|
+
link_object_source: str = "Ticket",
|
|
438
|
+
) -> Any:
|
|
409
439
|
"""Create the link
|
|
410
440
|
|
|
411
441
|
:params link_type: Link type ('normal', 'parent', 'child')
|
|
@@ -429,12 +459,12 @@ class Link(Resource):
|
|
|
429
459
|
|
|
430
460
|
def remove(
|
|
431
461
|
self,
|
|
432
|
-
link_object_target_value,
|
|
433
|
-
link_object_source_number,
|
|
434
|
-
link_type="normal",
|
|
435
|
-
link_object_target="Ticket",
|
|
436
|
-
link_object_source="Ticket",
|
|
437
|
-
):
|
|
462
|
+
link_object_target_value: int,
|
|
463
|
+
link_object_source_number: int,
|
|
464
|
+
link_type: str = "normal",
|
|
465
|
+
link_object_target: str = "Ticket",
|
|
466
|
+
link_object_source: str = "Ticket",
|
|
467
|
+
) -> Any:
|
|
438
468
|
"""Remove the Link
|
|
439
469
|
|
|
440
470
|
:params link_type: Link type ('normal', 'parent', 'child')
|
|
@@ -454,7 +484,7 @@ class Link(Resource):
|
|
|
454
484
|
response = self._connection.session.delete(self.url + "/remove", json=params)
|
|
455
485
|
return self._raise_or_return_json(response)
|
|
456
486
|
|
|
457
|
-
def get(self, id):
|
|
487
|
+
def get(self, id: int) -> Any:
|
|
458
488
|
"""Returns all the links associated with the ticket id
|
|
459
489
|
|
|
460
490
|
:param id: Ticket id
|
|
@@ -473,7 +503,7 @@ class TicketArticle(Resource):
|
|
|
473
503
|
class TicketArticleAttachment(Resource):
|
|
474
504
|
path_attribute = "ticket_attachment"
|
|
475
505
|
|
|
476
|
-
def download(self, id, article_id, ticket_id):
|
|
506
|
+
def download(self, id: int, article_id: int, ticket_id: int) -> Any:
|
|
477
507
|
"""Download the ticket attachment associated with the ticket id
|
|
478
508
|
|
|
479
509
|
:param id: Ticket attachment id
|
|
@@ -501,7 +531,7 @@ class TicketState(Resource):
|
|
|
501
531
|
class User(Resource):
|
|
502
532
|
path_attribute = "users"
|
|
503
533
|
|
|
504
|
-
def me(self):
|
|
534
|
+
def me(self) -> Any:
|
|
505
535
|
"""Returns current user information"""
|
|
506
536
|
response = self._connection.session.get(self.url + "/me")
|
|
507
537
|
return self._raise_or_return_json(response)
|
|
@@ -510,7 +540,7 @@ class User(Resource):
|
|
|
510
540
|
class OnlineNotification(Resource):
|
|
511
541
|
path_attribute = "online_notifications"
|
|
512
542
|
|
|
513
|
-
def mark_all_read(self):
|
|
543
|
+
def mark_all_read(self) -> Any:
|
|
514
544
|
"""Marks all online notification as read"""
|
|
515
545
|
response = self._connection.session.post(self.url + "/mark_all_as_read")
|
|
516
546
|
return self._raise_or_return_json(response)
|
|
@@ -519,7 +549,7 @@ class OnlineNotification(Resource):
|
|
|
519
549
|
class Object(Resource):
|
|
520
550
|
path_attribute = "object_manager_attributes"
|
|
521
551
|
|
|
522
|
-
def execute_migrations(self):
|
|
552
|
+
def execute_migrations(self) -> Any:
|
|
523
553
|
"""Executes all database migrations"""
|
|
524
554
|
response = self._connection.session.post(
|
|
525
555
|
self._connection.url + "object_manager_attributes_execute_migrations"
|
|
@@ -538,7 +568,7 @@ class TicketTag(Resource):
|
|
|
538
568
|
|
|
539
569
|
path_attribute = "tags"
|
|
540
570
|
|
|
541
|
-
def add(self, id, tag, object="Ticket"):
|
|
571
|
+
def add(self, id: int, tag: str, object: str = "Ticket") -> Any:
|
|
542
572
|
"""Add a tag to a ticket
|
|
543
573
|
|
|
544
574
|
:param id: Ticket id
|
|
@@ -555,7 +585,7 @@ class TicketTag(Resource):
|
|
|
555
585
|
response = self._connection.session.post(self.url + "/add", json=params)
|
|
556
586
|
return self._raise_or_return_json(response)
|
|
557
587
|
|
|
558
|
-
def remove(self, id, tag, object="Ticket"):
|
|
588
|
+
def remove(self, id: int, tag: str, object: str = "Ticket") -> Any:
|
|
559
589
|
"""Remove a tag from a ticket.
|
|
560
590
|
|
|
561
591
|
:param id: Ticket id
|
|
@@ -571,3 +601,399 @@ class TicketTag(Resource):
|
|
|
571
601
|
|
|
572
602
|
response = self._connection.session.delete(self.url + "/remove", json=params)
|
|
573
603
|
return self._raise_or_return_json(response)
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
class KnowledgeBases(Resource):
|
|
607
|
+
path_attribute = "knowledge_bases"
|
|
608
|
+
|
|
609
|
+
def init(self) -> Any:
|
|
610
|
+
"""Returns a bootstrap object containing the entire structure (settings, categories, and answer IDs) of the knowledge base"""
|
|
611
|
+
response = self._connection.session.post(
|
|
612
|
+
self._connection.url + "knowledge_bases/init"
|
|
613
|
+
)
|
|
614
|
+
return self._raise_or_return_json(response)
|
|
615
|
+
|
|
616
|
+
def manage(self, id: int, settings: dict) -> Any:
|
|
617
|
+
"""Updates specific knowledge base settings like custom URLs, colors, or visibility toggles
|
|
618
|
+
|
|
619
|
+
:param id: Knowledge Base ID
|
|
620
|
+
:param settings: Dictionary of setting to be applied to the knowledge base
|
|
621
|
+
"""
|
|
622
|
+
response = self._connection.session.patch(
|
|
623
|
+
self._connection.url + "knowledge_bases/manage/%s" % id, json=settings
|
|
624
|
+
)
|
|
625
|
+
return self._raise_or_return_json(response)
|
|
626
|
+
|
|
627
|
+
def show_permissions(self, id: int) -> Any:
|
|
628
|
+
"""Returns a list of roles and their associated access levels (reader/editor) for the knowledge base
|
|
629
|
+
|
|
630
|
+
:param id: Knowledge Base ID
|
|
631
|
+
"""
|
|
632
|
+
response = self._connection.session.get(
|
|
633
|
+
self._connection.url + "knowledge_bases/%s/permissions" % id,
|
|
634
|
+
)
|
|
635
|
+
return self._raise_or_return_json(response)
|
|
636
|
+
|
|
637
|
+
def change_permissions(self, id: int, permissions: dict) -> Any:
|
|
638
|
+
"""Replaces the current permission set with a new mapping of roles and access levels
|
|
639
|
+
|
|
640
|
+
:param id: Knowledge Base ID
|
|
641
|
+
:param permissions: Dictionary of new permissions to be applied to the knowledge base
|
|
642
|
+
"""
|
|
643
|
+
response = self._connection.session.put(
|
|
644
|
+
self._connection.url + "knowledge_bases/%s/permissions" % id,
|
|
645
|
+
json=permissions,
|
|
646
|
+
)
|
|
647
|
+
return self._raise_or_return_json(response)
|
|
648
|
+
|
|
649
|
+
def reorder_sub_categories(self, id: int, category_id: int, params: dict) -> Any:
|
|
650
|
+
"""Updates the display order of sub-categories within a specific parent category
|
|
651
|
+
|
|
652
|
+
:param id: Knowledge Base ID
|
|
653
|
+
:param category_id: Knowledge Base Category ID
|
|
654
|
+
:param params: A dictionary containing 'ordered_ids' (a list of sub-category IDs) in the desired sequence
|
|
655
|
+
"""
|
|
656
|
+
response = self._connection.session.patch(
|
|
657
|
+
self._connection.url
|
|
658
|
+
+ f"knowledge_bases/{id}/categories/{category_id}/reorder_categories",
|
|
659
|
+
json=params,
|
|
660
|
+
)
|
|
661
|
+
return self._raise_or_return_json(response)
|
|
662
|
+
|
|
663
|
+
def reorder_root_categories(self, id: int, params: dict) -> Any:
|
|
664
|
+
"""Updates the display order of all top-level categories on the knowledge base homepage
|
|
665
|
+
|
|
666
|
+
:param id: Knowledge Base ID
|
|
667
|
+
:param params: A dictionary containing 'ordered_ids' (a list of category IDs) in the desired sequence
|
|
668
|
+
"""
|
|
669
|
+
response = self._connection.session.patch(
|
|
670
|
+
self._connection.url
|
|
671
|
+
+ "knowledge_bases/%s/categories/reorder_root_categories" % id,
|
|
672
|
+
json=params,
|
|
673
|
+
)
|
|
674
|
+
return self._raise_or_return_json(response)
|
|
675
|
+
|
|
676
|
+
def all(self, page: int = 1, filters=None) -> Pagination:
|
|
677
|
+
"""Disabled: Zammad does not support a flat list of all knowledge bases"""
|
|
678
|
+
raise UnusedResourceError(self.__class__.__name__, "all")
|
|
679
|
+
|
|
680
|
+
def search(self, search_string: str, page: int = 1, filters=None) -> Pagination:
|
|
681
|
+
"""Disabled: Knowledge base search is not supported"""
|
|
682
|
+
raise UnusedResourceError(self.__class__.__name__, "search")
|
|
683
|
+
|
|
684
|
+
def find(self, id: int) -> Any:
|
|
685
|
+
"""Disabled: Knowledge base find is not supported"""
|
|
686
|
+
raise UnusedResourceError(self.__class__.__name__, "find")
|
|
687
|
+
|
|
688
|
+
def create(self, params: Any) -> Any:
|
|
689
|
+
"""Disabled: Creation of new knowledge base instances is typically handled via the init method"""
|
|
690
|
+
raise UnusedResourceError(self.__class__.__name__, "create")
|
|
691
|
+
|
|
692
|
+
def update(self, id: int, params: Any) -> Any:
|
|
693
|
+
"""Disabled: Update of a knowledge base instances is typically handled via the manage method"""
|
|
694
|
+
raise UnusedResourceError(self.__class__.__name__, "update")
|
|
695
|
+
|
|
696
|
+
def destroy(self, id: int) -> Any:
|
|
697
|
+
"""Disabled: Knowledge base destroy is not supported"""
|
|
698
|
+
raise UnusedResourceError(self.__class__.__name__, "destroy")
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
class KnowledgeBasesAnswers(Resource):
|
|
702
|
+
path_attribute = "knowledge_bases"
|
|
703
|
+
|
|
704
|
+
def all(self, page: int = 1, filters=None) -> Pagination:
|
|
705
|
+
"""Disabled: Zammad does not support a flat list of all answers"""
|
|
706
|
+
raise UnusedResourceError(self.__class__.__name__, "all")
|
|
707
|
+
|
|
708
|
+
def search(self, search_string: str, page: int = 1, filters=None) -> Pagination:
|
|
709
|
+
"""Disabled: Answers search is not supported"""
|
|
710
|
+
raise UnusedResourceError(self.__class__.__name__, "search")
|
|
711
|
+
|
|
712
|
+
def find(self, id: int) -> Any:
|
|
713
|
+
"""Disabled: Retrieving an answer requires both knowledge_base_id and answer_id"""
|
|
714
|
+
raise UnusedResourceError(self.__class__.__name__, "find")
|
|
715
|
+
|
|
716
|
+
def find_answer(
|
|
717
|
+
self,
|
|
718
|
+
knowledge_base_id: int,
|
|
719
|
+
answer_id: int,
|
|
720
|
+
include_content_id: Optional[int] = None,
|
|
721
|
+
) -> Any:
|
|
722
|
+
"""Retrieves a specific answer from a knowledge base, optionally including content details
|
|
723
|
+
|
|
724
|
+
:param knowledge_base_id: Knowledge Base ID
|
|
725
|
+
:param answer_id: Knowledge Base Answer ID
|
|
726
|
+
:param include_content_id: Optional ID to include specific translated content (localization) in the response
|
|
727
|
+
"""
|
|
728
|
+
if include_content_id is None:
|
|
729
|
+
find_answer_url = (
|
|
730
|
+
self._connection.url
|
|
731
|
+
+ "knowledge_bases/{}/answers/{}".format(
|
|
732
|
+
knowledge_base_id,
|
|
733
|
+
answer_id,
|
|
734
|
+
)
|
|
735
|
+
)
|
|
736
|
+
else:
|
|
737
|
+
find_answer_url = (
|
|
738
|
+
self._connection.url
|
|
739
|
+
+ "knowledge_bases/%s/answers/%s?include_contents=%s"
|
|
740
|
+
% (knowledge_base_id, answer_id, include_content_id)
|
|
741
|
+
)
|
|
742
|
+
|
|
743
|
+
response = self._connection.session.get(find_answer_url)
|
|
744
|
+
return self._raise_or_return_json(response)
|
|
745
|
+
|
|
746
|
+
def create(self, params: dict) -> Any:
|
|
747
|
+
"""Creates a new answer within a specified knowledge base
|
|
748
|
+
|
|
749
|
+
:param params: A dictionary containing all the required details for creating the new answer.
|
|
750
|
+
The dictionary must include "knowledge_base_id" field representing the Knowledge Base ID
|
|
751
|
+
"""
|
|
752
|
+
if not isinstance(params, dict):
|
|
753
|
+
raise InvalidTypeError("params", dict, type(params))
|
|
754
|
+
|
|
755
|
+
if "knowledge_base_id" not in params:
|
|
756
|
+
raise MissingParameterError(
|
|
757
|
+
"knowledge_base_id", context="create knowledge base answer"
|
|
758
|
+
)
|
|
759
|
+
|
|
760
|
+
knowledge_base_id = params.pop("knowledge_base_id")
|
|
761
|
+
|
|
762
|
+
response = self._connection.session.post(
|
|
763
|
+
self._connection.url + "knowledge_bases/%s/answers" % knowledge_base_id,
|
|
764
|
+
json=params,
|
|
765
|
+
)
|
|
766
|
+
return self._raise_or_return_json(response)
|
|
767
|
+
|
|
768
|
+
def update(self, id: int, params: dict) -> Any:
|
|
769
|
+
"""Updates an existing answer using the knowledge base ID and the answer ID
|
|
770
|
+
|
|
771
|
+
:param id: Knowledge Base Answer ID
|
|
772
|
+
:param params: A dictionary containing all the required details for updating the answer.
|
|
773
|
+
The dictionary must include "answer_id" field representing the Knowledge Base Answer ID
|
|
774
|
+
"""
|
|
775
|
+
if not isinstance(params, dict):
|
|
776
|
+
raise InvalidTypeError("params", dict, type(params))
|
|
777
|
+
|
|
778
|
+
if "answer_id" not in params:
|
|
779
|
+
raise MissingParameterError(
|
|
780
|
+
"answer_id", context="update knowledge base answer"
|
|
781
|
+
)
|
|
782
|
+
|
|
783
|
+
answer_id = params.pop("answer_id")
|
|
784
|
+
|
|
785
|
+
response = self._connection.session.patch(
|
|
786
|
+
self._connection.url + f"knowledge_bases/{id}/answers/{answer_id}",
|
|
787
|
+
json=params,
|
|
788
|
+
)
|
|
789
|
+
return self._raise_or_return_json(response)
|
|
790
|
+
|
|
791
|
+
def destroy(self, id: int) -> Any:
|
|
792
|
+
"""Disabled: Permanent deletion requires both knowledge_base_id and answer_id
|
|
793
|
+
|
|
794
|
+
:param id: Knowledge Base Answer ID
|
|
795
|
+
"""
|
|
796
|
+
raise UnusedResourceError(self.__class__.__name__, "destroy")
|
|
797
|
+
|
|
798
|
+
def destroy_answer(self, knowledge_base_id: int, answer_id: int) -> Any:
|
|
799
|
+
"""Permanently deletes an answer from the knowledge base
|
|
800
|
+
|
|
801
|
+
:param knowledge_base_id: Knowledge Base ID
|
|
802
|
+
:param answer_id: Knowledge Base Answer ID
|
|
803
|
+
"""
|
|
804
|
+
response = self._connection.session.delete(
|
|
805
|
+
self._connection.url
|
|
806
|
+
+ f"knowledge_bases/{knowledge_base_id}/answers/{answer_id}"
|
|
807
|
+
)
|
|
808
|
+
return self._raise_or_return_json(response)
|
|
809
|
+
|
|
810
|
+
def change_answer_visibility(
|
|
811
|
+
self,
|
|
812
|
+
knowledge_base_id: int,
|
|
813
|
+
answer_id: int,
|
|
814
|
+
answer_visibility: KnowledgeBaseAnswerPublicity,
|
|
815
|
+
) -> Any:
|
|
816
|
+
"""Updates the publication state (e.g., draft, public, internal) of a specific answer
|
|
817
|
+
|
|
818
|
+
:param knowledge_base_id: Knowledge Base ID
|
|
819
|
+
:param answer_id: Knowledge Base Answer ID
|
|
820
|
+
:param answer_visibility: The publication state of the answer (e.g., draft, internal, or public)
|
|
821
|
+
"""
|
|
822
|
+
response = self._connection.session.post(
|
|
823
|
+
self._connection.url
|
|
824
|
+
+ "knowledge_bases/%s/answers/%s/%s"
|
|
825
|
+
% (knowledge_base_id, answer_id, answer_visibility.value)
|
|
826
|
+
)
|
|
827
|
+
return self._raise_or_return_json(response)
|
|
828
|
+
|
|
829
|
+
def add_attachment(
|
|
830
|
+
self, knowledge_base_id: int, answer_id: int, attachment: Any
|
|
831
|
+
) -> Any:
|
|
832
|
+
"""Uploads a file as an attachment to an answer using multipart/form-data
|
|
833
|
+
|
|
834
|
+
:param knowledge_base_id: Knowledge Base ID
|
|
835
|
+
:param answer_id: Knowledge Base Answer ID
|
|
836
|
+
:param attachment: The file to be uploaded to the answer as an attachment
|
|
837
|
+
"""
|
|
838
|
+
response = self._connection.session.post(
|
|
839
|
+
self._connection.url
|
|
840
|
+
+ "knowledge_bases/%s/answers/%s/attachments"
|
|
841
|
+
% (knowledge_base_id, answer_id),
|
|
842
|
+
files={"file": attachment},
|
|
843
|
+
)
|
|
844
|
+
return self._raise_or_return_json(response)
|
|
845
|
+
|
|
846
|
+
def delete_attachment(
|
|
847
|
+
self, knowledge_base_id: int, answer_id: int, attachment_id: int
|
|
848
|
+
) -> Any:
|
|
849
|
+
"""Removes a specific attachment from an answer by its attachment ID
|
|
850
|
+
|
|
851
|
+
:param knowledge_base_id: Knowledge Base ID
|
|
852
|
+
:param answer_id: Knowledge Base Answer ID
|
|
853
|
+
:param attachment_id: Attachment ID
|
|
854
|
+
"""
|
|
855
|
+
response = self._connection.session.delete(
|
|
856
|
+
self._connection.url
|
|
857
|
+
+ "knowledge_bases/%s/answers/%s/attachments/%s"
|
|
858
|
+
% (knowledge_base_id, answer_id, attachment_id)
|
|
859
|
+
)
|
|
860
|
+
return self._raise_or_return_json(response)
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
class KnowledgeBasesCategories(Resource):
|
|
864
|
+
path_attribute = "knowledge_bases"
|
|
865
|
+
|
|
866
|
+
def all(self, page: int = 1, filters=None) -> Pagination:
|
|
867
|
+
"""Disabled: Zammad does not support a flat list of all knowledge base categories"""
|
|
868
|
+
raise UnusedResourceError(self.__class__.__name__, "all")
|
|
869
|
+
|
|
870
|
+
def search(self, search_string: str, page: int = 1, filters=None) -> Pagination:
|
|
871
|
+
"""Disabled: Knowledge base categories search is not supported"""
|
|
872
|
+
raise UnusedResourceError(self.__class__.__name__, "search")
|
|
873
|
+
|
|
874
|
+
def find(self, id: int) -> Any:
|
|
875
|
+
"""Disabled: Retrieving an answer requires both knowledge_base_id and category_id"""
|
|
876
|
+
raise UnusedResourceError(self.__class__.__name__, "find")
|
|
877
|
+
|
|
878
|
+
def find_category(self, knowledge_base_id: int, category_id: int) -> Any:
|
|
879
|
+
"""Retrieves a specific category from a knowledge base
|
|
880
|
+
|
|
881
|
+
:param knowledge_base_id: Knowledge Base ID
|
|
882
|
+
:param category_id: Knowledge Base Category ID
|
|
883
|
+
"""
|
|
884
|
+
response = self._connection.session.get(
|
|
885
|
+
self._connection.url
|
|
886
|
+
+ f"knowledge_bases/{knowledge_base_id}/categories/{category_id}"
|
|
887
|
+
)
|
|
888
|
+
return self._raise_or_return_json(response)
|
|
889
|
+
|
|
890
|
+
def create(self, params: dict) -> Any:
|
|
891
|
+
"""Creates a new category within a specified knowledge base
|
|
892
|
+
|
|
893
|
+
:param params: A dictionary containing all the required details for creating the new knowledge base category.
|
|
894
|
+
The dictionary must include "knowledge_base_id" field representing the Knowledge Base ID
|
|
895
|
+
"""
|
|
896
|
+
if not isinstance(params, dict):
|
|
897
|
+
raise InvalidTypeError("params", dict, type(params))
|
|
898
|
+
|
|
899
|
+
if "knowledge_base_id" not in params:
|
|
900
|
+
raise MissingParameterError(
|
|
901
|
+
"knowledge_base_id", context="create knowledge base category"
|
|
902
|
+
)
|
|
903
|
+
|
|
904
|
+
knowledge_base_id = params.pop("knowledge_base_id")
|
|
905
|
+
|
|
906
|
+
response = self._connection.session.post(
|
|
907
|
+
self._connection.url + "knowledge_bases/%s/categories" % knowledge_base_id,
|
|
908
|
+
json=params,
|
|
909
|
+
)
|
|
910
|
+
return self._raise_or_return_json(response)
|
|
911
|
+
|
|
912
|
+
def update(self, id: int, params: dict) -> Any:
|
|
913
|
+
"""Updates an existing category using the knowledge base ID and the category ID
|
|
914
|
+
|
|
915
|
+
:param id: Knowledge Base ID
|
|
916
|
+
:param params: A dictionary containing all the required details for updating the knowledge base category.
|
|
917
|
+
The dictionary must include "category_id" field representing the Knowledge Base Category ID
|
|
918
|
+
"""
|
|
919
|
+
if not isinstance(params, dict):
|
|
920
|
+
raise InvalidTypeError("params", dict, type(params))
|
|
921
|
+
|
|
922
|
+
if "category_id" not in params:
|
|
923
|
+
raise MissingParameterError(
|
|
924
|
+
"category_id", context="update knowledge base category"
|
|
925
|
+
)
|
|
926
|
+
|
|
927
|
+
category_id = params.pop("category_id")
|
|
928
|
+
|
|
929
|
+
response = self._connection.session.patch(
|
|
930
|
+
self._connection.url + f"knowledge_bases/{id}/categories/{category_id}",
|
|
931
|
+
json=params,
|
|
932
|
+
)
|
|
933
|
+
return self._raise_or_return_json(response)
|
|
934
|
+
|
|
935
|
+
def destroy(self, id: int) -> Any:
|
|
936
|
+
"""Disabled: Permanent deletion requires both knowledge_base_id and category_id
|
|
937
|
+
|
|
938
|
+
:param id: Knowledge Base Category ID
|
|
939
|
+
"""
|
|
940
|
+
raise UnusedResourceError(self.__class__.__name__, "destroy")
|
|
941
|
+
|
|
942
|
+
def destroy_category(self, knowledge_base_id: int, category_id: int) -> Any:
|
|
943
|
+
"""Permanently deletes a category from the knowledge base
|
|
944
|
+
|
|
945
|
+
:param knowledge_base_id: Knowledge Base ID
|
|
946
|
+
:param category_id: Knowledge Base Category ID
|
|
947
|
+
"""
|
|
948
|
+
response = self._connection.session.delete(
|
|
949
|
+
self._connection.url
|
|
950
|
+
+ f"knowledge_bases/{knowledge_base_id}/categories/{category_id}"
|
|
951
|
+
)
|
|
952
|
+
return self._raise_or_return_json(response)
|
|
953
|
+
|
|
954
|
+
def show_permissions(self, knowledge_base_id: int, category_id: int) -> Any:
|
|
955
|
+
"""Returns a list of roles and their associated access levels (reader/editor) for the knowledge base category
|
|
956
|
+
|
|
957
|
+
:param knowledge_base_id: Knowledge Base ID
|
|
958
|
+
:param category_id: Knowledge Base Category ID
|
|
959
|
+
"""
|
|
960
|
+
response = self._connection.session.get(
|
|
961
|
+
self._connection.url
|
|
962
|
+
+ "knowledge_bases/%s/categories/%s/permissions"
|
|
963
|
+
% (knowledge_base_id, category_id),
|
|
964
|
+
)
|
|
965
|
+
return self._raise_or_return_json(response)
|
|
966
|
+
|
|
967
|
+
def change_permissions(
|
|
968
|
+
self, knowledge_base_id: int, category_id: int, permissions: dict
|
|
969
|
+
) -> Any:
|
|
970
|
+
"""Replaces the current permission set with a new mapping of roles and access levels
|
|
971
|
+
|
|
972
|
+
:param knowledge_base_id: Knowledge Base ID
|
|
973
|
+
:param category_id: Knowledge Base Category ID
|
|
974
|
+
:param permissions: Dictionary of new permissions to be applied to the knowledge base category
|
|
975
|
+
"""
|
|
976
|
+
response = self._connection.session.put(
|
|
977
|
+
self._connection.url
|
|
978
|
+
+ "knowledge_bases/%s/categories/%s/permissions"
|
|
979
|
+
% (knowledge_base_id, category_id),
|
|
980
|
+
json=permissions,
|
|
981
|
+
)
|
|
982
|
+
return self._raise_or_return_json(response)
|
|
983
|
+
|
|
984
|
+
def reorder_answers(
|
|
985
|
+
self, knowledge_base_id: int, category_id: int, params: dict
|
|
986
|
+
) -> Any:
|
|
987
|
+
"""Updates the display order of answers within a specific category
|
|
988
|
+
|
|
989
|
+
:param knowledge_base_id: Knowledge Base ID
|
|
990
|
+
:param category_id: Knowledge Base Category ID
|
|
991
|
+
:param params: A dictionary containing 'ordered_ids' (a list of answer IDs) in the desired sequence
|
|
992
|
+
"""
|
|
993
|
+
response = self._connection.session.patch(
|
|
994
|
+
self._connection.url
|
|
995
|
+
+ "knowledge_bases/%s/categories/%s/reorder_answers"
|
|
996
|
+
% (knowledge_base_id, category_id),
|
|
997
|
+
json=params,
|
|
998
|
+
)
|
|
999
|
+
return self._raise_or_return_json(response)
|
zammad_py/enums.py
ADDED
zammad_py/exceptions.py
CHANGED
|
@@ -1,2 +1,36 @@
|
|
|
1
1
|
class ConfigException(Exception):
|
|
2
2
|
pass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class UnusedResourceError(NotImplementedError):
|
|
6
|
+
"""Exception raised when a method is not supported by a specific Zammad resource."""
|
|
7
|
+
|
|
8
|
+
def __init__(self, resource_name, method_name):
|
|
9
|
+
self.message = f"The method '{method_name}' is not available for the {resource_name} resource."
|
|
10
|
+
super().__init__(self.message)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MissingParameterError(ValueError):
|
|
14
|
+
"""Exception raised when a required field is missing from the parameters."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, field_name, context=None):
|
|
17
|
+
self.field_name = field_name
|
|
18
|
+
self.context = context
|
|
19
|
+
message = f"Missing required parameter: '{field_name}'"
|
|
20
|
+
if context:
|
|
21
|
+
message += f" in {context}"
|
|
22
|
+
super().__init__(message)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class InvalidTypeError(TypeError):
|
|
26
|
+
"""Exception raised when a variable is not of the expected type."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, variable_name, expected_type, actual_type):
|
|
29
|
+
self.variable_name = variable_name
|
|
30
|
+
self.expected_type = expected_type
|
|
31
|
+
self.actual_type = actual_type
|
|
32
|
+
message = (
|
|
33
|
+
f"Variable '{variable_name}' must be of type {expected_type.__name__}, "
|
|
34
|
+
f"but got {actual_type.__name__} instead."
|
|
35
|
+
)
|
|
36
|
+
super().__init__(message)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: zammad_py
|
|
3
|
+
Version: 3.2.1
|
|
4
|
+
Summary: Python API client for zammad
|
|
5
|
+
Home-page: https://github.com/joeirimpan/zammad_py
|
|
6
|
+
License: MIT
|
|
7
|
+
Author: Joe Paul
|
|
8
|
+
Author-email: joeirimpan@gmail.com
|
|
9
|
+
Requires-Python: >=3.9,<4.0
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Requires-Dist: requests (>=2.25.1,<3.0.0)
|
|
21
|
+
Project-URL: Documentation, https://zammad-py.readthedocs.io/
|
|
22
|
+
Project-URL: Repository, https://github.com/joeirimpan/zammad_py.git
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# Zammad API Client
|
|
26
|
+
|
|
27
|
+
[](https://pypi.python.org/pypi/zammad_py)
|
|
28
|
+
[](https://zammad-py.readthedocs.io/en/latest/?badge=latest)
|
|
29
|
+
|
|
30
|
+
Python API client for zammad
|
|
31
|
+
|
|
32
|
+
* Free software: MIT license
|
|
33
|
+
* Documentation: https://zammad-py.readthedocs.io.
|
|
34
|
+
|
|
35
|
+
## Quickstart
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from zammad_py import ZammadAPI
|
|
39
|
+
|
|
40
|
+
# Initialize the client with the URL, username, and password
|
|
41
|
+
# Note the Host URL should be in this format: 'https://zammad.example.org/api/v1/'
|
|
42
|
+
client = ZammadAPI(url='<HOST>', username='<USERNAME>', password='<PASSWORD>')
|
|
43
|
+
|
|
44
|
+
# Example: Access all users
|
|
45
|
+
this_page = client.user.all()
|
|
46
|
+
for user in this_page:
|
|
47
|
+
print(user)
|
|
48
|
+
|
|
49
|
+
# Example: Get information about the current user
|
|
50
|
+
print(client.user.me())
|
|
51
|
+
|
|
52
|
+
# Example: Create a ticket
|
|
53
|
+
params = {
|
|
54
|
+
"title": "Help me!",
|
|
55
|
+
"group": "2nd Level",
|
|
56
|
+
"customer": "david@example.com",
|
|
57
|
+
"article": {
|
|
58
|
+
"subject": "My subject",
|
|
59
|
+
"body": "I am a message!",
|
|
60
|
+
"type": "note",
|
|
61
|
+
"internal": False
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
new_ticket = client.ticket.create(params=params)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## General Methods
|
|
68
|
+
|
|
69
|
+
Most resources support these methods:
|
|
70
|
+
|
|
71
|
+
- `.all()`: Returns a paginated response with the current page number and a list of elements.
|
|
72
|
+
- `.next_page()`: Returns the next page of the current pagination object.
|
|
73
|
+
- `.prev_page()`: Returns the previous page of the current pagination object.
|
|
74
|
+
- `.search(params)`: Returns a paginated response based on the search parameters.
|
|
75
|
+
- `.find(id)`: Returns a single object with the specified ID.
|
|
76
|
+
- `.create(params)`: Creates a new object with the specified parameters.
|
|
77
|
+
- `.update(params)`: Updates an existing object with the specified parameters.
|
|
78
|
+
- `.destroy(id)`: Deletes an object with the specified ID.
|
|
79
|
+
|
|
80
|
+
## Available Resources
|
|
81
|
+
|
|
82
|
+
| Resource | Property |
|
|
83
|
+
|----------|----------|
|
|
84
|
+
| User | `client.user` |
|
|
85
|
+
| Organization | `client.organization` |
|
|
86
|
+
| Group | `client.group` |
|
|
87
|
+
| Role | `client.role` |
|
|
88
|
+
| Ticket | `client.ticket` |
|
|
89
|
+
| Link | `client.link` |
|
|
90
|
+
| TicketArticle | `client.ticket_article` |
|
|
91
|
+
| TicketArticleAttachment | `client.ticket_article_attachment` |
|
|
92
|
+
| TicketArticlePlain | `client.ticket_article_plain` |
|
|
93
|
+
| TicketPriority | `client.ticket_priority` |
|
|
94
|
+
| TicketState | `client.ticket_state` |
|
|
95
|
+
| TagList | `client.taglist` |
|
|
96
|
+
| TicketTag | `client.ticket_tag` |
|
|
97
|
+
| KnowledgeBases | `client.knowledge_bases` |
|
|
98
|
+
| KnowledgeBasesAnswers | `client.knowledge_bases_answers` |
|
|
99
|
+
| KnowledgeBasesCategories | `client.knowledge_bases_categories` |
|
|
100
|
+
|
|
101
|
+
## Resource-Specific Methods
|
|
102
|
+
|
|
103
|
+
### User
|
|
104
|
+
- `.me()`: Returns information about the current user.
|
|
105
|
+
|
|
106
|
+
### Ticket
|
|
107
|
+
- `.articles(id)`: Returns all articles associated with a ticket.
|
|
108
|
+
- `.tags(id)`: Returns all tags associated with a ticket.
|
|
109
|
+
- `.merge(id, number)`: Merges two tickets (requires password auth).
|
|
110
|
+
|
|
111
|
+
### Link
|
|
112
|
+
- `.get(id)`: Returns all links associated with a ticket.
|
|
113
|
+
- `.add(...)`: Creates a link between two objects.
|
|
114
|
+
- `.remove(...)`: Removes a link between two objects.
|
|
115
|
+
|
|
116
|
+
### TicketArticleAttachment
|
|
117
|
+
- `.download(id, article_id, ticket_id)`: Downloads a ticket attachment.
|
|
118
|
+
|
|
119
|
+
### TagList
|
|
120
|
+
- `.all()`: Returns all tags (paginated).
|
|
121
|
+
- `.create(params)`: Creates a new tag.
|
|
122
|
+
- `.destroy(id)`: Deletes a tag.
|
|
123
|
+
|
|
124
|
+
### TicketTag
|
|
125
|
+
- `.add(id, tag)`: Adds a tag to a ticket.
|
|
126
|
+
- `.remove(id, tag)`: Removes a tag from a ticket.
|
|
127
|
+
|
|
128
|
+
### KnowledgeBases
|
|
129
|
+
- `.init()`: Returns the entire knowledge base structure.
|
|
130
|
+
- `.manage(id, settings)`: Updates knowledge base settings.
|
|
131
|
+
- `.show_permissions(id)`: Returns permissions for a knowledge base.
|
|
132
|
+
- `.change_permissions(id, permissions)`: Updates permissions.
|
|
133
|
+
- `.reorder_sub_categories(id, category_id, params)`: Reorders sub-categories.
|
|
134
|
+
- `.reorder_root_categories(id, params)`: Reorders root categories.
|
|
135
|
+
|
|
136
|
+
### KnowledgeBasesAnswers
|
|
137
|
+
- `.find_answer(knowledge_base_id, answer_id)`: Retrieves a specific answer.
|
|
138
|
+
- `.create(params)`: Creates a new answer (requires `knowledge_base_id` in params).
|
|
139
|
+
- `.update(id, params)`: Updates an answer (requires `answer_id` in params).
|
|
140
|
+
- `.destroy_answer(knowledge_base_id, answer_id)`: Deletes an answer.
|
|
141
|
+
- `.change_answer_visibility(knowledge_base_id, answer_id, visibility)`: Updates answer visibility.
|
|
142
|
+
- `.add_attachment(knowledge_base_id, answer_id, attachment)`: Uploads an attachment.
|
|
143
|
+
- `.delete_attachment(knowledge_base_id, answer_id, attachment_id)`: Removes an attachment.
|
|
144
|
+
|
|
145
|
+
### KnowledgeBasesCategories
|
|
146
|
+
- `.find_category(knowledge_base_id, category_id)`: Retrieves a specific category.
|
|
147
|
+
- `.create(params)`: Creates a new category (requires `knowledge_base_id` in params).
|
|
148
|
+
- `.update(id, params)`: Updates a category (requires `category_id` in params).
|
|
149
|
+
- `.destroy_category(knowledge_base_id, category_id)`: Deletes a category.
|
|
150
|
+
- `.show_permissions(knowledge_base_id, category_id)`: Returns category permissions.
|
|
151
|
+
- `.change_permissions(knowledge_base_id, category_id, permissions)`: Updates permissions.
|
|
152
|
+
- `.reorder_answers(knowledge_base_id, category_id, params)`: Reorders answers.
|
|
153
|
+
|
|
154
|
+
## On Behalf Of
|
|
155
|
+
|
|
156
|
+
You can set the `on_behalf_of` attribute to perform actions on behalf of another user:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
client.on_behalf_of = 'user@example.com'
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Or use the context manager:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
with client.request_on_behalf_of('user@example.com'):
|
|
166
|
+
client.ticket.create(params=params)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Contributing
|
|
170
|
+
|
|
171
|
+
The Zammad API Client (zammad_py) welcomes contributions.
|
|
172
|
+
|
|
173
|
+
You can contribute by reporting bugs, fixing bugs, implementing new features, writing documentation, and submitting feedback.
|
|
174
|
+
|
|
175
|
+
To get started, see the contributing section in the docs!
|
|
176
|
+
|
|
177
|
+
Please ensure that your changes include tests and updated documentation if necessary.
|
|
178
|
+
|
|
179
|
+
## Credits
|
|
180
|
+
|
|
181
|
+
This package was created with [Cookiecutter](https://github.com/audreyr/cookiecutter) and the [audreyr/cookiecutter-pypackage](https://github.com/audreyr/cookiecutter-pypackage) project template.
|
|
182
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
zammad_py/__init__.py,sha256=Xu6tdXhuBbsKnzvlTOw11Nx7VvNakukOWC6ViW-3_Wg,175
|
|
2
|
+
zammad_py/api.py,sha256=JfaEMrLpo-F7DpT2hsK37QgK6pT_l8TNpzLHag50fMM,35323
|
|
3
|
+
zammad_py/enums.py,sha256=9mSsJ_GV7aqpzk3awB6ZvFT3xzzTBHgWENiBR4ezh3I,171
|
|
4
|
+
zammad_py/exceptions.py,sha256=-ABU-554T5MY2AI9KaVZm-iroiaXzakb3AIUa35Px9s,1285
|
|
5
|
+
zammad_py-3.2.1.dist-info/AUTHORS.md,sha256=NRpF3uzp7H8H_DqYsNRdopQNCniINZs0Ya3oGPSUOfk,119
|
|
6
|
+
zammad_py-3.2.1.dist-info/LICENSE,sha256=NNe9mRfWIQ3cigyQ1-cBQA5bRPuarc1iWRkfa72jSm0,1065
|
|
7
|
+
zammad_py-3.2.1.dist-info/METADATA,sha256=Me3XXn1fjAYL46mJEiuSDDl_n5EBY-jrYKOIqDECTu4,6786
|
|
8
|
+
zammad_py-3.2.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
9
|
+
zammad_py-3.2.1.dist-info/RECORD,,
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: zammad_py
|
|
3
|
-
Version: 3.2.0
|
|
4
|
-
Summary: Python API client for zammad
|
|
5
|
-
Home-page: https://github.com/joeirimpan/zammad_py
|
|
6
|
-
License: MIT
|
|
7
|
-
Author: Joe Paul
|
|
8
|
-
Author-email: joeirimpan@gmail.com
|
|
9
|
-
Requires-Python: >=3.9,<4.0
|
|
10
|
-
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
-
Classifier: Natural Language :: English
|
|
14
|
-
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
-
Requires-Dist: requests (>=2.25.1,<3.0.0)
|
|
20
|
-
Project-URL: Documentation, https://zammad-py.readthedocs.io/
|
|
21
|
-
Project-URL: Repository, https://github.com/joeirimpan/zammad_py.git
|
|
22
|
-
Description-Content-Type: text/x-rst
|
|
23
|
-
|
|
24
|
-
=================
|
|
25
|
-
Zammad API Client
|
|
26
|
-
=================
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
.. image:: https://img.shields.io/pypi/v/zammad_py.svg
|
|
30
|
-
:target: https://pypi.python.org/pypi/zammad_py
|
|
31
|
-
|
|
32
|
-
.. image:: https://img.shields.io/travis/joeirimpan/zammad_py.svg
|
|
33
|
-
:target: https://travis-ci.org/joeirimpan/zammad_py
|
|
34
|
-
|
|
35
|
-
.. image:: https://readthedocs.org/projects/zammad-py/badge/?version=latest
|
|
36
|
-
:target: https://zammad-py.readthedocs.io/en/latest/?badge=latest
|
|
37
|
-
:alt: Documentation Status
|
|
38
|
-
|
|
39
|
-
.. image:: https://pyup.io/repos/github/joeirimpan/zammad_py/shield.svg
|
|
40
|
-
:target: https://pyup.io/repos/github/joeirimpan/zammad_py/
|
|
41
|
-
:alt: Updates
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
Python API client for zammad
|
|
45
|
-
|
|
46
|
-
* Free software: MIT license
|
|
47
|
-
* Documentation: https://zammad-py.readthedocs.io.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
Quickstart
|
|
51
|
-
----------
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
.. code-block:: python
|
|
55
|
-
|
|
56
|
-
from zammad_py import ZammadAPI
|
|
57
|
-
|
|
58
|
-
# Initialize the client with the URL, username, and password
|
|
59
|
-
# Note the Host URL should be in this format: 'https://zammad.example.org/api/v1/'
|
|
60
|
-
client = ZammadAPI(url='<HOST>', username='<USERNAME>', password='<PASSWORD>')
|
|
61
|
-
|
|
62
|
-
# Example: Access all users
|
|
63
|
-
this_page = client.user.all()
|
|
64
|
-
for user in this_page:
|
|
65
|
-
print(user)
|
|
66
|
-
|
|
67
|
-
# Example: Get information about the current user
|
|
68
|
-
print(client.user.me())
|
|
69
|
-
|
|
70
|
-
# Example: Create a ticket
|
|
71
|
-
params = {
|
|
72
|
-
"title": "Help me!",
|
|
73
|
-
"group": "2nd Level",
|
|
74
|
-
"customer": "david@example.com",
|
|
75
|
-
"article": {
|
|
76
|
-
"subject": "My subject",
|
|
77
|
-
"body": "I am a message!",
|
|
78
|
-
"type": "note",
|
|
79
|
-
"internal": false
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
new_ticket = client.ticket.create(params=params)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
General Methods
|
|
87
|
-
---------------
|
|
88
|
-
Most resources support these methods:
|
|
89
|
-
|
|
90
|
-
`.all()`: Returns a paginated response with the current page number and a list of elements.
|
|
91
|
-
|
|
92
|
-
`.next_page()`: Returns the next page of the current pagination object.
|
|
93
|
-
|
|
94
|
-
`.prev_page()`: Returns the previous page of the current pagination object.
|
|
95
|
-
|
|
96
|
-
`.search(params)`: Returns a paginated response based on the search parameters.
|
|
97
|
-
|
|
98
|
-
`.find(id)`: Returns a single object with the specified ID.
|
|
99
|
-
|
|
100
|
-
`.create(params)`: Creates a new object with the specified parameters.
|
|
101
|
-
|
|
102
|
-
`.update(params)`: Updates an existing object with the specified parameters.
|
|
103
|
-
|
|
104
|
-
`.destroy(id)`: Deletes an object with the specified ID.
|
|
105
|
-
|
|
106
|
-
Additional Resource Methods
|
|
107
|
-
---------------------------
|
|
108
|
-
User resource also has the .me() method to get information about the current user.
|
|
109
|
-
|
|
110
|
-
Ticket resource also has the .articles() method to get the articles associated with a ticket.
|
|
111
|
-
|
|
112
|
-
Link resource has methods to list, add, and delete links between objects.
|
|
113
|
-
|
|
114
|
-
TicketArticleAttachment resource has the .download() method to download a ticket attachment.
|
|
115
|
-
|
|
116
|
-
Object resource has the .execute_migrations() method to run migrations on an object.
|
|
117
|
-
|
|
118
|
-
You can set the `on_behalf_of` attribute of the ZammadAPI instance to do actions on behalf of another user.
|
|
119
|
-
|
|
120
|
-
Contributing
|
|
121
|
-
------------
|
|
122
|
-
The Zammad API Client (zammad_py) welcomes contributions.
|
|
123
|
-
|
|
124
|
-
You can contribute by reporting bugs, fixing bugs, implementing new features, writing documentation, and submitting feedback.
|
|
125
|
-
|
|
126
|
-
To get started, see the contributing section in the docs!
|
|
127
|
-
|
|
128
|
-
Please ensure that your changes include tests and updated documentation if necessary.
|
|
129
|
-
|
|
130
|
-
Credits
|
|
131
|
-
-------
|
|
132
|
-
|
|
133
|
-
This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template.
|
|
134
|
-
|
|
135
|
-
.. _Cookiecutter: https://github.com/audreyr/cookiecutter
|
|
136
|
-
.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage
|
|
137
|
-
|
|
138
|
-
|
zammad_py-3.2.0.dist-info/RECORD
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
zammad_py/__init__.py,sha256=DM_s56KwTdX5X4aLsh6nVqKRlMK2zOagjiCcXhx9IaY,175
|
|
2
|
-
zammad_py/api.py,sha256=cNXvdFlQZRMIgx1agdvcVNak29S7fGEmbKwXFA9vYB0,17646
|
|
3
|
-
zammad_py/exceptions.py,sha256=zKJqzIAKcY_2NvbNK-jijycfCkL4vr6qSCGK7bDROfw,43
|
|
4
|
-
zammad_py-3.2.0.dist-info/LICENSE,sha256=NNe9mRfWIQ3cigyQ1-cBQA5bRPuarc1iWRkfa72jSm0,1065
|
|
5
|
-
zammad_py-3.2.0.dist-info/METADATA,sha256=RWeGdLfsStnT9zeLMByJQvBAtXHDUeiGh6H-ItmvzE0,4395
|
|
6
|
-
zammad_py-3.2.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
7
|
-
zammad_py-3.2.0.dist-info/RECORD,,
|
|
File without changes
|