Skip to content

Instantly share code, notes, and snippets.

@svbergerem
Created June 24, 2020 09:50
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save svbergerem/5914d7f87764901aefddba125af99938 to your computer and use it in GitHub Desktop.
Save svbergerem/5914d7f87764901aefddba125af99938 to your computer and use it in GitHub Desktop.
Nextcloud Deck Export/Import
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')
@keitalbame
Copy link

hello,
is it possible to use this script to save the maps on my windows pc?

Thank you

Hi,
Not familiar with python in windows but I would say the workflow is the same.

@keitalbame
Copy link

tbh, I'm not a python developer. Just find this script very useful since I also needed to move from a server with self signed certificates into one with proper certificates.

A quick search on python code examples on how to handle self signed certs in python and testing on my own instance did the trick.

Hope it helps.

@Jeanoo
Copy link

Jeanoo commented Nov 8, 2020

thank you for your messages

@mstyp
Copy link

mstyp commented Nov 15, 2020

@mstyp Check https://github.com/keitalbame/nextcloud-deck-export-import/tree/master

I'm still getting the same error.

File "nextcloud-deck-export-import.py", line 13
f'{urlFrom}/index.php/apps/deck/api/v1.0/boards',
^
SyntaxError: invalid syntax

Not sure what I am doing wrong here. I used the self signed cert script. I have all the urls and stuff in there. I ran python nextcloud-deck-export-import.py and it always spits out that error, even when I replace the {urlFrom} with the regular URL

@keitalbame
Copy link

@mstyp are you replacing variables in lines 2,3,5 and 6 with your own?
Make sure to have the values inside quotes.

I do not have any instance to test this again and I don’t remember of having any issues running the script.

@nousernameavailableanymore

Can this be used to store all board information in a file for backup and restore it later (if need be), or will this only work to copy boards from one NC instance to another?

@hrehfeld
Copy link

@mstyp Check https://github.com/keitalbame/nextcloud-deck-export-import/tree/master

I'm still getting the same error.

File "nextcloud-deck-export-import.py", line 13
f'{urlFrom}/index.php/apps/deck/api/v1.0/boards',
^
SyntaxError: invalid syntax

Not sure what I am doing wrong here. I used the self signed cert script. I have all the urls and stuff in there. I ran python nextcloud-deck-export-import.py and it always spits out that error, even when I replace the {urlFrom} with the regular URL

You're using a version of python that doesn't support f-strings.

@BooneyNoobington
Copy link

@mstyp You can run this with python nextcloud-deck-export-import.py.

If you are using selfsigned certificates, you need to add verify=False after headers=headers in all functions.

2FA also needs to be disabled for this to work.

@svbergerem, thanks for the script :)

Thanks for the tipp!

Feels like there should be a possibility to do this globally.

@BooneyNoobington
Copy link

Could this be turned in a full fledged export file?

@cloud2018
Copy link

@svbergerem
👍 👍 👍
excellent, works very well
many thanks for your script!

@OSevangelist
Copy link

Thank you @svbergerem Worked well for me as well!

@stif
Copy link

stif commented Oct 14, 2021

Thank you very much @svbergerem 🤝 Saved me a lot of work!

File "NC1-NC2.py", line 13 f'{urlFrom}/index.php/apps/deck/api/v1.0/boards' ^ SyntaxError: invalid syntax

@mstyp and anybody having the same error: make sure you use python3 and not python2

@TheRealRWJ
Copy link

TheRealRWJ commented Jan 29, 2023

Worked like a charm!
Thank you Sooooo much
Awesome!
image

Thank you, Thank you, Thank you

@webbird
Copy link

webbird commented Feb 16, 2023

Great work! Thank you very much for sharing!

I have one question, in my case the comments are missing after import, is that "by design"?

@svbergerem
Copy link
Author

@webbird I never used comments within deck, which is why I didn't implement this in the script.

@webbird
Copy link

webbird commented Feb 16, 2023

I see. Thank you.

@rolandixor
Copy link

Is it possible to use this script to export from a manual and import to a snap install?

@anibyl
Copy link

anibyl commented May 12, 2023

I was so disappointed that i can't import and export them, but then i found this. You're the best 💜

@CodeShakingSheep
Copy link

CodeShakingSheep commented May 13, 2023

@svbergerem Thank you for your work. I forked your gist and added API methods to copy card comments too. May be also interesting for @webbird
Edit: Please note that all comments will be created from the user account specified in the first lines of the script.
Edit2: Also added API methods to copy card attachments.

@Jeanoo
Copy link

Jeanoo commented Jul 10, 2023

could you please explain how to use this script on windows?

@petrisch
Copy link

petrisch commented Sep 3, 2023

Works like a charm. I had one error, which is more like a deck error itself and debatable.
When you create a label and add it to a card, then delete the label. The label is still on that card but not in the labels list anymore.
Then you hit this error when migrating:

File "/home/**/deck_migrate/deck_migrate.py", line 147, in copyCard assignLabel(labelsMap[label['id']], createdCard['id'], boardIdTo, stackIdTo) ~~~~~~~~~^^^^^^^^^^^^^

Not shure what is supposed to happen though. For me it was a nice cleanup feature once I figured out what was happening.

@vijay-prema
Copy link

vijay-prema commented Oct 8, 2023

Partially worked for me. Migrated from latest Snap install to latest Docker AIO version.

Notes:

  • Comments did not migrate.
  • Attachments did not migrate.
  • Archived boards became un-archived when migrated but no big deal, I just re-archived them.

EDIT: I then deleted them again from the destination, and tried the fork from CodeShakingSheep above and it worked perfectly. Thanks!

@Jeanoo
Copy link

Jeanoo commented Oct 9, 2023

please, how to change
urlTo = 'https://nextcloud.domainto.tld'
authTo = ('username', 'password')
to save on a pc
Thank you

@CodeShakingSheep
Copy link

please, how to change urlTo = 'https://nextcloud.domainto.tld' authTo = ('username', 'password') to save on a pc Thank you

You have to open the file with a text editor. If you're on Windows you can just right-click --> 'Open with' --> 'Editor'. Alternatively, you can download Notepad++ and then right click --> 'Edit with Notepad++'.

@CodeShakingSheep
Copy link

Partially worked for me. Migrated from latest Snap install to latest Docker AIO version.

Notes:

  • Comments did not migrate.
  • Attachments did not migrate.
  • Archived boards became un-archived when migrated but no big deal, I just re-archived them.

EDIT: I then deleted them again from the destination, and tried the fork from CodeShakingSheep above and it worked perfectly. Thanks!

Thanks for your appreciation. FYI, I just fixed archiving of boards in my fork.

@Jeanoo
Copy link

Jeanoo commented Oct 10, 2023

please, how to change urlTo = 'https://nextcloud.domainto.tld' authTo = ('username', 'password') to save on a pc Thank you

You have to open the file with a text editor. If you're on Windows you can just right-click --> 'Open with' --> 'Editor'. Alternatively, you can download Notepad++ and then right click --> 'Edit with Notepad++'.

I know that!
what I don't know is how to enter the correct information so that the data can be saved on my pc.
example: c:\documents\deck

@CodeShakingSheep
Copy link

please, how to change urlTo = 'https://nextcloud.domainto.tld' authTo = ('username', 'password') to save on a pc Thank you

You have to open the file with a text editor. If you're on Windows you can just right-click --> 'Open with' --> 'Editor'. Alternatively, you can download Notepad++ and then right click --> 'Edit with Notepad++'.

I know that! what I don't know is how to enter the correct information so that the data can be saved on my pc. example: c:\documents\deck

What you want is not possible with this script as it only transfers decks from one Nextcloud instance to another. You can check out this fork. May be it'll work for you. I have never tested myself.

@Jeanoo
Copy link

Jeanoo commented Oct 12, 2023

Thanks!

@MonkeysAreEvil
Copy link

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')

@PrintLukas
Copy link

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

@PrintLukas
Copy link

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