Beispiel #1
0
    def post(self, project_pk):
        """
        Move Ticket
        :param project_pk: Project ID
        :return:
        """
        get_project_request(project_pk)
        data = request.get_json(silent=True)
        if not data:
            raise api_errors.InvalidAPIUsage(api_errors.INVALID_JSON_BODY_MSG)

        source = data.get('source')
        destiny = data.get('dest')

        if not source or not destiny:
            raise api_errors.InvalidAPIUsage(payload={
                'source': api_errors.REQUIRED_MSG,
                'dest': api_errors.REQUIRED_MSG
            })

        remove_from_sprint = False
        sprint_id = None
        ticket_id = None

        if source.get('project_id'):
            sprint_id = destiny.get('sprint_id')
            ticket_id = source.get('ticket_id')
        elif source.get('sprint_id') and destiny.get('sprint_id'):
            sprint_id = destiny.get('sprint_id')
            ticket_id = source.get('ticket_id')
        elif source.get('sprint_id') and destiny.get('project_id'):
            sprint_id = source.get('sprint_id')
            ticket_id = source.get('ticket_id')
            remove_from_sprint = True

        sprint = get_sprint_request(sprint_id)
        ticket = get_ticket_request(ticket_id)

        if remove_from_sprint:
            SprintTicketOrder.inactivate_spo(sprint, ticket)
            Ticket.order_items(destiny.get('order'))
        else:
            SprintTicketOrder.inactivate_spo(sprint, ticket)

            tkt_ord_sprint = SprintTicketOrder()
            tkt_ord_sprint.sprint = sprint
            tkt_ord_sprint.ticket = ticket
            tkt_ord_sprint.ticket_repr = ticket.to_dict()
            tkt_ord_sprint.save()

            SprintTicketOrder.order_items(destiny.get('order'), sprint)

        # save activity
        save_notification(project_pk=project_pk,
                          verb='ticket_movement',
                          data=data)

        return data, 200
Beispiel #2
0
def project_member_pre_delete(sender, document, *args, **kwargs):
    """
    Delete related documents when a Project Member is deleted
    :param sender: Class
    :param document: Project Member Object
    :return: Nothing
    """
    Ticket.objects(
        assigned_to__contains=document
    ).update(pull__assigned_to=document)
Beispiel #3
0
def project_pre_delete(sender, document, *args, **kwargs):
    """
    Delete related documents when a User is deleted
    :param sender: Class
    :param document: Project Object
    :return: Nothing
    """
    # delete sprints
    Sprint.objects(project=document).delete()
    # delete members
    ProjectMember.objects(project=document).delete()
    # delete tickets
    Ticket.objects(project=document).delete()
    # delete columns
    Column.objects(project=document).delete()
Beispiel #4
0
    def post(self, project_pk, tkt_id):
        """
        Clone Ticket - Make a copy of a ticket
        :param project_pk:
        :param tkt_id:
        :return:
        """
        prj = get_project_request(project_pk)
        tkt = get_ticket_request(tkt_id)

        new_tkt = tkt.clone()
        last_tkt = Ticket.get_last_ticket(prj)
        new_tkt.number = last_tkt.number + 1 if last_tkt else 1
        new_tkt.order = Ticket.get_next_order_index(prj)
        new_tkt.save()
        return new_tkt, 200
Beispiel #5
0
    def delete(self, project_pk, tkt_id, rtkt_id):
        """
        Delete Related Ticket
        :param project_pk: Project ID
        :param tkt_id: Ticket ID
        :param rtkt_id: Related Ticket ID
        :return:
        """
        get_project_request(project_pk)
        get_ticket_request(tkt_id)

        rtkt = TicketDependency.get_by_id(rtkt_id)
        if not rtkt:
            raise api_errors.MissingResource(api_errors.INVALID_TICKET_MSG)

        Ticket.remove_related_ticket(tkt_id, rtkt)
        return {}, 204
Beispiel #6
0
    def post(self, project_pk):
        """
        Update Order
        """
        get_project_request(project_pk)
        data = request.get_json(silent=True)
        if not data:
            raise api_errors.InvalidAPIUsage(api_errors.INVALID_JSON_BODY_MSG)

        Ticket.order_items(data)

        # save activity
        save_notification(project_pk=project_pk,
                          verb='backlog_order',
                          data=data)

        return data, 200
Beispiel #7
0
    def get(self, project_pk):
        """
        Get Closed tickets

        :param project_pk: Project ID
        :return: List of tickets closed
        """
        prj = get_project_request(project_pk)
        return Ticket.get_closed_tickets(prj), 200
Beispiel #8
0
    def put(self, project_pk, tkt_id):
        """
        Update Ticket
        :param project_pk: Project ID
        :param tkt_id: Ticket ID
        :return: updated Ticket Resource
        """
        get_project_request(project_pk)
        tkt = get_ticket_request(tkt_id)
        data = request.get_json(silent=True)

        if not data:
            raise api_errors.InvalidAPIUsage(api_errors.INVALID_JSON_BODY_MSG)

        tkt.description = data.get('description', tkt.description)
        tkt.points = data.get('points', tkt.points)
        tkt.title = data.get('title', tkt.title)
        tkt.labels = data.get('labels', tkt.labels)
        tkt.type = data.get('type', tkt.type)
        tkt.closed = data.get('closed', tkt.closed)

        if 'related_tickets_data' in data:
            for tkt_rel_data in data.get('related_tickets_data'):
                tkt_rel = Ticket.get_by_id(tkt_rel_data.get('value'))
                if tkt_rel:
                    rt = TicketDependency()
                    rt.ticket = tkt_rel
                    rt.type = tkt_rel_data.get('type', 'R')
                    rt.save()
                    tkt.related_tickets.append(rt)

        tkt.save()

        if data.get('sprint'):
            sprint = Sprint.get_by_id(data.get('sprint')['pk'])
            if sprint:
                spo = SprintTicketOrder.get_active_sprint_ticket(sprint, tkt)
                if not spo:
                    # remove old data if this already exists
                    spo = SprintTicketOrder(sprint=sprint, ticket=tkt)
                    spo.ticket_repr = tkt.to_dict()
                    spo.order = SprintTicketOrder.get_next_order_index(
                        sprint.id)
                spo.save()
        else:
            spo = SprintTicketOrder.get_active_ticket(tkt)
            if spo:
                spo.ticket_repr = tkt.to_dict()
                spo.save()

        # save activity
        save_notification(project_pk=project_pk,
                          verb='update_ticket',
                          data=tkt.to_dict())

        return tkt, 200
Beispiel #9
0
def get_ticket_request(ticket_id):
    """
    Get Ticket from the url
    :param ticket_id: Ticket ID
    :return: Ticket Object
    """
    tkt = Ticket.get_by_id(ticket_id)
    if tkt is None:
        raise api_errors.MissingResource(api_errors.INVALID_TICKET_MSG)
    return tkt
Beispiel #10
0
 def get(self, query):
     """
     Search Tickets that contains the query
     :param query: text to search
     :return: List of matched tickets
     """
     projects = []
     projects_query = ProjectMember.get_by_member(current_user.id)
     for p in projects_query:
         projects.append(str(p.project.pk))
     return Ticket.search(query, projects), 200
Beispiel #11
0
    def delete(self, project_pk, tkt_id, att_id):
        """
        Delete an attachment
        :param project_pk: Project ID
        :param tkt_id: Ticket ID
        :param att_id: Attachment ID
        :return: Nothing
        """
        get_project_request(project_pk)
        att = Attachment.get_by_id(att_id)
        tkt = get_ticket_request(tkt_id)
        Ticket.remove_attachment(tkt.id, att)

        # save activity
        save_notification(project_pk=project_pk,
                          verb='delete_attachment',
                          data=att.to_dict())

        att.delete()

        return {}, 204
Beispiel #12
0
    def delete(self, project_pk, tkt_id, pm_id):
        """
        Remove member from ticket
        :param project_pk: Project ID
        :param tkt_id: Ticket ID
        :param member_id: ProjectMember ID
        :return: Nothing
        """
        get_project_request(project_pk)
        tkt = get_ticket_request(tkt_id)

        pm = ProjectMember.get_by_id(pm_id)
        if not pm:
            raise api_errors.MissingResource(
                api_errors.INVALID_PROJECT_MEMBER_MSG)

        Ticket.remove_member(tkt, pm)

        # save activity
        save_notification(project_pk=project_pk,
                          verb='delete_assignment',
                          data=tkt.to_dict())
        return {}, 204
Beispiel #13
0
    def get(self, project_pk, query):
        """
        Search Tickets by project

        :param project_pk: Project ID
        :param query: text to search
        :return: List of matched tickets
        """
        prj = get_project_request(project_pk)
        tickets = set(Ticket.search(query, [str(prj.pk)]))
        results = []
        for tkt in tickets:
            val = dict(text='%s-%s: %s' %
                       (tkt.project.prefix, tkt.number, tkt.title),
                       value=str(tkt.id))
            results.append(val)
        return results, 200
Beispiel #14
0
    def get(self, project_pk):
        """
        Get Tickets for a Project
        :param project_pk: Project ID
        :return: List of tickets
        """
        prj = get_project_request(project_pk)

        tickets = []
        sprints = Sprint.get_by_project(prj)

        if prj.project_type == u'S':
            for s in sprints:
                spos = SprintTicketOrder.get_active_sprint(s)
                for spo in spos:
                    tickets.append(spo.ticket.id)

        return Ticket.get_tickets_backlog(project_pk, tickets), 200
Beispiel #15
0
    def get(self, project_pk):
        """
        Get Tickets for backlog board

        :param project_pk: Project ID
        :return: List of tickets
        """
        tickets = []
        col_ids = []

        prj = get_project_request(project_pk)

        column_list = Column.get_by_project(prj)
        for c in column_list:
            col_ids.append(str(c.pk))

        tct_list = TicketCT.get_transitions_in_cols(col_ids)
        for t in tct_list:
            tickets.append(str(t.ticket.pk))

        results = Ticket.get_tickets_backlog(prj, not_tickets=tickets)
        return results, 200
Beispiel #16
0
    def post(self, project_pk):
        """
        Create Ticket
        """
        data = request.get_json(silent=True)

        if not data:
            raise api_errors.InvalidAPIUsage(api_errors.INVALID_JSON_BODY_MSG)

        project = get_project_request(project_pk)

        tkt = Ticket()

        last_tkt = Ticket.get_last_ticket(project_pk)
        tkt.number = last_tkt.number + 1 if last_tkt else 1
        tkt.order = Ticket.get_next_order_index(project_pk)
        tkt.project = project
        tkt.description = data.get('description')
        tkt.points = data.get('points', 0)
        tkt.title = data.get('title')
        tkt.labels = data.get('labels')
        tkt.type = data.get('type', 'U')
        tkt.save()

        if data.get('sprint'):
            # Assign to a sprint
            sprint = Sprint.get_by_id(pk=data.get('sprint')['pk'])
            if sprint:
                spo = SprintTicketOrder(sprint=sprint, ticket=tkt)
                spo.ticket_repr = tkt.to_dict()
                spo.order = SprintTicketOrder.get_next_order_index(sprint.id)
                spo.save()

        # save activity
        save_notification(project_pk=project_pk,
                          verb='new_ticket',
                          data=tkt.to_dict())

        return tkt, 201
Beispiel #17
0
    def put(self, project_pk, sp_id):
        """
        Update a Sprint
        :param project_pk:
        :param sp_id:
        :return:
        """
        get_project_request(project_pk)
        data = request.get_json(silent=True)
        if not data:
            raise api_errors.InvalidAPIUsage(api_errors.INVALID_JSON_BODY_MSG)

        sp = get_sprint_request(sp_id)
        sp.name = data.get('name', sp.name)

        if data.get('for_starting'):
            # sum all the ticket for the initial planning value
            sto = SprintTicketOrder.get_active_sprint(sp)
            total_planned_points = 0
            if sto:
                # get the sum of points
                for s in sto:
                    total_planned_points += s.ticket.points

            sp.total_points_when_started = total_planned_points

            sp.start_date = parser.parse(data.get('start_date'))
            sp.end_date = parser.parse(data.get('end_date'))
            sp.started = True

        elif data.get('for_finalized'):
            # Mark as finalized
            sp.finalized = True

            # Get tickets in Done column
            finished_tickets = []
            tickets_to_close_id = []
            tt = TicketCT.get_transitions_for_sprint(sp)

            for t in tt:
                if t.column.done_column:
                    finished_tickets.append(t.ticket)
                    tickets_to_close_id.append(str(t.ticket.pk))

            # Deactivate Tickets
            SprintTicketOrder.inactivate_list_spo(sp, finished_tickets)
            # Close Tickets
            Ticket.close_tickets(tickets_to_close_id)

        elif data.get('for_editing'):
            sp.start_date = parser.parse(data.get('start_date'))
            sp.end_date = parser.parse(data.get('end_date'))

        sp.save()

        # save activity
        save_notification(project_pk=project_pk,
                          verb='update_sprint',
                          data=sp.to_dict())

        return sp, 200
Beispiel #18
0
class ProjectImport(AuthResource):
    """
    Import Data Project
    """

    def post(self, project_pk):
        """
        Import cards and columns

        :param project_pk: Project ID
        :return: List of Tickets and Columns imported
        """
        project = get_project_request(project_pk)
        try:
            body = json.loads(request.form.get('data'))
        except ValueError, e:
            raise api_errors.InvalidAPIUsage(
                api_errors.INVALID_JSON_BODY_MSG
            )

        imported_file = request.files.get('file')

        if not imported_file:
            raise api_errors.InvalidAPIUsage(
                api_errors.REQUIRED_MSG
            )

        data = json.loads(imported_file.stream.read().decode('utf-8'),
                          encoding='UTF-8')

        import_args = body.get('data')
        tickets = []
        last_ticket = Ticket.get_last_ticket(project_pk)
        starting_number = last_ticket.number if last_ticket else 1
        amazon_url = 'https://trello-attachments.s3.amazonaws.com/'

        if import_args.get('include_cards'):
            for card in data.get('cards'):
                t = Ticket()
                t.title = card.get('name')
                t.description = card.get('desc')
                t.labels = [l.get('name') for l in card.get('labels')]
                t.closed = card.get('closed')

                for att in card.get('attachments'):
                    location = att.get('url')
                    if amazon_url in location:
                        file_location = urllib2.urlopen(location)
                        file_data = file_location.read()
                        if file_data:
                            att_file = Attachment()
                            att_file.name = att.get('name')
                            att_file.size = att.get('bytes')
                            att_file.type = att.get('mimeType')
                            att_file.data = base64.b64encode(file_data)
                            att_file.save()
                            t.files.append(att_file)
                t.project = project
                t.number = starting_number
                t.order = starting_number - 1
                # by default user story
                t.type = 'U'
                t.points = 0
                tickets.append(t)
                starting_number += 1

        columns = []
        if import_args.get('include_cols'):
            for col in data.get('lists'):
                if not col.get('closed'):
                    new_col = Column()
                    new_col.title = col.get('name')
                    new_col.project = project
                    columns.append(new_col)

        if tickets:
            Ticket.objects.insert(tickets, load_bulk=False)
        if columns:
            Column.objects.insert(columns, load_bulk=False)

        # save activity
        save_notification(project_pk=project_pk,
                          verb='import',
                          data=data)

        return [tickets, columns], 200