root/hodgestar/PythonCode/Tiki2Pm/tikiwiki.py

Revision 377, 15.7 kB (checked in by simon, 4 years ago)

Scripts for moving TikiWiki? data into PmWiki? and transforming the markup.

  • Property svn:mime-type set to text/python-source
  • Property svn:eol-style set to native
Line 
1import re, datetime
2from MySQLdb.cursors import DictCursor
3
4#
5# Tiki to PmWiki Markup Rules
6#
7
8class Tiki2PmWiki(object):
9    class HelperFunctions:
10        @classmethod
11        def pipeToPipePipe(cls,oM):
12            return "||" + oM.group(1).replace('|','||') + "||"
13
14        @classmethod
15        def newlineToPipePipe(cls,oM):
16            return "||border=1\n||" + oM.group(1).replace("\n","||\n||")  + "||"
17
18        @classmethod
19        def boxQuotes(cls,oM):
20            s = oM.group(1)
21            if len(s) < 5: return oM.group(0)
22            else: return "\n->''" + s.replace("\n","\\\\\\\n") + "''"
23
24        oSrc = re.compile(r"\ssrc=([^\s}]*)")
25        oLink = re.compile(r"\slink=([^\s}]*)")
26        oDesc = re.compile(r"\sdesc=([^\s}]*)")
27
28        @classmethod
29        def imgLink(cls,oImgM):
30            s = oImgM.group(0)
31
32            oM = cls.oDesc.search(s)
33            if oM: sDesc = '"' + oM.group(1) + '"'
34            else: sDesc = ''
35
36            oM = cls.oLink.search(s)
37            if oM: sLink = oM.group(1) + ' | '
38            else: sLink = ''
39
40            oM = cls.oSrc.search(s)
41            if oM: return '[[' + sLink + oM.group(1) + sDesc + ']]'
42            else: return s
43
44        @classmethod
45        def imageAttach(cls,oM):
46            filename = oM.group(1)
47            filename = filename.replace(" ","_")
48            return "Attach:%s" % filename
49
50        @classmethod
51        def safePageName(cls,s):
52            s = s.replace("/"," ")
53            s = s.replace(":"," ")
54            s = s.replace("."," ")
55            s = s.replace("-"," ")
56            s = s.replace("?"," ")
57            s = s.replace("!"," ")
58            s = s.replace("'"," ")
59            s = s.replace("_"," ")
60            s = s.replace("-"," ")
61            parts = s.split()
62            for i, part in enumerate(parts):
63                parts[i] = parts[i][0].upper() + parts[i][1:]
64            return " ".join(parts)
65
66        @classmethod
67        def wikiLink(cls,oM):
68            pagename = oM.group(1)
69            parts = pagename.split("|")
70            parts[0] = cls.safePageName(parts[0])
71            return "[[%s]]" % "|".join(parts)
72
73        @classmethod
74        def fixPreformatted(cls,oM):
75            preformatted = oM.group(1)
76            return "[@%s@]" % preformatted.replace('\\\\\n','\n')
77
78        @classmethod
79        def colourStyle(cls,oM):
80            rgb = oM.group(1)
81            text = oM.group(2)
82            return "%%color=#%s%% %s%%%%" % (rgb.lower(),text)
83
84    aSmilies = [
85        ("wink",";-)"), ("biggrin",":-D"), ("cool","8-)"), ("smile",":-)"),
86        ("sad",":-("), ("mrgreen",":-D"), ("eek",":-O"), ("confused","o_O"),
87        ("twisted",":-p"), ("evil",">:-("), ("exclaim",":-!"), ("frown",":-("),
88        ("cry","T_T"), ("lol",":-D"), ("idea",":-)"), ("mad",">:-X"),
89        ("rolleyes","e_e"),
90        ("neutral",":-|"), ("question",":-?"), ("razz",":-P"), ("redface",">_>;"), ("surprised","O_O"),
91        ("arrow","-->")
92    ]
93
94    aIntermapURLs = [
95        (r'https:\/\/192.168.1.21\/DSPFiles\/','dspfiles:'),
96        (r'https:\/\/katfs.kat.ac.za\/CompFiles\/','compfiles:'),
97        (r'https:\/\/katfs.kat.ac.za\/DSPFiles\/','dspfiles:'),
98        (r'https:\/\/katfs.kat.ac.za\/Public\/','public:'),
99        (r'https:\/\/katfs.kat.ac.za\/svnComputing\/','svncomp:'),
100        (r'https:\/\/katfs.kat.ac.za\/svnConfigDocuments\/','svnconfig:'),
101        (r'https:\/\/katfs.kat.ac.za\/svnCONRAD\/','svnconrad:'),
102        (r'https:\/\/katfs.kat.ac.za\/svnDBE\/','svndbe:'),
103        (r'https:\/\/katfs.kat.ac.za\/svnFeeds\/','svnfeeds:'),
104        (r'https:\/\/katfs.kat.ac.za\/svnProjectManagement\/','svnpm:'),
105        (r'https:\/\/katfs.kat.ac.za\/svnRFE\/','svnrfe:'),
106        (r'https:\/\/katfs.kat.ac.za\/svnROACH\/','svnroach:'),
107        (r'https:\/\/katfs.kat.ac.za\/svnScience\/','svnscience:'),
108        (r'https:\/\/katfs.kat.ac.za\/svnSystemEngineering\/','svnse:')
109    ]
110
111
112    aRules = [
113        (re.compile(r"\r\n") , r"\n" , "ExtraCarriageReturn" ),
114        (re.compile(r"\r(?!\n)") , r"\n" , "RequiredCarriageReturn" ),
115        (re.compile(r"__") , r"'''" , "Bolding" ),
116        #(re.compile(r"([*]\b)([^\n]*?)(\b[*])"), r"'''\2'''", "PhpWikiBolding" ),
117        #(re.compile(r"(\b_)([^\n]*?)(_\b)"), r"''\2''", "PhpWikiItalics" ),
118        #(re.compile(r"%%%+($|\s)"), r"\\\\\1", "PhpWikiLineBreaks" ),
119        (re.compile(r"---+"), r"----", "HorizontalRule" ),
120        (re.compile(r"^\;([^:]*?)\:",flags=re.MULTILINE) , r":\1:" , "DefinitionLists" ),
121        (re.compile(r"~np~") , r"[=" , "EscapeParsing" ),
122        (re.compile(r"~\/np~") , r"=]", "EscapeParsing" ),
123        (re.compile(r"\|nocache") , r"", "RemoveNoCache" ),
124        #(re.compile(r"(^|[^[])\[([^]\n]*?)\]([^]]|$)",flags=re.MULTILINE) , r"\1[[\2]]\3" , "ExternalLinks" ),
125        (re.compile(r"(?<!\[)\[([^]\n]*?)\](?!\])",flags=re.MULTILINE) , r"[[\1]]" , "ExternalLinks" ),
126        (re.compile(r"\(\(\(([^)\n]*)\)\)\)",flags=re.MULTILINE) , HelperFunctions.wikiLink , "MessedUpWikiLinks" ),
127        (re.compile(r"\(\(([^)\n]*)\)\)",flags=re.MULTILINE) , HelperFunctions.wikiLink , "WikiLinks" ),
128        (re.compile(r"-=(.*?)=-") , r"!\1" , "BoxHeadings" ),
129        (re.compile(r"===(.*?)===") , r"{+\1+}" , "Underline" ),
130        (re.compile(r"\|\|(.*?)\|\|",flags=re.DOTALL) , HelperFunctions.newlineToPipePipe , "Tables" ),
131        (re.compile(r"\|\|([^\n]*)\|\|") , HelperFunctions.pipeToPipePipe , "Tables" ),
132        (re.compile(r"\n<br>"), r"\n" , "LineBreaks" ),
133        (re.compile(r"<br>") , r"\\\\" , "LineBreaks" ),
134        #(re.compile(r"""^([^!_*#\n|][^\n]*[^\s\-*#|][ \t]*)(\n[^\s\-*#])""",flags=re.MULTILINE), r"\1\\\\\2", "InternalLineBreaks" ),
135        (re.compile(r"(?<!\n)\n(?!\n|!|_|\*|#|\||----)",flags=re.MULTILINE), r"\\\\\n", "InternalLineBreaks" ),
136        (re.compile(r"(!.*)\\\\"),r"\1\n","CorrectLineBreakAfterHeading"),
137        (re.compile(r"(\|\|)\\\\"),r"\1\n","CorrectLineBreakAfterTable"),
138        (re.compile(r"^([ \t]*)-{1,2}([ \t\w\[])",flags=re.MULTILINE), r"\1*\2", "DashedLists"),
139        (re.compile(r"(^|(\n[ \t\f\v]*\n))[ \t\f\v]+"), r"\1->" , "IndentedParagraphs" ),
140        (re.compile(r"^\s*[\^]([^\^]*?)[\^]",flags=re.MULTILINE), HelperFunctions.boxQuotes, "BoxQuotes" ),
141        (re.compile(r"\{maketoc\}"), r"(:toc:)" , "TableOfContents" ),
142        (re.compile(r"\{\s*img\s*[^}]*\}"), HelperFunctions.imgLink , "ImageLinks" ),
143        (re.compile(r"^\*\]",flags=re.MULTILINE), r"*" , "BulletLists" ),
144        (re.compile(r"(?<!\[)\[?(http[^\s\]])\]?(?!\])") , r"\1", "PlainHyperLinks" ),
145        (re.compile(r"~~#([A_F0-9][A_F0-9][A_F0-9][A_F0-9][A_F0-9][A_F0-9]):([^~]*)~~",flags=re.DOTALL), HelperFunctions.colourStyle, "ColourStyle"),
146        (re.compile(r"{picture file=img/wiki_up//([^}]*)}"), HelperFunctions.imageAttach , "Images"),
147        (re.compile(r"(Attach:.*)\\\\"),r"\1\n","CorrectLineBreakAfterImage"),
148        (re.compile(r"::(.*)::"), r"%center% \1 %%", "Center"),
149        (re.compile(r"{FORMULA\(\)}(.*?){FORMULA}",flags=re.DOTALL), r"{$\1$}", "LaTeX"),
150        (re.compile(r"{CODE\(\)}(.*?){CODE}",flags=re.DOTALL), HelperFunctions.fixPreformatted, "Code")
151    ]
152
153    aRules.extend([ (re.compile(r"\(:"+x+r":\)"),y,"Smilies") for x,y in aSmilies ])
154    aRules.extend([ (re.compile(x),y,"Intermap") for x,y in aIntermapURLs ])
155
156
157
158#
159# Tiki Object Classes
160#
161
162
163class Tiki(object):
164    def __init__(self,oTikiDbConn):
165        self._oConn = oTikiDbConn
166
167    def pages(self):
168        for oPage in TikiPage.fetchAll(self._oConn):
169            yield oPage
170           
171    def blogs(self):
172        for oBlog in TikiBlog.fetchAll(self._oConn):
173            yield oBlog
174           
175    def polls(self):
176        for oPoll in TikiPoll.fetchAll(self._oConn):
177            yield oPoll
178
179
180class TikiObject(object):
181    objectType = 'unknown' # Not Actual TikiWiki Type
182
183    def __init__(self,oTikiDbConn,sTitle,sData,sDescr,sAuthor,sDate):
184        self._oConn = oTikiDbConn
185        if not sTitle is None: self.title = sTitle
186        if not sData is None: self.data = sData
187        if not sDescr is None: self.description = sDescr
188        if not sAuthor is None: self.author = sAuthor
189        if not sDate is None: self.date = datetime.datetime.fromtimestamp(int(sDate))
190
191    def fetchAll(cls,oConn,aQueryArgs=None):
192        raise NotImplementedError
193
194    fetchAll = classmethod(fetchAll)
195
196
197class TikiTitleCommentableMixIn(object):
198    def comments(self):
199        for oComment in TikiComment.fetchAll(self._oConn,[self.title,self.objectType]):
200            yield oComment
201
202class TikiIdCommentableMixIn(object):
203    def comments(self):
204        for oComment in TikiComment.fetchAll(self._oConn,[self.id,self.objectType]):
205            yield oComment
206
207class TikiAttachableMixIn(object):
208    def attachments(self):
209        for oAttachment in TikiAttachment.fetchAll(self._oConn,[self.title]):
210            yield oAttachment
211
212class TikiPostableMixIn(object):
213    def posts(self):
214        for oPost in TikiBlogPost.fetchAll(self._oConn,[str(self.id)]):
215            yield oPost
216
217class TikiOptionableMixIn(object):
218    def options(self):
219        for oOption in TikiPollOption.fetchAll(self._oConn,[str(self.id)]):
220            yield oOption
221
222class TikiPage(TikiObject,TikiTitleCommentableMixIn,TikiAttachableMixIn):
223    objectType = 'wiki page'
224   
225    def fetchAll(cls,oConn,aQueryArgs=None):
226        sPageQuery = """
227            SELECT
228                tp.pageName as sTitle, tp.data as sData, tp.description as sDescr,
229                tp.creator as sAuthor, tp.lastModif as sDate
230            FROM
231                tiki_pages as tp
232            ORDER BY
233                tp.pageName
234        """
235        oCursor = DictCursor(oConn)
236        oCursor.execute(sPageQuery)
237       
238        for dRow in oCursor:
239            yield TikiPage(oConn,dRow['sTitle'],dRow['sData'],dRow['sDescr'],
240                                 dRow['sAuthor'],dRow['sDate'])
241           
242        oCursor.close()
243       
244    fetchAll = classmethod(fetchAll)
245
246               
247class TikiComment(TikiObject):
248    objectType = 'comment' # Not Actual TikiWiki Type
249
250    def fetchAll(cls,oConn,aQueryArgs=None):
251        sCommentQuery = """
252            SELECT 
253                cm.title as sTitle, cm.data as sData, cm.summary as sDescr,
254                cm.userName as sAuthor, cm.commentDate as sDate
255            FROM
256                tiki_comments as cm
257            WHERE
258                (cm.object = %s) and (cm.objectType = %s)
259            ORDER BY
260                cm.commentDate
261        """
262        oCursor = DictCursor(oConn)
263        oCursor.execute(sCommentQuery,aQueryArgs)
264       
265        for dRow in oCursor:
266            yield TikiComment(oConn,dRow['sTitle'],dRow['sData'],dRow['sDescr'],
267                                    dRow['sAuthor'],dRow['sDate'])
268           
269        oCursor.close()
270       
271    fetchAll = classmethod(fetchAll)
272
273class TikiAttachment(TikiObject):
274    objectType = 'attachment' # what does this do?
275   
276    def __init__(self,oTikiDbConn,sTitle,sData,sDescr,sAuthor,sDate,sFilename,sFiletype):
277        super(TikiAttachment, self).__init__(oTikiDbConn,sTitle,sData,sDescr,sAuthor,sDate)
278        if not sFilename is None: self.filename = sFilename
279        if not sFiletype is None: self.filetype = sFiletype
280
281    def fetchAll(cls,oConn,aQueryArgs=None):
282        sCommentQuery = """
283            SELECT 
284                att.data as sData,
285                att.user as sAuthor, att.created as sDate,
286                att.filename as sFilename, att.filetype as sFiletype
287            FROM
288                tiki_wiki_attachments as att
289            WHERE
290                (att.page = %s)
291            ORDER BY
292                att.created
293        """
294        oCursor = DictCursor(oConn)
295        oCursor.execute(sCommentQuery,aQueryArgs)
296       
297        for dRow in oCursor:
298            yield TikiAttachment(oConn,None,dRow['sData'],None,
299                                    dRow['sAuthor'],dRow['sDate'],dRow['sFilename'],dRow['sFiletype'])
300           
301        oCursor.close()
302       
303    fetchAll = classmethod(fetchAll)
304
305class TikiBlog(TikiObject,TikiIdCommentableMixIn,TikiPostableMixIn):
306    objectType = 'blog'
307
308    def __init__(self,oTikiDbConn,sTitle,sData,sDescr,sAuthor,sDate,iId):
309        super(TikiBlog,self).__init__(oTikiDbConn,sTitle,sData,sDescr,sAuthor,sDate)
310        self.id = iId
311
312    def fetchAll(cls,oConn,aQueryArgs=None):
313        sBlogQuery = """
314            SELECT 
315                blog.title as sTitle, blog.description as sData, blog.heading as sDescr,
316                blog.user as sAuthor, blog.lastModif as sDate, blog.blogId as sId
317            FROM
318                tiki_blogs as blog
319            ORDER BY
320                blog.title
321        """
322        oCursor = DictCursor(oConn)
323        oCursor.execute(sBlogQuery)
324       
325        for dRow in oCursor:
326            yield TikiBlog(oConn,dRow['sTitle'],dRow['sData'],dRow['sDescr'],
327                                 dRow['sAuthor'],dRow['sDate'],int(dRow['sId']))
328           
329        oCursor.close()
330       
331    fetchAll = classmethod(fetchAll)
332
333
334class TikiBlogPost(TikiObject,TikiIdCommentableMixIn):
335    objectType = 'post'
336
337    def __init__(self,oTikiDbConn,sTitle,sData,sDescr,sAuthor,sDate,iId):
338        super(TikiBlogPost,self).__init__(oTikiDbConn,sTitle,sData,sDescr,sAuthor,sDate)
339        self.id = iId
340
341    def fetchAll(cls,oConn,aQueryArgs=None):
342        sPostQuery = """
343            SELECT 
344                post.title as sTitle, post.data as sData,
345                post.user as sAuthor, post.created as sDate, post.postId as sId
346            FROM
347                tiki_blog_posts as post
348            WHERE
349                (post.blogId = %s)
350            ORDER BY
351                post.title
352        """
353        oCursor = DictCursor(oConn)
354        oCursor.execute(sPostQuery,aQueryArgs)
355       
356        for dRow in oCursor:
357            yield TikiBlogPost(oConn,dRow['sTitle'],dRow['sData'],None,
358                                     dRow['sAuthor'],dRow['sDate'],int(dRow['sId']))
359           
360        oCursor.close()
361       
362    fetchAll = classmethod(fetchAll)
363
364
365class TikiPoll(TikiObject,TikiIdCommentableMixIn,TikiOptionableMixIn):
366    objectType = 'poll'
367
368    def __init__(self,oTikiDbConn,sTitle,sData,sDescr,sAuthor,sDate,iId):
369        super(TikiPoll,self).__init__(oTikiDbConn,sTitle,sData,sDescr,sAuthor,sDate)
370        self.id = iId
371
372    def fetchAll(cls,oConn,aQueryArgs=None):
373        sPollQuery = """
374            SELECT 
375                poll.title as sTitle, poll.publishDate as sDate, poll.pollId as sId
376            FROM
377                tiki_polls as poll
378            ORDER BY
379                poll.title
380        """
381        oCursor = DictCursor(oConn)
382        oCursor.execute(sPollQuery)
383       
384        for dRow in oCursor:
385            yield TikiPoll(oConn,dRow['sTitle'],None,None,None,
386                                 dRow['sDate'],int(dRow['sId']))
387           
388        oCursor.close()
389       
390    fetchAll = classmethod(fetchAll)
391
392
393class TikiPollOption(TikiObject):
394    objectType = 'poll'
395
396    def __init__(self,oTikiDbConn,sTitle,sData,sDescr,sAuthor,sDate,iVotes):
397        super(TikiPollOption,self).__init__(oTikiDbConn,sTitle,sData,sDescr,sAuthor,sDate)
398        self.votes = iVotes
399
400    def fetchAll(cls,oConn,aQueryArgs=None):
401        sPostQuery = """
402            SELECT 
403                opt.title as sTitle, opt.votes as sVotes
404            FROM
405                tiki_poll_options as opt
406            WHERE
407                (opt.pollId = %s)
408            ORDER BY
409                opt.title
410        """
411        oCursor = DictCursor(oConn)
412        oCursor.execute(sPostQuery,aQueryArgs)
413       
414        for dRow in oCursor:
415            yield TikiPollOption(oConn,dRow['sTitle'],None,None,None,None,
416                                       int(dRow['sVotes']))
417           
418        oCursor.close()
419
420    fetchAll = classmethod(fetchAll)
421
422
423# To Be Started -->
424
425class TikiImage(TikiObject):
426    objectType = 'image' # Not Actual TikiWiki Type
427
428class TikiUser(TikiObject):
429    objectType = 'user' # Not Actual TikiWiki Type
Note: See TracBrowser for help on using the browser.