mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-02 02:36:24 -07:00
Add non-RPC changes to master
This commit is contained in:
parent
6e40ae8a16
commit
b3a57f50a8
20 changed files with 360 additions and 247 deletions
8
build.py
8
build.py
|
@ -27,8 +27,8 @@ release_files = (
|
|||
"html/favicon.png",
|
||||
"html/firstrun.html",
|
||||
"html/js/",
|
||||
"sample-configs/",
|
||||
"sample-plugins/",
|
||||
"examples/configs/",
|
||||
"examples/plugins/",
|
||||
"templates/",
|
||||
"sql/initdb_master.sql",
|
||||
"sql/initdb_mysql.sql",
|
||||
|
@ -380,12 +380,12 @@ def install(prefix="/usr", document_root="/srv/gochan", symlinks=False, js_only=
|
|||
|
||||
print(
|
||||
"gochan was successfully installed. If you haven't already, you should copy\n",
|
||||
"sample-configs/gochan.example.json to /etc/gochan/gochan.json (modify as needed)\n",
|
||||
"examples/configs/gochan.example.json to /etc/gochan/gochan.json (modify as needed)\n",
|
||||
"You may also need to go to https://yourgochansite/manage/rebuildall to rebuild the javascript config")
|
||||
if gcos == "linux":
|
||||
print(
|
||||
"If your Linux distribution has systemd, you will also need to run the following commands:\n",
|
||||
"cp sample-configs/gochan-[mysql|postgresql|sqlite3].service /lib/systemd/system/gochan.service\n",
|
||||
"cp examples/configs/gochan-[mysql|postgresql|sqlite3].service /lib/systemd/system/gochan.service\n",
|
||||
"systemctl daemon-reload\n",
|
||||
"systemctl enable gochan.service\n",
|
||||
"systemctl start gochan.service")
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
local string = require("string")
|
||||
local events = require("events")
|
||||
local gcsql = require("gcsql")
|
||||
|
||||
local recognized_tlds = {"com", "net", "org", "edu", "gov", "us", "uk"}
|
||||
|
||||
local function is_new_poster(ip)
|
||||
rows, err = db_query("SELECT COUNT(*) FROM DBPREFIXposts WHERE ip = ?", {ip})
|
||||
rows, err = gcsql.query_rows("SELECT COUNT(*) FROM DBPREFIXposts WHERE ip = ?", {ip})
|
||||
if(err ~= nil) then
|
||||
return true, err
|
||||
end
|
||||
|
@ -11,7 +13,7 @@ local function is_new_poster(ip)
|
|||
is_new = true
|
||||
while rows:Next() do
|
||||
rows_table = {}
|
||||
err = db_scan_rows(rows, rows_table)
|
||||
err = gcsql.scan_rows(rows, rows_table)
|
||||
if(err ~= nil) then
|
||||
rows:Close()
|
||||
return true, err
|
||||
|
@ -26,7 +28,7 @@ local function is_new_poster(ip)
|
|||
end
|
||||
|
||||
|
||||
event_register({"message-pre-format"}, function(tr, post)
|
||||
events.register_event({"message-pre-format"}, function(tr, post)
|
||||
is_new, err = is_new_poster(post.IP)
|
||||
if(err ~= nil) then
|
||||
error_log(err:Error())
|
|
@ -1,11 +1,14 @@
|
|||
-- requires ghostscript to be installed
|
||||
|
||||
local config = require("config")
|
||||
local os = require("os")
|
||||
local uploads = require("uploads")
|
||||
|
||||
local cmd = "gs -q -sDEVICE=jpeg -dLastPage=1 -dNOPAUSE -r720 -g%dx%d -dPDFFitPage -dFIXEDMEDIA -dCompatibilityLevel=1.4 -o %q - < %q" -- width, height outpath, inpath
|
||||
|
||||
register_upload_handler(".pdf", function(upload, post, board, filePath, thumbPath, catalogThumbPath, infoEv, accessEv, errEv)
|
||||
uploads.register_handler(".pdf", function(upload, post, board, filePath, thumbPath, catalogThumbPath, infoEv, accessEv, errEv)
|
||||
-- width, height = get_pdf_dimensions(filePath)
|
||||
local boardcfg = board_config(board)
|
||||
local boardcfg = config.board_config(board)
|
||||
upload.ThumbnailWidth = boardcfg.ThumbWidthReply
|
||||
upload.ThumbnailHeight = boardcfg.ThumbHeightReply
|
||||
if (post.IsTopPost) then
|
||||
|
@ -24,4 +27,4 @@ register_upload_handler(".pdf", function(upload, post, board, filePath, thumbPat
|
|||
|
||||
return nil
|
||||
end)
|
||||
set_thumbnail_ext(".pdf", ".jpg")
|
||||
uploads.set_thumbnail_ext(".pdf", ".jpg")
|
|
@ -1,7 +1,8 @@
|
|||
-- testing manage page registering from Lua plugins
|
||||
local strings = require("strings")
|
||||
local manage = require("manage")
|
||||
|
||||
register_manage_page("mgmtplugintest",
|
||||
manage.register_manage_page("mgmtplugintest",
|
||||
"Staff Plugin Testing",
|
||||
3, 1,
|
||||
function(writer, request, staff, wantsJSON, infoEv, errEv)
|
||||
|
@ -12,7 +13,7 @@ register_manage_page("mgmtplugintest",
|
|||
|
||||
|
||||
-- testing template parsing from Lua plugins
|
||||
register_manage_page("templateplugintest",
|
||||
manage.register_manage_page("templateplugintest",
|
||||
"Template Plugin Testing",
|
||||
3, 0,
|
||||
function(writer, request, staff, wantsJSON, infoEv, errEv)
|
21
examples/plugins/require_distinct_filenames.lua
Normal file
21
examples/plugins/require_distinct_filenames.lua
Normal file
|
@ -0,0 +1,21 @@
|
|||
local events = require("events")
|
||||
local gcsql = require("gcsql")
|
||||
|
||||
events.register_event({"incoming-upload"}, function(tr, upload)
|
||||
rows, err = gcsql.query_rows("SELECT COUNT(*) FROM DBPREFIXfiles WHERE original_filename = ?", {upload.OriginalFilename})
|
||||
if(err ~= nil) then
|
||||
return err:Error()
|
||||
end
|
||||
while rows:Next() do
|
||||
rows_table = {}
|
||||
err = gcsql.scan_rows(rows, rows_table)
|
||||
if(err ~= nil) then
|
||||
rows:Close()
|
||||
return err:Error()
|
||||
end
|
||||
if(rows_table["COUNT(*)"] > 0) then
|
||||
rows:Close()
|
||||
return "a file with that filename has already been uploaded"
|
||||
end
|
||||
end
|
||||
end)
|
|
@ -1,6 +1,9 @@
|
|||
event_register({"db-initialized"}, function(tr)
|
||||
local events = require('events')
|
||||
local gcsql = require("gcsql")
|
||||
|
||||
events.register_event({"db-initialized"}, function(tr)
|
||||
print("Testing SELECT query from Lua plugin")
|
||||
rows, err = db_query("SELECT id, dir, title FROM DBPREFIXboards where id > ?", {1})
|
||||
rows, err = gcsql.query_rows("SELECT id, dir, title FROM DBPREFIXboards where id > ?", {1})
|
||||
if(err ~= nil) then
|
||||
print(err:Error())
|
||||
return
|
||||
|
@ -9,7 +12,7 @@ event_register({"db-initialized"}, function(tr)
|
|||
print("Boards (id > 1):")
|
||||
while rows:Next() do
|
||||
rows_table = {}
|
||||
err = db_scan_rows(rows, rows_table)
|
||||
err = gcsql.scan_rows(rows, rows_table)
|
||||
if(err ~= nil) then
|
||||
print(err:Error())
|
||||
rows:Close()
|
||||
|
@ -21,14 +24,14 @@ event_register({"db-initialized"}, function(tr)
|
|||
rows:Close()
|
||||
|
||||
print("Testing SELECT COUNT(*) query from Lua plugin")
|
||||
rows, err = db_query("SELECT COUNT(*) FROM DBPREFIXstaff WHERE id > ?", {1})
|
||||
rows, err = gcsql.query_rows("SELECT COUNT(*) FROM DBPREFIXstaff WHERE id > ?", {1})
|
||||
if(err ~= nil) then
|
||||
print(err:Error())
|
||||
return
|
||||
end
|
||||
while rows:Next() do
|
||||
rows_table = {}
|
||||
err = db_scan_rows(rows, rows_table)
|
||||
err = gcsql.scan_rows(rows, rows_table)
|
||||
if(err ~= nil) then
|
||||
print(err:Error())
|
||||
rows:Close()
|
|
@ -1,5 +1,7 @@
|
|||
local events = require("events")
|
||||
|
||||
-- a simple demonstration of using the event system from a Lua plugin to modify an incoming upload
|
||||
event_register({"incoming-upload"}, function(tr, upload)
|
||||
events.register_event({"incoming-upload"}, function(tr, upload)
|
||||
print("Received upload, making the original filename upper case")
|
||||
before = upload.OriginalFilename
|
||||
upload.OriginalFilename = string.upper(upload.OriginalFilename)
|
|
@ -36,7 +36,7 @@ var (
|
|||
func initLua() {
|
||||
if lState == nil {
|
||||
lState = lua.NewState()
|
||||
registerLuaFunctions()
|
||||
preloadLua()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,179 +123,260 @@ func luaEventRegisterHandlerAdapter(l *lua.LState, fn *lua.LFunction) events.Eve
|
|||
}
|
||||
}
|
||||
|
||||
func registerLuaFunctions() {
|
||||
func preloadLua() {
|
||||
luaFilePath.Preload(lState)
|
||||
luaStrings.Preload(lState)
|
||||
lState.Register("info_log", createLuaLogFunc("info"))
|
||||
lState.Register("warn_log", createLuaLogFunc("warn"))
|
||||
lState.Register("error_log", createLuaLogFunc("error"))
|
||||
|
||||
lState.Register("register_upload_handler", func(l *lua.LState) int {
|
||||
ext := l.CheckString(1)
|
||||
handler := l.CheckFunction(2)
|
||||
uploads.RegisterUploadHandler(ext, func(upload *gcsql.Upload, post *gcsql.Post, board, filePath, thumbPath, catalogThumbPath string, infoEv, accessEv, errEv *zerolog.Event) error {
|
||||
l.CallByParam(lua.P{
|
||||
Fn: handler,
|
||||
NRet: 1,
|
||||
// Protect: true,
|
||||
}, luar.New(l, upload), luar.New(l, post), lua.LString(board), lua.LString(filePath), lua.LString(thumbPath), lua.LString(catalogThumbPath))
|
||||
|
||||
errRet := l.CheckAny(-1)
|
||||
if errRet != nil && errRet.Type() != lua.LTNil {
|
||||
return errors.New(errRet.String())
|
||||
}
|
||||
return nil
|
||||
lState.PreloadModule("config", func(l *lua.LState) int {
|
||||
t := l.NewTable()
|
||||
l.SetFuncs(t, map[string]lua.LGFunction{
|
||||
"system_critical_config": func(l *lua.LState) int {
|
||||
l.Push(luar.New(l, config.GetSystemCriticalConfig()))
|
||||
return 1
|
||||
},
|
||||
"site_config": func(l *lua.LState) int {
|
||||
l.Push(luar.New(l, config.GetSiteConfig()))
|
||||
return 1
|
||||
},
|
||||
"board_config": func(l *lua.LState) int {
|
||||
numArgs := l.GetTop()
|
||||
board := ""
|
||||
if numArgs > 0 {
|
||||
board = l.CheckString(1)
|
||||
}
|
||||
l.Push(luar.New(l, config.GetBoardConfig(board)))
|
||||
return 1
|
||||
},
|
||||
})
|
||||
return 0
|
||||
})
|
||||
lState.Register("get_thumbnail_ext", func(l *lua.LState) int {
|
||||
fileExt := l.CheckString(1)
|
||||
l.Push(luar.New(l, uploads.GetThumbnailExtension(fileExt)))
|
||||
return 1
|
||||
})
|
||||
lState.Register("set_thumbnail_ext", func(l *lua.LState) int {
|
||||
fileExt := l.CheckString(1)
|
||||
thumbExt := l.CheckString(2)
|
||||
uploads.SetThumbnailExtension(fileExt, thumbExt)
|
||||
return 0
|
||||
})
|
||||
|
||||
lState.Register("system_critical_config", func(l *lua.LState) int {
|
||||
l.Push(luar.New(l, config.GetSystemCriticalConfig()))
|
||||
return 1
|
||||
})
|
||||
lState.Register("site_config", func(l *lua.LState) int {
|
||||
l.Push(luar.New(l, config.GetSiteConfig()))
|
||||
return 1
|
||||
})
|
||||
lState.Register("board_config", func(l *lua.LState) int {
|
||||
l.Push(luar.New(l, config.GetBoardConfig(l.CheckString(1))))
|
||||
l.Push(t)
|
||||
return 1
|
||||
})
|
||||
|
||||
lState.Register("db_query", func(l *lua.LState) int {
|
||||
queryStr := l.CheckString(1)
|
||||
queryArgsL := l.CheckAny(2)
|
||||
|
||||
var queryArgs []any
|
||||
if queryArgsL.Type() != lua.LTNil {
|
||||
table := queryArgsL.(*lua.LTable)
|
||||
table.ForEach(func(_ lua.LValue, val lua.LValue) {
|
||||
arg := lvalueToInterface(l, val)
|
||||
queryArgs = append(queryArgs, arg)
|
||||
})
|
||||
}
|
||||
|
||||
rows, err := gcsql.QuerySQL(queryStr, queryArgs...)
|
||||
|
||||
l.Push(luar.New(l, rows))
|
||||
l.Push(luar.New(l, err))
|
||||
return 2
|
||||
})
|
||||
|
||||
lState.Register("db_scan_rows", func(l *lua.LState) int {
|
||||
rows := l.CheckUserData(1).Value.(*sql.Rows)
|
||||
table := l.CheckTable(2)
|
||||
var scanners []any
|
||||
colNames, err := rows.Columns()
|
||||
if err != nil {
|
||||
l.Push(luar.New(l, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
for range colNames {
|
||||
scanners = append(scanners, &lvalueScanner{state: l})
|
||||
}
|
||||
|
||||
if err = rows.Scan(scanners...); err != nil {
|
||||
l.Push(luar.New(l, err))
|
||||
return 1
|
||||
}
|
||||
for i, name := range colNames {
|
||||
table.RawSetString(name, scanners[i].(*lvalueScanner).val)
|
||||
}
|
||||
l.Push(lua.LNil)
|
||||
return 1
|
||||
})
|
||||
|
||||
lState.Register("event_register", func(l *lua.LState) int {
|
||||
table := l.CheckTable(-2)
|
||||
var triggers []string
|
||||
table.ForEach(func(i, val lua.LValue) {
|
||||
triggers = append(triggers, val.String())
|
||||
lState.PreloadModule("events", func(l *lua.LState) int {
|
||||
t := l.NewTable()
|
||||
l.SetFuncs(t, map[string]lua.LGFunction{
|
||||
"register_event": func(l *lua.LState) int {
|
||||
table := l.CheckTable(-2)
|
||||
var triggers []string
|
||||
table.ForEach(func(i, val lua.LValue) {
|
||||
triggers = append(triggers, val.String())
|
||||
})
|
||||
fn := l.CheckFunction(-1)
|
||||
events.RegisterEvent(triggers, luaEventRegisterHandlerAdapter(l, fn))
|
||||
return 0
|
||||
},
|
||||
"trigger_event": func(l *lua.LState) int {
|
||||
trigger := l.CheckString(1)
|
||||
numArgs := l.GetTop()
|
||||
var data []interface{}
|
||||
for i := 2; i <= numArgs; i++ {
|
||||
v := l.CheckAny(i)
|
||||
data = append(data, lvalueToInterface(l, v))
|
||||
}
|
||||
events.TriggerEvent(trigger, data...)
|
||||
return 0
|
||||
},
|
||||
})
|
||||
fn := l.CheckFunction(-1)
|
||||
events.RegisterEvent(triggers, luaEventRegisterHandlerAdapter(l, fn))
|
||||
return 0
|
||||
})
|
||||
lState.Register("event_trigger", func(l *lua.LState) int {
|
||||
trigger := l.CheckString(1)
|
||||
numArgs := l.GetTop()
|
||||
var data []interface{}
|
||||
for i := 2; i <= numArgs; i++ {
|
||||
v := l.CheckAny(i)
|
||||
data = append(data, lvalueToInterface(l, v))
|
||||
}
|
||||
events.TriggerEvent(trigger, data...)
|
||||
return 0
|
||||
})
|
||||
|
||||
lState.Register("register_manage_page", func(l *lua.LState) int {
|
||||
actionID := l.CheckString(1)
|
||||
actionTitle := l.CheckString(2)
|
||||
actionPerms := l.CheckInt(3)
|
||||
actionJSON := l.CheckInt(4)
|
||||
fn := l.CheckFunction(5)
|
||||
actionHandler := func(writer http.ResponseWriter, request *http.Request, staff *gcsql.Staff, wantsJSON bool, infoEv *zerolog.Event, errEv *zerolog.Event) (output interface{}, err error) {
|
||||
if err = l.CallByParam(lua.P{
|
||||
Fn: fn,
|
||||
NRet: 2,
|
||||
// Protect: true,
|
||||
}, luar.New(l, writer), luar.New(l, request), luar.New(l, staff), lua.LBool(wantsJSON), luar.New(l, infoEv), luar.New(l, errEv)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
out := lua.LVAsString(l.Get(-2))
|
||||
errStr := lua.LVAsString(l.Get(-1))
|
||||
if errStr != "" {
|
||||
err = errors.New(errStr)
|
||||
}
|
||||
return out, err
|
||||
}
|
||||
manage.RegisterManagePage(actionID, actionTitle, actionPerms, actionJSON, actionHandler)
|
||||
return 0
|
||||
})
|
||||
lState.Register("load_template", func(l *lua.LState) int {
|
||||
var tmplPaths []string
|
||||
for i := 0; i < l.GetTop(); i++ {
|
||||
tmplPaths = append(tmplPaths, l.CheckString(i+1))
|
||||
}
|
||||
tmpl, err := gctemplates.LoadTemplate(tmplPaths...)
|
||||
l.Push(luar.New(l, tmpl))
|
||||
l.Push(luar.New(l, err))
|
||||
return 2
|
||||
})
|
||||
lState.Register("parse_template", func(l *lua.LState) int {
|
||||
tmplName := l.CheckString(1)
|
||||
tmplData := l.CheckString(2)
|
||||
tmpl, err := gctemplates.ParseTemplate(tmplName, tmplData)
|
||||
l.Push(luar.New(l, tmpl))
|
||||
l.Push(luar.New(l, err))
|
||||
return 2
|
||||
})
|
||||
lState.Register("minify_template", func(l *lua.LState) int {
|
||||
tmplUD := l.CheckUserData(1)
|
||||
tmpl := tmplUD.Value.(*template.Template)
|
||||
dataTable := l.CheckTable(2)
|
||||
data := map[string]interface{}{}
|
||||
dataTable.ForEach(func(l1, l2 lua.LValue) {
|
||||
data[l1.String()] = lvalueToInterface(l, l2)
|
||||
})
|
||||
writer := l.CheckUserData(3).Value.(io.Writer)
|
||||
mediaType := l.CheckString(4)
|
||||
err := serverutil.MinifyTemplate(tmpl, data, writer, mediaType)
|
||||
l.Push(luar.New(l, err))
|
||||
l.Push(t)
|
||||
return 1
|
||||
})
|
||||
|
||||
lState.PreloadModule("gclog", func(l *lua.LState) int {
|
||||
t := l.NewTable()
|
||||
l.SetFuncs(t, map[string]lua.LGFunction{
|
||||
"info_log": createLuaLogFunc("info"),
|
||||
"warn_log": createLuaLogFunc("warn"),
|
||||
"error_log": createLuaLogFunc("error"),
|
||||
})
|
||||
l.Push(t)
|
||||
return 1
|
||||
})
|
||||
|
||||
lState.PreloadModule("gcsql", func(l *lua.LState) int {
|
||||
t := l.NewTable()
|
||||
l.SetFuncs(t, map[string]lua.LGFunction{
|
||||
"query_rows": func(l *lua.LState) int {
|
||||
queryStr := l.CheckString(1)
|
||||
queryArgsL := l.CheckAny(2)
|
||||
|
||||
var queryArgs []any
|
||||
if queryArgsL.Type() != lua.LTNil {
|
||||
table := queryArgsL.(*lua.LTable)
|
||||
table.ForEach(func(_ lua.LValue, val lua.LValue) {
|
||||
arg := lvalueToInterface(l, val)
|
||||
queryArgs = append(queryArgs, arg)
|
||||
})
|
||||
}
|
||||
|
||||
rows, err := gcsql.QuerySQL(queryStr, queryArgs...)
|
||||
|
||||
l.Push(luar.New(l, rows))
|
||||
l.Push(luar.New(l, err))
|
||||
return 2
|
||||
|
||||
},
|
||||
"execute_sql": func(l *lua.LState) int {
|
||||
execStr := l.CheckString(1)
|
||||
execArgsL := l.CheckAny(2)
|
||||
var execArgs []any
|
||||
if execArgsL.Type() != lua.LTNil {
|
||||
table := execArgsL.(*lua.LTable)
|
||||
table.ForEach(func(_, val lua.LValue) {
|
||||
arg := lvalueToInterface(l, val)
|
||||
execArgs = append(execArgs, arg)
|
||||
})
|
||||
}
|
||||
result, err := gcsql.ExecSQL(execStr)
|
||||
|
||||
l.Push(luar.New(l, result))
|
||||
l.Push(luar.New(l, err))
|
||||
return 2
|
||||
},
|
||||
"scan_rows": func(l *lua.LState) int {
|
||||
rows := l.CheckUserData(1).Value.(*sql.Rows)
|
||||
table := l.CheckTable(2)
|
||||
var scanners []any
|
||||
colNames, err := rows.Columns()
|
||||
if err != nil {
|
||||
l.Push(luar.New(l, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
for range colNames {
|
||||
scanners = append(scanners, &lvalueScanner{state: l})
|
||||
}
|
||||
|
||||
if err = rows.Scan(scanners...); err != nil {
|
||||
l.Push(luar.New(l, err))
|
||||
return 1
|
||||
}
|
||||
for i, name := range colNames {
|
||||
table.RawSetString(name, scanners[i].(*lvalueScanner).val)
|
||||
}
|
||||
l.Push(lua.LNil)
|
||||
return 1
|
||||
},
|
||||
})
|
||||
|
||||
l.Push(t)
|
||||
return 1
|
||||
})
|
||||
|
||||
lState.PreloadModule("gctemplates", func(l *lua.LState) int {
|
||||
t := l.NewTable()
|
||||
|
||||
l.SetFuncs(t, map[string]lua.LGFunction{
|
||||
"load_template": func(l *lua.LState) int {
|
||||
var tmplPaths []string
|
||||
for i := 0; i < l.GetTop(); i++ {
|
||||
tmplPaths = append(tmplPaths, l.CheckString(i+1))
|
||||
}
|
||||
tmpl, err := gctemplates.LoadTemplate(tmplPaths...)
|
||||
l.Push(luar.New(l, tmpl))
|
||||
l.Push(luar.New(l, err))
|
||||
return 2
|
||||
},
|
||||
"minify_template": func(l *lua.LState) int {
|
||||
tmplUD := l.CheckUserData(1)
|
||||
tmpl := tmplUD.Value.(*template.Template)
|
||||
dataTable := l.CheckTable(2)
|
||||
data := map[string]interface{}{}
|
||||
dataTable.ForEach(func(l1, l2 lua.LValue) {
|
||||
data[l1.String()] = lvalueToInterface(l, l2)
|
||||
})
|
||||
writer := l.CheckUserData(3).Value.(io.Writer)
|
||||
mediaType := l.CheckString(4)
|
||||
err := serverutil.MinifyTemplate(tmpl, data, writer, mediaType)
|
||||
l.Push(luar.New(l, err))
|
||||
return 1
|
||||
},
|
||||
"parse_template": func(l *lua.LState) int {
|
||||
tmplName := l.CheckString(1)
|
||||
tmplData := l.CheckString(2)
|
||||
tmpl, err := gctemplates.ParseTemplate(tmplName, tmplData)
|
||||
l.Push(luar.New(l, tmpl))
|
||||
l.Push(luar.New(l, err))
|
||||
return 2
|
||||
},
|
||||
})
|
||||
|
||||
l.Push(t)
|
||||
return 1
|
||||
})
|
||||
|
||||
lState.PreloadModule("manage", func(l *lua.LState) int {
|
||||
t := l.NewTable()
|
||||
l.SetFuncs(t, map[string]lua.LGFunction{
|
||||
"register_manage_page": func(l *lua.LState) int {
|
||||
actionID := l.CheckString(1)
|
||||
actionTitle := l.CheckString(2)
|
||||
actionPerms := l.CheckInt(3)
|
||||
actionJSON := l.CheckInt(4)
|
||||
fn := l.CheckFunction(5)
|
||||
actionHandler := func(writer http.ResponseWriter, request *http.Request, staff *gcsql.Staff, wantsJSON bool, infoEv *zerolog.Event, errEv *zerolog.Event) (output interface{}, err error) {
|
||||
if err = l.CallByParam(lua.P{
|
||||
Fn: fn,
|
||||
NRet: 2,
|
||||
// Protect: true,
|
||||
}, luar.New(l, writer), luar.New(l, request), luar.New(l, staff), lua.LBool(wantsJSON), luar.New(l, infoEv), luar.New(l, errEv)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
out := lua.LVAsString(l.Get(-2))
|
||||
errStr := lua.LVAsString(l.Get(-1))
|
||||
if errStr != "" {
|
||||
err = errors.New(errStr)
|
||||
}
|
||||
return out, err
|
||||
}
|
||||
manage.RegisterManagePage(actionID, actionTitle, actionPerms, actionJSON, actionHandler)
|
||||
return 0
|
||||
},
|
||||
})
|
||||
|
||||
l.Push(t)
|
||||
return 1
|
||||
})
|
||||
|
||||
lState.PreloadModule("uploads", func(l *lua.LState) int {
|
||||
t := l.NewTable()
|
||||
|
||||
l.SetFuncs(t, map[string]lua.LGFunction{
|
||||
"register_handler": func(l *lua.LState) int {
|
||||
ext := l.CheckString(1)
|
||||
handler := l.CheckFunction(2)
|
||||
uploads.RegisterUploadHandler(ext, func(upload *gcsql.Upload, post *gcsql.Post, board, filePath, thumbPath, catalogThumbPath string, infoEv, accessEv, errEv *zerolog.Event) error {
|
||||
l.CallByParam(lua.P{
|
||||
Fn: handler,
|
||||
NRet: 1,
|
||||
// Protect: true,
|
||||
}, luar.New(l, upload), luar.New(l, post), lua.LString(board), lua.LString(filePath), lua.LString(thumbPath), lua.LString(catalogThumbPath))
|
||||
|
||||
errRet := l.CheckAny(-1)
|
||||
if errRet != nil && errRet.Type() != lua.LTNil {
|
||||
return errors.New(errRet.String())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return 0
|
||||
},
|
||||
"get_thumbnail_ext": func(l *lua.LState) int {
|
||||
fileExt := l.CheckString(1)
|
||||
l.Push(luar.New(l, uploads.GetThumbnailExtension(fileExt)))
|
||||
return 1
|
||||
},
|
||||
"set_thumbnail_ext": func(l *lua.LState) int {
|
||||
fileExt := l.CheckString(1)
|
||||
thumbExt := l.CheckString(2)
|
||||
uploads.SetThumbnailExtension(fileExt, thumbExt)
|
||||
return 0
|
||||
},
|
||||
})
|
||||
|
||||
l.Push(t)
|
||||
return 1
|
||||
})
|
||||
|
||||
lState.SetGlobal("_GOCHAN_VERSION", lua.LString(config.GetVersion().String()))
|
||||
}
|
||||
|
||||
|
|
|
@ -19,14 +19,21 @@ post.MessageRaw = "Message modified by a plugin\n"
|
|||
post.Message = "Message modified by a plugin<br />"
|
||||
print(string.format("Modified message text: %q", post.MessageText))`
|
||||
|
||||
eventsTestingStr = `event_register({"newPost"}, function(tr, ...)
|
||||
eventsTestingStr = `local events = require("events")
|
||||
events.register_event({"newPost"}, function(tr, ...)
|
||||
print("newPost triggered :D")
|
||||
for i, v in ipairs(arg) do
|
||||
print(i .. ": " .. tostring(v))
|
||||
end
|
||||
end)
|
||||
|
||||
event_trigger("newPost", "blah", 16, 3.14, true, nil)`
|
||||
events.trigger_event("newPost", "blah", 16, 3.14, true, nil)`
|
||||
|
||||
configTestingStr = `local config = require("config")
|
||||
local system_critical_cfg = config.system_critical_config()
|
||||
local site_cfg = config.site_config()
|
||||
local board_cfg = config.board_config()
|
||||
return { ListenIP = system_critical_cfg.ListenIP, SiteSlogan = site_cfg.SiteSlogan, DefaultStyle = board_cfg.DefaultStyle }`
|
||||
)
|
||||
|
||||
func initPluginTests() {
|
||||
|
@ -37,7 +44,7 @@ func initPluginTests() {
|
|||
func TestVersionFunction(t *testing.T) {
|
||||
initPluginTests()
|
||||
err := lState.DoString(versionStr)
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
testingVersionStr := lState.Get(-1).(lua.LString)
|
||||
assert.EqualValues(t, config.GetVersion().String(), testingVersionStr)
|
||||
}
|
||||
|
@ -52,15 +59,26 @@ func TestStructPassing(t *testing.T) {
|
|||
}
|
||||
lState.SetGlobal("post", luar.New(lState, p))
|
||||
err := lState.DoString(structPassingStr)
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
t.Logf("Modified message text after Lua: %q", p.MessageRaw)
|
||||
if p.MessageRaw != "Message modified by a plugin\n" || p.Message != "Message modified by a plugin<br />" {
|
||||
t.Fatal("message was not properly modified by plugin")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEventPlugins(t *testing.T) {
|
||||
func TestEventModule(t *testing.T) {
|
||||
initPluginTests()
|
||||
err := lState.DoString(eventsTestingStr)
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestConfigModule(t *testing.T) {
|
||||
config.InitConfig(config.GetVersion().String())
|
||||
initPluginTests()
|
||||
err := lState.DoString(configTestingStr)
|
||||
assert.NoError(t, err)
|
||||
returnTable := lState.CheckTable(-1)
|
||||
assert.Equal(t, "127.0.0.1", returnTable.RawGetString("ListenIP").(lua.LString).String())
|
||||
assert.Equal(t, "Gochan testing", returnTable.RawGetString("SiteSlogan").(lua.LString).String())
|
||||
assert.Equal(t, "test.css", returnTable.RawGetString("DefaultStyle").(lua.LString).String())
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ func InitLog(logPath string, debug bool) (err error) {
|
|||
}
|
||||
|
||||
if debug {
|
||||
logger = zerolog.New(io.MultiWriter(logFile, os.Stdout)).Hook(&logHook{})
|
||||
logger = zerolog.New(io.MultiWriter(logFile, zerolog.NewConsoleWriter())).Hook(&logHook{})
|
||||
} else {
|
||||
logger = zerolog.New(logFile).Hook(&logHook{})
|
||||
}
|
||||
|
|
|
@ -2,57 +2,57 @@
|
|||
- **_GOCHAN_VERSION**
|
||||
- The version string of the running Gochan server
|
||||
|
||||
# Functions
|
||||
- **error_log([error_message string])**
|
||||
- Creates and returns a zerolog [Event](https://pkg.go.dev/github.com/rs/zerolog) object for the error log. If a string is used as the argument, it is used as the error message.
|
||||
|
||||
- **info_log()**
|
||||
- Creates and returns a zerolog [Event](https://pkg.go.dev/github.com/rs/zerolog) object with an info level.
|
||||
|
||||
- **warn_log()**
|
||||
- Creates and returns a zerolog [Event](https://pkg.go.dev/github.com/rs/zerolog) object with a warning level.
|
||||
|
||||
- **register_upload_handler(ext string, function(upload, post, board, filePath, thumbPath, catalogThumbPath, infoEv, accessEv, errEv))**
|
||||
- Registers a function to be called for handling uploaded files with the given extension. See [pdf_thumbnail.lua](./sample-plugins/pdf_thumbnail.lua) for a usage example.
|
||||
|
||||
- **get_thumbnail_ext(upload_ext string)**
|
||||
- Returns the configured (or built-in) thumbnail file extension to be used for the given upload extension
|
||||
|
||||
- **set_thumbnail_ext(upload_ext string, thumbnail_ext string)**
|
||||
- Sets the thumbnail extension to be used for the given upload extension
|
||||
|
||||
- **system_critical_config()**
|
||||
- Returns the [SystemCriticalConfig](https://pkg.go.dev/github.com/gochan-org/gochan/pkg/config#SystemCriticalConfig)
|
||||
|
||||
- **site_config()**
|
||||
# Modules
|
||||
The following are modules that can be loaded via `require("modulename")`. See [./examples/plugins/](./examples/plugins/) for usage examples
|
||||
## config
|
||||
- **config.system_critical_config()**
|
||||
- Returns the [SystemCriticalConfig](https://pkg.go.dev/github.com/gochan-org/gochan/pkg/config#SystemCriticalConfig)
|
||||
- **config.site_config()**
|
||||
- Returns the [SiteConfig](https://pkg.go.dev/github.com/gochan-org/gochan/pkg/config#SiteConfig)
|
||||
|
||||
- **board_config(board string)**
|
||||
- **config.board_config(board string)**
|
||||
- Returns the [BoardConfig](https://pkg.go.dev/github.com/gochan-org/gochan/pkg/config#BoardConfig) for the given board, or the default BoardConfig if `board` is an empty string
|
||||
|
||||
- **db_query(query string)**
|
||||
- Returns a [Rows](https://pkg.go.dev/database/sql#Rows) object for the given SQL query and an error if any occured, or nil if there were no errors.
|
||||
|
||||
- **db_scan_rows(rows, scan_table)**
|
||||
- scans the value of the current row into `scan_table` and returns an error if any occured, or nil if there were no errors.
|
||||
|
||||
- **event_register(events_table, handler_func)**
|
||||
## events
|
||||
- **events.register_event(events_table, handler_func)**
|
||||
- Registers `handler_func` for the events in `events_table`. If any arguments are passed to the event when it is triggered, it will be sent to `handler_func`.
|
||||
|
||||
- **event_trigger(event_name string, data...)**
|
||||
- **events.trigger_event(event_name string, data...)**
|
||||
- Triggers the event registered to `event_name` and passes `data` (if set) to the event handler.
|
||||
|
||||
- **register_manage_page(action string, title string, perms int, wants_json int, handler func(writer, request, staff, wants_json, info_ev, err_ev))**
|
||||
- Registers the manage page accessible at /manage/`action` to be handled by `handler`. See [manage.RegisterManagePage](https://pkg.go.dev/github.com/gochan-org/gochan/pkg/manage#RegisterManagePage) for info on how `handler` should be used, or [registermgmtpage.lua](./sample-plugins/registermgmtpage.lua) for an example
|
||||
## gclog
|
||||
- **gclog.info_log()**
|
||||
- Creates and returns a zerolog [Event](https://pkg.go.dev/github.com/rs/zerolog) object with an info level.
|
||||
- **gclog.warn_log()**
|
||||
- Creates and returns a zerolog [Event](https://pkg.go.dev/github.com/rs/zerolog) object with a warning level.
|
||||
- **gclog.error_log([error_message string])**
|
||||
- Creates and returns a zerolog [Event](https://pkg.go.dev/github.com/rs/zerolog) object for the error log. If a string is used as the argument, it is used as the error message.
|
||||
|
||||
- **load_template(files...)**
|
||||
## gcsql
|
||||
- **gcsql.query_rows(query string, args...)**
|
||||
- Returns a [Rows](https://pkg.go.dev/database/sql#Rows) object for the given SQL query and an error if any occured, or nil if there were no errors. `args` if given will be used for a parameterized query.
|
||||
- **gcsql.execute_sql(query string, args...)**
|
||||
- Executes the SQL string `query` with the optional `args` as parameters and returns a [Result](https://pkg.go.dev/database/sql#Result) object and an error (or nil if there were no errors)
|
||||
- **gcsql.scan_rows(rows, scan_table)**
|
||||
- scans the value of the current row into `scan_table` and returns an error if any occured, or nil if there were no errors.
|
||||
|
||||
## gctemplates
|
||||
- **gctemplates.load_template(files...)**
|
||||
- Calls [gctemplates.LoadTemplate](https://pkg.go.dev/github.com/gochan-org/gochan/pkg/gctemplates#LoadTemplate) using the given `files` and returns a [Template](https://pkg.go.dev/html/template#Template) and an error object (or nil if there were no errors).
|
||||
|
||||
- **parse_template(template_name string, template_data string)**
|
||||
- **gctemplates.minify_template(template, data_table, writer, media_type)**
|
||||
- Calls [serverutil.MinifyTemplate](https://pkg.go.dev/github.com/gochan-org/gochan/pkg/server/serverutil#MinifyTemplate) with the given `template` object, `data_table` (as variables passed to the template), `writer`, and `media_type`. See [registermgmtpage.lua](./examples/plugins/registermgmtpage.lua) for an example
|
||||
- **gctemplates.parse_template(template_name string, template_data string)**
|
||||
- Calls [gctemplates.ParseTemplate](https://pkg.go.dev/github.com/gochan-org/gochan/pkg/gctemplates#ParseTemplate) with the given template name and Go template data, and returns a [Template](https://pkg.go.dev/html/template#Template) and an error object (or nil if there were no errors).
|
||||
|
||||
- **minify_template(template, data_table, writer, media_type)**
|
||||
- Calls [serverutil.MinifyTemplate](https://pkg.go.dev/github.com/gochan-org/gochan/pkg/server/serverutil#MinifyTemplate) with the given `template` object, `data_table` (as variables passed to the template), `writer`, and `media_type`. See [registermgmtpage.lua](./sample-plugins/registermgmtpage.lua) for an example
|
||||
## manage
|
||||
- **manage.register_manage_page(action string, title string, perms int, wants_json int, handler func(writer, request, staff, wants_json, info_ev, err_ev))**
|
||||
- Registers the manage page accessible at /manage/`action` to be handled by `handler`. See [manage.RegisterManagePage](https://pkg.go.dev/github.com/gochan-org/gochan/pkg/manage#RegisterManagePage) for info on how `handler` should be used, or [registermgmtpage.lua](./examples/plugins/registermgmtpage.lua) for an example
|
||||
|
||||
## uploads
|
||||
- **uploads.register_handler(ext string, function(upload, post, board, filePath, thumbPath, catalogThumbPath, infoEv, accessEv, errEv))**
|
||||
- Registers a function to be called for handling uploaded files with the given extension. See [pdf_thumbnail.lua](./examples//plugins/pdf_thumbnail.lua) for a usage example.
|
||||
- **uploads.get_thumbnail_ext(upload_ext string)**
|
||||
- Returns the configured (or built-in) thumbnail file extension to be used for the given upload extension
|
||||
- **uploads.set_thumbnail_ext(upload_ext string, thumbnail_ext string)**
|
||||
- Sets the thumbnail extension to be used for the given upload extension
|
||||
|
||||
|
||||
# Events
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
event_register({"incoming-upload"}, function(tr, upload)
|
||||
rows, err = db_query("SELECT COUNT(*) FROM DBPREFIXfiles WHERE original_filename = ?", {upload.OriginalFilename})
|
||||
if(err ~= nil) then
|
||||
return err:Error()
|
||||
end
|
||||
while rows:Next() do
|
||||
rows_table = {}
|
||||
err = db_scan_rows(rows, rows_table)
|
||||
if(err ~= nil) then
|
||||
rows:Close()
|
||||
return err:Error()
|
||||
end
|
||||
if(rows_table["COUNT(*)"] > 0) then
|
||||
rows:Close()
|
||||
return "a file with that filename has already been uploaded"
|
||||
end
|
||||
end
|
||||
end)
|
Loading…
Add table
Add a link
Reference in a new issue