This repository has been archived by the owner on Aug 15, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
import_trello_json_to_NC_Deck.py
203 lines (178 loc) · 7.95 KB
/
import_trello_json_to_NC_Deck.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# Python 3 script for parsing data from json and uploading the data to a NextCloud deck application via API
import json
import requests
import os
from dateutil import parser
# Configuration from config.json
with open('config.json') as f:
data = json.load(f)
apiUser = data['user']
apiPword = data['password']
url = data['url']
# Specify the location of data here (the script will try to go through all .json-files in the folder
directory = './data/'
# Define function for making POST requests
def api_post(api_data, api_url):
response = requests.post(api_url, auth=(apiUser, apiPword), data=api_data)
if response:
print('Imported successfully ' + '"' + api_data['title'] + '"')
return json.loads(response.text)['id']
elif response.status_code == 400:
print('Importing failed: ' + '"' + api_data['title'] + '"')
print(response)
print('Bad request. Parameter missing?')
return ''
elif response.status_code == 403:
print('Importing failed: ' + '"' + api_data['title'] + '"')
print(response)
print('Permission denied, check credentials.')
return ''
elif response.status_code == 404:
print('Importing failed: ' + '"' + api_data['title'] + '"')
print(response)
print('Server not found.')
return ''
else:
print('Importing failed: ' + '"' + api_data['title'] + '"')
print('Something weird happened.')
print(response)
return ''
# Functions for formulating the text strings for checklists
def checklist_item(item):
if item['state'] == 'incomplete':
string_start = '- [ ]'
else:
string_start = '- [x]'
check_item_string = string_start + ' ' + item['name'] + '\n'
return check_item_string
def formulate_checklist_text(checklist):
checklist_string = '\n\n## ' + checklist['name'] + '\n'
for item in checklist['checkItems']:
checklist_item_string = checklist_item(item)
checklist_string = checklist_string + '\n' + checklist_item_string
return checklist_string
# This convert the duedate from Trello-format to Deck format (they both are ISO 8601, but signify timezone differently)
def convert_date(trellodate):
date = parser.isoparse(trellodate)
deckdate = date.replace(microsecond=0).isoformat()
return deckdate
# Define urls for api requests
boardUrl = url + 'boards'
labelUrl = boardUrl + '/%s/labels'
stackUrl = boardUrl + '/%s/stacks'
cardUrl = boardUrl + '/%s/stacks/%s/cards'
cardLabelUrl = boardUrl + '/%s/stacks/%s/cards/%s/assignLabel'
# NB: Maximum number of characters allowed for the title of a card
# in Deck is 255 (import of a will card fail if this is exceeded)
for filename in os.scandir(directory):
if filename.path.endswith('.json'):
print('\nProcessing file: %s \n' % filename.path)
with open(filename.path, encoding='utf-8') as f:
data = json.load(f)
# Add board to Deck and retrieve the new board id
trelloBoardName = data['name']
boardData = {'title': trelloBoardName, 'color': '0800fd'}
newboardId = api_post(boardData, boardUrl)
# Import labels
labels = {'labelId': 'newLabelId'}
print('')
print('Importing labels...')
for label in data['labels']:
labelId = label['id']
if label['name'] == '':
labelTitle = 'Unnamed ' + label['color'] + ' label'
else:
labelTitle = label['name']
if label['color'] == 'red':
labelColor = 'ff0000'
elif label['color'] == 'yellow':
labelColor = 'ffff00'
elif label['color'] == 'orange':
labelColor = 'ff6600'
elif label['color'] == 'green':
labelColor = '00ff00'
elif label['color'] == 'purple':
labelColor = '9900ff'
elif label['color'] == 'blue':
labelColor = '0000ff'
elif label['color'] == 'sky':
labelColor = '00ccff'
elif label['color'] == 'lime':
labelColor = '00ff99'
elif label['color'] == 'pink':
labelColor = 'ff66cc'
elif label['color'] == 'black':
labelColor = '000000'
else:
labelColor = 'ffffff'
labelData = {'title': labelTitle, 'color': labelColor}
url = labelUrl % newboardId
newLabelId = api_post(labelData, url)
labels[labelId] = newLabelId
# Save checklist content into a dictionary (_should_ work even if a card has multiple checklists
checklists = {'cardId': {'checklistId': 'checklistString'}}
for checkl in data['checklists']:
checklists[checkl['idCard']] = {}
for checkl in data['checklists']:
checklistText = formulate_checklist_text(checkl)
checklists[checkl['idCard']][checkl['id']] = checklistText
# Add stacks to the new board
print('')
print('Importing stacks...')
url = stackUrl % newboardId
stacks = {'listId': 'newStackId'}
order = 1
for lst in data['lists']:
# If a list (= stack in Deck) is archived, skips to the next one.
if lst['closed']:
print('List ' + lst['name'] + ' is archived, skipping to the next one...')
continue
listId = lst['id']
stackName = lst['name']
stackData = {'title': stackName, 'order': order}
newstackId = api_post(stackData, url)
stacks[listId] = newstackId
order = order + 1
# Go through the cards and assign them to the correct lists (= stacks in Deck)
print('')
print('Importing cards...')
cards = {'cardId': 'newCardId'}
for crd in data['cards']:
# Check whether a card is archived, if true, skipping to the next card
if crd['closed']:
print('Card ' + crd['name'] + ' is archived, skipping...')
continue
cardId = crd['id']
cardName = crd['name']
stringEnd = ''
# Insert checklists from previously created dictionary, if a card has one
# Should
if len(crd['idChecklists']) != 0:
for checklistId in checklists[cardId]:
stringEnd = stringEnd + '\n' + checklists[cardId][checklistId]
cardDesc = crd['desc'] + stringEnd
newstackId = stacks[crd['idList']]
cardOrder = crd['idShort']
# Here we check whether the card has a due date,
# if not, run the first one, if yes, convert the date to ISO 8601
if crd['due'] is None:
cardData = {'title': cardName, 'type': 'plain', 'order': cardOrder, 'description': cardDesc}
else:
cardDue = convert_date(crd['due'])
cardData = {'title': cardName, 'type': 'plain', 'order': cardOrder, 'description': cardDesc, 'duedate': cardDue}
url = cardUrl % (newboardId, newstackId)
newcardId = api_post(cardData, url)
cards[cardId] = newcardId
# If the card has a label assigned to it, we add it here
for lbl in crd['labels']:
oldLabelId = lbl['id']
newLabelId = int(labels[oldLabelId])
updateLabelData = {'labelId': newLabelId}
url = cardLabelUrl % (newboardId, newstackId, newcardId)
labelResponse = requests.put(url, auth=(apiUser, apiPword), data=updateLabelData)
if labelResponse:
print('Label assigned to card', cardName)
else:
print('Assigning label failed to card:', cardName)
else:
continue