1
0
mirror of https://github.com/lxsang/antd-web-apps synced 2024-11-20 02:18:20 +01:00

blog now use silk

This commit is contained in:
Xuan Sang LE 2018-09-05 16:56:04 +02:00
parent 1f57e18fc7
commit 914bff3498
28 changed files with 419 additions and 509 deletions

View File

@ -1,8 +1,6 @@
<?lua <?lua
local args = {...} local args = {...}
local views = args[1] local jsclass = __main__:get("jsclass")
local main = views.__main__
local jsclass = main:get("jsclass")
if jsclass == nil then jsclass = "" end if jsclass == nil then jsclass = "" end
?> ?>
<html> <html>
@ -28,7 +26,7 @@ if jsclass == nil then jsclass = "" end
<div id="desktop"> <div id="desktop">
<?lua <?lua
main:render() __main__:render()
?> ?>
</div> </div>
</body> </body>

View File

@ -1,10 +1,10 @@
BUILDDIR = ../build/blog BUILDDIR = ../build/blog
copyfiles = *.html assets *.lua view robot.txt copyfiles = assets views models controllers router.lua
main: main:
- mkdir $(BUILDDIR) - mkdir $(BUILDDIR)
cp -rf $(copyfiles) $(BUILDDIR) - cp -rf $(copyfiles) $(BUILDDIR)
- cd $(BUILDDIR) && ln -s ../grs ./rst - cd $(BUILDDIR) && ln -s ../grs ./rst
clean: clean:
rm -rf $(BUILDDIR)/* rm -rf $(BUILDDIR)/*

View File

@ -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 "<h3>Analyse complete</h3>"
else
return "<h3>Cannot get database objectw/h3>"
end
else
return "<h3>Cannot find data to analyse</h3>"
end
end
return get

View File

@ -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("</[Hh]1>")
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

View File

@ -1 +0,0 @@
require("blog.router")

View File

@ -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

52
blog/models/BlogModel.lua Normal file
View File

@ -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

View File

@ -1,2 +0,0 @@
User-agent: *
Allow: /

View File

@ -1,42 +1,60 @@
BLOG_ROOT = __ROOT__.."/blog"
MAX_ENTRY = 15 -- the rewrite rule for the framework
LAST_QUERY = nil -- should be something like this
BLOG_ADMIN = "mrsang" -- ^\/apps\/+(.*)$ = /apps/router.lua?r=<1>&<query>
local user = BLOG_ADMIN -- some global variables
local handle = function(p) DIR_SEP = "/"
local args = {} WWW_ROOT = "/opt/www/htdocs/blog"
local sort = {} HTTP_ROOT = "https://blog.localhost:9195"
local i = 1 -- class path: path.to.class
for s in p:gmatch("%:*([^%:]*)") do BASE_FRW = ""
args[i] = s -- class path: path.to.class
table.insert(sort, i) CONTROLLER_ROOT = BASE_FRW.."blog.controllers"
i = i+1 MODEL_ROOT = BASE_FRW.."blog.models"
end -- file path: path/to/file
table.sort(sort) VIEW_ROOT = WWW_ROOT..DIR_SEP.."views"
local api = require("blog.api") LOG_ROOT = WWW_ROOT..DIR_SEP.."logs"
local minid = api.minid(user) POST_LIMIT = 2
local maxid = api.maxid(user) -- require needed library
if #args == 0 or api == nil then require(BASE_FRW.."silk.api")
echo("Unknow request "..p)
elseif not api[args[1]] then if REQUEST.query.r then
echo("Unknow action.."..args[1]) REQUEST.query.r = REQUEST.query.r:gsub("%:", "/")
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)
end 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

View File

@ -1,144 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hi, I'm Xuan Sang LE</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="rst/ubuntu-regular.css" />
<link rel="stylesheet" type="text/css" href="rst/font-awesome.css" />
<link rel="stylesheet" type="text/css" href="rst/hermit-light.css" />
<link rel="stylesheet" type="text/css" href="assets/style.css" />
<script src="rst/gscripts/jquery-3.2.1.min.js"> </script>
</head>
<body>
<div id = "top">
<div id = "navbar">
<div class = "logo"></div>
<ul>
<li ><i class = "fa fa-address-card"></i><a href="https://info.lxsang.me" target="_blank">Porfolio</a></li>
<li><i class = "fa fa-newspaper-o"></i><a href="https://blog.lxsang.me" target="_blank">Blog</a></li>
<li><i class = "fa fa-paper-plane"></i><a href="#" onclick="" >Contact</a></li>
<li > <i class = "fa fa-globe"></i><a href = "https://os.lxsang.me" target="_blank">Web OS</a></li>
</ul>
<input type = "text" class = "search-box"></input>
<div class= "search-icon"></div>
</div>
</div>
<div id = "center">
<div id = "container">
<div class = "card">
<div class = "side">
<span class = "date">24 July 2017</span>
<span class = "tags">
<a href= "#">ROS</a>,
<a href= "#">distributed system</a>,
<a href= "#">middleware</a>,
<a href= "#">robotic</a>,
<a href= "#">SLAM</a>,
<a href= "#">autonomous exploration</a>
</span>
</div>
<div class = "blogentry">
<h1>What is Lorem Ipsum?</h1>
<div class = "shortcontent">
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
</div>
<div class = "detail">
<span></span>
<a href="#" ></a>
<span></span>
</div>
</div>
</div>
<div class = "card">
<div class = "side">
<span class = "date">24 July 2017</span>
<span class = "tags">
<a href= "#">ROS</a>,
<a href= "#">distributed system</a>,
<a href= "#">middleware</a>,
<a href= "#">robotic</a>,
<a href= "#">SLAM</a>,
<a href= "#">autonomous exploration</a>
</span>
</div>
<div class = "blogentry">
<h1>What is Lorem Ipsum?</h1>
<div class = "shortcontent">
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
</div>
<div class = "detail">
<span></span>
<a href="#" ></a>
<span></span>
</div>
</div>
</div>
<div class = "card">
<div class = "side">
<span class = "date">24 July 2017</span>
<span class = "tags">
<a href= "#">ROS</a>,
<a href= "#">distributed system</a>,
<a href= "#">middleware</a>,
<a href= "#">robotic</a>,
<a href= "#">SLAM</a>,
<a href= "#">autonomous exploration</a>
</span>
</div>
<div class = "blogentry">
<h1>What is Lorem Ipsum?</h1>
<div class = "shortcontent">
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
</div>
<div class = "detail">
<span></span>
<a href="#" ></a>
<span></span>
</div>
</div>
</div>
<div class = "card">
<div class = "side">
<span class = "date">24 July 2017</span>
<span class = "tags">
<a href= "#">ROS</a>,
<a href= "#">distributed system</a>,
<a href= "#">middleware</a>,
<a href= "#">robotic</a>,
<a href= "#">SLAM</a>,
<a href= "#">autonomous exploration</a>
</span>
</div>
<div class = "blogentry">
<h1>What is Lorem Ipsum?</h1>
<div class = "shortcontent">
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
</div>
<div class = "detail">
<span></span>
<a href="#" ></a>
<span></span>
</div>
</div>
</div>
</div>
</div>
<div id = "bottom">
Powered by antd server, (c) 2017 - 2018 Xuan Sang LE
</div>
</body>
</html>

View File

@ -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

View File

@ -1,6 +0,0 @@
<?lua
local arg = {...}
local data = arg[1]
loadscript(BLOG_ROOT.."/view/top.ls")("Welcome to my blog", false)
echo(data)
?>

View File

@ -1,7 +0,0 @@
</div>
</div>
<div id = "bottom">
Powered by antd server, (c) 2017 - 2018 Xuan Sang LE
</div>
</body>
</html>

View File

@ -1,9 +1,10 @@
<?lua <?lua
local arg = {...} local title = __main__:get("title")
local title = arg[1] local render = __main__:get("render")
local render = arg[2] local url = __main__:get("url")
local url = arg[3] local tags = __main__:get("tags")
local tags = arg[4]
local cls = "" local cls = ""
if HEADER.mobile then if HEADER.mobile then
cls = "navmobile" cls = "navmobile"
@ -14,16 +15,15 @@
<head> <head>
<title><?=title?></title> <title><?=title?></title>
<meta charset="UTF-8"> <meta charset="UTF-8">
<!--meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline' https://platform.twitter.com/widgets.js https://connect.facebook.net/en_US/sdk.js https://apis.google.com/js/plusone.js https://platform.twitter.com/js/button.556f0ea0e4da4e66cfdc182016dbd6db.js https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi.fr.G6aVHqjZQ7w.O/m=plusone/rt=j/sv=1/d=1/ed=1/am=AQE/rs=AGLTcCM3jVZaR98LsOLZhkxFJYLRGgZQ6A/cb=gapi.loaded_0 https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi.fr.G6aVHqjZQ7w.O/m=auth/exm=plusone/rt=j/sv=1/d=1/ed=1/am=AQE/rs=AGLTcCM3jVZaR98LsOLZhkxFJYLRGgZQ6A/cb=gapi.loaded_1"-->
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="rst/ubuntu-regular.css" /> <link rel="stylesheet" type="text/css" href="<?=HTTP_ROOT?>/rst/ubuntu-regular.css" />
<link rel="stylesheet" type="text/css" href="rst/font-awesome.css" /> <link rel="stylesheet" type="text/css" href="<?=HTTP_ROOT?>/rst/font-awesome.css" />
<link rel="stylesheet" type="text/css" href="assets/style.css" /> <link rel="stylesheet" type="text/css" href="<?=HTTP_ROOT?>/assets/style.css" />
<script src="rst/gscripts/riot.min.js"> </script> <script src="<?=HTTP_ROOT?>/rst/gscripts/riot.min.js"> </script>
<script src="rst/resources/antos_tags.js"></script> <script src="<?=HTTP_ROOT?>/rst/resources/antos_tags.js"></script>
<script src="rst/gscripts/jquery-3.2.1.min.js"> </script> <script src="<?=HTTP_ROOT?>/rst/gscripts/jquery-3.2.1.min.js"> </script>
<script src="rst/main.js"></script> <script src="<?=HTTP_ROOT?>/rst/main.js"></script>
<meta property="og:image" content="" /> <meta property="og:image" content="" />
<?lua if render then ?> <?lua if render then ?>
<meta name="twitter:card" content="summary" /> <meta name="twitter:card" content="summary" />
@ -33,17 +33,17 @@
<meta property="og:type" content="article" /> <meta property="og:type" content="article" />
<meta property="og:title" content="<?=title?>" /> <meta property="og:title" content="<?=title?>" />
<meta property="og:description" content="<?=tags?>" /> <meta property="og:description" content="<?=tags?>" />
<link rel="stylesheet" type="text/css" href="rst/hljs/github.css" /> <link rel="stylesheet" type="text/css" href="<?=HTTP_ROOT?>/rst/hljs/github.css" />
<link rel="stylesheet" type="text/css" href="rst/katex/katex.min.css" /> <link rel="stylesheet" type="text/css" href="<?=HTTP_ROOT?>/rst/katex/katex.min.css" />
<script src="rst/hljs/highlight.pack.js"> </script> <script src="<?=HTTP_ROOT?>/rst/hljs/highlight.pack.js"> </script>
<script src="rst/hljs/highlightjs-line-numbers.min.js"> </script> <script src="<?=HTTP_ROOT?>/rst/hljs/highlightjs-line-numbers.min.js"> </script>
<script src="rst/katex/katex.min.js"> </script> <script src="<?=HTTP_ROOT?>/rst/katex/katex.min.js"> </script>
<script src="rst/katex/auto-render.min.js"> </script> <script src="<?=HTTP_ROOT?>/rst/katex/auto-render.min.js"> </script>
<?lua else ?> <?lua else ?>
<meta property="og:url" content="https://blog.lxsang.me" /> <meta property="og:url" content="https://blog.lxsang.me" />
<meta property="og:type" content="article" /> <meta property="og:type" content="article" />
<meta property="og:title" content="Xuan Sang LE's blog" /> <meta property="og:title" content="Xuan Sang LE's blog" />
<meta property="og:description" content="My personal space" /> <meta property="og:description" content="Blog Home" />
<?lua end ?> <?lua end ?>
<script> <script>
@ -96,7 +96,7 @@
<div id = "navbar" class = "<?=cls?>"> <div id = "navbar" class = "<?=cls?>">
<div class = "logo"><a href = "https://lxsang.me"></a></div> <div class = "logo"><a href = "https://lxsang.me"></a></div>
<ul> <ul>
<li><i class = "fa fa-home"></i><a href="./">Home</a></li> <li><i class = "fa fa-home"></i><a href="<?=HTTP_ROOT?>">Home</a></li>
<li ><i class = "fa fa-address-card"></i><a href="https://info.lxsang.me" >Porfolio</a></li> <li ><i class = "fa fa-address-card"></i><a href="https://info.lxsang.me" >Porfolio</a></li>
<li><i class = "fa fa-envelope"></i><a href="#" onclick="mailtoMe('rst')" >Contact</a></li> <li><i class = "fa fa-envelope"></i><a href="#" onclick="mailtoMe('rst')" >Contact</a></li>
<?lua <?lua
@ -118,4 +118,13 @@
</div> </div>
<div id = "desktop"> <div id = "desktop">
<div id = "container"> <div id = "container">
<?lua
__main__:render()
?>
</div>
</div>
<div id = "bottom">
Powered by antd server, (c) 2017 - 2018 Xuan Sang LE
</div>
</body>
</html>

View File

@ -0,0 +1,8 @@
<div class = "notfound">
<p><?=error?></p>
<blockquote>
“In many ways my life has been rather like a record of the lost and found. Perhaps all lives are like that.”
<span>― Lucy Foley, The Book of Lost and Found</span>
</blockquote >
</div>

View File

@ -0,0 +1,3 @@
<?lua
echo("<h3>"..message.."</h3>")
?>

View File

@ -1,56 +1,10 @@
<?lua <?lua
local arg = {...} local data = post
local data = arg[1]
local order = arg[2]
local content = nil;
local url = nil
local topview = loadscript(BLOG_ROOT.."/view/top.ls")
local class = "card" local class = "card"
if HEADER.mobile then if HEADER.mobile then
class = "card mobile" class = "card mobile"
end end
local title = "Welcome to my blog" local content = data.rendered
if not #data or #order == 0 then
topview(title, false)
?>
<div class = "notfound">
<p>No entry found</p>
<blockquote>
“In many ways my life has been rather like a record of the lost and found. Perhaps all lives are like that.”
<span>― Lucy Foley, The Book of Lost and Found</span>
</blockquote >
</div>
<?lua
return
else
data = data[1]
content = bytes.__tostring(std.b64decode(data.rendered)):gsub("%%","%%%%")
local a,b = content:find("<[Hh]1[^>]*>")
if a then
local c,d = content:find("</[Hh]1>")
if c then
title = content:sub(b+1, c-1)
end
end
url = "https://blog.lxsang.me/r:id:"..data.id
topview(title, true, url, data.tags)
end
-- fetch the similar posts from database
local db = require("db.model").get(BLOG_ADMIN,"st_similarity", nil)
local similar_posts = nil
if db then
local records = db:find({ exp = {["="] = {pid = data.id}}, order = {score = "DESC"}})
--echo("records size is #"..#records)
local pdb = require("db.model").get(BLOG_ADMIN,"blogs", nil)
if(pdb) then
similar_posts = {}
for k,v in pairs(records) do
similar_posts[k] = { st = v, post = pdb:get(v.sid) }
end
pdb:close()
end
db:close()
end
?> ?>
<div class = "<?=class?>"> <div class = "<?=class?>">
<div class = "side"> <div class = "side">
@ -63,7 +17,7 @@
tag = std.trim(tag, " ") tag = std.trim(tag, " ")
if tag ~= "" then if tag ~= "" then
local b64tag = std.b64encode(tag) local b64tag = std.b64encode(tag)
atags[i] = '<a href = "./r:bytag:'..b64tag:gsub("=","")..':'..MAX_ENTRY..'">'..tag.."</a>" atags[i] = '<a href = "'..HTTP_ROOT..'/post/bytag/'..b64tag:gsub("=","")..'/'..POST_LIMIT..'">'..tag.."</a>"
i = i+ 1 i = i+ 1
end end
end end

View File

@ -0,0 +1,8 @@
<div class = "notfound">
<p><?=error?></p>
<blockquote>
“In many ways my life has been rather like a record of the lost and found. Perhaps all lives are like that.”
<span>― Lucy Foley, The Book of Lost and Found</span>
</blockquote >
</div>

View File

@ -1,30 +1,12 @@
<?lua <?lua
local arg = {...} local datas = posts
local datas = arg[1]
local order = arg[2]
local minid = arg[3]
local maxid = arg[4]
local action = arg[5]
local class = "card" local class = "card"
local first_id = nil local first_id = nil
local last_id = nil local last_id = nil
if HEADER.mobile then if HEADER.mobile then
class = "card mobile" class = "card mobile"
end end
loadscript(BLOG_ROOT.."/view/top.ls")("Welcome to my blog", false)
if #order == 0 then
?>
<div class = "notfound">
<p>No entry found</p>
<blockquote>
“In many ways my life has been rather like a record of the lost and found. Perhaps all lives are like that.”
<span>― Lucy Foley, The Book of Lost and Found</span>
</blockquote >
</div>
<?lua
return
end
for idx,v in pairs(order) do for idx,v in pairs(order) do
local data = datas[v] local data = datas[v]
if not last_id then last_id = data.id end if not last_id then last_id = data.id end
@ -41,12 +23,12 @@
tag = std.trim(tag, " ") tag = std.trim(tag, " ")
if tag ~= "" then if tag ~= "" then
local b64tag = std.b64encode(tag) local b64tag = std.b64encode(tag)
atags[i] = '<a href = "./r:bytag:'..b64tag:gsub("=","")..':'..MAX_ENTRY..'">'..tag.."</a>" atags[i] = '<a href = "'..HTTP_ROOT..'/post/bytag/'..b64tag:gsub("=","")..'/'..POST_LIMIT..'">'..tag.."</a>"
i = i+ 1 i = i+ 1
end end
end end
echo(table.concat(atags, ", ")) echo(table.concat(atags, ", "))
local url = "https://blog.lxsang.me/r:id:"..data.id local url = HTTP_ROOT.."/post/id/"..data.id
?> ?>
</span> </span>
<div class="fb-like" data-href="<?=url?>" data-layout="button_count" data-action="like" data-size="small" data-show-faces="true" data-share="true"></div> <div class="fb-like" data-href="<?=url?>" data-layout="button_count" data-action="like" data-size="small" data-show-faces="true" data-share="true"></div>
@ -72,7 +54,7 @@
end end
if title then if title then
echo(content:sub(0, b)) echo(content:sub(0, b))
echo("<a class = 'title_link' href='./r:id:"..data.id.."'>"..title.."</a>") echo("<a class = 'title_link' href='"..HTTP_ROOT.."/post/id/"..data.id.."'>"..title.."</a>")
echo(content:sub(c)) echo(content:sub(c))
else else
echo(content) echo(content)
@ -81,18 +63,18 @@
</div> </div>
<div class = "detail"> <div class = "detail">
<span></span> <span></span>
<?='<a href="./r:id:'..data.id..'" ></a>'?> <?='<a href="'..HTTP_ROOT..'/post/id/'..data.id..'" ></a>'?>
<span></span> <span></span>
</div> </div>
</div> </div>
</div> </div>
<?lua <?lua
end end
local beforelk = "./r:beforeof:"..first_id..":"..MAX_ENTRY local beforelk = HTTP_ROOT.."/post/beforeof/"..first_id.."/"..POST_LIMIT
local afterlk = "./r:afterof:"..last_id..":"..MAX_ENTRY local afterlk = HTTP_ROOT.."/post/afterof/"..last_id.."/"..POST_LIMIT
if action == "bytag" or action == "search" then if action == "bytag" or action == "search" then
beforelk = "./r:"..action..":"..LAST_QUERY..":"..MAX_ENTRY..":before:"..first_id beforelk = HTTP_ROOT.."/post/"..action.."/"..query.."/"..POST_LIMIT.."/before/"..first_id
afterlk = "./r:"..action..":"..LAST_QUERY..":"..MAX_ENTRY..":after:"..last_id afterlk = HTTP_ROOT.."/post/"..action.."/"..query.."/"..POST_LIMIT.."/after/"..last_id
end end
?> ?>
<div class = "time-travel"> <div class = "time-travel">

View File

@ -1,6 +1,4 @@
<?lua <?lua
local args = {...}
local data = args[1].data
if not data then return end if not data then return end
for k,v in pairs(data) do for k,v in pairs(data) do

View File

@ -1,24 +1,20 @@
<?lua
local args = {...}
local views = args[1]
?>
<html> <html>
<head> <head>
<script type="text/javascript" src="rst/gscripts/showdown.min.js"></script> <script type="text/javascript" src="<?=HTTP_ROOT?>/rst/gscripts/showdown.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css" /> <link rel="stylesheet" type="text/css" href="<?=HTTP_ROOT?>/style.css" />
<link rel="stylesheet" type="text/css" href="rst/font-awesome.css" /> <link rel="stylesheet" type="text/css" href="<?=HTTP_ROOT?>/rst/font-awesome.css" />
<title>Porfolio</title> <title>Porfolio</title>
</head> </head>
<body> <body>
<div class="layout"> <div class="layout">
<div class = "cv-content"> <div class = "cv-content">
<?lua <?lua
if views.user then if user then
views.user:render() user:render()
end end
if views.__main__ then if __main__ then
views.__main__:render() __main__:render()
end end
?> ?>
<div class = "container"> <div class = "container">
@ -27,9 +23,9 @@
</div> </div>
</div> </div>
<?lua <?lua
if views.toc then if toc then
views.toc:set("data", views.__main__:get("toc")) toc:set("data", __main__:get("toc"))
views.toc:render() toc:render()
end end
?> ?>
</div> </div>

View File

@ -1,7 +1,5 @@
<?lua <?lua
if HEADER.mobile then return end if HEADER.mobile then return end
local args = {...}
local data = args[1].data
if not data then return end if not data then return end
?> ?>
<div class = "cv-toc"> <div class = "cv-toc">

View File

@ -1,8 +1,3 @@
<?lua
local args = {...}
local data = args[1].data
?>
<h1> <h1>
<span class="name"><?=data.fullname?></span> <span class="name"><?=data.fullname?></span>
<span class="cv">Curriculum Vitae</span> <span class="cv">Curriculum Vitae</span>

View File

@ -75,6 +75,11 @@ BaseController:subclass("NotfoundController",{ registry = {}, models = {} })
function NotfoundController:index(...) function NotfoundController:index(...)
local args = {...} local args = {...}
local error = args[2] or "" 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) self:error("404: Controller "..args[1].." not found : "..error)
return false return false
end end
@ -102,7 +107,7 @@ function AssetController:get(...)
self:error("Access forbidden: "..path) self:error("Access forbidden: "..path)
end end
else else
self:error("Assset file not found: "..path) self:error("Asset file not found: "..path)
end end
return false return false
end end

View File

@ -38,6 +38,12 @@ function BaseModel:find(cond)
return false return false
end 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() function BaseModel:findAll()
if self.db then if self.db then
return self.db:getAll(self.name) return self.db:getAll(self.name)

View File

@ -6,6 +6,7 @@ end
function Router:initialize() function Router:initialize()
self.routes = {} self.routes = {}
self.remaps = {}
end end
--function Router:setArgs(args) --function Router:setArgs(args)
@ -23,7 +24,7 @@ function Router:infer(url)
-- c,d,e is parameters -- c,d,e is parameters
-- if user dont provide the url, try to infer it -- if user dont provide the url, try to infer it
-- from the REQUEST -- from the REQUEST
url = url or REQUEST.query.r url = url or REQUEST.query.r or ""
url = std.trim(url, "/") url = std.trim(url, "/")
local args = explode(url, "/") local args = explode(url, "/")
local data = { local data = {
@ -41,6 +42,10 @@ function Router:infer(url)
end end
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 -- find the controller class and init it
local controller_name = firstToUpper(data.name) .. "Controller" local controller_name = firstToUpper(data.name) .. "Controller"
local controller_path = self.path .. "." .. controller_name local controller_path = self.path .. "." .. controller_name
@ -84,7 +89,7 @@ function Router:delegate()
data.controller.main = true data.controller.main = true
views.__main__ = self:call(data) views.__main__ = self:call(data)
if not views.__main__ then if not views.__main__ then
--self:error("No main template is set") --self:error("No view available for this action")
return return
end end
-- get all visible routes -- get all visible routes
@ -94,16 +99,23 @@ function Router:delegate()
views[k] = self:call(data) views[k] = self:call(data)
end end
-- now require the main page to put the view -- 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() html()
if fn then if fn then
local r, o = pcall(fn, views) local r, o = pcall(fn, table.unpack(view_argv))
if not r then if not r then
self:error(o) self:error(o)
end end
else 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
end end
@ -142,6 +154,10 @@ function Router:call(data)
end end
end end
function Router:remap(from, to)
self.remaps[from] = to
end
function Router:route(layout, dependencies) function Router:route(layout, dependencies)
self.routes[layout] = dependencies self.routes[layout] = dependencies
end end

View File

@ -31,14 +31,24 @@ function Template:path()
if ulib.exists(path) then if ulib.exists(path) then
return path return path
else else
self:error("View not found: "..path) return false, path
end end
end end
-- render the page -- render the page
function Template:render() 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 if fn then
local r,o = pcall(fn, self.vars) local r,o = pcall(fn, table.unpack(argv))
if not r then if not r then
self:error(o) self:error(o)
end end

View File

@ -16,6 +16,7 @@ POLICY.mimes = {
["application/javascript"] = true, ["application/javascript"] = true,
["image/bmp"] = true, ["image/bmp"] = true,
["image/jpeg"] = true, ["image/jpeg"] = true,
["image/png"] = true,
["text/css"] = true, ["text/css"] = true,
["text/markdown"] = true, ["text/markdown"] = true,
["text/csv"] = true, ["text/csv"] = true,
@ -49,4 +50,8 @@ function html()
std.chtml(SESSION) std.chtml(SESSION)
HEADER_FLAG = true HEADER_FLAG = true
end end
end
function import(module)
return require(BASE_FRW.."silk.api."..module)
end end