Recreate trello board state using API given a date in past
Asked by Marcus Williams:

Hi -

I'm trying to recreate a trello board state from a date in the past for some board metrics. I'm only interested in which list a card is in on this date. Is there a simple way to do this from the API?

At the moment I'm resorting to replaying all the card \& list actions that create/move cards and lists over a simple dictionary of cards but I dont think I've caught all the possible actions that could create/move cards around as they dont tally with the current board positions if I run through the entire history (and I end up with lists that dont exist on my board anymore)

So the other question would be what action types should I be looking for to catch all card events necessary? Currently I'm looking at: updateCard:idList, updateCard:closed, createCard, deleteCard, updateList:closed, moveListFromBoard, moveListToBoard.

Thanks

Marcus


Answers:
author: Iain Dooley
body: [@Marcus Williams](/t5/user/viewprofilepage/user-id/2593389) If the only thing you're interested in is which list a card is in on a given date, then you can do this from a card centric point of view, and create a second board as a "view" for what cards exist at what point.

So starting from the earliest actions for a board, each time you get to a createCard or emailCardToBoard or moveCardToBoard event that would result in a card appearing on the board, find the list with the ID of the event, create the list in your view board if it doesn't already exist, then create a card with the same name as the created card and store the original card ID in the new card.

Then, later, if you find another action for a card (archived, deleted, moved to another board etc.) you can find the matching new card and archive it.

Play this forward until you get to the date/time you're after and your "view" board should show you what cards were in what lists on that date.

You don't need to worry about if a list was closed or not because when a list closes you get an archive event for each card in that list, likewise for when you move a list to another board.

comments: author: Marcus Williams
body: Thats essentially what I'm doing - I've filtered for these actions types:

updateCard:idList, updateCard:closed, copyCard, createCard, deleteCard, emailCardToBoard, moveCardToBoard, convertToCardFromCheckItem, moveCardFromBoard

For createCard, copyCard, moveCardToBoard, convertToCardFromCheckItem \& emailCardToBoard I create a list if needed \& add the card.

For updateCard I either move a card from listBefore to listAfter or I remove the card if the closed flag goes to True.

For deleteCard I remove the card

For moveCardFromBoard I remove the card (I dont seem to see these although I see cards in lists that appear to have moved boards - I also dont see moveListFromBoard events when filtered).

But a simple card count at the end doesnt tally with the current state of the board.


author: Iain Dooley
body: [@Marcus Williams](/t5/user/viewprofilepage/user-id/2593389) hmm, if instead of actually creating and removing the cards etc. you just increment and decrement a counter to indicate the difference between total card creation events versus card removal events, do you get the correct number? Just wanting to eliminate the prospect that somehow the actual operations to create/remove cards are failing.


author: Marcus Williams
body: Ok, so removing everything else and only looking at card actions a count still doesnt tally with whats on the board if I recreate from history. The simplified code (python) is this:

```
auth = {'key': API_KEY, 'token': OAUTH_TOKEN, 'filter': 'all', 'limit': 1000}
api_endpoint = 'https://api.trello.com/1/boards/XXXXXXX/actions'
r = requests.get(api_endpoint, params=auth)
all_actions = r.json()
all_actions.reverse() # earliest action first

c = 0
for a in all_actions:
  if a['type'] == 'updateCard':
    if 'listBefore' in a['data']:
      # card move (ignore for count as they move on same board)
      pass
    elif 'closed' in a['data']['old']:
      # card archived/unarchived
      if a['data']['card']['closed']:
        c = c - 1
      else:
        c = c + 1
  elif a['type'] == 'deleteCard':
    # card deleted
    c = c - 1
  elif a['type'] == 'createCard' or a['type'] == 'moveCardToBoard' or \
       a['type'] == 'copyCard' or a['type'] == 'convertToCardFromCheckItem':
    # new card created in some way
    c = c + 1


```

There are less than 1000 actions so I'm not missing any as far as I can tell.


author: Iain Dooley
body: [@Marcus Williams](/t5/user/viewprofilepage/user-id/2593389) The only action I can see missing from that list is emailCard and moveCardFromBoard.

Also are you sure there are less than 1000 actions total returned from the endpoint? As in the count of all_actions \< 1000 right after you make the query?

Also, when the board was created, was it copied from another board that had cards already in it? I'm not sure if those cards would show up as actions when copying a board (might, but haven't tested).

Also, there are actually differences in how actions are stored/retrieved via the API vs passed on to webhooks so while I'm confident that, for example, moveListToBoard will not only create a webhook notification for the list but also for each card in the list, I'm not confident that you would see the moveCardToBoard action for each card in the list, in the actions nested resource. It might be worth checking that out with a little test case.

Speaking of test cases, have you tried testing this out on a board with fewer actions to make sure you can get an accurate tally?

If you did this in a small test case, then you could experiment and see if there were any ways you could "fool" it for example by moving lists to the board etc.


Tags: api