From 4e67360ce9748d54c7e8acb51138026a0003c400 Mon Sep 17 00:00:00 2001 From: Michele Date: Sat, 30 Jan 2021 19:22:37 +0100 Subject: [PATCH 01/36] first steps --- admin/class-formality-editor.php | 1 + assets/scripts/editor.js | 3 +- assets/scripts/editor/blocks/upload.js | 108 +++++++++++++++++++ assets/scripts/editor/main/init.js | 1 + assets/scripts/editor/utility/blocks.js | 1 + assets/scripts/editor/utility/icons.js | 15 ++- assets/scripts/public/core/hints.js | 4 + assets/scripts/public/core/validate.js | 22 +++- assets/scripts/public/fields/switch.js | 2 +- assets/scripts/public/fields/upload.js | 59 ++++++++++ assets/scripts/public/init.js | 2 + assets/styles/public/components/_fields.scss | 20 ++++ public/class-formality-fields.php | 14 +++ 13 files changed, 246 insertions(+), 6 deletions(-) create mode 100644 assets/scripts/editor/blocks/upload.js create mode 100644 assets/scripts/public/fields/upload.js diff --git a/admin/class-formality-editor.php b/admin/class-formality-editor.php index 744ffed..5ba7180 100755 --- a/admin/class-formality-editor.php +++ b/admin/class-formality-editor.php @@ -122,6 +122,7 @@ public function get_allowed( $type = 'blocks' ) { 'formality/switch', 'formality/multiple', 'formality/rating', + 'formality/upload', 'formality/step', 'formality/message', 'formality/media', diff --git a/assets/scripts/editor.js b/assets/scripts/editor.js index ad343a8..ebb698c 100755 --- a/assets/scripts/editor.js +++ b/assets/scripts/editor.js @@ -13,9 +13,10 @@ import './editor/blocks/select.js'; import './editor/blocks/multiple.js'; import './editor/blocks/switch.js'; import './editor/blocks/rating.js'; +import './editor/blocks/upload.js'; import './editor/blocks/step.js'; import './editor/blocks/message.js'; import './editor/blocks/media.js'; -import './editor/blocks/widget.js'; \ No newline at end of file +import './editor/blocks/widget.js'; diff --git a/assets/scripts/editor/blocks/upload.js b/assets/scripts/editor/blocks/upload.js new file mode 100644 index 0000000..dfa8c4b --- /dev/null +++ b/assets/scripts/editor/blocks/upload.js @@ -0,0 +1,108 @@ +/** + * Formality block + * + */ + +const blockName = 'formality/upload' + +import React from 'react' + +import { + checkUID, + getPreview, + getBlockTypes, + mainOptions, + advancedPanel, + hasRules, +} from '../utility/blocks.js' + +const { __ } = wp.i18n; +const { + registerBlockType, + createBlock, +} = wp.blocks; + +const { + PanelBody, + Icon, +} = wp.components; + +const { + InspectorControls, +} = wp.blockEditor; + +import { iconUpload as blockicon } from '../utility/icons.js' + +registerBlockType( blockName, { + title: __('Upload', 'formality'), + description: __('Allow user to upload file to your form', 'formality'), + icon: blockicon, + category: 'formality', + attributes: { + uid: { type: 'string', default: '' }, + name: { type: 'string', default: ''}, + label: { type: 'string', default: ''}, + placeholder: { type: 'string', default: ''}, + required: { type: 'boolean', default: false }, + halfwidth: { type: 'boolean', default: false }, + value: { type: 'string', default: ''}, + rules: { type: 'string|array', attribute: 'rules', default: [], }, + dbg: { type: 'string|object', default: {}, }, + preview: { type: 'boolean', default: false }, + }, + supports: { + html: false, + customClassName: false, + }, + example: { attributes: { preview: true } }, + transforms: { + from: [{ + type: 'block', + blocks: getBlockTypes(blockName), + transform: function ( attributes ) { return createBlock( blockName, attributes); }, + }], + }, + edit(props) { + + checkUID(props) + let { name, label, placeholder, required, uid, value, rules, preview } = props.attributes + let focus = props.isSelected + if ( preview ) { return getPreview(props.name) } + + return ([ + + + { mainOptions(props) } + + { advancedPanel(props) } + + , +
+ +
+ +
+
+
, + ]) + }, + save () { + return null + }, +}); diff --git a/assets/scripts/editor/main/init.js b/assets/scripts/editor/main/init.js index 44d29c0..366bf62 100644 --- a/assets/scripts/editor/main/init.js +++ b/assets/scripts/editor/main/init.js @@ -40,6 +40,7 @@ 'formality/step', 'formality/select', 'formality/media', + 'formality/upload', ]; blocks.forEach(function(block){ wp.blocks.unregisterBlockType(block) diff --git a/assets/scripts/editor/utility/blocks.js b/assets/scripts/editor/utility/blocks.js index 66c6983..b775ec1 100644 --- a/assets/scripts/editor/utility/blocks.js +++ b/assets/scripts/editor/utility/blocks.js @@ -154,6 +154,7 @@ const { __ } = wp.i18n; 'formality/multiple', 'formality/switch', 'formality/rating', + 'formality/upload', ] if(exclude) { for( var i = 0; i < types.length; i++){ diff --git a/assets/scripts/editor/utility/icons.js b/assets/scripts/editor/utility/icons.js index de29173..d65f507 100644 --- a/assets/scripts/editor/utility/icons.js +++ b/assets/scripts/editor/utility/icons.js @@ -117,6 +117,18 @@ const iconRating = () => ( ) +const iconUpload = () => ( + + + + + + + + + +) + const iconMedia = () => ( @@ -161,8 +173,9 @@ export { iconWidget, iconRating, iconMedia, + iconUpload, iconPlay, glyphStar, glyphRhombus, glyphHeart, -} \ No newline at end of file +} diff --git a/assets/scripts/public/core/hints.js b/assets/scripts/public/core/hints.js index 5033846..bd3665f 100644 --- a/assets/scripts/public/core/hints.js +++ b/assets/scripts/public/core/hints.js @@ -30,6 +30,7 @@ export default { 'multiple': [4, 7], 'switch': [7, 0], 'rating': [4, 0], + 'upload': [8, 0], } const hints = [ { //0 @@ -56,6 +57,9 @@ export default { },{ //7 "text": __("Press space to confirm your option", "formality"), "icons": [ "space_bar" ], + },{ //8 + "text": __("Press space to select your file", "formality"), + "icons": [ "space_bar" ], }, ] const fieldArray = inputTypes[type] diff --git a/assets/scripts/public/core/validate.js b/assets/scripts/public/core/validate.js index 0c073fc..91a14ce 100644 --- a/assets/scripts/public/core/validate.js +++ b/assets/scripts/public/core/validate.js @@ -14,6 +14,7 @@ export default { this.field_error() this.field_success() this.form_error() + this.file_validation() this.i18n() }, checkstep(index, newindex) { @@ -30,7 +31,7 @@ export default { $(el("nav_section", "uid")).eq(index).addClass(el("nav_section", false, "--validated")) }) } - return valid + return valid }, form() { //validate standard form (1 step) @@ -54,7 +55,7 @@ export default { }, form_error() { window.Parsley.on('form:error', function() { - + }) }, field_error() { @@ -98,4 +99,19 @@ export default { }); window.Parsley.setLocale('en'); }, -} \ No newline at end of file + file_validation() { + window.Parsley.addValidator('maxFileSize', { + validateString: function(_value, maxSize, parsleyInstance) { + if (!window.FormData) { return true; } + var files = parsleyInstance.$element[0].files; + return files.length != 1 || files[0].size <= maxSize * 1024; + }, + requirementType: 'integer' + }); + window.Parsley.addValidator('filextension', function (value, requirement) { + var formats = requirement.split(", "); + var fileExtension = value.split('.').pop(); + return formats.indexOf(fileExtension) == -1 ? false : true; + }, 32) + } +} diff --git a/assets/scripts/public/fields/switch.js b/assets/scripts/public/fields/switch.js index 91f74fe..bc01ae4 100644 --- a/assets/scripts/public/fields/switch.js +++ b/assets/scripts/public/fields/switch.js @@ -20,4 +20,4 @@ export default { } }) }, -} \ No newline at end of file +} diff --git a/assets/scripts/public/fields/upload.js b/assets/scripts/public/fields/upload.js new file mode 100644 index 0000000..675004a --- /dev/null +++ b/assets/scripts/public/fields/upload.js @@ -0,0 +1,59 @@ +import { el } from '../core/helpers' +import uiux from '../core/uiux' + +export default { + init() { + this.build(); + }, + build() { + $(el("field", true, "--upload :input")).change(function () { + const input = $(this); + if (this.files && this.files[0]) { + var reader = new FileReader(); + var formats = ["jpeg", "jpg", "png", "gif", "svg", "webp"]; + reader.fileName = this.files[0].name; + reader.fileSize = this.files[0].size; + reader.fileFormat = this.files[0].name.split('.').pop().toLowerCase(); + reader.onload = function (e) { + console.log(formatBytes(e.target.fileSize), e.target.fileName, ) + //$().addClass("filled"); + if(formats.indexOf(e.target.fileFormat) == -1 ) { + //not an image + } else { + //is an image => preview + input.find("img").attr('src', e.target.result); + } + //print info + //e.target.fileName + //formatBytes(e.target.fileSize); + //$().removeClass("dragging").removeClass('highlight'); + } + reader.readAsDataURL(this.files[0]); + } else { + //$().removeClass("filled"); + } + }); + function formatBytes(a,b){if(0==a)return"0 Bytes";var c=1024,d=b||2,e=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],f=Math.floor(Math.log(a)/Math.log(c));return parseFloat((a/Math.pow(c,f)).toFixed(d))+" "+e[f]} + $(el("field", true, "--upload .formality__file-toggle")).click(function(e){ + $(this).prev().focus(); + }) + var drag_timer; + $(document).on('dragover', function(e){ + var dt = e.originalEvent.dataTransfer; + if(dt.types && (dt.types.indexOf ? dt.types.indexOf('Files') != -1 : dt.types.contains('Files'))){ + //$().addClass("dragging"); + window.clearTimeout(drag_timer); + } + }).on('dragleave', function(e){ + drag_timer = window.setTimeout(function(){ + //$().removeClass("dragging"); + }, 50); + }); + + $(el("field", true, "--upload")).on('dragenter', function(){ + //$().addClass('highlight'); + }).on('dragleave', function(){ + //$().removeClass('highlight'); + }); + }, +} diff --git a/assets/scripts/public/init.js b/assets/scripts/public/init.js index ce25f07..2f4e992 100644 --- a/assets/scripts/public/init.js +++ b/assets/scripts/public/init.js @@ -17,6 +17,7 @@ import number from './fields/number' import rating from './fields/rating' import multiple from './fields/multiple' import media from './fields/media' +import upload from './fields/upload' export default function() { loader.init() @@ -35,4 +36,5 @@ export default function() { rating.init() multiple.init() media.init() + upload.init() } diff --git a/assets/styles/public/components/_fields.scss b/assets/styles/public/components/_fields.scss index e44ecf5..c86a1b0 100755 --- a/assets/styles/public/components/_fields.scss +++ b/assets/styles/public/components/_fields.scss @@ -952,4 +952,24 @@ } } } + &--upload { + > .formality__label { + // + } + .formality__input { + //border: none; + input { + width: 0.1px; + height: 0.1px; + opacity: 0; + overflow: hidden; + position: absolute; + z-index: -1; + } + > label { + padding: 0.7em; + display: block; + } + } + } } diff --git a/public/class-formality-fields.php b/public/class-formality-fields.php index a1d6e60..7eb8b2c 100755 --- a/public/class-formality-fields.php +++ b/public/class-formality-fields.php @@ -361,4 +361,18 @@ public function media($options) { return $field; } + /** + * Render upload field + * + * @since 1.3.0 + */ + public function upload($options) { + $field = '
' . __("Choose file or drag here", "formality") . '
'; + $field .= '' . __("Size limit: ", "formality") . ' ' . 1000 . 'Kb'; + $field .= '' . __("Allowed formats: ", "formality") . ' ' . 'pdf, jpg, jpeg, png' . ''; + $field .= '
'; + return $field; + } + } From f5aea5c779ab527c8efe017d15b91ad20edc50e5 Mon Sep 17 00:00:00 2001 From: Michele Giorgi Date: Sun, 31 Jan 2021 21:41:01 +0100 Subject: [PATCH 02/36] temp upload --- assets/scripts/public/core/submit.js | 52 +++++++++--------- assets/scripts/public/fields/upload.js | 40 +++++++++++++- includes/class-formality.php | 9 ++- public/class-formality-fields.php | 4 +- public/class-formality-public.php | 1 + public/class-formality-upload.php | 76 ++++++++++++++++++++++++++ 6 files changed, 147 insertions(+), 35 deletions(-) create mode 100755 public/class-formality-upload.php diff --git a/assets/scripts/public/core/submit.js b/assets/scripts/public/core/submit.js index e8302dc..7e3b87f 100644 --- a/assets/scripts/public/core/submit.js +++ b/assets/scripts/public/core/submit.js @@ -16,35 +16,33 @@ export default { }) }) }, - token() { + token(submit = this, $single = false) { //request token - var submit = this - if(!$(el("form", "uid")).hasClass("formality--loading")) { - $(el("form", "uid")).addClass("formality--loading") - $.ajax({ - url: window.formality.api + 'formality/v1/token/', - data: { - nonce: window.formality.action_nonce, - action: "formality_token", - }, - beforeSend: function(xhr) { xhr.setRequestHeader('X-WP-Nonce', window.formality.login_nonce ) }, - cache: false, - type: 'POST', - success: function(response){ - if(response.status == 200) { - submit.send(response.token) - } else { - submit.result(response) - } - }, - error: function(){ - const data = { status: 400 } - submit.result(data) - }, - }) - } + if($(el("form", "uid")).hasClass("formality--loading")) return; + if(!$single) { $(el("form", "uid")).addClass("formality--loading") } + $.ajax({ + url: window.formality.api + 'formality/v1/token/', + data: { + nonce: window.formality.action_nonce, + action: "formality_token", + }, + beforeSend: function(xhr) { xhr.setRequestHeader('X-WP-Nonce', window.formality.login_nonce ) }, + cache: false, + type: 'POST', + success: function(response){ + if(response.status == 200) { + submit.send(response.token, $single) + } else { + submit.result(response) + } + }, + error: function(){ + const data = { status: 400 } + submit.result(data) + }, + }) }, - send(token) { + send(token, $single = false) { //send form var submit = this var fulldata = new FormData() diff --git a/assets/scripts/public/fields/upload.js b/assets/scripts/public/fields/upload.js index 675004a..b4ad803 100644 --- a/assets/scripts/public/fields/upload.js +++ b/assets/scripts/public/fields/upload.js @@ -1,14 +1,16 @@ import { el } from '../core/helpers' -import uiux from '../core/uiux' +import submit from '../core/submit' export default { init() { this.build(); }, build() { + let upload = this $(el("field", true, "--upload :input")).change(function () { - const input = $(this); + const $input = $(this); if (this.files && this.files[0]) { + submit.token(upload, $input) var reader = new FileReader(); var formats = ["jpeg", "jpg", "png", "gif", "svg", "webp"]; reader.fileName = this.files[0].name; @@ -21,7 +23,7 @@ export default { //not an image } else { //is an image => preview - input.find("img").attr('src', e.target.result); + $input.find("img").attr('src', e.target.result); } //print info //e.target.fileName @@ -56,4 +58,36 @@ export default { //$().removeClass('highlight'); }); }, + send(token, $input) { + //send form + var upload = this + var fulldata = new FormData() + fulldata.append("action", "formality_upload") + fulldata.append("nonce", window.formality.action_nonce) + fulldata.append("token", token) + fulldata.append("id", $(el("form", "uid")).attr("data-id")) + fulldata.append(("field_" + $input.prop("id")), $input[0].files[0]) + $.ajax({ + url: window.formality.api + 'formality/v1/upload/', + data: fulldata, + cache: false, + contentType: false, + processData: false, + beforeSend: function(xhr) { xhr.setRequestHeader('X-WP-Nonce', window.formality.login_nonce ) }, + type: 'POST', + success: function(data){ + upload.result(data) + }, + error: function(error){ + const data = { + status: 400, + error: ('responseText' in error) ? error.responseText : error + } + upload.result(data) + }, + }) + }, + result(data){ + console.log(data); + }, } diff --git a/includes/class-formality.php b/includes/class-formality.php index 579e283..89088c0 100755 --- a/includes/class-formality.php +++ b/includes/class-formality.php @@ -185,6 +185,9 @@ private function define_public_hooks() { $plugin_submit = new Formality_Submit( $this->get_formality(), $this->get_version() ); $this->loader->add_action( 'rest_api_init', $plugin_submit, 'api_endpoints' ); + $plugin_upload = new Formality_Upload( $this->get_formality(), $this->get_version() ); + $this->loader->add_action( 'rest_api_init', $plugin_upload, 'api_endpoints' ); + } /** @@ -195,12 +198,12 @@ private function define_public_hooks() { * @access private */ private function setup() { - + $plugin_setup = new Formality_Setup( $this->get_formality(), $this->get_version() ); $this->loader->add_action( 'init', $plugin_setup, 'post_types' ); - + } - + /** * Run the loader to execute all of the hooks with WordPress. * diff --git a/public/class-formality-fields.php b/public/class-formality-fields.php index 7eb8b2c..1fe7aaa 100755 --- a/public/class-formality-fields.php +++ b/public/class-formality-fields.php @@ -370,8 +370,8 @@ public function upload($options) { $field = 'attr_name($options['uid']) . $this->attr_required($options['required']) . $this->attr_placeholder($options['placeholder']) .' />'; $field .= '
'; + $field .= '' . __("Allowed formats: ", "formality") . ' ' . 'pdf, jpg, jpeg, png' . ''; + $field .= '
'; return $field; } diff --git a/public/class-formality-public.php b/public/class-formality-public.php index f7b5fe5..eb2827a 100755 --- a/public/class-formality-public.php +++ b/public/class-formality-public.php @@ -31,6 +31,7 @@ private function load_dependencies() { require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-formality-form.php'; require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-formality-fields.php'; require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-formality-submit.php'; + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-formality-upload.php'; } /** diff --git a/public/class-formality-upload.php b/public/class-formality-upload.php new file mode 100755 index 0000000..5d717dc --- /dev/null +++ b/public/class-formality-upload.php @@ -0,0 +1,76 @@ + + */ + +class Formality_Upload { + + private $formality; + private $version; + + public function __construct( $formality, $version ) { + $this->formality = $formality; + $this->version = $version; + } + + /** + * Add routes to upload files via WP REST API + * + * @since 1.3.0 + */ + public function api_endpoints() { + register_rest_route( 'formality/v1', '/upload/', array( + 'methods' => 'POST', + 'callback' => [$this, 'temp_upload'], + 'permission_callback' => function () { return true; } + )); + } + + /** + * Upload temp file + * + * @since 1.3.0 + */ + public function temp_upload() { + $response = array(); + $nonce = isset($_POST['nonce']) ? sanitize_key($_POST['nonce']) : ''; + if (wp_verify_nonce( $nonce, 'formality_async' ) && !empty($_FILES)) { + + require_once( ABSPATH . 'wp-admin/includes/file.php' ); + add_filter('upload_dir', 'formality_change_upload_dir'); + + function formality_change_upload_dir($dir) { + $dir['subdir'] = '/formality/uploads/temp'; + $dir['path'] = $dir['basedir'] . '/formality/uploads/temp'; + $dir['url'] = $dir['baseurl'] . '/formality/uploads/temp'; + return $dir; + } + + $file = $_FILES[array_key_first($_FILES)]; + $uploaded_file = wp_handle_upload($file, array('test_form' => false)); + if (!isset($uploaded_file['error'])) { + $response["status"] = 200; + $response["file"] = basename($uploaded_file['url']); + } else { + $response["status"] = 400; + $response['error'] = $uploaded_file['error']; + } + + remove_filter('upload_dir', 'formality_change_upload_dir'); + } else { + //bad token + $response["status"] = 300; + } + header('Content-type: application/json'); + echo json_encode($response); + exit; + } + +} From 3de9b9eefd09515c4e809259e713c9ef235d4a58 Mon Sep 17 00:00:00 2001 From: Michele Date: Sat, 6 Feb 2021 15:46:14 +0100 Subject: [PATCH 03/36] add file validation --- assets/scripts/public/fields/upload.js | 19 ++++--- public/class-formality-fields.php | 2 +- public/class-formality-upload.php | 69 +++++++++++++++++++------- 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/assets/scripts/public/fields/upload.js b/assets/scripts/public/fields/upload.js index b4ad803..d596f1d 100644 --- a/assets/scripts/public/fields/upload.js +++ b/assets/scripts/public/fields/upload.js @@ -8,21 +8,20 @@ export default { build() { let upload = this $(el("field", true, "--upload :input")).change(function () { - const $input = $(this); + const $input = $(this) if (this.files && this.files[0]) { submit.token(upload, $input) - var reader = new FileReader(); - var formats = ["jpeg", "jpg", "png", "gif", "svg", "webp"]; - reader.fileName = this.files[0].name; - reader.fileSize = this.files[0].size; + var reader = new FileReader() + const previewFormats = ["jpeg", "jpg", "png", "gif", "svg", "webp"] + const maxSize = parseInt($input.attr('data-max-size')) + reader.fileName = this.files[0].name + reader.fileSize = this.files[0].size reader.fileFormat = this.files[0].name.split('.').pop().toLowerCase(); reader.onload = function (e) { - console.log(formatBytes(e.target.fileSize), e.target.fileName, ) + console.log(formatBytes(e.target.fileSize), e.target.fileName) //$().addClass("filled"); - if(formats.indexOf(e.target.fileFormat) == -1 ) { - //not an image + if(previewFormats.indexOf(e.target.fileFormat) == -1 ) { } else { - //is an image => preview $input.find("img").attr('src', e.target.result); } //print info @@ -66,7 +65,7 @@ export default { fulldata.append("nonce", window.formality.action_nonce) fulldata.append("token", token) fulldata.append("id", $(el("form", "uid")).attr("data-id")) - fulldata.append(("field_" + $input.prop("id")), $input[0].files[0]) + fulldata.append("field_" + $input.prop("id")), $input[0].files[0]) $.ajax({ url: window.formality.api + 'formality/v1/upload/', data: fulldata, diff --git a/public/class-formality-fields.php b/public/class-formality-fields.php index 1fe7aaa..f0031b1 100755 --- a/public/class-formality-fields.php +++ b/public/class-formality-fields.php @@ -367,7 +367,7 @@ public function media($options) { * @since 1.3.0 */ public function upload($options) { - $field = 'attr_name($options['uid']) . $this->attr_required($options['required']) . $this->attr_placeholder($options['placeholder']) .' />'; + $field = 'attr_name($options['uid']) . $this->attr_required($options['required']) . $this->attr_placeholder($options['placeholder']) .' accept=".pdf, .jpg, .jpeg, .png" data-max-size="8388608" />'; $field .= ''; diff --git a/public/class-formality-upload.php b/public/class-formality-upload.php index 5d717dc..e0b1298 100755 --- a/public/class-formality-upload.php +++ b/public/class-formality-upload.php @@ -39,31 +39,66 @@ public function api_endpoints() { * @since 1.3.0 */ public function temp_upload() { - $response = array(); + + $response = array("status" => 400); $nonce = isset($_POST['nonce']) ? sanitize_key($_POST['nonce']) : ''; - if (wp_verify_nonce( $nonce, 'formality_async' ) && !empty($_FILES)) { - require_once( ABSPATH . 'wp-admin/includes/file.php' ); - add_filter('upload_dir', 'formality_change_upload_dir'); + if (wp_verify_nonce( $nonce, 'formality_async' ) && !empty($_FILES)) { - function formality_change_upload_dir($dir) { - $dir['subdir'] = '/formality/uploads/temp'; - $dir['path'] = $dir['basedir'] . '/formality/uploads/temp'; - $dir['url'] = $dir['baseurl'] . '/formality/uploads/temp'; - return $dir; + //get form and field informations + $postid = isset($_POST['id']) ? absint($_POST['id']) : 0; + $file = ""; + if($postid) { + $args = array( 'post_type' => 'formality_form', 'posts_per_page' => 1, 'p' => $postid, ); + $the_query = new WP_Query( $args ); + if ($the_query->have_posts()) { + while ( $the_query->have_posts() ) : $the_query->the_post(); + if(has_blocks()) { + $blocks = parse_blocks(get_the_content()); + foreach ( $blocks as $block ) { + $type = str_replace("formality/", "", $block['blockName']); + if($type=="upload") { + $field = "field_" . $block["attrs"]["uid"]; + if(isset($_FILES[$field])) { $file = $_FILES[$field]; break; } + } + } + } + endwhile; + } else { + $response['errors'][] = "wrong form id"; + } + wp_reset_query(); + wp_reset_postdata(); + } else { + $response['errors'][] = "no form id provided"; } - $file = $_FILES[array_key_first($_FILES)]; - $uploaded_file = wp_handle_upload($file, array('test_form' => false)); - if (!isset($uploaded_file['error'])) { - $response["status"] = 200; - $response["file"] = basename($uploaded_file['url']); + //upload file + if($file) { + require_once( ABSPATH . 'wp-admin/includes/file.php' ); + + add_filter('upload_dir', 'formality_change_upload_dir'); + + function formality_change_upload_dir($dir) { + $dir['subdir'] = '/formality/uploads/temp'; + $dir['path'] = $dir['basedir'] . '/formality/uploads/temp'; + $dir['url'] = $dir['baseurl'] . '/formality/uploads/temp'; + return $dir; + } + + $uploaded_file = wp_handle_upload($file, array('test_form' => false)); + if (!isset($uploaded_file['error'])) { + $response["status"] = 200; + $response["file"] = basename($uploaded_file['url']); + } else { + $response['errors'][] = $uploaded_file['error']; + } + + remove_filter('upload_dir', 'formality_change_upload_dir'); } else { - $response["status"] = 400; - $response['error'] = $uploaded_file['error']; + $response['errors'][] = "wrong file"; } - remove_filter('upload_dir', 'formality_change_upload_dir'); } else { //bad token $response["status"] = 300; From 8fb15ca048cd80a20ea484ff6d0baa9fdaf2d658 Mon Sep 17 00:00:00 2001 From: Michele Giorgi Date: Sun, 7 Feb 2021 00:17:58 +0100 Subject: [PATCH 04/36] file validation --- admin/class-formality-editor.php | 7 +++++ assets/scripts/editor/blocks/upload.js | 36 +++++++++++++++++++++++--- assets/scripts/public/fields/upload.js | 2 +- public/class-formality-upload.php | 14 ++++++++-- 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/admin/class-formality-editor.php b/admin/class-formality-editor.php index 5ba7180..e7f1e25 100755 --- a/admin/class-formality-editor.php +++ b/admin/class-formality-editor.php @@ -41,6 +41,11 @@ public function register_blocks() { public function enqueue_scripts() { $upload = wp_upload_dir(); + + $formats = array(); + $mimes = get_allowed_mime_types(); + if(!empty($mimes)) { foreach ($mimes as $type => $mime) { $formats[] = $type; } } + wp_enqueue_script( $this->formality . "-editor", plugin_dir_url(__DIR__) . 'dist/scripts/formality-editor.js', array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor', 'wp-plugins', 'wp-edit-post' ), $this->version, false ); wp_localize_script( $this->formality . "-editor", 'formality', array( @@ -50,6 +55,8 @@ public function enqueue_scripts() { 'admin_url' => get_admin_url(), 'api' => esc_url_raw(rest_url()), 'nonce' => wp_create_nonce('wp_rest'), + 'upload_formats' => $formats, + 'upload_max' => wp_max_upload_size() )); wp_set_script_translations( $this->formality . "-editor", 'formality', plugin_dir_path( __DIR__ ) . 'languages' ); diff --git a/assets/scripts/editor/blocks/upload.js b/assets/scripts/editor/blocks/upload.js index dfa8c4b..89caf42 100644 --- a/assets/scripts/editor/blocks/upload.js +++ b/assets/scripts/editor/blocks/upload.js @@ -25,6 +25,9 @@ const { const { PanelBody, Icon, + RangeControl, + BaseControl, + CheckboxControl } = wp.components; const { @@ -35,7 +38,7 @@ import { iconUpload as blockicon } from '../utility/icons.js' registerBlockType( blockName, { title: __('Upload', 'formality'), - description: __('Allow user to upload file to your form', 'formality'), + description: __('Let your users upload files to your form', 'formality'), icon: blockicon, category: 'formality', attributes: { @@ -45,6 +48,8 @@ registerBlockType( blockName, { placeholder: { type: 'string', default: ''}, required: { type: 'boolean', default: false }, halfwidth: { type: 'boolean', default: false }, + maxsize: { type: 'string', default: '3'}, + formats: { type: 'string|object', default: {}, }, value: { type: 'string', default: ''}, rules: { type: 'string|array', attribute: 'rules', default: [], }, dbg: { type: 'string|object', default: {}, }, @@ -65,14 +70,39 @@ registerBlockType( blockName, { edit(props) { checkUID(props) - let { name, label, placeholder, required, uid, value, rules, preview } = props.attributes + let { name, label, placeholder, required, uid, value, rules, preview, maxsize, formats } = props.attributes let focus = props.isSelected - if ( preview ) { return getPreview(props.name) } + const wpformats = [ 'pdf', 'jpg', 'gif', 'png' ] + if(preview) { return getPreview(props.name) } return ([ { mainOptions(props) } + { props.setAttributes({maxsize: val}) }} + min={ 1 } + max={ 8 } + label={ __( 'Max size', 'formality' ) } + help={ __( "nkjdsnjkfkdjsn", 'formality' ) } + //beforeIcon="editor-textcolor" + /> + + { + wpformats.map((format) => ( + {}} + /> + )) + } + { advancedPanel(props) } diff --git a/assets/scripts/public/fields/upload.js b/assets/scripts/public/fields/upload.js index d596f1d..fa85b7d 100644 --- a/assets/scripts/public/fields/upload.js +++ b/assets/scripts/public/fields/upload.js @@ -65,7 +65,7 @@ export default { fulldata.append("nonce", window.formality.action_nonce) fulldata.append("token", token) fulldata.append("id", $(el("form", "uid")).attr("data-id")) - fulldata.append("field_" + $input.prop("id")), $input[0].files[0]) + fulldata.append("field_" + $input.prop("id"), $input[0].files[0]) $.ajax({ url: window.formality.api + 'formality/v1/upload/', data: fulldata, diff --git a/public/class-formality-upload.php b/public/class-formality-upload.php index e0b1298..7cdb03a 100755 --- a/public/class-formality-upload.php +++ b/public/class-formality-upload.php @@ -59,7 +59,17 @@ public function temp_upload() { $type = str_replace("formality/", "", $block['blockName']); if($type=="upload") { $field = "field_" . $block["attrs"]["uid"]; - if(isset($_FILES[$field])) { $file = $_FILES[$field]; break; } + if(isset($_FILES[$field])) { + $file = $_FILES[$field]; + //check extension + $validextensions = explode(", ", $block["attrs"]["formats"]); + $file_extension = end(explode(".", $file["name"])); + if(!(in_array($file_extension, $validextensions))) { $response['errors'][] = "wrong extension"; } + //check size + maxsize = intval($block["attrs"]["maxsize"]) * 1048576; + if($file["size"] > $size) { $response['errors'][] = "max file size exceeded"; } + break; + } } } } @@ -74,7 +84,7 @@ public function temp_upload() { } //upload file - if($file) { + if($file && !isset($response['errors'])) { require_once( ABSPATH . 'wp-admin/includes/file.php' ); add_filter('upload_dir', 'formality_change_upload_dir'); From 004fb97866abdaae951679410a95834ebc6a9022 Mon Sep 17 00:00:00 2001 From: Michele Giorgi Date: Sun, 14 Feb 2021 22:47:07 +0100 Subject: [PATCH 05/36] add file size + format validation --- admin/class-formality-editor.php | 3 +- assets/scripts/editor/blocks/upload.js | 38 ++++++++++++++------------ public/class-formality-upload.php | 2 +- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/admin/class-formality-editor.php b/admin/class-formality-editor.php index e7f1e25..059d2fa 100755 --- a/admin/class-formality-editor.php +++ b/admin/class-formality-editor.php @@ -44,6 +44,7 @@ public function enqueue_scripts() { $formats = array(); $mimes = get_allowed_mime_types(); + $maxsize = wp_max_upload_size() / 1048576; if(!empty($mimes)) { foreach ($mimes as $type => $mime) { $formats[] = $type; } } wp_enqueue_script( $this->formality . "-editor", plugin_dir_url(__DIR__) . 'dist/scripts/formality-editor.js', array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor', 'wp-plugins', 'wp-edit-post' ), $this->version, false ); @@ -56,7 +57,7 @@ public function enqueue_scripts() { 'api' => esc_url_raw(rest_url()), 'nonce' => wp_create_nonce('wp_rest'), 'upload_formats' => $formats, - 'upload_max' => wp_max_upload_size() + 'upload_max' => $maxsize )); wp_set_script_translations( $this->formality . "-editor", 'formality', plugin_dir_path( __DIR__ ) . 'languages' ); diff --git a/assets/scripts/editor/blocks/upload.js b/assets/scripts/editor/blocks/upload.js index 89caf42..4678712 100644 --- a/assets/scripts/editor/blocks/upload.js +++ b/assets/scripts/editor/blocks/upload.js @@ -48,8 +48,8 @@ registerBlockType( blockName, { placeholder: { type: 'string', default: ''}, required: { type: 'boolean', default: false }, halfwidth: { type: 'boolean', default: false }, - maxsize: { type: 'string', default: '3'}, - formats: { type: 'string|object', default: {}, }, + maxsize: { type: 'number', default: 3}, + formats: { type: 'string|array', default: [], }, value: { type: 'string', default: ''}, rules: { type: 'string|array', attribute: 'rules', default: [], }, dbg: { type: 'string|object', default: {}, }, @@ -72,7 +72,7 @@ registerBlockType( blockName, { checkUID(props) let { name, label, placeholder, required, uid, value, rules, preview, maxsize, formats } = props.attributes let focus = props.isSelected - const wpformats = [ 'pdf', 'jpg', 'gif', 'png' ] + const wpformats = formality.upload_formats if(preview) { return getPreview(props.name) } return ([ @@ -80,28 +80,32 @@ registerBlockType( blockName, { { mainOptions(props) } { props.setAttributes({maxsize: val}) }} + value={ maxsize } + onChange={(val) => { props.setAttributes({maxsize: val }) }} min={ 1 } - max={ 8 } + max={ formality.upload_max } label={ __( 'Max size', 'formality' ) } help={ __( "nkjdsnjkfkdjsn", 'formality' ) } - //beforeIcon="editor-textcolor" /> - { - wpformats.map((format) => ( - {}} - /> - )) - } + { wpformats.map((format) => ( + { + let filtered = [...formats] + if(check) { + filtered.push(format) + } else { + filtered = formats.filter(function(value, index, arr){ return value !== format; }); + } + props.setAttributes({ formats: filtered }) + }} + /> + ))} { advancedPanel(props) } diff --git a/public/class-formality-upload.php b/public/class-formality-upload.php index 7cdb03a..af9ffe2 100755 --- a/public/class-formality-upload.php +++ b/public/class-formality-upload.php @@ -66,7 +66,7 @@ public function temp_upload() { $file_extension = end(explode(".", $file["name"])); if(!(in_array($file_extension, $validextensions))) { $response['errors'][] = "wrong extension"; } //check size - maxsize = intval($block["attrs"]["maxsize"]) * 1048576; + $maxsize = intval($block["attrs"]["maxsize"]) * 1048576; if($file["size"] > $size) { $response['errors'][] = "max file size exceeded"; } break; } From dc3156a3a0fc5a2a2b3029b2fed03ac077670f57 Mon Sep 17 00:00:00 2001 From: Michele Giorgi Date: Tue, 16 Feb 2021 22:57:48 +0100 Subject: [PATCH 06/36] fixes and refinements --- admin/class-formality-editor.php | 13 ++++++++----- assets/scripts/editor/blocks/upload.js | 2 +- public/class-formality-fields.php | 6 +++--- public/class-formality-upload.php | 9 +++++---- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/admin/class-formality-editor.php b/admin/class-formality-editor.php index 059d2fa..57eda52 100755 --- a/admin/class-formality-editor.php +++ b/admin/class-formality-editor.php @@ -41,14 +41,18 @@ public function register_blocks() { public function enqueue_scripts() { $upload = wp_upload_dir(); - $formats = array(); $mimes = get_allowed_mime_types(); $maxsize = wp_max_upload_size() / 1048576; - if(!empty($mimes)) { foreach ($mimes as $type => $mime) { $formats[] = $type; } } - + if(!empty($mimes)) { + foreach ($mimes as $type => $mime) { + $multiple = explode("|", $type); + foreach ($multiple as $single) { + $formats[] = $single; + } + } + } wp_enqueue_script( $this->formality . "-editor", plugin_dir_url(__DIR__) . 'dist/scripts/formality-editor.js', array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor', 'wp-plugins', 'wp-edit-post' ), $this->version, false ); - wp_localize_script( $this->formality . "-editor", 'formality', array( 'plugin_url' => str_replace('admin/', '', plugin_dir_url( __FILE__ )), 'templates_url' => $upload['baseurl'] . '/formality/templates', @@ -59,7 +63,6 @@ public function enqueue_scripts() { 'upload_formats' => $formats, 'upload_max' => $maxsize )); - wp_set_script_translations( $this->formality . "-editor", 'formality', plugin_dir_path( __DIR__ ) . 'languages' ); } diff --git a/assets/scripts/editor/blocks/upload.js b/assets/scripts/editor/blocks/upload.js index 4678712..e88fc5d 100644 --- a/assets/scripts/editor/blocks/upload.js +++ b/assets/scripts/editor/blocks/upload.js @@ -49,7 +49,7 @@ registerBlockType( blockName, { required: { type: 'boolean', default: false }, halfwidth: { type: 'boolean', default: false }, maxsize: { type: 'number', default: 3}, - formats: { type: 'string|array', default: [], }, + formats: { type: 'string|array', default: ['jpg', 'jpeg', 'gif', 'png', 'pdf'], }, value: { type: 'string', default: ''}, rules: { type: 'string|array', attribute: 'rules', default: [], }, dbg: { type: 'string|object', default: {}, }, diff --git a/public/class-formality-fields.php b/public/class-formality-fields.php index f0031b1..5d539a7 100755 --- a/public/class-formality-fields.php +++ b/public/class-formality-fields.php @@ -367,10 +367,10 @@ public function media($options) { * @since 1.3.0 */ public function upload($options) { - $field = 'attr_name($options['uid']) . $this->attr_required($options['required']) . $this->attr_placeholder($options['placeholder']) .' accept=".pdf, .jpg, .jpeg, .png" data-max-size="8388608" />'; + $field = 'attr_name($options['uid']) . $this->attr_required($options['required']) . $this->attr_placeholder($options['placeholder']) .' accept=".' . ( count($options['formats']) ? implode(", .", $options['formats']) : 'nnnn' ) . '" data-max-size="' . ($options['maxsize'] * 1048576) .'" />'; $field .= ''; + $field .= '' . __("Size limit: ", "formality") . ' ' . $options['maxsize'] . 'MB'; + $field .= '' . __("Allowed formats: ", "formality") . ' ' . ( count($options['formats']) ? implode(", ", $options['formats']) : __('none', 'formality') ) . ''; $field .= '
'; return $field; } diff --git a/public/class-formality-upload.php b/public/class-formality-upload.php index af9ffe2..0d7106f 100755 --- a/public/class-formality-upload.php +++ b/public/class-formality-upload.php @@ -62,12 +62,13 @@ public function temp_upload() { if(isset($_FILES[$field])) { $file = $_FILES[$field]; //check extension - $validextensions = explode(", ", $block["attrs"]["formats"]); - $file_extension = end(explode(".", $file["name"])); - if(!(in_array($file_extension, $validextensions))) { $response['errors'][] = "wrong extension"; } + $valid_extensions = $block["attrs"]["formats"]; + $file_name = explode(".", $file["name"]); + $file_extension = end($file_name); + if(!(in_array($file_extension, $valid_extensions))) { $response['errors'][] = "wrong extension"; } //check size $maxsize = intval($block["attrs"]["maxsize"]) * 1048576; - if($file["size"] > $size) { $response['errors'][] = "max file size exceeded"; } + if($file["size"] > $maxsize) { $response['errors'][] = "max file size exceeded"; } break; } } From fecc198eb25da613bd21f3bc73033884cc4adbf1 Mon Sep 17 00:00:00 2001 From: Michele Giorgi Date: Sun, 21 Feb 2021 19:28:43 +0100 Subject: [PATCH 07/36] prevent undefined defaults fix gutenberg 10+ blocklist sidebar --- assets/styles/admin/editor_form.scss | 6 ++++-- public/class-formality-fields.php | 2 ++ public/class-formality-upload.php | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/assets/styles/admin/editor_form.scss b/assets/styles/admin/editor_form.scss index dd8fbf5..afe6b71 100644 --- a/assets/styles/admin/editor_form.scss +++ b/assets/styles/admin/editor_form.scss @@ -435,6 +435,7 @@ } } + .block-editor-inserter { &__tabs { .components-tab-panel__tabs { @@ -444,16 +445,17 @@ &__tips { display: none; } + /* &__block-list { > div { > * { display: none; - &:nth-last-child(-n+4) { + &:nth-child(-n+4) { display: block; } } } - } + }*/ } .block-editor-block-navigation-leaf.is-selected { diff --git a/public/class-formality-fields.php b/public/class-formality-fields.php index 5d539a7..b36dbaa 100755 --- a/public/class-formality-fields.php +++ b/public/class-formality-fields.php @@ -367,6 +367,8 @@ public function media($options) { * @since 1.3.0 */ public function upload($options) { + if(!isset($options['formats'])) { $options['formats'] = array('jpg', 'jpeg', 'gif', 'png', 'pdf'); } + if(!isset($options['maxsize'])) { $options['maxsize'] = 3; } $field = 'attr_name($options['uid']) . $this->attr_required($options['required']) . $this->attr_placeholder($options['placeholder']) .' accept=".' . ( count($options['formats']) ? implode(", .", $options['formats']) : 'nnnn' ) . '" data-max-size="' . ($options['maxsize'] * 1048576) .'" />'; $field .= '