/* Original Script by cbk1994 Updated by fowlplay4 1. Added work-around for downloading images. No longer need to add anything to folder config. See function getGraphic(img) for more notes on that. 2. Added support for setting transparencies via fiximagetransparency(filepath) 3. Updated naming to be more user-friendly by changing the getUploadFullName() function. Prevents players from using periods in the name however. 4. Added support for hats. 5. Added support for using a different database. 6. Fixed to use V6's new uploadfile() function. */ function onCreated() { this.admins = {"fowlplay4", "cbk1994"}; this.custom_db = "default"; createTable(); } function onActionServerSide(cmd, data, pars) { switch (cmd) { case "requestFunc": temp.funcs = {"getAdminGraphics", "getMyUploads", "getAdmins", "getGraphic"}; if (funcs.index(@ data) <= -1) { printf("Hacker Alert: %s (%s) is attempting to send unrequestable function %s (uploads manager)!", player.communityname, player.account, data); return; } temp.returned = this.(@ data)(pars); if (returned == "msg") { return; } triggerclient("gui", name, "returnFunc", data, returned); break; case "callFunc": temp.funcs = {"doApproveGraphic", "doDenyGraphic", "doGraphicUploaded"}; if (funcs.index(@ data) <= -1) { printf("Hacker Alert: %s (%s) is attempting to send uncallable function %s (uploads manager)!", player.communityname, player.account, data); return; } this.(@ data)(pars); break; } } function getAdmins() { return this.admins; } function isStaff() { return player.account in this.admins; } function doGraphicUploaded(data) { // {filePath, fileName, getUploadFullName(), SupportUpload_Type.getSelectedText(), SupportUpload_Trans.checked} temp.path = data[0]; if (! fileexists(path)) { // client-rc upload? return; } temp.uName = data[1]; temp.fName = data[2].lower(); fName = fName.substring(0, fName.length() - 3); temp.gType = data[3]; temp.trans = (data[4] == true); temp.t = path.tokenize("."); temp.ext = t[t.size() - 1]; fName @= ext; if (fileSize(path) > 400000) { msg("Sorry, but your file must be no larger than 400 KB. Try using PNG 8 or another efficient format."); deletefile(path); return; } temp.okay = isOkay(path, ext, uName); if (okay != true) { msg("You uploaded an invalid file! Please remember that only PNG and GIF images will be accepted."); if (okay == 0) { deletefile(path); } else { // faked header movefile(path, "uploads/illegal/" @ player.account @ "_file" @ int(timevar2) @ "." @ ext); } return; } // check if the file already exists if (levelExists(fName) || headExists(fName) || shieldExists(fName) || bodyExists(fName) || req("SELECT count(*) FROM 'support_uploads' WHERE filename = '" @ fName.escape() @ "' AND status != 'denied'", true)[0][0] > 0) { deletefile(path); return msg("Sorry, a file already exists with that name!"); } temp.loc = "levels/uploads/upload_" @ player.account @ "_" @ int(timevar2) @ "." @ ext; movefile(path, loc); msg("Your file has been submitted successfully to the upload queue!"); // Fix Transparency Functionality if (temp.trans) { fiximagetransparency(loc); } req("INSERT INTO 'support_uploads' VALUES('" @ player.account.escape() @ "', '" @ gType.lower() @ "', '" @ fName.escape() @ "', '" @ loc.escape() @ "', 'pending', '', 0, '')"); } function isOkay(path, ext, fName) { if (! (ext in {"png", "gif"})) { return; } temp.str.loadLines(path); if ((ext == "png" && str.pos("PNG") >= 0) || (ext == "gif" && str.pos("GIF8") >= 0)) { return true; } else { // faked header temp.msg = { format("File Uploads: %s (%s) tried to upload graphic '%s' with a faked header!", player.communityname, player.account, fName), format(" File has been moved to: %s", "uploads/illegal/" @ player.account @ "_file" @ int(timevar2) @ "." @ ext) }; printf(msg[0]); printf(msg[1]); savelog2("uploads.txt", msg[0] @ "\n" @ msg[1]); return 2; } } function doApproveGraphic(gid) { if (! isStaff()) { return msg("You are not staff!"); } temp.file = req("SELECT uploader, type, filename, path, accepted FROM 'support_uploads' WHERE rowid = " @ gid.escape(), true)[0]; temp.uploader = file[0]; temp.gType = file[1]; temp.fName = file[2]; temp.path = file[3]; temp.status = file[4]; if (status) { return; } if (fileExists(path)) { temp.mPath = ""; switch (gType) { case "head": mPath = "levels/heads/"; break; case "body": mPath = "levels/bodies/"; break; case "shield": mPath = "levels/shields/"; break; case "hat": mPath = "levels/hats/"; break; } moveFile(path, mPath @ fName); } req("UPDATE 'support_uploads' SET 'accepted' = 1, admin = '" @ player.account.escape() @ "', status = 'accepted' WHERE rowid = " @ gid.escape()); } function doDenyGraphic(data) { if (! isStaff()) { return msg("You are not staff!"); } temp.gid = data[0]; temp.reason = data[1]; temp.file = req("SELECT path, status FROM 'support_uploads' WHERE rowid = " @ gid.escape(), true)[0]; temp.path = file[0]; temp.status = file[1]; if (status != "pending") { return; } if (fileExists(path)) { deletefile(path); } req("UPDATE 'support_uploads' SET 'accepted' = 0, admin = '" @ player.account.escape() @ "', status = 'denied', reason = '" @ reason.escape() @ "' WHERE rowid = " @ gid.escape()); } function getMyUploads() { // return {pending, approved, denied} // which are in form {id, type, upload name, admin, reason, path} temp.pending = req("SELECT rowid, type, filename, admin, reason, path FROM 'support_uploads' WHERE uploader = '" @ player.account.escape() @ "' AND status = 'pending'", true); temp.approved = req("SELECT rowid, type, filename, admin, reason, path FROM 'support_uploads' WHERE uploader = '" @ player.account.escape() @ "' AND status = 'accepted'", true); temp.denied = req("SELECT rowid, type, filename, admin, reason, path FROM 'support_uploads' WHERE uploader = '" @ player.account.escape() @ "' AND status = 'denied'", true); return {pending, approved, denied}; } function getGraphic(img) { // Work-around for Folder Config Modification // Basically so players can't use the files in // the uploads folder as hats before they've been // approved. Clients probably need V6 in order to // view them properly. temp.filedata.loadstring("levels/uploads/" @ img); temp.filedata = base64encode(temp.filedata); return {img, temp.filedata}; } function getAdminGraphics() { return req("SELECT rowid, type, filename, path, uploader FROM 'support_uploads' WHERE status = 'pending' ORDER BY type", true); } function createTable() { // support_uploads req("CREATE TABLE IF NOT EXISTS 'support_uploads' ( uploader TEXT NOT NULL DEFAULT '', type TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', status TEXT NOT NULL DEFAULT 'pending', admin TEXT NOT NULL DEFAULT '', accepted INT NOT NULL DEFAULT 0, reason TEXT NOT NULL DEFAULT '' )"); req("CREATE INDEX IF NOT EXISTS 'idx_support_uploads_uploader' ON 'support_uploads' (uploader)"); } // SQL stuff function req(request, wait) { temp.req = requestsql2(this.custom_db, request, wait); if (req.error != "") { errorSql(req.error, request); } if (wait == 0) { return; } if (! req.completed) { waitfor(req, "onReceiveData", 60); } return req.rows; } function errorSql(error, query) { echo("SQL Error:" SPC error); echo(" Query:" SPC query); savelog2("sqlerror.txt", "SQL Error:" SPC error @ "\n Query:" SPC query); } // Dialog function msg(msg) { triggerclient("gui", name, "showDialog", msg); return "msg"; } //#CLIENTSIDE function onCreated() { initProfiles(); requestServer("getAdmins"); } function onKeyPressed(code, key, id) { if (code == 122) { // F11 showMainWindow(); } } // Serverside Interaction function requestServer(func, data) { triggerserver("gui", name, "requestFunc", func, data); } function tellServer(func, data) { triggerserver("gui", name, "callFunc", func, data); } function onActionClientSide(cmd, func, data) { switch (cmd) { case "showDialog": showDialog(func); break; case "returnFunc": this.funcReturned(func, data); break; } } function funcReturned(func, data) { switch (func) { case "getAdmins": this.admins = data; break; case "getMyUploads": showMyUploads(data[0], data[1], data[2]); break; case "getAdminGraphics": showAdminGraphics(data); break; case "getGraphic": temp.filedata = base64decode(data[1]); temp.filedata.savestring("uploads/" @ data[0], 0); break; } } // GUI Profiles function initProfiles() { new GuiTextProfile("SupportTextProfile") { modal = false; fontColor = {0, 0, 0}; } } // Interfaces function showMainWindow() { if (isObject("SupportMain_Window")) { SupportMain_Window.destroy(); // destroy if open } new GuiWindowCtrl("SupportMain_Window") { profile = "GuiBlueWindowProfile"; visible = canClose = canMove = canMinimize = true; canResize = canMaximize = false; text = getServerName() @ " Upload Manager [F11]"; showTop(); temp.options = { {"upload", "Upload Graphics", "Submit heads, bodies, and shields to be added to the game."}, {"viewuploads", "View Uploads", "View pending and uploaded graphics you've submitted."} }; if (player.account in thiso.admins) { options.add({"viewu", "Manage Uploads", "Manage uploaded heads, shields, and bodies."}); } width = 19 + (141 * min(3, options.size())); // draw main frame with (addBar("SupportMain_MainFrame", 0, true)) { profile.fillColor = {179, 199, 226, 200}; x = 10; y = 28; width = SupportMain_Window.width - 20; height = 45; new GuiMLTextCtrl("SupportMain_MainFrame_Text") { profile = "SupportTextProfile"; x = 5; y = 2; width = SupportMain_Window.width - 30; text = "
" @ getServerName() @ " Upload Manager
Click one of the options below.
" @ option[1] @ "
" @ option[2] @ "
Warning:
Uploading obscene, indecent, stolen, or copyrighted images will result in a jail or ban.
No stolen, recolored, or copyrighted graphics\nNo heads with hats that exist\nNo invisible or mostly transparent graphics
"; } } with (addBar("SupportUpload_Bar2", 2)) { x = 6; y = startY; width = 238; height = 25; startY += height; new GuiMLTextCtrl("SupportUpload_TypeLabel") { profile = "SupportTextProfile"; x = 5; y = 5; width = 228; text = "Type:"; } new GuiPopUpMenuCtrl("SupportUpload_Type") { profile = "GuiBluePopUpMenuProfile"; textprofile = "GuiBlueTextListProfile"; scrollprofile = "GuiBlueScrollProfile"; width = 197; height = 21; x = 38; y = 2; clearRows(); temp.types = {"Head", "Body", "Shield", "Hat"}; for (temp.t : types) { addRow(0, t); } setSelectedRow(0); } } with (addBar("SupportUpload_Bar3", 3)) { x = 6; y = startY; width = 238; height = 25; startY += height; new GuiMLTextCtrl("SupportUpload_NameLabel") { profile = "SupportTextProfile"; x = 5; y = 5; width = 228; text = "Name:"; } new GuiTextEditCtrl("SupportUpload_Name") { profile = "GuiBlueTextEditProfile"; width = 197; height = 21; x = 38; y = 2; clearRows(); text = "my-graphic"; } } with (addBar("SupportUpload_Bar8", 4)) { x = 6; y = startY; width = 238; height = 25; startY += height; new GuiCheckBoxCtrl("SupportUpload_Trans") { profile = "GuiBlueCheckBoxProfile"; useownprofile = true; profile.fontcolor = "black"; width = 197; height = 21; x = 38; y = 2; clearRows(); text = "Set Transparencies"; checked = false; } } with (addBar("SupportUpload_Bar4", 5)) { x = 6; y = startY; width = 238; height = 58; startY += height; new GuiMLTextCtrl("SupportUpload_NameWarning") { profile = "SupportTextProfile"; x = 5; y = 5; width = 228; text = "Set Transparencies makes the transparent color as the same color in the top left corner of the graphic.
"; } } with (addBar("SupportUpload_Bar5", 6)) { x = 6; y = startY; width = 238; height = 25; startY += height; new GuiMLTextCtrl("SupportUpload_FullName") { profile = "SupportTextProfile"; x = 5; y = 5; width = 228; } } with (addBar("SupportUpload_Bar7", 7)) { x = 6; y = startY; width = 238; height = 25; startY += height; new GuiButtonCtrl("SupportUpload_Browse") { profile = "GuiBlueButtonProfile"; width = 248; height = 26; x = (- 5); y = 0; text = "Browse"; } } } } function FileSelector_Window.onCloseQuery() { filesClosed(); } function FileSelector_CancelButton.onAction() { filesClosed(); } function filesClosed() { if (SupportUpload_Browse.active == false && SupportUpload_Window.visible) { SupportUpload_Browse.active = true; SupportUpload_Window.active = true; } } function SupportUpload_Private.onAction() { updateFullName(); } function SupportUpload_Type.onSelect(z, text) { if (text != "Head") { SupportUpload_Private.active = false; SupportUpload_Private.alpha = .6; } else { SupportUpload_Private.active = true; SupportUpload_Private.alpha = 1; } updateFullName(); } function SupportUpload_Name.onTextChanged() { updateFullName(); } function updateFullName() { SupportUpload_FullName.text = "" @ getUploadFullName() @ "
"; } function SupportUpload_Browse.onAction() { SupportUpload_Window.active = false; SupportUpload_Browse.active = false; playerUploadFile(); } function onPlayerFileUploaded(fileName, filePath) { if (SupportUpload_Browse.active == false && SupportUpload_Window.visible) { tellServer("doGraphicUploaded", {filePath, fileName, getUploadFullName(), SupportUpload_Type.getSelectedText(), SupportUpload_Trans.checked}); SupportUpload_Window.destroy(); } } function getUploadPrefix(gType, gName) { temp.tokens = getServerName().lower().tokenize(); temp.svr = tokens[0]; switch (gType) { case "Head": temp.prefix = svr @ "_head-"; break; case "Body": temp.prefix = svr @ "_body-"; break; case "Shield": temp.prefix = svr @ "_shield-"; break; case "Hat": temp.prefix = svr @ "_hat-"; break; } return gName.starts(temp.prefix) ? "" : temp.prefix; } function getUploadFullName() { temp.gType = SupportUpload_Type.getSelectedText(); temp.gName = SupportUpload_Name.text; temp.gName = temp.gName.substring(0, temp.gName.pos(".")); temp.fullname = getUploadPrefix(gType, gName) @ gName @ ".ext"; return temp.fullname; } function playerUploadFile() { player.waitingForUpload = true; requestText("folder", "PERSONAL"); FileSelector_Window.requestscript = this.name; temp.file = selectFileForUpload(); } function onSelectedFileForUpload(fullfilename) { if (FileSelector_Window.requestscript==this.name) uploadfile(fullfilename); } function onFolderLog(msg) { if (! player.waitingForUpload) { return; } if (! msg.starts("Uploaded")) { return; } player.waitingForUpload = false; temp.filePath = msg.substring(msg.starts("Uploaded file") ? 14 : 18); if (msg.starts("Uploaded big")) { filePath = filePath.substring(0, filePath.length() - 1); } temp.parts = filePath.tokenize("/"); temp.fileName = parts[parts.size() - 1]; this.trigger("onPlayerFileUploaded", fileName, filePath); } function showMyUploads(pending, approved, denied) { if (isObject("SupportMyUploads_Window")) { SupportMyUploads_Window.destroy(); } new GuiWindowCtrl("SupportMyUploads_Window") { profile = "GuiBlueWindowProfile"; width = 300; height = 230; x = GraalControl.width / 2 - (width / 2); y = GraalControl.height / 2 - (height / 2); canMinimize = canClose = visible = true; canMaximize = canResize = false; text = "My Uploads"; temp.tabs = null; new GuiTabCtrl("SupportMyUploads_Tabs") { profile = "GuiBlueTabProfile"; width = 270; height = 23; tabwidth = 88; x = 15; y = 27; clearRows(); tabs.add(this.addRow(0, "Pending")); tabs.add(this.addRow(0, "Approved")); tabs.add(this.addRow(0, "Denied")); } temp.c = 0; for (temp.tab : {pending, approved, denied}) { new GuiScrollCtrl("SupportMyUploads_Scroll_" @ c) { profile = "GuiBlueScrollProfile"; useownprofile = true; profile.border = 1; x = 10; y = 49; width = 280; height = 172; tabs[c].scroll = this; visible = false; vScrollBar = "alwaysOff"; hScrollBar = "alwaysOff"; temp.par = this; new GuiMLTextCtrl("SupportMyUploads_" @ c @ "_Info") { profile = "GuiBlueMLTextProfile"; width = 145; x = 130; y = 2; text = "\n\n\n