444 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			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
 | 
