827 lines
22 KiB
Lua
827 lines
22 KiB
Lua
local SQL = require"luasql.mysql"
|
|
|
|
local BigGlobe = require"bigglobe"
|
|
|
|
local SQLEnv = SQL.mysql()
|
|
local SQLConn
|
|
|
|
local Rand = require"openssl.rand"
|
|
assert(Rand.ready())
|
|
|
|
local SessionsKey = Rand.bytes(64)
|
|
|
|
local ObjHideKey = io.open("objkey", "rb"):read"*a"
|
|
local AES128ECB = require"openssl.cipher".new("AES-128-ECB") -- Can be ECB without reprecussions
|
|
|
|
local Escapes = require"html"
|
|
|
|
local LFS = require"lfs"
|
|
|
|
local unistd = require"posix.unistd"
|
|
local stdio = require"posix.stdio"
|
|
|
|
local USER_PRIVS_BANNED = 0
|
|
local USER_PRIVS_UNAPPROVED = 1
|
|
local USER_PRIVS_APPROVED = 2
|
|
local USER_PRIVS_MOD = 128
|
|
local USER_PRIVS_ADMIN = 255
|
|
|
|
local function pingdb()
|
|
if not SQLConn or not SQLConn:ping() then
|
|
SQLConn = SQLEnv:connect("ikibooru", BigGlobe.cfg.sqlu, BigGlobe.cfg.sqlp, BigGlobe.cfg.sqlh)
|
|
end
|
|
return SQLConn ~= nil
|
|
end
|
|
|
|
-- UTC to store in database
|
|
local function getnow()
|
|
return "'" .. SQLConn:escape(os.date("!%Y-%m-%d %H:%M:%S")) .. "'"
|
|
end
|
|
|
|
local function autocomplete(liek, over18)
|
|
pingdb()
|
|
|
|
local ret = {}
|
|
local cursor = SQLConn:execute("SELECT * FROM tags WHERE name LIKE '" .. SQLConn:escape("%" .. liek .. "%") .. "'" .. (over18 and "" or " AND adultonly = 0") .. ";")
|
|
if not cursor then return "" end
|
|
local row = cursor:fetch({})
|
|
while row do
|
|
ret[#ret + 1] = table.concat(row, ",") .. "\n"
|
|
|
|
row = cursor:fetch(row)
|
|
end
|
|
cursor:close()
|
|
return table.concat(ret)
|
|
end
|
|
|
|
local function searchobjs(taglist, namefilter, offset, adultstuff)
|
|
-- Security check
|
|
for k,v in pairs(taglist) do
|
|
if type(taglist[k]) ~= "number" then
|
|
return nil
|
|
end
|
|
end
|
|
|
|
if not adultstuff then
|
|
adultstuff = -1
|
|
end
|
|
|
|
pingdb()
|
|
|
|
offset = tonumber(offset)
|
|
|
|
local sqlq
|
|
if #taglist > 0 and namefilter then
|
|
sqlq = string.format(
|
|
"SELECT * FROM objects WHERE %s id IN (SELECT objid FROM objtag WHERE tagid IN (%s) GROUP BY objid HAVING COUNT(tagid) >= %s) AND MATCH(name) AGAINST('%s') AND id > %s AND published = 1 ORDER BY id ASC LIMIT 50;",
|
|
|
|
({[-1] = "id NOT IN (SELECT objid FROM objtag WHERE tagid IN (SELECT id FROM tags WHERE adultonly = 1)) AND", [0] = "", [1] = "id IN (SELECT objid FROM objtag WHERE tagid IN (SELECT id FROM tags WHERE adultonly = 1)) AND"})[adultstuff],
|
|
table.concat(taglist, ","),
|
|
#taglist,
|
|
SQLConn:escape(namefilter),
|
|
offset
|
|
)
|
|
elseif #taglist > 0 and not namefilter then
|
|
sqlq = string.format(
|
|
"SELECT * FROM objects WHERE %s id IN (SELECT objid FROM objtag WHERE tagid IN (%s) GROUP BY objid HAVING COUNT(tagid) >= %s) AND id > %s AND published = 1 ORDER BY id ASC LIMIT 50;",
|
|
|
|
({[-1] = "id NOT IN (SELECT objid FROM objtag WHERE tagid IN (SELECT id FROM tags WHERE adultonly = 1)) AND", [0] = "", [1] = "id IN (SELECT objid FROM objtag WHERE tagid IN (SELECT id FROM tags WHERE adultonly = 1)) AND"})[adultstuff],
|
|
table.concat(taglist, ","),
|
|
#taglist,
|
|
offset
|
|
)
|
|
elseif #taglist == 0 and namefilter then
|
|
sqlq = string.format(
|
|
"SELECT * FROM objects WHERE %s MATCH(name) AGAINST('%s') AND id > %s AND published = 1 ORDER BY id ASC LIMIT 50;",
|
|
|
|
({[-1] = "id NOT IN (SELECT objid FROM objtag WHERE tagid IN (SELECT id FROM tags WHERE adultonly = 1)) AND", [0] = "", [1] = "id IN (SELECT objid FROM objtag WHERE tagid IN (SELECT id FROM tags WHERE adultonly = 1)) AND"})[adultstuff],
|
|
SQLConn:escape(namefilter),
|
|
offset
|
|
)
|
|
else
|
|
sqlq = string.format(
|
|
"SELECT * FROM objects WHERE %s id > %s AND published = 1 ORDER BY id ASC LIMIT 50;",
|
|
|
|
({[-1] = "id NOT IN (SELECT objid FROM objtag WHERE tagid IN (SELECT id FROM tags WHERE adultonly = 1)) AND", [0] = "", [1] = "id IN (SELECT objid FROM objtag WHERE tagid IN (SELECT id FROM tags WHERE adultonly = 1)) AND"})[adultstuff],
|
|
offset
|
|
)
|
|
end
|
|
|
|
local cursor = SQLConn:execute(sqlq)
|
|
if not cursor then return {} end
|
|
|
|
local ret = {}
|
|
while true do
|
|
local row = cursor:fetch({}, "a")
|
|
if not row then break end
|
|
table.insert(ret, row)
|
|
end
|
|
|
|
return ret
|
|
end
|
|
|
|
local function getobj(objid)
|
|
if type(objid) ~= "number" then return nil end
|
|
|
|
pingdb()
|
|
|
|
local cursor = SQLConn:execute("SELECT * FROM objects WHERE id = " .. objid .. ";")
|
|
if not cursor then return nil end
|
|
|
|
local ret = cursor:fetch({}, "a")
|
|
if not ret then return nil end
|
|
|
|
ret.id = tonumber(ret.id) --for some reason..
|
|
ret.owner = tonumber(ret.owner)
|
|
ret.published = ret.published:byte(1) ~= 0
|
|
ret.approved = ret.approved:byte(1) ~= 0
|
|
return ret
|
|
end
|
|
|
|
local hextointandinttohex = {}
|
|
for i=0,255 do local s = string.format("%02x", i); hextointandinttohex[s] = i; hextointandinttohex[i] = s; end
|
|
local function b256toreadable(src)
|
|
local r = {}
|
|
src:gsub(".", function(b) table.insert(r, hextointandinttohex[b:byte()]) end)
|
|
return table.concat(r)
|
|
end
|
|
local function readabletob256(src)
|
|
if #src % 2 == 1 then error("gotta be even length, man") end
|
|
local r = {}
|
|
for i=1,#src,2 do
|
|
table.insert(r, string.char(hextointandinttohex[src:sub(i, i + 1)]))
|
|
end
|
|
return table.concat(r)
|
|
end
|
|
|
|
local function isobjhexvalid(objhex)
|
|
return #objhex == 32 and not objhex:find("[^0-9a-f]")
|
|
end
|
|
|
|
local function objhideid(objid)
|
|
local t = {}
|
|
for i=1,16 do
|
|
table.insert(t, objid % 256)
|
|
objid = objid // 256
|
|
end
|
|
|
|
local c = AES128ECB:encrypt(ObjHideKey, nil, false):final(string.char(table.unpack(t)))
|
|
|
|
return b256toreadable(c)
|
|
end
|
|
|
|
local function objshowid(objhex)
|
|
if not isobjhexvalid(objhex) then return nil end
|
|
|
|
local c = AES128ECB:decrypt(ObjHideKey, nil, false):final(readabletob256(objhex))
|
|
|
|
local r = 0
|
|
for i=16,1,-1 do
|
|
r = r * 256 + c:byte(i)
|
|
end
|
|
|
|
return r
|
|
end
|
|
|
|
local function testobjfilename(fname)
|
|
if fname:match"^%s+.*$" or fname:match"^%.+$" or fname:match".*%s+$" or fname:match".*%.+$" then return false end
|
|
|
|
for k, v in pairs{"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"} do
|
|
if fname == v or fname:match("^" .. v .. "%..+") then
|
|
return false
|
|
end
|
|
end
|
|
|
|
return not fname:find"[/\\\0-\31%<%>%:%\"%|%?%*%[%]%%]" and #fname <= 56
|
|
end
|
|
|
|
local function urltophysical(p)
|
|
if p:sub(1, 6) == "/objd/" then
|
|
if isobjhexvalid(p:sub(7, 7 + 31)) and testobjfilename(p:sub(7 + 33)) then
|
|
return "objd/" .. p:sub(7, 7 + 31):gsub("..", "%0/") .. p:sub(7 + 32)
|
|
end
|
|
return nil
|
|
else
|
|
return p:sub(2)
|
|
end
|
|
end
|
|
|
|
-- PERFORMS NO QUOTA CHECKING; THATS DONE IN obje.html.l
|
|
local function createfile(objid, fname, fsz)
|
|
if not testobjfilename(fname) or fname == ".thumb.jpg" then return false end
|
|
if type(fsz) ~= "number" then return false end
|
|
|
|
local f = io.open(urltophysical("/objd/" .. objhideid(objid) .. "/" .. fname), "wb")
|
|
if not f then return false end
|
|
if unistd.ftruncate(stdio.fileno(f), fsz) ~= 0 then return false end
|
|
|
|
f:close()
|
|
|
|
return true
|
|
end
|
|
|
|
local function updatefile(objid, fname, offset, data)
|
|
if not testobjfilename(fname) or fname == ".thumb.jpg" then return false end
|
|
|
|
local fn = urltophysical("/objd/" .. objhideid(objid) .. "/" .. fname)
|
|
|
|
if offset + #data > lfs.attributes(fn).size then
|
|
return false
|
|
end
|
|
|
|
local f = io.open(fn, "r+b")
|
|
if not f then
|
|
return false
|
|
end
|
|
|
|
if not f:seek("set", offset) then return false end
|
|
if not f:write(data) then return false end
|
|
|
|
f:close()
|
|
|
|
return true
|
|
end
|
|
|
|
local function remfilefromobj(objid, fname)
|
|
if not testobjfilename(fname) then return false end
|
|
|
|
if not os.remove(urltophysical("/objd/" .. objhideid(objid) .. "/" .. fname)) then return false end
|
|
|
|
return true
|
|
end
|
|
|
|
local function genobjthumbnail(objid, fname, maxsize)
|
|
if not testobjfilename(fname) then return false end
|
|
|
|
local objhex = objhideid(objid)
|
|
|
|
local srcfn = urltophysical("/objd/" .. objhex .. "/" .. fname)
|
|
local tempfn = "/tmp/ikibooruthumb" .. b256toreadable(Rand.bytes(16)) .. ".jpg"
|
|
local destfn = urltophysical("/objd/" .. objhex .. "/.thumb.jpg")
|
|
|
|
local ret, killa, exitcode = os.execute(BigGlobe.cfg.magickprefix .. "convert " .. Escapes.shellescape(srcfn) .. " -background white -strip -interlace Plane -sampling-factor 4:2:0 -flatten -define jpeg:extent=100kb " .. Escapes.shellescape(tempfn))
|
|
if not ret or killa ~= "exit" or exitcode ~= 0 then return false end
|
|
|
|
if LFS.attributes(tempfn).size > maxsize then
|
|
os.remove(tempfn)
|
|
return false
|
|
end
|
|
|
|
local inn = io.open(tempfn, "rb")
|
|
local outt = io.open(destfn, "wb")
|
|
|
|
if not inn or not outt then
|
|
os.remove(tempfn)
|
|
return false
|
|
end
|
|
|
|
outt:write(inn:read"*a")
|
|
|
|
outt:close()
|
|
inn:close()
|
|
|
|
os.remove(tempfn)
|
|
|
|
return true
|
|
end
|
|
|
|
local function isdisplaynamevalid(str)
|
|
return not str:find"[\0-\31]" and #str <= 32
|
|
end
|
|
|
|
local function isemailvalid(str)
|
|
return not str:match"^%s*$" and not str:find"[\0-\31]" and #str <= 64
|
|
end
|
|
|
|
local function getuserbyemail(email)
|
|
if type(email) ~= "string" then return nil end
|
|
|
|
pingdb()
|
|
|
|
local cursor = SQLConn:execute("SELECT * FROM users WHERE email = '" .. SQLConn:escape(email) .. "';")
|
|
if not cursor then return nil end
|
|
|
|
local ret = cursor:fetch({}, "a")
|
|
if not ret then return nil end
|
|
|
|
ret.id = tonumber(ret.id)
|
|
ret.privs = tonumber(ret.privs)
|
|
|
|
return ret
|
|
end
|
|
|
|
local function getuserbyid(userid)
|
|
userid = tonumber(userid)
|
|
if not userid then return nil end
|
|
|
|
pingdb()
|
|
|
|
local cursor = SQLConn:execute("SELECT * FROM users WHERE id = " .. userid .. ";")
|
|
if not cursor then return nil end
|
|
|
|
local ret = cursor:fetch({}, "a")
|
|
if not ret then return nil end
|
|
|
|
ret.id = tonumber(ret.id)
|
|
ret.privs = tonumber(ret.privs)
|
|
|
|
return ret
|
|
end
|
|
|
|
local function reguser(email, displayname, privs)
|
|
if not isdisplaynamevalid(displayname) then return false, "displayname" end
|
|
|
|
privs = tonumber(privs)
|
|
if not privs then return false, "privs" end
|
|
|
|
pingdb()
|
|
|
|
local cursor = SQLConn:execute("INSERT INTO users (displayname, email, createtime, privs) VALUES ('" .. SQLConn:escape(displayname) .. "', '" .. SQLConn:escape(email) .. "', " .. getnow() .. ", " .. privs ..");")
|
|
if not cursor then return false, "db" end
|
|
|
|
return tonumber(SQLConn:getlastautoid())
|
|
end
|
|
|
|
local function userregverify(str)
|
|
local start, sep = str:find"^[^%;]+;"
|
|
|
|
-- Malformity check
|
|
if not start then return nil end
|
|
|
|
local digest = str:sub(1, sep - 1)
|
|
local msg = str:sub(sep + 1)
|
|
|
|
local thetime = msg:match"t%=(%d+)%;"
|
|
|
|
if not thetime then return nil end
|
|
|
|
if os.difftime(thetime, os.time()) < 0 then return false end
|
|
|
|
if b256toreadable(require"openssl.hmac".new(SessionsKey, "sha256"):final(msg)) ~= digest then
|
|
return nil
|
|
end
|
|
|
|
if not msg:match"^reg%;" then return nil end
|
|
|
|
return { em = readabletob256(msg:match"em=([^%;]*)") }
|
|
end
|
|
|
|
local function userregcode(em)
|
|
local t = os.date"*t"
|
|
t.day = t.day + 7 --7 day expiry
|
|
|
|
local str = "reg;em="..b256toreadable(em) .. ";t=" .. os.time(t) .. ";"
|
|
return b256toreadable(require"openssl.hmac".new(SessionsKey, "sha256"):final(str)) .. ";" .. str
|
|
end
|
|
|
|
local function userauth(user)
|
|
local t = os.date"*t"
|
|
t.day = t.day + 7 --7 day expiry
|
|
|
|
local str = "id=" .. user.id .. ";t=" .. os.time(t) .. ";"
|
|
|
|
return b256toreadable(require"openssl.hmac".new(SessionsKey, "sha256"):final(str)) .. ";" .. str
|
|
end
|
|
|
|
local function userverify(str)
|
|
local start, sep = str:find"^[^%;]+;";
|
|
|
|
-- Malformity check
|
|
if not start then return nil end
|
|
|
|
local digest = str:sub(1, sep - 1)
|
|
local msg = str:sub(sep + 1)
|
|
|
|
local thetime = msg:match("t%=(%d+)%;")
|
|
|
|
-- Malformity check
|
|
if not thetime then return nil end
|
|
|
|
-- Expiry check
|
|
if os.difftime(thetime, os.time()) < 0 then return false end
|
|
|
|
if b256toreadable(require"openssl.hmac".new(SessionsKey, "sha256"):final(msg)) ~= digest then
|
|
return nil
|
|
end
|
|
|
|
if not msg:match"^id%=" then return nil end
|
|
|
|
return getuserbyid(msg:match"^id%=(%d+)")
|
|
end
|
|
|
|
local function tagadd(name, category, adultonly)
|
|
category = tonumber(category)
|
|
if not category then return false end
|
|
category = category - 1
|
|
|
|
pingdb()
|
|
|
|
local cur = SQLConn:execute("INSERT INTO tags (name, category, adultonly) VALUES ('" .. SQLConn:escape(name) .. "', " .. category .. ", " .. (adultonly and 1 or 0) .. ");")
|
|
|
|
if not cur then return nil end
|
|
|
|
return tonumber(SQLConn:getlastautoid())
|
|
end
|
|
|
|
local function regnewobj(ownerid, approved, published)
|
|
ownerid = tonumber(ownerid)
|
|
if not ownerid then return nil end
|
|
|
|
if type(approved) ~= "boolean" then return nil end
|
|
if type(published) ~= "boolean" then return nil end
|
|
|
|
pingdb()
|
|
|
|
local cur = SQLConn:execute("INSERT INTO objects (name, owner, approved, published, createtime) VALUES ('', " .. ownerid .. ", " .. (approved and 1 or 0) .. ", " .. (published and 1 or 0) .. ", " .. getnow() .. ");")
|
|
|
|
if not cur then return nil end
|
|
|
|
local objid = tonumber(SQLConn:getlastautoid())
|
|
|
|
local objpath = "objd/"
|
|
for objpathpart in objhideid(objid):gmatch("..") do
|
|
objpath = objpath .. objpathpart .. "/"
|
|
LFS.mkdir(objpath)
|
|
end
|
|
|
|
return objid
|
|
end
|
|
|
|
local function getownedobjs(ownerid)
|
|
ownerid = tonumber(ownerid)
|
|
if not ownerid then return nil end
|
|
|
|
pingdb()
|
|
|
|
local cur = SQLConn:execute("SELECT * FROM objects WHERE owner = " .. ownerid .. " ORDER BY id DESC;")
|
|
|
|
if not cur then return {} end
|
|
|
|
local ret = {}
|
|
while true do
|
|
local row = cur:fetch({}, "a")
|
|
if not row then break end
|
|
row.id = tonumber(row.id)
|
|
row.owner = tonumber(row.owner)
|
|
table.insert(ret, row)
|
|
end
|
|
|
|
return ret
|
|
end
|
|
|
|
local function objupdate(objid, newname, newpublished)
|
|
if not isdisplaynamevalid(newname) then return false end
|
|
objid = tonumber(objid)
|
|
if not objid then return false end
|
|
if type(newpublished) ~= "boolean" then return false end
|
|
pingdb()
|
|
if not SQLConn:execute("UPDATE objects SET name = '" .. SQLConn:escape(newname) .. "', published = " .. (newpublished and 1 or 0) .. " WHERE id = " .. objid .. ";") then return false end
|
|
return true
|
|
end
|
|
|
|
local function updatetags(tagarr, newname, newcategory, newadultonly, del)
|
|
for k,v in pairs(tagarr) do
|
|
if type(v) ~= "number" then
|
|
return false
|
|
end
|
|
end
|
|
|
|
if #tagarr == 0 then return false end
|
|
|
|
if newcategory and type(newcategory) ~= "number" then
|
|
return false
|
|
end
|
|
|
|
pingdb()
|
|
|
|
if del then
|
|
return not not SQLConn:execute("DELETE FROM tags WHERE id IN (" .. table.concat(tagarr, ",") .. ");")
|
|
end
|
|
|
|
local cols = {"adultonly = " .. (newadultonly and 1 or 0)}
|
|
if newname then
|
|
table.insert(cols, newname and ("name = '" .. SQLConn:escape(newname) .. "'") or "")
|
|
end
|
|
if newcategory then
|
|
newcategory = newcategory - 1
|
|
table.insert(cols, newcategory and ("category = " .. newcategory) or "")
|
|
end
|
|
|
|
return not not SQLConn:execute("UPDATE tags SET " .. table.concat(cols, ", ") .. " WHERE id IN (" .. table.concat(tagarr, ",") .. ");")
|
|
end
|
|
|
|
local function csrf(userid)
|
|
local str = table.concat({os.time(), tonumber(userid)}, ";")
|
|
return b256toreadable(require"openssl.hmac".new(SessionsKey, "sha256"):final(str)) .. ";" .. str
|
|
end
|
|
|
|
local function csrfverify(userid, booboo)
|
|
if not booboo:find";" then return false end
|
|
|
|
local digest = booboo:sub(1, booboo:find";" - 1)
|
|
local msg = booboo:sub(booboo:find";" + 1)
|
|
|
|
if b256toreadable(require"openssl.hmac".new(SessionsKey, "sha256"):final(msg)) ~= digest then
|
|
return false
|
|
end
|
|
|
|
return tonumber(msg:match";(%d+)$") == userid
|
|
end
|
|
|
|
local function nexttoapproveobj()
|
|
pingdb()
|
|
|
|
local cur = SQLConn:execute("SELECT id FROM objects WHERE published = 1 AND approved = 0 ORDER BY id ASC LIMIT 1;")
|
|
if not cur then return nil end
|
|
return tonumber(cur:fetch())
|
|
end
|
|
|
|
local function banuser(uid)
|
|
if type(uid) ~= "number" then
|
|
return false
|
|
end
|
|
pingdb()
|
|
return not not SQLConn:execute("UPDATE users SET privs = " .. USER_PRIVS_BANNED .. " WHERE id = " .. uid .. ";")
|
|
end
|
|
|
|
local function approveuser(uid)
|
|
if type(uid) ~= "number" then
|
|
return false
|
|
end
|
|
pingdb()
|
|
return not not SQLConn:execute("UPDATE users SET privs = " .. USER_PRIVS_APPROVED .. " WHERE id = " .. uid .. " AND privs = " .. USER_PRIVS_UNAPPROVED .. ";")
|
|
end
|
|
|
|
local function delobj(oid, delfiles)
|
|
if type(oid) ~= "number" then
|
|
return false
|
|
end
|
|
|
|
pingdb()
|
|
if not SQLConn:execute("DELETE FROM objects WHERE id = " .. oid .. ";") then
|
|
return false
|
|
end
|
|
|
|
if delfiles then
|
|
local d = urltophysical("/objd/" .. objhideid(oid))
|
|
for f in LFS.dir(d) do
|
|
if f ~= "." and f ~= ".." then
|
|
os.remove(d .. f)
|
|
end
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
local function approveobj(oid)
|
|
if type(oid) ~= "number" then
|
|
return false
|
|
end
|
|
pingdb()
|
|
return not not SQLConn:execute("UPDATE objects SET approved = 1 WHERE id = " .. oid .. ";")
|
|
end
|
|
|
|
local function userinfoupdate(userid, displayname)
|
|
if type(userid) ~= "number" then return false end
|
|
|
|
if not isdisplaynamevalid(displayname) then return false end
|
|
|
|
pingdb()
|
|
return not not SQLConn:execute("UPDATE users SET displayname = '" .. SQLConn:escape(displayname) .. "' WHERE id = " .. userid .. ";")
|
|
end
|
|
|
|
local function getobjtags(objid)
|
|
if type(objid) ~= "number" then return nil end
|
|
|
|
pingdb()
|
|
local cur = SQLConn:execute("SELECT * FROM tags WHERE id IN (SELECT tagid FROM objtag WHERE objid = " .. objid .. ");")
|
|
if not cur then return nil end
|
|
|
|
local ret = {}
|
|
local n = 0
|
|
while true do
|
|
local t = cur:fetch({}, "*a")
|
|
if not t then break end
|
|
|
|
t.id = tonumber(t.id)
|
|
t.category = tonumber(t.category)
|
|
ret[t.id] = t
|
|
n = n + 1
|
|
end
|
|
|
|
return ret, n
|
|
end
|
|
|
|
local function addtagstoobj(objid, taglist)
|
|
if type(objid) ~= "number" then return false end
|
|
|
|
local temp = {}
|
|
for k, v in pairs(taglist) do
|
|
if type(v) ~= "number" then return false end
|
|
|
|
table.insert(temp, "(" .. objid .. "," .. v .. ")")
|
|
end
|
|
|
|
pingdb()
|
|
return not not SQLConn:execute("INSERT INTO objtag (objid, tagid) VALUES " .. table.concat(temp, ",") .. ";")
|
|
end
|
|
|
|
local function remtagsfromobj(objid, taglist)
|
|
if type(objid) ~= "number" then return false end
|
|
|
|
local temp = {}
|
|
for k, v in pairs(taglist) do
|
|
if type(v) ~= "number" then return false end
|
|
|
|
table.insert(temp, "tagid = " .. v)
|
|
end
|
|
|
|
pingdb()
|
|
return not not SQLConn:execute("DELETE FROM objtag WHERE objid = " .. objid .. " AND (" .. table.concat(temp, " OR ") .. ");")
|
|
end
|
|
|
|
local function getmoderators()
|
|
pingdb()
|
|
|
|
local cur = SQLConn:execute("SELECT * from users WHERE privs = " .. USER_PRIVS_MOD .. ";")
|
|
if not cur then return {} end
|
|
|
|
local ret = {}
|
|
while true do
|
|
local t = cur:fetch({}, "a")
|
|
if not t then break end
|
|
t.id = tonumber(t.id)
|
|
t.privs = tonumber(t.privs)
|
|
table.insert(ret, t)
|
|
end
|
|
|
|
return ret
|
|
end
|
|
|
|
local function setmodsviaemails(emails)
|
|
pingdb()
|
|
|
|
if not SQLConn:execute("UPDATE users SET privs = " .. USER_PRIVS_APPROVED .. " WHERE privs = " .. USER_PRIVS_MOD .. ";") then
|
|
return false
|
|
end
|
|
|
|
for k,v in pairs(emails) do
|
|
emails[k] = "'" .. SQLConn:escape(v) .. "'"
|
|
end
|
|
|
|
return not not SQLConn:execute("UPDATE users SET privs = " .. USER_PRIVS_MOD .. " WHERE privs < " .. USER_PRIVS_MOD .. " AND email IN (" .. table.concat(emails, ",") .. ");")
|
|
end
|
|
|
|
local function getcomments(objid)
|
|
if type(objid) ~= "number" then return nil end
|
|
|
|
pingdb()
|
|
|
|
local cur = SQLConn:execute("SELECT comment.id AS id, comment.content AS content, comment.authorid AS authorid, user.displayname AS authordisplayname, comment.createtime AS createtime FROM comments comment INNER JOIN users user ON comment.authorid = user.id WHERE comment.objid = " .. objid .. " ORDER BY id DESC;")
|
|
if not cur then return {} end
|
|
|
|
local ret = {}
|
|
while true do
|
|
local t = cur:fetch({}, "a")
|
|
if not t then break end
|
|
t.id = tonumber(t.id)
|
|
t.authorid = tonumber(t.authorid)
|
|
table.insert(ret, t)
|
|
end
|
|
|
|
return ret
|
|
end
|
|
|
|
local function postcomment(objid, userid, content)
|
|
if #content > BigGlobe.MAX_COMMENT_SIZE then
|
|
return false
|
|
end
|
|
|
|
pingdb()
|
|
|
|
return not not SQLConn:execute("INSERT INTO comments (objid, authorid, content, createtime) VALUES (" .. objid .. ", " .. userid .. ", '" .. SQLConn:escape(content) .. "', " .. getnow() .. ")")
|
|
end
|
|
|
|
local function addreport(reporterid, reporteeid, content)
|
|
if type(reporterid) ~= "number" then return false end
|
|
if type(reporteeid) ~= "number" then return false end
|
|
|
|
pingdb()
|
|
|
|
return not not SQLConn:execute("INSERT INTO reports (reporter, reportee, content, createtime, status) VALUES (" .. reporterid .. ", " .. reporteeid .. ", '" .. SQLConn:escape(content) .. "', " .. getnow() .. ", " .. BigGlobe.REPORT_STATUS_OPEN .. ")")
|
|
end
|
|
|
|
local function getreportcount()
|
|
pingdb()
|
|
|
|
local cur = SQLConn:execute("SELECT COUNT(*) FROM reports WHERE status = 0;")
|
|
if not cur then return nil end
|
|
|
|
return cur:fetch()
|
|
end
|
|
|
|
local function getreports(status, offset)
|
|
if type(status) ~= "number" then return nil end
|
|
|
|
if type(offset) ~= "number" then offset = 0 end
|
|
|
|
pingdb()
|
|
|
|
local cur = SQLConn:execute("SELECT * FROM reports WHERE status = " .. status .. " AND id > " .. offset .. " ORDER BY id ASC LIMIT 50;")
|
|
if not cur then return {} end
|
|
|
|
local ret = {}
|
|
while true do
|
|
local t = cur:fetch({}, "a")
|
|
if not t then break end
|
|
t.id = tonumber(t.id)
|
|
t.reporter = tonumber(t.reporter)
|
|
t.reportee = tonumber(t.reportee)
|
|
t.status = tonumber(t.status)
|
|
table.insert(ret, t)
|
|
end
|
|
|
|
return ret
|
|
end
|
|
|
|
local function setreportstatus(rid, newstatus)
|
|
if type(rid) ~= "number" then return false end
|
|
if type(newstatus) ~= "number" then return false end
|
|
|
|
pingdb()
|
|
|
|
return not not SQLConn:execute("UPDATE reports SET status = " .. newstatus .. " WHERE id = " .. rid .. ";")
|
|
end
|
|
|
|
local function getobjcount()
|
|
pingdb()
|
|
local cur = SQLConn:execute("SELECT COUNT(*) FROM objects;")
|
|
if not cur then return nil end
|
|
return cur:fetch()
|
|
end
|
|
|
|
local function gettagcount()
|
|
pingdb()
|
|
local cur = SQLConn:execute("SELECT COUNT(*) FROM tags;")
|
|
if not cur then return nil end
|
|
return cur:fetch()
|
|
end
|
|
|
|
return {
|
|
USER_PRIVS_BANNED = USER_PRIVS_BANNED,
|
|
USER_PRIVS_UNAPPROVED = USER_PRIVS_UNAPPROVED,
|
|
USER_PRIVS_APPROVED = USER_PRIVS_APPROVED,
|
|
USER_PRIVS_MOD = USER_PRIVS_MOD,
|
|
USER_PRIVS_ADMIN = USER_PRIVS_ADMIN,
|
|
|
|
autocomplete = autocomplete,
|
|
searchobjs = searchobjs,
|
|
getobj = getobj,
|
|
objhideid = objhideid,
|
|
objshowid = objshowid,
|
|
isobjhexvalid = isobjhexvalid,
|
|
urltophysical = urltophysical,
|
|
createfile = createfile,
|
|
updatefile = updatefile,
|
|
remfilefromobj = remfilefromobj,
|
|
genobjthumbnail = genobjthumbnail,
|
|
isdisplaynamevalid = isdisplaynamevalid,
|
|
isemailvalid = isemailvalid,
|
|
getuserbyemail = getuserbyemail,
|
|
getuserbyid = getuserbyid,
|
|
userauth = userauth,
|
|
userverify = userverify,
|
|
userregcode = userregcode,
|
|
userregverify = userregverify,
|
|
reguser = reguser,
|
|
tagadd = tagadd,
|
|
regnewobj = regnewobj,
|
|
getownedobjs = getownedobjs,
|
|
objupdate = objupdate,
|
|
updatetags = updatetags,
|
|
b256toreadable = b256toreadable,
|
|
readabletob256 = readabletob256,
|
|
csrf = csrf,
|
|
csrfverify = csrfverify,
|
|
nexttoapproveobj = nexttoapproveobj,
|
|
banuser = banuser,
|
|
approveuser = approveuser,
|
|
delobj = delobj,
|
|
approveobj = approveobj,
|
|
userinfoupdate = userinfoupdate,
|
|
getobjtags = getobjtags,
|
|
addtagstoobj = addtagstoobj,
|
|
remtagsfromobj = remtagsfromobj,
|
|
getmoderators = getmoderators,
|
|
setmodsviaemails = setmodsviaemails,
|
|
getcomments = getcomments,
|
|
postcomment = postcomment,
|
|
addreport = addreport,
|
|
getreportcount = getreportcount,
|
|
getreports = getreports,
|
|
setreportstatus = setreportstatus,
|
|
getobjcount = getobjcount,
|
|
gettagcount = gettagcount,
|
|
}
|