1
0
mirror of https://github.com/lxsang/antd-web-apps synced 2025-07-23 17:19:47 +02: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,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">