2016年3月4日 星期五

EasyuiCMS on GAE 新增應用程式的方法

完成 EasyuiCMS on GAE 基本架構之後, 感覺似乎離目標只剩一步之遙, 所以早上就趁著去上一個跟工作幾乎無關的無聊課 (防毒) 時, 把最後一塊拼圖補上, 那就是如何在此架站平台上新增應用服務呢?

在 PHP 版時只要單獨寫好應用程式與其安裝檔兩個檔案, 然後利用檔案上傳就可以自動處理應用程式安裝的所有工作, 安裝後馬上可用. 在 GAE 因為雲端平台架構的關係, 可能比較難做到這樣, 每次新增一個服務必須修改現有檔案並新增相關檔案. 以下便以新增一個工作日誌服務 JLOG 為例, 說明其增修程序.

首先修改資料儲存檔 model.py, 新增一個 Jlogtabs 頁籤的資料模型, 直接從系統的 Hometabs 複製過來改名稱即可 :

class Jlogtabs(db.Model):
    tab_name=db.StringProperty()
    tab_label=db.StringProperty()
    tab_link=db.StringProperty()
    tab_tip=db.StringProperty()
    tab_order=db.IntegerProperty()
    tab_admin=db.BooleanProperty()

並建立 jlog_home, jlog_knowledge, jlog_admin 三個頁籤的資料實體 :

jlogtab=Jlogtabs(key_name="jlog_home",tab_name="jlog_home",tab_label=u"工作日誌",tab_link="/jlog_home",tab_order=0,tab_admin=False)
jlogtab.put()
jlogtab=Jlogtabs(key_name="jlog_knowledge",tab_name="jlog_knowledge",tab_label=u"知識庫",tab_link="/jlog_knowledge",tab_order=98,tab_admin=False)
jlogtab.put()
jlogtab=Jlogtabs(key_name="jlog_admin",tab_name="jlog_admin",
    tab_label=u"管理",tab_link="/jlog_admin",tab_order=99,tab_admin=True)
jlogtab.put()

然後新增一個標頭連結 JLOG 就完成資料庫部分的調整作業了 :

headerlink=Headerlinks(key_name="JLOG",name="JLOG",title=u"JLOG",
    url="javascript:goJLOG()",target="_self",sequence=0,hint=u"JLOG")
headerlink.put()

這裡 url 中的 goJLOG() 函式是要在系統主版面 main.htm 中將工作日誌頁籤網頁載入 panel 的 center 區域, 所以必須到 template/main.htm 中新增此函式 :
   
    function gohome(){
      $(function(){
        var p=$("body").layout("panel","center");
        p.panel({href:"/hometabs"});
        });
      }
    function logout(){
      $(function(){
        $.messager.confirm("確認","確定要登出系統嗎?",function(btn){
          if (btn) {window.location.href="/logout";}
          });
        });
      }
    function goJLOG(){
      $(function(){
        var p=$("body").layout("panel","center");
        p.panel({href:"/jlogtabs"});
        });
      }

事實上就是將 gohome() 複製過來修改即可. 接下來就要去主控程式 main.py 中處理路徑與邏輯. 首先在最底下的 app 中新增上面新增的四個路徑 :

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    ('/login', login),
    ('/check_member', check_member),
    ('/logout', logout),
    ('/hometabs', hometabs),
    ('/home', home),
    ('/change_theme', change_theme),
    ('/list_visitors', list_visitors),
    ('/get_visitors', get_visitors),
    ('/list_members', list_members),
    ('/get_members', get_members),
    ('/remove_visitors', remove_visitors),
    ('/add_member', add_member),
    ('/update_member', update_member),
    ('/remove_member', remove_member),
    ('/list_headerlinks', list_headerlinks),
    ('/get_headerlinks', get_headerlinks),
    ('/add_headerlink', add_headerlink),
    ('/update_headerlink', update_headerlink),
    ('/remove_headerlink', remove_headerlink),
    ('/list_navblocks', list_navblocks),
    ('/get_navblocks', get_navblocks),
    ('/add_navblock', add_navblock),
    ('/update_navblock', update_navblock),
    ('/remove_navblock', remove_navblock),
    ('/list_navlinks', list_navlinks),
    ('/get_navlinks', get_navlinks),
    ('/add_navlink', add_navlink),
    ('/update_navlink', update_navlink),
    ('/remove_navlink', remove_navlink),
    ('/settings', settings),
    ('/update_settings', update_settings),
    ('/member_settings', member_settings),
    ('/jlogtabs', jlogtabs),
    ('/jlog_home', jlog_home),
    ('/jlog_knowledge', jlog_knowledge),
    ('/jlog_admin', jlog_admin)
], debug=True, config=config)

然後建立四個類別來處理工作日誌的四個路徑, 首先是複製 hometabs 類別來改為 jlogtabs 類別,  然後複製 home 類別來改為 jlog_home, jlog_knowledge, 與 jlog_admin 類別, 分別渲染 hometabs.htm,  jlog_home.htm, jlog_knowledge.htm, 以及 jlog_admin.htm 這四個網頁模板 :

class jlogtabs(BaseHandler):
    def get(self):
        self.check_login()
        jlogtabs=m.Jlogtabs.all()
        jlogtabs.order("tab_order")  #sort by tab_order
        tabs=[]  #for storing tab objects
        is_admin=self.session.get('is_admin')  #True/False
        for t in jlogtabs:
            tab={}
            tab["tab_label"]=t.tab_label
            tab["tab_link"]=t.tab_link
            if t.tab_admin:  #this tab is for admin only
                if is_admin: #current user is admin
                    tabs.append(tab)
            else:  #this tab is for registered users
                tabs.append(tab)
        url="templates/jlogtabs.htm"
        path=os.path.join(os.path.dirname(__file__), url)
        content=template.render(path,{"tabs":tabs})
        self.response.out.write(content)

class jlog_home(BaseHandler):
    def get(self):
        self.check_login()
        url="templates/jlog_home.htm"
        path=os.path.join(os.path.dirname(__file__), url)
        content=template.render(path,{})
        self.response.out.write(content)

class jlog_knowledge(BaseHandler):
    def get(self):
        self.check_login()
        url="templates/jlog_knowledge.htm"
        path=os.path.join(os.path.dirname(__file__), url)
        content=template.render(path,{})
        self.response.out.write(content)

class jlog_admin(BaseHandler):
    def get(self):
        self.check_login()
        url="templates/jlog_admin.htm"
        path=os.path.join(os.path.dirname(__file__), url)
        content=template.render(path,{})
        self.response.out.write(content)

這樣 main.py 也調整好了, 接下來就是到 /template 目錄下, 複製 hometabs.htm 為 jlogtabs.htm 修改如下 (只改 id 即可) :

<div id="jlogtabs" class="easyui-tabs" data-options="fit:'true'">
{% for t in tabs %}
  <div class="tab" title="{{t.tab_label}}" data-options="href:'{{t.tab_link}}',loadingMessage:'載入中 ... '"></div>
{% endfor %}
</div>

然後複製 home.htm 為 jlog_home.htm, jlog_knowledge.htm, 以及 jlog_admin.htm, 其內容暫時只是文字而已, 例如 jlog_admin.htm 內容為 :

<p>工作日誌管理</p>

OK, 這樣就完成新增應用服務作業了, 上傳雲端主機後按標頭連結 JLOG 即顯示工作日誌頁籤 :


按首頁又會載入 hometabs.htm, 如此即可在多個應用服務之間切換了. 每一個應用服務的入口主要是上面的標頭連結, 當然也可以在左方導覽區另行建立第二入口.

另外, 在新增 JLOG 時也發現標頭連結的排序程式不妥而加以調整, 就是將 main.py 中根目錄處理類別 MainHandler 中的 headerlinks 查詢物件從原先的逆向排序改為正向排序 :

        #create param: headerlinks
        headerlinks=m.Headerlinks.all()
        headerlinks.order("sequence")  #sort by sequence

然後把 model.py 中的 headerlink 實體排序如下, 即把系統的首頁與登入 sequence 分別改為 98 與 99, 應用服務則從 0 開始編號, 這樣在正向排序下系統標頭連結會排在最後面 :

headerlink=Headerlinks(key_name="JLOG",name="JLOG",title=u"JLOG",
    url="javascript:goJLOG()",target="_self",sequence=0,hint=u"JLOG")
headerlink.put()
headerlink=Headerlinks(key_name="home",name="home",title=u"首頁",
    url="javascript:gohome()",target="_self",sequence=98,hint=u"首頁")
headerlink.put()
headerlink=Headerlinks(key_name="logout",name="logout",title=u"登出",
    url="javascript:logout()",target="_self",sequence=99,hint=u"登出")
headerlink.put()

這樣這個小專案總算拚完了, 當然安全性上還有待改進 (例如密碼欄位的加密, 以及重設密碼的機制), 但至少可以正常運轉. 完整 zip 檔案可在下列連結下載 :

# 具有 JLOG 應用範例的 EasyuiCMS on GAE


沒有留言:

張貼留言