From 914bff34984f2854aed9546c3d4aa5f0326a7674 Mon Sep 17 00:00:00 2001 From: Xuan Sang LE Date: Wed, 5 Sep 2018 16:56:04 +0200 Subject: [PATCH] blog now use silk --- apps/views/default/layout.ls | 6 +- blog/Makefile | 4 +- blog/api.lua | 131 -------------- blog/controllers/PostController.lua | 167 ++++++++++++++++++ blog/index.lua | 1 - blog/models/AnalyticalModel.lua | 13 ++ blog/models/BlogModel.lua | 52 ++++++ blog/robot.txt | 2 - blog/router.lua | 100 ++++++----- blog/template.html | 144 --------------- blog/view.lua | 40 ----- blog/view/analyse.ls | 6 - blog/view/bot.html | 7 - blog/{view/top.ls => views/default/layout.ls} | 53 +++--- blog/views/default/notfound/index.ls | 8 + blog/views/default/post/analyse.ls | 3 + blog/{view => views/default/post}/detail.ls | 52 +----- blog/views/default/post/notfound.ls | 8 + .../default/post/posts.ls} | 38 ++-- info/views/default/index/index.ls | 2 - info/views/default/layout.ls | 24 ++- info/views/default/toc/index.ls | 2 - info/views/default/user/index.ls | 5 - silk/BaseController.lua | 7 +- silk/BaseModel.lua | 6 + silk/Router.lua | 26 ++- silk/Template.lua | 16 +- silk/api.lua | 5 + 28 files changed, 419 insertions(+), 509 deletions(-) delete mode 100644 blog/api.lua create mode 100644 blog/controllers/PostController.lua delete mode 100644 blog/index.lua create mode 100644 blog/models/AnalyticalModel.lua create mode 100644 blog/models/BlogModel.lua delete mode 100644 blog/robot.txt delete mode 100644 blog/template.html delete mode 100644 blog/view.lua delete mode 100644 blog/view/analyse.ls delete mode 100644 blog/view/bot.html rename blog/{view/top.ls => views/default/layout.ls} (69%) create mode 100644 blog/views/default/notfound/index.ls create mode 100644 blog/views/default/post/analyse.ls rename blog/{view => views/default/post}/detail.ls (67%) create mode 100644 blog/views/default/post/notfound.ls rename blog/{view/entries.ls => views/default/post/posts.ls} (68%) diff --git a/apps/views/default/layout.ls b/apps/views/default/layout.ls index beca6a7..a545f83 100644 --- a/apps/views/default/layout.ls +++ b/apps/views/default/layout.ls @@ -1,8 +1,6 @@ @@ -28,7 +26,7 @@ if jsclass == nil then jsclass = "" end
diff --git a/blog/Makefile b/blog/Makefile index 40caa87..80063f9 100644 --- a/blog/Makefile +++ b/blog/Makefile @@ -1,10 +1,10 @@ BUILDDIR = ../build/blog -copyfiles = *.html assets *.lua view robot.txt +copyfiles = assets views models controllers router.lua main: - mkdir $(BUILDDIR) - cp -rf $(copyfiles) $(BUILDDIR) + - cp -rf $(copyfiles) $(BUILDDIR) - cd $(BUILDDIR) && ln -s ../grs ./rst clean: rm -rf $(BUILDDIR)/* \ No newline at end of file diff --git a/blog/api.lua b/blog/api.lua deleted file mode 100644 index 9449d2b..0000000 --- a/blog/api.lua +++ /dev/null @@ -1,131 +0,0 @@ -local get = {} -get.fetch = function(user, cnd, limit, order) - local db = require("db.model").get(user,"blogs",nil) - if not db then return nil end - local exp = {} - exp[1] = {["="] = { publish = 1 }} - if cnd then - exp[2] = cnd - else - - end - - local cond = { - exp = {["and"] = exp }, - order = { ctime = "DESC" }, - fields = { - "id", "title", "utime", "ctime", "utimestr", "ctimestr", "rendered", "tags" - } - } - if limit then - cond.limit = limit - end - if order then - cond.order = order - end - local data, sort = db:find(cond) - db:close() - return data, sort -end -get.top = function(user, limit) - return get.fetch(user, nil, limit) -end - -get.id = function(user, id) - return get.fetch(user, { ["="] = { id = id } }, nil) -end - -get.minid = function(user) - local db = require("db.model").get(user,"blogs",nil) - local cond = { fields = { "MIN(id)" } } - local data = db:find(cond) - db:close() - return data[1]["MIN(id)"] -end - -get.maxid = function(user) - local db = require("db.model").get(user,"blogs",nil) - local cond = { fields = { "MAX(id)" }} - cond.exp = {["="] = { publish = 1 }} - local data = db:find(cond) - db:close() - return data[1]["MAX(id)"] -end - -get.afterof = function(user, id, limit) - local data, sort = get.fetch(user, { [">"] = { id = id } }, limit, { ctime = "ASC" }) - table.sort(sort, function(a, b) return a > b end) - return data, sort -end - -get.beforeof = function(user, id, limit) - return get.fetch(user, { ["<"] = { id = id } }, limit) -end - -get.nextof = function(user, id) - return get.afterof(user, id, 1) -end - -get.prevof = function(user, id) - return get.beforeof(user, id, 1) -end - -get.bytag = function(user, b64tag, limit, action, id) - LAST_QUERY = b64tag - local tag = bytes.__tostring(std.b64decode(b64tag.."==")) - local cond = { ["LIKE"] = { tags = "%%"..tag.."%%" } } - local order = nil - if action == "before" then - cond = { ["and"] = { cond, { ["<"] = {id = id} } } } - elseif action == "after" then - cond = { ["and"] = { cond, { [">"] = {id = id} } } } - order = { ctime = "ASC" } - end - local data, sort = get.fetch(user, cond, limit, order) - if(action == "after") then - table.sort(sort, function(a, b) return a > b end) - end - return data, sort -end - -get.analyse = function(user, n) - if not n then n = 5 end - local path = "/home/mrsang/aiws/blog-clustering" - local gettext = loadfile(path.."/gettext.lua")() - local cluster = loadfile(path.."/cluster.lua")() - local data = gettext.get({publish=1}) - local documents = {} - if data then - local sw = gettext.stopwords(path.."/stopwords.txt") - for k,v in pairs(data) do - local bag = cluster.bow(data[k].content, sw) - documents[data[k].id] = bag - end - cluster.tfidf(documents) - --local v = cluster.search("arm", documents) - --echo(JSON.encode(v)) - local vectors, maxv, size = cluster.get_vectors(documents) - local sample_data = {pid = 1, sid = 2, score = 0.1} - local db = require("db.model").get(user, "st_similarity", sample_data) - if db then - -- purge the table - db:delete({["="] = {["1"] = 1}}) - -- get similarity and put to the table - for id,v in pairs(vectors) do - local top = cluster.top_similarity(id,vectors,n) - for a,b in pairs(top) do - local record = {pid = id, sid = a, score = b} - db:insert(record) - end - end - db:close() - return "

Analyse complete

" - else - return "

Cannot get database objectw/h3>" - end - else - return "

Cannot find data to analyse

" - end -end - -return get \ No newline at end of file diff --git a/blog/controllers/PostController.lua b/blog/controllers/PostController.lua new file mode 100644 index 0000000..c3f6e74 --- /dev/null +++ b/blog/controllers/PostController.lua @@ -0,0 +1,167 @@ +BaseController:subclass( + "PostController", + { + registry = {}, + models = {"blog", "analytical"} + } +) + +function PostController:index(...) + return self:top(table.unpack({...})) +end + +function PostController:top(limit) + limit = limit or POST_LIMIT + local data, order = self.blog:fetch(nil, limit) + if not data or #order == 0 then + return self:notfound("No entry found") + end + self:list(data, order) + return true +end + +function PostController:afterof(id, limit) + limit = limit or POST_LIMIT + local data, order = self.blog:fetch({[">"] = {id = id}}, limit, {ctime = "ASC"}) + if not data or #order == 0 then + return self:notfound("No entry found") + end + table.sort( + order, + function(a, b) + return a > b + end + ) + self:list(data, order) + return true +end + +function PostController:beforeof(id, limit) + limit = limit or POST_LIMIT + local data, order = self.blog:fetch({["<"] = {id = id}}, limit) + if not data or #order == 0 then + return self:notfound("No entry found") + end + self:list(data, order) + return true +end + +-- this is a private function, should not be called by user +function PostController:list(data, order) + self.template:setView("posts") + self.template:set("posts", data) + self.template:set("order", order) + self.template:set("title", "Blog Home") + self.template:set("minid", self.blog:minid()) + self.template:set("maxid", self.blog:maxid()) + return false +end + +function PostController:bytag(b64tag, limit, action, id) + local tag = bytes.__tostring(std.b64decode(b64tag .. "==")) + local cond = {["LIKE"] = {tags = "%%" .. tag .. "%%"}} + local order = nil + limit = limit or POST_LIMIT + if action == "before" then + cond = {["and"] = {cond, {["<"] = {id = id}}}} + elseif action == "after" then + cond = {["and"] = {cond, {[">"] = {id = id}}}} + order = {ctime = "ASC"} + end + local data, sort = self.blog:fetch(cond, limit, order) + if not data or #sort == 0 then + return self:notfound("No entry found") + end + + if (action == "after") then + table.sort( + sort, + function(a, b) + return a > b + end + ) + end + + self.template:set("query", b64tag) + self.template:set("action", "bytag") + self:list(data, sort) + return true +end + +function PostController:id(pid) + local data, order = self.blog:fetch({["="] = {id = pid}}) + if not data or #order == 0 then + return self:notfound("No post found") + end + data = data[1] + data.rendered = bytes.__tostring(std.b64decode(data.rendered)):gsub("%%", "%%%%") + local a, b = data.rendered:find("<[Hh]1[^>]*>") + if a then + local c, d = data.rendered:find("") + if c then + self.template:set("title", data.rendered:sub(b + 1, c - 1)) + end + end + -- get similarity post + local st_records = self.analytical:similarof(data.id) + local similar_posts = {} + for k, v in pairs(st_records) do + similar_posts[k] = {st = v, post = self.blog:get(v.sid)} + end + self.template:set("post", data) + self.template:set("similar_posts", similar_posts) + self.template:set("render", true) + self.template:set("tags", data.tags) + self.template:set("url", HTTP_ROOT .. "/post/id/" .. pid) + self.template:setView("detail") + return true +end + +function PostController:notfound(...) + local args = {...} + self.template:set("title", "404 not found") + self.template:set("error", args[1]) + self.template:setView("notfound") + return true +end + +function PostController:actionnotfound(...) + local args = {...} + return self:notfound("Action [" .. args[1] .. "] not found") +end + +function PostController:analyse(n) + if not n then + n = 5 + end + local path = "/home/mrsang/aiws/blog-clustering" + local gettext = loadfile(path .. "/gettext.lua")() + local cluster = loadfile(path .. "/cluster.lua")() + local data = gettext.get({publish = 1}) + local documents = {} + if data then + local sw = gettext.stopwords(path .. "/stopwords.txt") + for k, v in pairs(data) do + local bag = cluster.bow(data[k].content, sw) + documents[data[k].id] = bag + end + cluster.tfidf(documents) + --local v = cluster.search("arm", documents) + --echo(JSON.encode(v)) + local vectors, maxv, size = cluster.get_vectors(documents) + -- purge the table + self.analytical:delete({["="] = {["1"] = 1}}) + -- get similarity and put to the table + for id, v in pairs(vectors) do + local top = cluster.top_similarity(id, vectors, n) + for a, b in pairs(top) do + local record = {pid = id, sid = a, score = b} + self.analytical:create(record) + end + end + self.template:set(message, "Analyse complete") + else + self.template:set(message, "Cannotto analyse") + end + return true +end diff --git a/blog/index.lua b/blog/index.lua deleted file mode 100644 index 6241237..0000000 --- a/blog/index.lua +++ /dev/null @@ -1 +0,0 @@ -require("blog.router") \ No newline at end of file diff --git a/blog/models/AnalyticalModel.lua b/blog/models/AnalyticalModel.lua new file mode 100644 index 0000000..57e2ce7 --- /dev/null +++ b/blog/models/AnalyticalModel.lua @@ -0,0 +1,13 @@ +BaseModel:subclass("AnalyticalModel",{ + registry = {}, + name = "st_similarity", + fields = { + pid = "NUMERIC", + sid = "NUMERIC", + score = "NUMERIC" + } +}) + +function AnalyticalModel:similarof(id) + return self:find({ exp = {["="] = {pid = id}}, order = {score = "DESC"}}) +end \ No newline at end of file diff --git a/blog/models/BlogModel.lua b/blog/models/BlogModel.lua new file mode 100644 index 0000000..396259e --- /dev/null +++ b/blog/models/BlogModel.lua @@ -0,0 +1,52 @@ +BaseModel:subclass("BlogModel",{ + registry = {}, + name = "blogs", + fields = { + tags = "TEXT", + content = "TEXT", + utime = "NUMERIC", + rendered = "TEXT", + title = "TEXT", + utimestr = "TEXT", + ctime = "NUMERIC", + ctimestr = "TEXT", + publish = "INTEGER DEFAULT 0" + } +}) + +function BlogModel:fetch(cnd, limit, order) + local exp = {} + exp[1] = {["="] = { publish = 1 }} + if cnd then + exp[2] = cnd + else + + end + + local cond = { + exp = {["and"] = exp }, + order = { ctime = "DESC" }, + fields = { + "id", "title", "utime", "ctime", "utimestr", "ctimestr", "rendered", "tags" + } + } + if limit then + cond.limit = limit + end + if order then + cond.order = order + end + return self:find(cond) +end + +function BlogModel:minid() + local cond = { fields = { "MIN(id)" } } + local data = self:find(cond) + return data[1]["MIN(id)"] +end + +function BlogModel:maxid() + local cond = { fields = { "MAX(id)" } } + local data = self:find(cond) + return data[1]["MAX(id)"] +end \ No newline at end of file diff --git a/blog/robot.txt b/blog/robot.txt deleted file mode 100644 index c2a49f4..0000000 --- a/blog/robot.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Allow: / diff --git a/blog/router.lua b/blog/router.lua index b444e9f..5222fa0 100644 --- a/blog/router.lua +++ b/blog/router.lua @@ -1,42 +1,60 @@ -BLOG_ROOT = __ROOT__.."/blog" -MAX_ENTRY = 15 -LAST_QUERY = nil -BLOG_ADMIN = "mrsang" -local user = BLOG_ADMIN -local handle = function(p) - local args = {} - local sort = {} - local i = 1 - for s in p:gmatch("%:*([^%:]*)") do - args[i] = s - table.insert(sort, i) - i = i+1 - end - table.sort(sort) - local api = require("blog.api") - local minid = api.minid(user) - local maxid = api.maxid(user) - if #args == 0 or api == nil then - echo("Unknow request "..p) - elseif not api[args[1]] then - echo("Unknow action.."..args[1]) - else - local action = args[1] - args[1] = user - local data, sort = api[action](table.unpack(args)) - if data == nil then - echo("Cannot query data") - else - require("blog.view").render(action, data, sort, minid, maxid) - end - end -end -std.html() -local action = REQUEST.query.action -if not action then action = "r:top:"..MAX_ENTRY end -local r, s = action:find("^r:") -if r then - handle(action:sub(s+1)) -else - echo("Unknow action "..action) + +-- the rewrite rule for the framework +-- should be something like this +-- ^\/apps\/+(.*)$ = /apps/router.lua?r=<1>& +-- some global variables +DIR_SEP = "/" +WWW_ROOT = "/opt/www/htdocs/blog" +HTTP_ROOT = "https://blog.localhost:9195" +-- class path: path.to.class +BASE_FRW = "" +-- class path: path.to.class +CONTROLLER_ROOT = BASE_FRW.."blog.controllers" +MODEL_ROOT = BASE_FRW.."blog.models" +-- file path: path/to/file +VIEW_ROOT = WWW_ROOT..DIR_SEP.."views" +LOG_ROOT = WWW_ROOT..DIR_SEP.."logs" +POST_LIMIT = 2 +-- require needed library +require(BASE_FRW.."silk.api") + +if REQUEST.query.r then + REQUEST.query.r = REQUEST.query.r:gsub("%:", "/") end + +-- registry object store global variables +local REGISTRY = {} +-- set logging level +REGISTRY.logger = Logger:new{ levels = {INFO = true, ERROR = true, DEBUG = true}} +REGISTRY.db = DBHelper:new{db="mrsang"} +REGISTRY.layout = 'default' + +REGISTRY.db:open() +local router = Router:new{registry = REGISTRY} +REGISTRY.router = router +router:setPath(CONTROLLER_ROOT) +--router:route('edit', 'post/edit', "ALL" ) + +-- example of depedencies to the current main route +-- each layout may have different dependencies +--[[ local default_routes_dependencies = { + user = { + url = "user/index", + visibility = "ALL" + }, + toc = { + url = "toc/index", + visibility = { + shown = true, + routes = { + ["index/index"] = true + } + } + } +} ]] +router:route('default', default_routes_dependencies ) +router:remap("index", "post") +router:remap("r", "post") +router:delegate() +if REGISTRY.db then REGISTRY.db:close() end + diff --git a/blog/template.html b/blog/template.html deleted file mode 100644 index bbef637..0000000 --- a/blog/template.html +++ /dev/null @@ -1,144 +0,0 @@ - - - - Hi, I'm Xuan Sang LE - - - - - - - - - -
- -
-
-
-
-
- 24 July 2017 - - ROS, - distributed system, - middleware, - robotic, - SLAM, - autonomous exploration - - -
-
-

What is Lorem Ipsum?

-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsumhas been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It ha -
-
- - - -
-
-
- -
-
- 24 July 2017 - - ROS, - distributed system, - middleware, - robotic, - SLAM, - autonomous exploration - - -
-
-

What is Lorem Ipsum?

-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsumhas been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It ha -
-
- - - -
-
-
-
-
- 24 July 2017 - - ROS, - distributed system, - middleware, - robotic, - SLAM, - autonomous exploration - - -
-
-

What is Lorem Ipsum?

-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsumhas been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It ha -
-
- - - -
-
-
-
-
- 24 July 2017 - - ROS, - distributed system, - middleware, - robotic, - SLAM, - autonomous exploration - - -
-
-

What is Lorem Ipsum?

-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum - - Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsumhas been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It ha -
-
- - - -
-
-
-
-
-
- Powered by antd server, (c) 2017 - 2018 Xuan Sang LE -
- - \ No newline at end of file diff --git a/blog/view.lua b/blog/view.lua deleted file mode 100644 index a9ae3bc..0000000 --- a/blog/view.lua +++ /dev/null @@ -1,40 +0,0 @@ -local view = {} - -view.html = function(name) - local path = BLOG_ROOT.."/view/"..name..".html" - if unix.exists(path) then - std.f(path) - else - echo("Cannot find "..path) - end -end - -view.render = function(action, data, sort, min, max) - local path = BLOG_ROOT.."/view" - local fn = nil - local e - if action == "id" then - --echo(bytes.__tostring(std.b64decode(data[0].rendered)):gsub("%%","%%%%")) - --return true - fn, e = loadscript(path.."/detail.ls") - --echo(data[0].rendered) - --fn = require("blog.view.compiledd") - elseif action == "analyse" then - fn, e = loadscript(path.."/analyse.ls") - else - --fn = require("blog.view.compiledd") - - fn, e = loadscript(path.."/entries.ls") - end - if fn then - local r,o = pcall(fn, data, sort, min, max, action) - if not r then - echo(o) - end - else - loadscript(path.."/top.ls")("Welcome to my blog") - echo(e) - end - view.html("bot") -end -return view \ No newline at end of file diff --git a/blog/view/analyse.ls b/blog/view/analyse.ls deleted file mode 100644 index 56d5c38..0000000 --- a/blog/view/analyse.ls +++ /dev/null @@ -1,6 +0,0 @@ - \ No newline at end of file diff --git a/blog/view/bot.html b/blog/view/bot.html deleted file mode 100644 index 6c93ca3..0000000 --- a/blog/view/bot.html +++ /dev/null @@ -1,7 +0,0 @@ - - -
- Powered by antd server, (c) 2017 - 2018 Xuan Sang LE -
- - \ No newline at end of file diff --git a/blog/view/top.ls b/blog/views/default/layout.ls similarity index 69% rename from blog/view/top.ls rename to blog/views/default/layout.ls index e81baac..b010741 100644 --- a/blog/view/top.ls +++ b/blog/views/default/layout.ls @@ -1,9 +1,10 @@ + + <?=title?> - - - - - - - - + + + + + + + @@ -33,17 +33,17 @@ - - - - - - + + + + + + - + - - + + + Porfolio
@@ -27,9 +23,9 @@
diff --git a/info/views/default/toc/index.ls b/info/views/default/toc/index.ls index c3941bb..4adb53e 100644 --- a/info/views/default/toc/index.ls +++ b/info/views/default/toc/index.ls @@ -1,7 +1,5 @@
diff --git a/info/views/default/user/index.ls b/info/views/default/user/index.ls index d8d6c6c..6f4eebf 100644 --- a/info/views/default/user/index.ls +++ b/info/views/default/user/index.ls @@ -1,8 +1,3 @@ - -

Curriculum Vitae diff --git a/silk/BaseController.lua b/silk/BaseController.lua index d495496..8cb6ad9 100644 --- a/silk/BaseController.lua +++ b/silk/BaseController.lua @@ -75,6 +75,11 @@ BaseController:subclass("NotfoundController",{ registry = {}, models = {} }) function NotfoundController:index(...) local args = {...} local error = args[2] or "" + if self.template:path() then + self.template:set("error", error) + self.template:set("title", "404 not found") + return true + end self:error("404: Controller "..args[1].." not found : "..error) return false end @@ -102,7 +107,7 @@ function AssetController:get(...) self:error("Access forbidden: "..path) end else - self:error("Assset file not found: "..path) + self:error("Asset file not found: "..path) end return false end \ No newline at end of file diff --git a/silk/BaseModel.lua b/silk/BaseModel.lua index ee00ba5..bf7e6a8 100644 --- a/silk/BaseModel.lua +++ b/silk/BaseModel.lua @@ -38,6 +38,12 @@ function BaseModel:find(cond) return false end +function BaseModel:get(id) + local data, order = self:find({exp = {["="] = { id = id}} }) + if not data or #order == 0 then return false end + return data[1] +end + function BaseModel:findAll() if self.db then return self.db:getAll(self.name) diff --git a/silk/Router.lua b/silk/Router.lua index 1051a0c..ab87b48 100644 --- a/silk/Router.lua +++ b/silk/Router.lua @@ -6,6 +6,7 @@ end function Router:initialize() self.routes = {} + self.remaps = {} end --function Router:setArgs(args) @@ -23,7 +24,7 @@ function Router:infer(url) -- c,d,e is parameters -- if user dont provide the url, try to infer it -- from the REQUEST - url = url or REQUEST.query.r + url = url or REQUEST.query.r or "" url = std.trim(url, "/") local args = explode(url, "/") local data = { @@ -41,6 +42,10 @@ function Router:infer(url) end end + -- remap if needed + if self.remaps[data.name] ~= nil then + data.name = self.remaps[data.name] + end -- find the controller class and init it local controller_name = firstToUpper(data.name) .. "Controller" local controller_path = self.path .. "." .. controller_name @@ -84,7 +89,7 @@ function Router:delegate() data.controller.main = true views.__main__ = self:call(data) if not views.__main__ then - --self:error("No main template is set") + --self:error("No view available for this action") return end -- get all visible routes @@ -94,16 +99,23 @@ function Router:delegate() views[k] = self:call(data) end -- now require the main page to put the view + local view_args = {} + local view_argv = {} + for k,v in pairs(views) do + table.insert( view_args, k ) + table.insert( view_argv, v ) + end - local fn, e = loadscript(VIEW_ROOT .. DIR_SEP .. self.registry.layout .. DIR_SEP .. "layout.ls") + local fn, e = loadscript(VIEW_ROOT .. DIR_SEP .. self.registry.layout .. DIR_SEP .. "layout.ls", view_args) html() if fn then - local r, o = pcall(fn, views) + local r, o = pcall(fn, table.unpack(view_argv)) if not r then self:error(o) end else - self:error("The index page is not found for layout: " .. self.registry.layout) + e = e or "" + self:error("The index page is not found for layout: " .. self.registry.layout..": "..e) end end @@ -142,6 +154,10 @@ function Router:call(data) end end +function Router:remap(from, to) + self.remaps[from] = to +end + function Router:route(layout, dependencies) self.routes[layout] = dependencies end diff --git a/silk/Template.lua b/silk/Template.lua index ae9004b..38eeb7c 100644 --- a/silk/Template.lua +++ b/silk/Template.lua @@ -31,14 +31,24 @@ function Template:path() if ulib.exists(path) then return path else - self:error("View not found: "..path) + return false, path end end -- render the page function Template:render() - local fn, e = loadscript(self:path()) + local path, err = self:path() + if not path then + return self:error("View not found: "..err) + end + local args = {} + local argv = {} + for k, v in pairs(self.vars) do + table.insert( args, k ) + table.insert( argv,v ) + end + local fn, e = loadscript(self:path(), args) if fn then - local r,o = pcall(fn, self.vars) + local r,o = pcall(fn, table.unpack(argv)) if not r then self:error(o) end diff --git a/silk/api.lua b/silk/api.lua index 441a99b..6dc685d 100644 --- a/silk/api.lua +++ b/silk/api.lua @@ -16,6 +16,7 @@ POLICY.mimes = { ["application/javascript"] = true, ["image/bmp"] = true, ["image/jpeg"] = true, + ["image/png"] = true, ["text/css"] = true, ["text/markdown"] = true, ["text/csv"] = true, @@ -49,4 +50,8 @@ function html() std.chtml(SESSION) HEADER_FLAG = true end +end + +function import(module) + return require(BASE_FRW.."silk.api."..module) end \ No newline at end of file