def get(self, request, *args, **kwargs): if 'task_id' in kwargs: task = get_task_by_id(kwargs['task_id']) else: return Http404('Wrong reqest') task = get_task_by_id(kwargs['task_id']) if not task: return Http404('Task not found') task.is_completed = True task.save() try: client = TrelloClient( api_key=request.user.profile.trello_api_key, api_secret=request.user.profile.trello_api_secret) desc = client.get_board(task.trello_id_board) except: return Http404('Wrong reqest') # или тут -2 будет right_list = desc.list_lists()[-2] card = client.get_card(task.trello_id_card) card.change_list(right_list.id) return HttpResponse('OK')
def uncomplete_task_trello(task, owner): prof = Profile.objects.get(user=owner) #получаем профайл пользователя key = prof.trello_key #из профайла достаем ключ token = prof.trello_token client = TrelloClient(api_key=key, api_secret=token) card = client.get_card(task.trello_id) board = client.get_board(task.trello_board_id) card.change_list(board.list_lists()[0].id)
def delete_from_trello(self): api_key = settings.TRELLO_KEY secret = settings.TRELLO_SECRET token = settings.TRELLO_TOKEN id = self.trello_id c = TrelloClient(api_key, secret, token) card = c.get_card(id) try: card.set_closed(True) except Exception: pass
def delete_trello_card(trello_card_id): """ Delete (forever) a Trello Card by ID :trello_card_id: Trello card ID """ trello_client = TrelloClient(api_key=trello_api_key, api_secret=trello_api_secret, token=trello_token, token_secret=trello_token_secret) try: trello_card = trello_client.get_card(trello_card_id) trello_card.delete() except Exception: print('Cannot find Trello card with ID {0} deleted in Task Warrior. Maybe you deleted it in Trello too.'.format(trello_card_id))
def main(): """Main application method.""" # Check for keys trello_key = environ.get('TRELLO_KEY') trello_token = environ.get('TRELLO_TOKEN') if not trello_key: print("ERROR: Missing environment variable TRELLO_KEY") return if not trello_token: print("ERROR: Missing environment variable TRELLO_TOKEN") return # Get arguments args = ask_arguments() # Create client print("Connecting to Trello") client = TrelloClient(api_key=trello_key, token=trello_token) folder = basename(args.folder) files = [f for f in listdir(args.folder) if isfile(join(args.folder, f))] print("Creating checklist for %d files" % len(files)) client.get_card(args.card).add_checklist(folder, sorted(files))
def complete_task(request, uid): t = TodoItem.objects.get(id=uid) t.is_completed = True t.save() if t.TRELLO_ID: key = request.user.profile.key secret = request.user.profile.token client = TrelloClient(key, secret) card = client.get_card(t.TRELLO_ID) board_id = card.board_id board = client.get_board(board_id) card.change_list(board.list_lists()[-1].id) messages.success(request, "Задача выполнена") return HttpResponse("OK")
def delete_trello_card(trello_card_id): """ Delete (forever) a Trello Card by ID :trello_card_id: Trello card ID """ trello_client = TrelloClient(api_key=trello_api_key, api_secret=trello_api_secret, token=trello_token, token_secret=trello_token_secret) try: trello_card = trello_client.get_card(trello_card_id) trello_card.delete() except Exception: print( 'Cannot find Trello card with ID {0} deleted in Task Warrior. Maybe you deleted it in Trello too.' .format(trello_card_id))
def complete_task(request, uid): print("Enter") t = TodoItem.objects.get(id=uid) t.is_completed = True t.save() print("Save") # Trello print(t.id_trello) client = TrelloClient(api_key=request.user.profile.api_key, api_secret=request.user.profile.api_secret) print(client) card = client.get_card(t.id_trello) print(card.id, card.idList, card.idBoard) # Board = client.get_board(card.idBoard) list = client.get_board(card.idBoard).list_lists()[-1] # list = client.get_board(card.idBoard) card.change_list(list.id) # card.change_list(untitled_board.list_lists()[1].id) return HttpResponse("OK")
def lambda_handler(event, context): # Trello Client client = TrelloClient(api_key=os.environ["trello_api_key"], api_secret=os.environ["trello_token"]) try: # イベント管理クラス tr_event = te.TrelloEvent(event) # デバッグ用 target_card = client.get_card(tr_event.get_card_id()) # Scrumに必要な作業を管理 scrum = sc.Scrum(client, tr_event) scrum.stamping(True) scrum.request_slack() scrum.move_story_to_task() except Exception as e: # デバッグ用 t, v, tb = sys.exc_info() target_card.comment(f"{e}\n{'>'.join(traceback.format_tb(tb))}") return return_context(f"{e}\n{traceback.format_tb(tb)}") return return_context("Succeed: Normal Exit")
class TrelloToPivotal: def __init__(self, project_id, board_id, api_key, trello_token, pivotal_token, redis_client): self.trello_board = board_id self.pivotal_project = project_id self.trello_key = api_key self.trello_token = trello_token self.pivotal_token = pivotal_token self.trello_client = TrelloClient( api_key=self.trello_key, token=self.trello_token, ) self.redis_client = redis_client def call_trello_api(self): """ This function call trello api and return list of dictionaries, where each dictionary is story from board :return: """ params = {'key': self.trello_key, 'token': self.trello_token} response = requests.get( 'https://api.trello.com/1/boards/{}/cards'.format( self.trello_board), params=params) return response.json() def create_card(self, list_name, card_title): payload = {'name': card_title, 'current_state': list_name} headers = { 'X-TrackerToken': self.pivotal_token, 'Content-type': 'application/json', 'Accept': 'application/json' } response = requests.post( 'https://www.pivotaltracker.com/services/v5/projects/{}/stories'. format(self.pivotal_project), data=json.dumps(payload), headers=headers).json() return response['id'] def delete_card(self, pivotal_story_id): headers = { 'X-TrackerToken': self.pivotal_token, 'Content-type': 'application/json', 'Accept': 'application/json' } response = requests.delete( 'https://www.pivotaltracker.com/services/v5/projects/{}/stories/{}' ''.format(self.pivotal_project, int(pivotal_story_id)), headers=headers) logger.info('Pivotal story with {} id is deleted\n{}'.format( pivotal_story_id, response)) def update_card(self, pivotal_story_id, action): data = action['data'] old = data['old'] card = data['card'] old_field = list(old.items())[0][0] payload = {} if old_field == 'name': # card-name.json new_name = card['name'] payload = {'name': new_name} if old_field == 'idList': # card-list.json new_state = data['listAfter']['name'] payload = {'current_state': new_state} if new_state == 'started' or new_state == 'finished' or new_state == 'delivered': due_date = self.trello_client.get_card( card_id=card['id']).due_date now = datetime.datetime.now() if due_date.day - now.day == 0: payload.update({"estimate": 0}) if due_date.day - now.day == 1: payload.update({"estimate": 0}) if due_date.day - now.day == 2: payload.update({"estimate": 1}) if due_date.day - now.day == 3: payload.update({"estimate": 2}) if due_date.day - now.day == 4: payload.update({"estimate": 2}) if due_date.day - now.day > 4: payload.update({"estimate": 3}) if old_field == 'desc': # card-desc.json new_desc = card['desc'] payload = {'description': new_desc} if old_field == 'due': # card-due.json payload = {} trello = self.trello_client card_id = card['id'] card_t = trello.get_card(card_id) due = card_t.due_date if not due: payload = {'estimate': 0} else: due_date = due.day now = datetime.datetime.now() if due_date - now.day == 0: payload = {'estimate': 0} if due_date - now.day == 1: payload = {'estimate': 0} if due_date - now.day == 2: payload = {'estimate': 1} if due_date - now.day == 3: payload = {"estimate": 2} if due_date - now.day == 4: payload = {'estimate': 2} if due_date - now.day > 4: payload = {'estimate': 3} if old_field == 'closed': # card-archive.json self.delete_card(pivotal_story_id) return headers = { 'X-TrackerToken': self.pivotal_token, 'Content-type': 'application/json', 'Accept': 'application/json' } response = requests.put( 'https://www.pivotaltracker.com/services/v5/projects/{}/stories/{}' ''.format(self.pivotal_project, int(pivotal_story_id)), data=json.dumps(payload), headers=headers).json() logger.info('Pivotal story with {} id is updated\n{}'.format( pivotal_story_id, response)) def add_label_to_card(self, pivotal_story_id, card_id): labels = self.trello_client.get_card(card_id=card_id).labels label_names = [i.name for i in labels] payload = {'labels': label_names} headers = { 'X-TrackerToken': self.pivotal_token, 'Content-type': 'application/json', 'Accept': 'application/json' } response = requests.put( 'https://www.pivotaltracker.com/services/v5/projects/{}/stories/{}' ''.format(self.pivotal_project, int(pivotal_story_id)), data=json.dumps(payload), headers=headers).json() logger.info('Pivotal story label with {} id is updated\n{}'.format( pivotal_story_id, response)) def update_label(self, pivotal_story_id, action): data = action['data'] old = data['old'] card = data['card'] old_field = list(old.items())[0][0] if old_field == 'name': # card-name.json labels = self.trello_client.get_card(card_id=card['id']).labels label_names = [i.name for i in labels] payload = {'labels': label_names} headers = { 'X-TrackerToken': self.pivotal_token, 'Content-type': 'application/json', 'Accept': 'application/json' } response = requests.put( 'https://www.pivotaltracker.com/services/v5/projects/{}/stories/{}' ''.format(self.pivotal_project, int(pivotal_story_id)), data=payload, headers=headers).json() logger.info('Pivotal story label with {} id is updated\n{}'.format( pivotal_story_id, response or 'color')) def initialize_board(self): trello_stories = self.call_trello_api() params = {'key': self.trello_key, 'token': self.trello_token} id_couples = [] for card in trello_stories: if not self.redis_client.get(card['id'] + "_created"): name = card['name'] description = card['desc'] label = [i['name'] for i in card['labels']] status = requests.get('https://trello.com/1/lists/{}'.format( card['idList']), params=params) list_name = status.json()['name'] due = card['due'] payload = { 'name': name, 'description': description, 'labels': label, 'current_state': list_name } if due: due_date = datetime.datetime.strptime( due, "%Y-%m-%dT%H:%M:%S.%fZ").day now = datetime.datetime.now() if due_date - now.day == 0: payload.update({'estimate': 0}) if due_date - now.day == 1: payload.update({'estimate': 0}) if due_date - now.day == 2: payload.update({'estimate': 1}) if due_date - now.day == 3: payload.update({'estimate': 2}) if due_date - now.day == 4: payload.update({'estimate': 2}) if due_date - now.day > 4: payload.update({'estimate': 3}) headers = { 'X-TrackerToken': self.pivotal_token, 'Content-type': 'application/json', 'Accept': 'application/json' } response = requests.post( 'https://www.pivotaltracker.com/services/v5/projects/{}/stories' .format(self.pivotal_project), data=json.dumps(payload), headers=headers).json() id_couples.append((card['id'], response['id'])) self.redis_client.set(card['id'] + "_created", card['name']) else: logger.warn( f'Card with id: "{card["id"] + "_created"}" and name:' f' "{self.redis_client.get(card["id"] + "_created")}" already exists' ) return id_couples
class TrelloHelper: def __init__(self, api_key, token, board_name, exclude_lanes=[], debug=False): self.client = TrelloClient(api_key=api_key, token=token) self.boards = self.client.list_boards() self.dbg = debug for b in self.boards: if (b.name == board_name): self.board = b assert hasattr( self, 'board'), "Unable to set board, \"%s\" not found" % board_name self.members = self.board.all_members() self.labels = self.board.get_labels() self.lanes = self.board.list_lists() self.exclude_lanes = exclude_lanes def set_lane(self, name): for l in self.lanes: if (l.name == name): self.debug("Setting lane: %s" % name) self.lane = l assert hasattr(self, 'lane'), "Unable to set lane, \"%s\" not found" % name def set_card(self, card_id): self.card = self.client.get_card(card_id) def list_boards(self): self.debug("Listing Boards") for b in self.boards: self.debug("%s %s %s" % (b.id, b.url, b.name)) yield b def list_lanes(self): self.debug("Listing Lanes") for l in self.lanes: self.debug("%s %s" % (l.id, l.name)) yield l def list_cards(self): self.debug("Listing Cards") for c in self.lane.list_cards(): self.debug("%s %s %s" % (c.id, c.url, c.name)) yield c def list_members(self): if hasattr(self, 'card'): self.debug("Listing Members of %s card" % self.card.name) for cm in self.card.member_id: for bm in self.members: if cm == bm.id: self.debug("%s %s" % (bm.id, bm.username)) yield bm else: self.debug("Listing Members of %s board" % self.board.name) for bm in self.members: self.debug("%s %s" % (bm.id, bm.username)) yield bm def list_labels(self): if hasattr(self, 'card'): self.debug("Listing Labels for card: %s" % self.card.name) for cl in self.card.labels: self.debug("%s %s" % (cl.id, cl.name)) yield cl else: self.debug("Listing Labels for board: %s" % self.board.name) for bl in self.labels: self.debug("%s %s" % (bl.id, bl.name)) yield bl def list_checklists(self): if hasattr(self, 'card'): self.debug("Listing checklists for card: %s" % self.card.name) for cl in self.card.checklists: self.debug("%s %s" % (cl.id, cl.name)) for i in cl.items: self.debug(" %s %s %s" % (i['id'], i['checked'], i['name'])) yield cl def create_card(self, name, desc=None): self.debug("Create card %s\n%s" % (name, desc)) card = self.lane.add_card(name, desc) return card.id def create_checklist(self, title, items): if hasattr(self, 'card'): self.debug("Adding checklist %s for card %s, items are %s" % (title, self.card.name, items)) self.card.add_checklist(title, items) def find_cards(self, search_text, include_closed=False): self.debug("""Excluding Lanes: %s""" % self.exclude_lanes) for l in self.lanes: if not l.name in self.exclude_lanes: #self.debug("""Searching for cards matching "%s" in lane "%s" """ % (search_text, l.name)) for c in l.list_cards(): #self.debug(""" search for: "%s" in name: "%s" desc: "%s..." """ % (search_text, c.name, c.desc[0:30])) if c.name.find(search_text) >= 0 or c.desc.find( search_text) >= 0: if include_closed or c.closed == include_closed: yield c def assign_card(self, member_names): self.debug("Assign '%s'" % member_names) if hasattr(self, 'card'): for nm in member_names: for bm in self.members: if nm == bm.username: if bm.id in self.card.member_id: self.debug("%s (%s) already assigned to card %s" % (nm, bm.id, self.card)) else: self.debug("Assign card %s to %s (%s)" % (self.card, nm, bm.id)) self.card.assign(bm.id) def unassign_card(self, member_names=None): self.debug("Unassign '%s'" % member_names) if hasattr(self, 'card'): if len(member_names) == 0: for cm in self.card.member_id: self.debug("Unassign card %s from %s" % (self.card, cm)) self.card.unassign(cm) else: for nm in member_names: for bm in self.members: if nm == bm.username: if bm.id in self.card.member_id: self.debug("Unassign card %s from %s" % (self.card, bm.id)) self.card.unassign(bm.id) else: self.debug("%s (%s) not assigned to card %s" % (nm, bm.id, self.card)) def label_card(self, labels): if hasattr(self, 'card'): for l in self.labels: if l.name in labels: self.debug("label card %s as %s (%s)" % (self.card, l.name, l.id)) self.card.add_label(l) def move_card(self, lane_name): if hasattr(self, 'card'): for l in self.board.list_lists(): if l.name == lane_name: self.card.change_list(l.id) def archive_card(self): if hasattr(self, 'card'): self.card.set_closed(True) def delete_card(self): if hasattr(self, 'card'): self.card.set_closed(True) def debug(self, m): if self.dbg: print(m)
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)
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
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
class TrelloModule: def __init__(self): with open("trello.json") as parameters_data: self.config = json.load(parameters_data) self.trello = TrelloClient(api_key=self.config['ApiKey'], api_secret=self.config['ApiSecret'], token=self.config['Token'], token_secret=self.config['TokenSecret']) def get_board(self): ''' Retourne la liste Trello indiquée dans trello.ini ''' # Chargement des paramètres et identifiants Trello depuis le fichier JSON for b in self.trello.list_boards(): if b.name == self.config['BoardName']: return b print("Board " + self.config['BoardName'] + " not found.") exit() def get_list(self, site): board = self.get_board() for l in board.all_lists(): if l.name == site: return l # Liste pas trouvée, on la crée return board.add_list(site) def post(self): ''' Poste les annonces sur Trello ''' posted = 0 for annonce in Annonce.select().where( Annonce.posted2trello == False).order_by(Annonce.site.asc()): title = "%s de %sm² à %s @ %s€" % (annonce.title, annonce.surface, annonce.city, annonce.price) description = "Créé le : %s\n\n" \ "%s pièces, %s chambre(s)\n" \ "Tel : %s\n\n" % \ (annonce.created.strftime("%a %d %b %Y %H:%M:%S"), annonce.rooms, annonce.bedrooms, annonce.telephone) if annonce.description is not None: description += ">%s" % annonce.description.replace("\n", "\n>") card = self.get_list(annonce.site).add_card(title, desc=description) # On s'assure que ce soit bien un tableau if annonce.picture is not None and annonce.picture.startswith("["): # Conversion de la chaîne de caractère représentant le tableau d'images en tableau for picture in literal_eval(annonce.picture): card.attach(url=picture) # Il n'y a qu'une photo elif annonce.picture is not None and annonce.picture.startswith( "http"): card.attach(url=annonce.picture) card.attach(url=annonce.link) annonce.posted2trello = True annonce.idtrello = card.id annonce.save() posted += 1 return posted def add_new_link(self, annonce, link): try: if not annonce.idtrello: raise ReferenceError card = self.trello.get_card(annonce.idtrello) card.attach(url=link) except (ResourceUnavailable, ReferenceError): logging.error("Trello card not found ( " + annonce.title + " : " + annonce.link + ")")
class TrelloUpdater(object): """ Class for writing to Trello. """ def __init__(self, processed_report, 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 self.projects = processed_report[':collected_content'][':projects']; self.epics = processed_report[':collected_content'][':epics']; self.assignments = processed_report[':collected_content'][':assignments']; def update_projects(self): """Main function to update all project cards from config.""" self.logger.info('---Started writing to Trello---') for project in self.projects: #find special card for no projects if self.projects[project][':name'] == 'No Project': no_project = project child_cards = [] #tuples of (name of chklist item, state of chklist item) #form lists of items for checklists for card in list(self.assignments): if self.assignments[card][':project'] == self.projects[project][':project'] and self.projects[project][':project'] != []: chk_item_name = self.assignments[card][':short_url'] +" (" + self.assignments[card][':list_name'] + ") (" + self.assignments[card][':board_name'] + ")" child_cards.append((chk_item_name, self.assignments[card][':completed'])) #self.logger.debug('Appending assignment %s to the project %s' % (self.assignments[card], self.projects[project][':name'])) self.assignments.pop(card,None) self.logger.debug("Project %s has assignments : %s" % (self.projects[project][':name'], child_cards)) child_cards.sort(key = lambda x: x[1]) # Sort, so that unresolved cards are on top self.update_card(project, [ i[0] for i in child_cards] , [ i[1] for i in child_cards]); #assign items with no project to a special project card child_cards = [] for card in self.assignments: chk_item_name = self.assignments[card][':short_url'] +" (" + self.assignments[card][':list_name'] + ") (" + self.assignments[card][':board_name'] + ")" child_cards.append((chk_item_name, self.assignments[card][':completed'])) #self.logger.debug('Appending assignment %s to the No Project' % (self.assignments[card])) child_cards.sort(key = lambda x: x[1]) self.logger.debug("Project %s has assignments : %s" % (self.projects[project][':name'], child_cards)) self.update_card(no_project, [ i[0] for i in child_cards] , [ i[1] for i in child_cards]); def update_card(self, card_id, checklist_names, checklist_states): """ Clean checklists from the card, Write new checklists to the card based on the report checklist_data: [("ID", "short_url", "list_name", "board_name", completed),...] """ while True: try: tr_card = self.client.get_card(card_id) tr_card.fetch(eager=True) #self.logger.debug('Fetching checklists < %s > for Trello for card: %s' % (tr_card.checklists,self.projects[card_id][':name'])) except ResourceUnavailable as e: self.logger.error('Trello unavailable! %s' % (e)) continue break # Remove all existing checklists for old_chklist in tr_card.checklists: old_chklist.delete() assign_chk = tr_card.add_checklist("Assignments", checklist_names, checklist_states)
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)
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)
def handle(self, *args, **options): trello = TrelloClient(settings.TRELLO_API_KEY, settings.TRELLO_TOKEN) master = Board.objects.get(name=settings.TRELLO_MASTER) updatedcards_ids = [] for board in Board.objects.all().order_by('pk'): logger.info('Importing board {0}'.format(board.name)) # search for the remote board b = board.remote_object(trello) # check if the board was updated since the last update if board.last_activity is not None and b.date_last_activity <= board.last_activity: logger.info(' - No activity detected') # If it is the first update then import all the lists from the board. if not board.last_activity: logger.info("*** FIRST IMPORT ***") for lst in board.boardlist_set.all(): l = lst.remote_object(trello) lst.name = l.name lst.closed = l.closed lst.position = l.pos lst.save() lst.import_cards(l) else: # if is not the first board update, update only the latest modifications # the board was already imported once query = { 'since': board.last_activity.isoformat(timespec='microseconds') } data = trello.fetch_json('/boards/' + board.remoteid + '/actions', query_params=query) ids = [] for update in data: action_type = update.get('type', None) card_info = update['data'].get('card', None) date_last_activity = dateparser.parse(update.get('date')) if card_info: card_id = card_info['id'] if action_type == 'deleteCard': try: card = Card.objects.get(remoteid=card_id) card.last_activity = date_last_activity card.delete_remotely = True card.remoteid = None card.save() logger.info( "The card [{0}] in the board [{1}] was marked to be removed" .format(card.name, card.boardlist.board.name)) except Card.DoesNotExist: # ignore pass else: # append to the list all the modified cards ids updatedcards_ids.append(card_id) board.last_activity = b.date_last_activity board.save() cards = [] # search in all the cards from the master board, # which cards were updated b = master.remote_object(trello) for c in b.open_cards(): try: card = Card.objects.get(remoteid=c.id) if card.last_activity < c.date_last_activity: cards.append(c) except Card.DoesNotExist: pass # get all the remote cards. updatedcards_ids = list(set(updatedcards_ids)) for idx, i in enumerate(updatedcards_ids): logger.info("Get remote card ({0}/{1})".format( idx + 1, len(updatedcards_ids))) cards.append(trello.get_card(i)) # sort the cards by activity, so the latest card is the one updated cards = sorted(cards, key=lambda x: x.date_last_activity) lists = {} # cache all the boards lists for c in cards: # check if the boad list is already in cache, otherwise add it if c.list_id not in lists: lists[c.list_id] = BoardList.objects.get(remoteid=c.list_id) try: card = Card.objects.get(remoteid=c.id) # the card list is diferent, mark it to update if card.name != c.name: card.update_name = True card.name = c.name if card.desc != c.description: card.update_desc = True card.desc = c.description if card.closed != c.closed: card.update_closed = True card.closed = c.closed if card.boardlist != lists[c.list_id]: card.update_list = True card.boardlist = lists[c.list_id] except Card.DoesNotExist: # the card does not exists, create it card = Card(remoteid=c.id) card.name = c.name card.desc = c.description card.closed = c.closed card.boardlist = lists[c.list_id] card.position = c.pos card.last_activity = c.date_last_activity card.save() card.update_members_by_id(trello, c.member_id) card.update_labels_by_id(trello, c.idLabels) logger.info( "Updated card [{1} > {2} > {0}]: name:{3}, description:{4}, closed:{5}, list:{6}, members:{7}, labels:{8}" .format(card.name, card.boardlist.board.name, card.boardlist.name, card.update_name, card.update_desc, card.update_closed, card.update_list, card.update_members, card.update_labels))
class TrelloClient: def __init__(self, api_key, api_secret, token, token_secret): self.trello_client = Client(api_key=api_key, api_secret=api_secret, token=token, token_secret=token_secret) self._uid = None self._project = None self._board = None self._lists = None self._board_labels = None self._lists_filter = None self._only_my_cards = False @property def whoami(self): """ Get my Trello UID :return: my Trello UID :rtype: string """ if self._uid is None: self._uid = self.trello_client.get_member('me').id return self._uid def project(self, project): """ Set the class working project :param project: TelloWarrior project object """ if self._project == None or self._project.name != project.name: self._board = self.get_board(project.trello_board_name) self._lists = self.get_lists() self._board_labels = self.get_board_labels() self._lists_filter = project.trello_lists_filter self._only_my_cards = project.only_my_cards def get_board(self, board_name): """ Get a open Trello board from name, if it does not exist create it :param board_name: the board name :return: a Tello board :rtype: Trello board object """ for trello_board in self.trello_client.list_boards( board_filter='open'): if trello_board.name == board_name and not trello_board.closed: logger.debug('Trello board {} found'.format(board_name)) return trello_board logger.debug('Creating Trello board {}'.format(board_name)) return self.trello_client.add_board(board_name) def get_lists(self): """ Get the open lists of a Trello board :return: a list of Trello list objects :rtype: list """ return self._board.open_lists() def get_list(self, list_name): """ Get a Trello list from list name, if it does not exist create it :param list_name: the list name :return: a Tello list :rtype: Trello list object """ if self._lists == None: raise ClientError('get_list') for trello_list in self._lists: if trello_list.name == list_name: logger.debug('Trello list {} found'.format(list_name)) return trello_list logger.debug('Creating Trello list {}'.format(list_name)) trello_list = self._board.add_list(list_name) self._lists.append(trello_list) # Update _lists with new list return trello_list def get_board_labels(self): """ Get the labels of a Trello board :param board_name: the board name :return: a list of Trello label objects :rtype: list """ return self._board.get_labels() def get_board_label(self, label_name): """ Get a Trello board label from label name, if it does not exist create it :param label_name: the label name :return: a Tello label :rtype: Trello label object """ if self._board_labels == None: raise ClientError('get_board_label') for board_label in self._board_labels: if board_label.name == label_name: logger.debug('Trello board label {} found'.format(label_name)) return board_label logger.debug('Creating Trello board label {}'.format(label_name)) board_label = self._board.add_label(label_name, 'black') self._board_labels.append( board_label) # Update _board_labels with new label return board_label def get_cards_dict(self): """ Get all cards of a list of Trello lists in a dictionary :return: a dict with Cards :rtype: dict """ trello_cards_dict = {} if self._lists_filter is not None: trello_lists = filter( lambda trello_list: trello_list.name not in self._lists_filter, self._lists) for trello_list in trello_lists: logger.debug('Getting Trello cards of list {}'.format( trello_list.name)) trello_cards_dict[trello_list.name] = trello_list.list_cards() if self._only_my_cards: trello_cards_dict[trello_list.name] = filter( lambda trello_card: self.whoami in trello_card.member_ids, trello_cards_dict[trello_list.name]) return trello_cards_dict def delete_trello_card(self, trello_card_id): """ Delete (forever) a Trello card by ID :param trello_card_id: ID of Trello card """ try: self.trello_client.get_card(trello_card_id).delete() except ResourceUnavailable: logger.warning( 'Cannot find Trello card with ID {} deleted in Task Warrior. Maybe you also deleted it in Trello?' .format(trello_card_id))
def generator(request): # create variables ingredient_list = {} context_dict = {} # get ll recipe types from database recipe_types = RecipeType.objects.all() context_dict['recipe_types'] = recipe_types # check if any button has been pushed and a POST object has been created if request.method == 'POST': # collect all the food types from the select boxes responses = {u'Måndag': request.POST['monday'], u'Tisdag': request.POST['tuesday'], u'Onsdag': request.POST['wednesday'], u'Torsdag': request.POST['thursday'], u'Fredag': request.POST['friday'], u'Lördag': request.POST['saturday'], u'Söndag': request.POST['sunday']} # collect number of portions from portions select boxes portions = {u'Måndag': request.POST['monday_portions'], u'Tisdag': request.POST['tuesday_portions'], u'Onsdag': request.POST['wednesday_portions'], u'Torsdag': request.POST['thursday_portions'], u'Fredag': request.POST['friday_portions'], u'Lördag': request.POST['saturday_portions'], u'Söndag': request.POST['sunday_portions']} fast = {u'Måndag': request.POST['monday_fast'], u'Tisdag': request.POST['tuesday_fast'], u'Onsdag': request.POST['wednesday_fast'], u'Torsdag': request.POST['thursday_fast'], u'Fredag': request.POST['friday_fast'], u'Lördag': request.POST['saturday_fast'], u'Söndag': request.POST['sunday_fast']} # if generate button is pushed if 'generate' in request.POST: # create empty data structure for matlista matlista = gen_empty_matlista() # loop over each day and generate a random food (if not NONE). Then multiply # the quantity of each ingredient with the number of portions selected. for day in responses: if responses[day] != 'None': gen_random_food(day, responses[day], matlista, fast[day]) multiply_portions(day, portions[day], matlista) # check if button to generate new dish on monday has been pushed elif 'random_monday' in request.POST: # fetch matlista object from session day = u'Måndag' matlista = request.session['matlista'] # generate a random recepie and update matlista. if responses[day] != 'None': gen_random_food(day,responses[day], matlista, fast[day]) multiply_portions(day, portions[day], matlista) # check if any of the other days buttons has been pushed elif 'random_tuesday' in request.POST: day = u'Tisdag' matlista = request.session['matlista'] if responses[day] != 'None': gen_random_food(day,responses[day], matlista, fast[day]) multiply_portions(day, portions[day], matlista) elif 'random_wednesday' in request.POST: day = u'Onsdag' matlista = request.session['matlista'] if responses[day] != 'None': gen_random_food(day,responses[day], matlista, fast[day]) multiply_portions(day, portions[day], matlista) elif 'random_thursday' in request.POST: day = u'Torsdag' matlista = request.session['matlista'] if responses[day] != 'None': gen_random_food(day,responses[day], matlista, fast[day]) multiply_portions(day, portions[day], matlista) elif 'random_friday' in request.POST: day = u'Fredag' matlista = request.session['matlista'] if responses[day] != 'None': gen_random_food(day,responses[day], matlista, fast[day]) multiply_portions(day, portions[day], matlista) elif 'random_saturday' in request.POST: day = u'Lördag' matlista = request.session['matlista'] if responses[day] != 'None': gen_random_food(day,responses[day], matlista, fast[day]) multiply_portions(day, portions[day], matlista) elif 'random_sunday' in request.POST: day = u'Söndag' matlista = request.session['matlista'] if responses[day] != 'None': gen_random_food(day,responses[day], matlista, fast[day]) multiply_portions(day, portions[day], matlista) # check if any manual dish selection has been done for monday elif 'select_monday_btn' in request.POST: day = u'Måndag' # get the name of the recipe selected from session name = request.POST['select_monday'] # get matlsta sesion object matlista = request.session['matlista'] #update matlista with the new dish gen_dish(day,name, matlista) multiply_portions(day, portions[day], matlista) # check if any of the other days buttons has been pushed elif 'select_tuesday_btn' in request.POST: day = u'Tisdag' name = request.POST['select_tuesday'] matlista = request.session['matlista'] gen_dish(day,name, matlista) multiply_portions(day, portions[day], matlista) elif 'select_wednesday_btn' in request.POST: day = u'Onsdag' name = request.POST['select_wednesday'] matlista = request.session['matlista'] gen_dish(day,name, matlista) multiply_portions(day, portions[day], matlista) elif 'select_thursday_btn' in request.POST: day = u'Torsdag' name = request.POST['select_thursday'] matlista = request.session['matlista'] gen_dish(day,name, matlista) multiply_portions(day, portions[day], matlista) elif 'select_friday_btn' in request.POST: day = u'Fredag' name = request.POST['select_friday'] matlista = request.session['matlista'] gen_dish(day,name, matlista) multiply_portions(day, portions[day], matlista) elif 'select_saturday_btn' in request.POST: day = u'Lördag' name = request.POST['select_saturday'] matlista = request.session['matlista'] gen_dish(day,name, matlista) multiply_portions(day, portions[day], matlista) elif 'select_sunday_btn' in request.POST: day = u'Söndag' name = request.POST['select_sunday'] matlista = request.session['matlista'] gen_dish(day,name, matlista) multiply_portions(day, portions[day], matlista) # check if the send to trello button has been pushed. elif 'trello' in request.POST and request.user.is_authenticated(): # get matlista object and ingredient object from session. matlista = request.session['matlista'] # if there are any ingredients if request.session['ingredient_strings']: ingredients = request.session['ingredient_strings'] trello_data = Trello.objects.filter(user=request.user).first() # create a trello client object, connect and authenticate trello_client = TrelloClient( api_key = trello_data.api_key, api_secret = trello_data.api_secret, token = trello_data.token, token_secret = trello_data.token_secret ) # get matlistan card matlistan_card = trello_client.get_card(trello_data.matlista_card_url) # add matlista as comment matlistan_card.comment(u'Måndag : ' + unicode(matlista[u'Måndag']['dish']) + '\n\n' + u'Tisdag : ' + unicode(matlista[u'Tisdag']['dish']) + '\n\n' + u'Onsdag : ' + unicode(matlista[u'Onsdag']['dish']) + '\n\n' + u'Torsdag : ' + unicode(matlista[u'Torsdag']['dish']) + '\n\n' + u'Fredag : ' + unicode(matlista[u'Fredag']['dish']) + '\n\n' + u'Lördag : ' + unicode(matlista[u'Lördag']['dish']) + '\n\n' + u'Söndag : ' + unicode(matlista[u'Söndag']['dish']) + '\n\n') handlingslista_card = trello_client.get_card(trello_data.handlingslista_card_url) handlingslista_card.add_checklist('handlingslista', ingredients) # save matlist object in session request.session['matlista'] = matlista # loop over each day. for day in matlista: # For all the ingredients that day for ingredient in matlista[day]['ingredients']: # check if a ingredient is already in the ingredient list if ingredient in ingredient_list: # if the ingredient is in the list and has the same unit. add the # quantity to the ingredient in the ingredient list if matlista[day]['ingredients'][ingredient]['unit'] == ingredient_list[ingredient]['unit']: quant_to_add = matlista[day]['ingredients'][ingredient]['quantity'] ingredient_list[ingredient]['quantity'] += quant_to_add # if the ingredient is in the list but the ingredient doe not have the same type of # unit, flag it as a unit conflict for user to resolve. else: ingredient_list.update(copy.deepcopy({ingredient + ' - UNIT CONFLICT' : matlista[day]['ingredients'][ingredient]})) # if the ingredient is not in the ingredient list add it to the list else: ingredient_list.update(copy.deepcopy({ingredient: matlista[day]['ingredients'][ingredient]})) # create a list for storing final ingredients as strings # ready to be sent to template. ingredient_strings = [] # loop over ingredients in ingredient list and make string in # format "ingredient-quantity ingredient-unit ingredient-name" # and save to sting list for ingredient in ingredient_list: name = ingredient quantity = ingredient_list[ingredient]['quantity'] unit = ingredient_list[ingredient]['unit'] ingredient_strings.append(unicode(quantity) + ' ' + unit + ' ' + name) #save ingredient string list to session request.session['ingredient_strings'] = ingredient_strings # create lists of manual recepie selction dish_type = RecipeType.objects.filter(name=responses[u'Måndag']).first() monday_recipes = Recipe.objects.all().filter(food_type=dish_type) dish_type = RecipeType.objects.filter(name=responses[u'Tisdag']).first() tuesday_recipes = Recipe.objects.all().filter(food_type=dish_type) dish_type = RecipeType.objects.filter(name=responses[u'Onsdag']).first() wednesday_recipes = Recipe.objects.all().filter(food_type=dish_type) dish_type = RecipeType.objects.filter(name=responses[u'Torsdag']).first() thursday_recipes = Recipe.objects.all().filter(food_type=dish_type) dish_type = RecipeType.objects.filter(name=responses[u'Fredag']).first() friday_recipes = Recipe.objects.all().filter(food_type=dish_type) dish_type = RecipeType.objects.filter(name=responses[u'Lördag']).first() saturday_recipes = Recipe.objects.all().filter(food_type=dish_type) dish_type = RecipeType.objects.filter(name=responses[u'Söndag']).first() sunday_recipes = Recipe.objects.all().filter(food_type=dish_type) # store in context dic and send to template context_dict['monday_recipes'] = monday_recipes context_dict['tuesday_recipes'] = tuesday_recipes context_dict['wednesday_recipes'] = wednesday_recipes context_dict['thursday_recipes'] = thursday_recipes context_dict['friday_recipes'] = friday_recipes context_dict['saturday_recipes'] = saturday_recipes context_dict['sunday_recipes'] = sunday_recipes context_dict['matlista'] = matlista context_dict['ingredient_strings'] = ingredient_strings # if no POST data create an empty data structure and save it in session else: matlista = gen_empty_matlista() request.session['matlista'] = matlista return render(request, 'generator.html', context=context_dict)
targetlist = [] for item in updated_list: targetlist.append(item['data']['card']['id']) for item in created_list: targetlist.append(item['data']['card']['id']) result_target = list(set(targetlist)) # travel each card by id and format dict payload = {} es = Elasticsearch("es_address:port") for item in result_target: currentcard = client.get_card(item) payload['id'] = currentcard.id payload['shortUrl'] = currentcard.short_url payload['dateLastActivity'] = str(currentcard.dateLastActivity)[:-22] payload['desc'] = currentcard.description payload['name'] = currentcard.name # insert date to es result = es.index(index="tm_trello_card", doc_type="card", id=payload['id'], body=payload) logger.info("updated es data %s", str(result))