예제 #1
0
    def post(self):
        """
        Create user resource
        :return: a Created resource
        """
        user_data = request.get_json(silent=True)
        if not user_data:
            raise api_errors.InvalidAPIUsage(
                api_errors.INVALID_JSON_BODY_MSG
            )

        user, errors_dic = create_user(user_data)
        errors_list = []
        if errors_dic:
            errors_list.append(errors_dic)

        if errors_list:
            raise api_errors.InvalidAPIUsage(
                api_errors.VALIDATION_ERROR_MSG,
                payload=errors_list
            )

        user.save()
        create_activation_email(user)

        return user, 201
예제 #2
0
    def post(self, project_pk, tkt_id):
        """
        Add Attachment to Ticket
        :param project_pk: Project ID
        :param tkt_id: Ticket ID
        :return: Created Attachment
        """
        get_project_request(project_pk)
        file_item = request.files.get('file')
        if not file_item:
            raise api_errors.InvalidAPIUsage(payload=dict(
                file=api_errors.REQUIRED_MSG))
        data = json.loads(request.form.get('data'))
        if not data:
            raise api_errors.InvalidAPIUsage(payload=dict(
                data=api_errors.REQUIRED_MSG))

        ticket = get_ticket_request(tkt_id)

        att = Attachment()
        att.name = data.get('name')
        att.size = data.get('size')
        att.type = data.get('type')
        att.data = base64.b64encode(file_item.stream.read())
        att.save()
        ticket.files.append(att)
        ticket.save()

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

        return att, 200
예제 #3
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
예제 #4
0
    def post(self, project_pk):
        """
        Create a new Project Member

        :param project_pk: Project ID
        :return: the created ProjectMember
        """

        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)

        members_added = []
        errors_list = []
        for member in data:
            if member.get('value'):
                user = User.get_by_id(member.get('value'))
                if not user:
                    errors_list.append(
                        dict(member=api_errors.INVALID_MEMBER_MSG))
            else:
                user = User(email=member.get('text'))
                user.active = False
                user.save()
            if user and project.owner.id != user.id:
                m = ProjectMember.get_by_project_member(project, user)
                if not m:
                    m = ProjectMember(project=project)
                    m.member = user
                    m.save()
                    # Send email notification
                    create_new_member_email(m.member, project)
                    members_added.append(m.to_dict())
                else:
                    errors_list.append(dict(
                        member=api_errors.INVALID_ALREADY_ADDED_MSG
                    ))
        if errors_list:
            raise api_errors.InvalidAPIUsage(
                api_errors.VALIDATION_ERROR_MSG,
                payload=errors_list
            )

        if members_added:
            # save activity
            save_notification(project_pk=project.id,
                              verb='new_members',
                              data={'members': members_added})
        return {}, 200
예제 #5
0
    def post(self):
        """
        Activate a user based on a token
        :return: token auth
        """
        data = request.get_json(silent=True)
        if not data:
            raise api_errors.InvalidAPIUsage(
                api_errors.INVALID_JSON_BODY_MSG
            )

        user = User.get_by_activation_token(data.get('token'))
        if not user:
            raise api_errors.MissingResource(
                api_errors.ACTIVATION_INVALID_TOKEN_MSG
            )

        user.active = True
        user.save()

        tokens_dict = current_app.token_handler.generate_tokens_dict(
            user.pk
        )

        return tokens_dict, 200
예제 #6
0
    def put(self, project_pk, tkt_id, pm_id):
        """
        Assign a member to a ticket, this will update the ticket
        :param project_pk: Project ID
        :param tkt_id: Ticket ID
        :param member_id: Member ID
        :return: Ticket Object
        """
        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)

        if pm in tkt.assigned_to:
            raise api_errors.InvalidAPIUsage(
                api_errors.INVALID_ALREADY_ADDED_MSG)

        tkt.assigned_to.append(pm)
        tkt.save()

        # save activity
        save_notification(project_pk=project_pk,
                          verb='new_assigment',
                          data=tkt.to_dict())
        return tkt, 200
예제 #7
0
    def put(self, project_pk, tkt_id, comment_id):
        """
        Update a comment
        :param project_pk: Project ID
        :param tkt_id: Ticket ID
        :param comment_id: Comment ID
        :return: Updated Comment
        """
        get_project_request(project_pk)
        get_ticket_request(tkt_id)

        comment = Comment.get_by_id(comment_id)
        if not comment:
            raise api_errors.MissingResource(api_errors.INVALID_COMMENT_MSG)

        data = request.get_json(silent=True)
        if not data:
            raise api_errors.InvalidAPIUsage(api_errors.INVALID_JSON_BODY_MSG)

        if comment.who.id != current_user.id:
            raise api_errors.ForbiddenRequest()

        comment.comment = data.get('comment')
        comment.save()

        save_notification(project_pk=project_pk,
                          verb='update_comment',
                          data={
                              "comment": comment.to_dict(),
                              "ticket": comment.ticket.to_dict()
                          })

        return comment, 200
예제 #8
0
    def post(self):
        """
        Endpoint for token requests.
        Creates a new access token based on provided credentials.
        :return: JSON with the token, refresh token and expiration time
        """
        data = request.get_json(silent=True)

        if data:
            email = data.get('email')
            password = data.get('password')

            try:
                user = User.objects.get(email=email, active=True)
            except errors.DoesNotExist:
                raise api_errors.UnauthorizedRequest(
                    api_errors.INVALID_CREDENTIALS_MSG)

            if not user.verify_password(password):
                raise api_errors.UnauthorizedRequest(
                    api_errors.INVALID_CREDENTIALS_MSG)

            tokens_dict = current_app.token_handler.generate_tokens_dict(
                user.pk)

            return tokens_dict, 200

        raise api_errors.InvalidAPIUsage(api_errors.INVALID_JSON_BODY_MSG)
예제 #9
0
    def post(self, project_pk, column):
        """
        Order Tickets in Columns
        :param project_pk: Project ID
        :param column: Column ID
        :return: Order
        """
        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)

        col = Column.get_by_id(column)
        if not col:
            raise api_errors.MissingResource(api_errors.INVALID_COLUMN_MSG)

        if project.project_type == 'S':
            sprint = get_sprint_request(data.get('sprint'))
            TicketCT.order_items(data.get('order'), sprint=sprint)
        else:
            TicketCT.order_items(data.get('order'))

        # save activity
        save_notification(project_pk=project_pk,
                          verb='ticket_column_order',
                          data=data)
        return data, 200
예제 #10
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
예제 #11
0
    def post(self):
        """
        Social authorization endpoint.
        """
        request_data = request.get_json(silent=True)

        # Check required data
        if not request_data:
            raise errors.InvalidAPIUsage(errors.INVALID_JSON_BODY_MSG)

        provider_name = request_data.get('provider')
        provider = oauth_handler.get_provider(provider_name)
        if not provider:
            raise errors.InvalidAPIUsage(errors.PROVIDER_INVALID_MSG)

        access_token = request_data.get('token')
        if not access_token:
            raise errors.InvalidAPIUsage(errors.MISSING_PROVIDER_TOKEN_MSG)

        user_id = request_data.get('user_id')
        if not user_id:
            raise errors.InvalidAPIUsage(errors.MISSING_PROVIDER_USER_ID_MSG)

        # Validate the token
        error_msg = provider.validate_token(access_token, user_id)
        if error_msg:
            raise errors.UnauthorizedRequest(errors.PROVIDER_INVALID_TOKEN_MSG)

        user_data = provider.get_user_data(access_token)

        if not user_data:
            raise errors.BasicAPIException(errors.PROVIDER_INVALID_RESP_MSG)

        # On new email, register the user
        user, _ = User.get_or_create(**user_data)
        user.save()

        tokens_dict = current_app.token_handler.generate_tokens_dict(user.id)

        return dict(tokens_dict), 200
예제 #12
0
    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
            )
예제 #13
0
    def put(self, project_pk):
        """
        Update a Project Instance
        :param project_pk:
        :return:
        """
        project = get_project_request(project_pk)
        data = request.get_json(silent=True)

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

        project.active = data.get('active')
        project.description = data.get('description')
        project.name = data.get('name')
        owner = User.get_by_id(data.get('owner_id'))

        if not owner:
            raise api_errors.InvalidAPIUsage(
                api_errors.INVALID_USER_ID_MSG
            )

        project.owner = owner.to_dbref()
        project.private = data.get('private')
        project.sprint_duration = data.get('sprint_duration')
        project.prefix = data.get('prefix')
        project.project_type = data.get('project_type', 'S')
        project.save()

        # save activity
        save_notification(project_pk=project.pk,
                          verb='update_project',
                          data=project.to_dict())

        return project, 200
예제 #14
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
예제 #15
0
    def post(self, project_pk):
        """
        Order sprints in a project

        :param project_pk: Project ID
        :return: Order
        """
        data = request.get_json(silent=True)
        if not data:
            raise api_errors.InvalidAPIUsage(api_errors.INVALID_JSON_BODY_MSG)

        Sprint.order_items(data)
        # save activity
        save_notification(project_pk=project_pk,
                          verb='order_sprints',
                          data=data)
        return data, 200
예제 #16
0
    def post(self):
        """
        Create Project
        """
        data = request.get_json(silent=True)
        if not data:
            raise api_errors.InvalidAPIUsage(
                api_errors.INVALID_JSON_BODY_MSG
            )

        prj = Project(name=data.get('name'),
                      owner=g.user.to_dbref())
        prj.active = data.get('active')
        prj.private = data.get('private')
        prj.prefix = data.get('prefix', data.get('name')[:3].upper())
        prj.description = data.get('description')
        prj.project_type = data.get('project_type', 'S')

        # Add initial config
        prj.sprint_duration = 15
        prj.save()

        # add owner as member
        pm = ProjectMember(project=prj)
        pm.member = prj.owner
        pm.is_owner = True
        pm.save()

        # Add 3 columns states
        col_names = ['ToDo', 'In Progress', 'Done']
        for index, c in enumerate(col_names):
            col = Column()
            col.title = c
            col.project = prj
            if index == len(col_names) - 1:
                col.done_column = True
            col.save()

        # save activity
        save_notification(project_pk=prj.pk,
                          verb='new_project',
                          data=prj.to_dict())

        return prj, 201
예제 #17
0
    def put(self, user_id):
        """
        Update Resource
        :param user_id: The User ID
        :return: Return a user instance updated
        """
        data = request.get_json(silent=True)
        if not data:
            raise api_errors.InvalidAPIUsage(api_errors.INVALID_JSON_BODY_MSG)

        user = get_user_for_request(user_id)
        user.first_name = data.get('first_name', user.first_name)
        user.last_name = data.get('last_name', user.last_name)
        user.picture = data.get('picture', user.picture)
        user.email = data.get('email', user.email)

        user.save()

        return user, 200
예제 #18
0
    def post(self, project_pk, tkt_id):
        """
        Create a Comment for a ticket
        :param project_pk: Project ID
        :param tkt_id: Ticket ID
        :return: Created Comment
        """
        get_project_request(project_pk)
        get_ticket_request(tkt_id)
        data = request.get_json(silent=True)
        if not data:
            raise api_errors.InvalidAPIUsage(api_errors.INVALID_JSON_BODY_MSG)

        c = Comment(ticket=tkt_id)
        c.who = current_user.to_dbref()
        c.comment = data.get('comment')
        c.save()

        if data.get('mentions'):
            for m in data.get('mentions'):
                if m is not None:
                    user = User.get_by_id(m)
                    if user:
                        create_notification_email(user, c)
                        # save activity
                        save_notification(project_pk=project_pk,
                                          verb='mention',
                                          user_to=user,
                                          data={
                                              "comment": c.to_dict(),
                                              "ticket": c.ticket.to_dict()
                                          })
        else:
            # save activity
            save_notification(project_pk=project_pk,
                              verb='new_comment',
                              data={
                                  "comment": c.to_dict(),
                                  "ticket": c.ticket.to_dict()
                              })

        return c, 201
예제 #19
0
    def post(self):
        """
        Endpoint for token refreshing.
        Takes a refresh token from a JSON body and issues a new
        access token.
        :return: A new token with a new expiration time.
        """
        data = request.get_json(silent=True)

        if data:
            refresh = data.get('refresh_token')
            expire = current_app.token_handler.expires_in
            new_token = current_app.token_handler.refresh_token(refresh)

            if not new_token:
                raise api_errors.UnauthorizedRequest(
                    api_errors.INVALID_REFRESH_TOKEN_MSG)

            return dict(token=new_token, expires_in=expire), 200

        raise api_errors.InvalidAPIUsage(api_errors.INVALID_JSON_BODY_MSG)
예제 #20
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
예제 #21
0
    def post(self, project_pk):
        """
        Update order of columns

        :param project_pk: project id
        :return: same data sent
        """
        prj = get_project_request(project_pk)

        data = request.get_json(silent=True)
        if not data:
            raise api_errors.InvalidAPIUsage(
                api_errors.INVALID_JSON_BODY_MSG
            )

        Column.order_items(data)

        # save activity
        save_notification(project_pk=prj.id,
                          verb='order_columns',
                          data=data)
        return data, 200
예제 #22
0
    def put(self, project_pk, column_pk):
        """
        Update a column instance

        :param project_pk: Project that belongs
        :param column_pk: Id of the column
        :return: The updated resource
        """

        col = Column.get_by_id(column_pk)
        if not col:
            raise api_errors.MissingResource(
                api_errors.INVALID_COLUMN_MSG
            )

        data = request.get_json(silent=True)

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

        col.title = data.get('title')
        col.color_max_cards = data.get('color_max_cards', '#FF0000')
        col.done_column = data.get('done_column', False)
        col.max_cards = data.get('max_cards', 9999)

        # check set other columns of the project to done_column in False
        if col.done_column:
            Column.clear_done_columns(project_pk)
        col.save()

        # save activity
        save_notification(project_pk=project_pk,
                          verb='update_column',
                          data=col.to_dict())

        return col, 200
예제 #23
0
    def post(self, project_pk, sprint_pk):
        """
        Update Order of tickets in sprint

        :param project_pk: Project ID
        :param sprint_pk: Sprint ID
        :return: 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)

        sprint = get_sprint_request(sprint_pk)

        SprintTicketOrder.order_items(data, sprint)
        # save activity
        save_notification(project_pk=project_pk,
                          verb='sprint_ticket_order',
                          data=data)

        return data, 200
예제 #24
0
def detect_mime_type():
    """
    Check all API requests for `application/json` media type.
    :raise: InvalidAPIUsage error if an incorrect type was used.
    """
    headers_dict = dict(request.headers)

    if request.method in ['POST', 'PUT']:
        # For POST/PUT we need to check the content type
        content_type = headers_dict.get('Content-Type').split(';')[0]

        if content_type not in APP_ACCEPTED_TYPES:
            raise errors.InvalidAPIUsage(errors.INVALID_CONTENT_TYPE_MSG)
    else:
        # For GET/DELETE we need to check the accept types
        accept_types = headers_dict.get('Accept')

        # If there are no accepted types, we assume the client accepts ours
        if accept_types:
            accepts_our_mime = ((accept_types in APP_ACCEPTED_TYPES)
                                or ('*/*' in accept_types))

            if not accepts_our_mime:
                raise errors.NotAcceptable(accepted=APP_ACCEPTED_TYPES)
예제 #25
0
    def post(self, project_pk):
        """
        :param project_pk: Project ID
        :return: Column Resource created
        """
        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)

        col = Column()
        col.order = Column.objects.count()
        col.project = project
        col.title = data.get('title')
        col.color_max_cards = data.get('color_max_cards', '#FF0000')
        col.done_column = data.get('done_column', False)
        col.max_cards = data.get('max_cards', 9999)

        # Check if already exists one Done column
        if col.done_column:
            columns = Column.get_by_project(project)
            for c in columns:
                if c.done_column:
                    c.done_column = False
                    c.save()
        col.save()

        # save activity
        save_notification(project_pk=project.pk,
                          verb='new_column',
                          data=col.to_dict())

        return col, 200
예제 #26
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
예제 #27
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
예제 #28
0
    def post(self, project_pk):
        """
        Move Ticket to Column or Backlog
        :param project_pk: Project ID
        :return: Ticket Transition
        """
        project = get_project_request(project_pk)

        data = request.get_json(silent=True)
        if not data:
            raise api_errors.InvalidAPIUsage(api_errors.INVALID_JSON_BODY_MSG)

        tkt = get_ticket_request(data.get('ticket'))

        result = {}
        if data.get('backlog'):
            latest_tran = TicketCT.get_latest_transition(tkt)
            if latest_tran:
                latest_tran.latest_state = False
                latest_tran.save()

            SprintTicketOrder.order_items(data.get('order'),
                                          data.get('backlog'))
            # save activity
            save_notification(project_pk=project_pk,
                              verb='ticket_transition',
                              data=data)

            result = latest_tran.to_json(), 200

        else:
            # Search already state
            col = Column.get_by_id(data.get('column'))

            if not col:
                raise api_errors.MissingResource(api_errors.INVALID_COLUMN_MSG)

            user = User.get_by_id(current_user.id)
            if not user:
                raise api_errors.MissingResource(
                    api_errors.INVALID_USER_ID_MSG)

            transition = TicketCT()
            transition.ticket = tkt
            transition.column = col
            transition.order = TicketCT.get_next_order_index(col)

            if project.project_type == 'S':
                sprint = get_sprint_request(data.get('sprint'))
                latest_tran = TicketCT.get_latest_transition(tkt, sprint)

                transition.sprint = sprint
            else:
                latest_tran = TicketCT.get_latest_transition(tkt)

            if latest_tran:
                latest_tran.latest_state = False
                latest_tran.save()

            transition.latest_state = True
            transition.who = user
            transition.save()

            if project.project_type == 'S':
                sprint = get_sprint_request(data.get('sprint'))
                TicketCT.order_items(data.get('order'),
                                     sprint=sprint,
                                     column=col)
            else:
                TicketCT.order_items(data.get('order'), column=col)

            # save activity
            save_notification(project_pk=project_pk,
                              verb='ticket_transition',
                              data=transition.to_dict())

            result = transition.to_json(), 201
        return result