def post(self):
        """ Collect data from the HTML form to fill in a Trello card.

        That card will be uploaded to Suggestion Box board, on the corresponding
        list, determined by the "System" attribute given in the form.
        """
        # Get form data
        date = datetime.now()
        title = self.get_argument('title')
        area = self.get_argument('area')
        system = self.get_argument('system')
        importance = self.get_argument('importance')
        difficulty = self.get_argument('difficulty')
        user = self.get_current_user_name()
        description = self.get_argument('description')
        suggestion = self.get_argument('suggestion')

        client = TrelloClient(api_key = self.application.trello_api_key,
                              api_secret = self.application.trello_api_secret,
                              token = self.application.trello_token)

        # Get Suggestion Box board
        boards = client.list_boards()
        suggestion_box = None
        for b in boards:
            if b.name == 'Suggestion Box':
                suggestion_box = client.get_board(b.id)
                break

        # Get the board lists (which correspond to System in the form data) and
        # concretely get the list where the card will go
        lists = b.all_lists()
        card_list = None
        for l in lists:
            if l.name == system:
                card_list = l
                break

        # Create new card using the info from the form
        new_card = card_list.add_card(TITLE_TEMPLATE.format(title=title, area=area))
        new_card.set_description(DESCRIPTION_TEMPLATE.format(date = date.ctime(),
                                                             area=area,
                                                             system=system,
                                                             importance=importance,
                                                             difficulty=difficulty,
                                                             user=user,
                                                             description=description,
                                                             suggestion=suggestion))

        # Save the information of the card in the database
        self.application.suggestions_db.create({'date': date.isoformat(),
                                                'card_id': new_card.id,
                                                'description': new_card.description,
                                                'name': new_card.name,
                                                'url': new_card.url,
                                                'archived': False})

        self.set_status(200)
    def save_to_trello(self):
        # print clean_form_data
        api_key = settings.TRELLO_KEY
        secret = settings.TRELLO_SECRET
        token = settings.TRELLO_TOKEN
        board = settings.TRELLO_REQUEST_BOARD

        c = TrelloClient(api_key, secret, token)
        b = c.get_board(board)

        # Currently we default to adding card to first list
        l = b.all_lists()[0]
        label_list = b.get_labels()

        ds_name = "%s - %s" % (self.dataset_name, self.dataset_source)

        ds_description = "%s\n%s\nRequested by: %s %s, %s" % \
            (self.dataset_name,
            self.dataset_description,
            self.user_first_name,
            self.user_last_name,
            self.user_email)

        try:
            label_to_add = next(x for x in label_list if x.name == 'Request')
        except StopIteration:
            label_to_add = b.add_label('Request', "lime")

        try:
            card = l.add_card(ds_name, ds_description, [label_to_add])
            self.trello_id = card.id
        except Exception:
            pass
def get_trello_cards():
    """
    Makes an API call to Trello to get all of the cards from Weird Canada's
    New Canadiana board. Requires an OAuth key.
    :return: list of trello cards
    """
    trello_client = TrelloClient(
        api_key=os.environ.get('TRELLO_API_KEY'),
        api_secret=os.environ.get('TRELLO_API_SECRET'),
        token=os.environ.get('TRELLO_OAUTH_KEY'),
        token_secret=os.environ.get('TRELLO_OAUTH_SECRET')
    )

    new_canadiana_board_id = os.environ.get('BOARD_ID')
    new_canadiana_board = trello_client.get_board(new_canadiana_board_id)

    return new_canadiana_board.open_cards()
Esempio n. 4
0
class TrelloManager(object):
    def __init__(self):
        trello_config = Config.open_api.trello

        self.client = TrelloClient(
            api_key=trello_config.API_KEY,
            api_secret=trello_config.API_SECRET,
            token=trello_config.TOKEN,
        )
        self.board = self.client.get_board(trello_config.BOARD)

    def get_list_by_name(self, name):
        for l in self.board.all_lists():
            if l.name == name:
                return l
        return None

    def get_card_count_by_list_name(self, name):
        l = self.get_list_by_name(name)
        if l is None:
            raise ValueError(f"there is no {name} list in trello board.")

        return len(l.list_cards())

    def get_random_card_name(self, list_name: str = "Inbox"):
        l = self.get_list_by_name(list_name)
        if l is None or len(l.list_cards()) == 0:
            return None
        return random.choice(l.list_cards()).name

    def add_card(self, list_name: str, card_name):
        l = self.get_list_by_name(list_name)
        l.add_card(card_name)

    def archive_all_cards(self, list_name):
        l = self.get_list_by_name(list_name)
        l.archive_all_cards()

    def clean_board(self, except_list_name=None):
        l_list = self.board.all_lists()
        for l in l_list:
            if except_list_name is not None and l.name in except_list_name:
                pass
            else:
                l.archive_all_cards()
def sync(events, token):
    trello = TrelloClient(api_key=TRELLO_KEY, token=token)
    board = trello.get_board('55f7167c46760fcb5d68b385')

    far_away, less_2_months, less_1_month, less_1_week, today, past = board.all_lists()

    all_cards = {card_id(c): c for c in board.all_cards()}

    date_today = datetime.date.today()

    for e in events:
        card = all_cards.get(e.id)

        if not card:
            card = create_card(e, far_away)
            create_checklist(card)

        #fetch card to get due date
        try:
            card.fetch()
        except ResourceUnavailable:
            print("Oopsie: too many requests! Let's wait 10 seconds!")
            time.sleep(10)
            card.fetch()

        if e.date != card.due_date.date():
            print('Changing due date of {} to {}'.format(e.city, e.date))
            card.set_due(e.date)

        distance = (e.date - date_today).days
        if distance < 0:
            right_list = past
        elif distance == 0:
            right_list = today
        elif distance < 7:
            right_list = less_1_week
        elif distance < 30:
            right_list = less_1_month
        elif distance < 60:
            right_list = less_2_months
        else:
            right_list = far_away

        ensure_card_in_list(card, right_list)
def sync(events, token):
    trello = TrelloClient(api_key=TRELLO_KEY, token=token)
    board = trello.get_board("55f7167c46760fcb5d68b385")

    far_away, less_2_months, less_1_month, less_1_week, today, past = board.all_lists()

    all_cards = {card_id(c): c for c in board.all_cards()}

    date_today = datetime.date.today()

    for e in events:
        card = all_cards.get(e.id)

        if not card:
            card = create_card(e, far_away)
            create_checklist(card)

        # fetch card to get due date
        card.fetch()

        if e.date != card.due_date.date():
            print("Changing due date of {} to {}".format(e.city, e.date))
            card.set_due(e.date)

        distance = (e.date - date_today).days
        if distance < 0:
            right_list = past
        elif distance == 0:
            right_list = today
        elif distance < 7:
            right_list = less_1_week
        elif distance < 30:
            right_list = less_1_month
        elif distance < 60:
            right_list = less_2_months
        else:
            right_list = far_away

        ensure_card_in_list(card, right_list)
Esempio n. 7
0
class TrelloCli:

    def __init__(self, file='config.yml'):
        """ Load Trello api keys from yaml file"""
        with open(file, 'r') as stream:
            try:
                config = yaml.safe_load(stream)
                self.__client = TrelloClient(
                    api_key = config['key'],
                    api_secret = config['token']
                )
            except yaml.YAMLError as exc:
                    print(exc)

    def get_board(self, board_name):
        """ Get the board from the board name """
        boards = self.__client.list_boards()
        for board in boards:
            if board.name == board_name:
                return self.__client.get_board(board.id)

    def get_list(self, board, list_name):
        lists = board.all_lists()
        for list in lists:
            if list.name == list_name:
                return board.get_list(list.id)

    def get_member(self, board, member_name):
        members = board.all_members()
        for member in members:
            if member.full_name == member_name:
                return member

    def display_cards(self, trello_list):
        cards = trello_list.list_cards()
        for card in cards:
            print(card.name)
Esempio n. 8
0
class trello:
    def __init__(self, apiKey, TOKEN):
        self.apiKey = apiKey
        self.token = TOKEN
        self.client = TrelloClient(api_key=apiKey,
                                   api_secret='your-secret',
                                   token=TOKEN,
                                   token_secret='your-oauth-token-secret')

    def printTrello(self):
        all_boards = self.client.list_boards()
        last_board = all_boards[-1]
        print("Boards ")

        for board in all_boards:
            print("Board Name :", board.name, " Board ID", board.id)
            for list in board.all_lists():
                print("\t", "ListName :", list.name, "listID :", list.id)
                for card in list.list_cards(""):
                    print("\t\t", "cardName :", card.name, "cardID :", card.id)

                    #for card in board.all_cards():
                    #   print("\tCard Name :",card.name," Card ID",card.id)
                ####### BOARD OPERATIONS

    def getBoard(self, boardID):
        self.board = self.client.get_board(board_id=boardID)
        return self.board

    def getBoardByName(self, boardName):
        all_boards = self.client.list_boards()
        for board in all_boards:
            if board.name == boardName:
                self.board = board
                return board
        return None

    # close all boards
    def clearBoards(self):
        for board in self.client.list_boards():
            board.close()

    def createBoard(self,
                    boardName,
                    organizationID=None,
                    permission_level="private"):
        self.board = self.client.add_board(board_name=boardName,
                                           source_board=None,
                                           organization_id=organizationID,
                                           permission_level=permission_level)
        for list in self.board.get_lists(None):
            self.board.get_list(list.id).close()
        self.createList("To Do:", self.board.id, 1)
        self.createList("Doing:", self.board.id, 2)
        self.createList("Build:", self.board.id, 3)
        self.createList("Test:", self.board.id, 4)
        self.createList("Deploy:", self.board.id, 5)
        return self.board

    def closeBoardByName(self, boardName=None):
        if boardName != None:
            all_boards = self.client.list_boards()
            for board in all_boards:
                if board.name == boardName:
                    return board.close()
        else:
            if self.board != None:
                self.closeBoard(self.board.id)

    def closeBoard(self, boardId=None):
        if boardId != None:
            return self.getBoard(boardID=boardId).close()
        else:
            if self.board != None:
                self.board.close()
            else:
                return None

    def boardList(self):
        return self.client.list_boards()

    ####### END BOARD OPERATIONS

    ####### LIST OPERATIONS

    def getList(self, listID, boardID):
        return self.client.get_board(board_id=boardID).get_list(list_id=listID)

    def getListByName(self, listID, boardID):
        return self.client.get_board(board_id=boardID).get_list(list_id=listID)

    def createList(self, listName, boardID, sira=None):
        board = self.client.get_board(boardID)
        addedlist = board.add_list(listName, sira)
        return addedlist

    def closeList(self, listID, boardID):
        return self.client.get_board(boardID).get_list(listID).close()

    def closeJustListID(self, listID):  # unsafe
        url = "https://api.trello.com/1/lists/" + listID + "?closed=true&key=" + self.apiKey + "&token=" + self.token
        querystring = {}
        response = requests.request("PUT", url, params=querystring)
        return response.text

    ####### END LIST OPERATIONS

    ####### CARD OPERATIONS

    def getCard(self, cardID):
        return self.client.get_card(card_id=cardID)

    def createCard(self, boardID, listID, cardName):
        self.getList(boardID=boardID, listID=listID).add_card(name=cardName,
                                                              labels=None,
                                                              due="",
                                                              source=None,
                                                              position=None)

    def removeCard(self, cardID):
        url = "https://api.trello.com/1/cards/" + cardID + "?key=" + self.apiKey + "&token=" + self.token
        querystring = {}
        response = requests.request("PUT", url, params=querystring)
        return response.text

    def moveCard(self, cardID, desListID):
        self.getCard(cardID=cardID).change_list(list_id=desListID)

    ####### END CARD OPERATIONS

    #######  TEAM MEMBER OPERATIONS

    def addMemberBoard(self, boardID, memberID):
        board = self.client.get_board(board_id=boardID)
        board.add_member(memberID)

    # ORGANIZATION OPERATIONS

    def getOrganization(self, organizationID):
        return self.client.get_organization(organizationID)

    def getOrganizationByName(self, organizationName):
        for organization in self.listOrganizations():
            if organization.name == "":
                return organization
        return None

    def listOrganizations(self):
        self.client.list_organizations()
        return self.client.list_organizations()

    def createOrganization(self, organizationName):
        url = "https://api.trello.com/1/organizations?displayName=" + organizationName + "&desc=" + organizationName + "&key=" + self.apiKey + "&token=" + self.token
        querystring = {}
        response = requests.request("POST", url, params=querystring)
        organizationID = str.split(response.text, ",")[0].split("\"")[3]
        return organizationID

    def addOrganizationMember(self,
                              organizationID,
                              mail,
                              memberType="normal",
                              fullName="member"):
        configuredMail = str.replace(mail, "@", "%40")
        url = "https://api.trello.com/1/organizations/" + organizationID + "/members?email=" + configuredMail + "&fullName=" + fullName + "&type=" + memberType + "&key=" + self.apiKey + "&token=" + self.token
        querystring = {}
        response = requests.request("PUT", url, params=querystring)

        data = (json.loads(response.text))
        memberID = (data["memberships"][-1]["idMember"])
        return memberID

    def removeOrganizationMember(self, organizationID, memberID):
        url = "https://api.trello.com/1/organizations/" + organizationID + "/members/" + memberID + "?key=" + self.apiKey + "&token=" + self.token
        querystring = {}
        response = requests.request("DELETE", url, params=querystring)
        return response.text

    def removeOrganization(self, organizationID):
        url = "https://api.trello.com/1/organizations/" + organizationID + "?key=" + self.apiKey + "&token=" + self.token
        querystring = {}
        response = requests.request("DELETE", url, params=querystring)
        return response.text

    def addCommendToCard(self, cardID, commendText):
        url = "https://api.trello.com/1/cards/" + cardID + "/actions/comments?text=" + commendText + "&key=" + self.apiKey + "&token=" + self.token
        querystring = {}
        response = requests.request("POST", url, params=querystring)
        return response.text
Esempio n. 9
0
class ServiceTrello(ServicesMgr):
    """
        Serivce Trello
    """

    # Boards own Lists own Cards

    def __init__(self, token=None, **kwargs):
        super(ServiceTrello, self).__init__(token, **kwargs)
        # app name
        self.app_name = DjangoThConfig.verbose_name
        # expiration
        self.expiry = "30days"
        # scope define the rights access
        self.scope = 'read,write'
        self.oauth = 'oauth1'
        self.service = 'ServiceTrello'

        base = 'https://www.trello.com'
        self.AUTH_URL = '{}/1/OAuthAuthorizeToken'.format(base)
        self.REQ_TOKEN = '{}/1/OAuthGetRequestToken'.format(base)
        self.ACC_TOKEN = '{}/1/OAuthGetAccessToken'.format(base)
        self.consumer_key = settings.TH_TRELLO_KEY['consumer_key']
        self.consumer_secret = settings.TH_TRELLO_KEY['consumer_secret']
        if token:
            token_key, token_secret = token.split('#TH#')
            try:
                self.trello_instance = TrelloClient(self.consumer_key,
                                                    self.consumer_secret,
                                                    token_key, token_secret)
            except ResourceUnavailable as e:
                us = UserService.objects.get(token=token)
                logger.error(e.msg, e.error_code)
                update_result(us.trigger_id, msg=e.msg, status=False)

    def read_data(self, **kwargs):
        """
            get the data from the service

            :param kwargs: contain keyword args : trigger_id at least
            :type kwargs: dict
        """
        trigger_id = kwargs.get('trigger_id')
        data = list()
        cache.set('th_trello_' + str(trigger_id), data)
        return data

    def save_data(self, trigger_id, **data):
        """
            let's save the data

            :param trigger_id: trigger ID from which to save data
            :param data: the data to check to be used and save
            :type trigger_id: int
            :type data:  dict
            :return: the status of the save statement
            :rtype: boolean
        """
        from th_trello.models import Trello

        data['output_format'] = 'md'
        title, content = super(ServiceTrello,
                               self).save_data(trigger_id, **data)

        if len(title):
            # get the data of this trigger
            t = Trello.objects.get(trigger_id=trigger_id)
            # footer of the card
            footer = self.set_card_footer(data, t)
            content += footer

            # 1 - we need to search the list and board where we will
            # store the card so ...

            # 1.a search the board_id by its name
            # by retrieving all the boards
            boards = self.trello_instance.list_boards()

            board_id = ''
            my_list = ''
            for board in boards:
                if t.board_name == board.name:
                    board_id = board.id
                    break

            if board_id:
                # 1.b search the list_id by its name
                my_board = self.trello_instance.get_board(board_id)
                lists = my_board.open_lists()
                # just get the open list ; not all the archive ones
                for list_in_board in lists:
                    # search the name of the list we set in the form
                    if t.list_name == list_in_board.name:
                        # return the (trello) list object
                        # to be able to add card at step 3
                        my_list = my_board.get_list(list_in_board.id)
                        break
                # we didnt find the list in that board
                # create it
                if my_list == '':
                    my_list = my_board.add_list(t.list_name)

            else:
                # 2 if board_id and/or list_id does not exist, create it/them
                my_board = self.trello_instance.add_board(t.board_name)
                # add the list that didnt exists and
                # return a (trello) list object
                my_list = my_board.add_list(t.list_name)

            # 3 create the card
            # create the Trello card
            my_list.add_card(title, content)

            sentence = str('trello {} created').format(data['link'])
            logger.debug(sentence)
            status = True
        else:
            sentence = "no token or link provided for trigger ID " \
                       "{}".format(trigger_id)
            update_result(trigger_id, msg=sentence, status=False)
            status = False

        return status

    @staticmethod
    def set_card_footer(data, trigger):
        """
            handle the footer of the note
        """
        footer = ''
        if data.get('link'):
            provided_by = _('Provided by')
            provided_from = _('from')
            footer_from = "<br/><br/>{} <em>{}</em> {} <a href='{}'>{}</a>"

            description = trigger.trigger.description
            footer = footer_from.format(provided_by, description,
                                        provided_from, data.get('link'),
                                        data.get('link'))

            import pypandoc
            footer = pypandoc.convert(footer, 'md', format='html')

        return footer

    def auth(self, request):
        """
            let's auth the user to the Service
            :param request: request object
            :return: callback url
            :rtype: string that contains the url to redirect after auth
        """
        request_token = super(ServiceTrello, self).auth(request)
        callback_url = self.callback_url(request)

        # URL to redirect user to, to authorize your app
        auth_url_str = '{auth_url}?oauth_token={token}'
        auth_url_str += '&scope={scope}&name={name}'
        auth_url_str += '&expiration={expiry}&oauth_callback={callback_url}'
        auth_url = auth_url_str.format(auth_url=self.AUTH_URL,
                                       token=request_token['oauth_token'],
                                       scope=self.scope,
                                       name=self.app_name,
                                       expiry=self.expiry,
                                       callback_url=callback_url)

        return auth_url

    def callback(self, request, **kwargs):
        """
            Called from the Service when the user accept to activate it
            :param request: request object
            :return: callback url
            :rtype: string , path to the template
        """
        return super(ServiceTrello, self).callback(request, **kwargs)
Esempio n. 10
0
import numpy as numpy
from datetime import date, datetime
from trello import TrelloClient
from card_plus import CardPlus

# Create connection to Trello
trello_client = TrelloClient(
    api_key = "daad4d77e580ebd5d2d522f439b07f74",
    api_secret = "c7a8b9ac48bb7074b92161f37f0ccaaf23ee8f165e234bccb86013dd0a28aa19",
    token = "00dc3572fd9d961e96966c4e2c983f196e69604f42fc9dca71f82484db9f6efd",
    token_secret = "129721ad1698d337826dcf66443f7e99"
)

# Get the board
board = trello_client.get_board("7R56bpzE")

# Get all the labels for the board
label_list = board.get_labels()

# Pull all the cards from the board using the basic Card object
card_list = board.all_cards()

# Initialise the list of the CardPlus objects which is a suclass of the base Card object that stores more data
card_plus_list = []

# Convert Card objects to CardPlus objects while adding extra data
todays_date = date.today()
for card in card_list:
  
  # Number of working days since card last updated
  last_updated_date = card.date_last_activity
Esempio n. 11
0
class EClaire(object):
    def __init__(self, credentials, boards=None, qrcode_enabled=True):
        self.trello_client = TrelloClient(api_key=credentials["public_key"],
                                          token=credentials["member_token"])

        self.boards = boards
        self.qrcode_enabled = qrcode_enabled

    def process_boards(self,
                       dry_run=False,
                       notify_fn=None,
                       notify_config=None):
        """
        Process each board in self.boards
        """

        for name, board_config in self.boards.items():
            log.info("Polling %s", name)
            processed = self.process_board(board_config, dry_run)

            if board_config.get("notify", False) and notify_fn is not None:
                for card in processed:
                    notify_fn(card, **notify_config)

    def process_board(self, board_config, dry_run=False):
        """
        Process each card in a given board
        """
        processed = []
        for card in self.fetch_cards(board_id=board_config["id"]):
            log.info('Printing card "%s"', card.name)

            pdf = generate_pdf(card=card, qrcode_enabled=self.qrcode_enabled)
            if not dry_run:
                print_card(pdf, printer_name=board_config["printer"])
            self.update_card(card, board_config)
            processed.append(card)

        return processed

    def fetch_cards(self, board_id):
        """
        Fetch all candidate cards on a board for processing
        """
        data = []
        board = self.trello_client.get_board(board_id)
        for card in board.open_cards():
            if card.labels and FILTER_LABEL in (l.name for l in card.labels):
                card.fetch_actions()
                data.append(card)

        return data

    def discover_labels(self):
        """
        Store object references for special labels
        """
        for name, config in self.boards.items():
            board = self.trello_client.get_board(config["id"])
            labels = {}
            for label in board.get_labels(limit=1000):
                if label.name in SPECIAL_LABELS:
                    labels[label.name] = label
            missing = set(SPECIAL_LABELS) - set(labels.keys())
            if missing:
                log.fatal('Board "%s" is missing the labels %s', board.name,
                          " and ".join(missing))
                log.fatal("Exiting")
                sys.exit(1)
            config["labels"] = labels

    def remove_label(self, card, label):
        """
        Remove a lable from a card.

        At the time of writing there is no way to remove a label with py-trello
        """
        self.trello_client.fetch_json("/cards/{}/idLabels/{}".format(
            card.id, label.id),
                                      http_method="DELETE")

    def update_card(self, card, board_config):
        """
        Replace PRINTME label with PRINTED
        """
        printme_label = board_config["labels"]["PRINTME"]
        printed_label = board_config["labels"]["PRINTED"]

        self.remove_label(card, printme_label)

        if printed_label not in card.labels:
            card.add_label(printed_label)

    def list_boards(self):
        """
        Fetch all board IDs from trello & print them out
        """
        for board in self.trello_client.list_boards():
            print("Board:", board.name)
            print("   ID:", board.id)
            print()
Esempio n. 12
0
class TrelloBoardTestCase(unittest.TestCase):
    """
    Tests for TrelloClient API. Note these test are in order to
    preserve dependencies, as an API integration cannot be tested
    independently.
    """
    def setUp(self):
        self._trello = TrelloClient(os.environ['TRELLO_API_KEY'],
                                    token=os.environ['TRELLO_TOKEN'])
        for b in self._trello.list_boards():
            if b.name == os.environ['TRELLO_TEST_BOARD_NAME']:
                self._board = b
                break
        try:
            self._list = self._board.open_lists()[0]
        except IndexError:
            self._list = self._board.add_list('List')

    def _add_card(self, name, description=None):
        try:
            card = self._list.add_card(name, description)
            self.assertIsNotNone(card, msg="card is None")
            self.assertIsNotNone(card.id, msg="id not provided")
            self.assertEquals(card.name, name)
            return card
        except Exception as e:
            print(str(e))
            self.fail("Caught Exception adding card")

    def test40_add_card(self):
        name = "Testing from Python - no desc"
        card = self._add_card(name)

        self.assertIsNotNone(card.closed, msg="closed not provided")
        self.assertIsNotNone(card.url, msg="url not provided")

        card2 = self._trello.get_card(card.id)
        self.assertEqual(card.name, card2.name)

    def test41_add_card(self):
        name = "Testing from Python"
        description = "Description goes here"
        card = self._add_card(name, description)

        self.assertEquals(card.description, description)
        self.assertIsNotNone(card.closed, msg="closed not provided")
        self.assertIsNotNone(card.url, msg="url not provided")
        card.fetch()
        self.assertIsNotNone(card.member_id)
        self.assertIsNotNone(card.short_id)
        self.assertIsNotNone(card.list_id)
        self.assertIsNotNone(card.comments)
        self.assertIsNotNone(card.checklists)
        self.assertIsInstance(card.create_date, datetime)

    def test42_add_card_with_comments(self):
        name = "Card with comments"
        comment = "Hello World!"
        card = self._add_card(name)
        card.comment(comment)
        card.fetch(True)

        self.assertEquals(card.description, '')
        self.assertIsNotNone(card.closed, msg="closed not provided")
        self.assertIsNotNone(card.url, msg="url not provided")
        self.assertEquals(len(card.comments), 1)
        self.assertEquals(card.comments[0]['data']['text'], comment)

    def test43_delete_checklist(self):
        name = "Card with comments"
        card = self._list.add_card(name)
        card.fetch(True)

        name = 'Checklists'
        checklist = card.add_checklist(name, ['item1', 'item2'])
        self.assertIsNotNone(checklist, msg="checklist is None")
        self.assertIsNotNone(checklist.id, msg="id not provided")
        self.assertEquals(checklist.name, name)
        checklist.delete()
        card.delete()

    def test44_attach_url_to_card(self):
        name = "Testing from Python - url"
        card = self._add_card(name)

        card.attach(name='lwn', url='http://lwn.net/')
        card.fetch()
        self.assertEquals(card.badges['attachments'], 1)
        card.delete()

    def test52_get_cards(self):
        cards = self._board.get_cards()
        self.assertEquals(len(cards), 4)

        for card in cards:
            if card.name == 'Testing from Python':
                self.assertEqual(card.description, 'Description goes here')
            elif card.name == 'Testing from Python - no desc':
                self.assertEqual(card.description, '')
            elif card.name == 'Card with comments':
                self.assertEqual(card.description, '')
            else:
                self.fail(msg='Unexpected card found')

        self.assertIsInstance(self._board.all_cards(), list)
        self.assertIsInstance(self._board.open_cards(), list)
        self.assertIsInstance(self._board.closed_cards(), list)

    def test52_add_card_set_due(self):
        name = "Testing from Python"
        description = "Description goes here"
        card = self._list.add_card(name, description)

        # Set the due date to be 3 days from now
        today = datetime.today()
        day_detla = timedelta(3)
        due_date = today + day_detla
        card.set_due(due_date)
        expected_due_date = card.due
        # Refresh the due date from cloud
        card.fetch()
        actual_due_date = card.due[:10]
        self.assertEquals(expected_due_date, actual_due_date)

    def test53_checklist(self):
        name = "Testing from Python"
        description = "Description goes here"
        card = self._list.add_card(name, description)

        name = 'Checklists'
        checklist = card.add_checklist(name, ['item1', 'item2'])
        self.assertIsNotNone(checklist, msg="checklist is None")
        self.assertIsNotNone(checklist.id, msg="id not provided")
        self.assertEquals(checklist.name, name)
        checklist.rename('Renamed')
        self.assertEquals(checklist.name, 'Renamed')

    def test54_set(self):
        name = "Testing from Python"
        description = "Description goes here"
        card = self._list.add_card('noname')
        card.set_name(name)
        card.set_description(description)
        self.assertEquals(card.name, name)
        self.assertEquals(card.description, description)

    def test60_delete_cards(self):
        cards = self._board.get_cards()
        for card in cards:
            card.delete()

    def test70_all_members(self):
        self.assertTrue(len(self._board.all_members()) > 0)

    def test71_normal_members(self):
        self.assertTrue(len(self._board.normal_members()) >= 0)

    def test72_admin_members(self):
        self.assertTrue(len(self._board.admin_members()) > 0)

    def test73_owner_members(self):
        members = self._board.owner_members()
        self.assertTrue(len(members) > 0)
        member = members[0].fetch()
        self.assertNotEqual(member.status, None)
        self.assertNotEqual(member.id, None)
        self.assertNotEqual(member.bio, None)
        self.assertNotEqual(member.url, None)
        self.assertNotEqual(member.username, None)
        self.assertNotEqual(member.full_name, None)
        self.assertNotEqual(member.initials, None)
        member2 = self._trello.get_member(member.id)
        self.assertEqual(member.username, member2.username)

    def test80_unauthorized(self):
        client = TrelloClient('a')
        self.assertRaises(Unauthorized, client.list_boards)

    def test81_resource_unavailable(self):
        self.assertRaises(ResourceUnavailable, self._trello.get_card, '0')

    def test90_get_board(self):
        board = self._trello.get_board(self._board.id)
        self.assertEqual(self._board.name, board.name)
Esempio n. 13
0
class Recent:
    """
    Class used to retrieve recent Trello updates. Uses sarumont's py-trello API wrapper lightly.
    Currently I just grab the full lump of data from the board API call. 
    
    For my use of Trello this works just fine, but if you're using it really 
    heavily I could see this using up too much memory, or the resultant xml being too big or something.
    Could improve that by specifying exactly what we want with the ?filter param, or digging into using
    the lists/cards apis more directly. However, I'm currently serving over 100 rss feeds on 
    trellorss.appspot.com with this method, so it works well enough, even if it kind of bothers me.

    """

    def __init__(self, api_key, api_private_key, token=None, board_id=None, public_board=False, all_private=False):
        self.api_key = api_key
	self.api_private_key = api_private_key
        self.token = token
        self.public_only = False
        if self.token is None:
            self.public_only = True
        self.trello = TrelloClient(self.api_key, self.api_private_key, self.token)
        self.boards = None # Lazy, so doesn't fetch until we ask for them
        self.board_id = board_id
        self.public_board = public_board
        self.all_private = all_private

        # A list of items currently supported. The user should pass in one of the keys below,
        # and we use the values when passing it to the Trello API.
        self.items = config.all_item_types


    def create_date(self, date):
        return datetime.strptime(date[:-5], '%Y-%m-%dT%H:%M:%S')

    def fetch_items(self, item_names):
        """ Fetch the specified recent activity for item_names """

        for item in item_names:
            if item not in self.items:
                raise InvalidItem("%s is not a supported item." % item)
        items = ','.join([self.items[item] for item in item_names])
        if self.all_private:
            return self._get_activity(items, None)
        else:
            return self._get_activity(items, self._get_boards())

    def _get_boards(self):
        """ Calls the list_boards() method if we haven't already """
        if self.board_id:
            self.boards = self.trello.get_board(self.board_id)
        elif self.boards is None:
            self.boards = self.trello.list_boards()
        return self.boards

    def _get_activity(self, action_filter, boards):
        """Given a action filter, returns those actions for boards from the Trello API"""
        actions = []
        if self.all_private:
            self.trello.info_for_all_boards(action_filter)
            actions.append(self.trello.all_info)
        else:
            if isinstance(boards, list) is False:
                boards = [boards]
            for board in boards:
                if board.closed is False:
                    board.fetch_actions(action_filter)
                    if len(board.actions) > 0:
                        actions.append(board.actions)
        return actions
Esempio n. 14
0
class TrelloBot:

    # targets = ["Todo", "In progress"]
    targets = ["Todo"]

    def __init__(
            self,
            conf_path="trello/trello.ini",
            process_config="config.ini"
    ):

        self.config = ConfigParser()
        self.config.read(conf_path)

        self.processor = Processor(process_config)

        self.client = TrelloClient(
            api_key=self.config["trello"]["key"],
            api_secret=self.config["trello"]["token"],
        )

        self.id = self.config["trello"]["member_id"]

        self.board = self.client.get_board(
            self.config["trello"]["board_id"]
        )
        print(self.board)

        self.lists = self.get_lists()

    def update(self):
        matched_cards = self.get_cards_with_case()

        self.process_cards_with_case(matched_cards)

    def get_lists(self):
        return [
            l
            for l in self.board.get_lists("open")
            if l.name in self.targets
        ]

    def get_all_cards(self):
        return [
            c
            for l in self.lists
            for c in l.list_cards()
        ]


    def get_cards_with_case(self):
        cards = self.get_all_cards()
        matched = [
            (card, found) for card, found in
            [(c, find_case_id(c.name)) for c in cards]
            if found
        ]

        return matched

    def get_own_comments(self, comments):
        own_comments = [
            c for c in comments
            if c["idMemberCreator"] == self.id
        ]
        return own_comments

    def is_bot_comment(self, comment):
        return Markdowner.signature in comment["data"]["text"]


    def process_cards_with_case(self, matched_list):
        for card, matched in matched_list:
            print(card, matched)
            card.fetch()
            comments = self.get_own_comments(card.fetch_comments())

            bot_comments = [c for c in comments if self.is_bot_comment(c)]

            cases = {
                m: self.processor.json_to_case(j) if j else j for m, j in
                [(m, self.processor.load_json(m)) for m in matched]
            }

            comment_text = str(CaseComment(cases, self.processor))

            if bot_comments:
                # get comment id
                comment_id = bot_comments[0]["id"]
                card.update_comment(comment_id, comment_text)
            else:
                card.comment(comment_text)

            print("------")
Esempio n. 15
0
    def post(self):
        """ Collect data from the HTML form to fill in a Trello card.

        That card will be uploaded to Suggestion Box board, on the corresponding
        list, determined by the "System" attribute given in the form.
        """
        # Get form data
        date = datetime.now()
        title = self.get_argument('title')
        area = self.get_argument('area')
        system = self.get_argument('system')
        importance = self.get_argument('importance')
        difficulty = self.get_argument('difficulty')
        user = self.get_current_user()
        description = self.get_argument('description')
        suggestion = self.get_argument('suggestion')

        client = TrelloClient(api_key=self.application.trello_api_key,
                              api_secret=self.application.trello_api_secret,
                              token=self.application.trello_token)

        # Get Suggestion Box board
        boards = client.list_boards()
        suggestion_box = None
        for b in boards:
            if b.name == 'Suggestion Box':
                suggestion_box = client.get_board(b.id)
                break

        # Get the board lists (which correspond to System in the form data) and
        # concretely get the list where the card will go
        lists = b.all_lists()
        card_list = None
        for l in lists:
            if l.name == system:
                card_list = l
                break

        # Create new card using the info from the form
        new_card = card_list.add_card(
            TITLE_TEMPLATE.format(title=title, area=area))
        new_card.set_description(
            DESCRIPTION_TEMPLATE.format(date=date.ctime(),
                                        area=area,
                                        system=system,
                                        importance=importance,
                                        difficulty=difficulty,
                                        user=user.name,
                                        description=description,
                                        suggestion=suggestion))

        # Save the information of the card in the database
        self.application.suggestions_db.create({
            'date': date.isoformat(),
            'card_id': new_card.id,
            'description': new_card.description,
            'name': new_card.name,
            'url': new_card.url,
            'archived': False
        })

        self.set_status(200)
Esempio n. 16
0
    # Подключение к БД
    conn = mysql.connector.connect(host=MYSQL_HOST,
                                   port=MYSQL_PORT,
                                   user=MYSQL_USER,
                                   password=MYSQL_SECRET,
                                   database=MYSQL_DB)

    cursor = conn.cursor()

elif config['db']['db'].strip() == 'sqlite':
    SQLITE_DB = BASE_PATH + config['sqlite']['pathtodb']
    conn = sqlite3.connect(SQLITE_DB)
    cursor = conn.cursor()
else:
    raise Exception(
        'В файле config.ini в контексте [db] не указан тип БД или указан не правильно'
    )

# Подключение к трелло
client = TrelloClient(
    api_key=TR_API_KEY,
    token=TR_TOKEN,
)

# Получение объекта доски по ее ид
BOARD = client.get_board(TR_BOARD_ID)
if BOARD.closed:
    print("Доска указання в конфигурации - закрыта")
    sys.exit(1)
BOARD_SHORT_LINK = BOARD.url
Esempio n. 17
0
from trello import TrelloClient
from pptx import Presentation
from pptx.util import Inches, Pt
from datetime import *

boardID = "bn3F6E4m" # whatever board that is, eg. https://trello.com/b/uDtSJilF/iab207
#init
client = TrelloClient(
    api_key='c75ebe201687acd0b1d4c55ec98aa42f',
    api_secret='02855a09c9756eb487c4e83b76ff5e3090ad111860b3cdbd0c5476d0b1fcd7e6',
    token='b03a2e5dd545cc1fbeebc65e520aafaa0faf6a37eee4df6d3a1e21e7da16475a'
)

# get board
board = client.get_board(boardID)

# tap that list
list_sections = board.list_lists()

# Generate Presentation
prs = Presentation()
title_slide_layout = prs.slide_layouts[0]
slide = prs.slides.add_slide(title_slide_layout)

left = top = width = height = Inches(1)
background = slide.shapes.add_picture(r'static\background.png', 0, 0)

title = slide.shapes.title
subtitle = slide.placeholders[1]

title.text = "QUT MOTORSPORT"
Esempio n. 18
0
class Trello:
    def __init__(self, tconfig, config_debug=False, config_proxy=None):
        from trello import TrelloClient

        self.client = TrelloClient(api_key=tconfig['tk'],
                                   api_secret=tconfig['ts'],
                                   proxies=config_proxy)
        #if (config_proxy):
        #    self.client = TrelloClient(api_key=tconfig['tk'], api_secret=tconfig['ts'], proxies=config_proxy)
        #else:
        #    self.client = TrelloClient(api_key=config_key, api_secret=config_secret)

        self.requests_board_id = tconfig['tboard']
        self.debug = config_debug
        self.board = None
        self.labels = None
        self.motives = tconfig["requests"]

    def getAllboards(self):
        all_boards = self.client.list_boards()
        print(">>Requests pending: {}".format(all_boards))
        return all_boards

    def getRequestsBoard(self):
        self.board = self.client.get_board(self.requests_board_id)
        lists = self.board.list_lists()
        pending = lists[0]
        if (self.debug):
            pending_cards = pending.list_cards()
            print(">>Requests pending: {}".format(pending_cards))
        return pending

    def getLabels(self):
        if (self.labels is None):
            self.labels = self.board.get_labels()

        if (self.debug):
            print(">>Labels: {}".format(self.labels))

        return self.labels

    def getLabel(self, name):
        if (self.labels is None):
            self.getLabels()

        label = next((x for x in self.labels if name in x.name), None)
        if (self.debug):
            print(">>Label: {}".format(label))
        return label

    def isCardNameCreated(self, query):  #board,
        if (self.debug):
            print("Search Card Name: {}".format(query))

        boards = list()
        if (self.board is not None):
            boards.append(self.board.id)
        else:
            boards.append(self.requests_board)
        cards = self.client.search(query,
                                   partial_match=False,
                                   models=['cards'],
                                   board_ids=boards)

        if (self.debug):
            print("Card Name: {}  Matches: {}".format(query, len(cards)))
            print("Results: {}".format(cards))

        if (len(cards) > 0):
            for c in cards:
                if (c.name == query):
                    return True
            return False
        else:
            return False

    def addRequests(self, requests, woffu):
        import json

        pending = self.getRequestsBoard()

        for request in requests:
            print("Request: {} {}".format(request['$id'],
                                          request['RequestId']))
            checklist_names = list()
            checklist_states = list()
            checklist_title = 'Datos de la solicitud'
            cardname_prefix = ''
            user_name = ''
            company_id = None
            duedate = None
            labels = list()
            files = list()

            # If request status is not accepted yet, not added to Trello board
            if (request['RequestStatusId'] < 20):
                print("Obviamos request: Request status {}".format(
                    request['RequestStatusId']))
                continue

            # User name
            if (request['UserId'] is not None):
                user = woffu.getUser(request['UserId'])
                company_id = user['CompanyId']
                if (user['FirstName'] and user['LastName']):
                    user_name = str(user['FirstName']) + " " + str(
                        user['LastName'])
                    #checklist_names.append("Nombre: " + user_name)
                    #checklist_states.append(True)
                else:
                    if (user['FirstName'] or user['LastName']):
                        user_name = (str(user['FirstName']) if
                                     user['FirstName'] else "Vacío") + " " + (
                                         str(request['LastName'])
                                         if request['LastName'] else "Vacío")
                        #checklist_names.append("Nombre: " + user_name)
                        #checklist_states.append(False)
                    else:
                        user_name = 'Nombre trabajador vacío'
                        #checklist_names.append("Nombre: Vacío")
                        #checklist_states.append(False)

            # User motive
            # Comment: If we only consider selected Motives, then empty is no valid
            if (request['AgreementEventId'] is not None):
                motive = woffu.getAgreementEvent(request['AgreementEventId'])
                if (motive['Name'] in self.motives):
                    if (motive['Name'] is not None):
                        checklist_names.append("Motivo: " +
                                               str(motive['Name']))
                        checklist_states.append(True)
                        label = self.getLabel(str(motive['Name']))
                        if label is not None:
                            labels.append(label)
                        cardname_prefix = str(motive['Name']) + ': '
                else:
                    continue
#                else:
#                    cardname_prefix = 'Motivo vacío: '
#                    checklist_names.append("Motivo: Vacío")
#                    checklist_states.append(False)
#            else:
#                cardname_prefix = 'Motivo vacío: '
#                checklist_names.append("Motivo: Vacío")
#                checklist_states.append(False)

# Generate Card Name
            card_name = ("[" + str(request['RequestId']) + "] [" +
                         str(woffu.getCompanyName(company_id)) + "] " +
                         cardname_prefix + user_name)
            if (self.isCardNameCreated(card_name)):
                continue

            # Start date
            if (request['StartDate'] is not None):
                checklist_names.append(
                    "Fecha Inicio: " +
                    str(helper.getDateFormat(request['StartDate'])))
                checklist_states.append(True)
            else:
                checklist_names.append("Fecha Inicio: Vacío")
                checklist_states.append(False)

            # End date
            if (request['EndDate'] is not None):
                checklist_names.append(
                    "Fecha Fin: " +
                    str(helper.getDateFormat(request['EndDate'])))
                checklist_states.append(True)
            else:
                checklist_names.append("Fecha Fin: Vacío")
                checklist_states.append(False)

            # Comments = Description
            if (request['QuickDescription'] is not None):
                checklist_names.append("Comentarios: " +
                                       str(request['QuickDescription']))
                checklist_states.append(True)
            else:
                checklist_names.append("Comentarios: Vacío")
                checklist_states.append(False)

            # Request document download
            # Warning: Docs is always NULL, even if request has documents
            # => Always checking
            #if (True): #request['Docs'] is not None ):
            documents = woffu.getRequestsDocuments(request['RequestId'])
            if (self.debug):
                print("Documents: {} ".format(documents))
            if (documents['Documents'] is not None):
                for d in documents['Documents']:
                    file = woffu.getDocumentDownload(d["DocumentId"])
                    file['name'] = d['Name']
                    files.append(file)
                if (self.debug):
                    print("Files: {} ".format(files))
                if (files):
                    fl = list()
                    for f in files:
                        fl.append(f['name'])
                    checklist_names.append("Doc Adjunto: " + ', '.join(fl))
                    checklist_states.append(True)
                else:
                    checklist_names.append("Doc Adjunto: Vacío")
                    checklist_states.append(False)

            card = pending.add_card(name=card_name,
                                    desc=None,
                                    labels=labels,
                                    due=duedate,
                                    source=None,
                                    position=None,
                                    assign=None)
            card.add_checklist(checklist_title, checklist_names,
                               checklist_states)
            if (len(files) > 0):
                for f in files:
                    if (int(f['length']) < 10485760):
                        card.attach(name=f['name'],
                                    mimeType=f['mime'],
                                    file=f['content'])
                    else:
                        card.comment(
                            "El fichero " + f['name'] +
                            " es demasiado pesado para adjuntar en Trello :( ")
                    #try:
                    #    card.attach(name=f['name'], mimeType=f['mime'], file=f['content'])
                    #finally:
                    #
                    #    card.comment("El fichero " + f['name'] + " es demasiado pesado para adjuntar en Trello :(")
                    #return False
        #            card.attach(name=f['name'], mimeType=f['mime'], file=f['content'])

            if (self.debug):
                card.comment(str(request))

        if (self.debug):
            pending_cards = pending.list_cards()
            print(pending_cards)

    def addUserRequests(self, users, woffu=None):
        import json
        import datetime

        pending = self.getRequestsBoard()

        for user in users:
            print("User: {} {}".format(user['$id'], user['UserId']))
            labels = list()

            checklist_names = list()
            checklist_states = list()
            checklist_title = ''
            cardname_prefix = ''
            duedate = None

            if (user['Active'] is False):
                continue

            # ID
            if (user['UserId'] is not None):
                checklist_names.append("ID: " + str(user['UserId']))
                checklist_states.append(True)
            else:
                checklist_names.append("ID: Vacío")
                checklist_states.append(False)

            # User name
            if (user['FirstName'] and user['LastName']):
                checklist_names.append("Nombre: " + str(user['FirstName']) +
                                       " " + str(user['LastName']))
                checklist_states.append(True)
            else:
                if (user['FirstName'] or user['LastName']):
                    checklist_names.append("Nombre: " + (str(
                        user['FirstName']) if user['FirstName'] else "Vacío") +
                                           " " +
                                           (str(user['LastName'])
                                            if user['LastName'] else "Vacío"))
                    checklist_states.append(False)
                else:
                    checklist_names.append("Nombre: Vacío")
                    checklist_states.append(False)

            # NIN: DNI
            if (user['NIN'] is not None):
                checklist_names.append("DNI: " + str(user['NIN']))
                checklist_states.append(True)
            else:
                checklist_names.append("DNI: Vacío")
                checklist_states.append(False)

            # SSN: NAF
            if (user['SSN'] is not None):
                checklist_names.append("NSS: " + str(user['SSN']))
                checklist_states.append(True)
            else:
                checklist_names.append("NSS: Vacío")
                checklist_states.append(False)

            # Birthday
            if (user['Birthday'] is not None):
                checklist_names.append(
                    "Fecha de Nacimiento: " +
                    str(helper.getDateFormat(user['Birthday'])))
                checklist_states.append(True)
            else:
                checklist_names.append("Fecha de Nacimiento: Vacío")
                checklist_states.append(False)

            # Start Date
            if (user['EmployeeStartDate'] is not None):
                checklist_names.append(
                    "Fecha Inicio: " +
                    str(helper.getDateFormat(user['EmployeeStartDate'])))
                checklist_states.append(True)
                if (datetime.datetime.strptime(user['EmployeeStartDate'],
                                               '%Y-%m-%dT%H:%M:%S.%f') >
                        datetime.datetime.now()):
                    #                    label = self.getLabel("ALTA TRABAJADOR")
                    #                    if label is not None:
                    #                        labels.append(label)
                    duedate = user['EmployeeStartDate']
                    #                    if (duedate is not None):
                    #                        checklist_title = "Checklist Alta y Baja Trabajador"
                    #                        cardname_prefix = "Alta y Baja: "
                    #                    else:
                    checklist_title = "Checklist Alta Trabajador"
                    cardname_prefix = "Alta usuario: "
                elif (user['EmployeeEndDate'] is None):
                    cardname_prefix = "Alta usuario: "
            else:
                checklist_names.append("Fecha Inicio: Vacío")
                checklist_states.append(False)

            # End date
            if (user['EmployeeEndDate'] is not None):
                checklist_names.append(
                    "Fecha Fin: " +
                    str(helper.getDateFormat(user['EmployeeEndDate'])))
                checklist_states.append(True)
                #                label = self.getLabel("BAJA TRABAJADOR")
                #                if label is not None:
                #                    labels.append(label)
                if (duedate is not None):
                    if (datetime.datetime.strptime(user['EmployeeStartDate'],
                                                   '%Y-%m-%dT%H:%M:%S.%f') >
                            datetime.datetime.now()):
                        checklist_title = "Checklist Alta y Baja Trabajador"
                        cardname_prefix = "Alta usuario: "
                    else:
                        duedate = user['EmployeeEndDate']
                        checklist_title = "Checklist Baja Trabajador"
                        cardname_prefix = "Baja usuario: "
                else:
                    duedate = user['EmployeeEndDate']
                    checklist_title = "Checklist Baja Trabajador"
                    cardname_prefix = "Baja usuario: "
#            else:
#                checklist_names.append("Fecha Fin: Vacío")
#                checklist_states.append(False)

# Generate Card name
            card_name = ("[" + str(user['UserId']) + "] [" +
                         str(woffu.getCompanyName(user['CompanyId'])) + "] " +
                         cardname_prefix + str(user['FirstName']) + " " +
                         str(user['LastName']))
            if (self.isCardNameCreated(card_name)):
                continue

            if (cardname_prefix is None):
                continue

            # Job Title
            if (user['JobTitleId'] is not None):
                jobtitle = woffu.getJobTitle(user['JobTitleId'])
                if (jobtitle['Name'] is not None):
                    checklist_names.append("Cargo: " + str(jobtitle['Name']))
                    checklist_states.append(True)
                else:
                    checklist_names.append("Cargo: Vacío")
                    checklist_states.append(False)
            else:
                checklist_names.append("Cargo: Vacío")
                checklist_states.append(False)

            # Department
            if (user['DepartmentId'] is not None):
                department = woffu.getDepartment(user['DepartmentId'])
                if (department['Name'] is not None):
                    checklist_names.append("Departamento: " +
                                           str(department['Name']))
                    checklist_states.append(True)
                else:
                    checklist_names.append("Departamento: Vacío")
                    checklist_states.append(False)
            else:
                checklist_names.append("Departamento: Vacío")
                checklist_states.append(False)

            # Office
            if (user['OfficeId'] is not None):
                office = woffu.getOffice(user['OfficeId'])
                if (office['Name'] is not None):
                    checklist_names.append("Centro de Trabajo: " +
                                           str(office['Name']))
                    checklist_states.append(True)
                else:
                    checklist_names.append("Centro de Trabajo: Vacío")
                    checklist_states.append(False)
            else:
                checklist_names.append("Centro de Trabajo: Vacío")
                checklist_states.append(False)

#            # Bank account: avoided
#            if (None is not None ):
#                checklist_names.append("Cuenta Bancaria: " + str(user['JobTitleId']))
#                checklist_states.append(True)
#            else:
#                checklist_names.append("Cuenta Bancaria: Vacío")
#                checklist_states.append(False)
#
#            # Address: avoided
#            if (None is not None ):
#                checklist_names.append("Dirección Postal: " + str(user['JobTitleId']))
#                checklist_states.append(True)
#            else:
#                checklist_names.append("Dirección Postal: Vacío")
#                checklist_states.append(False)

# E-mail
            if (user['Email'] is not None):
                checklist_names.append("E-mail: " + str(user['Email']))
                checklist_states.append(True)
            else:
                checklist_names.append("E-mail: Vacío")
                checklist_states.append(False)

            # Responsable
            if (user['ResponsibleUserId'] is not None):
                responsible = woffu.getUser(user['ResponsibleUserId'])
                if (responsible['FirstName'] is not None):
                    checklist_names.append("Responsable: " +
                                           str(responsible['FirstName'] + " " +
                                               responsible['LastName']))
                    checklist_states.append(True)
                else:
                    checklist_names.append("Responsable: Vacío")
                    checklist_states.append(False)
            else:
                checklist_names.append("Responsable: Vacío")
                checklist_states.append(False)

            # Supervisor
            if (user['AuthorizingUserId'] is not None):
                responsible = woffu.getUser(user['AuthorizingUserId'])
                if (responsible['FirstName'] is not None):
                    checklist_names.append("Supervisor: " +
                                           str(responsible['FirstName'] + " " +
                                               responsible['LastName']))
                    checklist_states.append(True)
                else:
                    checklist_names.append("Supervisor: Vacío")
                    checklist_states.append(False)
            else:
                checklist_names.append("Supervisor: Vacío")
                checklist_states.append(False)

            # Attributes
            user_attributes = woffu.getUserAttributes(user['UserId'])
            if (user_attributes):
                #checklist_names.append("Atributos: " + str(responsible['FirstName'] + " " + responsible['LastName']))
                #checklist_states.append(True)
                for s in user_attributes:
                    checklist_names.append(
                        s['Name'] + ": " +
                        str(s['Value'] if s['Value'] is not None else 'Vacío'))
                    checklist_states.append(
                        True if s['Value'] is not None else False)
            else:
                checklist_names.append(
                    "Atributos (telf, dirección, etc): Vacío")
                checklist_states.append(False)

            # Skills
            user_skills = woffu.getUserSkills(user['UserId'])
            if (user_skills):
                #checklist_names.append("Habilidades: " + str(responsible['FirstName'] + " " + responsible['LastName']))
                #checklist_names.append("Habilidades: Sí que tiene :)")
                #checklist_states.append(True)
                for s in user_skills:
                    checklist_names.append(
                        s['Name'] + ": " +
                        str(s['Value'] if s['Value'] is not None else 'Vacío'))
                    checklist_states.append(True)

            else:
                checklist_names.append("Habilidades: Vacío")
                checklist_states.append(False)

#            # Salary
#            if (None is not None ):
#                checklist_names.append("Salario: " + str(user['Email']))
#                checklist_states.append(True)
#            else:
#                checklist_names.append("Salario: Vacío")
#                checklist_states.append(False)

# Schedule
            if ((user['ScheduleId'] is not None) or
                (user['InheredScheduleId'] is not None)):  #InheredScheduleId?
                schedule_id = (user['ScheduleId'] if user['ScheduleId']
                               is not None else user['InheredScheduleId'])
                schedule = woffu.getSchedule(schedule_id)
                if (schedule['Name'] is not None):  #'TimeFrame'
                    checklist_names.append("Horario: " + str(schedule['Name']))
                    checklist_states.append(True)
                else:
                    checklist_names.append("Horario: Vacío")
                    checklist_states.append(False)
            else:
                checklist_names.append("Horario: Vacío")
                checklist_states.append(False)

            user_contract = woffu.getUserContract(user['UserId'])
            # User contract
            if (user_contract):
                checklist_names.append("Tipo Contrato: " +
                                       str(user_contract["ContractTypeName"].
                                           split("_ContractType_", 1)[1]))
                checklist_states.append(True)
                checklist_names.append(
                    "Modalidad: " +
                    str(user_contract["ContractModalityName"].split(
                        "_ContractModality_", 1)[1]))
                checklist_states.append(True)
            else:
                checklist_names.append("Tipo Contrato: Vacío")
                checklist_states.append(False)
                checklist_names.append("Modalidad: Vacío")
                checklist_states.append(False)

            card = pending.add_card(name=card_name,
                                    desc=None,
                                    labels=labels,
                                    due=duedate,
                                    source=None,
                                    position=None,
                                    assign=None)
            card.add_checklist(checklist_title, checklist_names,
                               checklist_states)
            if (self.debug):
                card.comment(str(user))
                if (user_attributes):
                    card.comment(str(user_attributes))
                if (user_skills):
                    card.comment(str(user_skills))

        if (self.debug):
            pending_cards = pending.list_cards()
            print(pending_cards)
DEBUG = str2bool(os.getenv('DEBUG', ''))
TRELLO_APP_KEY = os.getenv('TRELLO_APP_KEY')
TRELLO_SECRET = os.getenv('TRELLO_SECRET')
GITHUB_TOKEN = os.getenv('GITHUB_ACCESS_TOKEN')
LIST_TONIGHT = "Tonight's Pitches"

client = TrelloClient(
    api_key=TRELLO_APP_KEY,
    api_secret=TRELLO_SECRET,
)

board_url = 'https://trello.com/b/EVvNEGK5/hacknight-projects'
m = re.search('^https://trello.com/b/(?P<board_id>.+?)(?:/.*)?$', board_url)
board_id = m.group('board_id')

board = client.get_board(board_id)
lists = board.get_lists('open')
[pitch_list] = [l for l in lists if l.name == LIST_TONIGHT]
cards = pitch_list.list_cards()

def utc_to_local(utc_dt):
    local_dt = utc_dt.replace(tzinfo=pytz.utc).astimezone(LOCAL_TZ)
    return LOCAL_TZ.normalize(local_dt)

def last_hacknight(date):
    date = utc_to_local(date)
    DAYS_OF_WEEK = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
    offset = (date.weekday() - DAYS_OF_WEEK.index('Tue')) % 7
    # If before 5pm, assume we're working on last week
    if offset == 0 and date.time() < datetime.time(17, 0):
        offset += 7
def build_file():
    client = TrelloClient(**trello_creds.CREDS)
    sales_board = client.get_board(dsa_config.SALES_BOARD_ID)
    moves_list_dict = get_moves_list_dict(sales_board)
    pickle.dump(moves_list_dict, open("moves_list_dict.p","wb"))
    pp.pprint(moves_list_dict)
Esempio n. 21
0
class TrelloList(object):
    """
    Sugar class to work with Trello Lists.
    """
    def __init__(self, board_id, list_id, api_key, token=None, **kwargs):
        """
        Validate inputs and connect to Trello API.
        Exception is thrown if input details are not correct.

        :param board_id: Trello board ID where the List is located
        :type board_id: ``str``

        :param list_id: Trello List ID itself
        :type list_id: ``str``

        :param api_key: Trello API key
        :type api_key: ``str``

        :param token: Trello API token
        :type token: ``str``
        """
        self.board_id = board_id
        self.list_id = list_id
        self.api_key = api_key
        # assume empty string '' as None
        self.token = token or None

        self.validate()

        self._client = TrelloClient(api_key=self.api_key, token=self.token)
        self._list = self._client.get_board(self.board_id).get_list(
            self.list_id)

    def validate(self):
        """
        Ensure that Trello list details are correct.
        Raise an exception if validation failed.
        """
        if not self.api_key:
            raise ValueError(
                '[TrelloListSensor] "api_key" config value is required!')
        assert isinstance(self.api_key, six.string_types)

        if self.token:
            assert isinstance(self.token, six.string_types)

        if not self.board_id:
            raise ValueError(
                '[TrelloListSensor]: "board_id" config value is required!')
        assert isinstance(self.board_id, six.string_types)

        if not self.list_id:
            raise ValueError(
                '[TrelloListSensor]: "list_id" config value is required!')
        assert isinstance(self.list_id, six.string_types)

    @property
    def key_name(self):
        """
        Generate unique key name for built-in storage based on config values.

        :rtype: ``str``
        """
        return '{}.{}.date'.format(self.board_id, self.list_id)

    def fetch_actions(self, filter=None, since=None):
        """
        Fetch actions for Trello List with possibility to specify filters.
        Example API request:
        https://api.trello.com/1/lists/{list_id}/actions?filter=createCard&since=2015-09-14T21:45:56.850Z&key={key_id}&token={token_id}

        :param filter: Action types to filter, separated by comma or as a sequence.
        :type filter: ``str`` or ``list``

        :param since: Filter actions since specified date.
        :type since: ``str``

        :return: Events occurred in Trello list.
        :rtype: ``list`` of ``dict``
        """
        return self._client.fetch_json('/lists/' + self._list.id + '/actions',
                                       query_params={
                                           'filter': filter,
                                           'since': since,
                                       })
Esempio n. 22
0
class Command(BaseCommand):
    def __init__(self):

        super().__init__()
        self.trello_client = TrelloClient(settings.TRELLO_API_KEY,
                                          settings.TRELLO_API_TOKEN)
        self.github_client = Github(
            settings.GITHUB_TOKEN).get_organization('bluevine-dev')

        repos = self.github_client.get_repos()
        unmerged_pull_requests = []
        for repo in repos:
            unmerged_pull_requests += [
                pr for pr in repo.get_pulls() if not pr.merged_at
            ]

        self.unmerged_pull_requests = {
            pr.html_url: pr
            for pr in unmerged_pull_requests
        }

    def add_arguments(self, parser):  # pylint: disable=no-self-use
        """ Add extra arguments """

        super().add_arguments(parser)
        parser.add_argument('--csv',
                            action='store_true',
                            default=False,
                            help='attach a csv to the generated email')
        parser.add_argument('--user',
                            action='store',
                            help='run command for specified user')

    def handle(self, *args, **options):
        """ Run command """

        username = options.get('user')
        if username:
            users = User.objects.filter(username=username)
        else:
            users = User.objects.filter(role='TL')

        # generate unmerged pull request email to all desired users
        for user in users:
            member_id = self.trello_client.get_member(user.email).id
            data = self._get_unmerged_pull_requests(member_id)
            attachment = None
            if data and options['csv']:
                attachment = self.create_pull_requests_csv(data, member_id)
                logger.info(f'attachment {attachment} was created')

            self.send_unmerged_pull_requests_data(
                data=data,
                recipients=['*****@*****.**'],
                attachment=attachment)

    def _get_unmerged_pull_requests(self, member_id):
        """ Returns all unmerged pull requests related to cards """

        boards = self.trello_client.list_boards(board_filter='open')
        pull_requests_per_board = []
        for board in boards:
            cards = board.get_cards(card_filter='open')

            # get only member cards
            cards = [card for card in cards if member_id in card.member_id]
            pull_requests_per_card = []
            for card in cards:
                attachments = card.get_attachments()
                pr_attachments = [
                    attachment for attachment in attachments
                    if all(s in attachment.url for s in ['github.com', 'pull'])
                ]
                # check for unmerged pull request in card
                unmerged_pull_requests = []
                for pr_attachment in pr_attachments:
                    if pr_attachment.url in self.unmerged_pull_requests:
                        pull_request_data = {
                            'name': pr_attachment.name,
                            "url": pr_attachment.url,
                        }

                        unmerged_pull_requests.append(pull_request_data)
                if unmerged_pull_requests:
                    card_data = {
                        'name': card.name,
                        'url': card.url,
                        'pull_requests': unmerged_pull_requests
                    }
                    pull_requests_per_card.append(card_data)

            if pull_requests_per_card:
                board_data = {
                    'name': board.name,
                    'cards': pull_requests_per_card
                }
                pull_requests_per_board.append(board_data)

        return pull_requests_per_board

    @staticmethod
    def send_unmerged_pull_requests_data(data, recipients, attachment=None):
        """ Sends an email according to given data """

        html_content = Command.create_email_template(data)
        email_message = EmailMessage(
            subject='Trello Manager - Unmerged Pull Requests',
            body=html_content,
            from_email=settings.EMAIL_HOST_USER,
            to=recipients)
        email_message.content_subtype = 'html'
        if attachment:
            email_message.attach_file(attachment)
        email_message.send()

        logger.info(f'Email was sent to {recipients}')

    @staticmethod
    def create_pull_requests_csv(data, member_id):
        """ create a temporary csv file """

        import os, tempfile, csv
        from datetime import datetime

        now = datetime.now().strftime("%m_%d_%Y__%H%M%S")
        file_path = os.path.join(
            tempfile.gettempdir(),
            f'unmerged_pull_request_{member_id}_{now}.csv')
        with open(file_path, 'w') as csv_file:
            headers = [
                'board name', 'card name', 'card url', 'pull request name',
                'pull request url'
            ]
            writer = csv.writer(csv_file)
            writer.writerow(headers)
            for board in data:
                cards = board['cards']
                for card in cards:
                    pull_requests = card['pull_requests']
                    for pull_request in pull_requests:
                        writer.writerow([
                            board['name'], card['name'], card['url'],
                            pull_request['name'], pull_request['url']
                        ])

        return file_path

    @staticmethod
    def fetch_data_from_pull_request_url(pull_request_url):
        """ Parses and returns pull request data from a pull request url """

        split_url = pull_request_url.split("/")
        owner = split_url[3]
        repo = split_url[4]
        number = int(split_url[-1])

        return owner, repo, number

    def _fetch_cards_by_member(self, member_id):
        """ Fetches all the cards for this member """

        cards = self.trello_client.fetch_json('/members/' + member_id +
                                              '/cards',
                                              query_params={
                                                  'filter': 'visible',
                                                  'fields': 'name,idBoard,url',
                                                  'attachments': 'true'
                                              })
        return sorted(cards, key=lambda card: card['idBoard'])

    def _get_board_name_by_id(self, board_id):
        """ Returns the name of the board """

        if board_id not in self.boards_names:
            self.boards_names[board_id] = self.trello_client.get_board(
                board_id).name

        return self.boards_names[board_id]

    def _get_pull_request_by_url(self, pull_request_url):

        owner, repo, number = self.fetch_data_from_pull_request_url(
            pull_request_url)
        return self.github_client.get_repo(repo).get_pull(int(number))

    @staticmethod
    def create_email_template(data):

        email_template = Template(EMAIL_TEMPLATE)
        return email_template.render(Context({'boards': data}))
Esempio n. 23
0
def trelloinit(config):
    trelloconfig = config["trello"]
    client = TrelloClient(api_key=trelloconfig["api_key"],
                          api_secret=trelloconfig["api_secret"])
    return (client, client.get_board(trelloconfig["board_id"]))
Esempio n. 24
0
import csv
from trello import TrelloClient

# Put here your credentials
client = TrelloClient(api_key='API_KEY', token='TOKEN')


def get_label(labels, label_name):
    return next(filter(lambda label: label.name == label_name, labels))


# Put here your board id
board = client.get_board("BOARD_ID")

# Discover list
# for list in board.list_lists():
#     print(list.name + ": " + list.id)

board_labels = board.get_labels()

# Put here columns definition
todo_list = board.get_list("7d3895565ecd152b7d30d61e")
doing_list = board.get_list("4d189358d5f34a6eb0f41c8a")
done_list = board.get_list("2d08934c44d37b268a8a1ecd")

# Read file
with open('sample.csv') as csv_file:
    csv_dict = csv.DictReader(csv_file)

    for row in csv_dict:
Esempio n. 25
0
def getTableros(filtro=""):
    filtroPasado = filtro
    tableros = client.list_boards(board_filter=filtroPasado)
    lista = []
    
    registros = [(tn.name, tn.id) for tn in tableros]
    for f in registros:
        campos = ['nombre_tablero', 'id_tablero']
        convertir = dict(zip(campos, f))
        lista.append(convertir)
    tablerosDevolver = json.dumps(lista)
    return tablerosDevolver

# Obtener un tablero por su ID
tablero = client.get_board('57581f7d6a945e2f6630a793')
print(tablero)

# Obtener todas las listas de un tablero
print( tablero.all_lists() )

# Obtener de un tablero una lista o columna por su ID
lista = tablero.get_list('57582109bba4b95e66dbf4e1')

# Obtener de una lista la cantidad de tarjetas que posee
lista.cardsCnt()

# Obtener todas las tarjetas que posee
lista.list_cards()

# Listar los tableros Abiertos
Esempio n. 26
0
from __future__ import print_function

# Core
import ast

# 3rd-party
from trello import TrelloClient

# Local
from auth import py_trello_auth_dict

client = TrelloClient(
    **py_trello_auth_dict
)

board = client.get_board ('hPK2DcxK')
print("About to munge {!r}".format(board.name))

input_data = [{'name': 'Some Test Book',
               'desc': '''
This is _such_ a great book!  Here's a quote from it:
> Twas brillig, yo
> The slithey toves
> Were all like up in your shit
'''}]

with open('/private/tmp/wat') as inf:
    input_data += ast.literal_eval(inf.read())

lists = board.get_lists(None)
if len(lists) != 1:
Esempio n. 27
0
def main():
    parser = ArgumentParser(description='Generate a status page from a Trello '
                                        'board')
    parser.add_argument('-k', '--key', dest='key',
                        default=environ.get('TRELLO_KEY'),
                        help='Trello API key')
    parser.add_argument('-s', '--secret', dest='secret',
                        default=environ.get('TRELLO_SECRET'),
                        help='Trello API secret')
    parser.add_argument('-t', '--token', dest='token',
                        default=environ.get('TRELLO_TOKEN'),
                        help='Trello API auth token')
    parser.add_argument('-S', '--token-secret', dest='token_secret',
                        default=environ.get('TRELLO_TOKEN'),
                        help='Trello API auth token secret')
    parser.add_argument('-b', '--board-id', dest='board',
                        default=environ.get('TRELLO_BOARD_ID'),
                        help='Trello board ID')
    parser.add_argument('-T', '--custom-template', dest='template',
                        help='Custom jinja2 template to use instead of default')
    parser.add_argument('-d', '--template-data', dest='template_data',
                        help='If using --custom-template, you can provide a '
                             'YAML file to load in data that would be '
                             'available in the template the template')
    parser.add_argument('--skip-css', dest='skip_css', action='store_true',
                        help='Skip copying the default trestus.css to the '
                             'output dir.')
    parser.add_argument('output_path', help='Path to output rendered HTML to')
    args = parser.parse_args()

    client = TrelloClient(
        api_key=args.key,
        api_secret=args.secret,
        token=args.token,
        token_secret=args.token_secret)

    markdown = Markdown()
    board = client.get_board(args.board)
    labels = board.get_labels()
    service_labels = [l for l in labels if not l.name.startswith('status:')]
    service_ids = [s.id for s in service_labels]
    status_types = [l for l in labels if l not in service_labels]
    lists = board.open_lists()

    incidents = []
    panels = {}
    systems = {}

    for card_list in lists:
        cards = card_list.list_cards()
        cards.sort(key=lambda c: c.create_date, reverse=True)
        for card in cards:
            severity = None
            for label in card.labels:
                if not label.name.startswith('status:'):
                    continue

                severity = label.name.lstrip('status:').lstrip()
                if label.color == 'red':
                    break
            card.severity = severity


            card_service_labels = [l.name for l in card.labels if l.id in service_ids]
            if not card_service_labels or not card.severity:
                continue

            if card_list.name.lower() == 'fixed':
                card.closed = True
            else:
                if card.severity not in panels:
                    panels[card.severity] = []
                panels[card.severity] += card_service_labels

                for service in card_service_labels:
                    if service not in systems:
                        systems[service] = {'status': card_list.name,
                                            'severity': card.severity}

            card.html_desc = markdown(card.desc)

            # Working around a bug in latest py-trello which fails to
            # load/parse comments properly
            comments = card.fetch_comments(force=True)
            for comment in comments:
                comment['html_desc'] = markdown(comment['data']['text'])
                comment['parsed_date'] = datetime.strptime(
                    comment['date'].replace('-', '').replace(':', ''),
                    '%Y%m%dT%H%M%S.%fZ')

            card.parsed_comments = comments

            incidents.append(card)

    for label in service_labels:
        if label.name not in systems:
            systems[label.name] = {'status': 'Operational', 'severity': ''}

    if args.template_data:
        template_data = load_yaml(open(args.template_data))
    else:
        template_data = {}


    env = Environment(loader=FileSystemLoader(
        path.join(path.dirname(__file__), 'templates')))
    if args.template:
        with open(args.template) as f:
            template = env.from_string(f.read())
    else:
        template = env.get_template('trestus.html')

    with open(args.output_path, 'w+') as f:
        f.write(template.render(incidents=incidents, panels=panels,
                                systems=systems, **template_data))

    if not args.skip_css:
        css_path = path.join(path.dirname(__file__), 'templates',
                             'trestus.css')
        copy2(css_path, path.dirname(args.output_path))

    print('Status page written to {}'.format(args.output_path))
    return 0
Esempio n. 28
0
    api_key=APPKEY,
    api_secret=TOKEN
)

trello_label = input('Enter the Card Label: ')
trello_description = input('Description (optional): ')

if len(trello_label) == 0:
    print("ERROR: Please provide a Label to create the card")
    sys.exit(-1)
elif len(trello_description) == 0:
	trello_description = ""


try:
    my_board = trello.get_board(BOARD_ID)
    board_lists = my_board.all_lists()

    #print(board_lists)
    for boardList in board_lists:    
        boardList.fetch()
    #    print(boardList.name + ": " + boardList.id)

    theListID = LIST_ID
    if len(LIST_ID) == 0:
        theListID = board_lists[0].id

    trello.get_list(theListID).add_card(trello_label, trello_description)

except ResourceUnavailable as e:    
    print('ERROR: %s' % e._msg)
Esempio n. 29
0
class Trello_Client:

    def __init__(self, database=None):
        self.connection_tries = 0
        self.client = None
        self.api_key = None
        self.token = None
        if database is None:
            database = 'sent_to_cal.db'
        if not os.path.exists(database):
            open(database, "x")
        global db_proxy
        db = SqliteDatabase(database)
        db_proxy.initialize(db)
        db_proxy.create_tables([self.LoggedCard])
        logging.info("db: %s", db_proxy)

    def init(self):
        logging.info("trello_client init")
        self.login()
        # self.client = TrelloClient(config.get_client())

    def boards(self):
        return CONFIG.get_config(['TRELLO', 'boards']) or dict()

    def refresh_credentials(self):
        logging.warning("Unauthorized. Client: %s", self.client)

        print("Time to refresh credentials!")
        print("Log in to trello at https://trello.com,\
            then visit https://trello.com/app-key")

        self.api_key = input("Trello API key: ")
        CONFIG.write_config(["TRELLO", "api_key"], self.api_key)

        self.token = input("Trello token: ")
        CONFIG.write_config(["TRELLO", "token"], self.token)

        self.login_petition()

    def login_petition(self):
        self.client = TrelloClient(self.api_key, token=self.token)

    def is_logged_in(self):
        try:
            self.client.list_boards()
            return True
        except exceptions.Unauthorized:
            logging.warning("Not authorised")
        logging.warning("Not logged in")
        return False

    def login(self):
        logging.info("Trying to log in.")

        # GET API INFO
        self.api_key = CONFIG.get_api_info()
        self.token = CONFIG.get_token()
        if(self.api_key is None or self.token is None):
            self.refresh_credentials()
            return
        logging.info(
            "Trello API key and token: %s", [self.api_key, self.token])

        if self.connection_tries > 1:
            self.refresh_credentials()
            return
        self.connection_tries += 1
        logging.info("Connections tries: %s", self.connection_tries)

        self.login_petition()
        if self.is_logged_in():
            logging.info("Log in successful")
            self.connection_tries = 0
        else:
            logging.warning("Login failed.")
            self.login()

    class LoggedCard(Model):
        card_id = CharField()
        card_hash = CharField()
        datetime_added = DateField()
        session_id = CharField()

        def __string__(self):
            return (
                self.card_id, "\n",
                self.card_hash, "\n",
                self.datetime_added, "\n",
                self.session_id)

        class Meta:
            database = db_proxy

    def archive_card(self, card):
        card.set_closed(True)

    def build_checklist(self, checklists):
        checklists_out = ""
        for checklist in checklists:
            checklists_out += "\nCHECKLIST: " + checklist.name + "\n"
            for item in checklist.items:
                checklists_out += "- " + item['name'] + "\n"
        return checklists_out

    def get_checklists(self, card):
        checklists = card.fetch_checklists()
        checklists_out = self.build_checklist(checklists)
        return checklists_out

    def get_description(self, card):
        checklists = self.get_checklists(card)
        if checklists:
            return card.description + "\n" + checklists
        return card.description

    def card_hash(self, card):
        hashable = self.get_description(card)
        return hashlib.sha256(hashable.encode()).hexdigest()

# TEST ME
    def log__card(self, card_id, card_hash, datetime_added, session_id):
        self.LoggedCard.create(
            card_id=card_id,
            card_hash=card_hash,
            datetime_added=datetime_added,
            session_id=session_id)
        logging.info("Logged card_id: %s", card_id)

    def log_card(self, card, session):
        self.log__card(card.id, self.card_hash(card), datetime.now(), session)

# TEST ME
    def is__new_card(self, card_id, card_name):
        try:
            self.LoggedCard.get(self.LoggedCard.card_id == card_id)
        except DoesNotExist:
            message = "New card: %s" % card_name
            logging.info(message)
            logging.info("New card_id: %s", card_id)
            print(message)
            return True
        return False

    def is_new_card(self, card):
        return self.is__new_card(card.id, card.name)

    def get_list_cards(self, board_id, list_id, members=[]):
        logging.info(
            "Getting list %s from board %s with members %s",
            list_id, board_id, members)
        cards = self.client.get_board(board_id).get_list(list_id).list_cards()
        return filter(lambda x: x.member_id == members, cards)

# TEST ME
    def board_to_yaml(self, name, board_id):
        CONFIG.write_config(['TRELLO', 'boards', name, 'id'], board_id)

# TEST ME
    def find__board_id(self, board_name, boards):
        logging.warning("You don't seem to have a %s b, board!", board_name)
        logging.info("Available boards: %s", boards)
        for board_id, board in enumerate(boards):
            print("%s:%s" % (board_id, board))
        board_num = int(input("What is the id of your %s board?" % board_name))
        board_id = boards[board_num].id
        self.board_to_yaml(board_name, board_id)
        return board_id

    def find_board_id(self, board_name):
        boards = self.client.list_boards()
        return self.find__board_id(board_name, boards)

# TEST ME
    def get_board_id(self, board_name):
        try:
            if self.boards()[board_name]['id'] is None:
                return self.find_board_id(board_name)
            return self.boards()[board_name]['id']
        except (KeyError, exceptions.ResourceUnavailable) as e:
            logging.warning("Exception %s at get_board_id", e)
            CONFIG.get_config(['TRELLO', 'boards', board_name, 'id'])
            return self.get_board_id(board_name)

# TEST ME
    def list_to_yaml(self, board_name, list_name, list_id):
        CONFIG.write_config(
            ['TRELLO', 'boards', board_name, list_name, 'id'], list_id)

    def find_list_id(self, board_config, board_name, list_name):
        logging.warning(
            "You don't seem to have a %s list, on your this board!\
            Please select one of the following: ", list_name)
        board_id = str(board_config['id'])
        for elist_id, elist_name in enumerate(
                self.client.get_board(board_id).open_lists()):
            print("%s:%s" % (elist_id, elist_name))
        list_num = int(input("What is the id of your %s list?" % (list_name)))
        list_id = self.client.get_board(board_id).open_lists()[list_num].id
        self.list_to_yaml(board_config, board_name, list_name, list_id)
        return list_id

# TEST ME
    def get_list_id(self, board_name, list_name):
        board_config = self.boards()[board_name]
        try:
            if board_config[list_name] is None:
                return self.find_list_id(board_config, board_name, list_name)
            return self.boards()[board_name][list_name]["id"]
        except KeyError:
            CONFIG.get_config(['TRELLO', 'boards', board_name, list_name])
            return self.get_list_id(board_name, list_name)
#!/usr/bin/python3
from trello import TrelloClient
import pyperclip
import os
import constants

client = TrelloClient(
    api_key=constants.TRELLO_API_KEY,
    api_secret=constants.TRELLO_API_SECRET,
)

all_boards = client.list_boards()

con_list= client.get_board(constants.TRELLO_LEARNING_BOARD_ID).get_lists(list_filter=None)

data=str(pyperclip.paste())

print(con_list[0].add_card(data))

os.system('notify-send "New Card Added" "'+data+'"')
Esempio n. 31
0
class TaskManager():
    _client_trello = None
    _board = None
    _board_labels = None
    _config_file = ''
    _dict_label = {}

    def __init__(self, config_file):
        self._config_file = config_file
        config = ConfigParser.RawConfigParser()
        config.read(config_file)

        api_key = config.get('Management.Task', 'api.key')
        oath_token = config.get('Management.Task', 'oath.token')
        id_board = config.get('Management.Task', 'id.board')
        self._client_trello = TrelloClient(api_key, token=oath_token)
        self._board = self._client_trello.get_board(id_board)
        self._board_labels = self._board.get_labels()
        list_label = [label for label in self._board_labels if label.name != '' and label.color]
        for label in list_label:
            self._dict_label[label.name] = label

    @staticmethod
    def validate_connection():
        url_test = 'https://api.trello.com/1'
        try:
            result = requests.request('GET', url_test, timeout=5)
            return result.status_code == 200
        except ConnectionError as e:
            logger.warning("couldn't connect to trello, see error: %s" % e.message)
            return False
        except RuntimeError as e:
            logger.warning("couldn't connect to trello, timeout error: %s" % e.message)
            return False

    def refresh_list_id(self):
        dao_object = SdaTrackerDao(self._config_file)
        for a_list in self._board.all_lists():
            code_env = a_list.name
            id_list_tracker = a_list.id
            dao_object.update_list_tracker(code_env, id_list_tracker)

    def get_card_ticket(self, id_card_tracker):
        return self._client_trello.get_card(id_card_tracker) if id_card_tracker else None

    def send_ticket_card(self, dict_board_ticket):
        """Send new card or update it"""
        result_card = None
        dict_board = dict_board_ticket['dict_board']
        id_card_tracker = dict_board['id_card_tracker']
        try:
            action = None
            # get trello's card
            a_card = self.get_card_ticket(id_card_tracker)
            list_artifact = dict_board_ticket['artifacts']
            # get id_list trello
            id_list_tracker = dict_board['id_list_tracker']
            # id_ticket = card.name
            id_ticket = dict_board['id_ticket']
            # card's description
            string_json = json.dumps(list_artifact, indent=2)
            labels_artifact = self.get_labels_artifact(list_artifact)

            if a_card:
                action = "UPDATE"
                #print "update card"
                for label in a_card.labels:
                    a_card.client.fetch_json(
                        '/cards/' + a_card.id + '/idLabels/' + label.id,
                        http_method='DELETE')

                a_card.set_description(string_json)
                result_card = a_card

            else:
                action = "NEW"
                #print "new card"
                a_list = self._board.get_list(id_list_tracker)
                new_card = a_list.add_card(id_ticket, string_json)
                result_card = new_card

            result_card.add_label(self._dict_label['requested'])
            for label in labels_artifact:
                result_card.add_label(label)
            return {"result": "OK", "action": action, "result_card": result_card}
        except RuntimeError as e:
            return {"result": "ERROR", "description": e.message}

    def get_labels_artifact(self, list_artifact):
        list_label = []
        for dict_artifact in list_artifact:
            artifact = dict_artifact['artifact']
            ls = [label for label in self._board_labels if label.name == artifact]
            if len(ls) == 0:
                label = self._board.add_label(artifact, None)
                self._board_labels = self._board.get_labels()
                list_label.append(label)
            else:
                list_label.append(ls[0])
        return list_label
Esempio n. 32
0
class ServiceTrello(ServicesMgr):

    # Boards own Lists own Cards

    def __init__(self, token=None):
        super(ServiceTrello, self).__init__(token)
        # app name
        self.app_name = DjangoThConfig.verbose_name
        # expiration
        self.expiry = "30days"
        # scope define the rights access
        self.scope = 'read,write'

        base = 'https://www.trello.com'
        self.AUTH_URL = '{}/1/OAuthAuthorizeToken'.format(base)
        self.REQ_TOKEN = '{}/1/OAuthGetRequestToken'.format(base)
        self.ACC_TOKEN = '{}/1/OAuthGetAccessToken'.format(base)
        self.consumer_key = settings.TH_TRELLO['consumer_key']
        self.consumer_secret = settings.TH_TRELLO['consumer_secret']
        if token:
            token_key, token_secret = token.split('#TH#')
            self.trello_instance = TrelloClient(self.consumer_key,
                                                self.consumer_secret,
                                                token_key,
                                                token_secret)

    def read_data(self, **kwargs):
        """
            get the data from the service

            :param kwargs: contain keyword args : trigger_id at least
            :type kwargs: dict
        """
        trigger_id = kwargs['trigger_id']
        data = list()
        cache.set('th_trello_' + str(trigger_id), data)

    def process_data(self, **kwargs):
        """
            get the data from the cache
            :param kwargs: contain keyword args : trigger_id at least
            :type kwargs: dict
        """
        kw = {'cache_stack': 'th_trello',
              'trigger_id': str(kwargs['trigger_id'])}
        return super(ServiceTrello, self).process_data(**kw)

    def save_data(self, trigger_id, **data):
        """
            let's save the data

            :param trigger_id: trigger ID from which to save data
            :param data: the data to check to be used and save
            :type trigger_id: int
            :type data:  dict
            :return: the status of the save statement
            :rtype: boolean
        """
        from th_trello.models import Trello

        status = False
        kwargs = {'output_format': 'md'}
        title, content = super(ServiceTrello, self).save_data(trigger_id,
                                                              data,
                                                              **kwargs)

        if len(title):
            # get the data of this trigger
            t = Trello.objects.get(trigger_id=trigger_id)
            # footer of the card
            footer = self.set_card_footer(data, t)
            content += footer

            # 1 - we need to search the list and board where we will
            # store the card so ...

            # 1.a search the board_id by its name
            # by retreiving all the boards
            boards = self.trello_instance.list_boards()

            board_id = ''
            my_list = ''
            for board in boards:
                if t.board_name == board.name.decode('utf-8'):
                    board_id = board.id
                    break

            if board_id:
                # 1.b search the list_id by its name
                my_board = self.trello_instance.get_board(board_id)
                lists = my_board.open_lists()
                # just get the open list ; not all the archive ones
                for list_in_board in lists:
                    # search the name of the list we set in the form
                    if t.list_name == list_in_board.name.decode('utf-8'):
                        # return the (trello) list object
                        # to be able to add card at step 3
                        my_list = my_board.get_list(list_in_board.id)
                        break
                # we didnt find the list in that board
                # create it
                if my_list == '':
                    my_list = my_board.add_list(t.list_name)

            else:
                # 2 if board_id and/or list_id does not exist, create it/them
                my_board = self.trello_instance.add_board(t.board_name)
                # add the list that didnt exists and
                # return a (trello) list object
                my_list = my_board.add_list(t.list_name)

            # 3 create the card
            # create the Trello card
            my_list.add_card(title, content)

            sentance = str('trello {} created').format(data['link'])
            logger.debug(sentance)
            status = True
        else:
            sentance = "no token or link provided for trigger ID {}"
            logger.critical(sentance.format(trigger_id))
            status = False

        return status

    def set_card_footer(self, data, trigger):
        """
            handle the footer of the note
        """
        footer = ''
        if 'link' in data:
            provided_by = _('Provided by')
            provided_from = _('from')
            footer_from = "<br/><br/>{} <em>{}</em> {} <a href='{}'>{}</a>"

            description = trigger.trigger.description
            footer = footer_from.format(
                provided_by, description, provided_from,
                data['link'], data['link'])

        return footer

    def auth(self, request):
        """
            let's auth the user to the Service
        """
        request_token = super(ServiceTrello, self).auth(request)
        callback_url = self.callback_url(request, 'trello')

        # URL to redirect user to, to authorize your app
        auth_url_str = '{auth_url}?oauth_token={token}'
        auth_url_str += '&scope={scope}&name={name}'
        auth_url_str += '&expiration={expiry}&oauth_callback={callback_url}'
        auth_url = auth_url_str.format(auth_url=self.AUTH_URL,
                                       token=request_token['oauth_token'],
                                       scope=self.scope,
                                       name=self.app_name,
                                       expiry=self.expiry,
                                       callback_url=callback_url)

        return auth_url

    def callback(self, request, **kwargs):
        """
            Called from the Service when the user accept to activate it
        """
        kwargs = {'access_token': '', 'service': 'ServiceTrello',
                  'return': 'trello'}
        return super(ServiceTrello, self).callback(request, **kwargs)
Esempio n. 33
0
def get_trello_board(api_key, token, board_id):
    client = TrelloClient(api_key=api_key, token=token)

    return client.get_board(board_id)
Esempio n. 34
0
        def _trello(secrets):
            for key in ["TRELLO_TOKEN", "TRELLO_KEY", "TRELLO_BOARD_ID"]:
                if not getattr(secrets, key):
                    raise Exception("{} is not set".format(key))

            # https://github.com/sarumont/py-trello/tree/master/trello
            from trello import TrelloClient
            from trello.exceptions import ResourceUnavailable

            client = TrelloClient(
                api_key=secrets.TRELLO_KEY,
                api_secret=secrets.TRELLO_TOKEN,
            )
            board = client.get_board(secrets.TRELLO_BOARD_ID)

            # Webhook
            def set_webhook(url):
                id_model = board.id
                desc = "Demo Trello-Github Integration"
                log_transmission(
                    TRELLO, "set webhook: {}".format([url, id_model, desc]))

                # original create_hook is not used. See: https://github.com/sarumont/py-trello/pull/323
                # hook = client.create_hook(url, id_model, desc, token=secrets.TRELLO_TOKEN)
                token = secrets.TRELLO_TOKEN
                res = client.fetch_json(
                    "tokens/{}/webhooks/".format(token),
                    http_method="POST",
                    post_args={
                        "callbackURL": url,
                        "idModel": id_model,
                        "description": desc,
                    },
                )
                log("Trello response: %s" % json.dumps(res))

            def delete_webhooks():
                for hook in client.list_hooks(secrets.TRELLO_TOKEN):
                    if hook.id_model == board.id:
                        log_transmission(
                            TRELLO,
                            "delete webhook: {}".format([hook.callback_url]))
                        hook.delete()

            # Trello cards
            def card_create(name, issue_id):
                description = "https://github.com/{}/issues/{}".format(
                    secrets.GITHUB_REPO, issue_id)
                log_transmission(TRELLO,
                                 "create: {}".format([name, description]))
                card_list = board.open_lists()[0]
                card = card_list.add_card(name, description)
                return card.id

            def card_add_labels(card_id, tlabel_ids):
                log_transmission(
                    TRELLO,
                    "add labels to card#{}: {}".format(card_id, tlabel_ids))
                card = client.get_card(card_id)
                for label_id in tlabel_ids:
                    try:
                        label = client.get_label(label_id, board.id)
                    except ResourceUnavailable:
                        log("Label is deleted in trello: %s" % label_id,
                            LOG_WARNING)
                        continue
                    if label_id in card.idLabels:
                        log("Label is already in card: %s" % label)
                        continue
                    card.add_label(label)

            def card_remove_labels(card_id, tlabel_ids):
                log_transmission(
                    TRELLO, "remove labels from card#{}: {}".format(
                        card_id, tlabel_ids))
                card = client.get_card(card_id)
                for label_id in tlabel_ids:
                    label = client.get_label(label_id, board.id)
                    if label_id not in card.idLabels:
                        log("Label is already removed: %s" % label)
                        continue
                    card.remove_label(label)

            def card_add_message(card_id, message):
                log_transmission(
                    TRELLO,
                    "add message to card#{}: {}".format(card_id, message))
                card = client.get_card(card_id)
                card.comment(message)

            # Trello labels
            def label_create(name, color):
                log_transmission(TRELLO, "create label: %s" % (name))
                label = board.add_label(name, color)
                return label.id

            def label_delete(tlabel_id):
                log_transmission(TRELLO, "delete label: %s" % (tlabel_id))
                board.delete_label(tlabel_id)

            def label_update(tlabel_id, new_name, new_color):
                log_transmission(
                    TRELLO,
                    "label#{} update: {}".format(tlabel_id,
                                                 [new_name, new_color]),
                )
                res = client.fetch_json(
                    "/labels/{}".format(tlabel_id),
                    http_method="PUT",
                    post_args={
                        "id": tlabel_id,
                        "name": new_name,
                        "color": new_color
                    },
                )
                log("Trello response: {}".format(res))

            def get_labels_colors():
                return {lb.id: lb.color for lb in board.get_labels()}

            def get_all_cards():
                return [{
                    "id": card.id,
                    "idLabels": card.idLabels
                } for card in board.all_cards()]

            return AttrDict({
                "set_webhook": set_webhook,
                "delete_webhooks": delete_webhooks,
                "card_create": card_create,
                "card_add_labels": card_add_labels,
                "card_remove_labels": card_remove_labels,
                "card_add_message": card_add_message,
                "label_create": label_create,
                "label_delete": label_delete,
                "label_update": label_update,
                "get_labels_colors": get_labels_colors,
                "get_all_cards": get_all_cards,
            })
Esempio n. 35
0
def main():
    parser = ArgumentParser(description='Generate a status page from a Trello '
                            'board')
    parser.add_argument('-k',
                        '--key',
                        dest='key',
                        default=environ.get('TRELLO_KEY'),
                        help='Trello API key')
    parser.add_argument('-s',
                        '--secret',
                        dest='secret',
                        default=environ.get('TRELLO_SECRET'),
                        help='Trello API secret')
    parser.add_argument('-t',
                        '--token',
                        dest='token',
                        default=environ.get('TRELLO_TOKEN'),
                        help='Trello API auth token')
    parser.add_argument('-S',
                        '--token-secret',
                        dest='token_secret',
                        default=environ.get('TRELLO_TOKEN'),
                        help='Trello API auth token secret')
    parser.add_argument('-b',
                        '--board-id',
                        dest='board',
                        default=environ.get('TRELLO_BOARD_ID'),
                        help='Trello board ID')
    parser.add_argument(
        '-T',
        '--custom-template',
        dest='template',
        help='Custom jinja2 template to use instead of default')
    parser.add_argument('-d',
                        '--template-data',
                        dest='template_data',
                        help='If using --custom-template, you can provide a '
                        'YAML file to load in data that would be '
                        'available in the template the template')
    parser.add_argument('--skip-css',
                        dest='skip_css',
                        action='store_true',
                        help='Skip copying the default trestus.css to the '
                        'output dir.')
    parser.add_argument('output_path', help='Path to output rendered HTML to')
    args = parser.parse_args()

    client = TrelloClient(api_key=args.key,
                          api_secret=args.secret,
                          token=args.token,
                          token_secret=args.token_secret)

    markdown = Markdown()
    board = client.get_board(args.board)
    labels = board.get_labels()
    service_labels = [l for l in labels if not l.name.startswith('status:')]
    service_ids = [s.id for s in service_labels]
    status_types = [l for l in labels if l not in service_labels]
    lists = board.open_lists()

    incidents = []
    panels = {}
    systems = {}

    for card_list in lists:
        cards = card_list.list_cards()
        cards.sort(key=lambda c: c.create_date, reverse=True)
        for card in cards:
            severity = None
            for label in card.labels:
                if not label.name.startswith('status:'):
                    continue

                severity = label.name.lstrip('status:').lstrip()
                if label.color == 'red':
                    break
            card.severity = severity

            card_service_labels = [
                l.name for l in card.labels if l.id in service_ids
            ]
            if not card_service_labels or not card.severity:
                continue

            if card_list.name.lower() == 'fixed':
                card.closed = True
            else:
                if card.severity not in panels:
                    panels[card.severity] = []
                panels[card.severity] += card_service_labels

                for service in card_service_labels:
                    if service not in systems:
                        systems[service] = {
                            'status': card_list.name,
                            'severity': card.severity
                        }

            card.html_desc = markdown(card.desc)

            # Working around a bug in latest py-trello which fails to
            # load/parse comments properly
            comments = card.fetch_comments(force=True)
            for comment in comments:
                comment['html_desc'] = markdown(comment['data']['text'])
                comment['parsed_date'] = datetime.strptime(
                    comment['date'].replace('-', '').replace(':', ''),
                    '%Y%m%dT%H%M%S.%fZ')

            card.parsed_comments = comments

            incidents.append(card)

    for label in service_labels:
        if label.name not in systems:
            systems[label.name] = {'status': 'Operational', 'severity': ''}

    if args.template_data:
        template_data = load_yaml(open(args.template_data))
    else:
        template_data = {}

    env = Environment(loader=FileSystemLoader(
        path.join(path.dirname(__file__), 'templates')))
    if args.template:
        with open(args.template) as f:
            template = env.from_string(f.read())
    else:
        template = env.get_template('trestus.html')

    with open(args.output_path, 'w+') as f:
        f.write(
            template.render(incidents=incidents,
                            panels=panels,
                            systems=systems,
                            **template_data))

    if not args.skip_css:
        css_path = path.join(path.dirname(__file__), 'templates',
                             'trestus.css')
        copy2(css_path, path.dirname(args.output_path))

    print('Status page written to {}'.format(args.output_path))
    return 0
Esempio n. 36
0
    print("Please configure this program with the config file in \n\"{}\"".
          format(CONFIG_FILE))
    exit()


config = load_config()
if not config["params"]["api_key"]:
    api = toml.loads(open("api.toml").read())
    config["params"]["api_key"], config["params"]["token"] = api[
        "api_key"], api["token"]

client = TrelloClient(api_key=config["params"]["api_key"],
                      token=config["params"]["token"])

board = config["board"]
try:
    tb = client.get_board(board["id"])
except trello.exceptions.ResourceUnavailable:
    println("ERROR: Failed GET board, check that your config file is correct")
for li in config["list"]:
    tl = tb.get_list(li["id"])
    print("{}> {}".format(FORMAT_TITLE, tl.name))
    print(FORMAT_TASK, end="")
    for i, card in enumerate(tl.list_cards(), start=1):
        print("{}. {}".format(i, card.name))
    print()

END = FORMAT_RESET
if len(sys.argv) > 1:
    END = sys.argv[1]
print(END)
Esempio n. 37
0
def populate_board(url, target=None, update=False):
    '''takes a URL for a glass door posting, and creates a trello list with helpful job hunt items '''
    if target:
        auth = ret_labels(target)
        if update == True:
            auth = update_config(target)
    else:
        auth = load_config()
    client = TrelloClient(
        api_key=auth['key'],
        token=auth['token'])
    # gets board Labels
    board = client.get_board(board_id=auth['board_id'])
    link_l = client.get_label(auth['link_l'], auth['board_id'])
    desc_l = client.get_label(auth['desc_l'], auth['board_id'])
    check_l = client.get_label(auth['check_l'], auth['board_id'])
    # check URL for type
    url_clean = url.strip('https://').split('/')
    if url_clean[0] == 'www.glassdoor.com':
        url_type = '/'.join(url_clean[:2])
    if url_clean[0] == 'www.linkedin.com':
        url_type = '/'.join(url_clean[:3])
    else:
        url_type = url_clean[0]
    # use url type to call scrape function
    if url_type == 'www.glassdoor.com/job-listing':
        # scrapes GD for job info
        data = pull_data_gd(url)
    elif url_type == 'boards.greenhouse.io':
        data = pull_data_gh(url)
    elif url_type == 'jobs.lever.co':
        data = pull_data_lev(url)
    elif url_type == 'www.linkedin.com/jobs/view':
        data = pull_data_li(url)
    elif url_type == 'careers.jobscore.com':
        data = pull_data_js(url)
    else:
        print("Sorry, either {} isn't supported yet, or something unexpectedly changed\n".format(url_clean[0]))
        print("Feel free to implement and send a PR, or email: [email protected]")
        return None
    data['post_url'] = url
    list_name = data['company'] + ':\n' + data['job'] + '\n\nAdded: ' + str(datetime.now())
    j_title = data['company'] + ': ' + data['job']
    # create list object
    new_list = board.add_list(name=list_name, pos=None)
    # add cards to list object
    description = new_list.add_card(name='{} \nDetails:'.format(j_title), desc=data['desc'])
    attachCard = new_list.add_card(name='{} \nLinks:'.format(j_title))
    attachCard.attach(name=data['ap_type'], url=data['ap_url'])
    attachCard.attach(name='Original posting', url=data['post_url'])
    # attempts to build a direct search link for linkedin which targets company and department if available
    if data['dept'] != '':
        li_url = 'https://www.linkedin.com/search/results/people/?keywords=' + data['company'].replace(' ','%20') + '%20' + data['dept'].replace(' ', '%20')
        attachCard.attach(name='Linkedin search, Company + Department',
            url= li_url) 
    else:
        li_url = 'https://www.linkedin.com/search/results/people/?keywords=' + data['company'].replace(' ', '%20')
        attachCard.attach(name='Linkedin search, Company',
            url=li_url)
    goog_base = 'https://www.google.com/#safe=off&q='
    goog_company = goog_base+data['company'].replace(' ','+')
    attachCard.attach(name='Google search, Company',url=goog_company)
    gd_search_hack = 'https://www.glassdoor.com/Reviews/{}-reviews-SRCH_KE0,{}.htm'.format(data['company'], len(data['company']))
    dt = datetime.now() + timedelta(days=3)
    cl = ['Research Hiring manager [Linkedin]({})'.format(li_url), 'Research company, [glassdoor]({}), [google]({})'.format(gd_search_hack, goog_company),
          'Polish Resume [creddle](https://resume.creddle.io/)',
          'Craft Cover Letter, [Drive](https://drive.google.com)', 'Attempt to make contact on personal level [Linkedin]({})'.format(li_url),
          'Complete application [Application link]({})'.format(data['ap_url']), 'Send application',
          'Wait three days: {}'.format(str(dt.date())), 'Send follow up email']
    clCard = new_list.add_card('To Do List')
    clCard.add_checklist(title='To Do!\n\n{}'.format(j_title), items=cl)
    clCard.set_due(dt.date())
    notes_card = new_list.add_card(name='Notes')
    notes_card.comment('Added Via tgd on: {}\n Refered through {}'.format(datetime.now(), data['referer']))
    # add color coded labels to cards
    attachCard.add_label(link_l)
    description.add_label(desc_l)
    clCard.add_label(check_l)
    print('\n' + 'Success! \n\nAdded {} to you board'.format(j_title) + '\n\nCheck it out here:\nhttps://trello.com/b/{}'.format(auth['board_id'] + '\n'))
Esempio n. 38
0
class TarDriver:

    #Конструктор класса
    def __init__(
            self,
            trello_apiKey='',  #apiKey для подключения к trello
            trello_token='',  #apiToken для подключения к trello
            local_timezone='Asia/Tomsk'):

        self.API_KEY = trello_apiKey
        self.TOKEN = trello_token
        self.local_timezone = tz(local_timezone)
        self.filter_dates = []
        self.database_is_updating = False

        #Подключение к Trello
        try:
            self.trello_client = TrelloClient(
                api_key=self.API_KEY,
                token=self.TOKEN,
            )
        except Exception as err:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [ERROR] Failed to connect to Trello via API: {err}'
            )
        else:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] Connection to Trello established successful'
            )

        #Создание файла БД и таблиц в БД
        try:
            self.db = TinyDB('tar_database.json')
            #self.db.drop_tables()      !!!!!!!!!!!!!!!!!!!!!

            self.report = self.db.table('report')
            self.worktime = self.db.table('worktime')
            self.local_boards = self.db.table('boards')
            self.local_lists = self.db.table('lists')
            self.local_cards = self.db.table('cards')
            self.local_persons = self.db.table('persons')
            self.local_cards_has_persons = self.db.table('cards_has_persons')

        except Exception as err:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [ERROR] Failed to setup tar_database: {err}'
            )
        else:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] tar_database created'
            )

        self.basic_template = [{
            0:
            'Перечень Задач',
            'cards': [
                'П3 - Описание автоматизируемых функций',
                'П5 - Описание информационного обеспечения',
                'В1 - Описание входных сигналов и данных',
                'В2 - Описание выходных сигналов (сообщений)',
                'ПА - Описание программного обеспечения',
                'ПБ - Описание алгоритма', 'П6 - Описание информационной базы',
                'С9 - Чертеж форм (видеокадра)', 'И3 - Руководство оператора',
                'И3 - Руководство программиста',
                'И4 - Инструкция по ведению БД',
                'ПМИ - Программа и методика испытаний',
                'ПО ПЛК - Программа контроллера',
                'ПО Панели - Программа панели оператора',
                'ПО АРМ - Программа рабочего места оператора',
                'ПО БД - База данных', 'Ежедневная планерка',
                'Планирование цели (спринт)',
                'Анализ завершения цели (спринта)'
            ]
        }, {
            1: 'Комплекс Задач',
            'cards': []
        }, {
            2: 'В Работе',
            'cards': []
        }, {
            3: 'Согласование выполнения',
            'cards': []
        }, {
            4: 'Завершены',
            'cards': []
        }, {
            5: 'Отменены',
            'cards': []
        }]

        self.db.drop_table('worktime')
        self.worktime.insert({
            'work_day_starts': '09:00:00',
            'work_day_ends': '18:00:00',
            'work_day_duration': '09:00:00',
            'lunch_hours_starts': '13:00:00',
            'lunch_hours_ends': '14:00:00',
            'lunch_duration': '01:00:00',
            'day_work_hours': '08:00:00',
            'work_days': '5',
            'week_work_hours': '1 day, 16:00:00',
            'update_period': '00:02:00'
        })

    def add_board(self, board):
        #Добавление новой доски в БД
        try:
            self.local_boards.insert({
                'board_id':
                board.id,
                'board_name':
                board.name,
                'board_description':
                board.description,
                'board_last_modified':
                str(board.date_last_activity)
            })

            for list_ in board.list_lists():
                self.local_lists.insert({
                    'list_id':
                    list_.id,
                    'list_name':
                    list_.name,
                    'list_last_modified':
                    str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
                    'board_id':
                    board.id,
                    'board_name':
                    board.name
                })

                for card in list_.list_cards():

                    self.local_cards.insert({
                        'card_id': card.id,
                        'card_name': card.name,
                        'list_id': list_.id,
                        'list_name': list_.name,
                        'board_id': board.id,
                        'board_name': board.name
                    })

                    if len(card.member_id) > 0:
                        for person in self.team:
                            if person.id in card.member_id:
                                query_result = self.local_persons.get(
                                    where('person_id') == str(person.id))
                                self.local_cards_has_persons.insert({
                                    'card_id':
                                    card.id,
                                    'card_name':
                                    card.name,
                                    'person_id':
                                    person.id,
                                    'person_name':
                                    query_result['person_fullname'],
                                    'list_id':
                                    list_.id,
                                    'list_name':
                                    list_.name,
                                    'board_id':
                                    board.id,
                                    'board_name':
                                    board.name
                                })

        except Exception as err:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [ERROR] Failed to add "{board.name}": {err}'
            )
        else:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] "{board.name}" added successful'
            )

    def delete_board(self, board_id, board_name=''):
        #Удаление доски из БД
        try:
            #Удаляем записи из таблицы local_cards_has_persons
            self.local_cards_has_persons.remove(
                where('board_id') == str(board_id))
            #Удаляем записи из таблицы local_cards
            self.local_cards.remove(where('board_id') == str(board_id))
            #Удаляем записи из таблицы local_lists
            self.local_lists.remove(where('board_id') == str(board_id))
            #Удаляем записи из таблицы local_boards
            self.local_boards.remove(where('board_id') == str(board_id))
        except Exception as err:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [ERROR] Failed to delete {board_id}: {err}'
            )
        else:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] {board_id} deleted successful'
            )

    def update_board(self, board):
        #Обновление доски в БД
        datetime_format = "%Y-%m-%d %H:%M:%S.%f%z"

        try:
            query_result = self.local_boards.get(
                where('board_id') == str(board.id))

        except Exception as err:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] Updating "{board.name}"...{err}'
            )
            self.delete_board(board_id=board.id, board_name=board.name)
            self.add_board(board=board)
        else:
            board_date_last_activity = self.unify_time(
                datetime.strptime(query_result['board_last_modified'],
                                  datetime_format))

            if self.unify_time(
                    board.date_last_activity) > board_date_last_activity:
                print(
                    f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] Updating "{board.name}"...'
                )
                self.delete_board(board_id=board.id, board_name=board.name)
                self.add_board(board=board)

    def fill_main_boards(self):
        #Заполнение таблиц local_boards, local_lists, local_cards
        print(
            f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] Filling "local_boards / local_lists / local_cards" tables...'
        )
        try:
            for board in self.trello_client.list_boards():
                self.add_board(board=board)
        except Exception as err:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [ERROR] Failed to fill "local_boards / local_lists / local_cards" tables: {err}'
            )
        else:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] "local_boards / local_lists / local_cards" tables filled successful'
            )

    def fill_persons(self, team_board_name='КАДРЫ'):
        #Заполнение таблицы local_persons
        try:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] Filling "local_persons" table...'
            )
            for board in self.trello_client.list_boards():
                if board.name == team_board_name:
                    self.team = board.get_members(filters='all')
                    for list_ in board.list_lists():
                        for card in list_.list_cards():
                            if len(card.member_id) > 0:
                                for person in self.team:
                                    if person.id in card.member_id:
                                        self.local_persons.insert({
                                            'person_id':
                                            person.id,
                                            'person_username':
                                            person.username,
                                            'person_fullname':
                                            card.name,
                                            'status':
                                            list_.name,
                                            'last_modified':
                                            str(datetime.now().strftime(
                                                "%Y-%m-%d %H:%M:%S"))
                                        })
                    break
        except Exception as err:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [ERROR] Failed to fill "local_persons" table: {err}'
            )
        else:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] "local_persons" table filled successful'
            )

    def fill_cards_has_persons(self):
        #Заполнение таблицы cards_has_persons
        try:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] Filling "cards_has_persons" table...'
            )
            for board in self.trello_client.list_boards():
                for list_ in board.list_lists():
                    for card in list_.list_cards():
                        if len(card.member_id) > 0:
                            for person in self.team:
                                if person.id in card.member_id:
                                    query_result = self.local_persons.get(
                                        where('person_id') == str(person.id))
                                    self.local_cards_has_persons.insert({
                                        'card_id':
                                        card.id,
                                        'card_name':
                                        card.name,
                                        'person_id':
                                        person.id,
                                        'person_name':
                                        query_result['person_fullname'],
                                        'list_id':
                                        list_.id,
                                        'list_name':
                                        list_.name,
                                        'board_id':
                                        board.id,
                                        'board_name':
                                        board.name
                                    })
        except Exception as err:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [ERROR] Failed to fill "cards_has_persons" table: {err}'
            )
        else:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] "cards_has_persons" table filled successful'
            )

    def fill_database(self):
        self.fill_persons()
        self.fill_main_boards()

    def update_database(self, update_on_change=False):

        time_format = "%H:%M:%S"

        self.db.drop_table('persons')
        self.fill_persons()

        update = True

        while update:

            self.database_is_updating = True

            update_period_time = (time.strptime(self.get_update_period(),
                                                time_format))
            update_period_seconds = timedelta(
                hours=update_period_time.tm_hour,
                minutes=update_period_time.tm_min,
                seconds=update_period_time.tm_sec).total_seconds()

            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] Checking for updates...'
            )

            trello_boards = self.trello_client.list_boards()
            local_boards = self.local_boards.all()

            if len(trello_boards) > len(
                    local_boards):  #в trello добавили доску
                #ищем какую
                tempBoards = []

                for board in local_boards:
                    tempBoards.append(board['board_id'])

                for board in trello_boards:
                    if board.id not in tempBoards:  #новая доска обнаружена
                        self.add_board(board=board)

                print(
                    f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] Checking for updates finished'
                )

            elif len(trello_boards) < len(
                    local_boards):  #в trello удалили доску
                #ищем какую
                tempBoards = []

                for board in trello_boards:
                    tempBoards.append(board.id)

                for board in local_boards:
                    if board[
                            'board_id'] not in tempBoards:  #новая доска обнаружена
                        self.delete_board(board_id=board['board_id'],
                                          board_name=board['board_name'])

                print(
                    f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] Checking for updates finished'
                )

            else:  #обновляем все доски. Новых / удаленных не обнаружено
                for board in trello_boards:
                    self.update_board(board=board)

                print(
                    f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] Checking for updates finished'
                )

                if not update_on_change:
                    time.sleep(update_period_seconds)

                    self.database_is_updating = False

    def get_persons_active_tasks(self, person_id, active_list_name='В Работе'):
        query_result = self.local_cards_has_persons.search(
            (where('person_id') == str(person_id))
            & (where('list_name') == str(active_list_name)))
        return len(query_result)

    # !!!!! Изменить чтоб читал пользователей доски, возможно вернуть board_has_persons
    def get_project_members(self, board_id):
        temp_persons = []
        board_persons = []
        query_result = self.local_cards_has_persons.search(
            where('board_id') == str(board_id))
        for result in query_result:
            if result['person_id'] not in temp_persons:
                temp_persons.append(result['person_id'])
                board_persons.append({
                    'person_id': result['person_id'],
                    'person_name': result['person_name']
                })
        return board_persons

    def get_tasks_on_board(self, board_id, list_name='В работе'):
        tasks = []
        query_result = self.local_cards.search(
            where('board_id') == str(board_id))
        for result in query_result:

            if result['list_name'] == list_name:

                query_result_ = self.local_cards_has_persons.search(
                    where('list_id') == str(result['list_id']))
                for result_ in query_result_:
                    if result_['card_name'] == result['card_name']:
                        task = {
                            'task_name': result['card_name'],
                            'task_member': result_['person_name'],
                            'card_in_work_time': result['card_in_work_time']
                        }
                        tasks.append(task)
                        break

        return tasks

    def get_lists_by_board_id(self, board_id):
        query_result = self.local_lists.search(
            (where('board_id') == str(board_id)))
        return query_result

    def get_active_tasks_by_person(self, person_id):
        query_result = self.local_cards_has_persons.search(
            (where('person_id') == str(person_id))
            & ((where('list_name') == str('В Работе'))))
        return query_result

    def get_curr_stage_percent(self, board_id, board_template):
        tasks_planned = self.local_cards.search(
            (where('board_id') == str(board_id))
            & (where('list_name') == str('Комплекс задач')))
        tasks_in_progress = self.local_cards.search(
            (where('board_id') == str(board_id))
            & (where('list_name') == str('В Работе')))
        tasks_on_hold = self.local_cards.search(
            (where('board_id') == str(board_id))
            & (where('list_name') == str('Согласование Выполнения')))
        tasks_done = self.local_cards.search(
            (where('board_id') == str(board_id))
            & (where('list_name') == str('Завершены')))

        if (len(tasks_planned) + len(tasks_in_progress) + len(tasks_on_hold) +
                len(tasks_done)) == 0:
            return 0
        else:
            return round((len(tasks_done) /
                          (len(tasks_planned) + len(tasks_in_progress) +
                           len(tasks_on_hold) + len(tasks_done))) * 100.0)

    def create_new_project(self,
                           project_template,
                           project_name='Новый проект',
                           project_description=''):
        self.trello_client.add_board(board_name=project_name,
                                     source_board=None,
                                     organization_id=None,
                                     permission_level='private',
                                     default_lists=False)

        for board in self.trello_client.list_boards():
            if board.name == project_name:
                board.set_description(desc=project_description)

                for list_ in range(len(project_template) - 1, -1, -1):
                    board.add_list(name=project_template[list_].get(list_),
                                   pos=None)

                for _list in board.list_lists():
                    for list_ in range(0, len(project_template)):
                        if _list.name == project_template[list_].get(list_):
                            for card in project_template[list_]['cards']:
                                _list.add_card(name=card,
                                               desc=None,
                                               labels=None,
                                               due="null",
                                               source=None,
                                               position=None,
                                               assign=None,
                                               keep_from_source="all")
                                print(
                                    f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG] Card {card} was added'
                                )
                            break

    def utc_to_local(self, utc_dt):
        return utc_dt.replace(tzinfo=timezone.utc,
                              microsecond=0).astimezone(tz=None)

    def set_workhours(self, workhours=['09:00:00', '18:00:00']):
        format_ = '%H:%M:%S'
        try:
            work_day_starts = datetime.strptime(workhours[0], format_).time()
            work_day_ends = datetime.strptime(workhours[1], format_).time()
        except Exception as err:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [ERROR] {err}'
            )
            pass
            #self.worktime.update({ 'work_day_starts': str(datetime.strptime('9:00:00', format_).time())})
            #self.worktime.update({ 'work_day_ends': str(datetime.strptime('18:00:00', format_).time())})
        else:
            if work_day_starts < work_day_ends:
                self.worktime.update({'work_day_starts': str(work_day_starts)})
                self.worktime.update({'work_day_ends': str(work_day_ends)})

                work_day_duration = timedelta(hours = work_day_ends.hour, minutes = work_day_ends.minute, seconds = work_day_ends.second) \
                                            - timedelta(hours = work_day_starts.hour, minutes = work_day_starts.minute, seconds = work_day_starts.second)

                self.worktime.update(
                    {'work_day_duration': str(work_day_duration)})

                self.calculate_work_hours()

    def get_workhours(self):
        return self.worktime.get(where('work_day_starts') != None)

    def set_lunch_hours(self, lunch_hours=['13:00:00', '14:00:00']):
        format_ = '%H:%M:%S'
        try:
            lunch_hours_starts = datetime.strptime(lunch_hours[0],
                                                   format_).time()
            lunch_hours_ends = datetime.strptime(lunch_hours[1],
                                                 format_).time()
        except Exception as err:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [ERROR] {err}'
            )
            pass
        else:
            if lunch_hours_starts < lunch_hours_ends:
                self.worktime.update(
                    {'lunch_hours_starts': str(lunch_hours_starts)})
                self.worktime.update(
                    {'lunch_hours_ends': str(lunch_hours_ends)})

                lunch_duration = timedelta(hours = lunch_hours_ends.hour, minutes = lunch_hours_ends.minute, seconds = lunch_hours_ends.second) \
                                            - timedelta(hours = lunch_hours_starts.hour, minutes = lunch_hours_starts.minute, seconds = lunch_hours_starts.second)

                self.worktime.update({'lunch_duration': str(lunch_duration)})

                self.calculate_work_hours()

    def get_lunch_hours(self):
        return self.worktime.get(where('lunch_hours_starts') != None)

    def calculate_work_hours(self):
        format_ = '%H:%M:%S'
        str_work_day_duration = self.worktime.get(
            where('work_day_duration') != None)['work_day_duration']
        str_lunch_duration = self.worktime.get(
            where('lunch_duration') != None)['lunch_duration']

        time_work_day_duration = datetime.strptime(str_work_day_duration,
                                                   format_).time()
        time_lunch_duration = datetime.strptime(str_lunch_duration,
                                                format_).time()

        day_work_hours = timedelta(hours = time_work_day_duration.hour, minutes = time_work_day_duration.minute, seconds = time_work_day_duration.second) \
                                            - timedelta(hours = time_lunch_duration.hour, minutes = time_lunch_duration.minute, seconds = time_lunch_duration.second)

        self.worktime.update({'day_work_hours': str(day_work_hours)})

        work_days = self.worktime.get(where('work_days') != None)['work_days']

        week_work_hours = timedelta(seconds=int(work_days) *
                                    day_work_hours.total_seconds())
        self.worktime.update({'week_work_hours': str(week_work_hours)})

    def is_integer(self, n):
        try:
            float(n)
        except ValueError:
            return False
        else:
            return float(n).is_integer()

    def set_workdays(self, workdays='5'):
        if self.is_integer(workdays):
            if (int(workdays) >= 1) and (int(workdays) <= 7):
                self.worktime.update({'work_days': str(workdays)})
        else:
            print(
                f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [ERROR] workdays not a number'
            )

    def get_workdays(self):
        try:
            return ((self.worktime.get(
                where('work_days') != None))['work_days'])
        except:
            return '--:--'

    def set_database_update_period(self, update_period='01:00:00'):
        format_ = '%H:%M:%S'
        try:
            update_period = datetime.strptime(update_period, format_).time()
        except Exception as err:
            pass
        else:
            self.worktime.update({'update_period': str(update_period)})

    def get_update_period(self):
        try:
            return ((self.worktime.get(
                where('update_period') != None))['update_period'])
        except:
            return '--:--'

    def unify_time(self, datetime):
        return datetime.astimezone(self.local_timezone).replace(microsecond=0)

    def filter_work_hours(self, start_date, end_date):
        time_format = "%H:%M:%S"

        result_time = timedelta(hours=0, minutes=0, seconds=0)
        calculated_end_time = timedelta(hours=0, minutes=0, seconds=0)
        twelve_hours_delta = timedelta(hours=12, minutes=0)
        twenty_four_hours_delta = timedelta(hours=23, minutes=59, seconds=59)

        work_day_starts = self.worktime.get(
            where('work_day_starts') != None)['work_day_starts']
        work_day_ends = self.worktime.get(
            where('work_day_ends') != None)['work_day_ends']
        lunch_starts = self.worktime.get(
            where('lunch_hours_starts') != None)['lunch_hours_starts']
        lunch_ends = self.worktime.get(
            where('lunch_hours_ends') != None)['lunch_hours_ends']
        day_work_hours = self.worktime.get(
            where('day_work_hours') != None)['day_work_hours']

        work_day_starts = datetime.strptime(work_day_starts,
                                            time_format).time()
        work_day_ends = datetime.strptime(work_day_ends, time_format).time()
        lunch_starts = datetime.strptime(lunch_starts, time_format).time()
        lunch_ends = datetime.strptime(lunch_ends, time_format).time()
        day_work_hours = datetime.strptime(day_work_hours, time_format).time()

        while start_date <= end_date:
            till_the_end_of_he_day_delta = twenty_four_hours_delta - timedelta(
                hours=start_date.hour,
                minutes=start_date.minute,
                seconds=start_date.second)
            calculated_end_time = (start_date + till_the_end_of_he_day_delta)

            if calculated_end_time >= end_date:
                if calculated_end_time.time() > end_date.time():
                    calculated_end_time = end_date

            if start_date.weekday(
            ) < 5:  #этот день не выходной // сделать параметром чтоб менять первый день недели
                if (calculated_end_time.time() < work_day_starts
                    ):  #промежуток кончился раньше рабочего дня
                    pass

                elif (calculated_end_time.time() > work_day_starts) and (
                        calculated_end_time.time() <= lunch_starts
                ):  #промежуток кончился после начала рабочего дня но раньше обеда:

                    if start_date.time() <= work_day_starts:
                        result_time += timedelta(hours=calculated_end_time.hour, minutes=calculated_end_time.minute, seconds=calculated_end_time.second) - \
                                                    timedelta(hours=work_day_starts.hour, minutes=work_day_starts.minute, seconds=work_day_starts.second)

                    else:
                        result_time += timedelta(hours=calculated_end_time.hour, minutes=calculated_end_time.minute, seconds=calculated_end_time.second) - \
                                                    timedelta(hours=start_date.hour, minutes=start_date.minute, seconds=start_date.second)

                elif (calculated_end_time.time() > lunch_starts) and (
                        calculated_end_time.time() < lunch_ends
                ):  #промежуток кончился после начала обеда но раньше конца обеда:
                    if start_date.time() <= work_day_starts:
                        result_time += timedelta(hours=lunch_starts.hour, minutes=lunch_starts.minute, seconds=lunch_starts.second) - \
                                                    timedelta(hours=work_day_starts.hour, minutes=work_day_starts.minute, seconds=work_day_starts.second)

                    elif (start_date.time() > work_day_starts) and (
                            start_date.time() < lunch_starts):
                        result_time += timedelta(hours=lunch_starts.hour, minutes=lunch_starts.minute, seconds=lunch_starts.second) - \
                                                    timedelta(hours=start_date.hour, minutes=start_date.minute, seconds=start_date.second)

                    elif (start_date.time() >= lunch_starts):
                        pass

                elif (calculated_end_time.time() >= lunch_ends) and (
                        calculated_end_time.time() < work_day_ends
                ):  #промежуток кончился после конца обеда но раньше конца дня
                    if start_date.time() <= work_day_starts:
                        result_time += (timedelta(hours=lunch_starts.hour, minutes=lunch_starts.minute, seconds=lunch_starts.second) - \
                                                    timedelta(hours=work_day_starts.hour, minutes=work_day_starts.minute, seconds=work_day_starts.second)) + \
                                                    (timedelta(hours=calculated_end_time.hour, minutes=calculated_end_time.minute, seconds=calculated_end_time.second) - \
                                                    timedelta(hours=lunch_ends.hour, minutes=lunch_ends.minute, seconds=lunch_ends.second))

                    elif (start_date.time() > work_day_starts) and (
                            start_date.time() < lunch_starts):
                        result_time += (timedelta(hours=lunch_starts.hour, minutes=lunch_starts.minute, seconds=lunch_starts.second) - \
                                                    timedelta(hours=start_date.hour, minutes=start_date.minute, seconds=start_date.second)) + \
                                                    (timedelta(hours=calculated_end_time.hour, minutes=calculated_end_time.minute, seconds=calculated_end_time.second) - \
                                                    timedelta(hours=lunch_ends.hour, minutes=lunch_ends.minute, seconds=lunch_ends.second))

                    elif (start_date.time() >=
                          lunch_starts) and (start_date.time() < lunch_ends):
                        result_time += (timedelta(hours=calculated_end_time.hour, minutes=calculated_end_time.minute, seconds=calculated_end_time.second) - \
                                        timedelta(hours=lunch_ends.hour, minutes=lunch_ends.minute, seconds=lunch_ends.second))

                    elif (start_date.time() >= lunch_ends):
                        result_time += (timedelta(hours=calculated_end_time.hour, minutes=calculated_end_time.minute, seconds=calculated_end_time.second) - \
                                        timedelta(hours=start_date.hour, minutes=start_date.minute, seconds=start_date.second))

                elif (calculated_end_time.time() >=
                      work_day_ends):  #промежуток кончился позже рабочего дня
                    if start_date.time() <= work_day_starts:
                        result_time += timedelta(hours=day_work_hours.hour,
                                                 minutes=day_work_hours.minute,
                                                 seconds=day_work_hours.second)

                    elif (start_date.time() > work_day_starts) and (
                            start_date.time() < lunch_starts):
                        result_time += (timedelta(hours=lunch_starts.hour, minutes=lunch_starts.minute, seconds=lunch_starts.second) - \
                                                    timedelta(hours=start_date.hour, minutes=start_date.minute, seconds=start_date.second)) + \
                                                    (timedelta(hours=work_day_ends.hour, minutes=work_day_ends.minute, seconds=work_day_ends.second) - \
                                                    timedelta(hours=lunch_ends.hour, minutes=lunch_ends.minute, seconds=lunch_ends.second))

                    elif (start_date.time() >=
                          lunch_starts) and (start_date.time() < lunch_ends):
                        result_time += (timedelta(hours=work_day_ends.hour, minutes=work_day_ends.minute, seconds=work_day_ends.second) - \
                                        timedelta(hours=lunch_ends.hour, minutes=lunch_ends.minute, seconds=lunch_ends.second))

                    elif (start_date.time() >=
                          lunch_ends) and (start_date.time() <= work_day_ends):
                        result_time += (timedelta(hours=work_day_ends.hour, minutes=work_day_ends.minute, seconds=work_day_ends.second) - \
                                        timedelta(hours=start_date.hour, minutes=start_date.minute, seconds=start_date.second))

                    elif (start_date.time() > work_day_ends):
                        pass

            start_date += (till_the_end_of_he_day_delta + timedelta(minutes=1))

        return result_time

    def filter_reports_time(self, start_date, end_date, disable_filter=False):

        datetime_format = "%Y-%m-%d %H:%M:%S"
        filter_start_date = self.unify_time(
            datetime.strptime(self.filter_dates[0], datetime_format))
        filter_end_date = self.unify_time(
            datetime.strptime(self.filter_dates[1], datetime_format))

        result_time = timedelta(hours=0, minutes=0, seconds=0)

        if not disable_filter:

            #1
            if (start_date < filter_start_date) and (end_date <
                                                     filter_start_date):
                return result_time
            #2
            elif (start_date < filter_start_date) and (
                (end_date > filter_start_date) and
                (end_date < filter_end_date)):
                start_date = filter_start_date

                return self.filter_work_hours(start_date=start_date,
                                              end_date=end_date)
            #3
            elif (start_date < filter_start_date) and (end_date >
                                                       filter_end_date):
                start_date = filter_start_date
                end_date = filter_end_date

                return self.filter_work_hours(start_date=start_date,
                                              end_date=end_date)
            #4
            elif ((start_date > filter_start_date) and
                  (start_date < filter_end_date)) and (end_date <
                                                       filter_end_date):
                self.filter_work_hours(start_date=start_date,
                                       end_date=end_date)
            #5
            elif ((start_date > filter_start_date) and
                  (start_date < filter_end_date)) and (end_date >
                                                       filter_end_date):
                end_date = filter_end_date

                return self.filter_work_hours(start_date=start_date,
                                              end_date=end_date)
            #6
            elif (start_date > filter_end_date):
                return result_time

        else:
            #print("filter enabled!")
            return self.filter_work_hours(start_date=start_date,
                                          end_date=end_date)

    def get_card_stats_by_lists(self, card, disable_filter=False):

        board = self.trello_client.get_board(board_id=card.board_id)
        lists = board.list_lists()
        time_in_lists = {
            list_.id: {
                "time": timedelta(minutes=0)
            }
            for list_ in lists
        }

        ordered_list_movements = sorted(card.list_movements(),
                                        key=itemgetter("datetime"))

        if len(ordered_list_movements) == 0:

            time_in_lists[card.list_id]['time'] += self.filter_reports_time(
                start_date=card.created_date,
                end_date=self.unify_time(datetime.now()),
                disable_filter=disable_filter)  #!!!!!!!

        elif len(ordered_list_movements) == 1:
            time_start = card.created_date
            time_end = self.unify_time(ordered_list_movements[0]['datetime'])
            list_id = ordered_list_movements[0]['source']['id']

            time_in_lists[list_id]['time'] += self.filter_reports_time(
                start_date=time_start,
                end_date=time_end,
                disable_filter=disable_filter)

            time_start = self.unify_time(ordered_list_movements[0]['datetime'])
            time_end = self.unify_time(datetime.now())
            list_id = ordered_list_movements[0]['destination']['id']

            time_in_lists[list_id]['time'] += self.filter_reports_time(
                start_date=time_start,
                end_date=time_end,
                disable_filter=disable_filter)

        else:

            for change_index in range(0, len(ordered_list_movements)):
                list_id = ordered_list_movements[change_index]['source']['id']

                if change_index == 0:

                    time_in_lists[list_id]['time'] += self.filter_reports_time(
                        start_date=card.created_date,
                        end_date=self.unify_time(
                            ordered_list_movements[change_index]['datetime']),
                        disable_filter=disable_filter)

                elif change_index > 0:

                    time_start = ordered_list_movements[change_index -
                                                        1]['datetime']
                    time_end = ordered_list_movements[change_index]['datetime']

                    time_in_lists[list_id]['time'] += self.filter_reports_time(
                        start_date=self.unify_time(time_start),
                        end_date=self.unify_time(time_end),
                        disable_filter=disable_filter)

                    if change_index + 1 == len(ordered_list_movements):

                        time_start = ordered_list_movements[change_index][
                            'datetime']
                        time_end = datetime.now()

                        list_id = ordered_list_movements[change_index][
                            'destination']['id']
                        time_in_lists[list_id][
                            'time'] += self.filter_reports_time(
                                start_date=self.unify_time(time_start),
                                end_date=self.unify_time(time_end),
                                disable_filter=disable_filter)

        return time_in_lists

    def get_project_report(self, board_id, lists, members):
        self.db.drop_table('report')
        for list_id in lists:
            for member_id in members:
                query_result = self.local_cards_has_persons.search(
                    (where('board_id') == str(board_id))
                    & (where('person_id') == str(member_id)))

                for result in query_result:
                    try:
                        card = self.trello_client.get_card(
                            card_id=result['card_id'])
                        print(
                            f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [MSG]: got card {result["card_name"], result["card_id"]}'
                        )
                    except Exception as err:
                        print(
                            f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}: [ERROR]: {err}'
                        )
                    else:
                        card_lists_time = self.get_card_stats_by_lists(
                            card=card)

                        for time in card_lists_time:
                            if time == list_id:
                                key = f'{time}'
                                if card_lists_time.get(
                                        key)['time'] > timedelta(minutes=1):
                                    list_name_query = self.local_lists.get(
                                        (where('list_id') == str(time)))

                                    self.report.insert({
                                        'person_id':
                                        result['person_id'],
                                        'person_name':
                                        result['person_name'],
                                        'card_id':
                                        result['card_id'],
                                        'card_name':
                                        result['card_name'],
                                        'list_id':
                                        time,
                                        'list_name':
                                        list_name_query['list_name'],
                                        'list_time':
                                        str(card_lists_time.get(key)['time']),
                                        'board_id':
                                        result['board_id'],
                                        'board_name':
                                        result['board_name']
                                    })

    def convert_seconds_to_readable_time(self, seconds):
        min, sec = divmod(seconds, 60)
        hour, min = divmod(min, 60)
        return "%d:%02d:%02d" % (hour, min, sec)
Esempio n. 39
0
class TrelloPlugin(DIBasePlugin, DIPluginDashboardMixin):

    platform = xapi_settings.PLATFORM_TRELLO
    platform_url = "https://trello.com"

    #created for "create" actions
    #added for "add" actions
    #updated for "update" actions
    #commented for card "comment" actions
    # xapi_verbs = ['created', 'added', 'updated', 'commented', 'closed', 'opened']
    xapi_verbs = [
        xapi_settings.VERB_CREATED, xapi_settings.VERB_ADDED,
        xapi_settings.VERB_UPDATED, xapi_settings.VERB_COMMENTED,
        xapi_settings.VERB_CLOSED, xapi_settings.VERB_OPENED
    ]

    #Note for "commented" actions
    #Task for "created", "added", "updated", and "commented" actions
    #Collection for any "created", "added", "updated" List actions (tentative use)
    # xapi_objects = ['Note', 'Task', 'Collection', 'Person', 'File', 'checklist-item', 'checklist']
    xapi_objects = [
        xapi_settings.OBJECT_NOTE, xapi_settings.OBJECT_TASK,
        xapi_settings.OBJECT_COLLECTION, xapi_settings.OBJECT_PERSON,
        xapi_settings.OBJECT_FILE, xapi_settings.OBJECT_CHECKLIST_ITEM,
        xapi_settings.OBJECT_CHECKLIST
    ]

    user_api_association_name = 'Trello UID'  # eg the username for a signed up user that will appear in data extracted via a social API
    unit_api_association_name = 'Board ID'  # eg hashtags or a group name

    config_json_keys = ['consumer_key', 'consumer_secret']

    #from DIPluginDashboardMixin
    xapi_objects_to_includein_platformactivitywidget = [
        xapi_settings.OBJECT_NOTE
    ]
    xapi_verbs_to_includein_verbactivitywidget = [
        xapi_settings.VERB_CREATED, xapi_settings.VERB_SHARED,
        xapi_settings.VERB_LIKED, xapi_settings.VERB_COMMENTED
    ]

    #for OAuth1 authentication
    token_request_url = ''

    # Trello action type
    # Note: MoveCard, CloseCard, OpenCard are created for the toolkit to identify what users really did
    #       (The original action type of moving/closing/opening card are all same: updateCard)
    ACTION_TYPE_COMMENT_CARD = 'commentCard'
    ACTION_TYPE_CREATE_CARD = 'createCard'
    ACTION_TYPE_UPDATE_CHECKITEM_STATE_ON_CARD = 'updateCheckItemStateOnCard'
    ACTION_TYPE_UPDATE_CARD = 'updateCard'
    ACTION_TYPE_ADD_ATTACHMENT_TO_CARD = 'addAttachmentToCard'
    ACTION_TYPE_ADD_CHECKLIST_TO_CARD = 'addChecklistToCard'
    ACTION_TYPE_ADD_MEMBER_TO_CARD = 'addMemberToCard'
    ACTION_TYPE_MOVE_CARD = 'moveCard'
    ACTION_TYPE_CLOSE_CARD = 'closeCard'
    ACTION_TYPE_OPEN_CARD = 'openCard'

    VERB_OBJECT_MAPPER = {
        xapi_settings.VERB_CREATED: [ACTION_TYPE_CREATE_CARD],
        xapi_settings.VERB_ADDED: [
            ACTION_TYPE_ADD_ATTACHMENT_TO_CARD,
            ACTION_TYPE_ADD_CHECKLIST_TO_CARD, ACTION_TYPE_ADD_MEMBER_TO_CARD
        ],
        xapi_settings.VERB_UPDATED:
        [ACTION_TYPE_MOVE_CARD, ACTION_TYPE_UPDATE_CHECKITEM_STATE_ON_CARD],
        xapi_settings.VERB_COMMENTED: [ACTION_TYPE_COMMENT_CARD],
        xapi_settings.VERB_CLOSED: [ACTION_TYPE_CLOSE_CARD],
        xapi_settings.VERB_OPENED: [ACTION_TYPE_OPEN_CARD]
    }

    SEPARATOR_COLON = ": "
    SEPARATOR_HTML_TAG_BR = "<br>"
    MESSAGE_CARD_POSITION_CHANGED = 'Card position was changed.'

    def __init__(self):
        pass

    #retreival param is the user_id
    def perform_import(self, retreival_param, unit, token=None):
        #from clatoolkit.models import ApiCredentials
        #Set up trello auth and API
        self.TrelloCient = TrelloClient(
            api_key=os.environ.get("TRELLO_API_KEY"), token=token)
        #Get user-registered board in trello
        trello_board = self.TrelloCient.get_board(retreival_param)

        #Get boards activity/action feed
        trello_board.fetch_actions(
            'all'
        )  #fetch_actions() collects actions feed and stores to trello_board.actions
        self.import_TrelloActivity(trello_board.actions, unit)

    def import_TrelloActivity(self, feed, unit):
        #User needs to sign up username and board (board can be left out but is needed)
        print 'Beginning Trello import!'

        for action in list(feed):
            #We need to connect this with our user profile somewhere when they initially auth
            u_id = action['idMemberCreator']
            author = action['memberCreator']['username']
            type = action['type']  #commentCard, updateCard, createList,etc
            data = action['data']
            date = action['date']
            board_name = data['board']['name']

            # print 'got action type: %s' % (type)

            #Get all 'commented' verb actions
            if (type == self.ACTION_TYPE_COMMENT_CARD):
                target_obj_id = self.create_card_url(data)
                comment_from_uid = u_id
                comment_from_name = author
                comment_message = data['text']
                comment_id = target_obj_id + '/' + action['id']
                card_name = data['card']['name']

                if username_exists(comment_from_uid, unit, self.platform):
                    # Create "other" contextActivity object to store original activity in xAPI
                    card_details = self.TrelloCient.fetch_json(
                        '/cards/' + data['card']['id'])
                    context = get_other_contextActivity(
                        card_details['shortUrl'], 'Verb', type,
                        xapi_settings.get_verb_iri(
                            xapi_settings.VERB_COMMENTED))
                    context2 = get_other_contextActivity(
                        card_details['shortUrl'], 'Object',
                        data['card']['name'],
                        xapi_settings.get_verb_iri(
                            xapi_settings.VERB_COMMENTED))
                    other_context_list = [context, context2]

                    user = get_user_from_screen_name(comment_from_uid,
                                                     self.platform)
                    insert_comment(user,
                                   target_obj_id,
                                   comment_id,
                                   comment_message,
                                   date,
                                   unit,
                                   self.platform,
                                   self.platform_url,
                                   parent_user_external=card_name,
                                   other_contexts=other_context_list)

            if (type == self.ACTION_TYPE_CREATE_CARD):
                object_id = self.create_card_url(data) + '/' + action['id']
                card_name = data['card']['name']
                parent_id = self.create_list_url(data)

                if username_exists(u_id, unit, self.platform):
                    # Create "other" contextActivity object to store original activity in xAPI
                    card_details = self.TrelloCient.fetch_json(
                        '/cards/' + data['card']['id'])
                    context = get_other_contextActivity(
                        card_details['shortUrl'], 'Verb', type,
                        xapi_settings.get_verb_iri(xapi_settings.VERB_CREATED))
                    context2 = get_other_contextActivity(
                        card_details['shortUrl'], 'Object',
                        data['list']['name'],
                        xapi_settings.get_verb_iri(xapi_settings.VERB_CREATED))
                    other_context_list = [context, context2]
                    usr_dict = ClaUserUtil.get_user_details_by_smid(
                        u_id, self.platform)
                    user = get_user_from_screen_name(u_id, self.platform)

                    insert_task(user,
                                object_id,
                                card_name,
                                date,
                                unit,
                                self.platform,
                                self.platform_url,
                                parent_id=parent_id,
                                other_contexts=other_context_list)

            #Get all 'add' verbs (you tecnically aren't *creating* an attachment on a card so....)
            if (type in [
                    self.ACTION_TYPE_ADD_ATTACHMENT_TO_CARD,
                    self.ACTION_TYPE_ADD_CHECKLIST_TO_CARD,
                    self.ACTION_TYPE_ADD_MEMBER_TO_CARD
            ]):
                user = get_user_from_screen_name(u_id, self.platform)
                if user is None:
                    continue

                card_url = self.create_card_url(data)

                # Create "other" contextActivity object to store original activity in xAPI
                other_context_list = []
                card_details = self.TrelloCient.fetch_json('/cards/' +
                                                           data['card']['id'])
                context = get_other_contextActivity(
                    card_details['shortUrl'], 'Verb', type,
                    xapi_settings.get_verb_iri(xapi_settings.VERB_ADDED))
                other_context_list.append(context)
                context2 = get_other_contextActivity(
                    card_details['shortUrl'], 'Object', data['card']['name'],
                    xapi_settings.get_verb_iri(xapi_settings.VERB_ADDED))
                other_context_list = [context, context2]

                if type == self.ACTION_TYPE_ADD_ATTACHMENT_TO_CARD:

                    attachment = data['attachment']
                    attachment_id = card_url + '/' + data['attachment']['id']
                    attachment_data = attachment['name']
                    object_type = xapi_settings.OBJECT_FILE
                    parent_user_external = '%sc/%s' % (self.platform_url,
                                                       card_url)
                    other_context_list.append(
                        get_other_contextActivity(
                            card_details['shortUrl'], 'Object',
                            attachment['url'],
                            xapi_settings.get_verb_iri(
                                xapi_settings.VERB_ADDED)))

                    insert_added_object(
                        user,
                        card_url,
                        attachment_id,
                        attachment_data,
                        date,
                        unit,
                        self.platform,
                        self.platform_url,
                        object_type,
                        parent_user_external=parent_user_external,
                        other_contexts=other_context_list)

                if type == self.ACTION_TYPE_ADD_MEMBER_TO_CARD:  #or 'addMemberToBoard':

                    object_id = card_url + '/' + action['member']['id']
                    object_data = action['member']['username']
                    object_type = xapi_settings.OBJECT_PERSON
                    parent_user_external = '%sc/%s' % (self.platform_url,
                                                       card_url)

                    insert_added_object(
                        user,
                        card_url,
                        object_id,
                        object_data,
                        date,
                        unit,
                        self.platform,
                        self.platform_url,
                        object_type,
                        parent_user_external=parent_user_external,
                        other_contexts=other_context_list)

                if type == self.ACTION_TYPE_ADD_CHECKLIST_TO_CARD:

                    object_id = card_url + '/' + data['checklist']['id']
                    object_data = None
                    checklist_items = None
                    object_type = xapi_settings.OBJECT_COLLECTION
                    parent_user_external = '%sc/%s' % (self.platform_url,
                                                       card_url)

                    #get checklist contents
                    try:
                        checklist = self.TrelloCient.fetch_json(
                            '/checklists/' + data['checklist']['id'], )
                        checklist_items = checklist['checkItems']
                    except Exception:
                        print 'Could not retrieve checklist..'
                        continue

                    object_data = data['checklist']['name']
                    for item in checklist_items:
                        # items are stored individually in other contextActivities
                        other_context_list.append(
                            get_other_contextActivity(
                                card_details['shortUrl'], 'Object',
                                item['name'],
                                xapi_settings.get_verb_iri(
                                    xapi_settings.VERB_ADDED)))

                    insert_added_object(
                        user,
                        card_url,
                        object_id,
                        object_data,
                        date,
                        unit,
                        self.platform,
                        self.platform_url,
                        object_type,
                        parent_user_external=parent_user_external,
                        other_contexts=other_context_list)

            if (type in [
                    self.ACTION_TYPE_UPDATE_CHECKITEM_STATE_ON_CARD,
                    self.ACTION_TYPE_UPDATE_CARD
            ]):
                user = get_user_from_screen_name(u_id, self.platform)
                if user is None:
                    continue

                card_details = self.TrelloCient.fetch_json('/cards/' +
                                                           data['card']['id'])
                #many checklist items will be bugged - we require webhooks!

                if type == self.ACTION_TYPE_UPDATE_CHECKITEM_STATE_ON_CARD:
                    # Import check item ID & its state
                    # Use action ID as an object ID to avoid ID conflict.
                    object_id = self.create_card_url(data) + '/' + action['id']
                    obj_val = data['checkItem']['state']

                    # Create "other" contextActivity object to store original activity in xAPI
                    other_context_list = []
                    other_context_list.append(
                        get_other_contextActivity(
                            self.create_checklist_url(data), 'Verb', type,
                            xapi_settings.get_verb_iri(
                                xapi_settings.VERB_UPDATED)))
                    other_context_list.append(
                        get_other_contextActivity(
                            card_details['shortUrl'], 'Object',
                            data['checkItem']['name'],
                            xapi_settings.get_verb_iri(
                                xapi_settings.OBJECT_CHECKLIST_ITEM)))
                    other_context_list.append(
                        get_other_contextActivity(
                            card_details['shortUrl'], 'Object',
                            data['card']['name'],
                            xapi_settings.get_verb_iri(
                                xapi_settings.VERB_UPDATED)))

                    insert_updated_object(
                        user,
                        object_id,
                        obj_val,
                        date,
                        unit,
                        self.platform,
                        self.platform_url,
                        xapi_settings.OBJECT_CHECKLIST_ITEM,
                        parent_id=self.create_checklist_url(data),
                        obj_parent_type=xapi_settings.OBJECT_CHECKLIST,
                        other_contexts=other_context_list)

                #up to us to figure out what's being updated
                if type == self.ACTION_TYPE_UPDATE_CARD:

                    #Get and store the values that were changed, usually it's only one
                    #TODO: Handle support for multiple changes, if that's possible
                    try:
                        change = [
                            changed_value for changed_value in data['old']
                        ]
                    except Exception:
                        print 'Error occurred getting changes...'

                    # Use action ID as an object ID to avoid ID conflict.
                    object_id = self.create_card_url(data) + '/' + action['id']

                    if change[0] == 'pos':
                        # When user moves card in the same list (change order)

                        object_text = data['card']['name']
                        # object_text = 'Change order of card: %s to %s' % (data['old']['pos'], data['card']['pos'])
                        # object_text = card_name + object_text
                        other_context_list = []
                        other_context_list.append(
                            get_other_contextActivity(
                                card_details['shortUrl'], 'Verb',
                                self.ACTION_TYPE_MOVE_CARD,
                                xapi_settings.get_verb_iri(
                                    xapi_settings.VERB_UPDATED)))
                        other_context_list.append(
                            get_other_contextActivity(
                                card_details['shortUrl'], 'Object',
                                self.MESSAGE_CARD_POSITION_CHANGED,
                                xapi_settings.get_verb_iri(
                                    xapi_settings.VERB_UPDATED)))
                        other_context_list.append(
                            get_other_contextActivity(
                                card_details['shortUrl'], 'Object',
                                str(data['old']['pos']),
                                xapi_settings.get_verb_iri(
                                    xapi_settings.VERB_UPDATED)))
                        other_context_list.append(
                            get_other_contextActivity(
                                card_details['shortUrl'], 'Object',
                                str(data['card']['pos']),
                                xapi_settings.get_verb_iri(
                                    xapi_settings.VERB_UPDATED)))

                        insert_updated_object(
                            user,
                            object_id,
                            object_text,
                            date,
                            unit,
                            self.platform,
                            self.platform_url,
                            xapi_settings.OBJECT_TASK,
                            parent_id=self.create_list_url(data),
                            obj_parent_type=xapi_settings.OBJECT_COLLECTION,
                            other_contexts=other_context_list)

                    else:
                        # When user moves card from a list to another
                        if data.has_key('listBefore'):
                            object_text = data['card']['name']
                            # object_text = 'from %s to %s' % (data['listBefore']['name'], data['listAfter']['name'])
                            # object_text = card_name + object_text

                            other_context_list = []
                            other_context_list.append(
                                get_other_contextActivity(
                                    card_details['shortUrl'], 'Verb',
                                    self.ACTION_TYPE_MOVE_CARD,
                                    xapi_settings.get_verb_iri(
                                        xapi_settings.VERB_UPDATED)))
                            other_context_list.append(
                                get_other_contextActivity(
                                    card_details['shortUrl'], 'Object',
                                    data['listBefore']['name'],
                                    xapi_settings.get_verb_iri(
                                        xapi_settings.VERB_UPDATED)))
                            other_context_list.append(
                                get_other_contextActivity(
                                    card_details['shortUrl'], 'Object',
                                    data['listAfter']['name'],
                                    xapi_settings.get_verb_iri(
                                        xapi_settings.VERB_UPDATED)))

                            insert_updated_object(
                                user,
                                object_id,
                                object_text,
                                date,
                                unit,
                                self.platform,
                                self.platform_url,
                                xapi_settings.OBJECT_TASK,
                                parent_id=self.create_card_url(data),
                                obj_parent_type=xapi_settings.
                                OBJECT_COLLECTION,
                                other_contexts=other_context_list)

                        # When user closes (archives)/opens card
                        elif data['old'][change[0]] is False or data['old'][
                                change[0]] is True:
                            verb = xapi_settings.VERB_CLOSED
                            verb_iri = xapi_settings.get_verb_iri(verb)
                            action_type = self.ACTION_TYPE_CLOSE_CARD
                            object_text = data['card']['name']

                            # When card is opened
                            if data['old'][change[0]] is True:
                                verb = xapi_settings.VERB_OPENED
                                verb_iri = xapi_settings.get_verb_iri(verb)
                                action_type = self.ACTION_TYPE_OPEN_CARD

                            other_context_list = []
                            other_context_list.append(
                                get_other_contextActivity(
                                    card_details['shortUrl'], 'Verb',
                                    action_type, verb_iri))
                            other_context_list.append(
                                get_other_contextActivity(
                                    card_details['shortUrl'], 'Object',
                                    data['list']['name'], verb_iri))

                            insert_closedopen_object(
                                user,
                                object_id,
                                object_text,
                                date,
                                unit,
                                self.platform,
                                self.platform_url,
                                xapi_settings.OBJECT_TASK,
                                verb,
                                parent_id=self.create_list_url(data),
                                obj_parent_type=xapi_settings.
                                OBJECT_COLLECTION,
                                other_contexts=other_context_list)

    def create_card_url(self, data):
        return self.platform_url + '/c/' + str(data['card']['id'])

    def create_list_url(self, data):
        return self.platform_url + '/b/' + str(
            data['board']['id']) + '/' + str(data['list']['id'])

    def create_checklist_url(self, data):
        return self.platform_url + '/b/' + str(
            data['board']['id']) + '/' + str(data['checklist']['id'])

    def get_verbs(self):
        return self.xapi_verbs

    def get_objects(self):
        return self.xapi_objects

    def get_other_contextActivity_types(self, verbs=[]):
        ret = []
        if verbs is None or len(verbs) == 0:
            ret = [
                self.ACTION_TYPE_COMMENT_CARD, self.ACTION_TYPE_CREATE_CARD,
                self.ACTION_TYPE_UPDATE_CHECKITEM_STATE_ON_CARD,
                self.ACTION_TYPE_UPDATE_CARD,
                self.ACTION_TYPE_ADD_ATTACHMENT_TO_CARD,
                self.ACTION_TYPE_ADD_CHECKLIST_TO_CARD,
                self.ACTION_TYPE_ADD_MEMBER_TO_CARD,
                self.ACTION_TYPE_MOVE_CARD, self.ACTION_TYPE_CLOSE_CARD,
                self.ACTION_TYPE_OPEN_CARD
            ]
        else:
            for verb in verbs:
                action_types = self.VERB_OBJECT_MAPPER[verb]
                for type in action_types:
                    ret.append(type)
        return ret

    def get_display_names(self, mapper):
        if mapper is None:
            return mapper

        ret = {}
        for key, val in mapper.iteritems():
            for action in mapper[key]:
                ret[action] = self.get_action_type_display_name(action)

        return ret

    def get_action_type_display_name(self, action):
        if action == self.ACTION_TYPE_CREATE_CARD:
            return 'Created card'
        elif action == self.ACTION_TYPE_ADD_ATTACHMENT_TO_CARD:
            return 'Added attachment to card'
        elif action == self.ACTION_TYPE_ADD_CHECKLIST_TO_CARD:
            return 'Added checklist to card'
        elif action == self.ACTION_TYPE_ADD_MEMBER_TO_CARD:
            return 'Added member to card'
        elif action == self.ACTION_TYPE_MOVE_CARD:
            return 'Moved card'
        elif action == self.ACTION_TYPE_UPDATE_CHECKITEM_STATE_ON_CARD:
            return 'Updated checklist item state'
        elif action == self.ACTION_TYPE_COMMENT_CARD:
            return 'Commented on card'
        elif action == self.ACTION_TYPE_CLOSE_CARD:
            return 'Closed card'
        elif action == self.ACTION_TYPE_OPEN_CARD:
            return 'Opened card'
        else:
            return 'Unknown action type'

    def get_detail_values_by_fetch_results(self, xapi_statements):
        all_rows = []
        # return all_rows
        for stmt in xapi_statements:
            single_row = []
            # user name
            name = ''
            if 'name' in stmt['authority']['member'][0]:
                name = stmt['authority']['member'][0]['name']
            else:
                name = stmt['authority']['member'][1]['name']

            single_row.append(name)
            # verb or original action type
            other_context_activities = stmt['context']['contextActivities'][
                'other']
            single_row.append(
                self.get_action_type_from_context(other_context_activities))
            # Date
            dt = Utility.convert_to_datetime_object(stmt['timestamp'])
            date_str = str(dt.year) + ',' + str(dt.month) + ',' + str(dt.day)
            # date_str += ' ' + str(dt.hour) + ':' + str(dt.minute) + ':' + str(dt.second)
            single_row.append(date_str)

            # Value of an object
            single_row.append(self.get_object_diaplay_value(stmt))
            all_rows.append(single_row)
        return all_rows

    def get_action_type_from_context(self, json):
        return json[0]['definition']['name']['en-US']

    def get_object_diaplay_value(self, stmt):
        other_context_activities = stmt['context']['contextActivities'][
            'other']
        action = self.get_action_type_from_context(other_context_activities)
        object_val = stmt['object']['definition']['name']['en-US']
        if len(other_context_activities) <= 1:
            return object_val

        object_val = object_val
        contexts = other_context_activities
        value = ''
        index = 1
        if action == self.ACTION_TYPE_CREATE_CARD:
            value = "created %s in %s" % (
                self.italicize(object_val),
                self.italicize(contexts[index]['definition']['name']['en-US']))

        elif action == self.ACTION_TYPE_ADD_ATTACHMENT_TO_CARD:
            value = "attached %s to %s" % (
                self.italicize(object_val),
                self.italicize(contexts[index]['definition']['name']['en-US']))
            value = value + self.SEPARATOR_HTML_TAG_BR
            index = index + 1
            value = value + contexts[index]['definition']['name']['en-US']

        elif action == self.ACTION_TYPE_ADD_CHECKLIST_TO_CARD:
            value = "added %s to %s" % (
                self.italicize(object_val),
                self.italicize(contexts[index]['definition']['name']['en-US']))
            value = value + self.SEPARATOR_HTML_TAG_BR
            index = index + 1
            for key in range(index, len(contexts)):
                value = value + ' ' + contexts[key]['definition']['name'][
                    'en-US'] + self.SEPARATOR_HTML_TAG_BR

        elif action == self.ACTION_TYPE_ADD_MEMBER_TO_CARD:
            value = "added %s to %s" % (
                self.italicize(object_val),
                self.italicize(contexts[index]['definition']['name']['en-US']))
            value = value + self.SEPARATOR_HTML_TAG_BR

        elif action == self.ACTION_TYPE_MOVE_CARD:
            if contexts[index]['definition']['name'][
                    'en-US'] == self.MESSAGE_CARD_POSITION_CHANGED:
                value = contexts[index]['definition']['name']['en-US']
                value = value + self.SEPARATOR_HTML_TAG_BR
                value = value + self.italicize(object_val)
            else:
                value = "moved %s" % (self.italicize(object_val))
                value = value + " from %s" % (self.italicize(
                    contexts[index]['definition']['name']['en-US']))
                index = index + 1
                value = value + " to %s" % (self.italicize(
                    contexts[index]['definition']['name']['en-US']))

        elif action == self.ACTION_TYPE_UPDATE_CHECKITEM_STATE_ON_CARD:
            value = "%s: %s" % (self.italicize(
                contexts[index]['definition']['name']['en-US']),
                                self.italicize(object_val))

        elif action == self.ACTION_TYPE_COMMENT_CARD:
            value = 'commented in %s' % self.italicize(
                contexts[index]['definition']['name']['en-US'])
            value = value + self.SEPARATOR_HTML_TAG_BR
            value = value + self.italicize(
                self.replace_linechange_with_br_tag(object_val))

        elif action == self.ACTION_TYPE_CLOSE_CARD:
            value = "closed %s in %s" % (
                self.italicize(object_val),
                self.italicize(contexts[index]['definition']['name']['en-US']))

        elif action == self.ACTION_TYPE_OPEN_CARD:
            value = "opened %s in %s" % (
                self.italicize(object_val),
                self.italicize(contexts[index]['definition']['name']['en-US']))

        else:
            value = self.italicize(object_val)

        return value

    def italicize(self, value):
        return '<i>%s</i>' % (value)

    def replace_linechange_with_br_tag(self, target):
        return target.replace('\n', '<br>')
Esempio n. 40
0
class TrelloCollector(object):
    """
    Class representing all Trello information required to do the SysDesEng reporting.
    """

    def __init__(self, report_config, trello_secret):
        self.logger = logging.getLogger(__name__)
        self.client = TrelloClient(api_key = trello_secret[':consumer_key'],
                                   api_secret = trello_secret[':consumer_secret'],
                                   token = trello_secret[':oauth_token'],
                                   token_secret = trello_secret[':oauth_token_secret'])

        #Extract report configuration parameters
        trello_sources = report_config[':trello_sources'];
        #self.report_parameters = report_config[':output_metadata'];
        gen_date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")

        self.content = { ':output_metadata' : {
                              ':gen_date': gen_date, #Report name is built as :report_name + gen_date (where :report_name is taken from the config)
                              ':trello_sources': {
                                 ':boards':{},
                                 ':lists': {},
                                 ':cards': [] }}}

        self.load_config(trello_sources, self.content[':output_metadata'][':trello_sources'])
        self.logger.debug("Report output metadata: %s" % (self.content[':output_metadata']))

    def load_config(self, config_src, report_metadata):
        """ load all config data related to trello sources and structure them in the report_metadata"""
        for card_type in config_src.keys(): #card_type is project|assignment|epic
            for board_t in config_src[card_type].keys():
                board_id = config_src[card_type][board_t][':board_id']
                if not board_id in report_metadata: # initialize if the board wasn't present during the iterations over other card_type's
                    if not board_id in report_metadata[':boards']:
                        report_metadata[':boards'][board_id] = {};
                    report_metadata[':boards'][board_id][':board_id'] = config_src[card_type][board_t][':board_id'] #copy board id
                    report_metadata[':boards'][board_id][':board_name'] = board_t
                    if not ':lists' in report_metadata[':boards'][board_id]:
                        report_metadata[':boards'][board_id][':lists'] = []

                #iterate through all the lists and populate them
                for list_t in config_src[card_type][board_t][':lists'].keys():
                    self.logger.debug("Adding board %s, list %s to the report" % (config_src[card_type][board_t][':board_id'], config_src[card_type][board_t][':lists'][list_t]))
                    list_id = config_src[card_type][board_t][':lists'][list_t]
                    report_metadata[':lists'][list_id] = {};
                    report_metadata[':lists'][list_id][':list_id'] = list_id
                    report_metadata[':lists'][list_id][':completed'] = False;
                    report_metadata[':lists'][list_id][':card_type'] = card_type;
                    report_metadata[':lists'][list_id][':board_id'] = board_id
                    report_metadata[':boards'][board_id][':lists'].append(list_id)
                if ':done_lists' in config_src[card_type][board_t]:
                    for list_t in config_src[card_type][board_t][':done_lists'].keys():
                        self.logger.debug("Adding board %s, Done list %s to the report" % (config_src[card_type][board_t][':board_id'], config_src[card_type][board_t][':done_lists'][list_t]))
                        list_id = config_src[card_type][board_t][':done_lists'][list_t]
                        report_metadata[':lists'][list_id] = {};
                        report_metadata[':lists'][list_id][':list_id'] = list_id
                        report_metadata[':lists'][list_id][':completed'] = True;
                        report_metadata[':lists'][list_id][':card_type'] = card_type;
                        report_metadata[':lists'][list_id][':board_id'] = board_id
                        report_metadata[':boards'][board_id][':lists'].append(list_id)

    def list_boards(self):
        syseng_boards = self.client.list_boards()
        for board in syseng_boards:
            for tlist in board.all_lists():
                self.logger.info('board name: %s is here, board ID is: %s; list %s is here, list ID is: %s' % (board.name, board.id, tlist.name, tlist.id)) 

    def parse_trello(self, deep_scan):
        """
        :deep_scan: If deep_scan is True the scan will traverse actions, otherwise just a light scan(much faster)
        Main function to parse all Trello boards and lists.
        """
        trello_sources = self.content[':output_metadata'][':trello_sources'];
        self.logger.debug('The sources are %s' % (trello_sources))

        for board_id in trello_sources[':boards'].keys():
            tr_board = self.client.get_board(board_id);
            tr_board.fetch(); # get all board properties
            members = [ (m.id, m.full_name) for m in tr_board.get_members()];
            trello_sources[':boards'][board_id][':members'] = members;
            self.logger.info('----- querying board %s -----' % (trello_sources[':boards'][board_id][':board_name']))
            self.logger.debug('Board members are %s' % (trello_sources[':boards'][board_id][':members']))

            #trello_sources[board_id][':cards'] = []
            cards = tr_board.get_cards();

    
            for card in cards:
                card_content = {}
                card_content[':name'] = card.name
                card_content[':id'] = card.id
                card_content[':members'] = []
                card_content[':board_id'] = tr_board.id
                for member_id in card.member_ids:
                    for (m_id, m_full_name) in members:
                        if member_id == m_id :
                           card_content[':members'].append((m_id,m_full_name))
                card_content[':desc'] = card.desc
                card_content[':short_url'] = card.url
                card_content[':labels'] = [(label.name,label.color) for label in card.labels]
                #self.logger.debug('Card: {0} | LABELES are {1}'.format(card_content[':name'], card_content[':labels']))
                card_content[':board_name'] = tr_board.name
                card_content[':list_id'] = card.list_id
                if card.due:
                    card_content[':due_date'] = arrow.get(card.due).format('YYYY-MM-DD HH:mm:ss')
                trello_sources[':cards'].append(card_content);

            self.logger.debug('%s cards were collected' % (len(cards)))

            tr_board.fetch_actions(action_filter="commentCard,updateCard:idList,createCard,copyCard,moveCardToBoard,convertToCardFromCheckItem",action_limit=1000);
            trello_sources[':boards'][board_id][':actions'] = sorted(tr_board.actions,key=lambda act: act['date'], reverse=True)
            self.logger.debug('%s actions were collected' % (len(trello_sources[':boards'][board_id][':actions'])))
            #self.logger.debug('Oldest action is %s' % (trello_sources[':boards'][board_id][':actions'][-1]))

            tr_lists = tr_board.all_lists()
            for tr_list in tr_lists:
                if tr_list.id in trello_sources[':lists']:
                    trello_sources[':lists'][tr_list.id][':name'] = tr_list.name;
            self.logger.info('the lists are %s' % (tr_lists))

        return self.content


    def parse_card_details(self, card_id):
        card = card_details.CardDetails(card_id, self.client, self.content[':output_metadata'])
        details = card.fill_details();
        #self.logger.debug('Card\'s details are: %s' % (details))
        return details
Esempio n. 41
0
class ServiceTrello(ServicesMgr):
    """
        Serivce Trello
    """
    # Boards own Lists own Cards

    def __init__(self, token=None, **kwargs):
        super(ServiceTrello, self).__init__(token, **kwargs)
        # app name
        self.app_name = DjangoThConfig.verbose_name
        # expiration
        self.expiry = "30days"
        # scope define the rights access
        self.scope = 'read,write'
        self.oauth = 'oauth1'
        self.service = 'ServiceTrello'

        base = 'https://www.trello.com'
        self.AUTH_URL = '{}/1/OAuthAuthorizeToken'.format(base)
        self.REQ_TOKEN = '{}/1/OAuthGetRequestToken'.format(base)
        self.ACC_TOKEN = '{}/1/OAuthGetAccessToken'.format(base)
        self.consumer_key = settings.TH_TRELLO_KEY['consumer_key']
        self.consumer_secret = settings.TH_TRELLO_KEY['consumer_secret']
        if token:
            token_key, token_secret = token.split('#TH#')
            try:
                self.trello_instance = TrelloClient(self.consumer_key,
                                                    self.consumer_secret,
                                                    token_key,
                                                    token_secret)
            except ResourceUnavailable as e:
                us = UserService.objects.get(token=token)
                logger.error(e.msg, e.error_code)
                update_result(us.trigger_id, msg=e.msg, status=False)

    def read_data(self, **kwargs):
        """
            get the data from the service

            :param kwargs: contain keyword args : trigger_id at least
            :type kwargs: dict
        """
        trigger_id = kwargs.get('trigger_id')
        data = list()
        kwargs['model_name'] = 'Trello'
        kwargs['app_label'] = 'th_trello'
        super(ServiceTrello, self).read_data(**kwargs)
        cache.set('th_trello_' + str(trigger_id), data)
        return data

    def save_data(self, trigger_id, **data):
        """
            let's save the data

            :param trigger_id: trigger ID from which to save data
            :param data: the data to check to be used and save
            :type trigger_id: int
            :type data:  dict
            :return: the status of the save statement
            :rtype: boolean
        """
        data['output_format'] = 'md'
        title, content = super(ServiceTrello, self).save_data(trigger_id, **data)
        if len(title):
            # get the data of this trigger
            t = Trello.objects.get(trigger_id=trigger_id)
            # footer of the card
            footer = self.set_card_footer(data, t)
            content += footer

            # 1 - we need to search the list and board where we will
            # store the card so ...

            # 1.a search the board_id by its name
            # by retrieving all the boards
            boards = self.trello_instance.list_boards()

            board_id = ''
            my_list = ''
            for board in boards:
                if t.board_name == board.name:
                    board_id = board.id
                    break

            if board_id:
                # 1.b search the list_id by its name
                my_board = self.trello_instance.get_board(board_id)
                lists = my_board.open_lists()
                # just get the open list ; not all the archive ones
                for list_in_board in lists:
                    # search the name of the list we set in the form
                    if t.list_name == list_in_board.name:
                        # return the (trello) list object to be able to add card at step 3
                        my_list = my_board.get_list(list_in_board.id)
                        break
                # we didnt find the list in that board -> create it
                if my_list == '':
                    my_list = my_board.add_list(t.list_name)
            else:
                # 2 if board_id and/or list_id does not exist, create it/them
                my_board = self.trello_instance.add_board(t.board_name)
                # add the list that didn't exists and return a (trello) list object
                my_list = my_board.add_list(t.list_name)

            # 3 create the card
            my_list.add_card(title, content)

            logger.debug(str('trello {} created').format(data['link']))
            status = True
        else:
            sentence = "no token or link provided for trigger ID {}".format(trigger_id)
            update_result(trigger_id, msg=sentence, status=False)
            status = False

        return status

    @staticmethod
    def set_card_footer(data, trigger):
        """
            handle the footer of the note
        """
        footer = ''
        if data.get('link'):
            provided_by = _('Provided by')
            provided_from = _('from')
            footer_from = "<br/><br/>{} <em>{}</em> {} <a href='{}'>{}</a>"
            description = trigger.trigger.description
            footer = footer_from.format(provided_by, description, provided_from, data.get('link'), data.get('link'))
            import pypandoc
            footer = pypandoc.convert(footer, 'md', format='html')
        return footer

    def auth(self, request):
        """
            let's auth the user to the Service
            :param request: request object
            :return: callback url
            :rtype: string that contains the url to redirect after auth
        """
        request_token = super(ServiceTrello, self).auth(request)
        callback_url = self.callback_url(request)

        # URL to redirect user to, to authorize your app
        auth_url_str = '{auth_url}?oauth_token={token}'
        auth_url_str += '&scope={scope}&name={name}'
        auth_url_str += '&expiration={expiry}&oauth_callback={callback_url}'
        auth_url = auth_url_str.format(auth_url=self.AUTH_URL,
                                       token=request_token['oauth_token'],
                                       scope=self.scope,
                                       name=self.app_name,
                                       expiry=self.expiry,
                                       callback_url=callback_url)

        return auth_url

    def callback(self, request, **kwargs):
        """
            Called from the Service when the user accept to activate it
            :param request: request object
            :return: callback url
            :rtype: string , path to the template
        """
        return super(ServiceTrello, self).callback(request, **kwargs)
Esempio n. 42
0
class Trello:
    client = None

    def __init__(self):
        self.client = TrelloClient(
            api_key=os.environ.get("trello_api_key"),
            api_secret=os.environ.get("trello_api_secret"),
            token=os.environ.get("trello_token"),
        )

    def get_project_list(self):
        projects = []
        for b in self.client.list_boards():
            projects.append({"name": b.name.decode("utf-8"), "id": b.id})
        return projects

    def get_sprints(self, trell_project):

        board = self.client.get_board(trell_project)

        sprints = []

        for l in board.all_lists():
            m = re.search("Sprint (.*?) - Done", l.name.decode("utf-8"))
            if m is not None:
                sprints.append({"sprint": m.group(1)})

        return sprints

    def get_story_list(self, trell_project, sprint):

        board = self.client.get_board(trell_project)

        stories = []

        list = board.all_lists()
        for l in board.all_lists():
            type = None
            if l.name.decode("utf-8") == "Sprint " + sprint + " - Backlog":
                type = "Backlog"
            elif l.name.decode("utf-8") == "Sprint " + sprint + " - Doing":
                type = "Doing"
            elif l.name.decode("utf-8") == "Sprint " + sprint + " - Done":
                type = "Done"

            if type is not None:
                for c in l.list_cards():
                    if type == "Done":
                        if len(c.listCardMove_date()) > 0:
                            # Convert DateTime to Epoch
                            card_date = time.mktime(parser.parse(str(c.latestCardMove_date)).timetuple())
                        else:
                            # Convert DateTime to Epoch
                            card_date = time.mktime(c.create_date().timetuple())
                    else:
                        card_date = None

                    split = c.name.decode("utf-8").split("(")
                    points = split[len(split) - 1].replace(")", "")
                    del split[len(split) - 1]
                    name = "(".join(split)

                    stories.append(
                        {"status": type, "name": name, "id": c.id, "points": points, "date_completed": card_date}
                    )

        return stories
Esempio n. 43
0
    nucleos_tasks = wks.acell('G6').value
    it_tasks = wks.acell('G7').value
    planned_tasks = wks.acell('B%s' % (row_completed_tasks)).value
    wks.update_cell(2, 7, int(bernies_tasks) + members['Christian Bronstein'])
    wks.update_cell(3, 7, int(gonz_tasks) + members['Gonzalo Parra'])
    wks.update_cell(4, 7, int(lermits_tasks) + members['Lermit Rosell'])

    wks.update_cell(6, 7, int(nucleos_tasks) + labels['Nucleo'])
    wks.update_cell(7, 7, int(it_tasks) + labels['IT'])

    wks.update_cell(row_completed_tasks, 3, tasks)
    percentage = wks.acell('D%s' % (row_completed_tasks)).value
    return percentage, planned_tasks


origin = client.get_board(get_board_id('Origin'))
sprint = origin.get_list(get_list_id(origin, 'Done'))
sprint.fetch()
sprint_tasks = sprint.list_cards()
labels, members, task_count, tasks = get_sprint_info()
sprint_start_date = date.today()
sprint_close_date = sprint_start_date + timedelta(days=7)
sprint_lenght = "%s / %s" % (sprint_start_date, sprint_close_date)
percentage, planned_tasks = record_on_gsheets(sprint, tasks, members, labels)
#Send Slack Message
sc.api_call(
    "chat.postMessage",
    channel="#sprint",
    text=
    ":loudspeaker: *Atencion:* \nQueridos Originarios! Es _Benito_ otra vez.\nEsta vez quiero darles algunos datos del sprint pasado:\n completaron *%s* de *%s* tareas, lo que representa un *%s* del sprint.\n Estuvo bien, pero ser mejor, por ahora no me comere sus zapatos.\n_Happy Planning_ :dog:"
    % (task_count, planned_tasks, percentage))
Esempio n. 44
0
class TrelloBoardTestCase(unittest.TestCase):
    """
    Tests for TrelloClient API. Note these test are in order to
    preserve dependencies, as an API integration cannot be tested
    independently.
    """

    def setUp(self):
        self._trello = TrelloClient(os.environ['TRELLO_API_KEY'],
                                    token=os.environ['TRELLO_TOKEN'])
        for b in self._trello.list_boards():
            if b.name == os.environ['TRELLO_TEST_BOARD_NAME']:
                self._board = b
                break
        try:
            self._list = self._board.open_lists()[0]
        except IndexError:
            self._list = self._board.add_list('List')

    def _add_card(self, name, description=None):
        try:
            card = self._list.add_card(name, description)
            self.assertIsNotNone(card, msg="card is None")
            self.assertIsNotNone(card.id, msg="id not provided")
            self.assertEquals(card.name, name)
            return card
        except Exception as e:
            print(str(e))
            self.fail("Caught Exception adding card")

    def test40_add_card(self):
        name = "Testing from Python - no desc"
        card = self._add_card(name)

        self.assertIsNotNone(card.closed, msg="closed not provided")
        self.assertIsNotNone(card.url, msg="url not provided")

        card2 = self._trello.get_card(card.id)
        self.assertEqual(card.name, card2.name)

    def test41_add_card(self):
        name = "Testing from Python"
        description = "Description goes here"
        card = self._add_card(name, description)

        self.assertEquals(card.description, description)
        self.assertIsNotNone(card.closed, msg="closed not provided")
        self.assertIsNotNone(card.url, msg="url not provided")
        card.fetch()
        self.assertIsNotNone(card.member_id)
        self.assertIsNotNone(card.short_id)
        self.assertIsNotNone(card.list_id)
        self.assertIsNotNone(card.comments)
        self.assertIsNotNone(card.checklists)
        self.assertIsInstance(card.create_date, datetime)

    def test42_add_card_with_comments(self):
        name = "Card with comments"
        comment = "Hello World!"
        card = self._add_card(name)
        card.comment(comment)
        card.fetch(True)

        self.assertEquals(card.description, '')
        self.assertIsNotNone(card.closed, msg="closed not provided")
        self.assertIsNotNone(card.url, msg="url not provided")
        self.assertEquals(len(card.comments), 1)
        self.assertEquals(card.comments[0]['data']['text'], comment)

    def test43_delete_checklist(self):
        name = "Card with comments"
        card = self._list.add_card(name)
        card.fetch(True)

        name = 'Checklists'
        checklist = card.add_checklist(name,
                                       ['item1', 'item2'])
        self.assertIsNotNone(checklist, msg="checklist is None")
        self.assertIsNotNone(checklist.id, msg="id not provided")
        self.assertEquals(checklist.name, name)
        checklist.delete()
        card.delete()

    def test44_attach_url_to_card(self):
        name = "Testing from Python - url"
        card = self._add_card(name)

        card.attach(name='lwn', url='http://lwn.net/')
        card.fetch()
        self.assertEquals(card.badges['attachments'], 1)
        card.delete()

    def test52_get_cards(self):
        cards = self._board.get_cards()
        self.assertEquals(len(cards), 4)

        for card in cards:
            if card.name == 'Testing from Python':
                self.assertEqual(card.description, 'Description goes here')
            elif card.name == 'Testing from Python - no desc':
                self.assertEqual(card.description, '')
            elif card.name == 'Card with comments':
                self.assertEqual(card.description, '')
            else:
                self.fail(msg='Unexpected card found')

        self.assertIsInstance(self._board.all_cards(), list)
        self.assertIsInstance(self._board.open_cards(), list)
        self.assertIsInstance(self._board.closed_cards(), list)

    def test52_add_card_set_due(self):
        name = "Testing from Python"
        description = "Description goes here"
        card = self._list.add_card(name, description)

        # Set the due date to be 3 days from now
        today = datetime.today()
        day_detla = timedelta(3)
        due_date = today + day_detla
        card.set_due(due_date)
        expected_due_date = card.due
        # Refresh the due date from cloud
        card.fetch()
        actual_due_date = card.due[:10]
        self.assertEquals(expected_due_date, actual_due_date)
        # Note that set_due passes only the date, stripping time
        self.assertEquals(card.due_date.date(), due_date.date())

    def test53_checklist(self):
        name = "Testing from Python"
        description = "Description goes here"
        card = self._list.add_card(name, description)

        name = 'Checklists'
        checklist = card.add_checklist(name,
                                       ['item1', 'item2'])
        self.assertIsNotNone(checklist, msg="checklist is None")
        self.assertIsNotNone(checklist.id, msg="id not provided")
        self.assertEquals(checklist.name, name)
        checklist.rename('Renamed')
        self.assertEquals(checklist.name, 'Renamed')

    def test54_set(self):
        name = "Testing from Python"
        description = "Description goes here"
        card = self._list.add_card('noname')
        card.set_name(name)
        card.set_description(description)
        self.assertEquals(card.name, name)
        self.assertEquals(card.description, description)

    def test55_set_pos(self):
        card_names = lambda: [c.name for c in self._list.list_cards()]
        self._list.add_card('card1')
        card2 = self._list.add_card('card2')
        names = card_names()
        self.assertGreater(names.index('card2'), names.index('card1'))

        card2.set_pos('top')
        names = card_names()
        self.assertGreater(names.index('card1'), names.index('card2'))

        card2.set_pos('bottom')
        names = card_names()
        self.assertGreater(names.index('card2'), names.index('card1'))

    def test60_delete_cards(self):
        cards = self._board.get_cards()
        for card in cards:
            card.delete()

    def test70_all_members(self):
        self.assertTrue(len(self._board.all_members()) > 0)

    def test71_normal_members(self):
        self.assertTrue(len(self._board.normal_members()) >= 0)

    def test72_admin_members(self):
        self.assertTrue(len(self._board.admin_members()) > 0)

    def test73_owner_members(self):
        members = self._board.owner_members()
        self.assertTrue(len(members) > 0)
        member = members[0].fetch()
        self.assertNotEqual(member.status, None)
        self.assertNotEqual(member.id, None)
        self.assertNotEqual(member.bio, None)
        self.assertNotEqual(member.url, None)
        self.assertNotEqual(member.username, None)
        self.assertNotEqual(member.full_name, None)
        self.assertNotEqual(member.initials, None)
        member2 = self._trello.get_member(member.id)
        self.assertEqual(member.username, member2.username)

    def test80_unauthorized(self):
        client = TrelloClient('a')
        self.assertRaises(Unauthorized,
                          client.list_boards)

    def test81_resource_unavailable(self):
        self.assertRaises(ResourceUnavailable,
                          self._trello.get_card, '0')

    def test90_get_board(self):
        board = self._trello.get_board(self._board.id)
        self.assertEqual(self._board.name, board.name)
Esempio n. 45
0
def trelloToSQL():
    '''
    Liest Trello-Karten aus Liste "Texte lektoriert" des "Play-Boards" aus
    und wandelt Sie mit Pandoc in html um. Inklusive Literaturverzeichnis.
    Zusätzlich werden ein paar weitere Formatierungen vorgenommen.
    Das Ergebnis wird dann in die Datenbank geschrieben.
    Die Trello-Karten werden hinterher verschoben.
    '''
    from Scholien.models import Artikel

    client = TrelloClient(api_key=settings.TRELLO_API_KEY, token=settings.TRELLO_TOKEN)
    play_board = client.get_board('55d5dfee98d40fcb68fc0e0b')
    played_board = client.get_board('55c4665a4afe2f058bd3cb0a')
    target_list = played_board.get_list('5774e15c515d20dd2aa0b534')

    for list in play_board.open_lists():
        if list.name == "Texte lektoriert":
            print('%d lektorierte(n) Text(e) gefunden.' % len(list.list_cards()))
            # Karten werden von unten nach oben abgearbeitet.
            for card in list.list_cards()[::-1]:
                title = card.name
                text = card.desc
                fobj_out = codecs.open(os.path.join(md_path, "%s.md" % title), "w", "utf-8")
                # meta = codecs.open("%s" %meta,"r","utf-8")
                # fobj_out.write(meta.read())

                # ids
                p = re.compile(r"§§.*")
                id = p.findall(text)
                id = id[0][2:] if id else title
                priority = 1 if id[0] == '!' else 0
                id = slugify(id)
                text = p.sub("", text, count=1)

                fobj_out.write("---\nbibliography: {}\n---\n\n{}\n\n## Literatur".format(bib, text))
                fobj_out.close

                # to html
                fobj_out = codecs.open(os.path.join(md_path, "%s.md" % title), "r", "utf-8")
                md = fobj_out.read()
                extra_args = []
                filters = ['pandoc-citeproc']
                html = pypandoc.convert(md, 'html', format='md',  extra_args=extra_args, filters=filters)

                # blockquotes mit class versehen
                p = re.compile("<blockquote>")
                html = p.sub("<blockquote class=\"blockquote\">", html)

                # Gedankenstriche ("--" nach "–")
                p = re.compile("--")
                html = p.sub("&ndash;", html)

                # Trennungszeichen
                p = re.compile(r"<p>&lt;&lt;&lt;</p>")
                split = re.split(p, html)
                public = split[0]
                # lstrip entfernt mögliche Absätze am Anfang.
                private = split[1].lstrip() if len(split) > 1 else ""
                if not private:
                    print('Keinen privaten Teil gefunden für', title)
                    # print(html)

                try:
                    art_neu = Artikel.objects.create(
                        slug=id, bezeichnung=title, inhalt=public,
                        inhalt_nur_fuer_angemeldet=private, prioritaet=priority
                    )  # *art_neu* currently not in use
                    print('%s erfolgreich in DB übertragen.' % title)
                except IntegrityError as e:
                    print('Artikel schon vorhanden')
                except Exception as e:
                    print(title, 'failed:', e)
                    continue

                card.change_board(played_board.id, target_list.id)
                card.set_pos('top')
class TrelloList(object):
    """
    Sugar class to work with Trello Lists.
    """
    def __init__(self, board_id, list_id, api_key, token=None, **kwargs):
        """
        Validate inputs and connect to Trello API.
        Exception is thrown if input details are not correct.

        :param board_id: Trello board ID where the List is located
        :type board_id: ``str``

        :param list_id: Trello List ID itself
        :type list_id: ``str``

        :param api_key: Trello API key
        :type api_key: ``str``

        :param token: Trello API token
        :type token: ``str``
        """
        self.board_id = board_id
        self.list_id = list_id
        self.api_key = api_key
        # assume empty string '' as None
        self.token = token or None

        self.validate()

        self._client = TrelloClient(api_key=self.api_key, token=self.token)
        self._list = self._client.get_board(self.board_id).get_list(self.list_id)

    def validate(self):
        """
        Ensure that Trello list details are correct.
        Raise an exception if validation failed.
        """
        if not self.api_key:
            raise ValueError('[TrelloListSensor] "api_key" config value is required!')
        assert isinstance(self.api_key, basestring)

        if self.token:
            assert isinstance(self.token, basestring)

        if not self.board_id:
            raise ValueError('[TrelloListSensor]: "board_id" config value is required!')
        assert isinstance(self.board_id, basestring)

        if not self.list_id:
            raise ValueError('[TrelloListSensor]: "list_id" config value is required!')
        assert isinstance(self.list_id, basestring)

    @property
    def key_name(self):
        """
        Generate unique key name for built-in storage based on config values.

        :rtype: ``str``
        """
        return '{}.{}.date'.format(self.board_id, self.list_id)

    def fetch_actions(self, filter=None, since=None):
        """
        Fetch actions for Trello List with possibility to specify filters.
        Example API request:
        https://api.trello.com/1/lists/{list_id}/actions?filter=createCard&since=2015-09-14T21:45:56.850Z&key={key_id}&token={token_id}

        :param filter: Action types to filter, separated by comma or as a sequence.
        :type filter: ``str`` or ``list``

        :param since: Filter actions since specified date.
        :type since: ``str``

        :return: Events occurred in Trello list.
        :rtype: ``list`` of ``dict``
        """
        return self._client.fetch_json(
            '/lists/' + self._list.id + '/actions',
            query_params={
                'filter': filter,
                'since': since,
            })
Esempio n. 47
0
def main():
    parser = OptionParser(usage='Usage: %prog [options]')

    # look for the config file in ~/.trello.creds JSON
    # Should contain two keys
    #       api-key
    #       token
    default_config = os.path.expanduser('~')

    # TODO only shows Cards with a given Labels
    # TODO save current preferences into a config file (prefered board)
    # TODO build unit testing

    parser.add_option('-c',
                      dest='credentials',
                      help='location of the trello credential '
                      'json file (default ~/.trello.creds    ',
                      default="{}/.trello.creds".format(default_config))
    parser.add_option('-b',
                      '--list-boards',
                      dest='show_boards',
                      help='List all Boards available"',
                      action='store_true')
    parser.add_option('-B', dest='board', help='Active Board')
    parser.add_option('-l',
                      '--list-lanes',
                      dest='show_lanes',
                      help='List all Lanes available"',
                      action='store_true')
    parser.add_option('-L',
                      dest='lanes',
                      help='show only cards in lanes "Lane1,Lane2,Lane3"')
    parser.add_option('-m',
                      '--list-members',
                      dest='show_members',
                      help='List all members available',
                      action='store_true')
    parser.add_option('-s',
                      dest='show_labels',
                      help='show labels with cards',
                      action='store_true')
    parser.add_option('-M',
                      dest='members',
                      help='filter with a specific team member '
                      '(Names: coma separated list of names bob,sam,Luk all:'
                      'display everyone, none: display unassigned cards)')

    opts, args = parser.parse_args()

    try:
        with open(opts.credentials) as f:
            config = json.load(f)
            trello_api_key = config['api_key']
            trello_token = config['token']
    except (FileNotFoundError, json.JSONDecodeError):
        print('Trello Token information file {} '
              'could not be found or parsed.'.format(opts.credentials))
        print('')
        gather_token = input(
            "Do you want to entre your Trello token information now "
            "(see https://trello.com/app-key/) ? (Y/n) ")
        if gather_token == 'n':
            return 1
        trello_api_key = input('Please enter your Trello api key : ')
        trello_token = input('Please enter your Trello api token : ')
        save_token = input("Do you want to save those credentials for future "
                           "use of trello-cli? (Y/n) ")
        if save_token != 'n':
            try:
                data = {}
                data['api_key'] = trello_api_key
                data['token'] = trello_token
                with open(opts.credentials, 'w+') as f:
                    json.dump(data, (f))
            except (FileNotFoundError, json.JSONDecodeError):
                # TODO: Probably better error handling can be done here
                print("Something went wrong saving credentials")
                return 1

    the_boards = {}
    the_board_lanes = {}
    the_board_members = {}
    the_board_cards = []

    # TODO Catch error opening Trello here
    client = TrelloClient(api_key=trello_api_key, token=trello_token)

    # Get the list of boards available to current user
    for board in client.list_boards():
        the_boards[board.name] = board.id
        if opts.show_boards:
            print(board.name)

    # Exit after returning the board list
    if opts.show_boards:
        return 1

    # Pick the Active Board
    if opts.board:
        the_board = client.get_board(the_boards[opts.board])
    else:
        print("Active board missing, use -B \"Board Name\"")
        parser.print_help()
        return 0

    # Capture the board members in a dictionary
    for member in the_board.get_members():
        the_board_members[member.full_name] = member.id

    if opts.show_members:
        for name in the_board_members.keys():
            print(name)
        return 1

    if not opts.show_lanes and not opts.lanes:
        print("Missing lanes information")
        parser.print_help()
        return 1

    # Pick The Board Open Lanes
    for lane in the_board.get_lists('open'):
        if opts.show_lanes:
            print(lane.name)
        else:
            if opts.lanes:
                if lane.name in opts.lanes.split(","):
                    the_board_lanes[lane.name] = lane.id
            else:
                the_board_lanes[lane.name] = lane.id

    if opts.show_lanes:
        return 1

    # Capture all the cards from active lane into a dictionary
    for card in the_board.open_cards():
        if card.list_id in the_board_lanes.values():
            the_board_cards.append(card)

    # Simply show all the cards from said Lanes if no member selected
    if not opts.members:
        for lane in the_board_lanes:
            if the_board_cards:
                print("  {}".format(lane))
            drawCards(the_board_cards, opts.show_labels)
    elif opts.members.split(",")[0] == "none":
        for lane in the_board_lanes:
            card_list = []
            # Show the card only if nobody assigned to it
            # and the lane is in the list
            for card in list(
                    filter(
                        lambda x: len(x.member_id) == 0 and x.list_id ==
                        the_board_lanes[lane], the_board_cards)):
                card_list.append(card)
            if card_list:
                print("  {}".format(lane))
            drawCards(card_list, opts.show_labels)
    else:
        # Print active cards per member/lane
        for member in the_board_members:
            if opts.members.split(",")[0] == "all" or listInString(
                    opts.members, member):
                if list(
                        filter(
                            lambda x: the_board_members[member] in x.member_id,
                            the_board_cards)):
                    print(member)
                    for lane in the_board_lanes:
                        card_list = []
                        for card in list(
                                filter(
                                    lambda x: the_board_members[member] in x.
                                    member_id and x.list_id == the_board_lanes[
                                        lane], the_board_cards)):
                            card_list.append(card)
                        if card_list:
                            print("  {}".format(lane))
                        drawCards(card_list, opts.show_labels)
    return 0
Esempio n. 48
0
from fish import ProgressFish

## get the default browser
br = mechanize.Browser()
ua = ('Mozilla/5.0 (X11; U; Linux i686)'
                'Gecko/20071127 Firefox/2.0.0.11')
br.addheaders = [('User-Agent', ua)]
#br.set_debug_http(True)
#br.set_debug_responses(True)
#t_com = twill.commands
#t_brw = t_com.get_browser()

#Trello authentication
auth = TrelloClient(os.environ['TRELLO_API_KEY'], os.environ['TRELLO_TOKEN'])
gca_board = auth.get_board('4f199b088ab038761f17b066')
gca_lists = gca_board.all_lists()

total_sites = None
chapters_to_check = []
chapters_with_web_sites = []
for gca_list in gca_lists:
    #print gca_list.id, gca_list.name
    # we get the 'Chapters to Check' list
    # with id '4f199b088ab038761f17b06b'
    if gca_list.id == '4f199b088ab038761f17b06b':
        # get the cards
        cards = gca_list.list_cards()
        total_sites = len(cards)
        for i, c in enumerate(cards):
            # do something with the description and try to extract the website address
Esempio n. 49
0
class ServiceTrello(ServicesMgr):

    # Boards own Lists own Cards

    def __init__(self, token=None):
        # app name
        self.app_name = DjangoThConfig.verbose_name
        # expiration
        self.expiry = "30days"
        # scope define the rights access
        self.scope = 'read,write'

        base = 'https://www.trello.com'
        self.AUTH_URL = '{}/1/OAuthAuthorizeToken'.format(base)
        self.REQ_TOKEN = '{}/1/OAuthGetRequestToken'.format(base)
        self.ACC_TOKEN = '{}/1/OAuthGetAccessToken'.format(base)
        self.consumer_key = settings.TH_TRELLO['consumer_key']
        self.consumer_secret = settings.TH_TRELLO['consumer_secret']
        if token:
            token_key, token_secret = token.split('#TH#')
            self.trello_instance = TrelloClient(self.consumer_key,
                                                self.consumer_secret,
                                                token_key,
                                                token_secret)

    def read_data(self, token, trigger_id, date_triggered):
        """
            get the data from the service
            as the pocket service does not have any date
            in its API linked to the note,
            add the triggered date to the dict data
            thus the service will be triggered when data will be found
            :param trigger_id: trigger ID to process
            :param date_triggered: the date of the last trigger
            :type trigger_id: int
            :type date_triggered: datetime
            :return: list of data found from the date_triggered filter
            :rtype: list
        """
        data = list()
        cache.set('th_trello_' + str(trigger_id), data)

    def process_data(self, trigger_id):
        """
            get the data from the cache
            :param trigger_id: trigger ID from which to save data
            :type trigger_id: int
        """
        cache_data = cache.get('th_trello_' + str(trigger_id))
        return PublishingLimit.get_data('th_trello_', cache_data, trigger_id)

    def save_data(self, token, trigger_id, **data):
        """
            let's save the data

            :param trigger_id: trigger ID from which to save data
            :param **data: the data to check to be used and save
            :type trigger_id: int
            :type **data:  dict
            :return: the status of the save statement
            :rtype: boolean
        """
        from th_trello.models import Trello

        title = ''
        content = ''
        status = False

        title = self.set_card_title(data)
        content = self.set_card_content(data)

        if len(title):
            # get the data of this trigger
            t = Trello.objects.get(trigger_id=trigger_id)

            # 1 - we need to search the list and board where we will
            # store the card so ...

            # 1.a search the board_id by its name
            # by retreiving all the boards
            boards = self.trello_instance.list_boards()

            board_id = ''
            my_board = ''
            my_list = ''
            for board in boards:
                if t.board_name == board.name.decode('utf-8'):
                    board_id = board.id
                    break

            if board_id:
                # 1.b search the list_id by its name
                my_board = self.trello_instance.get_board(board_id)
                lists = my_board.open_lists()
                # just get the open list ; not all the archive ones
                for list_in_board in lists:
                    # search the name of the list we set in the form
                    if t.list_name == list_in_board.name.decode('utf-8'):
                        # return the (trello) list object
                        # to be able to add card at step 3
                        my_list = my_board.get_list(list_in_board.id)
                        break
                # we didnt find the list in that board
                # create it
                if my_list == '':
                    my_list = my_board.add_list(t.list_name)

            else:
                # 2 if board_id and/or list_id does not exist, create it/them
                my_board = self.trello_instance.add_board(t.board_name)
                # add the list that didnt exists and
                # return a (trello) list object
                my_list = my_board.add_list(t.list_name)

            # 3 create the card
            # create the Trello card
            my_list.add_card(title, content)

            sentance = str('trello {} created').format(data['link'])
            logger.debug(sentance)
            status = True
        else:
            sentance = "no token or link provided for trigger ID {}"
            logger.critical(sentance.format(trigger_id))
            status = False

        return status

    def set_card_title(self, data):
        """
            handle the title from the data
        """
        title = ''
        # if no title provided, fallback to the URL which should be provided
        # by any exiting service
        title = (data['title'] if 'title' in data else data['link'])
        return title

    def set_card_content(self, data):
        """
            handle the content from the data
        """
        content = ''
        if 'content' in data:
            if type(data['content']) is list or type(data['content']) is tuple\
               or type(data['content']) is dict:
                if 'value' in data['content'][0]:
                    content = data['content'][0].value
            else:
                if type(data['content']) is str:
                    content = data['content']
                else:
                    # if not str or list or tuple
                    # or dict it could be feedparser.FeedParserDict
                    # so get the item value
                    content = data['content']['value']

        elif 'summary_detail' in data:
            if type(data['summary_detail']) is list or\
               type(data['summary_detail']) is tuple or\
               type(data['summary_detail']) is dict:
                if 'value' in data['summary_detail'][0]:
                    content = data['summary_detail'][0].value
            else:
                if type(data['summary_detail']) is str:
                    content = data['summary_detail']
                else:
                    # if not str or list or tuple
                    # or dict it could be feedparser.FeedParserDict
                    # so get the item value
                    content = data['summary_detail']['value']

        elif 'description' in data:
            content = data['description']

        return content

    def auth(self, request):
        """
            let's auth the user to the Service
        """
        callback_url = 'http://%s%s' % (
            request.get_host(), reverse('trello_callback'))

        request_token = self.get_request_token()

        # Save the request token information for later
        request.session['oauth_token'] = request_token['oauth_token']
        request.session['oauth_token_secret'] = request_token[
            'oauth_token_secret']

        # URL to redirect user to, to authorize your app
        auth_url_str = '{auth_url}?oauth_token={token}&scope={scope}&name={name}'
        auth_url_str += '&expiration={expiry}&oauth_callback={callback_url}'
        auth_url = auth_url_str.format(auth_url=self.AUTH_URL,
                                       token=request_token['oauth_token'],
                                       scope=self.scope,
                                       name=self.app_name,
                                       expiry=self.expiry,
                                       callback_url=callback_url)

        return auth_url

    def callback(self, request):
        """
            Called from the Service when the user accept to activate it
        """

        try:
            # finally we save the user auth token
            # As we already stored the object ServicesActivated
            # from the UserServiceCreateView now we update the same
            # object to the database so :
            # 1) we get the previous objet
            us = UserService.objects.get(
                user=request.user,
                name=ServicesActivated.objects.get(name='ServiceTrello'))
            # 2) Trello API require to use 4 parms consumer_key/secret +
            # token_key/secret instead of usually get just the token
            # from an access_token request. So we need to add a string
            # seperator for later use to slpit on this one
            access_token = self.get_access_token(
                request.session['oauth_token'],
                request.session['oauth_token_secret'],
                request.GET.get('oauth_verifier', '')
            )
            us.token = access_token.get('oauth_token') + \
                '#TH#' + access_token.get('oauth_token_secret')
            # 3) and save everything
            us.save()
        except KeyError:
            return '/'

        return 'trello/callback.html'

    def get_request_token(self):
        oauth = OAuth1Session(self.consumer_key,
                              client_secret=self.consumer_secret)
        return oauth.fetch_request_token(self.REQ_TOKEN)

    def get_access_token(self, oauth_token, oauth_token_secret,
                         oauth_verifier):
        # Using OAuth1Session
        oauth = OAuth1Session(self.consumer_key,
                              client_secret=self.consumer_secret,
                              resource_owner_key=oauth_token,
                              resource_owner_secret=oauth_token_secret,
                              verifier=oauth_verifier)
        oauth_tokens = oauth.fetch_access_token(self.ACC_TOKEN)

        return oauth_tokens
Esempio n. 50
0
class EClaire(object):

    def __init__(self, credentials, boards=None):
        self.trello_client = TrelloClient(
            api_key=credentials['public_key'],
            token=credentials['member_token'],
        )

        self.boards = boards

    def process_boards(self, dry_run=False, notify_fn=None, notify_config=None):
        """
        Process each board in self.boards
        """

        for name, board_config in self.boards.iteritems():
            log.info('Polling %s', name)
            processed = self.process_board(board_config, dry_run)

            if board_config.get('notify', True) and notify_fn is not None:
                for card in processed:
                    notify_fn(card, **notify_config)

    def process_board(self, board_config, dry_run=False):
        """
        Process each card in a given board
        """
        processed = []
        for card in self.fetch_cards(board_id=board_config['id']):
            log.info('Printing card "%s"', card.name)

            pdf = generate_pdf(card)
            if not dry_run:
                print_card(pdf, printer_name=board_config['printer'])
            self.update_card(card, board_config)
            processed.append(card)

        return processed

    def fetch_cards(self, board_id):
        """
        Fetch all candidate cards on a board for processing
        """
        data = []
        board = self.trello_client.get_board(board_id)
        for card in board.all_cards():
            if FILTER_LABEL in [l.name for l in card.labels]:
                card.fetch_actions()
                data.append(card)

        return data

    def discover_labels(self):
        """
        Store object references for special labels
        """
        for name, config in self.boards.iteritems():
            board = self.trello_client.get_board(config['id'])
            labels = {}
            for label in board.get_labels(limit=100):
                if label.name in SPECIAL_LABELS:
                    labels[label.name] = label
            missing = set(SPECIAL_LABELS) - set(labels.keys())
            if missing:
                log.fatal(
                    'Board "%s" is missing the labels %s',
                    board.name,
                    ' and '.join(missing)
                    )
                log.fatal('Exiting')
                sys.exit(1)
            config['labels'] = labels

    def remove_label(self, card, label):
        """
        Remove a lable from a card.

        At the time of writing there is no way to remove a label with py-trello
        """
        self.trello_client.fetch_json(
            '/cards/' + card.id + '/idLabels/' + label.id,
            http_method="DELETE"
        )

    def update_card(self, card, board_config):
        """
        Replace PRINTME label with PRINTED
        """
        printme_label = board_config['labels']['PRINTME']
        printed_label = board_config['labels']['PRINTED']

        self.remove_label(card, printme_label)

        if printed_label not in card.labels:
            card.add_label(printed_label)

    def list_boards(self):
        """
        Fetch all board IDs from trello & print them out
        """
        for board in self.trello_client.list_boards():
            print 'Board:', board.name
            print '   ID:', board.id
            print
Esempio n. 51
0
class TrelloPlugin(DIBasePlugin, DIPluginDashboardMixin):

    platform = "trello"
    platform_url = "http://www.trello.com/"

    #created for "create" actions
    #added for "add" actions
    #updated for "update" actions
    #commented for card "comment" actions
    xapi_verbs = ['created', 'added', 'updated', 'commented', 'closed', 'opened']

    #Note for "commented" actions
    #Task for "created", "added", "updated", and "commented" actions
    #Collection for any "created", "added", "updated" List actions (tentative use)
    xapi_objects = ['Note', 'Task', 'Collection', 'Person', 'File', 'checklist-item', 'checklist']

    user_api_association_name = 'Trello UID' # eg the username for a signed up user that will appear in data extracted via a social API
    unit_api_association_name = 'Board ID' # eg hashtags or a group name

    config_json_keys = ['consumer_key', 'consumer_secret']

    #from DIPluginDashboardMixin
    xapi_objects_to_includein_platformactivitywidget = ['Note']
    xapi_verbs_to_includein_verbactivitywidget = ['created', 'shared', 'liked', 'commented']

    #for OAuth1 authentication
    token_request_url = ''

    def __init__(self):
       pass

    #retreival param is the user_id
    def perform_import(self, retreival_param, course_code, token=None):
        #from clatoolkit.models import ApiCredentials
        #Set up trello auth and API
        #self.usercontext_storage_dict = json.load(ApiCredentials.objects.get(platform=retreival_param).credentials_json)

        self.TrelloCient = TrelloClient(
            api_key=os.environ.get("TRELLO_API_KEY"),
            #api_secret=self.api_config_dict['api_secret'],
            token=token
        )

        #Get user-registered board in trello
        trello_board = self.TrelloCient.get_board(retreival_param)

        #Get boards activity/action feed
        trello_board.fetch_actions('all') #fetch_actions() collects actions feed and stores to trello_board.actions

        #self.key = trello_board.api_key
        #self.token = trello_board.resource_owner_key

        self.import_TrelloActivity(trello_board.actions, course_code)

    def import_TrelloActivity(self, feed, course_code):
        #User needs to sign up username and board (board can be left out but is needed)
        #TODO: RP
        print 'Beginning trello import!'

        for action in list(feed):
            #print 'action: %s' % (action)
            #action = json.load(action)

            #We need to connect this with our user profile somewhere when they initially auth
            u_id = action['idMemberCreator']
            author = action['memberCreator']['username']
            type = action['type'] #commentCard, updateCard, createList,etc
            data = action['data']
            date = action['date']
            board_name = data['board']['name']

            print 'got action type: %s' % (type)

            #print 'is action comment? %s' % (type == 'commentCard')
            #Get all 'commented' verb actions
            if (type == 'commentCard'):
                #do stuff
                target_obj_id = data['card']['id']
                #date
                comment_from_uid = u_id
                comment_from_name = author
                comment_message = data['text']
                comment_id = action['id']

                if username_exists(comment_from_uid, course_code, self.platform):
                    usr_dict = get_userdetails(comment_from_uid, self.platform)
                    insert_comment(usr_dict, target_obj_id, comment_id,
                                   comment_message, comment_from_uid,
                                   comment_from_name, date, course_code,
                                   self.platform, self.platform_url)
                    print 'Inserted comment!'

            #print 'is action card creation? %s' % (type == 'createCard')
            #Get all 'create' verb actions
            if (type == 'createCard'): #, 'createList']):
                #date
                #list_id = data['list']['id']
                task_id = data['card']['id']
                task_name = data['card']['name']

                if username_exists(u_id, course_code, self.platform):
                    usr_dict = get_userdetails(u_id, self.platform)
                    insert_task(usr_dict, task_id, task_name, u_id, author, date,
                                course_code, self.platform, self.platform_url) #, list_id=list_id)

                    #TODO: RP
                    print 'Inserted created card!'


            #Get all 'add' verbs (you tecnically aren't *creating* an attachment on
            #a card so....)
            #print 'is action an add event? %s' % (type in
            #    ['addAttachmentToCard', 'addMemberToBoard',
            #     'emailCard', 'addChecklistToCard'
            #     , 'addMemberToCard'])
            if (type in
                ['addAttachmentToCard', 'addMemberToBoard',
                 'emailCard', 'addChecklistToCard'
                 , 'addMemberToCard']):

                usr_dict = None
                if username_exists(u_id, course_code, self.platform):
                    usr_dict = get_userdetails(u_id, self.platform)

                if type is 'addAttachmentToCard' and usr_dict is not None:

                    target_id = data['card']['id']
                    attachment = data['attachment']
                    attachment_id = attachment['id']
                    attachment_data = '%s - %s' % (attachment['name'], attachment['url'])
                    object_type = 'File'
                    shared_displayname = '%sc/%s' % (self.platform_url, target_id)

                    insert_added_object(usr_dict, target_id, attachment_id, attachment_data,
                                        u_id, author, date, course_code, self.platform, self.platform_url,
                                        object_type, shared_displayname=shared_displayname)

                    #TODO: RP
                    print 'Added attachment!'

                if type is 'addMemberToCard' and usr_dict is not None: #or 'addMemberToBoard':

                    target_id = data['card']['id']
                    object_id = data['idMember']
                    object_data = action['memeber']['username']
                    object_type = 'Person'
                    shared_displayname = '%sc/%s' % (self.platform_url, target_id)

                    insert_added_object(usr_dict, target_id, object_id, object_data, u_id, author, date,
                                        course_code, self.platform, self.platform_url, object_type,
                                        shared_displayname=shared_displayname)

                    #TODO: RP
                    print 'Added add member to card!'

                if type is 'addChecklistToCard' and usr_dict is not None:

                    target_id = data['card']['id']
                    object_id = data['idMember']
                    object_data = None
                    checklist_items = None
                    object_type = 'Collection'
                    shared_displayname = '%sc/%s' % (self.platform_url, target_id)

                    #get checklist contents
                    try:
                        checklist = self.TrelloCient.fetch_json('/checklists/' + data['checklist']['id'],)
                        checklist_items = checklist['checkItems']
                    except Exception:
                        print 'Could not retrieve checklist..'

                    #data will be a comma separated list of checklist-item ids (e.g.: 'id1,id2,id3...')
                    object_data = ','.join([item['id'] for item in checklist_items])

                    insert_added_object(usr_dict, target_id, object_id, object_data, u_id, author, date,
                                        course_code, self.platform, self.platform_url, object_type,
                                        shared_displayname=shared_displayname)

                    #TODO: RP
                    print 'added add checklist to card!'


            #print 'is action type an update? %s' % (type in
            #    ['updateCheckItemStateOnCard', 'updateBoard',
            #     'updateCard', 'updateCheckList',
            #     'updateList', 'updateMember'])
            #Get all 'updated' verbs
            if (type in
                ['updateCheckItemStateOnCard', 'updateBoard',
                 'updateCard', 'updateCheckList',
                 'updateList', 'updateMember']):

                usr_dict = None
                if username_exists(u_id, course_code, self.platform):
                    usr_dict = get_userdetails(u_id, self.platform)

                #many checklist items will be bugged - we require webhooks!

                if type == 'updateCheckItemStateOnCard' and usr_dict is not None:

                    insert_updated_object(usr_dict,
                                          data['checkItem']['id'],
                                          data['checkItem']['state'],
                                          u_id, author, date, course_code,
                                          self.platform, self.platform_url,
                                          'checklist-item', obj_parent=data['checklist']['id'],
                                          obj_parent_type='checklist')
                    #TODO: RP
                    print 'add update checklist!'



                #type will only show 'updateCard'
                #up to us to figure out what's being updated
                if type == 'updateCard':
                    #TODO: Remove Print
                    print 'data: %s' % (data)

                    #Get and store the values that were changed, usually it's only one
                    #TODO: Handle support for multiple changes, if that's possible
                    try:
                        change = [changed_value for changed_value in data['old']]
                    except Exception:
                       print 'Error occurred getting changes...'
                    #assert len(change) is 1

                    #TODO: Remove Print
                    print 'got changes: %s' % (change)

                    #Insert all updates that aren't closed
                    if change[0] == 'pos':
                        if 'listBefore' in data:
                            insert_updated_object(usr_dict, data['card']['id'],
                                                  'Move card from %s to %s' % (data['listBefore']['name'], data['listAfter']['name']),
                                                  u_id, author, date, course_code,
                                                  self.platform, self.platform_url,
                                                  'Task', obj_parent=data['list']['name'],
                                                  obj_parent_type='Collection')
                        else:
                            insert_updated_object(usr_dict, data['card']['id'],
                                                  'Move card from %s to %s' % (data['old']['pos'], data['card']['pos']),
                                                  u_id, author, date, course_code,
                                                  self.platform, self.platform_url,
                                                  'Task', obj_parent=data['list']['name'],
                                                  obj_parent_type='Collection')
                        #TODO: RP
                        print 'added closed card!'
                    #add in close/open verbs
                    else:
                        if data['old'][change[0]] is False:
                            insert_closedopen_object(usr_dict, data['card']['id'],
                                                 '%s:%s' % ('Closed', data['card']['name']),
                                                 u_id, author, date, course_code,
                                                 self.platform, self.platform_url,
                                                 'Task', 'closed', obj_parent=data['list']['name'],
                                                 obj_parent_type='Collection')

                            #TODO: RP
                            print 'added closed/opened card!'

                        elif data['old'][change[0]] is True:
                            insert_closedopen_object(usr_dict, data['card']['id'],
                                                 '%s:%s' % ('Opened', data['card']['name']),
                                                 u_id, author, date, course_code,
                                                 self.platform, self.platform_url,
                                                 'Task', 'opened', obj_parent=data['list']['name'],
                                                 obj_parent_type='Collection')

                            #TODO: RP
                            print 'added closed/opened card!'

    def get_verbs(self):
        return self.xapi_verbs
            
    def get_objects(self):
        return self.xapi_objects
    get_trello_list = partial(get_trello_list_from_name,
                              api=api,
                              board=board,
                              list_id_lookup=list_id_lookup)

    done_today = get_trello_list(name='Done today')
    tomorrow = get_trello_list(name='Tomorrow')
    waiting_on = get_trello_list(name='Waiting on')
    in_progress = get_trello_list(name='In progress')

    print_cards_from_list(done_today, 'x')
    print_cards_from_list(in_progress, '-')
    print_cards_from_list(tomorrow, ' ')
    print_cards_from_list(waiting_on, '-')


if __name__ == '__main__':
    load_dotenv()
    client = TrelloClient(api_key=os.getenv('TRELLO_API_KEY'),
                          token=os.getenv('TRELLO_TOKEN'),
                          token_secret=os.getenv('TRELLO_TOKEN_SECRET'))
    my_week = client.get_board(os.getenv('BOARD_ID'))
    list_ids = {
        'Waiting on': os.getenv('LIST_WAITING_ON_ID'),
        'Done today': os.getenv('LIST_DONE_TODAY_ID'),
        'Tomorrow': os.getenv('LIST_TOMORROW_ID'),
        'In progress': os.getenv('LIST_INPROGRESS_ID'),
    }
    print('# {}'.format(DATE))
    main_print(client, my_week, list_ids)
Esempio n. 53
0
class TrelloAPI():
    """
    docstring
    """
    def __init__(self):
        """
        docstring
        """
        self._api_key = None
        self._token = None
        result = self._GetFile()
        self._SetAPIKeyToken(result)
        self._client = None
        self._TrelloClientAccess()
        self._board = []
        self._doing_list = []
        self._cards = []

    def _TrelloClientAccess(self):
        """
        docstring
        """
        self._client = TrelloClient(
            api_key=self._api_key,
            api_secret=self._token,
        )

    def _GetFile(self, path="../../mine/Token.txt"):
        """
        docstring
        """
        with open(path, encoding="utf-8") as target:
            result = target.readlines()
            result = list(map(lambda i: i.rstrip("\n"), result))
            return result

    def _SetAPIKeyToken(self, files):
        """
        docstring
        """
        self._api_key, self._token = files

    def _GetBookList(self):
        path = self._GetFile("../../mine/list.txt")
        self._doing_list = self._client.get_list(path[0])
        # print(self._doing_list.name)

    def _GetBoardList(self):
        path = self._GetFile("../../mine/Borad.txt")
        self._board = self._client.get_board(path[0])

    def _GetCardslist(self):
        self._cards = self._board.get_cards()

    def _GetDoingBookList(self):
        self._GetBookList()
        self._GetBoardList()
        self._GetCardslist()
        result = {}
        for i in self._cards:
            if i.list_id == self._doing_list.id:
                result[i.name.replace("\u3000", " ")] = i
        return result

    def _AddDoingBookList(self, book_name):
        self._GetBookList()
        self._GetBoardList()
        result = self._doing_list.add_card(book_name)
        dt = datetime.date.today()
        result.comment("READ START " + dt.strftime("%Y-%m-%d"))
        # print(self._doing_list)
        return True if result is not None else False

    def _AddResult(self, result):
        """
        everyday :daily doing  today check list add 
        book : move done book_name end read date
        """
        if result["today"]:
            pass
        if result["time"]:
            pass
        if result["finish"]:
            pass
        pass

    def _AddEveryday(self):
        pass

    def _MoveBookIsDone(self):
        pass

    def _MoveCard(self, ):
        """
        docstring
        """
        raise NotImplementedError
class TrelloListSensor(PollingSensor):
    """
    Sensor which monitors Trello list for a new actions (events).

    For reference see Trello API Docs:
    https://trello.com/docs/api/list/index.html#get-1-lists-idlist-actions
    """
    TRIGGER = 'trello.new_action'

    def __init__(self, sensor_service, config=None, poll_interval=None):
        """
        Set defaults and validate YAML config metadata.
        """
        super(TrelloListSensor, self).__init__(sensor_service, config, poll_interval)
        self._logger = self._sensor_service.get_logger(__name__)

        list_actions_sensor = self._config.get('list_actions_sensor')
        if not list_actions_sensor:
            raise ValueError('[TrelloListSensor]: "list_sensor" config value is required!')

        self._board_id = list_actions_sensor.get('board_id')
        if not self._board_id:
            raise ValueError('[TrelloListSensor]: "list_sensor.board_id" config value is required!')
        assert isinstance(self._board_id, basestring)

        self._list_id = list_actions_sensor.get('list_id')
        if not self._list_id:
            raise ValueError('[TrelloListSensor]: "list_sensor.list_id" config value is required!')
        assert isinstance(self._list_id, basestring)

        self._client = None

    @property
    def key_name(self):
        """
        Generate unique key name for built-in storage based on config values.

        :rtype: ``str``
        """
        return '{}.{}.date'.format(self._board_id, self._list_id)

    def setup(self):
        """
        Initiate connection to Trello API.
        """
        self._client = TrelloClient(api_key=self._config.get('api_key'),
                                   token=self._config.get('token') or None)

    def poll(self):
        """
        Fetch latest actions for Trello List, filter by type.
        Start reading feed where we stopped last time
        by passing `since` date parameter to Trello API.
        Save latest event `date` in st2 key-value storage.
        """
        _list = self._client.get_board(self._board_id).get_list(self._list_id)
        monkey_patch_trello(_list)
        _list.fetch_actions(
            action_filter=self._config['list_actions_sensor'].get('filter') or None,
            filter_since=self._sensor_service.get_value(self.key_name)
        )

        for action in reversed(_list.actions):
            self._sensor_service.dispatch(trigger=self.TRIGGER, payload=action)
            if is_date(action.get('date')):
                self._sensor_service.set_value(self.key_name, action.get('date'))

    def cleanup(self):
        """
        Run the sensor cleanup code (if any).
        """
        pass

    def add_trigger(self, trigger):
        """
        Runs when trigger is created
        """
        pass

    def update_trigger(self, trigger):
        """
        Runs when trigger is updated
        """
        pass

    def remove_trigger(self, trigger):
        """
        Runs when trigger is deleted
        """
        pass