Website exporter in progress - completed home page
authorHarishankar <v.harishankar@gmail.com>
Tue, 30 Nov 2010 10:27:14 +0000 (15:57 +0530)
committerHarishankar <v.harishankar@gmail.com>
Tue, 30 Nov 2010 10:27:14 +0000 (15:57 +0530)
Exporter in progress. Currently completed the export of the
main index.html file and the style sheet style.css

biaweb_db.py
biaweb_exporter.py [new file with mode: 0644]
biaweb_strings.py
generate_dialog.py
generate_dialog.ui
main_window.py
ui_generate_dialog.py
ui_main_window.py

index b310972..9b7cb10 100644 (file)
@@ -207,6 +207,34 @@ def get_configuration (dbname):
        except sqlite3.Error:
                return False
 
+# Function to get the latest articles (inner join with categories to get category stub)
+def site_latest_articles (dbname, num_arts):
+       try:
+               conn = sqlite3.connect (dbname)
+               c = conn.cursor ()
+               c.execute ("SELECT * FROM articles INNER JOIN categories ON articles.cid=categories.cid \
+                                       ORDER BY cdate DESC LIMIT ?;", (num_arts,))
+               conn.commit ()
+               rows = c.fetchall ()
+               conn.close ()
+               return rows
+       except sqlite3.Error:
+               return False
+
+# Function to get the best rated articles (inner join with categories to get category stub)
+def site_get_bestrated (dbname):
+       try:
+               conn = sqlite3.connect (dbname)
+               c = conn.cursor ()
+               c.execute ("SELECT * FROM articles INNER JOIN categories ON articles.cid=categories.cid \
+                                       ORDER BY rating DESC LIMIT 5;")
+               conn.commit ()
+               rows = c.fetchall ()
+               conn.close ()
+               return rows
+       except sqlite3.Error:
+               return False
+
 # Function to get list of articles (either full list or just in a category
 def get_articles (dbname, category_id=None):
        try:
diff --git a/biaweb_exporter.py b/biaweb_exporter.py
new file mode 100644 (file)
index 0000000..5bbe32b
--- /dev/null
@@ -0,0 +1,141 @@
+# BiaWeb Website content manager (c) 2010 V.Harishankar
+# Site exporter/generator class
+
+import os
+import os.path
+import time
+import sqlite3
+import string
+import shutil
+import biaweb_db
+
+# to format the best rated articles in a HTML link list
+def html_format_best_rated (best_rated):
+       items = [ "<ul>\n", ]
+       for art in best_rated:
+               # art[13] is category stub, art[8] is article stub
+               # thus forming the relative url as Category/Article.html
+               str_art = '<li><a href="' + art[13] + '/' + art[8] + '.html">' + art[1] + '</a></li>\n'
+               items.append (str_art)
+       items.append ("</ul>\n")
+       str_items = "".join (items)
+       return str_items
+
+# to format categories in a HTML link list
+def html_format_categories (cats):
+       items = [ "<ul>\n", ]
+       for cat in cats:
+               # cat[3] is category stub and cat[1] is category name
+               str_cat = '<li><a href="' + cat[3] + '/">' + cat[1] + '</a></li>\n'
+               items.append (str_cat)
+       items.append ("</ul>\n")
+       str_items = "".join (items)
+       return str_items
+
+# function to generate main index file and stylesheet
+def generate_home_page (dbname, conf, templates, category_str, bestrated_str):
+       # main template
+       tpl_main = string.Template (templates[0][1])
+       # index bit
+       tpl_indexbit = string.Template (templates[6][1])
+       # news bits
+       tpl_newsbit = string.Template (templates[2][1])
+
+       # get the latest articles - conf[4] is num of rss entries to be used also
+       latest_arts = biaweb_db.site_latest_articles (dbname, conf[4])
+       if latest_arts == False:
+               return False
+
+       news_items = []
+
+       # Run through the latest articles
+       # for the num of latest news items on index
+       for art in latest_arts:
+               # url is Category/Article.html
+               url = art[13] + "/" + art[8] + ".html"
+               # art[5] is creation time
+               strdate = time.ctime (art[5])
+               # now populate the template variables. art[1] is title, art[2] is summary
+               strnews = tpl_newsbit.safe_substitute (news_title = art[1],
+                                                                                       news_link = url,
+                                                                                       news_datetime = strdate,
+                                                                                       news_description = art[2]
+                                                                                       )
+               news_items.append (strnews)
+       # now convert it into a string
+       newsbit_str = "".join (news_items)
+
+       # now populate the index template
+       indexbit_str = tpl_indexbit.safe_substitute (site_name = conf[1],
+                                                                                               news_updates = newsbit_str
+                                                                                               )
+       # now populate the main page template
+       main_str = tpl_main.safe_substitute (site_title = conf[1],
+                                                                               site_url = "http://" + conf[0],
+                                                                               meta_keywords = conf[2],
+                                                                               meta_description = conf[3],
+                                                                               page_title = conf[1],
+                                                                               page_desc = conf[3],
+                                                                               contents_bit = indexbit_str,
+                                                                               list_of_categories = category_str,
+                                                                               list_best_rated = bestrated_str,
+                                                                               copyright = conf[6])
+
+       # write the index.html file in the destination directory
+       try:
+               findex = open (os.path.join (conf[5], "index.html"), "w+")
+               findex.write (main_str)
+               findex.close ()
+       except IOError, OSError:
+               return False
+
+       # write the style.css file in the destination directory
+       try:
+               fstyle = open (os.path.join (conf[5], "style.css"), "w+")
+               fstyle.write (templates[5][1])
+               fstyle.close ()
+               print "error"
+       except IOError, OSError:
+               return False
+
+       return True
+
+# superfunction to generate the site
+def generate_site (dbname, files_to_copy, folders_to_copy, search_type_full=True):
+       # get the configuration
+       conf = biaweb_db.get_configuration (dbname)
+       # get the templates
+       tpls = biaweb_db.get_templates (dbname)
+
+       # get the list of categories
+       cats = biaweb_db.get_categories (dbname)
+       # cannot get categories return false
+       if cats == False:
+               return False
+
+       # format the categories as a html bulleted list
+       cats_str = html_format_categories (cats)
+
+       # get the best rated articles
+       best_rated = biaweb_db.site_get_bestrated (dbname)
+       # if cannot retrieve
+       if best_rated == False:
+               return False
+       # format the best rated articles as a html bulleted list
+       best_rated_str = html_format_best_rated (best_rated)
+
+       # remove the destination tree and recreate it
+       try:
+               if os.path.exists (conf[5]):
+                       shutil.rmtree (conf[5])
+               os.mkdir (conf[5])
+       except OSError:
+               return False
+
+       # generate the index page including style sheet
+       ret = generate_home_page (dbname, conf, tpls, cats_str, best_rated_str)
+       if ret == False:
+               return False
+
+       # finally when all is successfully done return true
+       return True
index 62d1f5e..da2a227 100644 (file)
@@ -187,4 +187,24 @@ a:visited {
 }
 a:active, a:hover {
        color: #0000ff;
-}"""
\ No newline at end of file
+}"""
+
+template_rss = """<?xml version="1.0"?>
+<rss version="2.0">
+       <channel>
+               <title>${title}</title>
+               <link>${link}</link>
+               <description>${description}</description>
+               <generator>BiaWeb</generator>
+               ${rss_items}
+       </channel>
+</rss>"""
+
+template_rss_item = """
+                       <item>
+                               <title>${item_title}</title>
+                               <link>${item_link}</link>
+                               <description>${description}</description>
+                               <guid>${item_link}</guid>
+                       </item>
+"""
\ No newline at end of file
index d1882d2..dc0448b 100644 (file)
@@ -5,6 +5,7 @@ import PyQt4
 import os
 import os.path
 import ui_generate_dialog
+import biaweb_exporter
 
 class GenerateDialog (PyQt4.QtGui.QDialog, ui_generate_dialog.Ui_SiteGenerateDialog):
        def __init__ (self, master, currentdb):
@@ -38,6 +39,29 @@ class GenerateDialog (PyQt4.QtGui.QDialog, ui_generate_dialog.Ui_SiteGenerateDia
        def onSiteGenerate (self):
                files_list = self.get_list_from_tree (self.additional_files)
                folder_list = self.get_list_from_tree (self.additional_folders)
+               if self.fulltextindex.isChecked ():
+                       searchtype = True
+               else:
+                       searchtype = False
+
+               # confirm whether to delete the destination tree and work afresh
+               ans = PyQt4.QtGui.QMessageBox.question (self, "Confirm",
+                                       "This will delete the destination tree completely \
+and recreate the website. Are you sure you wish to proceed?",
+                               PyQt4.QtGui.QMessageBox.Yes, PyQt4.QtGui.QMessageBox.No)
+
+               # if confirmed
+               if ans == PyQt4.QtGui.QMessageBox.Yes:
+                       # call the main exporter to do our work
+                       ret = biaweb_exporter.generate_site (self.current_db, files_list, folder_list, searchtype)
+
+                       # if failed to generate site or any part thereof
+                       if ret == False:
+                               PyQt4.QtGui.QMessageBox.critical (self, "Error",
+                                                       "System or SQLite 3 error in generating website or parts thereof")
+                       else:
+                               PyQt4.QtGui.QMessageBox.information (self, "Success",
+                                                       "Successfully generated website in destination path!")
 
        # when folder add is clicked
        def onFolderAdd (self):
index ce8a88e..4544906 100644 (file)
 &lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
 p, li { white-space: pre-wrap; }
 &lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; color:#005500;&quot;&gt;Important Information&lt;/span&gt;&lt;/p&gt;
-&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This will generate your website in the destination directory specified in the site configuration dialog. The entire directory tree will be re-created from scratch and any manual changes you made to the generated files will be gone!&lt;/p&gt;
-&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; &lt;/p&gt;
-&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;You need to re-copy additional files/folders you require in the destination folder (e.g. image files or directories) every time you generate the site. Specify additional files/folders to copy below.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; color:#55007f;&quot;&gt;Important Information&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This will generate your website in the destination directory specified in the site configuration dialog. The entire directory tree will be re-created from scratch and any manual changes you made to the generated files will be gone!&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; &lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;You need to re-copy the additional files/folders you require in the destination folder (e.g. the rating (star) image files or directories, the search.py CGI script) every time you generate the site. Specify the files/folders to copy to generated site.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
      </property>
      <property name="wordWrap">
       <bool>true</bool>
index 02eaa8b..86e9b12 100644 (file)
@@ -377,7 +377,7 @@ class MainWindow (PyQt4.QtGui.QMainWindow, ui_main_window.Ui_MainWindow):
        def onAbout (self):
                PyQt4.QtGui.QMessageBox.about (self, "BiaWeb Qt",
                        "<b>A static website/weblog content management system</b><br /><br />\
-Copyright (C) 2010 <a href=\"http://www.harishankar.org\">Harishankar</a><br />\
+Copyright &copy; 2010 <a href=\"http://www.harishankar.org\">Harishankar</a><br />\
 Licensed under GNU/GPL v3")
 
        # file quit is clicked
index c81bb6f..fab5abf 100644 (file)
@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'generate_dialog.ui'
 #
-# Created: Tue Nov 30 12:38:46 2010
+# Created: Tue Nov 30 14:05:23 2010
 #      by: PyQt4 UI code generator 4.7.4
 #
 # WARNING! All changes made in this file will be lost!
@@ -105,10 +105,10 @@ class Ui_SiteGenerateDialog(object):
 "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
 "p, li { white-space: pre-wrap; }\n"
 "</style></head><body style=\" font-family:\'Sans\'; font-size:10pt; font-weight:400; font-style:normal;\">\n"
-"<p align=\"justify\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-weight:600; color:#005500;\">Important Information</span></p>\n"
-"<p align=\"justify\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">This will generate your website in the destination directory specified in the site configuration dialog. The entire directory tree will be re-created from scratch and any manual changes you made to the generated files will be gone!</p>\n"
-"<p align=\"justify\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"> </p>\n"
-"<p align=\"justify\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-style:italic;\">You need to re-copy additional files/folders you require in the destination folder (e.g. image files or directories) every time you generate the site. Specify additional files/folders to copy below.</span></p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
+"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-weight:600; color:#55007f;\">Important Information</span></p>\n"
+"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">This will generate your website in the destination directory specified in the site configuration dialog. The entire directory tree will be re-created from scratch and any manual changes you made to the generated files will be gone!</p>\n"
+"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"> </p>\n"
+"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-style:italic;\">You need to re-copy the additional files/folders you require in the destination folder (e.g. the rating (star) image files or directories, the search.py CGI script) every time you generate the site. Specify the files/folders to copy to generated site.</span></p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
         self.label_2.setText(QtGui.QApplication.translate("SiteGenerateDialog", "Additional files to add to destination", None, QtGui.QApplication.UnicodeUTF8))
         self.addfile.setText(QtGui.QApplication.translate("SiteGenerateDialog", "&Add file", None, QtGui.QApplication.UnicodeUTF8))
         self.removefile.setText(QtGui.QApplication.translate("SiteGenerateDialog", "&Remove", None, QtGui.QApplication.UnicodeUTF8))
index e7b4bfb..fbc36c5 100644 (file)
@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'main_window.ui'
 #
-# Created: Tue Nov 30 13:15:20 2010
+# Created: Tue Nov 30 13:50:40 2010
 #      by: PyQt4 UI code generator 4.7.4
 #
 # WARNING! All changes made in this file will be lost!