Merge branch 'develop' into wip/laravel-6

This commit is contained in:
Luke Towers 2020-06-11 10:38:29 -06:00
commit ad69711634
40 changed files with 574 additions and 110 deletions

View File

@ -1,6 +1,6 @@
---
name: "🐛 Bug Report"
about: 'Report a general OctoberCMS issue'
about: 'Report a general OctoberCMS issue. See our policy below if reporting a security issue.'
labels: 'Status: Review Needed, Type: Unconfirmed Bug'
---

View File

@ -0,0 +1,363 @@
#!/usr/bin/env bash
#
# git-subsplit.sh: Automate and simplify the process of managing one-way
# read-only subtree splits.
#
# Copyright (C) 2012 Dragonfly Development Inc.
#
# 2020-06-11: Modified by Ben Thomson for October CMS maintenance through GitHub Actions.
#
if [ $# -eq 0 ]; then
set -- -h
fi
OPTS_SPEC="\
git subsplit init url
git subsplit publish splits --heads=<heads> --tags=<tags> --splits=<splits>
git subsplit update
--
h,help show the help
q quiet
debug show plenty of debug output
n,dry-run do everything except actually send the updates
work-dir directory that contains the subsplit working directory
options for 'publish'
heads= only publish for listed heads instead of all heads
no-heads do not publish any heads
tags= only publish for listed tags instead of all tags
no-tags do not publish any tags
update fetch updates from repository before publishing
rebuild-tags rebuild all tags (as opposed to skipping tags that are already synced)
path= path of the repository
"
eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
# We can run this from anywhere.
NONGIT_OK=1
DEBUG=" :DEBUG >"
PATH=$PATH:$(git --exec-path)
. git-sh-setup
if [ "$(hash git-subtree &>/dev/null && echo OK)" = "" ]
then
die "Git subsplit needs git subtree; install git subtree or upgrade git to >=1.7.11"
fi
ANNOTATE=
QUIET=
COMMAND=
SPLITS=
REPO_URL=
WORK_DIR="${PWD}/.subsplit"
HEADS=
NO_HEADS=
TAGS=
NO_TAGS=
REBUILD_TAGS=
DRY_RUN=
VERBOSE=
subsplit_main()
{
while [ $# -gt 0 ]; do
opt="$1"
shift
case "$opt" in
-q) QUIET=1 ;;
--debug) VERBOSE=1 ;;
--heads) HEADS="$1"; shift ;;
--no-heads) NO_HEADS=1 ;;
--tags) TAGS="$1"; shift ;;
--no-tags) NO_TAGS=1 ;;
--update) UPDATE=1 ;;
-n) DRY_RUN="--dry-run" ;;
--dry-run) DRY_RUN="--dry-run" ;;
--rebuild-tags) REBUILD_TAGS=1 ;;
--path) WORK_DIR="$1"; shift ;;
--) break ;;
*) die "Unexpected option: $opt" ;;
esac
done
COMMAND="$1"
shift
case "$COMMAND" in
init)
if [ $# -lt 1 ]; then die "init command requires url to be passed as first argument"; fi
REPO_URL="$1"
shift
subsplit_init
;;
publish)
if [ $# -lt 1 ]; then die "publish command requires splits to be passed as first argument"; fi
SPLITS="$1"
shift
subsplit_publish
;;
update)
subsplit_update
;;
*) die "Unknown command '$COMMAND'" ;;
esac
}
say()
{
if [ -z "$QUIET" ];
then
echo "$@"
fi
}
subsplit_require_work_dir()
{
if [ ! -e "$WORK_DIR" ]
then
die "Working directory not found at ${WORK_DIR}; please run init first"
fi
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} pushd \"${WORK_DIR}\" >/dev/null"
fi
pushd "$WORK_DIR" >/dev/null
}
subsplit_init()
{
if [ -e "$WORK_DIR" ]
then
die "Working directory already found at ${WORK_DIR}; please remove or run update"
fi
say "Initializing subsplit from origin (${REPO_URL})"
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} git clone -q \"${REPO_URL}\" \"${WORK_DIR}\""
fi
git clone -q "$REPO_URL" "$WORK_DIR" || die "Could not clone repository"
}
subsplit_publish()
{
subsplit_require_work_dir
if [ -n "$UPDATE" ];
then
subsplit_update
fi
if [ -z "$HEADS" ] && [ -z "$NO_HEADS" ]
then
# If heads are not specified and we want heads, discover them.
HEADS="$(git ls-remote origin 2>/dev/null | grep "refs/heads/" | cut -f3- -d/)"
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} HEADS=\"${HEADS}\""
fi
fi
if [ -z "$TAGS" ] && [ -z "$NO_TAGS" ]
then
# If tags are not specified and we want tags, discover them.
TAGS="$(git ls-remote origin 2>/dev/null | grep -v "\^{}" | grep "refs/tags/" | cut -f3 -d/)"
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} TAGS=\"${TAGS}\""
fi
fi
for SPLIT in $SPLITS
do
SUBPATH=$(echo "$SPLIT" | cut -f1 -d:)
REMOTE_URL=$(echo "$SPLIT" | cut -f2- -d:)
REMOTE_NAME=$(echo "$SPLIT" | git hash-object --stdin)
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} SUBPATH=${SUBPATH}"
echo "${DEBUG} REMOTE_URL=${REMOTE_URL}"
echo "${DEBUG} REMOTE_NAME=${REMOTE_NAME}"
fi
if ! git remote | grep "^${REMOTE_NAME}$" >/dev/null
then
git remote add "$REMOTE_NAME" "$REMOTE_URL"
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} git remote add \"${REMOTE_NAME}\" \"${REMOTE_URL}\""
fi
fi
say "Syncing ${SUBPATH} -> ${REMOTE_URL}"
for HEAD in $HEADS
do
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} git show-ref --quiet --verify -- \"refs/remotes/origin/${HEAD}\""
fi
if ! git show-ref --quiet --verify -- "refs/remotes/origin/${HEAD}"
then
say " - skipping head '${HEAD}' (does not exist)"
continue
fi
LOCAL_BRANCH="${REMOTE_NAME}-branch-${HEAD}"
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} LOCAL_BRANCH=\"${LOCAL_BRANCH}\""
fi
say " - syncing branch '${HEAD}'"
git checkout master >/dev/null 2>&1
git branch -D "$LOCAL_BRANCH" >/dev/null 2>&1
git branch -D "${LOCAL_BRANCH}-checkout" >/dev/null 2>&1
git checkout -b "${LOCAL_BRANCH}-checkout" "origin/${HEAD}" >/dev/null 2>&1
git subtree split -q --prefix="$SUBPATH" --branch="$LOCAL_BRANCH" "origin/${HEAD}" >/dev/null 2>&1
RETURNCODE=$?
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} git checkout master >/dev/null 2>&1"
echo "${DEBUG} git branch -D \"$LOCAL_BRANCH\" >/dev/null 2>&1"
echo "${DEBUG} git branch -D \"${LOCAL_BRANCH}-checkout\" >/dev/null 2>&1"
echo "${DEBUG} git checkout -b \"${LOCAL_BRANCH}-checkout\" \"origin/${HEAD}\" >/dev/null 2>&1"
echo "${DEBUG} git subtree split -q --prefix=\"$SUBPATH\" --branch=\"$LOCAL_BRANCH\" \"origin/${HEAD}\" >/dev/null 2>&1"
fi
if [ $RETURNCODE -eq 0 ]
then
PUSH_CMD="git push -q ${DRY_RUN} --force $REMOTE_NAME ${LOCAL_BRANCH}:${HEAD}"
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} $PUSH_CMD"
fi
if [ -n "$DRY_RUN" ]
then
echo \# $PUSH_CMD
$PUSH_CMD
else
$PUSH_CMD
fi
PUSHRETURNCODE=$?
if [ $PUSHRETURNCODE -eq 0 ]
then
say " - completed"
fi
fi
done
for TAG in $TAGS
do
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} git show-ref --quiet --verify -- \"refs/tags/${TAG}\""
fi
if ! git show-ref --quiet --verify -- "refs/tags/${TAG}"
then
say " - skipping tag '${TAG}' (does not exist)"
continue
fi
LOCAL_TAG="${REMOTE_NAME}-tag-${TAG}"
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} LOCAL_TAG="${LOCAL_TAG}""
fi
if git branch | grep "${LOCAL_TAG}$" >/dev/null && [ -z "$REBUILD_TAGS" ]
then
say " - skipping tag '${TAG}' (already synced)"
continue
fi
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} git branch | grep \"${LOCAL_TAG}$\" >/dev/null && [ -z \"${REBUILD_TAGS}\" ]"
fi
say " - syncing tag '${TAG}'"
say " - deleting '${LOCAL_TAG}'"
git branch -D "$LOCAL_TAG" >/dev/null 2>&1
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} git branch -D \"${LOCAL_TAG}\" >/dev/null 2>&1"
fi
say " - subtree split for '${TAG}'"
git subtree split -q --annotate="${ANNOTATE}" --prefix="$SUBPATH" --branch="$LOCAL_TAG" "$TAG" >/dev/null 2>&1
RETURNCODE=$?
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} git subtree split -q --annotate=\"${ANNOTATE}\" --prefix=\"$SUBPATH\" --branch=\"$LOCAL_TAG\" \"$TAG\" >/dev/null"
fi
say " - subtree split for '${TAG}' [DONE]"
if [ $RETURNCODE -eq 0 ]
then
PUSH_CMD="git push -q ${DRY_RUN} --force ${REMOTE_NAME} ${LOCAL_TAG}:refs/tags/${TAG}"
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} PUSH_CMD=\"${PUSH_CMD}\""
fi
if [ -n "$DRY_RUN" ]
then
echo \# $PUSH_CMD
$PUSH_CMD
else
$PUSH_CMD
fi
PUSHRETURNCODE=$?
if [ $PUSHRETURNCODE -eq 0 ]
then
say " - completed"
fi
fi
done
done
popd >/dev/null
}
subsplit_update()
{
subsplit_require_work_dir
say "Updating subsplit from origin"
git fetch -q -t origin
git checkout master
git reset --hard origin/master
if [ -n "$VERBOSE" ];
then
echo "${DEBUG} git fetch -q -t origin"
echo "${DEBUG} git checkout master"
echo "${DEBUG} git reset --hard origin/master"
fi
popd >/dev/null
}
subsplit_main "$@"

22
.github/workflows/subsplit-push.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: Subsplit
on:
push:
branches:
- '**'
jobs:
subsplit:
runs-on: ubuntu-latest
name: Split repositories
steps:
- name: Checkout history
uses: actions/checkout@v1
with:
fetch-depth: 0
- name: Split system module
run: ${GITHUB_WORKSPACE}/.github/workflows/scripts/subsplit/git-subsplit.sh publish --debug --path="${GITHUB_WORKSPACE}" --heads="${GITHUB_REF/refs\/heads\//}" --no-tags modules/system:https://bennothommo:${{ secrets.MAINTENANCE_TOKEN }}@github.com/octoberrain/system.git
- name: Split backend module
run: ${GITHUB_WORKSPACE}/.github/workflows/scripts/subsplit/git-subsplit.sh publish --debug --path="${GITHUB_WORKSPACE}" --heads="${GITHUB_REF/refs\/heads\//}" --no-tags modules/backend:https://bennothommo:${{ secrets.MAINTENANCE_TOKEN }}@github.com/octoberrain/backend.git
- name: Split CMS module
run: ${GITHUB_WORKSPACE}/.github/workflows/scripts/subsplit/git-subsplit.sh publish --debug --path="${GITHUB_WORKSPACE}" --heads="${GITHUB_REF/refs\/heads\//}" --no-tags modules/cms:https://bennothommo:${{ secrets.MAINTENANCE_TOKEN }}@github.com/octoberrain/cms.git

22
.github/workflows/subsplit-tag.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: Subsplit
on:
push:
tags:
- '**'
jobs:
subsplit:
runs-on: ubuntu-latest
name: Split repositories
steps:
- name: Checkout history
uses: actions/checkout@v1
with:
fetch-depth: 0
- name: Split system module
run: ${GITHUB_WORKSPACE}/.github/workflows/scripts/subsplit/git-subsplit.sh publish --debug --path="${GITHUB_WORKSPACE}" --tags="${GITHUB_REF/refs\/tags\//}" --no-heads modules/system:https://bennothommo:${{ secrets.MAINTENANCE_TOKEN }}@github.com/octoberrain/system.git
- name: Split backend module
run: ${GITHUB_WORKSPACE}/.github/workflows/scripts/subsplit/git-subsplit.sh publish --debug --path="${GITHUB_WORKSPACE}" --tags="${GITHUB_REF/refs\/tags\//}" --no-heads modules/backend:https://bennothommo:${{ secrets.MAINTENANCE_TOKEN }}@github.com/octoberrain/backend.git
- name: Split CMS module
run: ${GITHUB_WORKSPACE}/.github/workflows/scripts/subsplit/git-subsplit.sh publish --debug --path="${GITHUB_WORKSPACE}" --tags="${GITHUB_REF/refs\/tags\//}" --no-heads modules/cms:https://bennothommo:${{ secrets.MAINTENANCE_TOKEN }}@github.com/octoberrain/cms.git

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -13,6 +13,9 @@
<?php if ($relationSearchWidget): ?>
<?= $relationSearchWidget->render() ?>
<?php endif ?>
<?php if ($relationManageFilterWidget): ?>
<?= $relationManageFilterWidget->render() ?>
<?php endif ?>
<?= $relationManageWidget->render() ?>
</div>
@ -43,4 +46,4 @@
function(){ $('#relationManagePivotPopup input.form-control:first').focus() },
310
)
</script>
</script>

View File

@ -4,6 +4,7 @@ use Lang;
use Flash;
use Backend;
use Redirect;
use Response;
use BackendMenu;
use BackendAuth;
use Backend\Models\UserGroup;

View File

@ -11,7 +11,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="redirect:0"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"

View File

@ -19,7 +19,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.creating')) ?>"
class="btn btn-primary">
@ -28,7 +28,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.creating')) ?>"

View File

@ -19,7 +19,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="redirect:0"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
@ -29,7 +29,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"

View File

@ -19,7 +19,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.creating')) ?>"
class="btn btn-primary">
@ -28,7 +28,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.creating')) ?>"

View File

@ -19,7 +19,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="redirect:0"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
@ -29,7 +29,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"

View File

@ -20,7 +20,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.creating')) ?>"
class="btn btn-primary">
@ -29,7 +29,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('backend::lang.form.creating')) ?>"

View File

@ -22,7 +22,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="redirect:0"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
@ -33,7 +33,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"

View File

@ -24,7 +24,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="redirect:0"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
@ -34,7 +34,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"

View File

@ -1,6 +1,7 @@
<?php namespace Backend\Helpers;
use Url;
use File;
use Html;
use Config;
use Request;
@ -170,6 +171,30 @@ class Backend
* @return array
*/
public function decompileAsset(string $file, bool $skinAsset = false)
{
$assets = $this->parseAsset($file, $skinAsset);
return array_map(function ($asset) use ($skinAsset) {
// Resolve relative asset paths
if ($skinAsset) {
$assetPath = base_path(substr(Skin::getActive()->getPath($asset, true), 1));
} else {
$assetPath = base_path($asset);
}
$relativePath = File::localToPublic(realpath($assetPath));
return Url::asset($relativePath);
}, $assets);
}
/**
* Parse the provided asset file to get the files that it includes
*
* @param string $file The compilation asset file to parse
* @param boolean $skinAsset If true, will load decompiled assets from the "skins" directory.
* @return array
*/
protected function parseAsset($file, $skinAsset)
{
if ($skinAsset) {
$assetFile = base_path(substr(Skin::getActive()->getPath($file, true), 1));
@ -177,6 +202,8 @@ class Backend
$assetFile = base_path($file);
}
$results = [$file];
if (!file_exists($assetFile)) {
throw new DecompileException('File ' . $file . ' does not exist to be decompiled.');
}
@ -186,30 +213,23 @@ class Backend
$contents = file_get_contents($assetFile);
if (!preg_match('/^=require/m', $contents)) {
throw new DecompileException('File ' . $file . ' does not appear to be a compiled asset.');
}
// Find all assets that are compiled in this file
preg_match_all('/^=require\s+([A-z0-9-_+\.\/]+)$/m', $contents, $matches, PREG_SET_ORDER);
if (!count($matches)) {
throw new DecompileException('Unable to extract any asset paths when decompiled file ' . $file . '.');
}
// Determine correct asset path
$directory = str_replace(basename($file), '', $file);
return array_map(function ($match) use ($directory, $skinAsset) {
// Resolve relative asset paths
if ($skinAsset) {
$assetPath = base_path(substr(Skin::getActive()->getPath($directory . $match[1], true), 1));
} else {
$assetPath = base_path($directory . $match[1]);
}
$realPath = str_replace(base_path(), '', realpath($assetPath));
if (count($matches)) {
$results = array_map(function ($match) use ($directory) {
return $directory . $match[1];
}, $matches);
return Url::asset($realPath);
}, $matches);
foreach ($results as $i => $result) {
$nested = $this->parseAsset($result, $skinAsset);
array_splice($results, $i, 1, $nested);
}
}
return $results;
}
}

View File

@ -69,7 +69,12 @@ trait UploadableWidget
* See mime type handling in the asset manager
*/
if (!$uploadedFile->isValid()) {
throw new ApplicationException($uploadedFile->getErrorMessage());
if ($uploadedFile->getError() === UPLOAD_ERR_OK) {
$message = "The file \"{$uploadedFile->getClientOriginalName()}\" uploaded successfully but wasn't available at {$uploadedFile->getPathName()}. Check to make sure that nothing moved it away.";
} else {
$message = $uploadedFile->getErrorMessage();
}
throw new ApplicationException($message);
}
// Use the configured upload path unless it's null, in which case use the user-provided path
@ -113,7 +118,7 @@ trait UploadableWidget
'result' => 'success'
]);
} catch (\Exception $ex) {
$response = Response::make($ex->getMessage(), 400);
throw new ApplicationException($ex->getMessage());
}
return $response;

View File

@ -6,6 +6,7 @@ use Lang;
use File;
use Input;
use Config;
use Backend;
use Request;
use Response;
use Exception;
@ -79,7 +80,15 @@ class MediaManager extends WidgetBase
protected function loadAssets()
{
$this->addCss('css/mediamanager.css', 'core');
$this->addJs('js/mediamanager-browser-min.js', 'core');
if (Config::get('develop.decompileBackendAssets', false)) {
$scripts = Backend::decompileAsset($this->getAssetPath('js/mediamanager-browser.js'));
foreach ($scripts as $script) {
$this->addJs($script, 'core');
}
} else {
$this->addJs('js/mediamanager-browser-min.js', 'core');
}
}
/**

View File

@ -313,7 +313,8 @@ this.hideUploadUi()}
MediaManager.prototype.updateUploadBar=function(templateName,classNames){var fileNumberLabel=this.$el.get(0).querySelector('[data-label="file-number-and-progress"]'),successTemplate=fileNumberLabel.getAttribute('data-'+templateName+'-template'),progressBar=this.$el.get(0).querySelector('[data-control="upload-progress-bar"]')
fileNumberLabel.innerHTML=successTemplate;progressBar.setAttribute('class',classNames)}
MediaManager.prototype.uploadSuccess=function(){this.updateUploadBar('success','progress-bar progress-bar-success');}
MediaManager.prototype.uploadError=function(file,message){this.updateUploadBar('error','progress-bar progress-bar-danger');if(!message){message='Error uploading file'}
MediaManager.prototype.uploadError=function(file,message){this.updateUploadBar('error','progress-bar progress-bar-danger');if(file.xhr.status===413){message='Server rejected the file because it was too large, try increasing post_max_size';}
if(!message){message='Error uploading file'}
$.oc.alert(message)}
MediaManager.prototype.cropSelectedImage=function(callback){var selectedItems=this.getSelectedItems(true)
if(selectedItems.length!=1){alert(this.options.selectSingleImage)

View File

@ -820,6 +820,9 @@
MediaManager.prototype.uploadError = function(file, message) {
this.updateUploadBar('error', 'progress-bar progress-bar-danger');
if (file.xhr.status === 413) {
message = 'Server rejected the file because it was too large, try increasing post_max_size';
}
if (!message) {
message = 'Error uploading file'
}

View File

@ -19,7 +19,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="redirect:0"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('cms::lang.theme.saving')) ?>"
@ -29,7 +29,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('cms::lang.theme.saving')) ?>"

View File

@ -57,8 +57,6 @@ class AssetList extends WidgetBase
parent::__construct($controller, []);
$this->bindToController();
$this->checkUploadPostback();
}
/**
@ -622,10 +620,12 @@ class AssetList extends WidgetBase
}
/**
* Checks the current request to see if it is a postback containing a file upload
* for this particular widget.
* Process file uploads submitted via AJAX
*
* @return void
* @throws ApplicationException If the file "file_data" wasn't detected in the request or if the file failed to pass validation / security checks
*/
protected function checkUploadPostback()
public function onUpload()
{
$fileName = null;

View File

@ -83,6 +83,9 @@
}
AssetList.prototype.onUploadFail = function(file, message) {
if (file.xhr.status === 413) {
message = 'Server rejected the file because it was too large, try increasing post_max_size';
}
if (!message) {
message = 'Error uploading file'
}
@ -170,6 +173,7 @@
$.each(self.$form.serializeArray(), function (index, field) {
formData.append(field.name, field.value)
})
xhr.setRequestHeader('X-OCTOBER-REQUEST-HANDLER', self.alias + '::onUpload')
self.onUploadStart()
})
}

View File

@ -4,7 +4,7 @@ if(window.jQuery.request!==undefined){throw new Error('The OctoberCMS framework
+function($){"use strict";var Request=function(element,handler,options){var $el=this.$el=$(element);this.options=options||{};if(handler===undefined){throw new Error('The request handler name is not specified.')}
if(!handler.match(/^(?:\w+\:{2})?on*/)){throw new Error('Invalid handler name. The correct handler name format is: "onEvent".')}
var $form=options.form?$(options.form):$el.closest('form'),$triggerEl=!!$form.length?$form:$el,context={handler:handler,options:options}
if((options.validate!==undefined)&&typeof document.createElement('input').reportValidity=='function'&&$form&&$form[0]&&!$form[0].checkValidity()){$form[0].reportValidity();return false;}
if((options.browserValidate!==undefined)&&typeof document.createElement('input').reportValidity=='function'&&$form&&$form[0]&&!$form[0].checkValidity()){$form[0].reportValidity();return false;}
$el.trigger('ajaxSetup',[context])
var _event=jQuery.Event('oc.beforeRequest')
$triggerEl.trigger(_event,context)
@ -103,7 +103,7 @@ return result.join('&')}
var old=$.fn.request
$.fn.request=function(handler,option){var args=arguments
var $this=$(this).first()
var data={evalBeforeUpdate:$this.data('request-before-update'),evalSuccess:$this.data('request-success'),evalError:$this.data('request-error'),evalComplete:$this.data('request-complete'),ajaxGlobal:$this.data('request-ajax-global'),confirm:$this.data('request-confirm'),redirect:$this.data('request-redirect'),loading:$this.data('request-loading'),flash:$this.data('request-flash'),files:$this.data('request-files'),validate:$this.data('request-validate'),form:$this.data('request-form'),url:$this.data('request-url'),update:paramToObj('data-request-update',$this.data('request-update')),data:paramToObj('data-request-data',$this.data('request-data'))}
var data={evalBeforeUpdate:$this.data('request-before-update'),evalSuccess:$this.data('request-success'),evalError:$this.data('request-error'),evalComplete:$this.data('request-complete'),ajaxGlobal:$this.data('request-ajax-global'),confirm:$this.data('request-confirm'),redirect:$this.data('request-redirect'),loading:$this.data('request-loading'),flash:$this.data('request-flash'),files:$this.data('request-files'),browserValidate:$this.data('browser-validate'),form:$this.data('request-form'),url:$this.data('request-url'),update:paramToObj('data-request-update',$this.data('request-update')),data:paramToObj('data-request-data',$this.data('request-data'))}
if(!handler)handler=$this.data('request')
var options=$.extend(true,{},Request.DEFAULTS,data,typeof option=='object'&&option)
return new Request($this,handler,options)}

View File

@ -4,7 +4,7 @@ if(window.jQuery.request!==undefined){throw new Error('The OctoberCMS framework
+function($){"use strict";var Request=function(element,handler,options){var $el=this.$el=$(element);this.options=options||{};if(handler===undefined){throw new Error('The request handler name is not specified.')}
if(!handler.match(/^(?:\w+\:{2})?on*/)){throw new Error('Invalid handler name. The correct handler name format is: "onEvent".')}
var $form=options.form?$(options.form):$el.closest('form'),$triggerEl=!!$form.length?$form:$el,context={handler:handler,options:options}
if((options.validate!==undefined)&&typeof document.createElement('input').reportValidity=='function'&&$form&&$form[0]&&!$form[0].checkValidity()){$form[0].reportValidity();return false;}
if((options.browserValidate!==undefined)&&typeof document.createElement('input').reportValidity=='function'&&$form&&$form[0]&&!$form[0].checkValidity()){$form[0].reportValidity();return false;}
$el.trigger('ajaxSetup',[context])
var _event=jQuery.Event('oc.beforeRequest')
$triggerEl.trigger(_event,context)
@ -103,7 +103,7 @@ return result.join('&')}
var old=$.fn.request
$.fn.request=function(handler,option){var args=arguments
var $this=$(this).first()
var data={evalBeforeUpdate:$this.data('request-before-update'),evalSuccess:$this.data('request-success'),evalError:$this.data('request-error'),evalComplete:$this.data('request-complete'),ajaxGlobal:$this.data('request-ajax-global'),confirm:$this.data('request-confirm'),redirect:$this.data('request-redirect'),loading:$this.data('request-loading'),flash:$this.data('request-flash'),files:$this.data('request-files'),validate:$this.data('request-validate'),form:$this.data('request-form'),url:$this.data('request-url'),update:paramToObj('data-request-update',$this.data('request-update')),data:paramToObj('data-request-data',$this.data('request-data'))}
var data={evalBeforeUpdate:$this.data('request-before-update'),evalSuccess:$this.data('request-success'),evalError:$this.data('request-error'),evalComplete:$this.data('request-complete'),ajaxGlobal:$this.data('request-ajax-global'),confirm:$this.data('request-confirm'),redirect:$this.data('request-redirect'),loading:$this.data('request-loading'),flash:$this.data('request-flash'),files:$this.data('request-files'),browserValidate:$this.data('browser-validate'),form:$this.data('request-form'),url:$this.data('request-url'),update:paramToObj('data-request-update',$this.data('request-update')),data:paramToObj('data-request-data',$this.data('request-data'))}
if(!handler)handler=$this.data('request')
var options=$.extend(true,{},Request.DEFAULTS,data,typeof option=='object'&&option)
return new Request($this,handler,options)}

View File

@ -39,7 +39,7 @@ if (window.jQuery.request !== undefined) {
/*
* Validate the form client-side
*/
if ((options.validate !== undefined) && typeof document.createElement('input').reportValidity == 'function' && $form && $form[0] && !$form[0].checkValidity()) {
if ((options.browserValidate !== undefined) && typeof document.createElement('input').reportValidity == 'function' && $form && $form[0] && !$form[0].checkValidity()) {
$form[0].reportValidity();
return false;
}
@ -446,7 +446,7 @@ if (window.jQuery.request !== undefined) {
loading: $this.data('request-loading'),
flash: $this.data('request-flash'),
files: $this.data('request-files'),
validate: $this.data('request-validate'),
browserValidate: $this.data('browser-validate'),
form: $this.data('request-form'),
url: $this.data('request-url'),
update: paramToObj('data-request-update', $this.data('request-update')),

View File

@ -4959,6 +4959,11 @@ while(current){if(current.propertyName){result.push(current.propertyName)}
current=current.parentSurface}
result.reverse()
return result.join('.')}
Surface.prototype.findDependentProperties=function(propertyName){var dependents=[]
for(var i in this.rawProperties){var property=this.rawProperties[i]
if(!property.depends){continue}
if(property.depends.indexOf(propertyName)!==-1){dependents.push(property.property)}}
return dependents}
Surface.prototype.mergeChildSurface=function(surface,mergeAfterRow){var rows=surface.tableContainer.querySelectorAll('table.inspector-fields > tbody > tr')
surface.tableContainer=this.getRootSurface().tableContainer
for(var i=rows.length-1;i>=0;i--){var row=rows[i]
@ -5631,6 +5636,7 @@ select.appendChild(option)}
DropdownEditor.prototype.createOptions=function(select,options){for(var value in options){this.createOption(select,options[value],value)}}
DropdownEditor.prototype.initCustomSelect=function(){var select=this.getSelect()
var options={dropdownCssClass:'ocInspectorDropdown'}
if(this.propertyDefinition.emptyOption!==undefined){options.placeholder=this.propertyDefinition.emptyOption}
if(this.propertyDefinition.placeholder!==undefined){options.placeholder=this.propertyDefinition.placeholder}
options.templateResult=this.formatSelectOption
options.templateSelection=this.formatSelectOption
@ -5638,7 +5644,7 @@ options.escapeMarkup=function(m){return m}
$(select).select2(options)
if(!Modernizr.touchevents){this.indicatorContainer=$('.select2-container',this.containerCell)
this.indicatorContainer.addClass('loading-indicator-container size-small')}}
DropdownEditor.prototype.createPlaceholder=function(select){var placeholder=this.propertyDefinition.placeholder
DropdownEditor.prototype.createPlaceholder=function(select){var placeholder=this.propertyDefinition.placeholder||this.propertyDefinition.emptyOption
if(placeholder!==undefined&&!Modernizr.touchevents){this.createOption(select,null,null)}
if(placeholder!==undefined&&Modernizr.touchevents){this.createOption(select,placeholder,null)}}
DropdownEditor.prototype.getSelect=function(){return this.containerCell.querySelector('select')}
@ -5655,7 +5661,7 @@ DropdownEditor.prototype.registerHandlers=function(){var select=this.getSelect()
$(select).on('change',this.proxy(this.onSelectionChange))}
DropdownEditor.prototype.onSelectionChange=function(){var select=this.getSelect()
this.inspector.setPropertyValue(this.propertyDefinition.property,this.normalizeValue(select.value),this.initialization)}
DropdownEditor.prototype.onInspectorPropertyChanged=function(property,value){if(!this.propertyDefinition.depends||this.propertyDefinition.depends.indexOf(property)===-1){return}
DropdownEditor.prototype.onInspectorPropertyChanged=function(property){if(!this.propertyDefinition.depends||this.propertyDefinition.depends.indexOf(property)===-1){return}
var dependencyValues=this.getDependencyValues()
if(this.prevDependencyValues===undefined||this.prevDependencyValues!=dependencyValues){this.loadDynamicOptions()}}
DropdownEditor.prototype.onExternalPropertyEditorHidden=function(){if(this.dynamicOptions){this.loadDynamicOptions(false)}}
@ -5678,10 +5684,12 @@ this.createPlaceholder(select)
this.createOptions(select,this.propertyDefinition.options)
if(value===undefined){value=this.propertyDefinition.default}
select.value=value}
DropdownEditor.prototype.loadDynamicOptions=function(initialization){var currentValue=this.inspector.getPropertyValue(this.propertyDefinition.property),data=this.getRootSurface().getValues(),self=this,$form=$(this.getSelect()).closest('form')
DropdownEditor.prototype.loadDynamicOptions=function(initialization){var currentValue=this.inspector.getPropertyValue(this.propertyDefinition.property),data=this.getRootSurface().getValues(),self=this,$form=$(this.getSelect()).closest('form'),dependents=this.inspector.findDependentProperties(this.propertyDefinition.property)
if(currentValue===undefined){currentValue=this.propertyDefinition.default}
var callback=function dropdownOptionsRequestDoneClosure(data){self.hideLoadingIndicator()
self.optionsRequestDone(data,currentValue,true)}
self.optionsRequestDone(data,currentValue,true)
if(dependents.length>0){for(var i in dependents){var editor=self.inspector.findPropertyEditor(dependents[i])
if(editor&&typeof editor.onInspectorPropertyChanged==='function'){editor.onInspectorPropertyChanged(self.propertyDefinition.property)}}}}
if(this.propertyDefinition.depends){this.saveDependencyValues()}
data['inspectorProperty']=this.getPropertyPath()
data['inspectorClassName']=this.inspector.options.inspectorClass
@ -6626,7 +6634,7 @@ for(var i=0,len=this.propertyDefinition.depends.length;i<len;i++){var property=t
if(value===undefined){value='';}
result+=property+':'+value+'-'}
return result}
AutocompleteEditor.prototype.onInspectorPropertyChanged=function(property,value){if(!this.propertyDefinition.depends||this.propertyDefinition.depends.indexOf(property)===-1){return}
AutocompleteEditor.prototype.onInspectorPropertyChanged=function(property){if(!this.propertyDefinition.depends||this.propertyDefinition.depends.indexOf(property)===-1){return}
this.clearAutoUpdateTimeout()
if(this.prevDependencyValues===undefined||this.prevDependencyValues!=dependencyValues){this.autoUpdateTimeout=setTimeout(this.proxy(this.loadDynamicItems),200)}}
AutocompleteEditor.prototype.clearAutoUpdateTimeout=function(){if(this.autoUpdateTimeout!==null){clearTimeout(this.autoUpdateTimeout)

View File

@ -224,9 +224,9 @@ class PluginManager
}
/**
* Verify that the provided plugin should be registered
* Prevent autoloaders from loading if plugin is disabled
*/
if (!$plugin || $plugin->disabled || (self::$noInit && !$plugin->elevated)) {
if ($plugin->disabled) {
return;
}
@ -238,6 +238,13 @@ class PluginManager
ComposerManager::instance()->autoload($pluginPath . '/vendor');
}
/**
* Disable plugin registration for restricted pages, unless elevated
*/
if (self::$noInit && !$plugin->elevated) {
return;
}
/**
* Run the plugin's register() method
*/

View File

@ -19,7 +19,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="redirect:0"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"

View File

@ -18,7 +18,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('system::lang.mail_templates.creating_layout')) ?>"
class="btn btn-primary">
@ -27,7 +27,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('system::lang.mail_templates.creating_layout')) ?>"

View File

@ -29,7 +29,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="redirect:0"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('system::lang.mail_templates.saving_layout')) ?>"
@ -39,7 +39,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('system::lang.mail_templates.saving_layout')) ?>"

View File

@ -18,7 +18,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('system::lang.mail_templates.creating_partial')) ?>"
class="btn btn-primary">
@ -27,7 +27,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('system::lang.mail_templates.creating_partial')) ?>"

View File

@ -29,7 +29,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="redirect:0"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('system::lang.mail_templates.saving_layout')) ?>"
@ -39,7 +39,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('system::lang.mail_templates.saving_layout')) ?>"

View File

@ -18,7 +18,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('system::lang.mail_templates.creating')) ?>"
class="btn btn-primary">
@ -27,7 +27,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('system::lang.mail_templates.creating')) ?>"

View File

@ -29,7 +29,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="redirect:0"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('system::lang.mail_templates.saving')) ?>"
@ -39,7 +39,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('system::lang.mail_templates.saving')) ?>"

View File

@ -11,7 +11,7 @@
<button
type="submit"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="redirect:0"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
@ -21,7 +21,7 @@
<button
type="button"
data-request="onSave"
data-request-validate
data-browser-validate
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"

View File

@ -1 +0,0 @@
console.log('Legitimate file');

View File

@ -22,12 +22,4 @@ class BackendHelperTest extends TestCase
$backendHelper = new Backend;
$assets = $backendHelper->decompileAsset('tests/fixtures/backend/assets/missing.js');
}
public function testDecompileNonCompilationFile()
{
$this->expectException(DecompileException::class);
$backendHelper = new Backend;
$assets = $backendHelper->decompileAsset('tests/fixtures/backend/assets/not-compilation.js');
}
}