1
0
mirror of https://github.com/lxsang/antd-web-apps synced 2025-07-16 13:59:52 +02:00

Compare commits

..

38 Commits

Author SHA1 Message Date
bed7fc6ec0 Merge pull request #38 from lxsang/master
Update style.css
2021-01-03 22:53:03 +01:00
a361a475c9 Merge pull request #37 from lxsang/master
setting file should not be readable by other user
2021-01-02 13:51:55 +01:00
dd0f7bc860 Merge pull request #36 from lxsang/master
update
2020-12-25 22:42:20 +01:00
71a661bc4a Merge pull request #35 from lxsang/master
update script
2020-12-18 21:57:22 +01:00
291a45cdb5 Merge pull request #34 from lxsang/master
fix scrollbug
2020-12-09 12:13:41 +01:00
4ba7bd6b24 Merge pull request #33 from lxsang/master
fix scrolldown bug
2020-12-09 12:01:06 +01:00
47eab0a1dc Merge pull request #32 from lxsang/master
fix scrolldown bug
2020-12-09 11:55:03 +01:00
be1f9e9fe1 Merge pull request #31 from lxsang/master
fix display issues
2020-12-09 11:30:25 +01:00
c076bd68b2 Merge pull request #30 from lxsang/master
fix display issues
2020-12-09 11:27:58 +01:00
185f676dd6 Merge pull request #29 from lxsang/master
Update sites styles
2020-12-09 11:25:11 +01:00
7f326baad5 Merge pull request #28 from lxsang/master
update
2020-11-19 19:03:46 +01:00
91f15fd884 Merge pull request #27 from lxsang/master
add script
2020-11-19 18:10:28 +01:00
cd30af6da4 Merge pull request #26 from lxsang/master
fix local image rendering bug
2020-10-01 11:19:53 +02:00
05ee884e8d Merge pull request #25 from lxsang/master
clean up front pages
2020-09-24 19:19:25 +02:00
d96a9c699e Merge pull request #24 from lxsang/master
support author notification
2020-09-22 19:51:29 +02:00
fda4a23943 Merge pull request #23 from lxsang/master
add To to sendmail function
2020-09-22 18:24:50 +02:00
acbbe8f0a2 Merge pull request #22 from lxsang/master
support comments in odc
2020-09-22 17:59:22 +02:00
99414311e5 Merge pull request #21 from lxsang/master
allow tab, math and highlight in comments
2020-09-22 17:16:54 +02:00
3f7bc5fa7d Merge pull request #20 from lxsang/master
allow tab, math and highlight in comments
2020-09-22 17:14:25 +02:00
dd3e56fb01 Merge pull request #19 from lxsang/master
enhance error handling
2020-09-22 16:51:56 +02:00
5c5d3504ad Merge pull request #18 from lxsang/master
use quicktalk as comment API
2020-09-22 16:24:45 +02:00
53e2b3b891 Merge pull request #17 from lxsang/master
update profile pic
2020-09-18 14:01:59 +02:00
6bde15ff78 Merge pull request #16 from lxsang/master
fix antos build destination
2020-09-18 13:37:08 +02:00
90b812f35a Merge pull request #15 from lxsang/master
use afx in blog
2020-09-18 13:27:43 +02:00
81f8e1c984 Merge pull request #14 from lxsang/master
Update antos doc
2020-09-15 16:56:24 +02:00
6e6b7930bc Merge pull request #13 from lxsang/master
add Youtube support on doc front end
2020-09-15 11:12:13 +02:00
7d05a51cff Merge pull request #12 from lxsang/master
Youtube support for doc frontend
2020-09-15 10:30:57 +02:00
f03d18499b Merge pull request #11 from lxsang/master
clean up
2020-09-13 17:58:07 +02:00
8de304f2c6 Merge pull request #10 from lxsang/master
add jarvis controller
2020-09-13 17:28:32 +02:00
f684005fe4 Merge pull request #9 from lxsang/master
support for local media
2020-09-13 17:16:01 +02:00
257f1e42bd Merge pull request #8 from lxsang/master
fix bug
2020-09-01 18:03:51 +02:00
db730f7220 Merge pull request #7 from lxsang/master
use backend markdown renderer
2020-09-01 17:40:03 +02:00
f04a756b4c Merge pull request #6 from lxsang/master
increase document font size
2020-06-26 16:51:36 +02:00
396f1950dc Merge pull request #5 from lxsang/master
external link should be opened in a new tab
2020-06-26 16:46:25 +02:00
2902e95e86 Merge pull request #4 from lxsang/master
add style for line number
2020-06-26 16:38:00 +02:00
3af5abdf87 Merge pull request #3 from lxsang/master
add style for line number
2020-06-26 16:35:54 +02:00
7e96479136 Merge pull request #2 from lxsang/master
fix auth bug
2020-06-26 15:47:07 +02:00
36c73c8035 Merge pull request #1 from lxsang/master
Add auto build script on pull request
2020-06-26 10:34:20 +02:00
44 changed files with 277 additions and 1576 deletions

View File

@ -1,22 +0,0 @@
---
kind: pipeline
type: exec
name: default
platform:
os: linux
arch: amd64
clone:
disable: true
steps:
- name: clone
commands:
- pwd
- git clone ssh://git@iohub.dev/lxsang/antd-web-apps.git
- cd ./antd-web-apps && git checkout master
- name: build
commands:
- cd ./antd-web-apps
- BUILDDIR=/opt/www/htdocs make
trigger:
branch:
- master

49
Jenkinsfile vendored
View File

@ -1,49 +0,0 @@
def remote = [:]
remote.name = 'workstation'
remote.host = 'workstation'
remote.user = 'dany'
remote.identityFile = '/var/jenkins_home/.ssh/id_rsa'
remote.allowAnyHosts = true
remote.agent = false
remote.logLevel = 'INFO'
pipeline{
agent { node{ label'master' }}
options {
// Limit build history with buildDiscarder option:
// daysToKeepStr: history is only kept up to this many days.
// numToKeepStr: only this many build logs are kept.
// artifactDaysToKeepStr: artifacts are only kept up to this many days.
// artifactNumToKeepStr: only this many builds have their artifacts kept.
buildDiscarder(logRotator(numToKeepStr: "1"))
// Enable timestamps in build log console
timestamps()
// Maximum time to run the whole pipeline before canceling it
timeout(time: 1, unit: 'HOURS')
// Use Jenkins ANSI Color Plugin for log console
ansiColor('xterm')
// Limit build concurrency to 1 per branch
disableConcurrentBuilds()
}
stages
{
stage('Build') {
steps {
sshCommand remote: remote, command: '''
set -e
export WORKSPACE=$(realpath "./jenkins/workspace/antd-web-apps")
cd $WORKSPACE
[ -d build ] && rm -rf build
mkdir -p build/opt/www/htdocs
export BUILDDIR="$WORKSPACE/build/opt/www/htdocs"
make
'''
script {
// only useful for any master branch
//if (env.BRANCH_NAME =~ /^master/) {
archiveArtifacts artifacts: 'build/', fingerprint: true
//}
}
}
}
}
}

View File

@ -1,12 +1,12 @@
BUILDDIR?=./build BUILDDIR?=./build
PROJS?=grs info blog os doc talk get PROJS?=grs info blog os doc ci talk get
copyfiles = index.ls mimes.json copyfiles = index.ls mimes.json
main: copy main: copy
for f in $(PROJS); do BUILDDIR=$(BUILDDIR)/"$${f}" make -C "$${f}" ; done for f in $(PROJS); do BUILDDIR=$(BUILDDIR)/"$${f}" make -C "$${f}" ; done
copy: copy:
cp -rfv $(copyfiles) $(BUILDDIR) cp -rf $(copyfiles) $(BUILDDIR)
cp -rv silk $(BUILDDIR) cp -r silk $(BUILDDIR)
ar: ar:
-[ -d /tmp/antd_web_apps ] && rm -r /tmp/antd_web_apps -[ -d /tmp/antd_web_apps ] && rm -r /tmp/antd_web_apps
@ -19,4 +19,4 @@ ar:
clean: clean:
-for f in $(PROJS); do rm -r $(BUILDDIR)/"$${f}"; done -for f in $(PROJS); do rm -r $(BUILDDIR)/"$${f}"; done
-for f in $(copyfiles); do rm -r $(BUILDDIR)/"$${f}"; done -for f in $(copyfiles); do rm -r $(BUILDDIR)/"$${f}"; done
-rm -r $(BUILDDIR)/silk -rm -r $(BUILDDIR)/silk

View File

@ -1,2 +1,2 @@
# antd-web-apps # antd-web-apps
Various web apps for antd server Some web apps for antd server

View File

@ -1,4 +1,4 @@
copyfiles = assets views models ai controllers router.lua copyfiles = assets views models controllers router.lua
main: main:
- mkdir -p $(BUILDDIR) - mkdir -p $(BUILDDIR)

View File

@ -1,345 +0,0 @@
local doclassify = {}
local st = require("stmr")
doclassify.bow = function(data, stopwords)
-- first step get a table of worlds that contain
-- world: occurences
local bag = {}
for w in data:gmatch('%w+') do
local word = w:lower()
if not stopwords[word] then
word = st.stmr(word)
if bag[word] then
bag[word].count = bag[word].count + 1
else
bag[word] = {count=0, tf=0, tfidf=0.0}
bag[word].count = 1
end
end
end
-- now calculate the tf of the bag
for k,v in pairs(bag) do
bag[k].tf = math.log(1 + bag[k].count)
end
return bag
end
doclassify.len = function(table)
local cnt = 0
for k,v in pairs(table) do cnt = cnt+1 end
return cnt
end
doclassify.tfidf = function(documents)
-- now for each term in a bag, calculate
-- the inverse document frequency, which
-- is a measure of how much information
-- the word provides, that is, whether the
-- term is common or rare across all documents
local ndoc = doclassify.len(documents)
for k,bag in pairs(documents) do
-- for eacht term in bag
-- calculate its idf across all documents
for term,b in pairs(bag) do
local n = 0
for id,doc in pairs(documents) do
if doc[term] then n = n+1 end
end
--echo("term:"..term.." appears in"..n.." documents")
b.tfidf = b.tf*math.log(ndoc/n)
end
end
end
doclassify.search = function(term, documents)
local r = {}
for id, doc in pairs(documents) do
if doc[term:lower()] then
r[id] = doc[term].tfidf
end
end
return r
end
doclassify.get_vectors = function(documents)
-- get a list of vector from documents
local index = 0
local vectors = {}
local maps = {}
local terms = {}
local maxv = 0
for id in pairs(documents) do
maps[id] = {}
vectors[id] = {}
end
-- first loop, get the term
for id, doc in pairs(documents) do
for k,v in pairs(doc) do
-- get max value
if v.tfidf > maxv then
maxv = v.tfidf
end
-- get the term
if not terms[k] then
index = index + 1
terms[k] = index
end
for pid in pairs(documents) do
if not maps[pid][k] then
if id == pid then
maps[pid][k] = v.tfidf
else
maps[pid][k] = 0
end
else
if maps[pid][k] == 0 and id == pid then
maps[pid][k] = v.tfidf
end
end
end
end
end
-- reindexing the vectors
for id in pairs(documents) do
for k,v in pairs(maps[id]) do
vectors[id][terms[k]] = v
end
end
--echo("Max tfidf "..maxv.." in document #"..maxid.." of term "..term)
return vectors, maxv, index, terms
end
doclassify.similarity = function(va, vb)
-- using cosin similarity
local dotp = 0
local maga = 0
local magb = 0
for k = 1,#va do
dotp = dotp + va[k]*vb[k]
maga = maga + va[k]*va[k]
magb = magb + vb[k]*vb[k]
end
maga = math.sqrt(maga)
magb = math.sqrt(magb)
local d = 0
if maga ~= 0 and magb ~= 0 then
d = dotp/ (magb*maga)
end
return d
end
doclassify.similarities = function(v1, collection)
local similarities = {}
assert(#v1 == #(collection[1]), "Incorrect vectors size")
for i=1,#collection do
similarities[i] = doclassify.similarity(v1, collection[i])
end
return similarities
end
doclassify.mean_similarity = function(v1, v2)
assert(#v1 == #v2, "Incorrect vectors size")
local similarities = {}
for i = 1,#v1 do similarities[i] = doclassify.similarity(v1[i], v2[i]) end
return doclassify.mean(similarities)
end
doclassify.similarity_chart = function(id, vectors)
local vs = {}
local cnt = 0
local lut = {}
for k,v in pairs(vectors) do
if k ~= id then
cnt = cnt + 1
vs[cnt] = v
lut[cnt] = k
end
end
if not vs[1] then return {} end
return doclassify.similarities(vectors[id], vs), lut
end
doclassify.top_similarity = function(id, vectors, n, th)
local chart,lut = doclassify.similarity_chart(id,vectors)
--echo(JSON.encode(chart))
--echo(JSON.encode(lut))
if not lut or #lut <= 0 then return nil end
local top = {}
local j=0
local goon = true
if not th then
goon = false
end
while j < n or goon
do
local i,maxv = doclassify.argmax(chart)
top[lut[i]] = maxv
chart[i] = 0.0
j=j+1
if maxv < th and goon then
goon = false
end
end
--for j=1,n do
-- local i,maxv = doclassify.argmax(chart)
-- top[lut[i]] = maxv
-- chart[i] = 0.0
--end
return top
end
doclassify.save_vectors = function(vectors, name)
local f = io.open(name,"w")
if f == nil then return false end
for id, v in pairs(vectors) do
f:write(id)
for i=1,#v do f:write(","..v[i]) end
f:write("\n")
end
f:close()
return true
end
doclassify.save_topchart = function(vectors, name,n)
local f = io.open(name,"w")
if f == nil then return false end
for k,v in pairs(vectors) do
local top = doclassify.top_similarity(k,vectors,n, 0.1)
for a,b in pairs(top) do
f:write(k.." "..a.." "..b.."\n")
end
end
f:close()
return true
end
doclassify.kmean = function(nclass, documents, maxstep, ids)
-- now
local vectors, maxv, size = doclassify.get_vectors(documents)
-- random centroids
local centroids = {}
local old_centroids = {}
local clusters = {}
--for pid in pairs(documents) do clusters[pid] = 0 end
-- add noise to mean_vector
for i = 1,nclass do
if ids == nil then
centroids[i] = doclassify.random(size,math.floor(maxv))
else
centroids[i] = vectors[ids[i]]
end
old_centroids[i] = doclassify.zeros(size)
end
-- loop until convergence or maxstep reached
local similarity = doclassify.mean_similarity(centroids, old_centroids)
local step = maxstep
while 1.0-similarity > 1e-9 and step > 0 do
clusters = {}
--echo(JSON.encode(centroids))
for id,v in pairs(vectors) do
local similarities = doclassify.similarities(v, centroids)
--echo(JSON.encode(similarities))
local cluster, maxvalue = doclassify.argmax(similarities)
--echo("doc #"..id.." is in clusters #"..cluster.." max value is "..maxvalue)
clusters[id] = cluster
end
-- storing the old centroids
old_centroids = centroids
-- calculate new centroids
local new_centroids = {}
for class in pairs(centroids) do
local cnt = 0
local cvectors = {}
for id,v in pairs(vectors) do
if clusters[id] == class then
cnt = cnt + 1
cvectors[cnt] = v
end
end
new_centroids[class] = doclassify.mean_vector(cvectors, size)
end
centroids = new_centroids
--echo(JSON.encode(centroids))
--echo(JSON.encode(old_centroids))
similarity = doclassify.mean_similarity(centroids, old_centroids)
echo("step #"..step..", similarity "..similarity)
step = step - 1
end
local results = {}
for i = 1,nclass do
local list = {}
local cnt = 0
for id,c in pairs(clusters) do
if c == i then
cnt = cnt + 1
list[cnt] = id
end
end
results[i] = list
end
return results, clusters, centroids
end
doclassify.zeros = function(n)
local vector = {}
for i = 1,n do vector[i] = 0.0 end
return vector
end
doclassify.random = function(n,maxv)
local vector = {}
for i=1,n do
vector[i] = math.random() + math.random(0, maxv)
end
return vector
end
doclassify.sum = function(v)
local sum = 0.0
for i=1,#v do sum = sum + v[i] end
return sum
end
doclassify.mean = function(v)
return doclassify.sum(v)/#v
end
doclassify.mean_vector = function(vectors, size)
local means = doclassify.zeros(size)
if not vectors or #vectors == 0 then return means end
--local size = #(vectors[1])
local times = 0
for k,v in pairs(vectors) do
for i=1,#v do means[i] = means[i] + v[i] end
times = times + 1
end
for i = 1,size do means[i] = means[i]/times end
return means
end
doclassify.argmin = function(v)
local minv = 0.0
local mini = 0.0
for i = 1,#v do
if v[i] <= minv then
mini = i
minv = v[i]
end
end
--echo("min index"..mini.." val "..minv)
return mini, minv
end
doclassify.argmax = function(v)
local maxv = 0.0
local maxi = 0.0
for i = 1,#v do
if v[i] >= maxv then
maxi = i
maxv = v[i]
end
end
return maxi,maxv
end
return doclassify

View File

@ -1,29 +0,0 @@
local gettext = {}
require("sqlite")
gettext.get = function(q)
local db = require("os.libs.dbmodel").get("mrsang","blogs",nil)
if not db then return nil end
local exp = {["="] =q}
local cond = {
exp = exp,
fields = {"id", "content"}
}
local data, sort = db:find(cond)
db:close()
if not data or #data == 0 then return nil end
--for k,v in pairs(data) do
-- data[k].content = bytes.__tostring(std.b64decode(data[k].content)):gsub("%%","%%%%")
--end
return data
end
gettext.stopwords = function(ospath)
--local ospath = require("fs/vfs").ospath(path)
local words = {}
for line in io.lines(ospath) do
words[line] = true
end
return words
end
return gettext

View File

@ -1,151 +0,0 @@
i
me
my
myself
we
our
ours
ourselves
you
your
yours
yourself
yourselves
he
him
his
himself
she
her
hers
herself
it
its
itself
they
them
their
theirs
themselves
what
which
who
whom
this
that
these
those
am
is
are
was
were
be
been
being
have
has
had
having
do
does
did
doing
a
an
the
and
but
if
or
because
as
until
while
of
at
by
for
with
about
against
between
into
through
during
before
after
above
below
to
from
up
down
in
out
on
off
over
under
again
further
then
once
here
there
when
where
why
how
all
any
both
each
few
more
most
other
some
such
no
nor
not
only
own
same
so
than
too
very
s
t
can
will
just
don
should
now
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
w
r
s
t
x
y
z

View File

@ -1,50 +0,0 @@
local path = require("fs/vfs").ospath("home://aiws/blog-clustering")
local gettext = loadfile(path.."/gettext.lua")()
local cluster = loadfile(path.."/cluster.lua")()
local refresh = false
local file = "/home/mrsang/test.csv"
if refresh then
local data = gettext.get({publish=1})
local documents = {}
if data then
local sw = gettext.stopwords("home://aiws/blog-clustering/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 s = cluster.save_topchart(vectors,file, 3)
if s then echo("file saved") else echo("error save file") end
--echo(JSON.encode(r))
--r = cluster.similarity(vectors["14"],vectors["16"])
--echo("Similarity "..r)
--local c,l = cluster.kmean(3, documents, 10)
--echo(JSON.encode(c))
--echo(JSON.encode(l))
else
echo("Data missing")
end
else
local f = io.open(file,"r")
local result = {}
for line in f:lines() do
local arr = {}
local cnt = 0
for i in line:gmatch( "%S+") do
cnt = cnt + 1
arr[cnt] = i
end
if not result[arr[1]] then result[arr[1]] = {} end
result[arr[1]][arr[2]] = tonumber(arr[3])
end
f:close()
echo(JSON.encode(result))
--local r = cluster.top_similarity("2",vectors, 3)
--echo(JSON.encode(r))
end

View File

@ -1,220 +0,0 @@
$(document).ready(function () {
const colors = [
"#3957ff", "#d3fe14", "#c9080a", "#fec7f8", "#0b7b3e", "#0bf0e9", "#c203c8", "#fd9b39",
"#888593", "#906407", "#98ba7f", "#fe6794", "#10b0ff", "#ac7bff", "#fee7c0", "#964c63",
"#1da49c", "#0ad811", "#bbd9fd", "#fe6cfe", "#297192", "#d1a09c", "#78579e", "#81ffad",
"#739400", "#ca6949", "#d9bf01", "#646a58", "#d5097e", "#bb73a9", "#ccf6e9", "#9cb4b6",
"#b6a7d4", "#9e8c62", "#6e83c8", "#01af64", "#a71afd", "#cfe589", "#d4ccd1", "#fd4109",
"#bf8f0e", "#2f786e", "#4ed1a5", "#d8bb7d", "#a54509", "#6a9276", "#a4777a", "#fc12c9",
"#606f15", "#3cc4d9", "#f31c4e", "#73616f", "#f097c6", "#fc8772", "#92a6fe", "#875b44",
"#699ab3", "#94bc19", "#7d5bf0", "#d24dfe", "#c85b74", "#68ff57", "#b62347", "#994b91",
"#646b8c", "#977ab4", "#d694fd", "#c4d5b5", "#fdc4bd", "#1cae05", "#7bd972", "#e9700a",
"#d08f5d", "#8bb9e1", "#fde945", "#a29d98", "#1682fb", "#9ad9e0", "#d6cafe", "#8d8328",
"#b091a7", "#647579", "#1f8d11", "#e7eafd", "#b9660b", "#a4a644", "#fec24c", "#b1168c",
"#188cc1", "#7ab297", "#4468ae", "#c949a6", "#d48295", "#eb6dc2", "#d5b0cb", "#ff9ffb",
"#fdb082", "#af4d44", "#a759c4", "#a9e03a", "#0d906b", "#9ee3bd", "#5b8846", "#0d8995",
"#f25c58", "#70ae4f", "#847f74", "#9094bb", "#ffe2f1", "#a67149", "#936c8e", "#d04907",
"#c3b8a6", "#cef8c4", "#7a9293", "#fda2ab", "#2ef6c5", "#807242", "#cb94cc", "#b6bdd0",
"#b5c75d", "#fde189", "#b7ff80", "#fa2d8e", "#839a5f", "#28c2b5", "#e5e9e1", "#bc79d8",
"#7ed8fe", "#9f20c3", "#4f7a5b", "#f511fd", "#09c959", "#bcd0ce", "#8685fd", "#98fcff",
"#afbff9", "#6d69b4", "#5f99fd", "#aaa87e", "#b59dfb", "#5d809d", "#d9a742", "#ac5c86",
"#9468d5", "#a4a2b2", "#b1376e", "#d43f3d", "#05a9d1", "#c38375", "#24b58e", "#6eabaf"];
d3.json("/post/graph_json")
.then(
function (json) {
if (json.result) {
const tooltip_div = d3.select("#desktop")
.append("div")
.attr("class", "d3tooltip")
.style("display", "none");
const links = json.result.links;
const nodes = json.result.nodes;
drag = simulation => {
function dragstarted(event) {
if (!event.active) simulation.alphaTarget(0.3).restart();
event.subject.fx = event.subject.x;
event.subject.fy = event.subject.y;
tooltip_div.style("display", "none");
}
function dragged(event) {
event.subject.fx = event.x;
event.subject.fy = event.y;
}
function dragended(event) {
if (!event.active) simulation.alphaTarget(0);
event.subject.fx = null;
event.subject.fy = null;
}
return d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
};
const simulation = d3.forceSimulation(nodes)
.force("link",
d3.forceLink(links)
.id(d => d.id)
.distance(d => 1.0 / d.score)
.strength(d => d.score)
)
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter());
const svg = d3.create("svg")
.attr("preserveAspectRatio", "xMidYMid meet");
const link = svg.append("g")
.attr("stroke", "#999")
.attr("stroke-opacity", 0.8)
.selectAll("line")
.data(links)
.join("line")
.attr("stroke-width", d => d.score * 7.0); //d.score
const node = svg.append("g")
.attr("stroke", "#fff")
.attr("stroke-width", 0.5)
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("r", (d) => {
conn = links.filter((l) => {
//console.log(d.id, l.target.id, l.source.id)
return l.target.id == d.id || l.source.id == d.id;
}).map(c=>c.score);
//return conn.reduce((a, b) => a + b, 0) * 10;
return conn.length;
})
.attr("fill", (d) => {
conn = links.filter((l) => {
//console.log(d.id, l.target.id, l.source.id)
return l.target.id == d.id || l.source.id == d.id;
});
return colors[conn.length % colors.length - 1];
})
.on("click", (d) => {
const index = $(d.target).index();
const data = nodes[index];
d3.json("/post/json/" + data.id)
.then( (json) => {
if(json.result)
{
$("#floating_content").html(json.result.description);
$("#floating_container").show();
$("#floating_btn_read_more").attr("href", "/post/id/" + json.result.id);
}
})
.catch ((e)=>{
console.log(e);
});
})
.call(drag(simulation))
.on('mouseover', function (d) {
const index = $(d.target).index();
const data = nodes[index];
link.style('stroke', function (l) {
if (data.id == l.source.id || data.id == l.target.id)
return "#9a031e";
else
return "#999";
});
const off = $("#desktop").offset();
tooltip_div.transition()
.duration(200)
tooltip_div.style("display", "block")
.style("opacity", .8);
tooltip_div.html(data.title)
.style("left", (d.clientX - off.left + 10) + "px")
.style("top", (d.clientY - off.top + 10) + "px");
})
.on('mouseout', function () {
link.style('stroke', "#999");
tooltip_div.style("display", "none");
});
//node.append("title")
// .text(d => d.title);
/*const label = svg.append("g")
.attr("stroke", "#fff")
.attr("stroke-width", 0.2)
.selectAll("text")
.data(nodes)
.join("text")
.text(d=>d.id)
.style("user-select", "none")
.style("font-size", (d) =>{
conn = links.filter((l) => {
//console.log(d.id, l.target.id, l.source.id)
return l.target.id == d.id || l.source.id == d.id;
});
return conn.length + "px";
})
.style('fill', '#000');*/
simulation.on("tick", () => {
link
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);
node
.attr("cx", d => d.x)
.attr("cy", d => d.y);
const nodes_x = nodes.map(d => d.x);
const nodes_y = nodes.map(d => d.y);
const min_x = Math.min(...nodes_x) - 10;
const min_y = Math.min(...nodes_y) - 10;
const w = Math.max(...nodes_x) - min_x + 10;
const h = Math.max(...nodes_y) - min_y + 10;
svg.attr("viewBox",
[min_x, min_y, w, h]);
/*label
.attr("x", d => {
conn = links.filter((l) => {
//console.log(d.id, l.target.id, l.source.id)
return l.target.id == d.id || l.source.id == d.id;
});
return d.x - conn.length / 2;
})
.attr("y", d => {
conn = links.filter((l) => {
//console.log(d.id, l.target.id, l.source.id)
return l.target.id == d.id || l.source.id == d.id;
});
return d.y + conn.length / 2;
});*/
});
// invalidation.then(() => simulation.stop());
$("#floating_btn_close").click((e)=>{
$("#floating_container").hide();
});
$("#desktop")
.css("position", "relative");
$("#container")
.css("height", "100%")
.css("position", "relative")
.append($(svg.node())
.css("height", "calc(100% - 10px)")
.css("margin", "0 auto")
.css("display", "block"));
$("#floating_container").show();
}
}
)
.catch((e) => {
console.log(e);
});
});

View File

@ -18,6 +18,7 @@ function subscribe(prefix) {
scheme = undefined; scheme = undefined;
}); });
obs.on("rendered", function (d) { obs.on("rendered", function (d) {
console.log("rednered");
$(".afx-window-title", scheme).html("Subscribe"); $(".afx-window-title", scheme).html("Subscribe");
$("[data-id='send']", scheme).click(function () { $("[data-id='send']", scheme).click(function () {
var status = $("[data-id='status']", scheme); var status = $("[data-id='status']", scheme);

View File

@ -73,52 +73,6 @@ body {
justify-content: flex-end; justify-content: flex-end;
flex-direction: row; flex-direction: row;
} }
div.d3tooltip {
position: absolute;
padding: 5px;
background-color: #2c2c2c;
color: white;
border: 0px;
border-radius: 5px;
max-width: 300px;
overflow: auto;
}
div.d3tooltip a{
color: white;
text-decoration: underline;
}
#floating_container {
position: absolute;
max-width: 50%;
height: calc(100% - 1px);
background-color: #2c2c2c;
opacity: 0.9;
right: 0;
overflow:hidden;
display: none;
}
#floating_content
{
overflow-y:auto;
height: 100%;
padding-left: 15px;
padding-right: 15px;
}
#floating_btn_container
{
display: block;
height: 24px;
padding: 5px;
font-weight: bold;
border-bottom: 1px solid #cccccc;
}
#floating_btn_container a {
text-decoration: none;
margin-right: 10px;
}
#floating_container, #floating_container a{
color: white;
}
#navbar.navmobile { #navbar.navmobile {
margin: 0 auto; margin: 0 auto;
max-width: 960px; max-width: 960px;

View File

@ -88,43 +88,6 @@ function PostController:bytag(b64tag, limit, action, id)
return true return true
end end
function PostController:json(id)
local obj = {
error = false,
result = false
}
local data, order = self.blog:fetch({["="] = {id = id}})
if not data or #order == 0 then
obj.error = "No data found"
else
data = data[1]
obj.result = {
id = data.id,
title = data.title,
description = nil,
tags = data.tags,
ctime = data.ctimestr,
utime = data.utimestr
}
local c, d = data.content:find("%-%-%-%-%-")
if c then
obj.description = data.content:sub(0, c - 1)
else
obj.description = data.content
end
-- convert description to html
local content = ""
local md = require("md")
local callback = function(s) content = content .. s end
md.to_html(obj.description, callback)
obj.result.description = content
end
std.json()
std.t(JSON.encode(obj));
return false;
end
function PostController:id(pid) function PostController:id(pid)
local data, order = self.blog:fetch({["="] = {id = pid}}) local data, order = self.blog:fetch({["="] = {id = pid}})
if not data or #order == 0 then if not data or #order == 0 then
@ -167,57 +130,11 @@ function PostController:actionnotfound(...)
return self:notfound("Action [" .. args[1] .. "] not found") return self:notfound("Action [" .. args[1] .. "] not found")
end end
function PostController:graph_json(...)
local nodes = self.blog:find({exp= { ["="] = { publish = 1}}, fields = {"id", "title"}})
local output = { error = false, result = false }
local lut = {}
std.json()
if not nodes then
output.error = "No nodes found"
else
output.result = {
nodes = {},
links = {}
}
for k,v in ipairs(nodes) do
local title = v.title
output.result.nodes[k] = { id = tonumber(v.id), title = title }
end
-- get statistic links
local links = self.analytical:find({fields = {"pid", "sid", "score"}})
if links then
local i = 1
for k,v in ipairs(links) do
local link = { source = tonumber(v.pid), target = tonumber(v.sid), score = tonumber(v.score)}
local key = ""
if link.source < link.target then
key = v.pid..v.sid
else
key = v.sid..v.pid
end
key = std.sha1(key)
if not lut[key] then
output.result.links[i] = link
i = i + 1
lut[key] = true
end
end
end
end
std.t(JSON.encode(output))
return false
end
function PostController:graph(...)
self.template:set("title", "Posts connection graph")
self.template:set("d3", true)
return true
end
function PostController:analyse(n) function PostController:analyse(n)
if not n then if not n then
n = 5 n = 5
end end
local path = WWW_ROOT..DIR_SEP.."ai" local path = "/home/mrsang/aiws/blog-clustering"
local gettext = loadfile(path .. "/gettext.lua")() local gettext = loadfile(path .. "/gettext.lua")()
local cluster = loadfile(path .. "/cluster.lua")() local cluster = loadfile(path .. "/cluster.lua")()
local data = gettext.get({publish = 1}) local data = gettext.get({publish = 1})
@ -236,7 +153,7 @@ function PostController:analyse(n)
self.analytical:delete({["="] = {["1"] = 1}}) self.analytical:delete({["="] = {["1"] = 1}})
-- get similarity and put to the table -- get similarity and put to the table
for id, v in pairs(vectors) do for id, v in pairs(vectors) do
local top = cluster.top_similarity(id, vectors, tonumber(n), 0.1) local top = cluster.top_similarity(id, vectors, n)
for a, b in pairs(top) do for a, b in pairs(top) do
local record = {pid = id, sid = a, score = b} local record = {pid = id, sid = a, score = b}
self.analytical:create(record) self.analytical:create(record)

View File

@ -27,7 +27,7 @@ function BlogModel:fetch(cnd, limit, order)
exp = {["and"] = exp }, exp = {["and"] = exp },
order = { ctime = "DESC" }, order = { ctime = "DESC" },
fields = { fields = {
"id", "title", "utime", "ctime", "utimestr", "content", "ctimestr", "rendered", "tags" "id", "title", "utime", "ctime", "utimestr", "ctimestr", "rendered", "tags"
} }
} }
if limit then if limit then

View File

@ -5,7 +5,6 @@
local render = __main__:get("render") local render = __main__:get("render")
local url = __main__:get("url") local url = __main__:get("url")
local tags = __main__:get("tags") local tags = __main__:get("tags")
local d3 = __main__:get("d3")
local cls = "" local cls = ""
if HEADER.mobile then if HEADER.mobile then
cls = "navmobile" cls = "navmobile"
@ -28,16 +27,8 @@
<script src="https://chat.iohub.dev/assets/quicktalk.js"> </script> <script src="https://chat.iohub.dev/assets/quicktalk.js"> </script>
<script src="<?=HTTP_ROOT?>/rst/afx.js"> </script> <script src="<?=HTTP_ROOT?>/rst/afx.js"> </script>
<script src="<?=HTTP_ROOT?>/rst/gscripts/jquery-3.4.1.min.js"> </script> <script src="<?=HTTP_ROOT?>/rst/gscripts/jquery-3.2.1.min.js"> </script>
<script src="<?=HTTP_ROOT?>/assets/main.js"></script> <script src="<?=HTTP_ROOT?>/assets/main.js"></script>
<?lua if d3 then ?>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.5.0/d3.min.js" ></script>
<script src="https://d3js.org/d3-dispatch.v2.min.js"></script>
<script src="https://d3js.org/d3-quadtree.v2.min.js"></script>
<script src="https://d3js.org/d3-timer.v2.min.js"></script>
<script src="https://d3js.org/d3-force.v2.min.js"></script>
<script src="<?=HTTP_ROOT?>/assets/graph.js"></script>
<?lua end ?>
<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" />
@ -125,14 +116,14 @@
<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="<?=HTTP_ROOT?>">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" >Portfolio</a></li>
<li><i class = "fa fa-envelope"></i><a href="#" onclick="mailtoMe('<?=HTTP_ROOT?>')" >Contact</a></li>
<?lua <?lua
if not HEADER.mobile then if not HEADER.mobile then
?> ?>
<li > <i class = "fa fa-globe"></i><a href = "/post/graph">Explore</a></li>
<li> <i class = "fa fa-paper-plane"></i><a href="#" onclick="subscribe('<?=HTTP_ROOT?>')">Subscribe</a></li> <li> <i class = "fa fa-paper-plane"></i><a href="#" onclick="subscribe('<?=HTTP_ROOT?>')">Subscribe</a></li>
<li > <i class = "fa fa-globe"></i><a href = "https://os.lxsang.me" target="_blank">AntOS</a></li>
<?lua end ?> <?lua end ?>
<li ><i class = "fa fa-address-card"></i><a href="https://info.lxsang.me" >Portfolio</a></li>
<li><i class = "fa fa-envelope"></i><a href="#" onclick="mailtoMe('<?=HTTP_ROOT?>')" >Contact</a></li>
</ul> </ul>
<?lua <?lua
if not HEADER.mobile then if not HEADER.mobile then
@ -152,7 +143,7 @@
</div> </div>
</div> </div>
<div id = "bottom"> <div id = "bottom">
Powered by antd server, (c) 2017 - <?=os.date("*t").year?> Dany LE Powered by antd server, (c) 2017 - <?=os.date("*t").year?> Xuan Sang LE
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,26 +0,0 @@
<div id="floating_container">
<div id="floating_btn_container">
<a id="floating_btn_close" href="#" ><i class="fa fa-close"></i>&nbsp;Close</a>
<a id="floating_btn_read_more" href="#"><i class="fa fa-chain"></i>&nbsp;Read more</a>
</div>
<div id="floating_content">
<p>
The graph shows this blog posts relationship in term of similarity.
Each node in the graph is a post, two nodes are connected by an edge if
they share some degree of similarity (weighted by edge thickness and edge distance).
A large edge thickness and/or short edge distance shows a strong similarity between
the two connected nodes.
</p>
<p>
Nodes are arranged by force which is modelled by content similarity.
The more similar the nodes content, the stronger the force between them.
Therefore, nodes that share similar topic will tend to group themself together in a cluster.
</p>
<p>
Navigate the blog by hovering the mouse on a node and following the node relationship
(edges) to find your interesting topic.
</p>
</div>
</div>

View File

@ -1,6 +1,3 @@
<?lua if not HEADER.mobile then ?>
<iframe width="980" height="410" src="https://mars.nasa.gov/layout/embed/send-your-name/future/certificate/?cn=792789419260" frameborder="0"></iframe>
<?lua end ?>
<?lua <?lua
local datas = posts local datas = posts
local class = "card" local class = "card"

6
ci/Makefile Normal file
View File

@ -0,0 +1,6 @@
copyfiles = router.lua scripts
main:
- mkdir -p $(BUILDDIR)
cp -rvf $(copyfiles) $(BUILDDIR)
- mkdir -p $(BUILDDIR)/log

82
ci/router.lua Normal file
View File

@ -0,0 +1,82 @@
-- the rewrite rule for the framework
-- should be something like this
-- ^\/apps\/+(.*)$ = /apps/router.lua?r=<1>&<query>
-- some global variables
function fail(msg)
std.json()
std.t(JSON.encode({error=msg}))
end
function result(obj)
std.json()
std.t(JSON.encode({result=obj, error=false}))
end
DIR_SEP = "/"
WWW_ROOT = __ROOT__.."/ci"
if HEADER.Host then
HTTP_ROOT= "https://"..HEADER.Host
else
HTTP_ROOT = "https://ci.iohub.dev"
end
-- class path: path.to.class
BASE_FRW = ""
-- class path: path.to.class
CONTROLLER_ROOT = BASE_FRW.."ci.controllers"
MODEL_ROOT = BASE_FRW.."ci.models"
-- file path: path/to/file
VIEW_ROOT = WWW_ROOT..DIR_SEP.."views"
LOG_ROOT = WWW_ROOT..DIR_SEP.."logs"
-- require needed library
require(BASE_FRW.."silk.api")
function NotfoundController:index(...)
local args = {...}
if #args == 0 then
fail("Unknown action")
return false
end
local action = args[1]
if action == "BuildController" then
if REQUEST.json then
local request = JSON.decodeString(REQUEST.json)
if request.ref and request.ref == "refs/heads/ci" then
local branch = "ci"
local repository = request.repository.name
local path = WWW_ROOT..DIR_SEP.."scripts"..DIR_SEP..repository..".sh"
if ulib.exists(path) then
result("Build action triggered, log file will soon be available at: https://ci.iohub.dev/log/"..repository.."_"..branch..".txt")
os.execute("at now -f "..path)
else
fail("No build script found")
end
else
result("This action is ignored by the CI")
end
else
fail("Unknow action parameters")
end
else
fail("Action not supported: "..action)
end
end
-- registry object store global variables
local REGISTRY = {}
-- set logging level
REGISTRY.logger = Logger:new{ levels = {INFO = false, ERROR = false, DEBUG = false}}
REGISTRY.layout = 'default'
REGISTRY.fileaccess = true
local router = Router:new{registry = REGISTRY}
REGISTRY.router = router
router:setPath(CONTROLLER_ROOT)
--router:route('edit', 'post/edit', "ALL" )
router:route('default', default_routes_dependencies )
router:delegate()

View File

@ -0,0 +1,31 @@
#! /bin/bash
BRANCH="ci"
PRJ="antd-web-apps"
DEST="/opt/www/htdocs"
REPO="https://github.com/lxsang/$PRJ.git"
if [ ! -z $1 ]; then
BRANCH="$1"
fi
{
echo "Build date: $(date)"
echo "Building $PRJ using branch $BRANCH..."
if [ -d "/tmp/ci/$PRJ" ]; then
echo "Clean up /tmp/ci/$PRJ"
rm -rf /tmp/ci/$PRJ
else
echo "Creating /tmp/ci/"
mkdir -p "/tmp/ci"
fi
cd /tmp/ci || (echo "Unable to change directory to /tmp/ci" && exit 1)
echo "Cloning $PRJ (branch $BRANCH) to /tmp/ci..."
git clone -b "$BRANCH" --single-branch --depth=1 "$REPO"
cd "$PRJ" || (echo "Unable to change directory to source code folder" && exit 1)
mkdir -p "$DEST"
BUILDDIR="$DEST" make
echo "Done!"
} 2>&1 | tee "/opt/www/htdocs/ci/log/${PRJ}_${BRANCH}.txt"

31
ci/scripts/antos.sh Normal file
View File

@ -0,0 +1,31 @@
#! /bin/bash
BRANCH="ci"
PRJ="antos"
DEST="/opt/www/htdocs/"
# /opt/www/htdocs
REPO="https://github.com/lxsang/$PRJ.git"
if [ ! -z $1 ]; then
BRANCH="$1"
fi
{
echo "Build date: $(date)"
echo "Building $PRJ using branch $BRANCH..."
if [ -d "/tmp/ci/$PRJ" ]; then
echo "Clean up /tmp/ci/$PRJ"
rm -rf /tmp/ci/$PRJ
else
echo "Creating /tmp/ci/"
mkdir -p "/tmp/ci"
fi
cd /tmp/ci || (echo "Unable to change directory to /tmp/ci" && exit 1)
echo "Cloning $PRJ (branch $BRANCH) to /tmp/ci..."
git clone -b "$BRANCH" --single-branch --depth=1 "$REPO"
cd "$PRJ" || (echo "Unable to change directory to source code folder" && exit 1)
npm i @types/jquery
mkdir -p "$DEST/os"
BUILDDIR="$DEST/os" make release
mkdir -p "$DEST/grs"
BUILDDIR="$DEST/grs" make standalone_tags
echo "Done!"
} 2>&1 | tee "/opt/www/htdocs/ci/log/${PRJ}_${BRANCH}.txt"

Binary file not shown.

View File

@ -1,4 +0,0 @@
html, body {
margin: 0;
height: 100%;
}

View File

@ -29,7 +29,6 @@ body {
width: 100%; width: 100%;
padding: 5px; padding: 5px;
border-top: 1px solid #878887; border-top: 1px solid #878887;
z-index: 22;
} }
#cover { #cover {
@ -39,14 +38,14 @@ body {
} }
#navbar { #navbar {
margin: 0 auto; margin: 0 auto;
/* max-width: 80%; */ max-width: 80%;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
flex-direction: row; flex-direction: row;
} }
#book { #book {
margin: 0 auto; margin: 0 auto;
/* max-width: 80%; */ max-width: 80%;
max-height: 100%; max-height: 100%;
display: block; display: block;
justify-content: flex-end; justify-content: flex-end;
@ -54,36 +53,10 @@ body {
text-align: justify; text-align: justify;
height: 100%; height: 100%;
} }
div.doc-toc-menu { div.doc-name {
text-align: left; text-align: left;
padding-top: 3px; padding-top: 3px;
} }
div.doc-toc-menu a {
text-decoration: none;
color: #c9c9c9;
}
div.doc-toc-legend::before
{
content: "\f0c9";
color: #2c2c2c;
width: 20px;
height: 25px;
margin-right: 3px;
font-family: "FontAwesome";
font-size: 18px;
}
div.doc-toc-menu a::before {
/* padding-top:13px; */
content: "\f02d";
color: #c9c9c9;
width: 20px;
height: 25px;
font-family: "FontAwesome";
font-size: 18px;
}
div.doc-name{
font-weight: bold;
}
div.doc-name a { div.doc-name a {
text-decoration: none; text-decoration: none;
color: #c9c9c9; color: #c9c9c9;
@ -92,14 +65,13 @@ div.doc-name a {
a.x-link, a.x-link,
a.x-link:hover { a.x-link:hover {
text-decoration: none; text-decoration: none;
color: #2c2c2c; color: #c9c9c9;
font-weight: bold; padding-left: 15px;
/* padding-left: 15px; */
padding-top: 7px; padding-top: 7px;
} }
a.x-link::before { a.x-link::before {
content: "\f08e"; content: "\f08e";
color: #2c2c2c; color: #c9c9c9;
width: 20px; width: 20px;
height: 25px; height: 25px;
font-family: "FontAwesome"; font-family: "FontAwesome";
@ -108,7 +80,7 @@ a.x-link::before {
div.doc-name a::before { div.doc-name a::before {
/* padding-top:13px; */ /* padding-top:13px; */
content: "\f015"; content: "\f015";
color: #2c2c2c; color: #c9c9c9;
width: 20px; width: 20px;
height: 25px; height: 25px;
font-family: "FontAwesome"; font-family: "FontAwesome";
@ -145,8 +117,8 @@ div.search-icon {
width: 35px; width: 35px;
} }
div.doc-toc { div.doc-toc {
max-width: 70%; width: 300px;
padding-right: 0; /* font-size: 11px; */
background-color: #e3e3e3; background-color: #e3e3e3;
color: #2c2c2c; color: #2c2c2c;
overflow: auto; overflow: auto;
@ -154,38 +126,8 @@ div.doc-toc {
top: 30px; top: 30px;
bottom: 30px; bottom: 30px;
border-right: 1px solid #c9c9c9; border-right: 1px solid #c9c9c9;
border-left: 1px solid #c9c9c9; padding-top: 10px;
padding-top: 0;
padding-bottom: 10px;
box-shadow: 0px 6px 3px -1px rgba(0,0,0,0.65);
z-index: 20;
} }
a.toc-active {
border: 1px solid #c9c9c9;
border-bottom: 0;
background-color: #e3e3e3;
outline: none;
display: block;
padding-left: 5px;
padding-right: 5px;
color: #2c2c2c !important;
}
a.toc-active::before{
color: #2c2c2c !important;
}
div.doc-toc-header{
display: block;
padding: 0px;
margin: 0px;
padding-left: 10px;
padding: 3px;
/* height: 24px; */
border-bottom: 1px solid #c9c9c9;
font-weight: bold;
}
div.doc-toc a { div.doc-toc a {
text-decoration: none; text-decoration: none;
color: #2c2c2c; color: #2c2c2c;
@ -195,7 +137,6 @@ div.doc-toc a {
list-style-type: none; list-style-type: none;
padding: 0; padding: 0;
padding-left: 10px; padding-left: 10px;
padding-right: 10px;
} }
div.doc-toc ul.nested { div.doc-toc ul.nested {
list-style-type: none; list-style-type: none;
@ -237,7 +178,7 @@ div.doc-toc a.highlight {
div.doc-content { div.doc-content {
display: block; display: block;
width: 100%; width: calc(100% - 300px);
float: right; float: right;
padding-left: 10px; padding-left: 10px;
} }

View File

@ -1,91 +0,0 @@
BaseController:subclass(
"OfficeController",
{
registry = {},
models = {}
}
)
local docType = function(ext)
if ext == "doc" or ext=="docx" or ext =="odt" then
return "word"
elseif ext == "csv" or ext =="ods" or ext== "xls" or ext == "xlsx" then
return "cell"
elseif ext == "odp" or ext == "ppt" or ext == "pptx" then
return "slide"
else
return "none"
end
end
function OfficeController:index(sid)
-- doing nothing here
require("sqlite")
local ospath = require("shared").ospath(sid)
local ext = ospath:match("^.+%.(.+)$")
local name = ospath:match("^.+/(.+)$")
if(ulib.exists(ospath)) then
local stat = ulib.file_stat(ospath)
if stat.error == nil then
local key = std.sha1(ospath..":"..stat.mtime)
self.template:set("shareid", sid)
self.template:set("ext", ext )
self.template:set("doctype", docType(ext) )
self.template:set("name", name)
self.template:set("key", key)
end
end
self:switchLayout("office")
return true
end
function OfficeController:shared(id)
require("sqlite")
require(BASE_FRW.."shared").get(id)
return false
end
function OfficeController:save(sid)
require("sqlite")
local ospath = require("shared").ospath(sid)
std.json()
local obj = {
error = false,
result = false
}
if not REQUEST.json then
obj.error = "Invalid request"
echo(JSON.encode(obj))
return false
end
local data = JSON.decodeString(REQUEST.json)
if not data then
obj.error = "Invalid request"
echo(JSON.encode(obj))
return false
end
if data.status == 2 then
local tmpfile = "/tmp/"..std.sha1(ospath)
local cmd = "curl -o "..tmpfile..' "'..data.url..'"'
os.execute(cmd)
-- move file to correct position
if ulib.exists(tmpfile) then
cmd = "mv "..tmpfile.." "..ospath
os.execute(cmd)
print("File "..ospath.." sync with remote")
else
obj.error = "Unable to sync file"
echo(JSON.encode(obj))
return false
end
end
obj.result = "OK"
echo(JSON.encode(obj))
return false
end
function OfficeController:actionnotfound(...)
self.template:setView("index")
return self:index(table.unpack({...}))
end

View File

@ -13,7 +13,7 @@ local pre_process_md = function(str, obj)
"%%-") "%%-")
if apath then if apath then
apath = apath:gsub(" ", "%%%%20") apath = apath:gsub(" ", "%%%%20")
--print(apath) print(apath)
content = content:gsub(pattern, "![](" .. HTTP_ROOT .. "/" .. content = content:gsub(pattern, "![](" .. HTTP_ROOT .. "/" ..
obj.name .. "/asset/" .. apath .. ")") obj.name .. "/asset/" .. apath .. ")")
end end

View File

@ -22,8 +22,6 @@ POST_LIMIT = 10
-- require needed library -- require needed library
require(BASE_FRW.."silk.api") require(BASE_FRW.."silk.api")
package.path = package.path..";"..__ROOT__.."/os/libs/?.lua"
POLICY.mimes["model/gltf-binary"] = true POLICY.mimes["model/gltf-binary"] = true
if REQUEST.r then if REQUEST.r then

View File

@ -76,12 +76,12 @@
<?lua <?lua
if prev_entry then if prev_entry then
echo("<a class = 'go_prev' href="..HTTP_ROOT..'/'..toc.controller..'/'..std.b64encode(prev_entry.path):gsub("=","")..'/'..prev_entry.name:gsub(" ", "_")..".md?show_toc=false".." >") echo("<a class = 'go_prev' href="..HTTP_ROOT..'/'..toc.controller..'/'..std.b64encode(prev_entry.path):gsub("=","")..'/'..prev_entry.name:gsub(" ", "_")..".md".." >")
echo(prev_entry.name) echo(prev_entry.name)
echo("</a>") echo("</a>")
end end
if next_entry then if next_entry then
echo("<a class = 'go_next' href="..HTTP_ROOT..'/'..toc.controller..'/'..std.b64encode(next_entry.path):gsub("=","")..'/'..next_entry.name:gsub(" ", "_")..".md?show_toc=false".." >") echo("<a class = 'go_next' href="..HTTP_ROOT..'/'..toc.controller..'/'..std.b64encode(next_entry.path):gsub("=","")..'/'..next_entry.name:gsub(" ", "_")..".md".." >")
echo(next_entry.name) echo(next_entry.name)
echo("</a>") echo("</a>")
end end
@ -108,12 +108,12 @@ The comment editor supports <b>Markdown</b> syntax. Your email is necessary to n
<div class = "pagenav"> <div class = "pagenav">
<?lua <?lua
if prev_entry then if prev_entry then
echo("<a class = 'go_prev' href="..HTTP_ROOT..'/'..toc.controller..'/'..std.b64encode(prev_entry.path):gsub("=","")..'/'..prev_entry.name:gsub(" ", "_")..".md?show_toc=false".." >") echo("<a class = 'go_prev' href="..HTTP_ROOT..'/'..toc.controller..'/'..std.b64encode(prev_entry.path):gsub("=","")..'/'..prev_entry.name:gsub(" ", "_")..".md".." >")
echo(prev_entry.name) echo(prev_entry.name)
echo("</a>") echo("</a>")
end end
if next_entry then if next_entry then
echo("<a class = 'go_next' href="..HTTP_ROOT..'/'..toc.controller..'/'..std.b64encode(next_entry.path):gsub("=","")..'/'..next_entry.name:gsub(" ", "_")..".md?show_toc=false".." >") echo("<a class = 'go_next' href="..HTTP_ROOT..'/'..toc.controller..'/'..std.b64encode(next_entry.path):gsub("=","")..'/'..next_entry.name:gsub(" ", "_")..".md".." >")
echo(next_entry.name) echo(next_entry.name)
echo("</a>") echo("</a>")
end end

View File

@ -3,20 +3,10 @@ local tocdata = __main__:get("toc")
local elinks = __main__:get("elinks") local elinks = __main__:get("elinks")
local has_3d = __main__:get("has_3d") local has_3d = __main__:get("has_3d")
local url = __main__:get("url") local url = __main__:get("url")
local show_toc_css = ''
if REQUEST.show_toc and REQUEST.show_toc == "false" then
show_toc_css = 'style="display:none;"'
end
local book_width_css='style="max-width:80%;"'
if HEADER.mobile then
book_width_css='style="max-width:95%;"'
end
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link <link
rel="stylesheet" rel="stylesheet"
type="text/css" type="text/css"
@ -25,7 +15,7 @@ end
rel="stylesheet" rel="stylesheet"
type="text/css" type="text/css"
href="<?=HTTP_ROOT?>/rst/katex/katex.min.css" /> href="<?=HTTP_ROOT?>/rst/katex/katex.min.css" />
<script src="<?=HTTP_ROOT?>/rst/gscripts/jquery-3.4.1.min.js"> </script> <script src="<?=HTTP_ROOT?>/rst/gscripts/jquery-3.2.1.min.js"> </script>
<?lua <?lua
if has_3d then if has_3d then
?> ?>
@ -87,20 +77,28 @@ end
</head> </head>
<body> <body>
<div id = "top"> <div id = "top">
<div id = "navbar" <?=book_width_css?>> <div id = "navbar">
<?lua <div class = "doc-name">
if tocdata then
?>
<div class = "doc-toc-menu">
<?lua if tocdata then ?> <?lua if tocdata then ?>
<a href ="#" id="btn_toc"> <a href ="<?=HTTP_ROOT..'/'..tocdata.controller..'/'?>">
<?=tocdata.data.name?> <?=tocdata.data.name?>
</a> </a>
<?lua end ?> <?lua end ?>
</div> </div>
<?lua
if elinks then
for k,v in ipairs(elinks) do
?>
<a class = "x-link" target="_blank" href ="<?=v.url?>">
<?=v.name?>
</a>
<?lua
end
end
if tocdata then
?>
<form id = "search_form" action="<?=HTTP_ROOT..'/'..tocdata.controller..'/search/'?>" method="get" class="search-form"> <form id = "search_form" action="<?=HTTP_ROOT..'/'..tocdata.controller..'/search/'?>" method="get" class="search-form">
<input id = "search_box" name="q" type = "text" class = "search-box"></input> <input id = "search_box" name="q" type = "text" class = "search-box"></input>
<input name="show_toc" type = "hidden" value="false"></input>
</form> </form>
<div class= "search-icon"></div> <div class= "search-icon"></div>
<?lua <?lua
@ -109,28 +107,11 @@ end
</div> </div>
</div> </div>
<div id = "cover"> <div id = "cover">
<div id = "book" <?=book_width_css?>> <div id = "book">
<?lua if tocdata then ?> <?lua
<div id="doc_toc" class = "doc-toc" <?=show_toc_css?> > if tocdata then
<div class = "doc-name doc-toc-header"> ?>
<a href ="<?=HTTP_ROOT..'/'..tocdata.controller..'/'?>"> <div class = "doc-toc">
<?=tocdata.data.name?>
</a>
</div>
<?lua
if elinks then
for k,v in ipairs(elinks) do
?>
<div class = "doc-toc-header">
<a class = "x-link" target="_blank" href ="<?=v.url?>">
<?=v.name?>
</a>
</div>
<?lua
end
end
?>
<div class = "doc-toc-header doc-toc-legend">Table of content</div>
<?lua <?lua
if toc then if toc then
toc:set("data", tocdata) toc:set("data", tocdata)
@ -138,7 +119,7 @@ end
end end
?> ?>
</div> </div>
<div class="doc-content markdown-body" id="doc_content"> <div class="doc-content markdown-body">
<?lua <?lua
if __main__ then if __main__ then
__main__:render() __main__:render()
@ -163,25 +144,7 @@ end
Powered by antd server, (c) 2019 - <?=os.date("*t").year?> Xuan Sang LE Powered by antd server, (c) 2019 - <?=os.date("*t").year?> Xuan Sang LE
</div> </div>
<script> <script>
const toc_class_toggle = () => {
if(!$("#doc_toc").is(":hidden"))
{
$("#btn_toc").attr("class", "toc-active");
}
else
{
$("#btn_toc").removeClass("toc-active");
}
};
window.addEventListener('load', (event) => { window.addEventListener('load', (event) => {
$("#btn_toc").click(function(){
$("#doc_toc").toggle();
toc_class_toggle();
});
$("#doc_content").click(function(){
$("#doc_toc").hide();
toc_class_toggle();
});
// tree view events // tree view events
var toggler = document.getElementsByClassName("caret"); var toggler = document.getElementsByClassName("caret");
var i; var i;
@ -228,7 +191,7 @@ end
end end
?> ?>
}); });
toc_class_toggle();
</script> </script>
</body> </body>
</html> </html>

View File

@ -1,67 +0,0 @@
<?lua
local shareid = __main__:get("shareid")
local ext = __main__:get("ext")
local doctype = __main__:get("doctype")
local name = __main__:get("name")
local key = __main__:get("key")
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link
rel="stylesheet"
type="text/css"
href="<?=HTTP_ROOT?>/assets/office.css" />
<!--meta name="viewport" content="width=device-width, initial-scale=1"-->
<script src="https://office.iohub.dev/web-apps/apps/api/documents/api.js"> </script>
<title>
<?lua
echo(name)
?>
</title>
<script type="text/javascript">
<?lua
if shareid and ext and doctype ~= "none" then
?>
window.onload = () => {
const editor = new DocsAPI.DocEditor("container", {
events: {
onAppReady: (e) => () => {},
//onRequestCreateNew: () => @newDocument(),
//onRequestSaveAs: (e) => @saveAs(e)
},
document: {
fileType: '<?=ext?>',
key: '<?=key?>',
title: '<?=name?>',
url: "https://doc.iohub.dev/office/shared/<?=shareid?>"
},
documentType: '<?=doctype?>',
editorConfig: {
//user: {
// id: @systemsetting.user.id.toString(),
// name: @systemsetting.user.username
//},
customization: {
compactHeader: false,
},
callbackUrl:"https://doc.iohub.dev/office/save/<?=shareid?>"
}
});
};
<?lua
end
?>
</script>
</head>
<body>
<div id = "container">
<?lua
if not shareid or not ext or doctype == "none" then
echo("<h1> Invalid document </h1>")
end
?>
</div>
</body>
</html>

View File

@ -33,7 +33,7 @@ function NotfoundController:index(...)
if ulib.exists(path) then if ulib.exists(path) then
std.header("text/plain") std.header("text/plain")
std.sendFile(path) std.f(path)
else else
self:error("No script found: "..path) self:error("No script found: "..path)
end end

View File

@ -2,32 +2,23 @@
set -e set -e
V_ANTD="1.0.6b"
V_LUA="0.5.2b"
#V_WTERM="1.0.0b"
V_TUNNEL="0.1.3b"
#V_CGI="1.0.0b"
V_PUBS="0.1.2a"
V_ANTOS=$(wget -qO- https://github.com/lxsang/antos/raw/1.2.1/release/latest)
mkdir -p /opt/www/htdocs mkdir -p /opt/www/htdocs
if [ "$1" = "full" ]; then if [ "$1" = "full" ]; then
# base server # base server
wget -O- https://get.iohub.dev/antd | bash -s "$V_ANTD" wget -O- https://get.bitdojo.dev/antd | bash -s "1.0.6b"
# base plugin # base plugin
wget -O- https://get.iohub.dev/antd_plugin | bash -s "lua-$V_LUA" wget -O- https://get.bitdojo.dev/antd_plugin | bash -s "lua-0.5.2b"
#wget -O- https://get.iohub.dev/antd_plugin | bash -s "wterm-$V_WTERM" wget -O- https://get.bitdojo.dev/antd_plugin | bash -s "wterm-1.0.0b"
wget -O- https://get.iohub.dev/antd_plugin | bash -s "tunnel-$V_TUNNEL" wget -O- https://get.bitdojo.dev/antd_plugin | bash -s "tunnel-0.1.0b"
#wget -O- https://get.iohub.dev/antd_plugin | bash -s "cgi-$V_CGI"
# install antos # install antos
[ -d /tmp/apub ] && rm -r /tmp/apub [ -d /tmp/apub ] && rm -r /tmp/apub
mkdir -p /tmp/apub mkdir -p /tmp/apub
cd /tmp/apub cd /tmp/apub
wget --no-check-certificate "https://github.com/lxsang/antd-tunnel-publishers/raw/master/dist/antd-publishers-$V_PUBS.tar.gz" wget --no-check-certificate "https://github.com/lxsang/antd-tunnel-publishers/raw/master/dist/antd-publishers-0.1.0a.tar.gz"
tar xvzf antd-publishers-$V_PUBS.tar.gz tar xvzf antd-publishers-0.1.0a.tar.gz
cd antd-publishers-$V_PUBS cd antd-publishers-0.1.0a
./configure --prefix=/opt/www && make && make install ./configure --prefix=/opt/www && make && make install
cd /opt/www cd /opt/www
@ -104,11 +95,11 @@ cd /opt/www/htdocs
wget --no-check-certificate "https://github.com/lxsang/antd-web-apps/raw/master/dist/antd_web_apps.tar.gz" wget --no-check-certificate "https://github.com/lxsang/antd-web-apps/raw/master/dist/antd_web_apps.tar.gz"
tar xvzf antd_web_apps.tar.gz tar xvzf antd_web_apps.tar.gz
rm antd_web_apps.tar.gz rm antd_web_apps.tar.gz
rm -r blog doc index.ls info talk get rm -r ci blog doc index.ls info talk get
cd /opt/www/htdocs/os cd /opt/www/htdocs/os
wget --no-check-certificate "https://github.com/lxsang/antos/raw/1.2.1/release/antos-$V_ANTOS.tar.gz" wget --no-check-certificate "https://github.com/lxsang/antos/raw/master/release/antos-1.1.2.tar.gz"
tar xvzf antos-$V_ANTOS.tar.gz tar xvzf antos-1.1.2.tar.gz
rm antos-$V_ANTOS.tar.gz rm antos-1.1.2.tar.gz
echo "Install done..." echo "Install done..."

View File

@ -19,7 +19,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<title>Hi, I'm <?=data.fullname?></title> <title>Hi, I'm Xuan Sang LE</title>
<meta charset="UTF-8"> <meta charset="UTF-8">
<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="grs/ubuntu-regular.css" /> <link rel="stylesheet" type="text/css" href="grs/ubuntu-regular.css" />
@ -39,7 +39,7 @@
<div id = "container" class="<?=mobilecls?>" > <div id = "container" class="<?=mobilecls?>" >
<img src = "grs/images/mrsang.png" ></img> <img src = "grs/images/mrsang.png" ></img>
<div id = "vcard"> <div id = "vcard">
<p class = "greeting">Hi, I'm <b><?=data.fullname?></b></p> <p class = "greeting">Hi, I'm <b>Xuan Sang LE</b></p>
<p class = "dedicate"> <p class = "dedicate">
<span class="fa fa-quote-left"></span> <span class="fa fa-quote-left"></span>
<span> <span>
@ -47,13 +47,12 @@
</span> </span>
<span class="fa fa-quote-right"></span> <span class="fa fa-quote-right"></span>
</p> </p>
<a href="https://blog.iohub.dev" class ="about">Read my blog</a> <a href="https://info.lxsang.me" class ="about">Find out more about me</a>
<a href="https://info.iohub.dev" class ="about">More about me</a>
</div> </div>
</div> </div>
</div> </div>
<div id = "bottom"> <div id = "bottom">
Powered by antd server, (c) 2017 - 2022 Dany LE Powered by antd server, (c) 2017 - 2018 Xuan Sang LE
</div> </div>
</div> </div>
</body> </body>

View File

@ -53,8 +53,7 @@ end
function IndexController:pdf(...) function IndexController:pdf(...)
local tmp_file = WWW_ROOT.."/cv_exported.pdf" local tmp_file = WWW_ROOT.."/cv_exported.pdf"
local cmd = "wkhtmltopdf "..HTTP_ROOT.."/"..self.registry.user.."/index/notoc "..tmp_file local cmd = "wkhtmltopdf "..HTTP_ROOT.."/"..self.registry.user.."/notoc "..tmp_file
print(cmd)
local r = os.execute(cmd) local r = os.execute(cmd)
if r then if r then
local mime = std.mimeOf(tmp_file) local mime = std.mimeOf(tmp_file)

View File

@ -15,25 +15,3 @@ function UserController:index(...)
self.template:set("data", data[1]) self.template:set("data", data[1])
return true return true
end end
function UserController:photo(...)
local data = self.user:findAll()
if not data or not data[1] then
self:error("Cannot fetch user info")
end
if(not data[1] or data[1].photo == "") then
self:error("User photo is not available")
end
local prefix = data[1].photo:match("%a+://")
local suffix = data[1].photo:gsub(prefix,"")
local path = string.format("/home/%s/", self.registry.user)..suffix
print(path)
if ulib.exists(path) then
local mime = std.mimeOf(path)
std.sendFile(path)
else
self:error("Asset file not found or access forbidden: "..path)
end
return false
end

View File

@ -26,7 +26,7 @@ require(BASE_FRW.."silk.api")
local REGISTRY = {} local REGISTRY = {}
-- set logging level -- set logging level
REGISTRY.logger = Logger:new{ levels = {INFO = false, ERROR = true, DEBUG = false}} REGISTRY.logger = Logger:new{ levels = {INFO = false, ERROR = true, DEBUG = false}}
REGISTRY.users_allowed = { phuong = true, mrsang = true, dany = true } REGISTRY.users_allowed = { phuong = true, mrsang = true }
REGISTRY.user = "mrsang" REGISTRY.user = "mrsang"
REGISTRY.db = DBHelper:new{db=REGISTRY.user} REGISTRY.db = DBHelper:new{db=REGISTRY.user}
REGISTRY.layout = 'default' REGISTRY.layout = 'default'
@ -67,7 +67,7 @@ function NotfoundController:index(...)
self:error("404: Controller "..args[1].." not found : "..args[2]) self:error("404: Controller "..args[1].." not found : "..args[2])
return return
end end
REQUEST.r = std.trim(REQUEST.r:gsub(user, ""), "/") REQUEST.r = "index/"..std.trim(REQUEST.r:gsub(user, ""), "/")
if REGISTRY.db then REGISTRY.db:close() end if REGISTRY.db then REGISTRY.db:close() end
REGISTRY.user = user REGISTRY.user = user
REGISTRY.db = DBHelper:new{db=REGISTRY.user} REGISTRY.db = DBHelper:new{db=REGISTRY.user}

View File

@ -31,7 +31,7 @@
} }
.layout div.container{ .layout div.container{
display: block; display: none;
} }
.layout div.container_active{ .layout div.container_active{
display: block; display: block;
@ -169,16 +169,4 @@ hr{
border-top: 1px solid #878887; border-top: 1px solid #878887;
padding: 0; padding: 0;
} }
img {max-width:100%} img {max-width:100%}
.header_container {
display: block;
width: 100%;
}
.header_container img {
float: left;
max-width: 150px;
margin-right: 10px;
margin-bottom: 20px;
display: block;
}

View File

@ -8,8 +8,7 @@
local active = "toc_active" local active = "toc_active"
for k, v in pairs(data) do for k, v in pairs(data) do
?> ?>
<!--onclick='switchTab("toc<?=v[2]?>", this)'--> <li class="<?=active?>"><a href=<?='"#toc'..v[2]..'"'?> onclick='switchTab("toc<?=v[2]?>", this)' ><?=v[1]?></a></li>
<li class="<?=active?>"><a href=<?='"#toc'..v[2]..'"'?> ><?=v[1]?></a></li>
<?lua <?lua
active = '' active = ''
end end

View File

@ -1,36 +1,27 @@
<div class="header_container"> <h1>
<?lua if data.photo and data.photo ~= "" and data.user ~= "mrsang" then ?> <span class="name"><?=data.fullname?></span>
<img src="/<?=data.user?>/user/photo"></img> <span class="cv">Curriculum Vitae</span>
<?lua end ?> </h1>
<h1> <p class="coordination">
<span class="name"><?=data.fullname?></span> <span class="fa fa-home"></span><?=data.address?></p>
<span class="cv">Curriculum Vitae</span> <p class="coordination">
</h1> <span class="fa fa-phone"></span>
<p class="coordination"> <span class="text"><?=data.Phone?></span>
<span class="fa fa-home"></span><?=data.address?></p> <span class="fa fa-envelope-o"></span>
<p class="coordination"> <span class="text"><?=data.email?></span>
<span class="fa fa-phone"></span> <span class="fa fa-globe"></span>
<span class="text"><?=data.Phone?></span> <span class="text"><a href ="<?=data.url?>"><?=data.url?></a></span>
<span class="fa fa-envelope-o"></span> <?lua
<span class="text"><?=data.email?></span> if not preview then
<br/> ?>
<span class="fa fa-globe"></span> <span class="fa fa-file-pdf-o"></span>
<span class="text"><a href ="<?=data.url?>"><?=data.url?></a></span> <span class="text"><a href ="<?=HTTP_ROOT?>/<?=data.user?>/pdf" target="_blank">Download</a></span>
<?lua <?lua
if not preview then end
?> ?>
<span class="fa fa-file-pdf-o"></span> </p>
<span class="text"><a href ="<?=HTTP_ROOT?>/<?=data.user?>/index/pdf" target="_blank">Download</a></span> <p class="shortbio">
<?lua <span class="fa fa-quote-left"></span>
end <span><?=data.shortbiblio?></span>
?> <span class="fa fa-quote-right"></span>
</p> </p>
<p class="shortbio">
<span class="fa fa-quote-left"></span>
<span><?=data.shortbiblio?></span>
<span class="fa fa-quote-right"></span>
</p>
</div>
<?lua if not HEADER.mobile and data.user == "mrsang" then ?>
<!--iframe width="770" height="330" src="https://mars.nasa.gov/layout/embed/send-your-name/future/certificate/?cn=792789419260" frameborder="0"></iframe-->
<?lua end ?>

View File

@ -1,48 +1,5 @@
{ {
"odt": { "odt": { "mime": "application/vnd.oasis.opendocument.text", "binary": true },
"mime": "application/vnd.oasis.opendocument.text",
"binary": true
},
"docx": {
"mime": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"binary": true
},
"doc": {
"mime": "application/msword",
"binary": true
},
"xls": {
"mime": "application/vnd.ms-excel",
"binary": true
},
"xlsx": {
"mime": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"binary": true
},
"ppt": {
"mime": "application/vnd.ms-powerpoint",
"binary": true
},
"pptx": {
"mime": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
"binary": true
},
"epub": {
"mime": "application/epub+zip",
"binary": true
},
"csv": {
"mime": "text/csv",
"binary": false
},
"ods": {
"mime": "application/vnd.oasis.opendocument.spreadsheet",
"binary": true
},
"odp": {
"mime": "application/vnd.oasis.opendocument.presentation",
"binary": true
},
"viz": { "viz": {
"mime": "text/vnd.graphviz", "mime": "text/vnd.graphviz",
"binary": false "binary": false
@ -51,7 +8,7 @@
"mime": "text/x-python", "mime": "text/x-python",
"binary": false "binary": false
}, },
"coffee": { "coffee":{
"mime": "text/vnd.coffeescript", "mime": "text/vnd.coffeescript",
"binary": false "binary": false
}, },
@ -66,13 +23,5 @@
"glb": { "glb": {
"mime": "model/gltf-binary", "mime": "model/gltf-binary",
"binary": true "binary": true
},
"ts":{
"mime": "text/x.typescript",
"binary": false
},
"map":{
"mime": "application/json",
"binary": false
} }
} }

View File

@ -98,7 +98,6 @@ function SystemController:application(...)
end end
function SystemController:apigateway(...) function SystemController:apigateway(...)
local args={...}
local use_ws = false local use_ws = false
if REQUEST and REQUEST.ws == "1" then if REQUEST and REQUEST.ws == "1" then
-- override the global echo command -- override the global echo command
@ -132,12 +131,10 @@ function SystemController:apigateway(...)
r, e = loadfile(ospath) r, e = loadfile(ospath)
if r then if r then
local status, result = pcall(r, data.parameters) local status, result = pcall(r, data.parameters)
if result then if (status) then
if (status) then echo(JSON.encode(result))
echo(JSON.encode(result)) else
else echo(result)
echo(result)
end
end end
else else
echo(e) echo(e)
@ -159,9 +156,7 @@ function SystemController:apigateway(...)
if use_ws then if use_ws then
if std.ws.enable() then if std.ws.enable() then
-- read header -- read header
local header = nil local header = std.ws.header()
-- wait until we receive request
while(not header) do header = std.ws.header() end
if header then if header then
if header.mask == 0 then if header.mask == 0 then
print("Data is not masked") print("Data is not masked")
@ -188,26 +183,10 @@ function SystemController:apigateway(...)
print("Web socket is not available.") print("Web socket is not available.")
end end
else else
if REQUEST.path then if REQUEST.json then
exec_with_user_priv(REQUEST)
elseif REQUEST.json then
data = JSON.decodeString(REQUEST.json) data = JSON.decodeString(REQUEST.json)
--std.json()
exec_with_user_priv(data) exec_with_user_priv(data)
elseif args and #args > 0 then
-- data is encoded in url safe base64
local encoded = args[1]:gsub('_', '/'):gsub('-', '+')
if #encoded % 4 == 2 then
encoded = encoded.."=="
elseif #encoded %4 == 3 then
encoded = encoded.."="
end
local decoded = std.b64decode(encoded)
data = JSON.decodeString(bytes.__tostring(decoded))
if data and data.path then
exec_with_user_priv(data)
else
fail("Unknown request")
end
else else
fail("Unkown request") fail("Unkown request")
end end

View File

@ -191,7 +191,6 @@ function VFSController:upload(...)
if r then if r then
result(r) result(r)
else else
self:error(m)
fail(m) fail(m)
end end
else else

View File

@ -1,13 +1,10 @@
require("sqlite") require("sqlite")
local TUNNEL_KEYCHAIN = "/opt/www/tmp/channels/antunnel_keychain"
function fail(msg) function fail(msg)
std.custom_header("Connection","close")
std.json() std.json()
std.t(JSON.encode({error=msg})) std.t(JSON.encode({error=msg}))
end end
function result(obj) function result(obj)
std.custom_header("Connection","close")
std.json() std.json()
std.t(JSON.encode({result=obj, error=false})) std.t(JSON.encode({result=obj, error=false}))
end end
@ -29,33 +26,17 @@ function sysdb()
end end
function is_auth() function is_auth()
local sessionid = nil if SESSION.sessionid == nil or SESSION.sessionid == '0' then return false end
if SESSION.sessionid and SESSION.sessionid ~= '0' then
sessionid = SESSION.sessionid
-- should be used only by API call
elseif REQUEST.sessionid and REQUEST.sessionid ~= '0' then
sessionid = REQUEST.sessionid
elseif REQUEST.access_token and REQUEST.access_token ~= '0' then
sessionid = REQUEST.access_token
end
if sessionid == nil then
return false
end
-- query session id from database -- query session id from database
local db = sysdb() local db = sysdb()
if db == nil then return false end if db == nil then return false end
local cond = {exp= {["="] = { sessionid = sessionid }}} local cond = {exp= {["="] = { sessionid = SESSION.sessionid }}}
local data = db:find(cond) local data = db:find(cond)
--print(JSON.encode(data)) --print(JSON.encode(data))
db:close() db:close()
if data == nil or data[1] == nil then return die("No user data found") end if data == nil or data[1] == nil then return die("No user data found") end
-- next time check the stamp -- next time check the stamp
SESSION.user = data[1].username SESSION.user = data[1].username
local f = io.open(TUNNEL_KEYCHAIN, "w")
if f then
f:write(sessionid..SESSION.user)
f:close()
end
return true return true
end end
@ -63,4 +44,4 @@ function auth_or_die(msg)
if(is_auth() == false) then if(is_auth() == false) then
die(msg) die(msg)
end end
end end

View File

@ -113,7 +113,7 @@ vfs.write = function(path,data)
local uid = ulib.uid(SESSION.user) local uid = ulib.uid(SESSION.user)
-- --
if data ~= "" then if data ~= "" then
local header = string.match(data, "^data%:[%w%.-%+]+%/[%w%.-%+]+;base64,") local header = string.match(data, "^data%:[%w%.-]+%/[%w%.-]+;base64,")
if header ~= nil then if header ~= nil then
local b64data = string.gsub(data, utils.escape_pattern(header),"") local b64data = string.gsub(data, utils.escape_pattern(header),"")
local barr = std.b64decode(b64data) local barr = std.b64decode(b64data)
@ -141,23 +141,13 @@ vfs.write = function(path,data)
end end
vfs.upload = function(path) vfs.upload = function(path)
if(not path) then
return false, "Unknown upload destination, abort!"
end
local r,m = vfs.checkperm(path,"write") local r,m = vfs.checkperm(path,"write")
if(r) then if(r) then
local uid = ulib.uid(SESSION.user) local uid = ulib.uid(SESSION.user)
local index = 0 local file = m.."/"..REQUEST["upload.file"]
while(REQUEST["upload-"..index..".tmp"] ~= nil) do ulib.move(REQUEST["upload.tmp"], file)
local file = m.."/"..REQUEST["upload-"..index..".file"] ulib.chown(file, uid.id, uid.gid)
ulib.move(REQUEST["upload-"..index..".tmp"], file) return true, nil
ulib.chown(file, uid.id, uid.gid)
index = index + 1
end
if(index == 0) then
return false, "No file is uploaded"
end
return true, index
else else
return r,m return r,m
end end
@ -166,14 +156,14 @@ end
vfs.checkperm = function(path, right) vfs.checkperm = function(path, right)
local osfile = vfs.ospath(path) local osfile = vfs.ospath(path)
local perm = vfs.perm(osfile) local perm = vfs.perm(osfile)
--print(osfile) print(osfile)
if not ulib.exists(osfile) then if not ulib.exists(osfile) then
return false,"Resource does not exist" return false,"Resource does not exist"
end end
-- check if user own the file -- check if user own the file
if perm ~= nil then if perm ~= nil then
if perm[right] == true then if perm[right] == true then
--print("Permission granted") print("Permission granted")
return true,osfile return true,osfile
else else
print("Permission denie") print("Permission denie")
@ -192,13 +182,13 @@ vfs.perm = function(file)
if uid ~= nil and st ~= nil and st.perm ~= nil then if uid ~= nil and st ~= nil and st.perm ~= nil then
--print(JSON.encode({uid, st})) --print(JSON.encode({uid, st}))
if(uid.id == st.uid) then -- the user owned the file if(uid.id == st.uid) then -- the user owned the file
--print("file belong to user") print("file belong to user")
return st.perm.owner return st.perm.owner
elseif uid.groups and uid.groups[st.gid] then elseif uid.groups and uid.groups[st.gid] then
--print("User belong to this group") print("User belong to this group")
return st.perm.group return st.perm.group
else else
--print("User belong to other") print("User belong to other")
return st.perm.other return st.perm.other
end end
else else