Created
June 24, 2020 09:50
-
-
Save svbergerem/5914d7f87764901aefddba125af99938 to your computer and use it in GitHub Desktop.
Nextcloud Deck Export/Import
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
urlFrom = 'https://cloud.domainfrom.tld' | |
authFrom = ('username', 'password') | |
urlTo = 'https://nextcloud.domainto.tld' | |
authTo = ('username', 'password') | |
headers={'OCS-APIRequest': 'true', 'Content-Type': 'application/json'} | |
def getBoards(): | |
response = requests.get( | |
f'{urlFrom}/index.php/apps/deck/api/v1.0/boards', | |
auth=authFrom, | |
headers=headers) | |
response.raise_for_status() | |
return response.json() | |
def getBoardDetails(boardId): | |
response = requests.get( | |
f'{urlFrom}/index.php/apps/deck/api/v1.0/boards/{boardId}', | |
auth=authFrom, | |
headers=headers) | |
response.raise_for_status() | |
return response.json() | |
def getStacks(boardId): | |
response = requests.get( | |
f'{urlFrom}/index.php/apps/deck/api/v1.0/boards/{boardId}/stacks', | |
auth=authFrom, | |
headers=headers) | |
response.raise_for_status() | |
return response.json() | |
def getStacksArchived(boardId): | |
response = requests.get( | |
f'{urlFrom}/index.php/apps/deck/api/v1.0/boards/{boardId}/stacks/archived', | |
auth=authFrom, | |
headers=headers) | |
response.raise_for_status() | |
return response.json() | |
def createBoard(title, color): | |
response = requests.post( | |
f'{urlTo}/index.php/apps/deck/api/v1.0/boards', | |
auth=authTo, | |
json={ | |
'title': title, | |
'color': color | |
}, | |
headers=headers) | |
response.raise_for_status() | |
board = response.json() | |
boardId = board['id'] | |
# remove all default labels | |
for label in board['labels']: | |
labelId = label['id'] | |
response = requests.delete( | |
f'{urlTo}/index.php/apps/deck/api/v1.0/boards/{boardId}/labels/{labelId}', | |
auth=authTo, | |
headers=headers) | |
response.raise_for_status() | |
return board | |
def createLabel(title, color, boardId): | |
response = requests.post( | |
f'{urlTo}/index.php/apps/deck/api/v1.0/boards/{boardId}/labels', | |
auth=authTo, | |
json={ | |
'title': title, | |
'color': color | |
}, | |
headers=headers) | |
response.raise_for_status() | |
return response.json() | |
def createStack(title, order, boardId): | |
response = requests.post( | |
f'{urlTo}/index.php/apps/deck/api/v1.0/boards/{boardId}/stacks', | |
auth=authTo, | |
json={ | |
'title': title, | |
'order': order | |
}, | |
headers=headers) | |
response.raise_for_status() | |
return response.json() | |
def createCard(title, ctype, order, description, duedate, boardId, stackId): | |
response = requests.post( | |
f'{urlTo}/index.php/apps/deck/api/v1.0/boards/{boardId}/stacks/{stackId}/cards', | |
auth=authTo, | |
json={ | |
'title': title, | |
'type': ctype, | |
'order': order, | |
'description': description, | |
'duedate': duedate | |
}, | |
headers=headers) | |
response.raise_for_status() | |
return response.json() | |
def assignLabel(labelId, cardId, boardId, stackId): | |
response = requests.put( | |
f'{urlTo}/index.php/apps/deck/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/assignLabel', | |
auth=authTo, | |
json={ | |
'labelId': labelId | |
}, | |
headers=headers) | |
response.raise_for_status() | |
def archiveCard(card, boardId, stackId): | |
cardId = card['id'] | |
card['archived'] = True | |
response = requests.put( | |
f'{urlTo}/index.php/apps/deck/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}', | |
auth=authTo, | |
json=card, | |
headers=headers) | |
response.raise_for_status() | |
def copyCard(card, boardIdTo, stackIdTo, labelsMap): | |
createdCard = createCard( | |
card['title'], | |
card['type'], | |
card['order'], | |
card['description'], | |
card['duedate'], | |
boardIdTo, | |
stackIdTo | |
) | |
# copy card labels | |
if card['labels']: | |
for label in card['labels']: | |
assignLabel(labelsMap[label['id']], createdCard['id'], boardIdTo, stackIdTo) | |
if card['archived']: | |
archiveCard(createdCard, boardIdTo, stackIdTo) | |
# get boards list | |
boards = getBoards() | |
# create boards | |
for board in boards: | |
boardIdFrom = board['id'] | |
# create board | |
createdBoard = createBoard(board['title'], board['color']) | |
boardIdTo = createdBoard['id'] | |
print('Created board', board['title']) | |
# create labels | |
boardDetails = getBoardDetails(board['id']) | |
labelsMap = {} | |
for label in boardDetails['labels']: | |
createdLabel = createLabel(label['title'], label['color'], boardIdTo) | |
labelsMap[label['id']] = createdLabel['id'] | |
# copy stacks | |
stacks = getStacks(boardIdFrom) | |
stacksMap = {} | |
for stack in stacks: | |
createdStack = createStack(stack['title'], stack['order'], boardIdTo) | |
stackIdTo = createdStack['id'] | |
stacksMap[stack['id']] = stackIdTo | |
print(' Created stack', stack['title']) | |
# copy cards | |
if not 'cards' in stack: | |
continue | |
for card in stack['cards']: | |
copyCard(card, boardIdTo, stackIdTo, labelsMap) | |
print(' Created', len(stack['cards']), 'cards') | |
# copy archived stacks | |
stacks = getStacksArchived(boardIdFrom) | |
for stack in stacks: | |
# copy cards | |
if not 'cards' in stack: | |
continue | |
print(' Stack', stack['title']) | |
for card in stack['cards']: | |
copyCard(card, boardIdTo, stacksMap[stack['id']], labelsMap) | |
print(' Created', len(stack['cards']), 'archived cards') |
I had trouble transferring large stacks due to the api request being cut off (and thus being invalid json). A quick hack to fix this:
def get_response(url):
response = requests.get(
url,
auth=authFrom,
headers=headers, stream=True, timeout=30)
response_content = []
for chunk in response.iter_content(101024):
if len(chunk)>10000000:
response_content.append(chunk)
response.close()
break
else:
response_content.append(chunk)
break
return json.loads(response_content[0])
def getStacks(boardId):
return get_response(f'{urlFrom}/index.php/apps/deck/api/v1.0/boards/{boardId}/stacks')
Hey there!
Awesome Script! Thank you so much for your work! Unfortunately I ran into an error:
File "/usr/lib/python3/dist-packages/requests/models.py", line 943, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://mydomain.tld/index.php/apps/deck/api/v1.0/boards
User@server:~/import/nextcloud-deck-export-import$
Thank you in advance!
lukas
I use a cloudflare tunnel for this domain… Could that be the problem? Is there a way to enter the ipaddr without a certificate?
Lg
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks!