@ -1,26 +1,45 @@
import argparse
import datetime
import sys
import time
import xml.etree.ElementTree as ET
import requests
# Prepare and send the propfind request return xml string
# we only need one session for the whole script
session = requests . Session ( )
def propfind ( path , auth ) :
"""
Get a file ' s Last Modified timestamp and FileID via a PROPFIND request
: param path : The path of the file in question
: param auth : Auth data for the HTTP request ( e . g . a requests . auth . HTTPBasicAuth object )
: return : The properties in XML format
"""
headers = { " Depth " : " 1 " }
# This body returns only the timelastmodified and the fileid variable
data = " <d:propfind xmlns:d= \" DAV: \" xmlns:oc= \" http://owncloud.org/ns \" xmlns:nc= \" http://nextcloud.org/ns \" > " + " <d:prop> " + " <d:getlastmodified /> " + " <oc:fileid /> " + " </d:prop> " + " </d:propfind> "
req = r = requests . Request ( " PROPFIND " , path , headers = headers , auth = auth , data = data )
requested_data = \
"""
< d : propfind xmlns : d = \" DAV: \" xmlns:oc= \" http://owncloud.org/ns \" xmlns:nc= \" http://nextcloud.org/ns \" >
< d : prop >
< d : getlastmodified / >
< oc : fileid / >
< / d : prop >
< / d : propfind >
"""
req = requests . Request ( " PROPFIND " , path , headers = headers , auth = auth , data = requested_data )
prepped = req . prepare ( )
s = requests . Session ( )
resp = s . send ( prepped )
resp = session . send ( prepped )
return resp . text
# Function iterates through the given xml which contains all files and folders in the provided path
def search_folder ( requestreturn ) :
"""
Iterates through a folder ' s properties XML and returns
: param requestreturn :
: return :
"""
# List to collect path of folders stored in path
innerfolders = [ ]
# List to collect path of files with wrong timestamp
@ -53,11 +72,16 @@ def search_folder(requestreturn):
if lastmodified < 631148400 :
for fileid in p . findall ( ' .//{http://owncloud.org/ns}fileid ' ) :
linkswrongtime . append ( fileid . text )
return [ innerfolders , linkswrongtime ]
return ( innerfolders , linkswrongtime )
# This function returns the fileid of the version of a given fileid with the most current timestamp or None if there are no versions with a timestamp younger than 01.01.1990
def version_check ( xmlfile ) :
"""
This function returns the fileid of the version of a given fileid with the most current timestamp or None if
there are no versions with a timestamp younger than 01.01 . 1990
: param xmlfile : An XML file with Last Modified timestamps and FileIDs as returned by propfind ( )
: return : The FileID of the most recent version or None if no valid version exists
"""
tree = ET . ElementTree ( ET . fromstring ( xmlfile ) )
# Name of files are stored as a string. But we can check the timestamp of the file only after we can check the name,
# so it needs to be stored temporary in case the timestamp is the most current
@ -91,14 +115,23 @@ def version_check(xmlfile):
if __name__ == " __main__ " :
# Enter username and password to enter nextcloud via webdav
user = sys . argv [ 1 ]
passw = sys . argv [ 2 ]
auth = requests . auth . HTTPBasicAuth ( user , passw )
# get all necessary data from the command line
argparser = argparse . ArgumentParser ( description = " Fix broken dates in Nextcloud folders. " )
argparser . add_argument ( " server " , help = " The base URL of the Nextcloud server. " )
argparser . add_argument ( " username " , help = " The user to log in as. " )
argparser . add_argument ( " password " , help = " The password for accessing Nextcloud. Hint: Use an App Token! " )
argparser . add_argument (
" -p " , " --path " ,
default = " / " ,
help = " The path to search, relative to the user ' s root. Default: / " ,
dest = " search_path "
)
arguments = argparser . parse_args ( )
# Prepare HTTP Basic Authentication
auth = requests . auth . HTTPBasicAuth ( arguments . username , arguments . password )
# Prepare the path we want to use
prefix_path = " https://kingsx.cs.uni-saarland.de "
mainpath = " /remote.php/dav/files/ " + user + " /Testrequests/ "
# List of all folderpaths we need to enter
mainpath = " /remote.php/dav/files/ " + arguments . username + arguments . search_path
# List of all folders we need to enter
folders = [ mainpath ]
# List of all fileids with wrong time
wrongtime = [ ]
@ -106,16 +139,18 @@ if __name__ == "__main__":
# Iterate through all folders and check for wrong timestamps
while folders :
path_suffix = folders . pop ( 0 )
path = prefix_path + str ( path_suffix )
path = arguments . server + str ( path_suffix )
r = propfind ( path , auth )
res = search_folder ( r )
new_folders , new_wrongtime = search_folder ( r )
# Append all found folders and files with wrong timestamps to global list
folders = folders + res [ 0 ]
wrongtime = wrongtime + res [ 1 ]
folders + = new_folders
wrongtime + = new_wrongtime
# Iterate through all fileids with wrong timestamps and check for versions with intact timestamp
while wrongtime :
fileid = wrongtime . pop ( 0 )
version_suffix = " /remote.php/dav/versions/ " + user + " /versions/ " + fileid
version_path = prefix_path + version_suffix
version_suffix = " /remote.php/dav/versions/ " + arguments . username + " /versions/ " + fileid
version_path = arguments . server + version_suffix
versions = propfind ( version_path , auth )
print ( version_check ( versions ) )
mrv = version_check ( versions )
print ( fileid , end = " : " )
print ( mrv )