From 0871fde1dcebeab44e723f09a272f0be6a1b72fc Mon Sep 17 00:00:00 2001 From: Chuck Scott Date: Tue, 16 Jan 2018 12:16:40 -0500 Subject: [PATCH] Added "File Library" main Associate menu option. Updated database with file_library and file_library_categories tables (the later is not yet in use). Copied code from js/imageUpload to js/fileLibraryUpload and modified to serve for the File Library. Created models and views to support new feature. --- classes/data/dataFileLibrary.php | 181 +++++++++ classes/data/settings/dataSettingsGeneral.php | 9 +- defines.php | 2 + index.php | 2 +- js/fileLibraryUpload/fileLibraryUpload.css | 203 ++++++++++ js/fileLibraryUpload/fileLibraryUpload.js | 365 ++++++++++++++++++ models/admin/ajax/fileLibraryUpload.php | 258 +++++++++++++ models/admin/fileLibrary/index.php | 129 +++++++ setup/adminMenus.php | 12 + ...1.1.32.sql => create_database_V1.1.33.sql} | 28 ++ setup/databaseScripts/dbVersions.php | 3 +- ..._V1.1.32.sql => drop_database_V1.1.33.sql} | 4 +- .../update_database_V1.1.33.sql | 36 ++ setup/validActions.php | 4 + views/admin/fileLibrary/index.html | 149 +++++++ views/admin/management/index.html | 10 +- 16 files changed, 1390 insertions(+), 5 deletions(-) create mode 100644 classes/data/dataFileLibrary.php create mode 100644 js/fileLibraryUpload/fileLibraryUpload.css create mode 100644 js/fileLibraryUpload/fileLibraryUpload.js create mode 100644 models/admin/ajax/fileLibraryUpload.php create mode 100644 models/admin/fileLibrary/index.php rename setup/databaseScripts/{create_database_V1.1.32.sql => create_database_V1.1.33.sql} (95%) rename setup/databaseScripts/{drop_database_V1.1.32.sql => drop_database_V1.1.33.sql} (89%) create mode 100644 setup/databaseScripts/update_database_V1.1.33.sql create mode 100644 views/admin/fileLibrary/index.html diff --git a/classes/data/dataFileLibrary.php b/classes/data/dataFileLibrary.php new file mode 100644 index 00000000..ecd1c4e7 --- /dev/null +++ b/classes/data/dataFileLibrary.php @@ -0,0 +1,181 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataFileLibrary.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +/** + * EventManagementDataFileLibrary class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataFiles.php,v 1.0 2011/01/25 19:31:47 cscott + * Exp $ + */ +class GlmDataFileLibrary extends GlmDataAbstract +{ + + /** + * WordPress Database Object + * + * @var $wpdb + * @access public + */ + public $wpdb; + /** + * Plugin Configuration Data + * + * @var $config + * @access public + */ + public $config; + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter + * functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d + * database connection + * + * @return void + * @access public + */ + function __construct ($wpdb, $config) + { + + // If this class is not being extended along with existing $wpdb and $config + if (!$this->wpdb) { + + // Save WordPress Database object + $this->wpdb = $wpdb; + + // Save plugin configuration object + $this->config = $config; + + } + + /* + * Table Name + */ + $this->table = GLM_MEMBERS_PLUGIN_DB_PREFIX . 'file_library'; + + /* + * Table Data Fields + */ + $this->fields = array( + + 'id' => array( + 'field' => 'id', + 'type' => 'integer', + 'view_only' => true, + 'use' => 'a' + ), + + // Original file name + 'name' => array( + 'field' => 'name', + 'type' => 'text', + 'use' => 'a' + ), + + // File Name + 'file_name' => array( + 'field' => 'file_name', + 'type' => 'text', + 'use' => 'a' + ), + + // Description + 'descr' => array( + 'field' => 'descr', + 'type' => 'text', + 'use' => 'a' + ), + + // Title + 'title' => array( + 'field' => 'title', + 'type' => 'text', + 'use' => 'a' + ), + + // Last Access time + 'last_access_time' => array( + 'field' => 'last_access_time', + 'type' => 'datetime', + 'use' => 'a' + ) + + ); + + } + + /** + * Entry Post Processing Call-Back Method + * + * Perform post-processing for all result entries. + * + * In this case we're using it to append an array of category + * data to each member result and also sort by member name. + * + * @param array $r Array of field result data for a single entry + * @param string $a Action being performed (l, i, g, ...) + * + * @return object Class object + * + */ + public function entryPostProcessing( $r, $a ) + { + + if (in_array($a, array('l','g'))) { + + $r['link_url'] = GLM_MEMBERS_WORDPRESS_FILE_LIBRARY_URL.$r['file_name']; + } + + return $r; + } + +} diff --git a/classes/data/settings/dataSettingsGeneral.php b/classes/data/settings/dataSettingsGeneral.php index d42854e0..98aa1b8e 100644 --- a/classes/data/settings/dataSettingsGeneral.php +++ b/classes/data/settings/dataSettingsGeneral.php @@ -157,7 +157,14 @@ class GlmDataSettingsGeneral extends GlmDataAbstract 'type' => 'checkbox', 'use' => 'a' ), - + + // Enable File Library Menu + 'file_library' => array( + 'field' => 'file_library', + 'type' => 'checkbox', + 'use' => 'a' + ), + // Google Maps API Key 'google_maps_api_key' => array( 'field' => 'google_maps_api_key', diff --git a/defines.php b/defines.php index b3bd2c50..3b6ed84c 100644 --- a/defines.php +++ b/defines.php @@ -79,11 +79,13 @@ define('GLM_MEMBERS_PLUGIN_LIB_PATH', GLM_MEMBERS_PLUGIN_PATH.'/lib'); define('GLM_MEMBERS_PLUGIN_MEDIA_PATH', $WPUploadDir['basedir'].'/'.GLM_MEMBERS_PLUGIN_SLUG); define('GLM_MEMBERS_PLUGIN_IMAGES_PATH', GLM_MEMBERS_PLUGIN_MEDIA_PATH.'/images'); define('GLM_MEMBERS_PLUGIN_FILES_PATH', GLM_MEMBERS_PLUGIN_MEDIA_PATH.'/files'); +define('GLM_MEMBERS_PLUGIN_FILE_LIBRARY_PATH', GLM_MEMBERS_PLUGIN_MEDIA_PATH.'/fileLibrary'); define('GLM_MEMBERS_PLUGIN_CONFIG_PATH', GLM_MEMBERS_PLUGIN_PATH.'/config'); $pluginsPath = str_replace(GLM_MEMBERS_PLUGIN_SLUG, '', GLM_MEMBERS_PLUGIN_PATH); define('GLM_MEMBERS_WORDPRESS_PLUGIN_PATH', $pluginsPath); define('GLM_MEMBERS_WORDPRESS_PLUGIN_URL', WP_PLUGIN_URL); +define('GLM_MEMBERS_WORDPRESS_FILE_LIBRARY_URL', GLM_MEMBERS_PLUGIN_MEDIA_URL.'/fileLibrary/'); // Database defines global $wpdb; diff --git a/index.php b/index.php index 642ee22a..4585dedf 100644 --- a/index.php +++ b/index.php @@ -45,7 +45,7 @@ if (!defined('ABSPATH')) { */ define('GLM_MEMBERS_PLUGIN_VERSION', '2.10.20'); -define('GLM_MEMBERS_PLUGIN_DB_VERSION', '1.1.32'); +define('GLM_MEMBERS_PLUGIN_DB_VERSION', '1.1.33'); // Check if plugin version is not current in WordPress option and if needed updated it if (GLM_MEMBERS_PLUGIN_VERSION != get_option('glmMembersDatabasePluginVersion')) { diff --git a/js/fileLibraryUpload/fileLibraryUpload.css b/js/fileLibraryUpload/fileLibraryUpload.css new file mode 100644 index 00000000..4337ba9a --- /dev/null +++ b/js/fileLibraryUpload/fileLibraryUpload.css @@ -0,0 +1,203 @@ +.glm-fileLibraryDropContainer +{ + position: relative; + text-align: center; + padding: 0 1em 1em 1em; + background-color: #eee; + border: 2px solid #ccc; + border-radius: 7px; + cursor: default; + margin-left: auto; + margin-right: auto; + margin-bottom: 1em; + width: 50%; + height: 2em; +} +.glm-fileLibraryDrop +{ + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + z-index: 10; + border-radius: 7px; + height: 100%; + background-color: #000; + opacity: .0; + filter: alpha(opacity=0); /* For IE8 and earlier */ + +} +.glm-fileLibraryDropText +{ + color: #666; + z-index: 9; +} +.glm-noFileDropText +{ + color: #666; +} +.glm-fileLibraryItemHidden +{ + display: none; + z-index: 9; +} +.glm-fileLibraryDropDragOver +{ + border: 2px solid #000 important; + background-color: #fff; +} +.glm-fileLibraryUploadStatus +{ + position: absolute; + width: 100%; + height: 100%; + top: 20px; + left: 10px; + z-index: 11; + border: 2px solid black; + border-radius: 7px; + height: 8rem; + background-color: #fff; + box-shadow: 10px 10px 5px grey; + padding: 1rem; +} + +.glm-statusTable +{ + width: 100%; +/* table-layout: fixed; */ + line-height: 80%; +} +.glm-statusPrompt +{ + width: 10%; + padding: 0px; + font-weight: bold; + text-align: right; +} +.glm-statusValue +{ + width: 65%; + padding: 0px; + text-align: left; +} +.glm-progressBarContainer +{ + height: 100%; + width: 95%; + background-color: #ccc; + border: 1px solid black; + line-height: 1em; +} +.glm-progressBar +{ + height: 1em; + background-color: red; + width: 0%; +} + +/* Files */ +.glm-fileLibraryContainer +{ + margin: .5em 1em 1em 1em; + padding: .5em; + border: 2px solid #ccc; + text-align: center; + width: 90%; +} + +.glm-fileLibraryDrop +{ + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + z-index: 10; + border-radius: 7px; + height: 100%; + background-color: #000; + opacity: .0; + filter: alpha(opacity=0); /* For IE8 and earlier */ + +} +.glm-fileLibraryDropText +{ + color: #666; + z-index: 9; +} +.glm-noFileDropText +{ + color: #666; +} +.glm-fileLibraryItemHidden +{ + display: none; + z-index: 9; +} +#glm-table-files { + width: 90%; +} +.glm-fileLibraryDropDragOver +{ + border: 2px solid #000 important; + background-color: #fff; +} +/*.glm-fileLibraryData { + width: 70%; + float: right; +} +.glm-fileLibrary { + width: 30%; + float: left; +}*/ +.glm-statusTable +{ + width: 100%; +/* table-layout: fixed; */ + line-height: 80%; +} +.glm-statusPrompt +{ + width: 10%; + padding: 0px; + font-weight: bold; + text-align: right; +} +.glm-statusValue +{ + width: 65%; + padding: 0px; + text-align: left; +} +.glm-statusFileTD +{ + max-width: 100%; + overflow: hidden; + padding: 13px; + display: table-cell; + vertical-align: middle; +} +.glm-statusFileContainer +{ + display: block; + width: 100px; + height: 100%; +} +.glm-statusFileContainer img +{ + position: absolute; + top: 0px; + right: 0px; + bottom: 0px; + left: 0px; + /* Maintain aspect ratio */ + max-height:100%; + max-width: 100%; +} + +.glm-file-library-table-left +{ + text-align: left; +} diff --git a/js/fileLibraryUpload/fileLibraryUpload.js b/js/fileLibraryUpload/fileLibraryUpload.js new file mode 100644 index 00000000..bec4ed6d --- /dev/null +++ b/js/fileLibraryUpload/fileLibraryUpload.js @@ -0,0 +1,365 @@ +/* + * Gaslight Media HTML5 Image Upload Support for glm-member-db plugin. + * + * Author: Chuck Scott + * + * Developed from information in + * http://www.sitepoint.com/html5-file-drag-and-drop/ + * http://hayageek.com/drag-and-drop-file-upload-jquery/ + * + * See also the following methods in classes/data/dataImages.php in this plugin. + * galleryPositionOrder() + * galleryImageDataUpdate() + * + */ + +jQuery(document).ready(function($) { + + var drop; + var fileDrop; + var recordID; + var refType; + var recordID; + var maxFileSize; + var allowedTypes; + var files; + var uploadStatusTemplate; + var imageDataTemplate; + var galleryImages; + var galleryFiles; + var newImageAdded = false; + var enableDraggable = true; + var statusArea = false; + + // Setup Drag and Drop when Add + if (window.File && window.FileList && window.FileReader) { + + // is XHR2 available? + var xhr = new XMLHttpRequest(); + if (xhr.upload) { + + // Change from Drag/Drop not supported to drop here text + $('.glm-fileLibraryBrowseButton').addClass('glm-fileLibraryItemHidden'); + $('.glm-fileLibraryDropText').removeClass('glm-fileLibraryItemHidden'); + $('.glm-fileLibraryDrop').removeClass('glm-fileLibraryItemHidden'); + + // Prevent dropping on the document + $(document).on('dragenter', function (e) { + e.stopPropagation(); + e.preventDefault(); + }); + $(document).on('dragover', function (e) { + e.stopPropagation(); + e.preventDefault(); + }); + $(document).on('drop', function (e) { + e.preventDefault(); + }); + + // For each file drop area on the page + $('.glm-fileLibraryDrop').each(function() { + fileDrop = $(this); + initFileDrop(); + }); + + } else { + alert('Your Web browser does not support "Drag & Drop" uploads using "XHR2".\nThat capability is required to upload images for the image gallery on this page.\nConsider upgrading your browser.'); + } + + } + + // Setup a File fileDrop area + function initFileDrop() { + + maxFileSize = fileDrop.attr("data-maxFileSizeKB") * 1000; + allowedTypes = fileDrop.attr("data-allowedTypes"); + + uploadStatusTemplate = fileDrop.children('.glm-fileLibraryUploadStatusTemplate').html(); + galleryFiles = $('#glm-newFileContainer'); + + // Change fileDrop destination appearance only when dragging over a file. + fileDrop.on('dragenter', function(e){ + e.stopPropagation(); + e.preventDefault(); + fileDrop.parent().addClass('glm-fileLibraryDropDragOver'); + }); + fileDrop.on('dragover', function(e){ + e.stopPropagation(); + e.preventDefault(); + }); + fileDrop.on('dragleave', function(e){ + e.stopPropagation(); + e.preventDefault(); + fileDrop.parent().removeClass('glm-fileLibraryDropDragOver'); + }); + + // File fileDrop action + $('.glm-fileLibraryDrop').on('drop', function (e) { + e.preventDefault(); + files = e.originalEvent.dataTransfer.files; + handleFileOnlyDrop(); + fileDrop.parent().removeClass('glm-fileLibraryDropDragOver'); + }); + } + + /* + * This function sets up AJAX processing of the list of files. It then fires + * off the processFile() function to do the first file. When the AJAX call + * in sendFileToServer() completes, the complete: function will call + * processFile() again to do the next file, if one exists. + */ + var thisFile = 0; + var numbFiles = 0; + + /* + * This function sets up AJAX processing for just files and not images + */ + function handleFileOnlyDrop() { + + // Reset file pointer and set number of last file + thisFile = 0; + numbFiles = files.length; + + // Process only Files + processOnlyFiles(); + } + + function processOnlyFiles() { + + // If we still have files to process + if (thisFile < numbFiles) { + file = files[thisFile]; + + // Setup field pairs for sending in request + var fd = new FormData(); + + // Add file upload information + fd.append('file', file); + + /* + * Add "action" post parameter specifying where WordPress should + * route the request. In this case we are routing this AJAX request + * to the admin controller glmMembersAdminAjax() method which will + * route the request to the proper file in the models/admin/ajax + * directory of this plugin. + * + * see "add_action( 'wp_ajax_glm_members_admin_ajax',...." in admin + * controller. + */ + fd.append( 'action', 'glm_members_admin_ajax' ); + + // Tell admin controller where to route the AJAX call. + // (models/admin/ajax/fileUpload.php) + fd.append( 'glm_action', 'fileLibraryUpload' ); + + // Setup status display area + var status = new createStatusbar(file, thisFile, numbFiles, true); + + statusArea.fadeIn( function() { + + // Check image size and alert the user if it's too big + if (file.size > maxFileSize) { + + alert("This file is too large to process.\n\nMaximum image size is " + (maxFileSize/1000) + "KB."); + statusArea.fadeOut(); + processOnlyFiles(); + + // Check the image mime type and alert the user if it's not + // permitted + } else if (allowedTypes.indexOf(file.type) < 0) { + + alert("The file is not an accepted type.\nTo use this file, consider resaving it as a different file type.\n"); + statusArea.fadeOut(); + processOnlyFiles(); + + } else { + + // When status has faded in, Send the files + sendFileToServer(fd, status); + + } + + }); + + thisFile++; + + } + + } + + function createStatusbar(file, thisFile, numbFiles, onlyFile) + { + var statusDone = false; + + /* + * We need to redefine these values inside this function so the + * reader.onload function can see them. + */ + var curFile = thisFile + 1; + var lastFile = numbFiles; + + // Get status area for this drop area + statusArea = fileDrop.siblings('.glm-fileLibraryUploadStatus'); + + // Make status area visible (overlay) and clear contents + statusArea.html(''); + + // Create HTML5 file reader and load image + var reader = new FileReader(); + reader.onload = function (e) { + + // Using a copy of the supplied template, add file information + // to statusbar + statusbar = uploadStatusTemplate; + if ( !( onlyFile ) ) { + statusbar = statusbar.replace('bust-stupid-ngg-image-selection', 'img'); + } + statusbar = statusbar.replace('{ thisFile }', curFile); + statusbar = statusbar.replace('{ numbFiles }', lastFile); + statusbar = statusbar.replace('{ fileImage }', e.target.result); + statusbar = statusbar.replace('{ fileName }', file.name); + statusbar = statusbar.replace('{ fileType }', file.type); + + // Fix up file size string and replace that + var sizeStr=""; + var sizeKB = file.size/1024; + if(parseInt(sizeKB) > 1024) + { + var sizeMB = sizeKB/1024; + sizeStr = sizeMB.toFixed(2)+" MB"; + } + else + { + sizeStr = sizeKB.toFixed(2)+" KB"; + } + + // If a large file, notify user it will take time. + if (file.size > 100000 && file.type == 'image/png') { + sizeStr += ' -- NOTE: Processing for this image may be slow!'; + } + + statusbar = statusbar.replace('{ fileSize }', sizeStr); + + // Assign the HTML to the status area + statusArea.html(statusbar); + + } + reader.readAsDataURL(file); + + this.setProgress = function(progress) + { + statusArea.find('.glm-progressBar').css('width', progress + '%'); + } + + this.setAbort = function(jqxhr) + { + var sb = this.statusbar; + if ( !( onlyFile ) ) { + $('#imageUploadCancel').click(function() + { + jqxhr.abort(); + sb.hide(); + }); + } else { + $('#fileUploadCancel').click(function() + { + jqxhr.abort(); + sb.hide(); + }); + } + } + } + + /* + * Uploads the image via AJAX submission targeting WordPress AJAX + * handler. + */ + function sendFileToServer(fd, status) + { + + // Send one (or more) images to the server. Normally only one image here for now. + var jqXHR=$.ajax({ + xhr: function() { + var xhrobj = $.ajaxSettings.xhr(); + if (xhrobj.upload) { + xhrobj.upload.addEventListener('progress', function(event) { + + // calculate progress periodically and set the progress bar + var percent = 0; + var position = event.loaded || event.position; + var total = event.total; + if (event.lengthComputable) { + percent = Math.ceil(position / total * 100); + } + status.setProgress(percent); + }, false); + + } + return xhrobj; + }, + url: ajaxurl, + type: "POST", + contentType:false, + processData: false, + cache: false, + data: fd, + success: function(data){ + + // Parse returned data + fileData = JSON.parse(data); + + // Check for success + if (fileData.status) { + + // Add files(s) to files display + for ( var i = 0; i < fileData.files.length; i++ ) { + // Using a copy of the supplied template, add file information + fData = $('#glm-fileLibraryDataTemplate').html(); + fData = fData.replace(/{ id }/g, fileData.files[i].id); + fData = fData.replace(/\{ filename \}/g, fileData.files[i].newFileName); + fData = fData.replace(/\{ fileurl \}/g, fileData.files[i].newFileUrl); + fData = fData.replace(/\{ newfilename \}/g, fileData.files[i].newFileName); + $('#glm-newFileContainer').prepend(fData); + $('.glm-NewFileHidden').removeClass('glm-fileLibraryItemHidden'); + + // Enable the fields that were just added + $("#" + fileData.files[i].id + " input, #" + fileData.files[i].id + " textarea").removeAttr('disabled'); + + // Prepend file ID to position order input field + $("#filePositionOrder").val(fileData.files[i].id + ',' + $("#filePositionOrder").val()); + } + + } else { + alert("Upload Failed\nReason: " + fileData.message); + } + + }, + complete: function() { + + // When status area has faded + statusArea.fadeOut( function() { + processOnlyFiles(); + }); + + } + }); + + return jqXHR; + + } + + // Copy an element to the clipboard + function copyToClipboard(text) { + var $temp = $(""); + $("body").append($temp); + $temp.val(text).select(); + document.execCommand("copy"); + $temp.remove(); + } + + $('body').on('click', '.glm-file-library-copy', function(e) { + copyToClipboard($(this).attr('data-link')); + }); + + +}); diff --git a/models/admin/ajax/fileLibraryUpload.php b/models/admin/ajax/fileLibraryUpload.php new file mode 100644 index 00000000..0281dde9 --- /dev/null +++ b/models/admin/ajax/fileLibraryUpload.php @@ -0,0 +1,258 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @version 0.1 + */ + +// Load Members data abstract +require_once GLM_MEMBERS_PLUGIN_CLASS_PATH.'/data/dataFileLibrary.php'; + +/* + * This class performs the work of handling images passed to it via + * an AJAX call that goes through the WorPress AJAX Handler. + * + */ +class GlmMembersAdmin_ajax_fileLibraryUpload extends GlmDataFileLibrary +{ + + /** + * WordPress Database Object + * + * @var $wpdb + * @access public + */ + public $wpdb; + /** + * Plugin Configuration Data + * + * @var $config + * @access public + */ + public $config; + + /* + * Constructor + * + * This contructor sets up this model. At this time that only includes + * storing away the WordPress data object. + * + * @return object Class object + * + */ + public function __construct ($wpdb, $config) + { + + // Save WordPress Database object + $this->wpdb = $wpdb; + + // Save plugin configuration object + $this->config = $config; + + // Run constructor for members data class + parent::__construct(false, false); + + } + + /* + * Perform Model Action + * + * This modelAction takes an AJAX image upload and stores the image in the + * media/images directory of the plugin. + * + * This model action does not return, it simply does it's work then calls die(); + * + * @param $actionData + * + * Echos JSON string as response and does not return + */ + public function modelAction ($actionData = false) + { + + $return = array( + 'status' => false, // Assume we didn't get files or nothing works + 'files' => false, // Provide submitted data along with stored image data + 'message' => '' + ); + +/* + // Check for valid refType - See validActions in Admin Controller + if (!isset($_REQUEST['glm_refType']) || !isset($this->config['ref_type_table'][$_REQUEST['glm_refType']])) { + $return['message'] = 'Invalid target table does not exists!'; + echo json_encode($return); + die(); + } + $refType = $_REQUEST['glm_refType']; + $refTable = $this->config['ref_type_table'][$_REQUEST['glm_refType']]; +*/ + + // Check for uploaded files + if (!isset($_FILES) || count($_FILES) == 0) { + $return['message'] = 'No image file provided!'; + echo json_encode($return); + die(); + } + +/* + // Check for valid target record ID + if (!isset($_REQUEST['glm_refDest']) || ($_REQUEST['glm_refDest']-0) <= 0) { + $return['message'] = 'Invalid target ID!'; + echo json_encode($return); + die(); + } + $refDest = ($_REQUEST['glm_refDest']-0); + + + // Make sure the record actually exists + $sql = "SELECT id FROM ".GLM_MEMBERS_PLUGIN_DB_PREFIX ."$refTable WHERE id = $refDest;"; + $record = $this->wpdb->get_row($sql, ARRAY_A); + if (count($record['id']) != 1) { + $return['message'] = "Specified target record (".$record['id'].") does not exist in table (".$refTable.")!\n\n".$sql; + echo json_encode($return); + die(); + } +*/ + + // For each submitted file (usually only one) + foreach( $_FILES as $file ) { + + // Is there a file of the right type with a temp file that exists + if (isset($file['name']) && is_file($file['tmp_name'])) { + + // Store the image + $file = $this->storeFile($file); + + $return['files'][] = $file; + + // Indicate if we actually stored an image + $return['status'] = ($file != false); + $return['noimage'] = true; + + } else { + + // File was not uploaded or of the wrong type + $file['message'] = 'Image file "'.$file['name'].'" was not uploaded or is not a valid image file!'; + $file['status'] = false; + + } + + } + + // Return stored image data + echo json_encode($return); + die(); + } + + + /* + * Store a single image file using a reference table to link to a table. + * + * Images are stored in various sizes in the media/images/{size} directories + * which are created if they don't already exist. + * + * @param $file array Array containing uploaded file data + * + * @return array + * + */ + public function storeFile ($file) + { + + // Check for fileLibrary media directory + if (!file_exists(GLM_MEMBERS_PLUGIN_FILE_LIBRARY_PATH)) { + mkdir(GLM_MEMBERS_PLUGIN_FILE_LIBRARY_PATH); + } + + + // If $file is just a URL to an image, then simulate the file array from a form submission + if (!is_array($file)) { + if ( preg_match( '/^http/', $file ) ) { + $fileName = basename( $file ); + } else { + $fileName = $file; + } + $file = array( + 'tmp_name' => $file, + 'name' => $fileName + ); + } + + // Get the desired file name and add a timestamps to it to ensure that it's unique + $fInfo = pathinfo($file['name']); + + // Strip all characters from the file name other than the permitted characters. + $fInfo['filename'] = preg_replace('/([^a-zA-Z0-9-_\.]+)/','_', $fInfo['filename']); + + // Build new file name + $newFilename = strtolower($fInfo['filename'].'_'.time().'.'.$fInfo['extension']); + + // If the file is in the FILES array + if ( isset( $_FILES['file'] ) ) { + $fileUploaded = move_uploaded_file( $_FILES['file']['tmp_name'], GLM_MEMBERS_PLUGIN_FILE_LIBRARY_PATH . '/'. $newFilename ); + } else { + // Use wordpress remote get method + $wp_response = wp_remote_get( $file['tmp_name'] ); + if ( is_array( $wp_response ) ) { + $fileContents = $wp_response['body']; + $fp = fopen( GLM_MEMBERS_PLUGIN_FILE_LIBRARY_PATH . '/'. $newFilename, 'w' ); + fwrite( $fp, $fileContents ); + fclose( $fp ); + $fileUploaded = true; + } else { + $fileUploaded = false; + } + } + + // If we have a good image + if ( $fileUploaded ) { + + $file['newFileName'] = $newFilename; + $file['newFileUrl'] = GLM_MEMBERS_WORDPRESS_FILE_LIBRARY_URL.$newFilename; + + // Store image name in images table + $sql = " + INSERT INTO ".GLM_MEMBERS_PLUGIN_DB_PREFIX ."file_library + ( + name, + file_name, + descr, + title + ) + VALUES + ( + '".$file['name']."', + '".$file['newFileName']."', + '', + '' + ); + "; + $this->wpdb->query($sql); + $queryError = $this->wpdb->last_error; + + if ($queryError) { + $file['error'] = true; + $file['message'] = $queryError."\n".$sql; + } + + // Get new ID and data from the new record + $file['id'] = $this->wpdb->insert_id; + + return $file; + + // Otherwise we don't have a good image, so fail + } else { + return false; + } + + + } + +} diff --git a/models/admin/fileLibrary/index.php b/models/admin/fileLibrary/index.php new file mode 100644 index 00000000..c6f85db8 --- /dev/null +++ b/models/admin/fileLibrary/index.php @@ -0,0 +1,129 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release index.php,v 1.0 2014/10/31 19:31:47 cscott Exp $ + * @link http://dev.gaslightmedia.com/ + */ + +require_once GLM_MEMBERS_PLUGIN_CLASS_PATH . '/data/dataFileLibrary.php'; + +/* + * This model is called when the "Shortcodes" menu is selected + * + */ +class GlmMembersAdmin_fileLibrary_index extends GlmDataFileLibrary +{ + + /** + * WordPress Database Object + * + * @var $wpdb + * @access public + */ + public $wpdb; + + /* + * Constructor + * + * This contructor performs the work for this model. This model returns + * an array containing the following. + * + * 'status' + * + * True if successfull and false if there was a fatal failure. + * + * 'view' + * + * A suggested view name that the contoller should use instead of the + * default view for this model or false to indicate that the default view + * should be used. + * + * 'data' + * + * Data that the model is returning for use in merging with the view to + * produce output. + * + * @wpdb object WordPress database object + * + * @return array Array containing status, suggested view, and any data + */ + public function __construct ($wpdb, $config) + { + + // Save WordPress Database object + $this->wpdb = $wpdb; + + // Save plugin configuration object + $this->config = $config; + + // Run constructor for members data class + parent::__construct(false, false); + + } + + public function modelAction($actionData = false) { + + $paging = false; + + // File Library Upload scripts and css + wp_register_script( + 'glm-members-admin-filelibrary-upload', + GLM_MEMBERS_PLUGIN_URL . 'js/fileLibraryUpload/fileLibraryUpload.js', + array( + 'jquery' + ), + GLM_MEMBERS_PLUGIN_VERSION + ); + wp_enqueue_script('glm-members-admin-filelibrary-upload', false, array('jquery'), false, true); + wp_register_style( + 'glm-members-admin-filelibrary-upload-css', + GLM_MEMBERS_PLUGIN_URL . 'js/fileLibraryUpload/fileLibraryUpload.css', + false, + GLM_MEMBERS_PLUGIN_VERSION + ); + wp_enqueue_style('glm-members-admin-filelibrary-upload-css'); + + $haveFiles = false; + + $files = $this->getList(); + if ($files && count($files) > 0) { + $haveFiles = true; + } +/* + // Update image gallery titles, descriptions, and image positions then return current image gallery + $this->imageGallery = $Images->galleryImageDataUpdate($this->config['ref_type_numb']['MemberInfo'], $this->memberInfoID, 'galleryPositionOrder'); + $this->haveImageGallery = ($this->imageGallery != false); + + // Update file captions, descriptions, and file positions then + // return current files data. + $this->files = $Files->filesDataUpdate( $this->config['ref_type_numb']['MemberInfo'], $this->memberInfoID, 'filePositionOrder' ); + $this->haveFiles = ($this->files != false); +*/ + + // echo "
".print_r($files,1)."
"; + + // Compile template data + $templateData = array( + 'haveFiles' => $haveFiles, + 'files' => $files, + 'paging' => $paging + ); + + // Return status, any suggested view, and any data to controller + return array( + 'status' => true, + 'modelRedirect' => false, + 'view' => 'admin/fileLibrary/index.html', + 'data' => $templateData + ); + + } +} diff --git a/setup/adminMenus.php b/setup/adminMenus.php index b27f32f0..4b46f7b2 100644 --- a/setup/adminMenus.php +++ b/setup/adminMenus.php @@ -127,6 +127,18 @@ if (current_user_can('glm_members_members')) { } +// Add a submenu for the "Files" +if ($this->config['settings']['file_library']) { + add_submenu_page( + 'glm-members-admin-menu-members', + 'Files Library', + 'Files Library', + 'glm_members_settings', + 'glm-members-admin-menu-fileLibrary', + function() {$this->controller('fileLibrary');} + ); +} + // Add a submenu for the "Settings" section add_submenu_page( 'glm-members-admin-menu-members', diff --git a/setup/databaseScripts/create_database_V1.1.32.sql b/setup/databaseScripts/create_database_V1.1.33.sql similarity index 95% rename from setup/databaseScripts/create_database_V1.1.32.sql rename to setup/databaseScripts/create_database_V1.1.33.sql index d7b19d6f..1fd8d26d 100644 --- a/setup/databaseScripts/create_database_V1.1.32.sql +++ b/setup/databaseScripts/create_database_V1.1.33.sql @@ -273,6 +273,33 @@ CREATE TABLE {prefix}counties ( ---- +-- File Library Cateogries - used with "Files Library" - Created due to PDF failures in WordPress Media Library +CREATE TABLE {prefix}file_library_categories ( + id INT NOT NULL AUTO_INCREMENT, + name TINYTEXT NULL, -- Name of this category + descr TEXT NULL, -- Description of this category + short_descr TINYTEXT NULL, -- Short description of this category + parent INT NULL, -- Pointer to parent category in this table - if there is one + PRIMARY KEY (id) +); + +---- + +-- Files Library - Files are stored under /wp-content/uploads/glm-member-db/filesLibrary/ +CREATE TABLE {prefix}file_library ( + id INT NOT NULL AUTO_INCREMENT, + name TINYTEXT NULL, -- Original name of the file - might be URL if copied via HTTP + file_name TINYTEXT NULL, -- Stored file name for the file + descr TEXT NULL, -- Description + title TINYTEXT NULL, -- File title + last_access_time DATETIME DEFAULT NOW(), -- Upload time or last access time + PRIMARY KEY (id), + INDEX(name(20)), + INDEX(file_name(20)) +); + +---- + -- General settings available on Management page in admin - Only 1 entry in this table -- Items in this table should be all self-explanatory CREATE TABLE {prefix}settings_general ( @@ -300,6 +327,7 @@ CREATE TABLE {prefix}settings_general ( memb_info_files BOOLEAN DEFAULT '1', memb_info_video BOOLEAN DEFAULT '1', memb_info_cam BOOLEAN DEFAULT '1', + file_library BOOLEAN DEFAULT '0', list_show_map BOOLEAN DEFAULT '1', list_show_list BOOLEAN DEFAULT '1', list_order_list SMALLINT DEFAULT '10', diff --git a/setup/databaseScripts/dbVersions.php b/setup/databaseScripts/dbVersions.php index 6dc1e568..70813043 100644 --- a/setup/databaseScripts/dbVersions.php +++ b/setup/databaseScripts/dbVersions.php @@ -63,7 +63,8 @@ $glmMembersDbVersions = array( '1.1.29' => array('version' => '1.1.29', 'tables' => 19, 'date' => '04/10/17'), '1.1.30' => array('version' => '1.1.30', 'tables' => 19, 'date' => '04/12/17'), '1.1.31' => array('version' => '1.1.31', 'tables' => 20, 'date' => '04/23/17'), - '1.1.32' => array('version' => '1.1.32', 'tables' => 20, 'date' => '06/14/17') + '1.1.32' => array('version' => '1.1.32', 'tables' => 20, 'date' => '06/14/17'), + '1.1.33' => array('version' => '1.1.33', 'tables' => 22, 'date' => '01/15/18') ); diff --git a/setup/databaseScripts/drop_database_V1.1.32.sql b/setup/databaseScripts/drop_database_V1.1.33.sql similarity index 89% rename from setup/databaseScripts/drop_database_V1.1.32.sql rename to setup/databaseScripts/drop_database_V1.1.33.sql index ef327d88..ed1f62db 100644 --- a/setup/databaseScripts/drop_database_V1.1.32.sql +++ b/setup/databaseScripts/drop_database_V1.1.33.sql @@ -24,6 +24,8 @@ DROP TABLE IF EXISTS {prefix}categories, {prefix}amenity_groups, {prefix}grouped_amenities, - {prefix}cache + {prefix}cache, + {prefix}file_library_categories, + {prefix}file_library ; diff --git a/setup/databaseScripts/update_database_V1.1.33.sql b/setup/databaseScripts/update_database_V1.1.33.sql new file mode 100644 index 00000000..d17d8fef --- /dev/null +++ b/setup/databaseScripts/update_database_V1.1.33.sql @@ -0,0 +1,36 @@ +-- Gaslight Media Members Database +-- File Created: 01/15/18 +-- Database Version: 1.1.33 +-- Database Update From Previous Version Script +-- +-- To permit each query below to be executed separately, +-- all queries must be separated by a line with four dashes. + +-- File Library Cateogries - used with "Files Library" - Created due to PDF failures in WordPress Media Library +CREATE TABLE {prefix}file_library_categories ( + id INT NOT NULL AUTO_INCREMENT, + name TINYTEXT NULL, -- Name of this category + descr TEXT NULL, -- Description of this category + short_descr TINYTEXT NULL, -- Short description of this category + parent INT NULL, -- Pointer to parent category in this table - if there is one + PRIMARY KEY (id) +); + +---- + +-- Files Library - Files are stored under /wp-content/uploads/glm-member-db/filesLibrary/ +CREATE TABLE {prefix}file_library ( + id INT NOT NULL AUTO_INCREMENT, + name TINYTEXT NULL, -- Original name of the file - might be URL if copied via HTTP + file_name TINYTEXT NULL, -- Stored file name for the file + descr TEXT NULL, -- Description + title TINYTEXT NULL, -- File title + last_access_time DATETIME DEFAULT NOW(), -- Upload time or last access time + PRIMARY KEY (id), + INDEX(name(20)), + INDEX(file_name(20)) +); + +---- + +ALTER TABLE {prefix}settings_general ADD COLUMN file_library BOOLEAN DEFAULT '0'; \ No newline at end of file diff --git a/setup/validActions.php b/setup/validActions.php index ff0a1552..dbd11575 100644 --- a/setup/validActions.php +++ b/setup/validActions.php @@ -35,6 +35,7 @@ $glmMembersValidActions = array( 'ajax' => array( 'imageUpload' => 'glm-member-db', 'fileUpload' => 'glm-member-db', + 'fileLibraryUpload' => 'glm-member-db', 'newOldMemberIdsCsv' => 'glm-member-db', 'membersListExport' => 'glm-member-db', 'memberClickThrough' => 'glm-member-db', @@ -48,6 +49,9 @@ $glmMembersValidActions = array( 'dashboardWidget' => array( 'index' => 'glm-member-db', ), + 'fileLibrary' => array( + 'index' => 'glm-member-db', + ), 'members' => array( 'index' => 'glm-member-db', // member list 'list' => 'glm-member-db', diff --git a/views/admin/fileLibrary/index.html b/views/admin/fileLibrary/index.html new file mode 100644 index 00000000..acfaf3ae --- /dev/null +++ b/views/admin/fileLibrary/index.html @@ -0,0 +1,149 @@ +
+ +

Files Library

+
+ +
+
+
+
+ + +
+ +
+ + + Uploading File { thisFile } of { numbFiles } + + + + + + + + + + + + + + + + + +
File NameFile TypeFile Size 
{ fileName }{ fileType }{ fileSize } +
Cancel Upload
+
Progress Bar +
+
+ + +
+ + + + + + + + + + + + + +
+
Copy Link URL
+ { newfilename } +
+ { filename } + +   + +   + +
Edit
+
Delete
+
+
+
+
Drag and drop new files here
+
HTML5 file drag-and-drop not supported by your browser.
Use "Browse" button above to upload an file.
+
+
+
+
+ +

NOTE: The "Copy" button will copy the entire URL for the uploaded file to the user's "Clipboard".

+
+
+ {if $paging} + + + {/if} + + + + + + + + + + + + + + + + + + + {if $haveFiles} + {assign var="i" value="0"} + {foreach $files as $f} + {if $i++ is odd by 1} + + {else} + + {/if} + + + + + + + {/foreach} + {else} + + {/if} + +
FileOriginal NameTitleLast Access 
    New Uploads
 
    Previous Uploads
+
Copy Link URL
+ {$f.file_name} +
+ {$f.name} + + {$f.title} + + {$f.last_access_time.datetime} + +
Edit
+
Delete
+
(no files listed)
+ {if $paging} + + + {/if} +
+
+
+ + +{include file='admin/footer.html'} diff --git a/views/admin/management/index.html b/views/admin/management/index.html index dbe35f1f..dd82dcd7 100644 --- a/views/admin/management/index.html +++ b/views/admin/management/index.html @@ -91,7 +91,7 @@ {/foreach} - + @@ -129,7 +129,15 @@ + + + + + +

Members Related Settings

Misc. Settings

Enable File Library Menu: + +
Google Maps API Key: -- 2.17.1