-
-
Save CodeShakingSheep/e6efe69f2f7082ceb590e8ce68fa2bfc to your computer and use it in GitHub Desktop.
# You need to have the 'requests' module installed, see here: https://pypi.org/project/requests/ | |
import requests | |
# Note regarding 2FA | |
# You can either disable 'Enforce 2FA' setting and disable '2FA'. Then you can just use your regular user password. | |
# Or you can just use an app password, e.g. named 'migration' which you can create in 'Personal settings' --> 'Security'. After successful migration you can delete the app password. | |
urlFrom = 'https://nextcloud.domainfrom.tld' | |
authFrom = ('username', 'user password or app password') | |
urlTo = 'https://nextcloud.domainto.tld' | |
authTo = ('username', 'user password or app password') | |
# Deck API documentation: https://deck.readthedocs.io/en/latest/API/ | |
# Use API v1.1 with Deck >= 1.3.0 | |
# For Deck >= 1.0.0 and < 1.3.0 change API version in deckApiPath to v1.0 (leave ocsApiPath unchanged) | |
# Note that exporting / importing attachments only works with API v.1.1 | |
deckApiPath='index.php/apps/deck/api/v1.1' | |
ocsApiPath='ocs/v2.php/apps/deck/api/v1.0' | |
headers={'OCS-APIRequest': 'true', 'Content-Type': 'application/json'} | |
headersOcsJson={'OCS-APIRequest': 'true', 'Accept': 'application/json'} | |
def getBoards(): | |
response = requests.get( | |
f'{urlFrom}/{deckApiPath}/boards', | |
auth=authFrom, | |
headers=headers) | |
response.raise_for_status() | |
return response.json() | |
def getBoardDetails(boardId): | |
response = requests.get( | |
f'{urlFrom}/{deckApiPath}/boards/{boardId}', | |
auth=authFrom, | |
headers=headers) | |
response.raise_for_status() | |
return response.json() | |
def getStacks(boardId): | |
response = requests.get( | |
f'{urlFrom}/{deckApiPath}/boards/{boardId}/stacks', | |
auth=authFrom, | |
headers=headers) | |
response.raise_for_status() | |
return response.json() | |
def getStacksArchived(boardId): | |
response = requests.get( | |
f'{urlFrom}/{deckApiPath}/boards/{boardId}/stacks/archived', | |
auth=authFrom, | |
headers=headers) | |
response.raise_for_status() | |
return response.json() | |
def getAttachments(boardId, stackId, cardId): | |
response = requests.get( | |
f'{urlFrom}/{deckApiPath}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments', | |
auth=authFrom, | |
headers=headers) | |
response.raise_for_status() | |
return response.json() | |
def getAttachment(path): | |
response = requests.get( | |
f'{urlFrom}/{path}', | |
auth=authFrom, | |
headers=headers) | |
response.raise_for_status() | |
return response | |
def getComments(cardId): | |
response = requests.get( | |
f'{urlFrom}/{ocsApiPath}/cards/{cardId}/comments', | |
auth=authFrom, | |
headers=headersOcsJson) | |
response.raise_for_status() | |
return response.json() | |
def createBoard(title, color): | |
response = requests.post( | |
f'{urlTo}/{deckApiPath}/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}/{deckApiPath}/boards/{boardId}/labels/{labelId}', | |
auth=authTo, | |
headers=headers) | |
response.raise_for_status() | |
return board | |
def createLabel(title, color, boardId): | |
response = requests.post( | |
f'{urlTo}/{deckApiPath}/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}/{deckApiPath}/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}/{deckApiPath}/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}/{deckApiPath}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/assignLabel', | |
auth=authTo, | |
json={ | |
'labelId': labelId | |
}, | |
headers=headers) | |
response.raise_for_status() | |
def createAttachment(boardId, stackId, cardId, fileType, fileContent, mimetype, fileName): | |
url = f'{urlTo}/{deckApiPath}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments' | |
payload = {'type' : fileType} | |
files=[ | |
('file',(fileName, fileContent, mimetype)) | |
] | |
response = requests.post( url, auth=authTo, data=payload, files=files) | |
response.raise_for_status() | |
return response.json() | |
def createComment(cardId, message): | |
response = requests.post( | |
f'{urlTo}/{ocsApiPath}/cards/{cardId}/comments', | |
auth=authTo, | |
json={ | |
'message': message | |
}, | |
headers=headersOcsJson) | |
response.raise_for_status() | |
return response.json() | |
def archiveCard(card, boardId, stackId): | |
cardId = card['id'] | |
card['archived'] = True | |
response = requests.put( | |
f'{urlTo}/{deckApiPath}/boards/{boardId}/stacks/{stackId}/cards/{cardId}', | |
auth=authTo, | |
json=card, | |
headers=headers) | |
response.raise_for_status() | |
def copyCard(card, boardIdTo, stackIdTo, labelsMap, boardIdFrom): | |
createdCard = createCard( | |
card['title'], | |
card['type'], | |
card['order'], | |
card['description'], | |
card['duedate'], | |
boardIdTo, | |
stackIdTo | |
) | |
# copy attachments | |
attachments = getAttachments(boardIdFrom, card['stackId'], card['id']) | |
for attachment in attachments: | |
fileName = attachment['data'] | |
owner = attachment['createdBy'] | |
mimetype = attachment['extendedData']['mimetype'] | |
attachmentPath = attachment['extendedData']['path'] | |
path = f'remote.php/dav/files/{owner}{attachmentPath}' | |
fileContent = getAttachment(path).content | |
createAttachment(boardIdTo, stackIdTo, createdCard['id'], attachment['type'], fileContent, mimetype, fileName) | |
# 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) | |
# copy card comments | |
comments = getComments(card['id']) | |
if(comments['ocs']['data']): | |
for comment in comments['ocs']['data']: | |
createComment(createdCard['id'], comment['message']) | |
def archiveBoard(boardId, title, color): | |
response = requests.put( | |
f'{urlTo}/{deckApiPath}/boards/{boardId}', | |
auth=authTo, | |
json={ | |
'title': title, | |
'color': color, | |
'archived': True | |
}, | |
headers=headers) | |
response.raise_for_status() | |
# get boards list | |
print('Starting script') | |
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, boardIdFrom) | |
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, boardIdFrom) | |
print(' Created', len(stack['cards']), 'archived cards') | |
# archive board if it was archived | |
if(board['archived']): | |
archiveBoard(board['id'], board['title'], board['color']) | |
print(' Archived board') |
Hey, I get a module not found error, for requests ? any tips?
edit: found it at https://pypi.org/project/requests/
Hey,
yes right, you need to install requests module with either pip install requests
for Python 2 or pip3 install requests
for Python 3. Did the gist work for you afterwards?
Edit: Added a comment about the module to the first line of the script.
Hey, I get a module not found error, for requests ? any tips?
edit: found it at https://pypi.org/project/requests/
Thx for this script! Works nicely ;)
This was an absolute lifesaver, thank you it worked perfectly. Point of note for anyone who gets auth error obviously you need to disable 2FA as well as disable Enforce 2FA if you have it set as otherwise it will halt.
Thanks! this worked perfectly for me, going from Snap install to Docker AIO. I'm very happy the comments and attachments migrated. Minor point: archived decks become un-archived when migrated.
This was an absolute lifesaver, thank you it worked perfectly. Point of note for anyone who gets auth error obviously you need to disable 2FA as well as disable Enforce 2FA if you have it set as otherwise it will halt.
Thanks for the feedback! 2FA can also stay enabled if you use an app password instead of the user password. I added comments about this in the script.
Thanks! this worked perfectly for me, going from Snap install to Docker AIO. I'm very happy the comments and attachments migrated. Minor point: archived decks become un-archived when migrated.
Thanks for your feedback! I fixed the point regarding deck archiving in the latest revision. It works now.
Worked really well. Can't thank you enough, dude!
Hi, I'm getting an SSL certification error even though the site has a valid certificate.
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='cloud.scape-net.de', port=443): Max retries exceeded with url: //index.php/apps/deck/api/v1.1/boards (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])")))
I have tried to switch off the certification in the script but it does not work
session = requests.Session()
session.verify = False
Any idea how to solve the problem?
Thanks
Hi, I'm getting an SSL certification error even though the site has a valid certificate. Any idea how to solve the problem?
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='cloud.scape-net.de', port=443): Max retries exceeded with url: //index.php/apps/deck/api/v1.1/boards (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])")))
Thanks
Hi @mafunken ,
I haven't encountered this error before. Perhaps you can try adding verify=False
to the requests, see https://stackoverflow.com/a/72546332 . Let me know if it works. If yes, I could add an option for skipping verification in the script. Don't know if that would be a good idea though.
Edit: Instead of using session, try to add verify=False
directly to the request calls. E.g.
def getBoards():
response = requests.get(
f'{urlFrom}/{deckApiPath}/boards',
auth=authFrom,
headers=headers,
verify=False)
response.raise_for_status()
If it doesn't help, you can also write disable_warnings(InsecureRequestWarning)
at the beginning of the script (see linked Stackoverflow answer above).
Also, please make sure that you enter the root URL of your old Nextcloud installation without trailing slash in line 7. From your stack trace it seems that you have a double slash after the URL. Let me know if that helps.
I tried to reach your address and it took nearly 30 Seconds for the Handshake. So maybe it's a timeout!?
Hi @CodeShakingSheep,
works except for the attachments if I add verify=False to every single request.get of the fromURL. I commented out the attachments so that I could migrate my personal board even though the script was cancelled.
Since I need to migrate more boards from my account, I ran the script again and now I get this error message:
Starting script
Created board Persönlich
Traceback (most recent call last):
File "nextcloud-deck-export-import_scape-Matthias03.py", line 248, in
boardDetails = getBoardDetails(board['id'])
File "nextcloud-deck-export-import_scape-Matthias03.py", line 41, in getBoardDetails
response.raise_for_status()
File "/usr/lib/python3/dist-packages/requests/models.py", line 940, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://cloud.scape-net.de/index.php/apps/deck/api/v1.1/boards/5
Any advice on how I can resolve this?
Thank you very much
@mafunken Regarding attachments: Are you using v1.1 in deckApiPath
? The way it's implemented it only works with API v 1.1 (not with API v 1.0). If you use API v 1.1 what was the error message you got for attachments?
Hm, regarding the 403 error, I'm not sure. I don't think it's a permission issue as your user had access to the board, so it should also have same permissions for board details. Might be your hosting company blocking requests. There was a similar issue a while back https://help.nextcloud.com/t/suddenly-started-receiving-403-errors/3307/11 .
So, you wrote that you already imported your personal board to your new Nextcloud instance. Probably that was the board "Persönlich", right? If so, you can also skip this board by adding something like this (untested, just an idea).
This in line 234:
# List of board names to be excluded
excluded_boards = ["Persönlich"]
Then add this after line 236:
board_name = board['title']
# Check if the current board's name is in the exclusion list
if board_name in excluded_boards:
print(f"Skipping board: {board_name}")
continue
Hey.. thx for this very very helpfull script!
When i was using it, after several boards, i got this error:
Traceback (most recent call last):
File "/tmp/lala/nextcloud-deck-export-import.py", line 262, in <module>
copyCard(card, boardIdTo, stackIdTo, labelsMap, boardIdFrom)
File "/tmp/lala/nextcloud-deck-export-import.py", line 199, in copyCard
attachmentPath = attachment['extendedData']['path']
~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
KeyError: 'path'
Any idea about this? It seems to happen on every card with an attachment. Maybe, because those Decks are shared with me and attachments are not uploaded by me?
Or maybe because this is an old nextcloud (v22.2.10) with old deck-app (v1.5.8)? Browser-inspector says, for example this url works to download the file:
GET
https://cloud.foo.bar/apps/deck/cards/76/attachment/1
EDIT: This works for me:
Changing this
def getAttachment(path):
response = requests.get(
f'{urlFrom}/remote.php/dav/files/{authFrom[0]}{path}',
auth=authFrom,
headers=headers)
response.raise_for_status()
return response
to this:
def getAttachment(cardId, attachmentId):
response = requests.get(
f'{urlFrom}/apps/deck/cards/{cardId}/attachment/{attachmentId}',
auth=authFrom,
headers=headers)
response.raise_for_status()
return response
And also changing this:
# copy attachments
attachments = getAttachments(boardIdFrom, card['stackId'], card['id'])
for attachment in attachments:
fileName = attachment['data']
mimetype = attachment['extendedData']['mimetype']
attachmentPath = attachment['extendedData']['path']
path = f'{urlFrom}/remote.php/dav/files/{authFrom[0]}{attachmentPath}'
fileContent = getAttachment(attachmentPath).content
createAttachment(boardIdTo, stackIdTo, createdCard['id'], attachment['type'], fileContent, mimetype, fileName)
to this:
# copy attachments
attachments = getAttachments(boardIdFrom, card['stackId'], card['id'])
for attachment in attachments:
fileName = attachment['data']
mimetype = attachment['extendedData']['mimetype']
fileContent = getAttachment(card['id'], attachment['id']).content
createAttachment(boardIdTo, stackIdTo, createdCard['id'], attachment['type'], fileContent, mimetype, fileName)
Second:
What do you think about commandline options for include/exclude boards? Sometimes People don't want to migrate all boards at the same time..
Hi, I am using this script to transfer form my old instance to an AIO instance, both currently running parallel in Docker, the old one is obviously only running locally, with no domain and direct IP connection and works as it did before. the AIO is already running in production mode, with a domain.
the script however is painfully slow. I'm talking many minutes just to create a board, and it's probably going to be hours or days to do all the cards and other boards I have. Is this normal to be so slow? both instances a running Deck 1.12.2 so that is API 1.1.
the original script was much faster but had issues with many cards and would crash.
I am also still getting errors when trying to import certain boards. not all, but some:
Created board 02_Hallways
Traceback (most recent call last):
File "/home/user/Downloads/nextcloud-deck-export-import/nextcloud-deck-export-import2.py", line 265, in
createdStack = createStack(stack['title'], stack['order'], boardIdTo)
File "/home/user/Downloads/nextcloud-deck-export-import/nextcloud-deck-export-import2.py", line 127, in createStack
response.raise_for_status()
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: 400 Client Error: Bad Request for url: https://nextcloud.domain.tld/index.php/apps/deck/api/v1.1/boards/76/stacks
not really sure what is going on there.
Hey.. thx for this very very helpfull script!
Hi, Thanks for your feedback!
When i was using it, after several boards, i got this error:
Traceback (most recent call last): File "/tmp/lala/nextcloud-deck-export-import.py", line 262, in <module> copyCard(card, boardIdTo, stackIdTo, labelsMap, boardIdFrom) File "/tmp/lala/nextcloud-deck-export-import.py", line 199, in copyCard attachmentPath = attachment['extendedData']['path'] ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^ KeyError: 'path'Any idea about this? It seems to happen on every card with an attachment. Maybe, because those Decks are shared with me and attachments are not uploaded by me? Or maybe because this is an old nextcloud (v22.2.10) with old deck-app (v1.5.8)? Browser-inspector says, for example this url works to download the file:
GET https://cloud.foo.bar/apps/deck/cards/76/attachment/1
This is interesting. I haven't encountered this yet. I'm not sure if your specific error is related to another user having initially uploaded the file. In theory, key path
should always exist from my understanding. Not sure what's going on here.
Though, you are right about the attachment owner issue. That slipped through. I will push a fix for this in a few minutes.
EDIT: This works for me: Changing this
def getAttachment(path): response = requests.get( f'{urlFrom}/remote.php/dav/files/{authFrom[0]}{path}', auth=authFrom, headers=headers) response.raise_for_status() return responseto this:
def getAttachment(cardId, attachmentId): response = requests.get( f'{urlFrom}/apps/deck/cards/{cardId}/attachment/{attachmentId}', auth=authFrom, headers=headers) response.raise_for_status() return responseAnd also changing this:
# copy attachments attachments = getAttachments(boardIdFrom, card['stackId'], card['id']) for attachment in attachments: fileName = attachment['data'] mimetype = attachment['extendedData']['mimetype'] attachmentPath = attachment['extendedData']['path'] path = f'{urlFrom}/remote.php/dav/files/{authFrom[0]}{attachmentPath}' fileContent = getAttachment(attachmentPath).content createAttachment(boardIdTo, stackIdTo, createdCard['id'], attachment['type'], fileContent, mimetype, fileName)to this:
# copy attachments attachments = getAttachments(boardIdFrom, card['stackId'], card['id']) for attachment in attachments: fileName = attachment['data'] mimetype = attachment['extendedData']['mimetype'] fileContent = getAttachment(card['id'], attachment['id']).content createAttachment(boardIdTo, stackIdTo, createdCard['id'], attachment['type'], fileContent, mimetype, fileName)
I'm happy that you found a solution for this error. I just checked the script with your changes and in my case unfortunately, I receive a HTTP 403 response when using https://mynextcloud.tld/apps/deck/cards/11/attachment/1
.
{
"status": 403,
"message": "Permission denied"
}
So, for now I prefer to leave the URLs as they are as in my case the changes aren't working. Unfortunately, I don't have the capacity to investigate this further at the moment. If more people report this issue, I will consider changing it. Thanks for your investigation on this so far!
Second: What do you think about commandline options for include/exclude boards? Sometimes People don't want to migrate all boards at the same time..
Yes, I'm in for that. I have been wanting to do that for some time as the request to exclude boards already came up. I will see if I can find time next week to implement this.
Hi, I am using this script to transfer form my old instance to an AIO instance, both currently running parallel in Docker, the old one is obviously only running locally, with no domain and direct IP connection and works as it did before. the AIO is already running in production mode, with a domain.
the script however is painfully slow. I'm talking many minutes just to create a board, and it's probably going to be hours or days to do all the cards and other boards I have. Is this normal to be so slow? both instances a running Deck 1.12.2 so that is API 1.1.
the original script was much faster but had issues with many cards and would crash.
Yes, the script is slow. I just took over the base logic from the original script and didn't look specifically into performance optimization as I just used this script one time for my own migration. The original script has fewer requests as it doesn't migrate attachments and comments. So, it makes sense for this script to be slower.
I think a possible approach to speed it up would be to use connection pooling or async programming, see here. Unfortunately, I don't have the capacity to implement and test this at the moment. If you want to jump into it, you're more than welcome to fork this gist, do the optimization and post the link here. I would happily review and apply the changes then.
I am also still getting errors when trying to import certain boards. not all, but some:
Created board 02_Hallways
Traceback (most recent call last):
File "/home/user/Downloads/nextcloud-deck-export-import/nextcloud-deck-export-import2.py", line 265, in
createdStack = createStack(stack['title'], stack['order'], boardIdTo)
File "/home/user/Downloads/nextcloud-deck-export-import/nextcloud-deck-export-import2.py", line 127, in createStack
response.raise_for_status()
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: 400 Client Error: Bad Request for url: https://nextcloud.domain.tld/index.php/apps/deck/api/v1.1/boards/76/stacksnot really sure what is going on there.
Hm, not sure either. You could try to omit /index.php
from the URL. Also, I just updated the script. So, perhaps you can try with the new version, although I don't think the changes will affect your error.
Hey,
First of all, I would like to thank you for your work.
I noticed that for accounts where the personal deck is missing the synchronization breaks off with this error message.
Starting script
Created board Personal
Traceback (most recent call last):
File "/home/John/Downloads/e6efe69f2f7082ceb590e8ce68fa2bfc-9f2d3ed64f151f158fe6be7b899d3fd78b147e24/nextcloud-deck-export-import.py", line 245, in <module>
boardDetails = getBoardDetails(board['id'])
File "/home/John/Downloads/e6efe69f2f7082ceb590e8ce68fa2bfc-9f2d3ed64f151f158fe6be7b899d3fd78b147e24/nextcloud-deck-export-import.py", line 37, in getBoardDetails
response.raise_for_status()
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://my.example.com/index.php/apps/deck/api/v1.1/boards/1
Unfortunately, it didn't stop at this one mistake. The following error message is clearly too complex for me. I therefore wanted to ask if anyone can help me with this?
Stack Erledigt
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 169, in _new_conn
conn = connection.create_connection(
File "/usr/lib/python3/dist-packages/urllib3/util/connection.py", line 96, in create_connection
raise err
File "/usr/lib/python3/dist-packages/urllib3/util/connection.py", line 86, in create_connection
sock.connect(sa)
TimeoutError: [Errno 110] Connection timed out
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 700, in urlopen
httplib_response = self._make_request(
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 383, in _make_request
self._validate_conn(conn)
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 1017, in _validate_conn
conn.connect()
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 353, in connect
conn = self._new_conn()
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 174, in _new_conn
raise ConnectTimeoutError(
urllib3.exceptions.ConnectTimeoutError: (<urllib3.connection.HTTPSConnection object at 0x7f192856c970>, 'Connection to server2.com timed out. (connect timeout=None)')
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/requests/adapters.py", line 439, in send
resp = conn.urlopen(
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 756, in urlopen
retries = retries.increment(
File "/usr/lib/python3/dist-packages/urllib3/util/retry.py", line 574, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='server2.com', port=443): Max retries exceeded with url: /index.php/apps/deck/api/v1.1/boards/10/stacks/18/cards (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at 0x7f192856c970>, 'Connection to server2.com timed out. (connect timeout=None)'))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/John/Downloads/e6efe69f2f7082ceb590e8ce68fa2bfc-9f2d3ed64f151f158fe6be7b899d3fd78b147e24/Johannah.py", line 274, in <module>
copyCard(card, boardIdTo, stacksMap[stack['id']], labelsMap, boardIdFrom)
File "/home/John/Downloads/e6efe69f2f7082ceb590e8ce68fa2bfc-9f2d3ed64f151f158fe6be7b899d3fd78b147e24/Johannah.py", line 184, in copyCard
createdCard = createCard(
File "/home/John/Downloads/e6efe69f2f7082ceb590e8ce68fa2bfc-9f2d3ed64f151f158fe6be7b899d3fd78b147e24/Johannah.py", line 127, in createCard
response = requests.post(
File "/usr/lib/python3/dist-packages/requests/api.py", line 119, in post
return request('post', url, data=data, json=json, **kwargs)
File "/usr/lib/python3/dist-packages/requests/api.py", line 61, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 544, in request
resp = self.send(prep, **send_kwargs)
File "/usr/lib/python3/dist-packages/requests/sessions.py", line 657, in send
r = adapter.send(request, **kwargs)
File "/usr/lib/python3/dist-packages/requests/adapters.py", line 504, in send
raise ConnectTimeout(e, request=request)
requests.exceptions.ConnectTimeout: HTTPSConnectionPool(host='server2.com', port=443): Max retries exceeded with url: /index.php/apps/deck/api/v1.1/boards/10/stacks/18/cards (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at 0x7f192856c970>, 'Connection to server2.com timed out. (connect timeout=None)'))
I would be very grateful to the person and they would take the pain out of copying everything by hand
Getting this one?!
Created stack Speicher
Traceback (most recent call last):
File "bin/deck_ex_import.py", line 263, in <module>
copyCard(card, boardIdTo, stackIdTo, labelsMap, boardIdFrom)
File "bin/deck_ex_import.py", line 208, in copyCard
assignLabel(labelsMap[label['id']], createdCard['id'], boardIdTo, stackIdTo)
KeyError: 11
Saved my cute, little hind-side! Thank you very much. It worked like a charm and helped me change my hosted Nextcloud to another provider.