Fed up with the occasional spam attacks, I've written a Python script to undo changes from a given name or IP address, when using the VersioningFileProvider.
Its a bit convoluted, I've no time to make it better, but it may be of interest. You really should back up your pages directory, save the script as unspam.py and then run as
python unspam.py /pathto/pages.dir 61.145.233.118
or
python unspam.py /pathto/pages.dir BadPersonName
You'll have to restart to clear the CachingProvider cache if you're using it.
import sys
import os
import os.path
import re
import shutil
class PropertiesLine:
def __init__(self, line):
match = re.match(r'^(\d*).(.*)=(.*)', line)
if match != None:
self.version, self.tag, self.value = match.groups()
self.version = int(self.version)
else:
self.tag = self.version = self.value = None
def __repr__(self):
return '%s.%s=%s' % (self.version, self.tag, self.value)
def parseLine(line):
return PropertiesLine(line)
def moveFile(src, dest):
print 'moving %s to %s' % (src, dest)
shutil.copy2(src, dest)
os.remove(src)
def deleteFile(src):
print 'deleting %s' % src
os.remove(src)
class PropertiesFile:
def __init__(self, filename):
self.filename = filename
file = open(self.filename)
try:
self.lines = file.readlines()
finally:
file.close()
def latestEdit(self):
latestVersion = -1
result = None
for line in self.lines:
pLine = parseLine(line)
if pLine.version > latestVersion:
latestVersion = pLine.version
result = pLine
return result
def removeVersion(self, version):
self.lines = filter(lambda x: parseLine(x).version != version, self.lines)
def save(self):
file = open(self.filename, 'w')
try:
file.writelines(self.lines)
finally:
file.close()
class Page:
def __init__(self, filename):
self.filename = filename
self.dir, self.file = os.path.split(filename)
self.name = os.path.splitext(self.file)[0]
propertiesFilename = os.path.join(self.historyDir(), 'page.properties')
if os.path.exists(propertiesFilename):
self.propertiesFile = PropertiesFile(propertiesFilename)
else:
self.propertiesFile = None
def versionFilename(self, version):
return os.path.join(self.historyDir(), str(version) + '.txt')
def historyDir(self):
return os.path.join(self.dir, 'OLD', self.name)
def isLastEditBy(self, name):
if self.propertiesFile == None:
return 0
latestEdit = self.propertiesFile.latestEdit()
return latestEdit.value == name
def latestVersion(self):
if self.propertiesFile == None:
return -1
return self.propertiesFile.latestEdit().version
def undoLastEdit(self):
if self.propertiesFile == None:
return
latestVersion = self.latestVersion()
versionToRestore = latestVersion - 1
backupFile = os.path.join(self.historyDir(), 'spam-deleted-' + str(latestVersion)) + '.txt'
moveFile(self.filename, backupFile)
if versionToRestore >= 1:
moveFile(self.versionFilename(versionToRestore), self.filename)
self.propertiesFile.removeVersion(latestVersion)
self.propertiesFile.save()
def __repr__(self):
return 'Page %s' % (self.name)
class Site:
def __init__(self, dir):
self.dir = dir
self.pages = []
for filename in os.listdir(dir):
root, ext = os.path.splitext(filename)
if ext == '.txt':
self.pages.append(Page(os.path.join(dir, filename)))
def undoEditsBy(self, name):
for page in self.pagesWithLastEditBy(name):
page.undoLastEdit()
def pagesWithLastEditBy(self, name):
for page in self.pages:
if page.isLastEditBy(name):
yield page
if __name__ == "__main__":
if len(sys.argv) == 2:
dir = '.'
name = sys.argv[1]
else:
dir = sys.argv[1]
name = sys.argv[2]
Site(dir).undoEditsBy(name)