Source code for taiga.models.models

import datetime
import warnings
from io import IOBase

from .. import exceptions
from .base import InstanceResource, ListResource


[docs] class MoveOnDestroyMixinList: """ Mixin that define a delete method with moveTo parameter """ def delete(self, resource_id, move_to_id): return super().delete(resource_id=resource_id, query={"moveTo": move_to_id})
[docs] class MoveOnDestroyMixinObject: """ Mixin that define a delete method with moveTo parameter """ def delete(self, move_to_id): return super().delete(query={"moveTo": move_to_id})
[docs] class CommentableResource(InstanceResource): """ CommentableResource base class """
[docs] def add_comment(self, comment): """ Add a comment to the current element :param comment: the comment you want to insert """ return self.update(comment=comment)
[docs] class CustomAttributeResource(InstanceResource): """ CustomAttributeResource base class """
[docs] def set_attribute(self, id, value, version=1): # noqa: A002 """ Set attribute to a specific value :param id: id of the attribute :param value: value of the attribute :param version: version of the attribute (default = 1) """ attributes = self._get_attributes(cache=True) formatted_id = "{}".format(id) attributes["attributes_values"][formatted_id] = value response = self.requester.patch( "/{endpoint}/custom-attributes-values/{id}", endpoint=self.endpoint, id=self.id, payload={"attributes_values": attributes["attributes_values"], "version": version}, ) cache_key = self.requester.get_full_url( "/{endpoint}/custom-attributes-values/{id}", endpoint=self.endpoint, id=self.id ) self.requester.cache.put(cache_key, response) return response.json()
def _get_attributes(self, cache=False): response = self.requester.get( "/{endpoint}/custom-attributes-values/{id}", endpoint=self.endpoint, id=self.id, cache=cache ) return response.json()
[docs] def get_attributes(self): """ Get all the attributes of the current object """ return self._get_attributes()
[docs] class CustomAttribute(InstanceResource): """ CustomAttribute base class :param requester: :class:`Requester` instance :param name: name of the custom attribute :param description: id of the current object :param order: order of the custom attribute :param project: :class:`Project` id """ repr_attribute = "name" allowed_params = ["name", "description", "order", "project"]
[docs] class CustomAttributes(ListResource): """ CustomAttributes factory base class """
[docs] def create(self, project, name, **attrs): """ Create a new :class:`CustomAttribute`. :param project: :class:`Project` id :param name: name of the custom attribute :param attrs: optional attributes of the custom attributes """ attrs.update({"project": project, "name": name}) return self._new_resource(payload=attrs)
[docs] class User(InstanceResource): """ User model """ endpoint = "users" repr_attribute = "full_name"
[docs] def starred_projects(self): """ Get a list of starred :class:`Project`. """ response = self.requester.get("/{endpoint}/{id}/starred", endpoint=self.endpoint, id=self.id) return Projects.parse(self.requester, response.json())
[docs] class Users(ListResource): """ Users factory class """ instance = User
[docs] class Membership(InstanceResource): """ Membership model :param email: email of :class:`Membership` :param role: role of :class:`Membership` :param project: project of :class:`Membership` """ endpoint = "memberships" allowed_params = ["email", "role", "project"] repr_attribute = "email"
[docs] class Memberships(ListResource): """ Memberships factory class """ instance = Membership
[docs] def create(self, project, email, role, **attrs): """ Create a new :class:`Membership`. :param project: :class:`Project` id :param email: email of :class:`Membership` :param role: role of :class:`Membership` :param attrs: optional attributes of :class:`Membership` """ attrs.update({"project": project, "email": email, "role": role}) return self._new_resource(payload=attrs)
[docs] class Priority(MoveOnDestroyMixinObject, InstanceResource): """ Priority model :param name: name of :class:`Priority` :param color: color of the class:`Priority` :param order: order of the class:`Priority` :param project: project of the class:`Priority` """ endpoint = "priorities" allowed_params = ["name", "color", "order", "project"] repr_attribute = "name"
[docs] class Priorities(MoveOnDestroyMixinList, ListResource): """ Priorities factory class """ instance = Priority
[docs] def create(self, project, name, **attrs): """ Create a new :class:`Priority`. :param project: :class:`Project` id :param name: email of the priority :param attrs: optional attributes of the priority """ attrs.update({"project": project, "name": name}) return self._new_resource(payload=attrs)
[docs] class Attachment(InstanceResource): """ Attachment base class :param object_id: object_id of :class:`Attachment` :param project: project of :class:`Attachment` :param attached_file: attached_file of :class:`Attachment` :param description: description of :class:`Attachment` :param is_deprecated: is_deprecated of :class:`Attachment` """ repr_attribute = "subject" allowed_params = ["object_id", "project", "attached_file", "description", "is_deprecated", "size", "name", "url"]
[docs] class Attachments(ListResource): """ Attachments factory base class """
[docs] def create(self, project, object_id, attached_file, **attrs): """ Create a new :class:`Attachment`. :param project: :class:`Project` id :param object_id: id of the current object :param ref: :class:`Task` reference :param attached_file: file path that you want to upload :param attrs: optional attributes for the :class:`Attachment` """ attrs.update({"project": project, "object_id": object_id}) if isinstance(attached_file, IOBase): attachment = attached_file elif isinstance(attached_file, str): try: attachment = open(attached_file, "rb") except OSError: raise exceptions.TaigaException("Attachment must be a IOBase or a path to an existing file") else: raise exceptions.TaigaException("Attachment must be a IOBase or a path to an existing file") return self._new_resource(files={"attached_file": attachment}, payload=attrs)
[docs] class UserStoryAttachment(Attachment): """ UserStoryAttachment class """ endpoint = "userstories/attachments"
[docs] class UserStoryAttachments(Attachments): """ UserStoryAttachments factory class """ instance = UserStoryAttachment
[docs] class EpicAttachment(Attachment): """ EpicAttachment class """ endpoint = "epics/attachments"
[docs] class EpicAttachments(Attachments): """ EpicAttachments factory class """ instance = EpicAttachment
[docs] class Epic(CustomAttributeResource, CommentableResource): """ Epic model :param assigned_to: assigned to property of :class:`Epic` :param blocked_note: blocked note of :class:`Epic` :param description: description of :class:`Epic` (not available in the :py:meth:`Epics.list` response) :param is_blocked: is blocked property of :class:`Epic` :param is_closed: is closed property of :class:`Epic` :param color: the color of :class:`Epic` :param project: the project of :class:`TaskStatus` :param subject: subject of :class:`TaskStatus` :param tags: tags of :class:`TaskStatus` :param watchers: watchers of :class:`TaskStatus` :param version: version of :class:`Epic` """ endpoint = "epics" repr_attribute = "subject" allowed_params = [ "assigned_to", "blocked_note", "description", "is_blocked", "is_closed", "color", "project", "subject", "tags", "watchers", "version", ]
[docs] def list_user_stories(self, **queryparams): """ Returns the :class:`UserStory` list of the project. """ return UserStories(self.requester).list(epic=self.id, **queryparams)
[docs] def list_attachments(self): """ Get a list of :class:`EpicAttachment`. """ return EpicAttachments(self.requester).list(object_id=self.id)
[docs] def attach(self, attached_file, **attrs): """ Attach a file to the :class:`Epic` :param attached_file: file path to attach :param attrs: optional attributes for the attached file """ return EpicAttachments(self.requester).create(self.project, self.id, attached_file, **attrs)
[docs] class Epics(ListResource): """ Epics factory class """ instance = Epic
[docs] def create(self, project, subject, **attrs): """ Create a new :class:`Epic`. :param project: :class:`Project` id :param subject: subject of :class:`Epic` :param attrs: optional attributes of :class:`Epic` """ attrs.update({"project": project, "subject": subject}) return self._new_resource(payload=attrs)
[docs] class EpicStatus(MoveOnDestroyMixinObject, InstanceResource): """ Taiga Epic Status model :param color: the color of :class:`EpicStatus` :param is_closed: closed property of :class:`EpicStatus` :param name: The name of :class:`EpicStatus` :param order: order of :class:`EpicStatus` :param project: the Taiga project of :class:`EpicStatus` :param slug: the slug of :class:`EpicStatus` """ repr_attribute = "subject" endpoint = "epic-statuses" allowed_params = ["color", "is_closed", "name", "order", "project", "slug`"]
[docs] class EpicStatuses(MoveOnDestroyMixinList, ListResource): instance = EpicStatus
[docs] def create(self, project, name, **attrs): """ Create a new :class:`EpicStatus`. :param project: :class:`Project` id :param name: name of :class:`EpicStatus` :param attrs: optional attributes of :class:`EpicStatus` """ attrs.update({"project": project, "name": name}) return self._new_resource(payload=attrs)
[docs] class UserStory(CustomAttributeResource, CommentableResource): """ User Story model :param assigned_to: assigned to of :class:`UserStory` :param assigned_users: additional users assigned to of :class:`UserStory` :param backlog_order: backlog order of :class:`UserStory` :param blocked_note: blocked note of :class:`UserStory` :param version: version of :class:`UserStory` :param client_requirement: client requirement of :class:`UserStory` :param description: description of :class:`UserStory` (not available in the :py:meth:`UserStories.list` response) :param is_blocked: is blocked of :class:`UserStory` :param kanban_order: kanban order of :class:`UserStory` :param milestone: milestone of :class:`UserStory` :param points: points of :class:`UserStory` :param project: project of :class:`UserStory` :param sprint_order: sprint order of :class:`UserStory` :param status: status of :class:`UserStory` :param subject: subject of :class:`UserStory` :param tags: tags of :class:`UserStory` :param team_requirement: team requirement of :class:`UserStory` :param watchers: watchers of :class:`UserStory` :param due_date: :class:`UserStory` due date :param generated_from_issue: :class:`UserStory` parent issue :param generated_from_task: :class:`UserStory` parent task """ endpoint = "userstories" repr_attribute = "subject" element_type = "User Story" element_shortcut = "us" allowed_params = [ "assigned_to", "assigned_users", "backlog_order", "blocked_note", "version", "client_requirement", "description", "is_blocked", "is_closed", "kanban_order", "milestone", "points", "project", "sprint_order", "status", "subject", "tags", "team_requirement", "watchers", "due_date", "generated_from_issue", "generated_from_task", ]
[docs] def add_task(self, subject, status, **attrs): """ Add a :class:`Task` to the current :class:`UserStory` and return it. :param subject: subject of :class:`Task` :param status: status of :class:`Task` :param attrs: optional attributes for :class:`Task` """ return Tasks(self.requester).create(self.project, subject, status, user_story=self.id, **attrs)
[docs] def list_tasks(self): """ Get a list of :class:`Task` in the current :class:`UserStory`. """ return Tasks(self.requester).list(user_story=self.id)
[docs] def list_attachments(self): """ Get a list of :class:`UserStoryAttachment`. """ return UserStoryAttachments(self.requester).list(object_id=self.id)
[docs] def attach(self, attached_file, **attrs): """ Attach a file to the :class:`UserStory` :param attached_file: file path to attach :param attrs: optional attributes for the attached file """ return UserStoryAttachments(self.requester).create(self.project, self.id, attached_file, **attrs)
[docs] class UserStories(ListResource): """ UserStories factory class """ instance = UserStory
[docs] def create(self, project, subject, **attrs): """ Create a new :class:`UserStory`. :param project: :class:`Project` id :param subject: subject of :class:`UserStory` :param attrs: optional attributes of :class:`UserStory` """ attrs.update({"project": project, "subject": subject}) return self._new_resource(payload=attrs)
def import_(self, project, subject, status, **attrs): attrs.update({"project": project, "subject": subject, "status": status}) response = self.requester.post( "/{endpoint}/{id}/{type}", endpoint="importer", id=project, type="us", payload=attrs ) return self.instance.parse(self.requester, response.json())
[docs] class UserStoryStatus(MoveOnDestroyMixinObject, InstanceResource): """ Taiga User Story Status model :param color: the color of :class:`UserStoryStatus` :param is_closed: closed property of :class:`UserStoryStatus` :param name: The name of :class:`UserStoryStatus` :param order: order of :class:`UserStoryStatus` :param project: the Taiga project of :class:`UserStoryStatus` :param wip_limit: wip limit of :class:`UserStoryStatus` """ repr_attribute = "subject" endpoint = "userstory-statuses" allowed_params = ["color", "is_closed", "name", "order", "project", "wip_limit"]
[docs] class UserStoryStatuses(MoveOnDestroyMixinList, ListResource): instance = UserStoryStatus
[docs] def create(self, project, name, **attrs): """ Create a new :class:`UserStoryStatus`. :param project: :class:`Project` id :param name: name of :class:`UserStoryStatus` :param attrs: optional attributes of :class:`UserStoryStatus` """ attrs.update({"project": project, "name": name}) return self._new_resource(payload=attrs)
[docs] class SwimLane(MoveOnDestroyMixinObject, InstanceResource): """ Taiga Swimlane model :param name: The name of :class:`SwimLane` :param order: the order of :class:`SwimLane` :param project: the project of :class:`SwimLane` :param statuses: the statuses of :class:`SwimLane` """ repr_attribute = "name" endpoint = "swimlanes" allowed_params = ["name", "order", "project", "statuses"] parser = { "statuses": UserStoryStatuses, }
[docs] class SwimLanes(MoveOnDestroyMixinList, ListResource): instance = SwimLane
[docs] def create(self, project, name, **attrs): """ Create a new :class:`SwimLane`. :param project: :class:`Project` id :param name: name of :class:`SwimLane` :param attrs: optional attributes of :class:`SwimLane` """ attrs.update({"project": project, "name": name}) return self._new_resource(payload=attrs)
[docs] class Point(MoveOnDestroyMixinObject, InstanceResource): """ Taiga Point model :param color: the color of :class:`Point` :param value: value of :class:`Point` :param name: name of :class:`Point` :param order: the order of :class:`Point` :param project: the Taiga project of :class:`Point` """ endpoint = "points" repr_attribute = "subject" allowed_params = ["color", "value", "name", "order", "project"]
[docs] class Points(MoveOnDestroyMixinList, ListResource): """ Points factory """ instance = Point
[docs] def create(self, project, name, value, **attrs): """ Create a new :class:`UserStoryStatus`. :param project: :class:`Project` id :param name: name of :class:`Point` :param value: value of :class:`Point` :param attrs: optional attributes of :class:`Point` """ attrs.update({"project": project, "name": name, "value": value}) return self._new_resource(payload=attrs)
[docs] class Milestone(InstanceResource): """ Milestone model :param name: the name of :class:`Milestone` :param project: the Taiga project of :class:`Milestone` :param estimated_start: the estimated start of :class:`Milestone` :param estimated_finish: the estimated finish of :class:`Milestone` :param disponibility: the disponibility of :class:`Milestone` """ endpoint = "milestones" allowed_params = [ "name", "project", "estimated_start", "estimated_finish", "disponibility", "slug", "order", "watchers", ] parser = { "user_stories": UserStories, }
[docs] def stats(self): """ Get the stats for the current :class:`Milestone` """ response = self.requester.get("/{endpoint}/{id}/stats", endpoint=self.endpoint, id=self.id) return response.json()
[docs] class Milestones(ListResource): """ Milestones factory """ instance = Milestone
[docs] def create(self, project, name, estimated_start, estimated_finish, **attrs): """ Create a new :class:`Milestone`. :param project: :class:`Project` id :param name: name of :class:`Milestone` :param estimated_start: est. start time of :class:`Milestone` :param estimated_finish: est. finish time of :class:`Milestone` :param attrs: optional attributes of :class:`Milestone` """ if isinstance(estimated_start, datetime.datetime): estimated_start = estimated_start.strftime("%Y-%m-%d") if isinstance(estimated_finish, datetime.datetime): estimated_finish = estimated_finish.strftime("%Y-%m-%d") attrs.update( { "project": project, "name": name, "estimated_start": estimated_start, "estimated_finish": estimated_finish, } ) return self._new_resource(payload=attrs)
def import_(self, project, name, estimated_start, estimated_finish, **attrs): if isinstance(estimated_start, datetime.datetime): estimated_start = estimated_start.strftime("%Y-%m-%d") if isinstance(estimated_finish, datetime.datetime): estimated_finish = estimated_finish.strftime("%Y-%m-%d") attrs.update( { "project": project, "name": name, "estimated_start": estimated_start, "estimated_finish": estimated_finish, } ) response = self.requester.post( "/{endpoint}/{id}/{type}", endpoint="importer", id=project, type="milestone", payload=attrs ) return self.instance.parse(self.requester, response.json())
[docs] class TaskStatus(MoveOnDestroyMixinObject, InstanceResource): """ Task Status model :param name: the name of :class:`TaskStatus` :param color: the color of :class:`TaskStatus` :param order: the order of :class:`TaskStatus` :param project: the project of :class:`TaskStatus` :param is_closed: the is closed property of :class:`TaskStatus` """ endpoint = "task-statuses" allowed_params = ["name", "color", "order", "project", "is_closed"]
[docs] class TaskStatuses(MoveOnDestroyMixinList, ListResource): instance = TaskStatus
[docs] def create(self, project, name, **attrs): """ Create a new :class:`TaskStatus`. :param project: :class:`Project` id :param name: name of :class:`TaskStatus` :param attrs: optional attributes of :class:`TaskStatus` """ attrs.update({"project": project, "name": name}) return self._new_resource(payload=attrs)
[docs] class TaskAttachment(Attachment): """ TaskAttachment model """ endpoint = "tasks/attachments"
[docs] class TaskAttachments(Attachments): """ TaskAttachments factory """ instance = TaskAttachment
[docs] class Task(CustomAttributeResource, CommentableResource): """ Task model :param assigned_to: assigned to property of :class:`TaskStatus` :param blocked_note: blocked note of :class:`TaskStatus` :param description: description of of :class:`TaskStatus` (not available in the :py:meth:`Tasks.list` response) :param version: version of :class:`TaskStatus` :param is_blocked: is blocked property of :class:`TaskStatus` :param milestone: milestone property of :class:`TaskStatus` :param project: the project of :class:`TaskStatus` :param user_story: the user story of :class:`TaskStatus` :param status: status of :class:`TaskStatus` :param subject: subject of :class:`TaskStatus` :param tags: tags of :class:`TaskStatus` :param us_order: the use order of :class:`TaskStatus` :param taskboard_order: the taskboard order of :class:`TaskStatus` :param is_iocaine: the is iocaine of :class:`TaskStatus` :param external_reference: external reference of :class:`TaskStatus` :param watchers: watchers of :class:`TaskStatus` :param due_date: :class:`Task` due date """ endpoint = "tasks" repr_attribute = "subject" element_type = "Task" element_shortcut = "task" allowed_params = [ "assigned_to", "blocked_note", "description", "version", "is_blocked", "is_closed", "milestone", "project", "user_story", "status", "subject", "tags", "us_order", "taskboard_order", "is_iocaine", "external_reference", "watchers", ]
[docs] def list_attachments(self): """ Get a list of :class:`TaskAttachment`. """ return TaskAttachments(self.requester).list(object_id=self.id)
[docs] def attach(self, attached_file, **attrs): """ Attach a file to the :class:`Task` :param attached_file: file path to attach :param attrs: optional attributes for the attached file """ return TaskAttachments(self.requester).create(self.project, self.id, attached_file, **attrs)
[docs] class Tasks(ListResource): """ Tasks factory """ instance = Task
[docs] def create(self, project, subject, status, **attrs): """ Create a new :class:`Task`. :param project: :class:`Project` id :param subject: subject of :class:`Task` :param status: status of :class:`Task` :param attrs: optional attributes of :class:`Task` """ attrs.update({"project": project, "subject": subject, "status": status}) return self._new_resource(payload=attrs)
def import_(self, project, subject, status, **attrs): attrs.update({"project": project, "subject": subject, "status": status}) response = self.requester.post( "/{endpoint}/{id}/{type}", endpoint="importer", id=project, type="task", payload=attrs ) return self.instance.parse(self.requester, response.json())
[docs] class IssueType(MoveOnDestroyMixinObject, InstanceResource): """ IssueType model :param name: name of :class:`IssueType` :param color: color of :class:`IssueType` :param order: order of :class:`IssueType` :param project: the taiga project of :class:`IssueType` """ endpoint = "issue-types" allowed_params = ["name", "color", "order", "project"]
[docs] class IssueTypes(MoveOnDestroyMixinList, ListResource): """ IssueTypes factory """ instance = IssueType def create(self, project, name, **attrs): attrs.update({"project": project, "name": name}) return self._new_resource(payload=attrs)
[docs] class IssueStatus(MoveOnDestroyMixinObject, InstanceResource): """ Issue Status model :param name: name of :class:`IssueStatus` :param color: color of :class:`IssueStatus` :param order: order of :class:`IssueStatus` :param project: the taiga project of :class:`IssueStatus` :param is_closed: is closed property of :class:`IssueStatus` """ endpoint = "issue-statuses" allowed_params = ["name", "color", "order", "project", "is_closed"]
[docs] class IssueStatuses(MoveOnDestroyMixinList, ListResource): """ IssueStatuses factory """ instance = IssueStatus def create(self, project, name, **attrs): attrs.update({"project": project, "name": name}) return self._new_resource(payload=attrs)
[docs] class IssueAttachment(Attachment): """ IssueAttachment model """ endpoint = "issues/attachments"
[docs] class IssueAttachments(Attachments): """ IssueAttachments factory """ instance = IssueAttachment
[docs] class Issue(CustomAttributeResource, CommentableResource): """Issue model :param requester: :class:`Requester` instance :param assigned_to: :class:`User` id this issue is assigned to :param description: description of the issue (not available in the :py:meth:`Issues.list` response) :param is_blocked: set if this issue is blocked or not :param milestone: :class:`Milestone` id :param project: :class:`Project` id :param status: :class:`Status` id :param severity: class:`Severity` id :param priority: class:`Priority` id :param type: class:`Type` id :param subject: subject of the issue :param tags: array of tags :param watchers: array of watchers id :param due_date: :class:`Issue` due date """ endpoint = "issues" repr_attribute = "subject" element_type = "Issue" element_shortcut = "issue" allowed_params = [ "assigned_to", "blocked_note", "description", "version", "is_blocked", "is_closed", "milestone", "project", "status", "severity", "priority", "type", "subject", "tags", "watchers", ]
[docs] def list_attachments(self): """ Get a list of :class:`IssueAttachment`. """ return IssueAttachments(self.requester).list(object_id=self.id)
[docs] def upvote(self): """ Upvote :class:`Issue`. """ self.requester.post("/{endpoint}/{id}/upvote", endpoint=self.endpoint, id=self.id) return self
[docs] def downvote(self): """ Downvote :class:`Issue`. """ self.requester.post("/{endpoint}/{id}/downvote", endpoint=self.endpoint, id=self.id) return self
[docs] def attach(self, attached_file, **attrs): """ Attach a file to the :class:`Issue` :param attached_file: file path to attach :param attrs: optional attributes for the attached file """ return IssueAttachments(self.requester).create(self.project, self.id, attached_file, **attrs)
[docs] class Issues(ListResource): instance = Issue
[docs] def create(self, project, subject, priority, status, issue_type, severity, **attrs): """ Create a new :class:`Task`. :param project: :class:`Project` id :param subject: subject of :class:`Issue` :param priority: priority of :class:`Issue` :param status: status of :class:`Issue` :param issue_type: Issue type of :class:`Issue` :param severity: severity of :class:`Issue` :param attrs: optional attributes of :class:`Task` """ attrs.update( { "project": project, "subject": subject, "priority": priority, "status": status, "type": issue_type, "severity": severity, } ) return self._new_resource(payload=attrs)
def import_(self, project, subject, priority, status, issue_type, severity, **attrs): attrs.update( { "project": project, "subject": subject, "priority": priority, "status": status, "type": issue_type, "severity": severity, } ) response = self.requester.post( "/{endpoint}/{id}/{type}", endpoint="importer", id=project, type="issue", payload=attrs ) return self.instance.parse(self.requester, response.json())
[docs] class IssueAttribute(CustomAttribute): """ IssueAttribute model """ endpoint = "issue-custom-attributes"
[docs] class IssueAttributes(CustomAttributes): """ IssueAttributes factory """ instance = IssueAttribute
[docs] class TaskAttribute(CustomAttribute): """ TaskAttribute model """ endpoint = "task-custom-attributes"
[docs] class TaskAttributes(CustomAttributes): """ TaskAttributes factory """ instance = TaskAttribute
[docs] class UserStoryAttribute(CustomAttribute): """ UserStoryAttribute model """ endpoint = "userstory-custom-attributes"
[docs] class UserStoryAttributes(CustomAttributes): """ UserStoryAttributes factory """ instance = UserStoryAttribute
[docs] class EpicAttribute(CustomAttribute): """ EpicAttribute model """ endpoint = "epic-custom-attributes"
[docs] class EpicAttributes(CustomAttributes): """ EpicAttributes factory """ instance = EpicAttribute
[docs] class Severity(MoveOnDestroyMixinObject, InstanceResource): """ Severity model :param requester: :class:`Requester` instance :param name: name of :class:`Severity` :param order: order of :class:`Severity` :param project: :class:`Project` id """ endpoint = "severities" allowed_params = ["name", "color", "order", "project"]
[docs] class Severities(MoveOnDestroyMixinList, ListResource): """ Severities factory """ instance = Severity
[docs] def create(self, project, name, **attrs): """ Create a new :class:`Severity` :param project: :class:`Project` id :param name: name of :class:`Severity` :param attrs: optional attributes for :class:`Role` """ attrs.update({"project": project, "name": name}) return self._new_resource(payload=attrs)
[docs] class Role(InstanceResource): """ Role model :param requester: :class:`Requester` instance :param name: name of :class:`Role` :param slug: slug of :class:`Role` :param order: order of :class:`Role` :param computable: choose if :class:`Role` is computable or not """ endpoint = "roles" allowed_params = ["name", "slug", "order", "computable"]
[docs] class Roles(ListResource): """ Roles factory """ instance = Role
[docs] def create(self, project, name, **attrs): """ Create a new :class:`Role` :param project: :class:`Project` id :param name: name of :class:`Role` :param attrs: optional attributes for :class:`Role` """ attrs.update({"project": project, "name": name}) return self._new_resource(payload=attrs)
[docs] class Project(InstanceResource): """Taiga project model :param requester: :class:`Requester` instance :param name: name of the project :param description: description of the project (not available in the :py:meth:`Projects.list` response) :param creation_template: base template for the project :param is_backlog_activated: name of the project :param is_issues_activated: name of the project :param is_kanban_activated: name of the project :param is_wiki_activated: determines if the project is private or not :param is_private: determines if the project is private or not :param videoconferences: appear-in or talky :param videoconferences_salt: for videoconference chat url generation :param total_milestones: missing :param total_story_points: missing """ endpoint = "projects" allowed_params = [ "name", "description", "default_swimlane", "creation_template", "is_backlog_activated", "is_issues_activated", "is_kanban_activated", "is_private", "is_wiki_activated", "videoconferences", "videoconferences_salt", "total_milestones", "total_story_points", ] parser = { "members": Users, "priorities": Priorities, "issue_statuses": IssueStatuses, "issue_types": IssueTypes, "task_statuses": TaskStatuses, "severities": Severities, "roles": Roles, "points": Points, "us_statuses": UserStoryStatuses, "milestones": Milestones, "swimlanes": SwimLanes, } def get_item_by_ref(self, ref): response = self.requester.get( "/resolver?project={project_id}&ref={task_ref}", task_ref=ref, project_id=self.slug ) response_json = response.json() if response_json and "task" in response_json: return self.get_task_by_ref(ref) elif response_json and "us" in response_json: return self.get_userstory_by_ref(ref) elif response_json and "issue" in response_json: return self.get_issue_by_ref(ref) else: return None
[docs] def get_task_by_ref(self, ref): """ Get a :class:`Task` by ref. :param ref: :class:`Task` reference """ response = self.requester.get( "/{endpoint}/by_ref?ref={task_ref}&project={project_id}", endpoint=Task.endpoint, task_ref=ref, project_id=self.id, ) return Task.parse(self.requester, response.json())
[docs] def get_epic_by_ref(self, ref): """ Get a :class:`Epic` by ref. :param ref: :class:`Epic` reference """ response = self.requester.get( "/{endpoint}/by_ref?ref={ep_ref}&project={project_id}", endpoint=Epic.endpoint, ep_ref=ref, project_id=self.id, ) return Epic.parse(self.requester, response.json())
[docs] def get_userstory_by_ref(self, ref): """ Get a :class:`UserStory` by ref. :param ref: :class:`UserStory` reference """ response = self.requester.get( "/{endpoint}/by_ref?ref={us_ref}&project={project_id}", endpoint=UserStory.endpoint, us_ref=ref, project_id=self.id, ) return UserStory.parse(self.requester, response.json())
[docs] def get_issue_by_ref(self, ref): """ Get a :class:`Issue` by ref. :param ref: :class:`Issue` reference """ response = self.requester.get( "/{endpoint}/by_ref?ref={us_ref}&project={project_id}", endpoint=Issue.endpoint, us_ref=ref, project_id=self.id, ) return Issue.parse(self.requester, response.json())
[docs] def stats(self): """ Get the stats of the project """ response = self.requester.get("/{endpoint}/{id}/stats", endpoint=self.endpoint, id=self.id) return response.json()
[docs] def issues_stats(self): """ Get stats for issues of the project """ response = self.requester.get("/{endpoint}/{id}/issues_stats", endpoint=self.endpoint, id=self.id) return response.json()
[docs] def like(self): """ Like the project """ self.requester.post("/{endpoint}/{id}/like", endpoint=self.endpoint, id=self.id) return self
[docs] def unlike(self): """ Unlike the project """ self.requester.post("/{endpoint}/{id}/unlike", endpoint=self.endpoint, id=self.id) return self
[docs] def star(self): """ Stars the project .. deprecated:: 0.8.5 Update Taiga and use like instead """ warnings.warn("Deprecated! Update Taiga and use .like() instead", DeprecationWarning) self.requester.post("/{endpoint}/{id}/star", endpoint=self.endpoint, id=self.id) return self
[docs] def unstar(self): """ Unstars the project .. deprecated:: 0.8.5 Update Taiga and use unlike instead """ warnings.warn("Deprecated! Update Taiga and use .unlike() instead", DeprecationWarning) self.requester.post("/{endpoint}/{id}/unstar", endpoint=self.endpoint, id=self.id) return self
[docs] def add_membership(self, email, role, **attrs): """ Add a Membership to the project and returns a :class:`Membership` resource. :param email: email for :class:`Membership` :param role: role for :class:`Membership` :param attrs: role for :class:`Membership` :param attrs: optional :class:`Membership` attributes """ return Memberships(self.requester).create(self.id, email, role, **attrs)
[docs] def list_memberships(self): """ Get the list of :class:`Membership` resources for the project. """ return Memberships(self.requester).list(project=self.id)
[docs] def add_user_story(self, subject, **attrs): """ Adds a :class:`UserStory` and returns a :class:`UserStory` resource. :param subject: subject of :class:`UserStory` :param attrs: other :class:`UserStory` attributes """ return UserStories(self.requester).create(self.id, subject, **attrs)
[docs] def import_user_story(self, subject, status, **attrs): """ Import an user story and returns a :class:`UserStory` resource. :param subject: subject of :class:`UserStory` :param status: status of :class:`UserStory` :param attrs: optional :class:`UserStory` attributes """ return UserStories(self.requester).import_(self.id, subject, status, **attrs)
[docs] def list_user_stories(self, **queryparams): """ Returns the :class:`UserStory` list of the project. """ return UserStories(self.requester).list(project=self.id, **queryparams)
[docs] def add_swimlane(self, name, **attrs): """ Adds a :class:`SwimLane` and returns a :class:`SwimLane` resource. :param name: name of :class:`SwimLane` :param attrs: other :class:`SwimLane` attributes """ return SwimLanes(self.requester).create(self.id, name, **attrs)
[docs] def list_swimlanes(self, **queryparams): """ Returns the :class:`SwimLane` list of the project. """ return SwimLanes(self.requester).list(project=self.id, **queryparams)
[docs] def add_issue(self, subject, priority, status, issue_type, severity, **attrs): """ Adds a Issue and returns a :class:`Issue` resource. :param subject: subject of :class:`Issue` :param priority: priority of :class:`Issue` :param priority: status of :class:`Issue` :param issue_type: type of :class:`Issue` :param severity: severity of :class:`Issue` :param attrs: other :class:`Issue` attributes """ return Issues(self.requester).create(self.id, subject, priority, status, issue_type, severity, **attrs)
[docs] def import_issue(self, subject, priority, status, issue_type, severity, **attrs): """ Import and issue and returns a :class:`Issue` resource. :param subject: subject of :class:`Issue` :param priority: priority of :class:`Issue` :param status: status of :class:`Issue` :param issue_type: issue type of :class:`Issue` :param severity: severity of :class:`Issue` :param attrs: optional :class:`Issue` attributes """ return Issues(self.requester).import_(self.id, subject, priority, status, issue_type, severity, **attrs)
[docs] def list_issues(self): """ Returns the :class:`Issue` list of the project. """ return Issues(self.requester).list(project=self.id)
[docs] def add_milestone(self, name, estimated_start, estimated_finish, **attrs): """ Add a Milestone to the project and returns a :class:`Milestone` object. :param name: name of :class:`Milestone` :param estimated_start: estimated start time of the :class:`Milestone` :param estimated_finish: estimated finish time of the :class:`Milestone` :param attrs: optional attributes for :class:`Milestone` """ return Milestones(self.requester).create(self.id, name, estimated_start, estimated_finish, **attrs)
[docs] def import_milestone(self, name, estimated_start, estimated_finish, **attrs): """ Import a Milestone and returns a :class:`Milestone` object. :param name: name of :class:`Milestone` :param estimated_start: estimated start time of the :class:`Milestone` :param estimated_finish: estimated finish time of the :class:`Milestone` :param attrs: optional attributes for :class:`Milestone` """ return Milestones(self.requester).import_(self.id, name, estimated_start, estimated_finish, **attrs)
[docs] def list_milestones(self, **queryparams): """ Get the list of :class:`Milestone` resources for the project. """ return Milestones(self.requester).list(project=self.id, **queryparams)
[docs] def add_point(self, name, value, **attrs): """ Add a Point to the project and returns a :class:`Point` object. :param name: name of :class:`Point` :param value: value of :class:`Point` :param attrs: optional attributes for :class:`Point` """ return Points(self.requester).create(self.id, name, value, **attrs)
[docs] def list_points(self): """ Get the list of :class:`Point` resources for the project. """ return Points(self.requester).list(project=self.id)
[docs] def add_epic(self, subject, **attrs): """ Adds a :class:`UserStory` and returns a :class:`UserStory` resource. :param subject: subject of :class:`UserStory` :param attrs: other :class:`UserStory` attributes """ return Epics(self.requester).create(self.id, subject, **attrs)
[docs] def list_epics(self): """ Get the list of :class:`Epic` resources for the project. """ return Epics(self.requester).list(project=self.id)
[docs] def add_task_status(self, name, **attrs): """ Add a Task status to the project and returns a :class:`TaskStatus` object. :param name: name of :class:`TaskStatus` :param attrs: optional attributes for :class:`TaskStatus` """ return TaskStatuses(self.requester).create(self.id, name, **attrs)
[docs] def list_task_statuses(self): """ Get the list of :class:`Task` resources for the project. """ return TaskStatuses(self.requester).list(project=self.id)
[docs] def import_task(self, subject, status, **attrs): """ Import a Task and return a :class:`Task` object. :param subject: subject of :class:`Task` :param status: status of :class:`Task` :param attrs: optional attributes for :class:`Task` """ return Tasks(self.requester).import_(self.id, subject, status, **attrs)
[docs] def add_user_story_status(self, name, **attrs): """ Add a UserStory status to the project and returns a :class:`UserStoryStatus` object. :param name: name of :class:`UserStoryStatus` :param attrs: optional attributes for :class:`UserStoryStatus` """ return UserStoryStatuses(self.requester).create(self.id, name, **attrs)
[docs] def list_user_story_statuses(self): """ Get the list of :class:`UserStoryStatus` resources for the project. """ return UserStoryStatuses(self.requester).list(project=self.id)
[docs] def add_issue_type(self, name, **attrs): """ Add a Issue type to the project and returns a :class:`IssueType` object. :param name: name of :class:`IssueType` :param attrs: optional attributes for :class:`IssueType` """ return IssueTypes(self.requester).create(self.id, name, **attrs)
[docs] def list_issue_types(self): """ Get the list of :class:`IssueType` resources for the project. """ return IssueTypes(self.requester).list(project=self.id)
[docs] def add_severity(self, name, **attrs): """ Add a Severity to the project and returns a :class:`Severity` object. :param name: name of :class:`Severity` :param attrs: optional attributes for :class:`Severity` """ return Severities(self.requester).create(self.id, name, **attrs)
[docs] def list_severities(self): """ Get the list of :class:`Severity` resources for the project. """ return Severities(self.requester).list(project=self.id)
[docs] def add_role(self, name, **attrs): """ Add a Role to the project and returns a :class:`Role` object. :param name: name of :class:`Role` :param attrs: optional attributes for :class:`Role` """ return Roles(self.requester).create(self.id, name, **attrs)
[docs] def list_roles(self): """ Get the list of :class:`Role` resources for the project. """ return Roles(self.requester).list(project=self.id)
[docs] def add_priority(self, name, **attrs): """ Add a Priority to the project and returns a :class:`Priority` object. :param name: name of :class:`Priority` :param attrs: optional attributes for :class:`Priority` """ return Priorities(self.requester).create(self.id, name, **attrs)
[docs] def list_priorities(self): """ Get the list of :class:`Priority` resources for the project. """ return Priorities(self.requester).list(project=self.id)
[docs] def add_issue_status(self, name, **attrs): """ Add a Issue status to the project and returns a :class:`IssueStatus` object. :param name: name of :class:`IssueStatus` :param attrs: optional attributes for :class:`IssueStatus` """ return IssueStatuses(self.requester).create(self.id, name, **attrs)
[docs] def list_issue_statuses(self): """ Get the list of :class:`IssueStatus` resources for the project. """ return IssueStatuses(self.requester).list(project=self.id)
[docs] def add_wikipage(self, slug, content, **attrs): """ Add a Wiki page to the project and returns a :class:`WikiPage` object. :param name: name of :class:`WikiPage` :param attrs: optional attributes for :class:`WikiPage` """ return WikiPages(self.requester).create(self.id, slug, content, **attrs)
[docs] def import_wikipage(self, slug, content, **attrs): """ Import a Wiki page and return a :class:`WikiPage` object. :param slug: slug of :class:`WikiPage` :param content: content of :class:`WikiPage` :param attrs: optional attributes for :class:`Task` """ return WikiPages(self.requester).import_(self.id, slug, content, **attrs)
[docs] def list_wikipages(self): """ Get the list of :class:`WikiPage` resources for the project. """ return WikiPages(self.requester).list(project=self.id)
[docs] def add_issue_attribute(self, name, **attrs): """ Add a new Issue attribute and return a :class:`IssueAttribute` object. :param name: name of :class:`IssueAttribute` :param attrs: optional attributes for :class:`IssueAttribute` """ return IssueAttributes(self.requester).create(self.id, name, **attrs)
[docs] def list_issue_attributes(self): """ Get the list of :class:`IssueAttribute` resources for the project. """ return IssueAttributes(self.requester).list(project=self.id)
[docs] def add_task_attribute(self, name, **attrs): """ Add a new Task attribute and return a :class:`TaskAttribute` object. :param name: name of :class:`TaskAttribute` :param attrs: optional attributes for :class:`TaskAttribute` """ return TaskAttributes(self.requester).create(self.id, name, **attrs)
[docs] def list_task_attributes(self): """ Get the list of :class:`TaskAttribute` resources for the project. """ return TaskAttributes(self.requester).list(project=self.id)
[docs] def add_user_story_attribute(self, name, **attrs): """ Add a new User Story attribute and return a :class:`UserStoryAttribute` object. :param name: name of :class:`UserStoryAttribute` :param attrs: optional attributes for :class:`UserStoryAttribute` """ return UserStoryAttributes(self.requester).create(self.id, name, **attrs)
[docs] def list_user_story_attributes(self): """ Get the list of :class:`UserStoryAttribute` resources for the project. """ return UserStoryAttributes(self.requester).list(project=self.id)
[docs] def list_epic_attributes(self): """ Get the list of :class:`EpicAttribute` resources for the project. """ return EpicAttributes(self.requester).list(project=self.id)
[docs] def add_webhook(self, name, url, key, **attrs): """ Add a new Webhook and return a :class:`Webhook` object. :param name: name of :class:`Webhook` :param url: payload url of :class:`Webhook` :param key: secret key of :class:`Webhook` :param attrs: optional attributes for :class:`Webhook` """ return Webhooks(self.requester).create(self.id, name, url, key, **attrs)
[docs] def list_webhooks(self): """ Get the list of :class:`Webhook` resources for the project. """ return Webhooks(self.requester).list(project=self.id)
[docs] def add_tag(self, tag, color=None): """ Add a new tag and return a response object. :param tag: name of the tag :param color: optional color of the tag """ attrs = {"tag": tag} if color: attrs["color"] = color response = self.requester.post("/{}/{}/create_tag".format(self.endpoint, self.id), payload=attrs) return response
[docs] def list_tags(self): """ Get the list of tags for the project. """ response = self.requester.get("/{}/{}/tags_colors".format(self.endpoint, self.id)) return response.json()
[docs] def duplicate(self, name, description, is_private=False, users=[], **attrs): """ Duplicate a :class:`Project` :param name: name of new :class:`Project` :param description: description of new :class:`Project` :param is_private: determines if the project is private or not :param users: users of the new :class:`Project` :param attrs: optional attributes for the new :class:`Project` """ attrs.update({"name": name, "description": description, "is_private": is_private, "users": users}) response = self.requester.post("/{endpoint}/{id}/duplicate", payload=attrs, endpoint=self.endpoint, id=self.id) return self.parse(self.requester, response.json())
[docs] class Projects(ListResource): """ Projects factory """ instance = Project
[docs] def create(self, name, description, **attrs): """ Create a new :class:`Project` :param name: name of :class:`Project` :param description: description of :class:`Project` :param attrs: optional attributes for :class:`Project` """ attrs.update({"name": name, "description": description}) return self._new_resource(payload=attrs)
def import_(self, name, description, roles, **attrs): attrs.update({"name": name, "description": description, "roles": roles}) response = self.requester.post("/{endpoint}", endpoint="importer", payload=attrs) return self.instance.parse(self.requester, response.json())
[docs] def get_by_slug(self, slug): """ Get a :class:`Project` by slug :param slug: the slug of :class:`Project` """ response = self.requester.get("/{endpoint}/by_slug?slug={slug}", endpoint=self.instance.endpoint, slug=slug) return self.instance.parse(self.requester, response.json())
[docs] class WikiAttachment(Attachment): """ WikiAttachment model """ endpoint = "wiki/attachments"
[docs] class WikiAttachments(Attachments): """ WikiAttachments factory """ instance = WikiAttachment
[docs] class WikiPage(InstanceResource): """ WikiPage model :param project: :class:`Project` id :param slug: slug of the wiki page :param content: content of the wiki page :param watchers: list of watchers id """ endpoint = "wiki" repr_attribute = "slug" allowed_params = ["project", "slug", "content", "watchers", "version"]
[docs] def attach(self, attached_file, **attrs): """ Attach a file to the :class:`WikiPage` :param attached_file: file path to attach :param attrs: optional attributes for the attached file """ return WikiAttachments(self.requester).create(self.project, self.id, attached_file, **attrs)
[docs] def list_attachments(self): """ Get a list of :class:`WikiAttachment`. """ return WikiAttachments(self.requester).list(object_id=self.id, project=self.project)
[docs] class WikiPages(ListResource): """ WikiPages factory """ instance = WikiPage
[docs] def create(self, project, slug, content, **attrs): """ create a new :class:`WikiPage` :param project: :class:`Project` id :param slug: slug of the wiki page :param content: content of the wiki page :param attrs: optional attributes for the :class:`WikiPage` """ attrs.update({"project": project, "slug": slug, "content": content}) return self._new_resource(payload=attrs)
def import_(self, project, slug, content, **attrs): attrs.update({"project": project, "slug": slug, "content": content}) response = self.requester.post( "/{endpoint}/{id}/{type}", endpoint="importer", id=project, type="wiki_page", payload=attrs ) return self.instance.parse(self.requester, response.json())
[docs] class History(InstanceResource): """ History model """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.issue = HistoryIssue(self.requester) self.task = HistoryTask(self.requester) self.user_story = HistoryUserStory(self.requester) self.wiki = HistoryWiki(self.requester) self.epic = HistoryEpic(self.requester)
[docs] class HistoryEntity: """ HistoryEntity model """ endpoint = "history" def __init__(self, requester): self.requester = requester
[docs] def get(self, resource_id): """ Get a history element :param resource_id: id of the resource object (resource type is defined by the HistoryEntity subclass used) """ response = self.requester.get( "/{endpoint}/{entity}/{id}", endpoint=self.endpoint, entity=self.entity, id=resource_id, paginate=False ) return response.json()
[docs] def delete_comment(self, resource_id, comment_id): """ Delete a comment :param resource_id: id of the resource object (resource type is defined by the HistoryEntity subclass used) :param comment_id: id of the comment to delete """ self.requester.post( "/{endpoint}/{entity}/{id}/delete_comment?id={comment_id}", endpoint=self.endpoint, entity=self.entity, id=resource_id, comment_id=comment_id, )
[docs] def undelete_comment(self, resource_id, comment_id): """ Undelete a comment :param resource_id: id of the resource object (resource type is defined by the HistoryEntity subclass used) :param comment_id: id of the comment to undelete """ self.requester.post( "/{endpoint}/{entity}/{id}/undelete_comment?id={comment_id}", endpoint=self.endpoint, entity=self.entity, id=resource_id, comment_id=comment_id, )
[docs] class HistoryIssue(HistoryEntity): """ HistoryIssue model """ def __init__(self, *args, **kwargs): super(type(self), self).__init__(*args, **kwargs) self.entity = "issue"
[docs] class HistoryEpic(HistoryEntity): """ HistoryEpic model """ def __init__(self, *args, **kwargs): super(type(self), self).__init__(*args, **kwargs) self.entity = "epic"
[docs] class HistoryTask(HistoryEntity): """ HistoryTask model """ def __init__(self, *args, **kwargs): super(type(self), self).__init__(*args, **kwargs) self.entity = "task"
[docs] class HistoryUserStory(HistoryEntity): """ HistoryUserStory model """ def __init__(self, *args, **kwargs): super(type(self), self).__init__(*args, **kwargs) self.entity = "userstory"
[docs] class HistoryWiki(HistoryEntity): """ HistoryWiki model """ def __init__(self, *args, **kwargs): super(type(self), self).__init__(*args, **kwargs) self.entity = "wiki"
[docs] class Webhook(InstanceResource): """ Webhook model :param requester: :class:`Requester` instance :param name: name of :class:`Webhook` :param url: payload url of :class:`Webhook` :param key: secret key of :class:`Webhook` """ endpoint = "webhooks" allowed_params = ["name", "url", "key"]
[docs] class Webhooks(ListResource): """ Webhooks factory """ instance = Webhook
[docs] def create(self, project, name, url, key, **attrs): """ Create a new :class:`Webhook` :param project: :class:`Project` id :param name: name of :class:`Webhook` :param url: payload url of :class:`Webhook` :param key: secret key of :class:`Webhook` :param attrs: optional attributes for :class:`Webhook` """ attrs.update({"project": project, "name": name, "url": url, "key": key}) return self._new_resource(payload=attrs)