RecentChanges now stored in new .work subdirectory of pages, and can be used to gener...
authorPhil Jones <interstar@gmail.com>
Sat, 16 Sep 2017 22:29:45 +0000 (23:29 +0100)
committerPhil Jones <interstar@gmail.com>
Sat, 16 Sep 2017 22:29:45 +0000 (23:29 +0100)
python/servers/assets/page.tpl
python/servers/wiki.py
python/thoughtstorms/PageStore.py
python/thoughtstorms/txlib.py

index 609bfba..e501816 100755 (executable)
@@ -11,7 +11,7 @@
        <div class="menubar">\r
                <a href="/">HelloWorld</a> \r
                |\r
-               <a href="/view/RecentChanges">RecentChanges</a>\r
+               <a href="/service/recentchanges">RecentChanges</a>\r
 \r
                % if pageStore.is_writable() :\r
                | <a href="/{{editPathName}}/{{pageName}}">Edit this Page</a>\r
index 8ce9c20..dcfe783 100755 (executable)
@@ -5,6 +5,8 @@ from bottle import route, run, template, get, post, request, redirect, static_fi
 
 import bottle, yaml
 
+import difflib
+
 from thoughtstorms.PageStore import PageStore, WritablePageStore
 from thoughtstorms.txlib import MarkdownThoughtStorms, Environment
 
@@ -173,9 +175,11 @@ def delete(pname) :
 
 # Services
 wiki.service_names = [["services","/service/services","List of all Services on this wiki"], 
+                                         ["recentchanges","/service/recentchanges","RecentChanges of this wiki"],
                                          ["all","/service/all","List of all Pages in this wiki"],
                                          ["all raw","/service/all_raw","List of all Pages in raw text"],
-                                         ["raw","/service/raw/HelloWorld","Raw version of a page"],
+                                         ["raw","/service/raw/HelloWorld","Raw version of a page"],                                      
+                                         ["changed","/service/changed/HelloWorld","Diff between current and most recent old version of a page"],
                                          ["analyze","/service/analyze","Analyze a link to derive embeddable form and other useful data"],
                                          ["sister_sites","","Sister sites are defined on the data-page, and used in double-square links"],
                                          ["search","/service/search/HelloWorld","Crude grep for text in pages"]
@@ -215,6 +219,73 @@ def get_raw(pname) :
        response.content_type="text/text"
        return wiki.page_store.get(pname,lambda pname, e : "Page does not exist. Try <a href='/edit/%s'>editing</a>"%pname, lambda pname, e : "Error: %s" % e )
        
+@get('/service/recentchanges')
+def recentchanges() :
+       def layout(cs) :
+               if len(cs) > 1 :
+                       return """<tr><td><a href="/view/%s">%s</a></td><td>%s</td>
+                                         <td><a href="/service/additions/%s">additions</a></td>
+                                         <td><a href="/service/changed/%s">diff</td>
+                                         </tr>""" % (cs[0],cs[0],cs[1],cs[0],cs[0])
+               else :
+                       return "<!-- Error %s -->" % cs
+               
+       rcs = """<table class="table table-striped table-bordered table-condensed"> 
+<tr><th>Page</th><th>Date</th><th>Additions</th><th>Diff</th></tr>
+%s
+</table>""" % "\n".join((layout(x.split(",")) for x in wiki.page_store.get_recentchanges() ))
+       return make_page("RecentChanges",wiki.chef.cook(rcs,Environment("",wiki.get_sister_sites())),wiki)
+
+
+def diff(pname) :
+       new = wiki.page_store.get(pname, lambda pname, e : "Page does not exist.", lambda pname, e : "Error: %s" % e ).split("\n")
+       old = wiki.page_store.get_old(pname, lambda pname, e : "", lambda pname, e : "Error: %s" % e ).split("\n")
+       return difflib.Differ().compare(old,new)
+
+@get('/service/changed/<pname>')
+def changed(pname) :
+       raw = "\n".join(diff(pname))
+       
+       page = """
+
+Recent changes to this page :
+<br/>
+<textarea cols="120" rows="30">
+       
+%s
+
+</textarea>
+""" % raw  
+       return make_page(pname,page,wiki)
+       
+@get('/service/additions/<pname>')
+def additions(pname) :
+       xs = (x[2:] for x in diff(pname) if x[0:2]=="+ ")
+       raw = "\n".join(xs)
+       cooked = wiki.chef.cook(raw,Environment("",wiki.get_sister_sites()))
+       
+       d = """
+Additions to this page :
+<br/>
+Raw
+<br/>
+<textarea cols="120" rows="30">
+
+%s
+
+</textarea>
+<br/>
+Cooked
+<br/>
+<textarea cols="120" rows="30">
+
+%s
+
+</textarea>
+
+""" % (raw,cooked)
+       return make_page(pname,d,wiki)
+
 analyzer = Analyzer()
 
 @get('/service/analyze')
index d83bc48..6294715 100755 (executable)
@@ -1,15 +1,26 @@
 
 from subprocess import check_output, CalledProcessError
 
-import datetime, re
+import datetime, re, csv
 
 class PageStore :
-       
+               
        def __init__(self,pages_dir,extension,lc=False) :
                self.pages_dir = pages_dir
                self.extension = extension
                self.lower_case = lc
-       
+               self.init_common()
+
+       def init_common(self) :
+               self.work_dir = "%s/.work" % self.pages_dir
+               self.old_files_dir = "%s/old_pages" % self.work_dir
+               import os
+               try:
+                       os.makedirs(self.old_files_dir)
+               except Exception, e :
+                       print e
+
+                       
        def __str__(self) :
                return "(ReadOnly) PageStore with pages at %s" % self.pages_dir
        
@@ -18,6 +29,12 @@ class PageStore :
                        pName=pName.lower()                     
                return "%s/%s.%s" % (self.pages_dir,pName,self.extension)
                
+       def old_fName(self,pName) :
+               if self.lower_case :
+                       pName=pName.lower()
+               return "%s/%s.%s" % (self.old_files_dir,pName,self.extension)
+
+               
        def get(self,pName,no_file_handler,other_error_handler) :
                file_name = self.fName(pName)
                try :
@@ -28,7 +45,18 @@ class PageStore :
                                return no_file_handler(pName,e)
                        else :
                                return other_error_handler(pName,e)
-               
+       
+       def get_old(self,pName,no_file_handler,other_error_handler) :
+               file_name = self.old_fName(pName)
+               try :
+                       with open(file_name) as f :
+                               return f.read().decode("utf-8")
+               except Exception, e :
+                       if "No such file or directory:" in "%s"%e :
+                               return no_file_handler(pName,e)
+                       else :
+                               return other_error_handler(pName,e)
+       
 
        def is_writable(self) : return False
        
@@ -78,6 +106,9 @@ class WritablePageStore(PageStore) :
                self.extension = extension
                self.lower_case = lc
                self.recent_changes = recent_changes
+               self.init_common()
+               
+
 
        def __str__(self) :
                return "Read/Write PageStore with pages at %s" % self.pages_dir
@@ -108,13 +139,60 @@ class WritablePageStore(PageStore) :
                f.write("\n".join(ys))
                f.close()
                
+       def save_old(self,pName) :
+               try :
+                       with open(self.fName(pName)) as old_f :
+                               old_body = old_f.read()
+               except Exception, e :
+                       if "No such file or directory:" in "%s"%e :
+                               old_body = ""
+                       else :
+                               print e
+                               raise e
+               with open(self.old_fName(pName),"w") as old_f :
+                       old_f.write(old_body)
+                       
+       def recent_changes_name(self) :
+               return "%s/recentchanges.csv" % self.work_dir
+
+
+       def get_recentchanges(self) :
+               try :           
+                       rc = open(self.recent_changes_name())
+                       return rc.readlines()
+               except Exception, e :
+                       if "No such file or directory:" in "%s"%e :
+                               return []
+                       else :
+                               print e
+                               raise e
+
+       def new_recent_changes(self,pName) :
+               new =  ["%s, %s" % (pName,datetime.date.today())]
+               xs = new + self.get_recentchanges()
+               seen = set([])
+               ys = []
+               for x in xs :
+                       n = x.split(",")[0]
+                       if not n in seen :
+                               seen.add(n)
+                               ys.append(x)
+               
+               rc = open("%s/recentchanges.csv" % self.work_dir,"w")
+               rc.write("\n".join(ys))
+               rc.close()
+
 
        def put(self,pName,body) :
+               self.save_old(pName)
+                                                       
                f = open(self.fName(pName),"w")
                f.write(body)
                f.close()
-               if self.recent_changes :
+
+               if self.recent_changes :                        
                        self.update_recent_changes(pName)
+                       self.new_recent_changes(pName)
                        
        def append(self,pName,marker,extra) :
                f = open(self.fName(pName)) 
index 9297876..1b61ee7 100755 (executable)
@@ -324,7 +324,7 @@ class CSVBlock() :
     </table>""" % build]
                except Exception, e :
                        return ["Error in CSV Include %s " % e]
-       
+
        
 class Block :
        def __init__(self,typ,env) :