ikibooru/obje.html.l
2024-07-18 22:53:44 +03:00

444 lines
14 KiB
Plaintext

{%
local obj, files, usedSpace, tags, tagcount
if DB.isobjhexvalid(request:path():sub(7, 7 + 31)) then
obj = DB.getobj(DB.objshowid(request:path():sub(7, 7 + 31)))
end
function recalcfiles()
local virt = "/objd/" .. DB.objhideid(obj.id) .. "/"
local phys = DB.urltophysical(virt)
files = {}
usedSpace = 0
for f in LFS.dir(phys) do
if f ~= "." and f ~= ".." then
local attribs = LFS.attributes(phys .. f)
table.insert(files, {name = f, size = attribs.size, modtime = attribs.modification, phys = phys .. f, virt = virt .. f})
usedSpace = usedSpace + attribs.size
end
end
table.sort(files, function(a,b)
if a.modtime == b.modtime then
return a.name < b.name
else
return a.modtime < b.modtime
end
end)
end
if obj then
-- !!!CHECK IF OWNER HAPPENS HERE!!!
if verified and (verified.id ~= obj.owner) then
verified = nil
end
recalcfiles()
tags, tagcount = DB.getobjtags(obj.id)
if verified then
obj.sizequota = BigGlobe.cfg.maxtotalobjsize * 1024 -- Temporary
local post = request:post()
if post and post.csrf and DB.csrfverify(verified.id, Escapes.urlunescape(tostring(post.csrf))) then
if post["createfiles"] then
local sztoadd = 0
for fn, sz in post["createfiles"]:gmatch"([^;]+);(%d+)" do
sztoadd = sztoadd + sz
end
if usedSpace + sztoadd > obj.sizequota then
response:statusCode(409)
else
for fn, sz in post["createfiles"]:gmatch"([^;]+);(%d+)" do
DB.createfile(obj.id, Escapes.urlunescape(fn), tonumber(sz))
end
end
return
elseif post["upchu"] then
DB.updatefile(obj.id, post["upchu"], tonumber(post["offset"]), post["data"].data)
return
elseif post["remfiles"] then
for d in post["remfiles"]:gmatch"(%d+)" do
DB.remfilefromobj(obj.id, files[tonumber(d) + 1].name)
end
return
else
recalcfiles()
if tonumber(post.newthumbnail) and files[tonumber(post.newthumbnail)] then
DB.genobjthumbnail(obj.id, files[tonumber(post.newthumbnail)].name, obj.sizequota - usedSpace)
recalcfiles()
end
if post["objname"] then
local newname = Escapes.urlunescape(post["objname"])
local newpublished = usedSpace > 0
if newname ~= obj.name or obj.published ~= newpublished then
if DB.objupdate(obj.id, newname, newpublished) then
obj.name = newname
obj.published = newpublished
end
end
end
if post["objtags"] then
local newtagset = {}
for m in post["objtags"]:gmatch"%d+" do
newtagset[tonumber(m)] = true
end
local tagstoremove = {}
for k,_ in pairs(tags) do
if not newtagset[k] then
table.insert(tagstoremove, k)
end
end
local tagstoadd = {}
for k,_ in pairs(newtagset) do
if not tags[k] then
table.insert(tagstoadd, k)
end
end
DB.remtagsfromobj(obj.id, tagstoremove)
DB.addtagstoobj(obj.id, tagstoadd)
tags, tagcount = DB.getobjtags(obj.id)
end
end
end
end
end
title = BigGlobe.cfg.sitename .. " - Editing " .. (obj and obj.name or "Object not found")
function content() %}
{% if obj then %}
{% if verified then %}
<form method="post" enctype="multipart/form-data" action="#" id="editform">
<div style="display:inline-block;vertical-align:top;width:49%;">
<h2>Editing object</h2>
<input type="hidden" name="csrf" value="{{ Escapes.htmlescape(DB.csrf(verified.id)) }}" />
<div><label>Name: </label><input type="text" name="objname" autocomplete="off" value="{{ Escapes.htmlescape(obj.name) }}" /></div>
<div><p>Once files are uploaded, the object will be considered published.</p></div>
<div><p>Object sized at <strong>{{ (usedSpace + 1023) // 1024 }}kB</strong> out of <strong>{{ (obj.sizequota + 1023) // 1024 }}kB</strong> maximum (<strong>{{math.floor(usedSpace / obj.sizequota * 1000 + 0.5) / 10}}%</strong>) </p></div>
<table style="margin-top:1em"><thead><tr><td>File</td><td>Size</td><td colspan="3">Actions</td></tr></thead><tbody>
{% for idx,f in pairs(files) do %}
<tr>
<td>{{ Escapes.htmlescape(f.name) }}</td>
<td>{{ (f.size + 1023) // 1024 }}kB</td>
<td><input type="checkbox" id="delcb{{ idx }}"><label for="delcb{{ idx }}">Delete</label></td>
</tr>
{% end %}
<tr style="{% if #files >= BigGlobe.cfg.maxfilesperobj then %}display:none;{% end %}"><td><input type="file" /><button type="button" style="margin:0;" onclick="clearfile(this)">Clear</button></td><td></td><td></td></tr>
</tbody></table>
<select name="newthumbnail" style="margin-top: 1em; margin-bottom: 1em; display: block;">
<option value="none" selected>Generate thumbnail from image file...</option>
{% for idx,f in pairs(files) do %}
<option value="{{idx}}">{{ Escapes.htmlescape(f.name) }}</option>
{% end %}
</select>
</div>
<div style="display:inline-block;vertical-align:top;width:49%;">
<h2>Tags</h2>
<div style="position:relative;width:80%;" class="tagbox" data-formid="editform" data-formparaminputid="objtagsparam" data-unknowntags="">
<p{% if tagcount > 0 then %} style="visibility:hidden;"{% end %}>Enter tags...</p>
{% for _, tag in pairs(tags) do %}
<div class="tag tc{{ tag.category }}" data-tagid="{{ tag.id }}">{{ Escapes.htmlescape(tag.name) }}</div>
{% end %}
<span style="position:relative;min-width:4px;left:0;" contenteditable></span>
</div>
<div class="autocomplete" style="visibility:hidden;width:80%;"></div>
<input type="hidden" id="objtagsparam" name="objtags" value="" />
{% if BigGlobe.cfg.enable18plus then %}
<ul class="over18" style="width: 80%;">
<li>
<input type="radio" name="a" value="-1" id="o18h" onchange="upd(false)" />
<label for="o18h">Hide 18+</label>
</li><li>
<input type="radio" name="a" value="0" id="o18s" onchange="upd(true)" />
<label for="o18s">Show 18+</label>
</li>
</ul>
{% end %}
</div>
<div style="text-align:center;">
<input type="submit" value="Submit" />
<progress id="proggers" max="1" value="0" />
</div>
</form>
<div id="newtagsform" class="hidden">
<p>There are unknown tags in your submission. Please assign them categories.</p>
<table>{% --[[
<select style="border: 0;"><option value="a">A</option><option value="b">B</option></select>
]] %}</table>
<button>Submit</button>
</div>
<script>
{% if BigGlobe.cfg.enable18plus then %}
function upd(over18) {
document.querySelector(".tagbox").setAttribute("data-over18", +over18 != -1)
}
var activeo18
if(window.localStorage.getItem("o18")) {
activeo18 = window.localStorage.getItem("o18")
}
if(!activeo18 || activeo18 == 1) {
activeo18 = 0; // Make "Show 18+", not "Only 18+"
}
upd(activeo18)
document.querySelector("ul.over18 input[type=\"radio\"][value=\"" + activeo18 + "\"]").checked = true
{% end %}
var totalfiles = {{ #files }}
function clearfile(el) {
var inp = el.parentElement.querySelector("input")
inp.value = ""
var allofem = Array.from(document.querySelectorAll("input[type='file']"))
var idx = allofem.indexOf(inp)
if(idx != allofem.length - 1) {
// remove row
el.parentElement.parentElement.parentElement.removeChild(el.parentElement.parentElement)
if(totalfiles == {{ BigGlobe.cfg.maxfilesperobj }}) {
allofem[allofem.length - 1].parentElement.parentElement.style.display = ""
}
totalfiles--
}
}
function rebind() {
var v = document.querySelectorAll("input[type='file']")
var last = v[v.length - 1]
last.onchange = function(ev) {
last.onchange = undefined
var tablerow = this.parentElement.parentElement
var clond = tablerow.cloneNode(true)
tablerow.parentElement.appendChild(clond)
clond.querySelector("input").value = ""
totalfiles++
if(totalfiles == {{ BigGlobe.cfg.maxfilesperobj }}) {
clond.style.display = "none"
}
rebind()
}
}
rebind()
var CHUNK_SIZE = 1024 * 512
var files
var totalsizetoupload
var totaluploaded
function send(fileidx, offset) {
var xhr = new XMLHttpRequest()
xhr.open("POST", "#", true)
var sz = Math.min(CHUNK_SIZE, files[fileidx].files[0].size - offset)
var formData = new FormData()
formData.append("csrf", document.querySelector("[name='csrf']").value)
formData.append("upchu", encodeURIComponent(files[fileidx].files[0].name))
formData.append("offset", offset)
formData.append("data", files[fileidx].files[0].slice(offset, offset + sz))
xhr.onreadystatechange = function() {
if(xhr.readyState == XMLHttpRequest.DONE) {
if(xhr.status == 200) {
document.getElementById("proggers").value = totaluploaded / totalsizetoupload
totaluploaded += sz
if(sz < CHUNK_SIZE) {
if(fileidx < files.length - 1) {
send(fileidx + 1, 0)
} else {
var daform = document.getElementById("editform")
for(var i = 0; i < files.length; i++) files[i].disabled = true
daform.submit()
}
} else {
send(fileidx, offset + sz)
}
} else {
send(fileidx, offset)
}
}
}
xhr.send(formData)
}
function testsizes() {
var xhr = new XMLHttpRequest()
xhr.open("POST", "#", true)
var formData = new FormData()
formData.append("csrf", document.querySelector("[name='csrf']").value)
formData.append("createfiles", files.map(function(x) {return [encodeURIComponent(x.files[0].name), x.files[0].size]}).flat().join(";"))
totalsizetoupload = files.map(function(x) {return x.files[0].size}).reduce(function(x,y){return x+y}, 0)
totaluploaded = 0
xhr.onreadystatechange = function() {
if(xhr.readyState == XMLHttpRequest.DONE) {
if(xhr.status == 200) {
send(0, 0)
} else {
alert("Too much space.")
window.location.href = window.location.href.split("#")[0]
}
}
}
xhr.send(formData)
}
function doremoves() {
var xhr = new XMLHttpRequest()
xhr.open("POST", "#", true)
var idxs = []
var remchecks = document.querySelectorAll("#editform input[type='checkbox']")
for(var i = 0; i < remchecks.length; i++) {
if(remchecks[i].checked) idxs.push(i)
}
var formData = new FormData()
formData.append("csrf", document.querySelector("[name='csrf']").value)
formData.append("remfiles", idxs.join(";"))
xhr.onreadystatechange = function() {
if(xhr.readyState == XMLHttpRequest.DONE) {
if(xhr.status == 200) {
if(files.length > 0) {
testsizes()
} else {
document.getElementById("editform").submit()
}
} else {
window.location.href = window.location.href.split("#")[0]
}
}
}
xhr.send(formData)
}
function fixnewtags(afterfunc) {
var newtagsform = document.querySelector("div#newtagsform")
var tbl = newtagsform.querySelector("table")
var newTags = document.querySelectorAll("div.tagbox div.tag.tcNew")
for(var i = 0; i < newTags.length; i++) {
var row = tbl.insertRow(-1)
var sel = document.createElement("select")
{% for tc = 1, #BigGlobe.cfg.tc do if BigGlobe.cfg.tc[tc].name ~= "" then %}
{
var opt = document.createElement("option")
opt.textContent = "{{ Escapes.htmlescape(BigGlobe.cfg.tc[tc].name) }}"
opt.value = {{ tc - 1 }}
sel.appendChild(opt)
}
{% end end %}
var adult = document.createElement("input")
adult.type = "checkbox"
adult.checked = false
adult.id = "boobietc" + i
var adultLbl = document.createElement("label")
adultLbl.htmlFor = adult.id
adultLbl.textContent = "18+"
row.insertCell(-1).appendChild(sel)
row.insertCell(-1).textContent = newTags[i].textContent
var c = row.insertCell(-1)
c.appendChild(adult)
c.appendChild(adultLbl)
}
newtagsform.classList.toggle("hidden")
var btn = newtagsform.querySelector("button")
btn.onclick = function() {
btn.toggleAttribute("disabled")
var xhr = new XMLHttpRequest()
xhr.open("POST", "/addtags", true)
var formData = new FormData()
formData.append("csrf", document.querySelector("[name='csrf']").value)
for(var i = 0; i < newTags.length; i++) {
formData.append("name[]", tbl.rows[i].cells[1].textContent)
formData.append("tc[]", tbl.rows[i].cells[0].querySelector("select").value)
formData.append("adult[]", tbl.rows[i].cells[2].querySelector("input").checked ? "1" : "0")
}
xhr.onreadystatechange = function() {
if(xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
var resp = xhr.responseText.split(",")
// Set data-tagids so they object may be updated with the new tags
for(var i = 0; i < newTags.length; i++) {
newTags[i].setAttribute("data-tagid", resp[i])
}
tagbox_updateformdata()
afterfunc()
}
}
xhr.send(formData);
}
}
document.getElementById("editform").addEventListener("submit", function(ev) {
ev.preventDefault()
files = Array.from(document.querySelectorAll("input[type='file']"))
files.pop() // don't count empty input box
var newTags = document.querySelectorAll("div.tagbox div.tag.tcNew")
if(newTags.length != 0) {
fixnewtags(doremoves)
} else {
doremoves()
}
})
</script>
<script src="/static/tagbox.js"></script>
{% else %}
<p>You are not eligible to edit this object.</p>
{% end %}
{% else %}
<p>Object was not found.</p>
{% end %}
{% end %}
{# base.inc