1
0
mirror of https://github.com/lxsang/antd-web-apps synced 2024-12-25 17:08:22 +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
local args = {...}
local views = args[1]
local main = views.__main__
local jsclass = main:get("jsclass")
local jsclass = __main__:get("jsclass")
if jsclass == nil then jsclass = "" end
?>
<html>
@ -28,7 +26,7 @@ if jsclass == nil then jsclass = "" end
<div id="desktop">
<?lua
main:render()
__main__:render()
?>
</div>
</body>

View File

@ -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)/*

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
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>&<query>
-- 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

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
local arg = {...}
local title = arg[1]
local render = arg[2]
local url = arg[3]
local tags = arg[4]
local title = __main__:get("title")
local render = __main__:get("render")
local url = __main__:get("url")
local tags = __main__:get("tags")
local cls = ""
if HEADER.mobile then
cls = "navmobile"
@ -14,16 +15,15 @@
<head>
<title><?=title?></title>
<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">
<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="assets/style.css" />
<script src="rst/gscripts/riot.min.js"> </script>
<script src="rst/resources/antos_tags.js"></script>
<script src="rst/gscripts/jquery-3.2.1.min.js"> </script>
<script src="rst/main.js"></script>
<link rel="stylesheet" type="text/css" href="<?=HTTP_ROOT?>/rst/ubuntu-regular.css" />
<link rel="stylesheet" type="text/css" href="<?=HTTP_ROOT?>/rst/font-awesome.css" />
<link rel="stylesheet" type="text/css" href="<?=HTTP_ROOT?>/assets/style.css" />
<script src="<?=HTTP_ROOT?>/rst/gscripts/riot.min.js"> </script>
<script src="<?=HTTP_ROOT?>/rst/resources/antos_tags.js"></script>
<script src="<?=HTTP_ROOT?>/rst/gscripts/jquery-3.2.1.min.js"> </script>
<script src="<?=HTTP_ROOT?>/rst/main.js"></script>
<meta property="og:image" content="" />
<?lua if render then ?>
<meta name="twitter:card" content="summary" />
@ -33,17 +33,17 @@
<meta property="og:type" content="article" />
<meta property="og:title" content="<?=title?>" />
<meta property="og:description" content="<?=tags?>" />
<link rel="stylesheet" type="text/css" href="rst/hljs/github.css" />
<link rel="stylesheet" type="text/css" href="rst/katex/katex.min.css" />
<script src="rst/hljs/highlight.pack.js"> </script>
<script src="rst/hljs/highlightjs-line-numbers.min.js"> </script>
<script src="rst/katex/katex.min.js"> </script>
<script src="rst/katex/auto-render.min.js"> </script>
<link rel="stylesheet" type="text/css" href="<?=HTTP_ROOT?>/rst/hljs/github.css" />
<link rel="stylesheet" type="text/css" href="<?=HTTP_ROOT?>/rst/katex/katex.min.css" />
<script src="<?=HTTP_ROOT?>/rst/hljs/highlight.pack.js"> </script>
<script src="<?=HTTP_ROOT?>/rst/hljs/highlightjs-line-numbers.min.js"> </script>
<script src="<?=HTTP_ROOT?>/rst/katex/katex.min.js"> </script>
<script src="<?=HTTP_ROOT?>/rst/katex/auto-render.min.js"> </script>
<?lua else ?>
<meta property="og:url" content="https://blog.lxsang.me" />
<meta property="og:type" content="article" />
<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 ?>
<script>
@ -96,7 +96,7 @@
<div id = "navbar" class = "<?=cls?>">
<div class = "logo"><a href = "https://lxsang.me"></a></div>
<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-envelope"></i><a href="#" onclick="mailtoMe('rst')" >Contact</a></li>
<?lua
@ -118,4 +118,13 @@
</div>
<div id = "desktop">
<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
local arg = {...}
local data = arg[1]
local order = arg[2]
local content = nil;
local url = nil
local topview = loadscript(BLOG_ROOT.."/view/top.ls")
local data = post
local class = "card"
if HEADER.mobile then
class = "card mobile"
end
local title = "Welcome to my blog"
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
local content = data.rendered
?>
<div class = "<?=class?>">
<div class = "side">
@ -63,7 +17,7 @@
tag = std.trim(tag, " ")
if tag ~= "" then
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
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
local arg = {...}
local datas = arg[1]
local order = arg[2]
local minid = arg[3]
local maxid = arg[4]
local action = arg[5]
local datas = posts
local class = "card"
local first_id = nil
local last_id = nil
if HEADER.mobile then
class = "card mobile"
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
local data = datas[v]
if not last_id then last_id = data.id end
@ -41,12 +23,12 @@
tag = std.trim(tag, " ")
if tag ~= "" then
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
end
end
echo(table.concat(atags, ", "))
local url = "https://blog.lxsang.me/r:id:"..data.id
local url = HTTP_ROOT.."/post/id/"..data.id
?>
</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>
@ -72,7 +54,7 @@
end
if title then
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))
else
echo(content)
@ -81,18 +63,18 @@
</div>
<div class = "detail">
<span></span>
<?='<a href="./r:id:'..data.id..'" ></a>'?>
<?='<a href="'..HTTP_ROOT..'/post/id/'..data.id..'" ></a>'?>
<span></span>
</div>
</div>
</div>
<?lua
end
local beforelk = "./r:beforeof:"..first_id..":"..MAX_ENTRY
local afterlk = "./r:afterof:"..last_id..":"..MAX_ENTRY
local beforelk = HTTP_ROOT.."/post/beforeof/"..first_id.."/"..POST_LIMIT
local afterlk = HTTP_ROOT.."/post/afterof/"..last_id.."/"..POST_LIMIT
if action == "bytag" or action == "search" then
beforelk = "./r:"..action..":"..LAST_QUERY..":"..MAX_ENTRY..":before:"..first_id
afterlk = "./r:"..action..":"..LAST_QUERY..":"..MAX_ENTRY..":after:"..last_id
beforelk = HTTP_ROOT.."/post/"..action.."/"..query.."/"..POST_LIMIT.."/before/"..first_id
afterlk = HTTP_ROOT.."/post/"..action.."/"..query.."/"..POST_LIMIT.."/after/"..last_id
end
?>
<div class = "time-travel">

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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