diff --git a/.htaccess b/.htaccess index cfae3fa39..b710aed85 100644 --- a/.htaccess +++ b/.htaccess @@ -29,38 +29,40 @@ ## White listed folders and files ## RewriteCond %{REQUEST_FILENAME} -f - RewriteCond %{REQUEST_URI} !\.js - RewriteCond %{REQUEST_URI} !\.map - RewriteCond %{REQUEST_URI} !\.ico - RewriteCond %{REQUEST_URI} !\.jpg - RewriteCond %{REQUEST_URI} !\.jpeg - RewriteCond %{REQUEST_URI} !\.bmp - RewriteCond %{REQUEST_URI} !\.png - RewriteCond %{REQUEST_URI} !\.gif - RewriteCond %{REQUEST_URI} !\.svg - RewriteCond %{REQUEST_URI} !\.css - RewriteCond %{REQUEST_URI} !\.less - RewriteCond %{REQUEST_URI} !\.scss - RewriteCond %{REQUEST_URI} !\.pdf - RewriteCond %{REQUEST_URI} !\.swf - RewriteCond %{REQUEST_URI} !\.txt - RewriteCond %{REQUEST_URI} !\.xml - RewriteCond %{REQUEST_URI} !\.xls - RewriteCond %{REQUEST_URI} !\.eot - RewriteCond %{REQUEST_URI} !\.woff - RewriteCond %{REQUEST_URI} !\.woff2 - RewriteCond %{REQUEST_URI} !\.ttf - RewriteCond %{REQUEST_URI} !\.flv - RewriteCond %{REQUEST_URI} !\.wmv - RewriteCond %{REQUEST_URI} !\.mp3 - RewriteCond %{REQUEST_URI} !\.ogg - RewriteCond %{REQUEST_URI} !\.wav - RewriteCond %{REQUEST_URI} !\.avi - RewriteCond %{REQUEST_URI} !\.mov - RewriteCond %{REQUEST_URI} !\.mp4 - RewriteCond %{REQUEST_URI} !\.mpeg - RewriteCond %{REQUEST_URI} !\.webm - RewriteCond %{REQUEST_URI} !\.mkv + RewriteCond %{REQUEST_URI} !\.js$ + RewriteCond %{REQUEST_URI} !\.map$ + RewriteCond %{REQUEST_URI} !\.ico$ + RewriteCond %{REQUEST_URI} !\.jpg$ + RewriteCond %{REQUEST_URI} !\.jpeg$ + RewriteCond %{REQUEST_URI} !\.bmp$ + RewriteCond %{REQUEST_URI} !\.png$ + RewriteCond %{REQUEST_URI} !\.gif$ + RewriteCond %{REQUEST_URI} !\.svg$ + RewriteCond %{REQUEST_URI} !\.css$ + RewriteCond %{REQUEST_URI} !\.less$ + RewriteCond %{REQUEST_URI} !\.scss$ + RewriteCond %{REQUEST_URI} !\.pdf$ + RewriteCond %{REQUEST_URI} !\.swf$ + RewriteCond %{REQUEST_URI} !\.txt$ + RewriteCond %{REQUEST_URI} !\.xml$ + RewriteCond %{REQUEST_URI} !\.xls$ + RewriteCond %{REQUEST_URI} !\.eot$ + RewriteCond %{REQUEST_URI} !\.woff$ + RewriteCond %{REQUEST_URI} !\.woff2$ + RewriteCond %{REQUEST_URI} !\.ttf$ + RewriteCond %{REQUEST_URI} !\.flv$ + RewriteCond %{REQUEST_URI} !\.wmv$ + RewriteCond %{REQUEST_URI} !\.mp3$ + RewriteCond %{REQUEST_URI} !\.ogg$ + RewriteCond %{REQUEST_URI} !\.wav$ + RewriteCond %{REQUEST_URI} !\.avi$ + RewriteCond %{REQUEST_URI} !\.mov$ + RewriteCond %{REQUEST_URI} !\.mp4$ + RewriteCond %{REQUEST_URI} !\.mpeg$ + RewriteCond %{REQUEST_URI} !\.webm$ + RewriteCond %{REQUEST_URI} !\.mkv$ + RewriteCond %{REQUEST_URI} !\.rar$ + RewriteCond %{REQUEST_URI} !\.zip$ RewriteCond %{REQUEST_URI} !docs/.* RewriteCond %{REQUEST_URI} !themes/.* RewriteRule ^ index.php [L,NC] diff --git a/.travis.yml b/.travis.yml index 20b6e700a..81ca66d41 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,9 @@ matrix: sudo: false -install: travis_retry composer install --no-interaction --prefer-source +install: + - composer self-update + - travis_retry composer install --no-interaction --prefer-source before_script: git reset --hard HEAD diff --git a/CHANGELOG.md b/CHANGELOG.md index 1841ed7c2..13bc33a72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +* **Build 317** (2015-02-24) + - The `/404` route now returns 404 HTTP response code as it should. + - Updated the `.htaccess` file with a minor security precaution. + +* **Build 316** (2015-02-11) + - Various back-end UI enhancements used for the [Builder plugin](http://octobercms.com/plugin/rainlab-builder). + * **Build 313** (2015-12-12) - Added a `clickable` option to list columns (see Backend > Lists docs). diff --git a/composer.json b/composer.json index 8f432ab70..da51917f9 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,7 @@ "october/backend": "dev-stable", "october/cms": "dev-stable", "laravel/framework": "5.1.*" + "wikimedia/composer-merge-plugin": "dev-master" }, "require-dev": { "fzaninotto/faker": "~1.4", @@ -52,5 +53,15 @@ "preferred-install": "dist" }, "minimum-stability": "dev", - "prefer-stable": true + "prefer-stable": true, + "extra": { + "merge-plugin": { + "include": [ + "plugins/*/*/composer.json" + ], + "recurse": true, + "replace": false, + "merge-dev": false +} + } } diff --git a/modules/backend/behaviors/ListController.php b/modules/backend/behaviors/ListController.php index 714c22040..882ef3a3a 100644 --- a/modules/backend/behaviors/ListController.php +++ b/modules/backend/behaviors/ListController.php @@ -3,6 +3,7 @@ use Str; use Lang; use Event; +use Flash; use ApplicationException; use Backend\Classes\ControllerBehavior; @@ -107,7 +108,7 @@ class ListController extends ControllerBehavior * Create the model */ $class = $listConfig->modelClass; - $model = new $class(); + $model = new $class; $model = $this->controller->listExtendModel($model, $definition); /* @@ -211,7 +212,6 @@ class ListController extends ControllerBehavior * Filter the list when the scopes are changed */ $filterWidget->bindEvent('filter.update', function () use ($widget, $filterWidget) { - $widget->addFilter([$filterWidget, 'applyAllScopesToQuery']); return $widget->onRefresh(); }); @@ -245,6 +245,72 @@ class ListController extends ControllerBehavior $this->makeLists(); } + /** + * Bulk delete records. + * @return void + */ + public function index_onDelete() + { + if (method_exists($this->controller, 'onDelete')) { + return call_user_func_array([$this->controller, 'onDelete'], func_get_args()); + } + + /* + * Validate checked identifiers + */ + $checkedIds = post('checked'); + + if (!$checkedIds || !is_array($checkedIds) || !count($checkedIds)) { + Flash::error(Lang::get('backend::lang.list.delete_selected_empty')); + return $this->controller->listRefresh(); + } + + /* + * Establish the list definition + */ + $definition = post('definition', $this->primaryDefinition); + + if (!isset($this->listDefinitions[$definition])) { + throw new ApplicationException(Lang::get('backend::lang.list.missing_parent_definition', compact('definition'))); + } + + $listConfig = $this->makeConfig($this->listDefinitions[$definition], $this->requiredConfig); + + /* + * Create the model + */ + $class = $listConfig->modelClass; + $model = new $class; + $model = $this->controller->listExtendModel($model, $definition); + + /* + * Create the query + */ + $query = $model->newQuery(); + $this->controller->listExtendQueryBefore($query, $definition); + + $query->whereIn($model->getKeyName(), $checkedIds); + $this->controller->listExtendQuery($query, $definition); + + /* + * Delete records + */ + $records = $query->get(); + + if ($records->count()) { + foreach ($records as $record) { + $record->delete(); + } + + Flash::success(Lang::get('backend::lang.list.delete_selected_success')); + } + else { + Flash::error(Lang::get('backend::lang.list.delete_selected_empty')); + } + + return $this->controller->listRefresh(); + } + /** * Renders the widget collection. * @param string $definition Optional list definition. diff --git a/modules/backend/behaviors/RelationController.php b/modules/backend/behaviors/RelationController.php index 028452e85..dddf8b4a8 100644 --- a/modules/backend/behaviors/RelationController.php +++ b/modules/backend/behaviors/RelationController.php @@ -686,7 +686,8 @@ class RelationController extends ControllerBehavior if ($this->viewMode == 'single') { $config->showCheckboxes = false; $config->recordOnClick = sprintf( - "$.oc.relationBehavior.clickManageListRecord(:id, '%s', '%s')", + "$.oc.relationBehavior.clickManageListRecord(:%s, '%s', '%s')", + $this->relationModel->getKeyName(), $this->field, $this->relationGetSessionKey() ); @@ -696,7 +697,8 @@ class RelationController extends ControllerBehavior } elseif ($isPivot) { $config->recordOnClick = sprintf( - "$.oc.relationBehavior.clickManagePivotListRecord(:id, '%s', '%s')", + "$.oc.relationBehavior.clickManagePivotListRecord(:%s, '%s', '%s')", + $this->relationModel->getKeyName(), $this->field, $this->relationGetSessionKey() ); diff --git a/modules/backend/behaviors/UserPreferencesModel.php b/modules/backend/behaviors/UserPreferencesModel.php index d65b40623..ea6a1ab25 100644 --- a/modules/backend/behaviors/UserPreferencesModel.php +++ b/modules/backend/behaviors/UserPreferencesModel.php @@ -109,6 +109,8 @@ class UserPreferencesModel extends SettingsModel */ protected function getCacheKey() { - return 'backend::userpreferences.'.$this->recordCode; + $item = UserPreferences::forUser(); + $userId = $item->userContext ? $item->userContext->id : 0; + return $this->recordCode.'-userpreference-'.$userId; } } diff --git a/modules/backend/formwidgets/DataTable.php b/modules/backend/formwidgets/DataTable.php index 121b97273..fc33b2546 100644 --- a/modules/backend/formwidgets/DataTable.php +++ b/modules/backend/formwidgets/DataTable.php @@ -3,6 +3,7 @@ use Lang; use Backend\Widgets\Table; use Backend\Classes\FormWidgetBase; +use October\Rain\Html\Helper as HtmlHelper; use ApplicationException; /** @@ -106,8 +107,8 @@ class DataTable extends FormWidgetBase */ public function getSaveValue($value) { - // TODO: provide a streaming implementation of saving - // data to the model. The current implementation returns + // TODO: provide a streaming implementation of saving + // data to the model. The current implementation returns // all records at once. -ab $dataSource = $this->table->getDataSource(); @@ -133,7 +134,7 @@ class DataTable extends FormWidgetBase { $dataSource = $this->table->getDataSource(); - // TODO: provide a streaming implementation of loading + // TODO: provide a streaming implementation of loading // data from the model. The current implementation loads // all records at once. -ab @@ -150,10 +151,10 @@ class DataTable extends FormWidgetBase // It's safe to use the field name as an alias // as field names do not repeat in forms. This - // approach lets to access the table data by the + // approach lets to access the table data by the // field name in POST requests directly (required // in some edge cases). - $config->alias = $this->fieldName; + $config->alias = studly_case(HtmlHelper::nameToId($this->fieldName)) . 'datatable'; $table = new Table($this->controller, $config); diff --git a/modules/backend/formwidgets/RecordFinder.php b/modules/backend/formwidgets/RecordFinder.php index 03a9f39b3..bc5c985a1 100644 --- a/modules/backend/formwidgets/RecordFinder.php +++ b/modules/backend/formwidgets/RecordFinder.php @@ -16,7 +16,7 @@ use Backend\Classes\FormWidgetBase; * prompt: Click the Find button to find a user * nameFrom: name * descriptionFrom: email - * + * * @package october\backend * @author Alexey Bobkov, Samuel Georges */ @@ -232,7 +232,7 @@ class RecordFinder extends FormWidgetBase $config->showSetup = false; $config->showCheckboxes = false; $config->recordsPerPage = 20; - $config->recordOnClick = sprintf("$('#%s').recordFinder('updateRecord', this, ':id')", $this->getId()); + $config->recordOnClick = sprintf("$('#%s').recordFinder('updateRecord', this, ':" . $this->keyFrom . "')", $this->getId()); $widget = $this->makeWidget('Backend\Widgets\Lists', $config); // $widget->bindEvent('list.extendQueryBefore', function($query) { diff --git a/modules/backend/lang/de/lang.php b/modules/backend/lang/de/lang.php index 9e8279dd0..c0000d0d8 100644 --- a/modules/backend/lang/de/lang.php +++ b/modules/backend/lang/de/lang.php @@ -248,5 +248,45 @@ return [ ], 'filter' => [ 'all' => 'Alle' - ] + ], + 'import_export' => [ + 'upload_csv_file' => '1. CSV-Datei hochladen', + 'import_file' => 'Datei importieren', + 'first_row_contains_titles' => 'Erste Zeile enthält Spaltentitel', + 'first_row_contains_titles_desc' => 'Aktiviert lassen, falls erste Zeile Spaltentitel enthält.', + 'match_columns' => '2. Spalten der Datei den Datenbankfeldern zuordnen', + 'file_columns' => 'Spalten der Datei', + 'database_fields' => 'Datenbankfelder', + 'set_import_options' => '3. Importoptionen festlegen', + 'export_output_format' => '1. Exportformat wählen', + 'file_format' => 'Dateiformat', + 'standard_format' => 'Standardformat', + 'custom_format' => 'Benutzerdefiniertes Format', + 'delimiter_char' => 'Trennzeichen', + 'enclosure_char' => 'Textqualifizierer', + 'escape_char' => 'Escape-Zeichen', + 'select_columns' => '2. Spalten für den Export auswählen', + 'column' => 'Spalte', + 'columns' => 'Spalten', + 'set_export_options' => '3. Exportoptionen festlegen', + 'show_ignored_columns' => 'Ignorierte Spalten anzeigen', + 'auto_match_columns' => 'Spalten automatisch zuordnen', + 'created' => 'Erstellt', + 'updated' => 'Geändert', + 'skipped' => 'Übersprungen', + 'warnings' => 'Warnungen', + 'errors' => 'Fehler', + 'skipped_rows' => 'Übersprungene Zeilen', + 'import_progress' => 'Import-Fortschritt', + 'processing' => 'Verarbeite', + 'import_error' => 'Import-Fehler', + 'upload_valid_csv' => 'Bitte eine gültige CSV-Datei hochladen.', + 'drop_column_here' => 'Spalte hier ablegen...', + 'ignore_this_column' => 'Diese Spalte ignorieren', + 'processing_successful_line1' => 'Datei-Exportvorgang erfolgreich abgeschlossen!', + 'processing_successful_line2' => 'Ihr Browser sollte Sie nun automatisch zum Download weiterleiten.', + 'export_progress' => 'Export-Fortschritt', + 'export_error' => 'Export-Fehler', + 'column_preview' => 'Spaltenvorschau', + ], ]; diff --git a/modules/backend/lang/en/lang.php b/modules/backend/lang/en/lang.php index 837137278..80fea9b74 100644 --- a/modules/backend/lang/en/lang.php +++ b/modules/backend/lang/en/lang.php @@ -125,6 +125,7 @@ return [ 'missing_column' => 'There are no column definitions for :columns.', 'missing_columns' => 'List used in :class has no list columns defined.', 'missing_definition' => "List behavior does not contain a column for ':field'.", + 'missing_parent_definition' => "List behavior does not contain a definition for ':definition'.", 'behavior_not_ready' => 'List behavior has not been initialized, check that you have called makeLists() in your controller.', 'invalid_column_datetime' => "Column value ':column' is not a DateTime object, are you missing a \$dates reference in the Model?", 'pagination' => 'Displayed records: :from-:to of :total', @@ -369,5 +370,7 @@ return [ 'export_progress' => 'Export progress', 'export_error' => 'Export error', 'column_preview' => 'Column preview', + 'file_not_found_error' => 'File not found', + 'empty_error' => 'There was no data supplied to export', ], ]; diff --git a/modules/backend/lang/fa/lang.php b/modules/backend/lang/fa/lang.php index 6edd19772..b3cb9332c 100644 --- a/modules/backend/lang/fa/lang.php +++ b/modules/backend/lang/fa/lang.php @@ -6,7 +6,7 @@ return [ ], 'field' => [ 'invalid_type' => 'نوع فیلد :type نا معتبر می باشد.', - 'options_method_not_exists' => 'کلاس مدل :model باید شامل متد :method() باشد و گزینه های مورد نیاز ":field" را بازگرداند.', + 'options_method_not_exists' => 'کلاس مدل :model باید شامل متد :method() باشد و گزینه های مورد نیاز ":field" را بازنشاند.', ], 'widget' => [ 'not_registered' => "کلاس مربوط به ابزارک ':name' به سیستم معرفی نشده است", @@ -30,7 +30,7 @@ return [ 'sign_out' => 'خروج', 'login' => 'ورود', 'reset' => 'تنظیم مجدد', - 'restore' => 'بازگرداندن', + 'restore' => 'بازنشاندن', 'login_placeholder' => 'ورود', 'password_placeholder' => 'کلمه عبور', 'forgot_password' => "کلمه عبور خود را فراموش کرده اید؟", @@ -38,12 +38,12 @@ return [ 'enter_login' => "نام کاربری خود را وارد نمایید", 'email_placeholder' => "پست الکترونیکی", 'enter_new_password' => "کلمه عبور جدید را وارد نمایید", - 'password_reset' => "بازگرداندن کلمه عبور", + 'password_reset' => "بازنشاندن کلمه عبور", 'restore_success' => "یک نامه به پست الکترونیکی شما جهت شروع عملیات بارگرداندن کلمه عبور ارسال شد.", 'restore_error' => "کاربری با نام کاریری ':login' یافت نشد.", 'reset_success' => "کلمه عبور شما بارگردانی شد و شما هم اکنون میتوانید وارد سیستم شوید.", 'reset_error' => "اطلاعات رمز عبور نا معتبر است , لطفا مجددا تلاش نمایید!", - 'reset_fail' => "عدم توانایی در بازگرداندن کلمه عبور شما!", + 'reset_fail' => "عدم توانایی در بازنشاندن کلمه عبور شما!", 'apply' => 'اعمال کردن', 'cancel' => 'انصراف', 'delete' => 'حذف', @@ -84,7 +84,7 @@ return [ 'full_name' => "نام کامل", 'email' => "پست الکترونیکی", 'groups' => "گروه ها", - 'groups_comment' => "مختص گروهی که این شخص به آن تعلق دارد.", + 'groups_comment' => "اختصاص به گروهی که این شخص به آن تعلق دارد.", 'avatar' => "نمایه", 'password' => "کلمه عبور", 'password_confirmation' => "تکرار کلمه عبور", @@ -130,6 +130,8 @@ return [ 'pagination' => 'نمایش :from تا :to از :total مورد', 'prev_page' => 'صفحه قبل', 'next_page' => 'صفحه بعد', + 'refresh' => 'بازنشانی', + 'updating' => 'درحال به روز رسانی...', 'loading' => 'در حال بارگذاری...', 'setup_title' => 'راه اندازی لیست', 'setup_help' => 'ستون هایی را که میخواهید مشاهده نمایید را انتخاب نمایید. میتوانید محل قرار گیری ستونها را با جابجا نمودن آنها به .', @@ -139,13 +141,15 @@ return [ 'delete_selected_empty' => 'مورد جهت حذف انتخاب نشده است.', 'delete_selected_confirm' => 'آیا میخواهید موارد انتخابی را حذف کنید؟', 'delete_selected_success' => 'حدف موارد انخابی انجام شد.', + 'column_switch_true' => 'بله', + 'column_switch_false' => 'خیر' ], 'fileupload' => [ 'attachment' => 'فایل ضمیمه', - 'help' => 'برای فایل ضمیمه عنوان و توضیح مختصری وارد نمایید.', + 'help' => 'برای فایل ضمیمه عنوان و توضیح اختصاص بهری وارد نمایید.', 'title_label' => 'عنوان', 'description_label' => 'توضیحات', - 'default_prompt' => 'فایل را جهت ارسال به این نقطه بکشید و یا %s را کلیک کنیید', + 'default_prompt' => 'فایل را جهت ارسال به این نقطه بکشید و یا %s را کلیک کنید', 'attachment_url' => 'آدرس پیوست', 'upload_file' => 'ارسال فایل', 'upload_error' => 'خطا در ارسال فایل', @@ -174,13 +178,15 @@ return [ 'saving_name' => 'درحال ذخیره :name...', 'delete' => 'حذف', 'deleting' => 'در حال حذف...', + 'confirm_delete' => 'آیا از حذف این مورد اطمینان دارید؟', + 'confirm_delete_multiple' => 'آیا از حذف موارد انتخاب شده اطمینان دارید؟', 'deleting_name' => 'درحال حذف :name...', 'reset_default' => 'بازگشت به پیش فرض', - 'resetting' => 'بازگذاری مجدد', - 'resetting_name' => 'بارگذاری :name', + 'resetting' => 'بازنشانی', + 'resetting_name' => 'بازنشانی name:', 'undefined_tab' => 'متفرقه', - 'field_off' => 'خاموش', - 'field_on' => 'روشن', + 'field_off' => 'بله', + 'field_on' => 'خیر', 'add' => 'افزودن', 'apply' => 'اعمال', 'cancel' => 'انصراف', @@ -199,9 +205,14 @@ return [ 'select_none' => 'هیچ', 'select_placeholder' => 'لطفا انتخاب نمایید', 'insert_row' => 'افزودن سطر', + 'insert_row_below' => 'افزودن سطر بعد از', 'delete_row' => 'حذف سطر', 'concurrency_file_changed_title' => 'فایل تغییر کرد', 'concurrency_file_changed_description' => 'فایلی که شما ویرایش کردید توسط کاربر دیگری تغییر یافته و ذخیره شده است. شما میتوانید فایل را مجددا بارگذاری نمایید و تغییراتی که اعمال کرده اید را از دست بدهید و یا تغییرات اعمال شده توسط آن کاربر را بین برده و فایل را بازنویسی نمایید.', + 'return_to_list' => 'بازگشت به لیست' + ], + 'recordfinder' => [ + 'find_record' => 'انتخاب مورد' ], 'relation' => [ 'missing_config' => "کنترل کننده ارتباطات پایگاه داده شامل تعریفی برای ':config' نمی باشد.", @@ -247,7 +258,7 @@ return [ 'missing_relation' => "مدل ':class' شامل تعریفی از ':relation'.", 'missing_method' => "مدل ':class' متدی با نام ':method' ندارد.", 'invalid_class' => "مدل :model استفاده شده در :class معتبر نمی باشد، این مدل باید از کلاس \Model ارث برده باشد.", - 'mass_assignment_failed' => "Mass assignment failed for Model attribute ':attribute'.", + 'mass_assignment_failed' => "عدم توانایی در مقدار دهی ':attribute'.", ], 'warnings' => [ 'tips' => 'راهنمایی پیکر بندی سیستم', @@ -270,7 +281,7 @@ return [ 'theme' => 'رنگ بندی', ], 'tooltips' => [ - 'preview_website' => 'پیش نماسش وب سایت' + 'preview_website' => 'پیش نمایش وب سایت' ], 'mysettings' => [ 'menu_label' => 'تنظیمات من', @@ -311,12 +322,52 @@ return [ 'menu_description' => 'نمایش لیست ورود موفقیت آمیز کاربران مدیر.', 'created_at' => 'زمان و تاریخ', 'login' => 'ورود', - 'ip_address' => 'آدرس آی پی', + 'ip_address' => 'آدرس IP', 'first_name' => 'نام', - 'last_name' => 'نام خوانوادگی', + 'last_name' => 'نام خانوادگی', 'email' => 'پست الکترونیکی', ], 'filter' => [ 'all' => 'همه' ], + 'import_export' => [ + 'upload_csv_file' => '1. ارسال فایل CSV.', + 'import_file' => 'درورن ریزی فایل', + 'first_row_contains_titles' => 'سطر اول شامل عنوان ستون ها می باشد', + 'first_row_contains_titles_desc' => 'اگر سطر اول فایل CSV حاوی عنوان ستون ها می باشد این گزینه را انتخاب نمایید.', + 'match_columns' => '2. مطابقت سازی ستون های فایل با فیلد های پایگاه داده', + 'file_columns' => 'ستون های فایل', + 'database_fields' => 'فیلد های پایگاه داده', + 'set_import_options' => '3. تنظیم گزینه های درون ریزی', + 'export_output_format' => '1. قالب خروجی برون ریزی', + 'file_format' => 'نوع فایل', + 'standard_format' => 'قالب استاندارد', + 'custom_format' => 'قالب سفارشی', + 'delimiter_char' => 'کاراکار جدا کننده', + 'enclosure_char' => 'کاراکتر Enclosure', + 'escape_char' => 'کاراکتر Escape', + 'select_columns' => '2. انتخاب ستون ها جهت برون ریزی', + 'column' => 'ستون', + 'columns' => 'ستون ها', + 'set_export_options' => '3. تنظیم گزینه های برون ریزی', + 'show_ignored_columns' => 'نمایش ستون های نادیده گرفته شده', + 'auto_match_columns' => 'مطابقت خودکار ستون ها', + 'created' => 'ایجاد شده', + 'updated' => 'به روز رسانی شده', + 'skipped' => 'نادیده گرفته شده', + 'warnings' => 'هشدار ها', + 'errors' => 'خطاها', + 'skipped_rows' => 'سطر های نادیده گرفته شده', + 'import_progress' => 'پردازش درون ریزی', + 'processing' => 'در حال پردازش', + 'import_error' => 'خطا در درون ریزی', + 'upload_valid_csv' => 'لطفا فایل CSV معتبری را ارسال نمایید', + 'drop_column_here' => 'ستون را این جا بکشید...', + 'ignore_this_column' => 'این ستون را نادیده بگیر', + 'processing_successful_line1' => 'عملیات برون ریزی فایل با موفقیت انجام شد', + 'processing_successful_line2' => 'مرورگر به صورت خودکار به آدرس دانلود فایل هدایت خواهد شد. ', + 'export_progress' => 'پردازش برون ریزی', + 'export_error' => 'خطا در ایجاد خروجی', + 'column_preview' => 'پیش نمایش ستون', + ], ]; diff --git a/modules/backend/lang/fr/lang.php b/modules/backend/lang/fr/lang.php index 3fde1d150..94b3c770b 100644 --- a/modules/backend/lang/fr/lang.php +++ b/modules/backend/lang/fr/lang.php @@ -189,7 +189,7 @@ return [ 'close' => 'Fermer', 'confirm' => 'Confirmer', 'reload' => 'Recharger', - 'complete' => 'Complet', + 'complete' => 'Terminé', 'ok' => 'OK', 'or' => 'ou', 'confirm_tab_close' => 'Confirmer la fermeture de cet onglet ? Les modifications réalisées seront perdues.', @@ -317,4 +317,46 @@ return [ 'filter' => [ 'all' => 'tous' ], + 'import_export' => [ + 'upload_csv_file' => '1. Envoyer un fichier CSV', + 'import_file' => 'Importer un fichier', + 'first_row_contains_titles' => 'La première ligne contient les titres des colonnes', + 'first_row_contains_titles_desc' => 'Laissez coché si la première ligne du fichier CSV contient les titres des colonnes.', + 'match_columns' => '2. Faire correspondre les colonnes du fichier avec les champs du modèle de données', + 'file_columns' => 'Colonnes du fichier', + 'database_fields' => 'Champs de la base de données', + 'set_import_options' => '3. Fixer les options d’importation', + 'export_output_format' => '1. Format de sortie de l’export', + 'file_format' => 'Format du fichier', + 'standard_format' => 'Format Standard', + 'custom_format' => 'Format Personnalisé', + 'delimiter_char' => 'Caractère séparateur', + 'enclosure_char' => 'Caractère d’encadrement', + 'escape_char' => 'Caractère d’échappement', + 'select_columns' => '2. Choisissez les colonnes à exporter', + 'column' => 'Colonne', + 'columns' => 'Colonnes', + 'set_export_options' => '3. Fixer les options d’exportation', + 'show_ignored_columns' => 'Voir les colonnes ignorées', + 'auto_match_columns' => 'Correspondance automatique des colonnes', + 'created' => 'Créés', + 'updated' => 'Mis à jour', + 'skipped' => 'Ignorés', + 'warnings' => 'Alertes', + 'errors' => 'Erreurs', + 'skipped_rows' => 'Lignes ignorées', + 'import_progress' => 'Progression de l’import', + 'processing' => 'Traitement', + 'import_error' => 'Erreur d’import', + 'upload_valid_csv' => 'Veuillez envoyer un fichier CSV valide.', + 'drop_column_here' => 'Déposez les colonnes ici...', + 'ignore_this_column' => 'Ignorer cette colonne', + 'processing_successful_line1' => 'Le processus d’export du fichier s’est terminé avec succès !', + 'processing_successful_line2' => 'Le navigateur devrait automatiquement vous rediriger vers le téléchargement du fichier.', + 'export_progress' => 'Progression de l’export', + 'export_error' => 'Erreur d’export', + 'column_preview' => 'Prévisualisation des colonnes', + 'file_not_found_error' => 'Fichier non trouvé', + 'empty_error' => 'Il n‘y a aucune donnée à exporter', + ], ]; diff --git a/modules/backend/lang/pl/lang.php b/modules/backend/lang/pl/lang.php index 355661e8c..dea253e49 100644 --- a/modules/backend/lang/pl/lang.php +++ b/modules/backend/lang/pl/lang.php @@ -138,7 +138,9 @@ return [ 'delete_selected' => 'Usuń zaznaczone', 'delete_selected_empty' => 'Nie wybrano elementów do usunięcia.', 'delete_selected_confirm' => 'Usunąć zaznaczone elementy?', - 'delete_selected_success' => 'Pomyślnie usunięto zaznaczone elementy.' + 'delete_selected_success' => 'Pomyślnie usunięto zaznaczone elementy.', + 'column_switch_true' => 'Tak', + 'column_switch_false' => 'Nie' ], 'fileupload' => [ 'attachment' => 'Załącznik', diff --git a/modules/backend/lang/pt-br/lang.php b/modules/backend/lang/pt-br/lang.php index 6fde8f9c2..44066a241 100644 --- a/modules/backend/lang/pt-br/lang.php +++ b/modules/backend/lang/pt-br/lang.php @@ -130,6 +130,8 @@ return [ 'pagination' => 'Registros exibidos: :from-:to de :total', 'prev_page' => 'Anterior', 'next_page' => 'Próxima', + 'refresh' => 'Atualizar', + 'updating' => 'Atualizando...', 'loading' => 'Carregando...', 'setup_title' => 'Configuração da Lista', 'setup_help' => 'Selecione as colunas que deseja ver na lista. Você pode alterar as posições das colunas arrastando-as para cima ou para baixo.', @@ -139,6 +141,8 @@ return [ 'delete_selected_empty' => 'Não há registros selecionados para excluir.', 'delete_selected_confirm' => 'Excluir os registros selecionados?', 'delete_selected_success' => 'Registros selecionados excluídos com sucesso.', + 'column_switch_true' => 'Sim', + 'column_switch_false' => 'Não' ], 'fileupload' => [ 'attachment' => 'Anexo', @@ -174,6 +178,8 @@ return [ 'saving_name' => 'Salvando :name...', 'delete' => 'Apagar', 'deleting' => 'Apagando...', + 'confirm_delete' => 'Você realmente deseja apagar este registro?', + 'confirm_delete_multiple' => 'Você realmente deseja apagar os registros selecionados?', 'deleting_name' => 'Apagando :name...', 'reset_default' => 'Redefinir para o padrão', 'resetting' => 'Redefinindo', @@ -199,9 +205,14 @@ return [ 'select_none' => 'nenhum', 'select_placeholder' => 'por favor, selecione', 'insert_row' => 'Inserir linha', + 'insert_row_below' => 'Inserir linha abaixo', 'delete_row' => 'Excluir linha', 'concurrency_file_changed_title' => 'O arquivo foi alterado', 'concurrency_file_changed_description' => 'O arquivo que você está editando foi alterado em disco. Você pode recarregá-lo e perder suas alterações ou sobrescrever o arquivo do disco.', + 'return_to_list' => 'Retornar à lista', + ], + 'recordfinder' => [ + 'find_record' => 'Localizar Registro' ], 'relation' => [ 'missing_config' => 'Comportamento relation não tem uma configuração para ":config".', @@ -209,7 +220,7 @@ return [ 'missing_model' => 'Comportamento relation utilizado na classe :class não possui um model definido.', 'invalid_action_single' => 'Essa ação não pode ser realizada num relacionamento singular.', 'invalid_action_multi' => 'Essa ação não pode ser realizada num relacionamento múltiplo.', - 'help' => 'Clique em um item para adicionar', + 'help' => 'Clique em um item para adicionar', 'related_data' => 'Dados de :name relacionado', 'add' => 'Adicionar', 'add_selected' => 'Adicionar seleção', @@ -236,6 +247,10 @@ return [ 'unlink_name' => 'Desvincular :name', 'unlink_confirm' => 'Você tem certeza?', ], + 'reorder' => [ + 'default_title' => 'Reordenar registros', + 'no_records' => 'Não há registros disponíveis para ordenar.', + ], 'model' => [ 'name' => 'Model', 'not_found' => 'Model ":class" com ID :id não foi encontrado', @@ -260,6 +275,7 @@ return [ 'code_folding' => 'Código flexível', 'word_wrap' => 'Quebra de linha', 'highlight_active_line' => 'Destaque na linha ativa', + 'auto_closing' => 'Auto completar tags e caracteres especiais', 'show_invisibles' => 'Mostrar caracteres invisíveis', 'show_gutter' => 'Mostrar numeração de linhas', 'theme' => 'Esquema de cores', @@ -314,4 +330,46 @@ return [ 'filter' => [ 'all' => 'todos', ], + 'import_export' => [ + 'upload_csv_file' => '1. Enviar arquivo CSV', + 'import_file' => 'Importar arquivo', + 'first_row_contains_titles' => 'Primeira linha contém títulos das colunas', + 'first_row_contains_titles_desc' => 'Deixe marcado se primeira linha do CSV é utilizada como títulos das colunas.', + 'match_columns' => '2. Associar as colunas do arquivo a campos do banco de dados', + 'file_columns' => 'Colunas do arquivo', + 'database_fields' => 'Campos do banco de dados', + 'set_import_options' => '3. Definir opções de importação', + 'export_output_format' => '1. Formato de saída da exportação', + 'file_format' => 'Formato do arquivo', + 'standard_format' => 'Formato padrão', + 'custom_format' => 'Formato personalizado', + 'delimiter_char' => 'Caracter delimitador', + 'enclosure_char' => 'Caracter qualificador', + 'escape_char' => 'Caracter de escape', + 'select_columns' => '2. Selecione colunas para exportar', + 'column' => 'Coluna', + 'columns' => 'Colunas', + 'set_export_options' => '3. Definir opções de exportação', + 'show_ignored_columns' => 'Mostrar colunas ignoradas', + 'auto_match_columns' => 'Auto associar colunas', + 'created' => 'Criados', + 'updated' => 'Atualizados', + 'skipped' => 'Ignorados', + 'warnings' => 'Alertas', + 'errors' => 'Erros', + 'skipped_rows' => 'Registros Ignorados', + 'import_progress' => 'Progresso da Importação', + 'processing' => 'Processando', + 'import_error' => 'Erro de importação', + 'upload_valid_csv' => 'Por favor envie um arquivo CSV válido.', + 'drop_column_here' => 'Soltar coluna aqui...', + 'ignore_this_column' => 'Ignorar esta coluna', + 'processing_successful_line1' => 'Processo de exportação de arquivo concluído com sucesso!', + 'processing_successful_line2' => 'O navegador agora deve redirecionar automaticamente para o download do arquivo.', + 'export_progress' => 'Progresso da exportação', + 'export_error' => 'Erro de exportação', + 'column_preview' => 'Pré-visualizar coluna', + 'file_not_found_error' => 'Arquivo não encontrado', + 'empty_error' => 'Não havia dados fornecidos para exportar', + ], ]; diff --git a/modules/backend/lang/ru/lang.php b/modules/backend/lang/ru/lang.php index 90404e55d..b20688864 100644 --- a/modules/backend/lang/ru/lang.php +++ b/modules/backend/lang/ru/lang.php @@ -130,6 +130,8 @@ return [ 'pagination' => 'Отображено записей: :from-:to из :total', 'prev_page' => 'Предыдущая страница', 'next_page' => 'Следующая страница', + 'refresh' => 'Обновить', + 'updating' => 'Обновление...', 'loading' => 'Загрузка...', 'setup_title' => 'Настройка списка', 'setup_help' => 'Используйте флажки для выбора колонок, которые вы хотите видеть в списке. Вы можете изменить положение столбцов, перетаскивая их вверх или вниз.', @@ -176,6 +178,8 @@ return [ 'saving_name' => 'Сохранение :name...', 'delete' => 'Удалить', 'deleting' => 'Удаление...', + 'confirm_delete' => 'Вы действительно хотите удалить эту запись?', + 'confirm_delete_multiple' => 'Вы действительно хотите удалить выбранные записи?', 'deleting_name' => 'Удаление :name...', 'reset_default' => 'Сбросить настройки', 'resetting' => 'Сброс', @@ -204,7 +208,11 @@ return [ 'insert_row_below' => 'Вставить строку ниже', 'delete_row' => 'Удалить строку', 'concurrency_file_changed_title' => 'Файл был изменен', - 'concurrency_file_changed_description' => 'Файл, который вы редактируете был изменен другим пользователем. Вы можете либо перезагрузить файл и потерять ваши изменения или перезаписать его' + 'concurrency_file_changed_description' => 'Файл,редактируемый вами, был изменен другим пользователем. Вы можете перезагрузить файл и потерять ваши изменения или перезаписать его', + 'return_to_list' => 'Вернуться к списку' + ], + 'recordfinder' => [ + 'find_record' => 'Найти запись' ], 'relation' => [ 'missing_config' => "Поведение отношения не имеет конфигурации для ':config'.", @@ -321,5 +329,47 @@ return [ ], 'filter' => [ 'all' => 'все' - ] + ], + 'import_export' => [ + 'upload_csv_file' => '1. Загрузка CSV-файл', + 'import_file' => 'Импорт файла', + 'first_row_contains_titles' => 'Первая строка содержит заголовки столбцов', + 'first_row_contains_titles_desc' => 'Выберите эту опцию, если первая строка в CSV-файле используется как заголовки для столбцов.', + 'match_columns' => '2. Применение столбцов файла к полям базы данных', + 'file_columns' => 'Столбцы файла', + 'database_fields' => 'Поля базы данных', + 'set_import_options' => '3. Установка параметров импорта', + 'export_output_format' => '1. Выбор формата экспорта', + 'file_format' => 'Формат файла', + 'standard_format' => 'Стандартный формат', + 'custom_format' => 'Пользовательский формат', + 'delimiter_char' => 'Символ разделения полей', + 'enclosure_char' => 'Символ обрамления полей', + 'escape_char' => 'Экранирующий символ', + 'select_columns' => '2. Выберите колонки для экспорта', + 'column' => 'Столбец', + 'columns' => 'Столбцы', + 'set_export_options' => '3. Установка параметров экспорта', + 'show_ignored_columns' => 'Показать пропущенные столбцы', + 'auto_match_columns' => 'Авто применение столбцов', + 'created' => 'Создано', + 'updated' => 'Обновлено', + 'skipped' => 'Пропущено', + 'warnings' => 'Предупреждения', + 'errors' => 'Ошибки', + 'skipped_rows' => 'Пропущенные строки', + 'import_progress' => 'Прогресс импорта', + 'processing' => 'Обработка', + 'import_error' => 'Ошибка импорта', + 'upload_valid_csv' => 'Пожалуйста, загрузите валидный CSV-файл..', + 'drop_column_here' => 'Отпустите столбец здесь...', + 'ignore_this_column' => 'Игонорировать этот столбец', + 'processing_successful_line1' => 'Процесс экспорта файла завершился успешно!', + 'processing_successful_line2' => 'Теперь браузер автоматически должен начать загрузку файла.', + 'export_progress' => 'Прогресс экспорта', + 'export_error' => 'Ошибка экспорта', + 'column_preview' => 'Предпросмотр столбца', + 'file_not_found_error' => 'Файл не найден', + 'empty_error' => 'Нет данных доступных для экспорта', + ], ]; diff --git a/modules/backend/lang/tr/lang.php b/modules/backend/lang/tr/lang.php index 6d5aa5484..6862b4c72 100644 --- a/modules/backend/lang/tr/lang.php +++ b/modules/backend/lang/tr/lang.php @@ -130,6 +130,8 @@ return [ 'pagination' => 'Gösterilen kayıtlar: :from-:to Toplam: :total', 'prev_page' => 'Önceki sayfa', 'next_page' => 'Sonraki sayfa', + 'refresh' => 'Yenile', + 'updating' => 'Güncelleniyor...', 'loading' => 'Yükleniyor...', 'setup_title' => 'Liste Ayarları', 'setup_help' => 'Listede görmek istediğiniz sütunları seçmek için onay kutularını kullanın. Sütunları yukarı veya aşağı sürükleyerek konumlarını değiştirebilirsiniz.', @@ -138,7 +140,9 @@ return [ 'delete_selected' => 'Seçili olanı sil', 'delete_selected_empty' => 'Silinecek seçili kayıt bulunamadı.', 'delete_selected_confirm' => 'Seçili kayıtları silmek istediğize emin misiniz?', - 'delete_selected_success' => 'Seçili kayıtlar başarıyla silindi.' + 'delete_selected_success' => 'Seçili kayıtlar başarıyla silindi.', + 'column_switch_true' => 'Evet', + 'column_switch_false' => 'Hayır' ], 'fileupload' => [ 'attachment' => 'Dosya Eki', @@ -174,6 +178,8 @@ return [ 'saving_name' => 'Kaydediliyor :name...', 'delete' => 'Sil', 'deleting' => 'Siliniyor...', + 'confirm_delete' => 'Bu kaydı silmek istediğinize emin misiniz?', + 'confirm_delete_multiple' => 'Seçilen kayıtları silmek istediğinize emin misiniz?', 'deleting_name' => 'Siliniyor :name...', 'reset_default' => 'Ön Tanımlı Ayarlara Dön!', 'resetting' => 'İşleniyor', @@ -199,11 +205,17 @@ return [ 'select_none' => 'hiçbiri', 'select_placeholder' => 'lütfen seçin', 'insert_row' => 'Kayıt Ekle', + 'insert_row_below' => 'Alt Satıra Kayıt Ekle', 'delete_row' => 'Kayıt Sil', 'concurrency_file_changed_title' => 'Dosya değiştirildi', - 'concurrency_file_changed_description' => "Düzenlemeye çalıştığınız dosya disk üzerinde başka bir kullanıcı tarafından değiştirilmiş. Dosyayı yeniden yükleyebilir ve değişiklikleri kaybedersiniz ya da diskteki dosyayı kendi düzenlediğiniz hali ile değiştirebilirsiniz." + 'concurrency_file_changed_description' => "Düzenlemeye çalıştığınız dosya disk üzerinde başka bir kullanıcı tarafından değiştirilmiş. Dosyayı yeniden yükleyebilir ve değişiklikleri kaybedersiniz ya da diskteki dosyayı kendi düzenlediğiniz hali ile değiştirebilirsiniz.", + 'return_to_list' => 'Listeye dön' + ], + 'recordfinder' => [ + 'find_record' => 'Kayıt Bul' ], 'relation' => [ + 'missing_config' => "İlişki ':config' için bir yapılandırma ayarı içermiyor.", 'missing_definition' => "İlişki ':field' için bir sütun değeri içermiyor.", 'missing_model' => ":class da kullanılan ilişki için model değeri tanımlanmamış.", 'invalid_action_single' => "Bu işlem tekli ilişkilendirme için kullanılamaz.", @@ -317,5 +329,45 @@ return [ ], 'filter' => [ 'all' => 'tümü' - ] + ], + 'import_export' => [ + 'upload_csv_file' => '1. Bir CSV dosyası yükleyin', + 'import_file' => 'Dosya İçeri Aktar', + 'first_row_contains_titles' => 'İlk satır, sütun isimlerini içermelidir', + 'first_row_contains_titles_desc' => 'Eğer CSV dosyanızda ilk satır, sütun isimlerini içeriyorsa bu seçeneği işaretleyin.', + 'match_columns' => '2. Veritabanı sütunları ile dosyanızdaki verileri eşleştirin', + 'file_columns' => 'Dosyadaki sütunlar', + 'database_fields' => 'Veritabanındaki sütunlar', + 'set_import_options' => '3. İçeri aktarmayı yapılandırın', + 'export_output_format' => '1. Dışarı aktarma formatı', + 'file_format' => 'Dosya formatı', + 'standard_format' => 'Standart format', + 'custom_format' => 'Özel format', + 'delimiter_char' => 'Ayırıcı karakter', + 'enclosure_char' => 'Kapsayıcı karakter', + 'escape_char' => 'Kaçış karakteri', + 'select_columns' => '2. Dışarı aktarılacak sütunları seçin', + 'column' => 'Sütun', + 'columns' => 'Sütunlar', + 'set_export_options' => '3. Dışarı aktarmayı yapılandırın', + 'show_ignored_columns' => 'Göz ardı edilen sütunları göster', + 'auto_match_columns' => 'Sütunları otomatik eşleştir', + 'created' => 'Oluşturulma', + 'updated' => 'Güncellenme', + 'skipped' => 'Atlandı', + 'warnings' => 'Uyarılar', + 'errors' => 'Hatalar', + 'skipped_rows' => 'Atlanan Satırlar', + 'import_progress' => 'İçeri aktarma ilerlemesi', + 'processing' => 'İşleniyor', + 'import_error' => 'İçeri aktarma hatası', + 'upload_valid_csv' => 'Lütfen geçerli bir CSV dosyası seçin.', + 'drop_column_here' => 'Sütunu buraya bırakın...', + 'ignore_this_column' => 'Bu sütunu göz ardı et', + 'processing_successful_line1' => 'Dosya dışarı aktarma işlemi başarıyla tamamlandı!', + 'processing_successful_line2' => 'Tarayıcınız dosyayı otomatik olarak indirecektir', + 'export_progress' => 'Dışarı aktarma ilerlemesi', + 'export_error' => 'Dışarı aktarma hatası', + 'column_preview' => 'Sütun önizlemesi', + ], ]; diff --git a/modules/backend/models/ExportModel.php b/modules/backend/models/ExportModel.php index 84b0d43d8..f10b6829d 100644 --- a/modules/backend/models/ExportModel.php +++ b/modules/backend/models/ExportModel.php @@ -55,12 +55,12 @@ abstract class ExportModel extends Model public function download($name, $outputName = null) { if (!preg_match('/^oc[0-9a-z]*$/i', $name)) { - throw new ApplicationException('File not found'); + throw new ApplicationException(Lang::get('backend::lang.import_export.file_not_found_error')); } $csvPath = temp_path() . '/' . $name; if (!file_exists($csvPath)) { - throw new ApplicationException('File not found'); + throw new ApplicationException(Lang::get('backend::lang.import_export.file_not_found_error')); } $headers = Response::download($csvPath, $outputName)->headers->all(); @@ -80,7 +80,7 @@ abstract class ExportModel extends Model * Validate */ if (!$results) { - throw new ApplicationException('There was no data supplied to export'); + throw new ApplicationException(Lang::get('backend::lang.import_export.empty_error')); } /* diff --git a/modules/backend/models/User.php b/modules/backend/models/User.php index 4aaefd3f6..def0a1b6f 100644 --- a/modules/backend/models/User.php +++ b/modules/backend/models/User.php @@ -1,6 +1,7 @@ codeMap; } - /** + /** * Returns an array of all component detail definitions. * @return array Array keys are component codes, values are the details defined in the component. */ @@ -210,7 +211,7 @@ class ComponentManager )); } - $component = new $className($cmsObject, $properties); + $component = App::make($className, [$cmsObject, $properties]); $component->name = $name; return $component; diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index c52c25d7f..59e39d395 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -190,7 +190,7 @@ class Controller /* * If the page was not found, render the 404 page - either provided by the theme or the built-in one. */ - if (!$page) { + if (!$page || $url === '404') { $this->setStatusCode(404); // Log the 404 request @@ -753,6 +753,7 @@ class Controller public function renderPartial($name, $parameters = [], $throwException = true) { $vars = $this->vars; + $this->vars = array_merge($this->vars, $parameters); /* * Alias @ symbol for :: diff --git a/modules/cms/classes/MediaLibrary.php b/modules/cms/classes/MediaLibrary.php index 2bfadb3ef..76bfa8aee 100644 --- a/modules/cms/classes/MediaLibrary.php +++ b/modules/cms/classes/MediaLibrary.php @@ -125,9 +125,9 @@ class MediaLibrary /** * Finds files in the Library. * @param string $searchTerm Specifies the search term. - * @param string $sortBy Determines the sorting preference. + * @param string $sortBy Determines the sorting preference. * Supported values are 'title', 'size', 'lastModified' (see SORT_BY_XXX class constants). - * @param string $filter Determines the document type filtering preference. + * @param string $filter Determines the document type filtering preference. * Supported values are 'image', 'video', 'audio', 'document' (see FILE_TYPE_XXX constants of MediaLibraryItem class). * @return array Returns an array of MediaLibraryItem objects. */ @@ -381,14 +381,30 @@ class MediaLibrary $path = str_replace('\\', '/', $path); $path = '/'.trim($path, '/'); - if ($normalizeOnly) + if ($normalizeOnly) { return $path; + } - if (strpos($path, '..') !== false) - throw new ApplicationException(Lang::get('cms::lang.media.invalid_path', ['path'=>$path])); + $regexDirectorySeparator = preg_quote(DIRECTORY_SEPARATOR, '/'); + $regexDot = preg_quote('.', '/'); + $regex = [ + // Checks for parent or current directory reference at beginning of path + '(^'.$regexDot.'+?'.$regexDirectorySeparator.')', - if (strpos($path, './') !== false || strpos($path, '//') !== false) - throw new ApplicationException(Lang::get('cms::lang.media.invalid_path', ['path'=>$path])); + // Check for parent or current directory reference in middle of path + '('.$regexDirectorySeparator.$regexDot.'+?'.$regexDirectorySeparator.')', + + // Check for parent or current directory reference at end of path + '('.$regexDirectorySeparator.$regexDot.'+?$)', + ]; + + /* + * Combine everything to one regex + */ + $regex = '/'.implode('|', $regex).'/'; + if (preg_match($regex, $path) !== 0 || strpos($path, '//') !== false) { + throw new ApplicationException(Lang::get('cms::lang.media.invalid_path', compact('path'))); + } return $path; } @@ -537,7 +553,7 @@ class MediaLibrary /** * Sorts the item list by title, size or last modified date. * @param array $itemList Specifies the item list to sort. - * @param string $sortBy Determines the sorting preference. + * @param string $sortBy Determines the sorting preference. * Supported values are 'title', 'size', 'lastModified' (see SORT_BY_XXX class constants). */ protected function sortItemList(&$itemList, $sortBy) @@ -567,7 +583,7 @@ class MediaLibrary /** * Filters item list by file type. * @param array $itemList Specifies the item list to sort. - * @param string $filter Determines the document type filtering preference. + * @param string $filter Determines the document type filtering preference. * Supported values are 'image', 'video', 'audio', 'document' (see FILE_TYPE_XXX constants of MediaLibraryItem class). */ protected function filterItemList(&$itemList, $filter) @@ -586,7 +602,7 @@ class MediaLibrary /** * Initializes and returns the Media Library disk. - * This method should always be used instead of trying to access the + * This method should always be used instead of trying to access the * $storageDisk property directly as initializing the disc requires * communicating with the remote storage. * @return mixed Returns the storage disk object. diff --git a/modules/cms/lang/fa/lang.php b/modules/cms/lang/fa/lang.php index 038fad914..fd26d58fa 100644 --- a/modules/cms/lang/fa/lang.php +++ b/modules/cms/lang/fa/lang.php @@ -5,21 +5,21 @@ return [ 'invalid_file' => 'نام :name برای فایل نام معتبر است. نام فایل میتواند شامل کاراکتر انگلیسی ، خط تیره و نقطه باشد. بعنوان مثال page.htm، page و subdirectory/page', 'invalid_property' => 'عدم توانایی در تغییر خاصیت ":name"', 'file_already_exists' => 'فایلی با نام ":name" موجود است.', - 'error_saving' => 'خطا در ذخیره فایل ":name". لطفا حق دسترسی ها را بررسی نمایید.', - 'error_creating_directory' => 'خطا در ایجاد پوشه ی :name. لطفا حق دسترسی ها را بررسی نمایید.', + 'error_saving' => 'خطا در ذخیره فایل ":name". لطفا سطح دسترسی ها را بررسی نمایید.', + 'error_creating_directory' => 'خطا در ایجاد پوشه ی :name. لطفا سطح دسترسی ها را بررسی نمایید.', 'invalid_file_extension'=>'پسوند :invalid برای فایل نا معتبر است. پسوند های معتبر عبارتند از: :allowed.', - 'error_deleting' => 'خطا در خذف فایل ":name". لطفا حق دسترسی ها را بررسی نمایید.', + 'error_deleting' => 'خطا در خذف فایل ":name". لطفا سطح دسترسی ها را بررسی نمایید.', 'delete_success' => 'تعداد :count فایل با موفقیت حذف شد.', 'file_name_required' => 'نام فایل را وارد نمایید.' ], 'theme' => [ - 'not_found_name' => "یافت ن قالبی با نام ':name یافت نشد.'", + 'not_found_name' => "یافتن قالبی با نام ':name یافت نشد.'", 'active' => [ - 'not_set' => "قالب فعال مشخص نشده است.", - 'not_found' => "قالب فعال یافت نشد.", + 'not_set' => "قالب فعال انتخاب نشده است.", + 'not_found' => "قالب فعال یافت نشد", ], 'edit' => [ - 'not_set' => "قالب ویرایش مشخص نشده ایت.", + 'not_set' => "قالب ویرایش مشخص نشده است.", 'not_found' => "قالب ویرایش یافت نشد.", 'not_match' => "شی مورد نظر شما در قالبی که ویرایش می کنید یافت نشد. لطفا صفحه را مجددا بارگذاری نمایید." ], @@ -56,7 +56,7 @@ return [ 'import_title' => 'وارد کردن قالب', 'import_theme_success' => 'عملیات وارد کردن قالب با موفقیت انجام شد', 'import_uploaded_file' => 'فایل قالب', - 'import_overwrite_label' => 'جایگذینی فایلها در صورت موجود بودن آنها', + 'import_overwrite_label' => 'جایگزینی فایلها در صورت موجود بودن آنها', 'import_overwrite_comment' => 'اگر میخواهید فقط فایل های جدید وارد شوند این گزینه را غیر فعال کنید.', 'import_folders_label' => 'پوشه ها', 'import_folders_comment' => 'لطفا پوشه قالب هایی را که میخواهید وارد کنید را انتخاب نمایید', @@ -150,7 +150,7 @@ return [ 'title' => 'عنوان', 'new_title' => 'عنوان صفحه جدید', 'url' => 'آدرس', - 'filename' => 'تام فایل', + 'filename' => 'نام فایل', 'layout' => 'طرح بندی', 'description' => 'توضیحات', 'preview' => 'پیش نمایش', @@ -182,7 +182,7 @@ return [ 'new' => 'فایل جدید', 'rename_popup_title' => 'تغییر نام', 'rename_new_name' => 'نام جدید', - 'invalid_path' => 'مسیر می تواند فقط شلمل اعداد، حروف لاتین، حط فاصلع و این کاراکتر ها باشد: ._-/', + 'invalid_path' => 'مسیر می تواند فقط شامل اعداد، حروف لاتین، حط فاصله و این کاراکتر ها باشد: ._-/', 'error_deleting_file' => 'در حذف فایل :name مشکلی به وجود آمده است.', 'error_deleting_dir_not_empty' => 'در حذف پوشه ی :name مشکلی به وجود آمده است. پوشه خالی نیست.', 'error_deleting_dir' => 'خطایی در حذف :name به وجود آمده است.', @@ -190,12 +190,12 @@ return [ 'original_not_found' => 'فایل یا پوشه ی اصلی یافت نشد.', 'already_exists' => 'فایل یا پوشه ای با این نام وجود دارد.', 'error_renaming' => 'در تغییر نام فایل یا پوشه مورد نظر خطایی رخ داده است', - 'name_cant_be_empty' => 'نام منی تواند خالی باشد', - 'too_large' => 'فایل ارسال شده بیش از حد حجیم اشت. بیشترین حجم مورد قبول :max_size می باشد', + 'name_cant_be_empty' => 'نام نمی تواند خالی باشد', + 'too_large' => 'فایل ارسال شده بیش از حد مجاز است. بیشترین حجم مورد قبول :max_size می باشد', 'type_not_allowed' => 'فقط این نوع فایل ها قابل قبول می باشد: :allowed_types', - 'file_not_valid' => 'فال نا معتبر است', + 'file_not_valid' => 'فایل نامعتبر است', 'error_uploading_file' => 'خطا در ارسال فال ":name": :error', - 'move_please_select' => 'اطفا انتخاب نمایید', + 'move_please_select' => 'لطفا انتخاب نمایید', 'move_destination' => 'پوشه مورد نظر', 'move_popup_title' => 'جابجایی فایل', 'move_button' => 'جابجایی', @@ -208,7 +208,7 @@ return [ 'path' => 'محل قرار گیری' ], 'component' => [ - 'menu_label' => "ابرار ها", + 'menu_label' => "ابزارها", 'unnamed' => "بدون نام", 'no_description' => "توصیحات وجود ندارد", 'alias' => "نام مستعار", @@ -258,13 +258,14 @@ return [ 'last_modified' => 'آخرین تغییرات', 'public_url' => 'آدرس عمومی', 'click_here' => 'اینجا کلیک کنید', - 'thumbnail_error' => 'خطا در ایجاد تصویر بند انگشنتی', + 'thumbnail_error' => 'خطا در ایجاد تصویر بند انگشتی', 'return_to_parent' => 'بازگشت به پوشه قبل', - 'return_to_parent_label' => 'بازکشت ..', + 'return_to_parent_label' => 'بازگشت ..', 'nothing_selected' => 'چیزی انتخاب نشده است.', 'multiple_selected' => 'چند مورد انتخاب شده', 'uploading_file_num' => 'ارسال :number فایل(ها)...', 'uploading_complete' => 'ارسال انجام شد', + 'uploading_error' => 'خطا در ارسال', 'order_by' => 'مرتب سازی با', 'folder' => 'پوشه', 'no_files_found' => 'فایلی با درخواست شما یافت نشد', @@ -278,10 +279,10 @@ return [ 'move_empty' => 'لطفا موارد را جهت جابجایی انتخاب نمایید', 'move_popup_title' => 'جابحایی فایل یا پوشه ها', 'move_destination' => 'پوشه مقصد', - 'please_select_move_dest' => 'لطفا پوشه مقصد را انتخاب تمایید.', + 'please_select_move_dest' => 'لطفا پوشه مقصد را انتخاب نمائید.', 'move_dest_src_match' => 'لطفا پوشه دیگری را انتخاب نمایید.', 'empty_library' => 'چیزی یافت نشد.', - 'insert' => 'Insert', + 'insert' => 'قرار دادن', 'crop_and_insert' => 'بریدن و افزودن', 'select_single_image' => 'لطفا یک تصویر انتخاب نمایید', 'selection_not_image' => 'مورد انتخاب شده تصویر نمی باشد', diff --git a/modules/cms/lang/pl/lang.php b/modules/cms/lang/pl/lang.php index fe63d40a8..5dd7a5921 100644 --- a/modules/cms/lang/pl/lang.php +++ b/modules/cms/lang/pl/lang.php @@ -13,7 +13,7 @@ return [ 'file_name_required' => 'Pole Nazwa Pliku jest wymagane.' ], 'theme' => [ - 'not_found_name' => "Motyw ':name' nie został odnaleziony.", + 'not_found_name' => "Motyw ':name' nie został odnaleziony.", 'active' => [ 'not_set' => 'Brak aktywnego motywu.', 'not_found' => 'Aktywny motyw nie został odnaleziony.' @@ -25,7 +25,7 @@ return [ ], 'settings_menu' => 'Motyw strony (Front-end theme)', 'settings_menu_description' => 'Zobacz listę zainstalowanych motywów i wybierz, który aktywować.', - 'default_tab' => 'Właściwości', + 'default_tab' => 'Właściwości', 'name_label' => 'Nazwa', 'name_create_placeholder' => 'Nowa nazwa motywu', 'author_label' => 'Autor', @@ -43,7 +43,7 @@ return [ 'activate_button' => 'Aktywuj', 'active_button' => 'Aktywuj', 'customize_button' => 'Personalizuj', - 'duplicate_button' => 'Doplikuj', + 'duplicate_button' => 'Duplikuj', 'duplicate_title' => 'Duplikuj motyw', 'duplicate_theme_success' => 'Pomyślnie utworzono kopię motywu!', 'manage_button' => 'Zarządzaj', @@ -87,7 +87,7 @@ return [ 'is_enabled_comment' => 'Kiedy włączony odwiedzający zamiast normalnej strony zobaczą stronę wybraną poniżej.' ], 'page' => [ - 'not_found_name' => "Strona ':name' nie została znaleziona", + 'not_found_name' => "Strona ':name' nie została znaleziona", 'not_found' => [ 'label' => 'Nie znaleziono strony', 'help' => 'Żądana strona nie została znaleziona.' @@ -231,9 +231,9 @@ return [ 'manage_layouts' => 'Zarządzaj układami', 'manage_partials' => 'Zarządzaj blokami', 'manage_themes' => 'Zarządzaj motywami', - 'manage_media' => 'Manage mediami' + 'manage_media' => 'Manage mediami' ], - 'mediafinder' => [ + 'mediafinder' => [ 'default_prompt' => 'Kliknij przycisk %s aby znaleźć element' ], 'media' => [ diff --git a/modules/cms/lang/tr/lang.php b/modules/cms/lang/tr/lang.php index 821333af3..f64557b2c 100644 --- a/modules/cms/lang/tr/lang.php +++ b/modules/cms/lang/tr/lang.php @@ -265,6 +265,7 @@ return [ 'multiple_selected' => 'Birden fazla öğe seçildi.', 'uploading_file_num' => ':number adet dosya yükleniyor...', 'uploading_complete' => 'Yükleme tamamlandı', + 'uploading_error' => 'Yükleme hatası', 'order_by' => 'Sırala', 'folder' => 'Klasör', 'no_files_found' => 'İsteğiniz doğrultusunda hiçbir dosya bulunamadı.', diff --git a/modules/cms/twig/FrameworkNode.php b/modules/cms/twig/FrameworkNode.php index 2ca246181..434b4b6cf 100644 --- a/modules/cms/twig/FrameworkNode.php +++ b/modules/cms/twig/FrameworkNode.php @@ -36,8 +36,8 @@ class FrameworkNode extends Twig_Node $compiler ->write("echo ''.PHP_EOL;" . PHP_EOL) - ->write("echo ''.PHP_EOL;" . PHP_EOL) + ->write("echo ''.PHP_EOL;" . PHP_EOL) ; } } diff --git a/modules/cms/widgets/AssetList.php b/modules/cms/widgets/AssetList.php index 70f3b871c..57167a7c2 100644 --- a/modules/cms/widgets/AssetList.php +++ b/modules/cms/widgets/AssetList.php @@ -61,9 +61,11 @@ class AssetList extends WidgetBase 'css', 'js', 'woff', + 'woff2', 'svg', 'ttf', 'eot', + 'otf', 'json', 'md', 'less', diff --git a/modules/cms/widgets/MediaManager.php b/modules/cms/widgets/MediaManager.php index 2114c47e5..bbeda53d4 100644 --- a/modules/cms/widgets/MediaManager.php +++ b/modules/cms/widgets/MediaManager.php @@ -970,15 +970,14 @@ class MediaManager extends WidgetBase $fileName = File::name($fileName).'.'.$extension; /* - * File name contains non-latin characters, attempt to slug the value - */ + * File name contains non-latin characters, attempt to slug the value + */ if (!$this->validateFileName($fileName)) { - $fileNameSlug = Str::slug(File::name($fileName), '-'); - $fileName = $fileNameSlug.'.'.$extension; + $fileNameClean = $this->cleanFileName(File::name($fileName)); + $fileName = $fileNameClean . '.' . $extension; } // See mime type handling in the asset manager - if (!$uploadedFile->isValid()) { throw new ApplicationException($uploadedFile->getErrorMessage()); } @@ -999,9 +998,14 @@ class MediaManager extends WidgetBase } } + /** + * Validate a proposed media item file name. + * @param string + * @return string + */ protected function validateFileName($name) { - if (!preg_match('/^[0-9a-z\.\s_\-]+$/i', $name)) { + if (!preg_match('/^[0-9a-z@\.\s_\-]+$/i', $name)) { return false; } @@ -1012,6 +1016,29 @@ class MediaManager extends WidgetBase return true; } + /** + * Creates a slug form the string. A modified version of Str::slug + * with the main difference that it accepts @-signs + * @param string + * @return string + */ + protected function cleanFileName($name) + { + $title = Str::ascii($title); + + // Convert all dashes/underscores into separator + $flip = $separator = '-'; + $title = preg_replace('!['.preg_quote($flip).']+!u', $separator, $title); + + // Remove all characters that are not the separator, letters, numbers, whitespace or @. + $title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s@]+!u', '', mb_strtolower($title)); + + // Replace all separator characters and whitespace by a single separator + $title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title); + + return trim($title, $separator); + } + // // Cropping // diff --git a/modules/system/assets/ui/less/icon.close.less b/modules/system/assets/ui/less/icon.close.less index 9e5403662..918e43979 100644 --- a/modules/system/assets/ui/less/icon.close.less +++ b/modules/system/assets/ui/less/icon.close.less @@ -11,7 +11,7 @@ font-size: (@font-size-base * 1.5); font-weight: @close-font-weight; line-height: 1; - color: @close-color; + color: @close-color !important; text-shadow: @close-text-shadow; .opacity(.2); diff --git a/modules/system/assets/ui/storm.css b/modules/system/assets/ui/storm.css index 0f2beee1c..92066e7e2 100644 --- a/modules/system/assets/ui/storm.css +++ b/modules/system/assets/ui/storm.css @@ -1118,7 +1118,7 @@ input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button" .oc-icon-vimeo:before,.icon-vimeo:before{content:"\f27d"} .oc-icon-black-tie:before,.icon-black-tie:before{content:"\f27e"} .oc-icon-fonticons:before,.icon-fonticons:before{content:"\f280"} -.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20)} +.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000000 !important;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20)} .close:hover,.close:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)} button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none} @font-face{font-family:'FontAwesome';src:url('font/fontawesome-webfont.eot?v=1.0.1');src:url('font/fontawesome-webfont.eot?#iefix&v=1.0.1') format('embedded-opentype'),url('font/fontawesome-webfont.woff?v=1.0.1') format('woff'),url('font/fontawesome-webfont.ttf?v=1.0.1') format('truetype'),url('font/fontawesome-webfont.svg#fontawesomeregular?v=1.0.1') format('svg');font-weight:normal;font-style:normal} @@ -2641,4 +2641,4 @@ ul.autocomplete.dropdown-menu.inspector-autocomplete li a{padding:5px 12px;white .popup-backdrop .popup-loading-indicator{display:block;width:100px;height:100px;position:absolute;top:130px;left:50%;margin-left:-50px;-webkit-transition:all 0.3s,width 0s;transition:all 0.3s,width 0s;-webkit-transform:scale(0.7);-ms-transform:scale(0.7);transform:scale(0.7);opacity:0;filter:alpha(opacity=0)} .popup-backdrop .popup-loading-indicator:after{content:' ';display:block;background-size:50px 50px;background-repeat:no-repeat;background-position:50% 50%;background-image:url('images/loader-transparent.svg');-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite;width:50px;height:50px;margin:25px 0 0 25px} .popup-backdrop.loading .popup-loading-indicator{opacity:1;filter:alpha(opacity=100);-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)} -.mac body.modal-open{margin-right:0} \ No newline at end of file +.mac body.modal-open{margin-right:0} diff --git a/modules/system/classes/PluginBase.php b/modules/system/classes/PluginBase.php index 01c9b90eb..eeca39fdc 100644 --- a/modules/system/classes/PluginBase.php +++ b/modules/system/classes/PluginBase.php @@ -106,7 +106,7 @@ class PluginBase extends ServiceProviderBase if (is_array($navigation)) { array_walk_recursive($navigation, function(&$item, $key){ - if ($key == 'url') { + if ($key === 'url') { $item = Backend::url($item); } }); diff --git a/modules/system/classes/PluginManager.php b/modules/system/classes/PluginManager.php index bb270c059..73fb84074 100644 --- a/modules/system/classes/PluginManager.php +++ b/modules/system/classes/PluginManager.php @@ -457,6 +457,7 @@ class PluginManager if (array_key_exists($code, $this->disabledPlugins)) { return true; } + return false; } /** diff --git a/modules/system/controllers/Updates.php b/modules/system/controllers/Updates.php index b8133dbe7..8e6087e4f 100644 --- a/modules/system/controllers/Updates.php +++ b/modules/system/controllers/Updates.php @@ -892,11 +892,11 @@ class Updates extends Controller // /** - * Encode HTML safe product code. + * Encode HTML safe product code, this is to prevent issues with array_get(). */ protected function encodeCode($code) { - return str_replace('.', '_', $code); + return str_replace('.', ':', $code); } /** @@ -904,6 +904,6 @@ class Updates extends Controller */ protected function decodeCode($code) { - return str_replace('_', '.', $code); + return str_replace(':', '.', $code); } } diff --git a/modules/system/controllers/updates/index.htm b/modules/system/controllers/updates/index.htm index 3bccc8e16..6d98cd48c 100644 --- a/modules/system/controllers/updates/index.htm +++ b/modules/system/controllers/updates/index.htm @@ -28,7 +28,7 @@

- : + :

diff --git a/modules/system/lang/es/lang.php b/modules/system/lang/es/lang.php index 886a16a4a..a3a744a13 100644 --- a/modules/system/lang/es/lang.php +++ b/modules/system/lang/es/lang.php @@ -20,7 +20,7 @@ return [ 'id' => 'Bahasa Indonesia', 'it' => 'Italiano', 'ja' => 'Japonés', - 'lv' => 'Latvian', + 'lv' => 'Letón', 'nb-no' => 'Noruego (Bokmål)', 'nl' => 'Holandés', @@ -29,7 +29,7 @@ return [ 'ro' => 'Romana', 'ru' => 'Ruso', 'sv' => 'Sueco', - 'sk' => 'Slovak (Slovakia)', + 'sk' => 'Eslovaco (Eslovaquia)', 'tr' => 'Turco', 'zh-cn' => 'Chino (China)', 'zh-tw' => 'Chino (Taiwan)' @@ -41,7 +41,7 @@ return [ 'create_fail' => 'No es posible crear el archivo: :name' ], 'combiner' => [ - 'not_found' => "The combiner file ':name' is not found." + 'not_found' => "El archivo combinador ':name' no se encuentra." ], 'system' => [ 'name' => 'Sistema', @@ -62,20 +62,20 @@ return [ ] ], 'theme' => [ - 'label' => 'Theme', - 'unnamed' => 'Unnamed theme', + 'label' => 'Tema', + 'unnamed' => 'Tema sin nombre', 'name' => [ - 'label' => 'Theme Name', - 'help' => 'Name the theme by its unique code. For example, RainLab.Vanilla' + 'label' => 'Nombre Tema', + 'help' => 'Nombre del tema por su código único. Por ejemplo, RainLab.Vanilla' ], ], 'themes' => [ - 'install' => 'Install themes', - 'search' => 'search themes to install...', - 'installed' => 'Installed themes', - 'no_themes' => 'There are no themes installed from the marketplace.', - 'recommended' => 'Recommended', - 'remove_confirm' => 'Are you sure you want to remove this theme?' + 'install' => 'Instalar temas', + 'search' => 'buscar temas para instalar...', + 'installed' => 'Temas Instalados', + 'no_themes' => 'No hay temas instalados desde el mercado.', + 'recommended' => 'Recomendado', + 'remove_confirm' => '¿Seguro que quieres eliminar este tema?' ], 'plugin' => [ 'label' => 'Plugin', @@ -89,18 +89,18 @@ return [ 'manage' => 'Gestionar plugins', 'enable_or_disable' => 'Activar o desactivar', 'enable_or_disable_title' => 'Activar o Desactivar Plugins', - 'install' => 'Install plugins', - 'install_products' => 'Install products', - 'search' => 'search plugins to install...', - 'installed' => 'Installed plugins', - 'no_plugins' => 'There are no plugins installed from the marketplace.', - 'recommended' => 'Recommended', + 'install' => 'Instalar plugins', + 'install_products' => 'Instalar productos', + 'search' => 'buscar plugins para instalar...', + 'installed' => 'Plugins Instalados', + 'no_plugins' => 'No hay plugins instalados desde el mercado.', + 'recommended' => 'Recomendado', 'remove' => 'Eliminar', 'refresh' => 'Recargar', 'disabled_label' => 'Desactivar', 'disabled_help' => 'Plugins que están deshabilitadas son ignorados por la aplicación.', - 'frozen_label' => 'Freeze updates', - 'frozen_help' => 'Plugins that are frozen will be ignored by the update process.', + 'frozen_label' => 'Congele actualizaciones', + 'frozen_help' => 'Plugins que están congelados serán ignorados por el proceso de actualización.', 'selected_amount' => 'Plugins seleccionado: :amount', 'remove_confirm' => 'Está seguro?', 'remove_success' => 'Eliminado con éxito los plugins del sistema.', @@ -157,15 +157,15 @@ return [ 'sendmail_path' => 'Directorio de Sendmail', 'sendmail_path_comment' => 'Por favor, especifique la ruta de acceso del programa sendmail.', 'mailgun' => 'Mailgun', - 'mailgun_domain' => 'Mailgun domain', - 'mailgun_domain_comment' => 'Please specify the Mailgun domain name.', + 'mailgun_domain' => 'Dominio Mailgun', + 'mailgun_domain_comment' => 'Por favor, especifique el nombre de dominio Mailgun.', 'mailgun_secret' => 'Mailgun secret', - 'mailgun_secret_comment' => 'Enter your Mailgun API key.', + 'mailgun_secret_comment' => 'Introduzca su key de Mailgun API.', 'mandrill' => 'Mandrill', 'mandrill_secret' => 'Mandrill secret', - 'mandrill_secret_comment' => 'Enter your Mandrill API key.', - 'drivers_hint_header' => 'Drivers not installed', - 'drivers_hint_content' => 'This mail method requires the plugin ":plugin" be installed before you can send mail.' + 'mandrill_secret_comment' => 'Introduzca su key de Mandrill API.', + 'drivers_hint_header' => 'Drivers no instalados', + 'drivers_hint_content' => 'Este método de correo electrónico requiere que el plugin ":plugin" este instalado antes de poder enviar correo.' ], 'mail_templates' => [ 'menu_label' => 'Plantillas de Correo', @@ -222,7 +222,7 @@ return [ 'core_downloading' => 'Descargando archivos de la aplicación', 'core_extracting' => 'Descomprimiendo archivos de la aplicación', 'plugins' => 'Plugins', - 'themes' => 'Themes', + 'themes' => 'Temas', 'disabled' => 'Desactivado', 'plugin_downloading' => 'Descargando plugin: :name', 'plugin_extracting' => 'Descomprimiendo plugin: :name', @@ -245,20 +245,20 @@ return [ 'help' => 'No se encontraron nuevas actualizaciones disponibles.', ], 'important_action' => [ - 'empty' => 'Select action', - 'confirm' => 'Confirm update', - 'skip' => 'Skip this plugin (once only)', - 'ignore' => 'Skip this plugin (always)', + 'empty' => 'Seleccione acción', + 'confirm' => 'Confirmar actualización', + 'skip' => 'Saltar este plugin (sólo una vez)', + 'ignore' => 'Saltar este plugin (siempre)', ], - 'important_action_required' => 'Action required', - 'important_view_guide' => 'View upgrade guide', - 'important_alert_text' => 'Some updates need your attention.', - 'details_title' => 'Plugin details', - 'details_view_homepage' => 'View homepage', + 'important_action_required' => 'Acción requerida', + 'important_view_guide' => 'Ver guía de actualización', + 'important_alert_text' => 'Algunas actualizaciones necesitan su atención.', + 'details_title' => 'Detalles plugin', + 'details_view_homepage' => 'Ver página de inicio', 'details_readme' => 'Documentación', - 'details_readme_missing' => 'There is no documentation provided.', - 'details_upgrades' => 'Upgrade Guide', - 'details_upgrades_missing' => 'There are no upgrade instructions provided.', + 'details_readme_missing' => 'No hay documentación proporcionada.', + 'details_upgrades' => 'Guía de actualización', + 'details_upgrades_missing' => 'No hay instrucciones de actualización proporcionadas.', 'details_current_version' => 'Versión actual', 'details_author' => 'Autor' ], diff --git a/modules/system/lang/fa/lang.php b/modules/system/lang/fa/lang.php index a32e937f4..bf4f618e8 100644 --- a/modules/system/lang/fa/lang.php +++ b/modules/system/lang/fa/lang.php @@ -3,7 +3,7 @@ return [ 'app' => [ 'name' => 'مدیریت محتوی اکتبر', - 'tagline' => 'بازگشت به گذشته', + 'tagline' => 'ورود به پنل مدیریت', ], 'locale' => [ 'cs' => 'چک اسلواکی', @@ -131,7 +131,7 @@ return [ 'search' => 'جستجو' ], 'mail' => [ - 'log_file' => 'فایل ثبت وقایع', + 'log_file' => 'فایل گزارش', 'menu_label' => 'تنظیمات پست الکترونیکی', 'menu_description' => 'مدیریت تنظیمات پست الکترونیکی.', 'general' => 'عمومی', @@ -177,7 +177,7 @@ return [ 'layouts' => 'طرح بندی ها', 'no_layout' => '-- بدون طرح بندی --', 'name' => 'نام', - 'name_comment' => 'نام یکتای مشخص کننده ی این قالی', + 'name_comment' => 'نام یکتای مشخص کننده ی این قالب', 'code' => 'کد', 'code_comment' => 'کد یکتای مشخص کننده ی این قالب', 'subject' => 'موضوع', @@ -188,16 +188,23 @@ return [ 'content_text' => 'متن معمولی', 'test_send' => 'ارسال پیغام آزمایشی', 'test_success' => 'پیغام آزمایشی ارسال شد.', - 'return' => 'بازگشت به لیست قالب ها', - 'test_confirm' => 'یک نامه الکترونیکی جهت آزمایش به :email ارسال شد. آیا میخواهید ادامه دهید؟', + 'test_confirm' => 'پیغام آزمایشی به آدرس :email ارسال خواهد شد آیا میخواهید ادامه دهید؟', + 'creating' => 'درحال ایجاد قالب...', + 'creating_layout' => 'در حال ایجاد طرح بندی...', 'saving' => 'ذخیره سازی قالب...', + 'saving_layout' => 'درحال ذخیره سازی طرح بندی...', + 'delete_confirm' => 'آیا از حذف این قالب اطمینان دارید؟', + 'delete_layout_confirm' => 'آیا از حذف این طرح بندی اطمینان دارید؟', + 'deleting' => 'درحال حذف قالب...', + 'deleting_layout' => 'در حال حذف طرح بندی...', 'sending' => 'ارسال نامه الکترونیکی آزمایشی...', + 'return' => 'بازگشت به لیست قالب ها' ], 'install' => [ 'project_label' => 'ضمیمه کردن به نرم افزار', 'plugin_label' => 'نصب افزونه', 'theme_label' => 'نصب قالب', - 'missing_plugin_name' => 'لطفان نام افزونه را جهت نصب وارد نمایید.', + 'missing_plugin_name' => 'لطفا نام افزونه را جهت نصب وارد نمایید.', 'missing_theme_name' => 'لطفا نام قالب را جهت نصب وارد نمایید.', 'install_completing' => 'مرحله ی پایانی عملیات نصب', 'install_success' => 'افزونه با موفقیت نصب شد.', @@ -237,7 +244,7 @@ return [ 'update_failed_label' => 'بروز رسانی موفق نبود', 'force_label' => 'اصرار در بروز رسانی', 'found' => [ - 'label' => 'بروز رسانی جدیدی یافت شده است!', + 'label' => 'بروز رسانی جدید وجود دارد', 'help' => 'بر روی بروز رسانی نرم افزار جهت شروع عملیات بروز رسانی کلیک کنید.', ], 'none' => [ @@ -306,7 +313,7 @@ return [ 'id_label' => 'مشخصه ی گزارش', 'count' => 'شمارشگر', 'referer' => 'منتقل شده از', - 'url' => 'آردس', + 'url' => 'آدرس', 'status_code' => 'وضعیت', ], 'permissions' => [ diff --git a/modules/system/lang/ru/lang.php b/modules/system/lang/ru/lang.php index aa08f89cd..293c920b3 100644 --- a/modules/system/lang/ru/lang.php +++ b/modules/system/lang/ru/lang.php @@ -188,10 +188,17 @@ return [ 'content_text' => 'Plaintext', 'test_send' => 'Отправить тестовое сообщение', 'test_success' => 'Тестовое сообщение было успешно отправлено.', - 'return' => 'Вернуться к списку шаблонов', 'test_confirm' => 'Тестовое сообщение будет отправлено на :email. Продолжить?', + 'creating' => 'Создание шаблона...', + 'creating_layout' => 'Создание макета...', 'saving' => 'Сохранение шаблона...', + 'saving_layout' => 'Сохранение макета...', + 'delete_confirm' => 'Вы действительно хотите удалить этот шаблон?', + 'delete_layout_confirm' => 'Вы действительно хотите удалить этот макет?', + 'deleting' => 'Удаление шаблона...', + 'deleting_layout' => 'Удаление макета...', 'sending' => 'Отправка тестового сообщения...', + 'return' => 'Вернуться к списку шаблонов' ], 'install' => [ 'project_label' => 'Присоединить к проекту', diff --git a/modules/system/lang/tr/client.php b/modules/system/lang/tr/client.php new file mode 100644 index 000000000..47dd9b30d --- /dev/null +++ b/modules/system/lang/tr/client.php @@ -0,0 +1,57 @@ + [ + 'formatting' => 'Formatlama', + 'quote' => 'Alıntı', + 'code' => 'Kod', + 'header1' => 'Başlık 1', + 'header2' => 'Başlık 2', + 'header3' => 'Başlık 3', + 'header4' => 'Başlık 4', + 'header5' => 'Başlık 5', + 'header6' => 'Başlık 6', + 'bold' => 'Kalın', + 'italic' => 'İtalik', + 'unorderedlist' => 'Sırasız Liste', + 'orderedlist' => 'Sıralı Liste', + 'video' => 'Video', + 'image' => 'Görsel/Resim', + 'link' => 'Link', + 'horizontalrule' => 'Yatay Çizgi Ekle', + 'fullscreen' => 'Tam Ekran', + 'preview' => 'Önizleme', + ], + + 'mediamanager' => [ + 'insert_link' => "Medya Linki Ekle", + 'insert_image' => "Medya Resim Ekle", + 'insert_video' => "Medya Video Ekle", + 'insert_audio' => "Medya Ses Ekle", + 'invalid_file_empty_insert' => "Lütfen link verilecek dosyayı seçin.", + 'invalid_file_single_insert' => "Lütfen tek bir dosya seçin.", + 'invalid_image_empty_insert' => "Lütfen eklenecek resim(ler)i seçin.", + 'invalid_video_empty_insert' => "Lütfen eklenecek video dosyasını seçin.", + 'invalid_audio_empty_insert' => "Lütfen eklenecek ses dosyasını seçin.", + ], + + 'alert' => [ + 'confirm_button_text' => 'TAMAM', + 'cancel_button_text' => 'İptal', + ], + +]; + + + diff --git a/modules/system/lang/tr/lang.php b/modules/system/lang/tr/lang.php index 6b33f99b5..996558206 100644 --- a/modules/system/lang/tr/lang.php +++ b/modules/system/lang/tr/lang.php @@ -3,26 +3,33 @@ return [ 'app' => [ 'name' => 'October CMS', - 'tagline' => 'Basitliğe dönüş...' + 'tagline' => 'Sadeliğe dönüş...' ], 'locale' => [ - 'cs' => 'Czech', + 'cs' => 'Čeština (Česko)', 'en' => 'English (United States)', 'de' => 'Deutsch (Deutschland)', + 'el' => 'Ελληνικά (Ελλάδα)', 'es' => 'Español (Spanish)', 'es-ar' => 'Español (Argentina)', 'fa' => '‏فارسی‏ (Iran) ايران', 'fr' => 'Français (France)', - 'hu' => 'Magyar (Magyarország - Hungary)', + 'hu' => 'Magyar - Magyarország (Hungary)', + 'id' => 'Bahasa Indonesia (Indonesia)', 'it' => 'Italiano (Italia)', 'ja' => '日本語 (Japan) 日本', + 'lv' => 'Latviešu (Latvija)', + 'nb-no' => 'Norsk - Bokmål (Norge)', 'nl' => 'Nederlands (Nederland)', + 'pl' => 'Polski (Polska)', 'pt-br' => 'Português (Brasil)', 'ro' => 'Română (România)', 'ru' => 'Русский (Россия - Russia)', 'sv' => 'Svenska (Sverige)', + 'sk' => 'Slovenčina (Slovensko)', 'tr' => 'Türkçe (Türkiye)', - 'nb-no' => 'Norwegian (Bokmål)' + 'zh-cn' => '中文(简体) - 中国 (Chine-Simplified Chinese)', + 'zh-tw' => '中文(台灣) - 台灣 (Taiwan-Traditional Chinese)' ], 'directory' => [ 'create_fail' => "Klasör oluşturulamıyor: :name" @@ -181,10 +188,17 @@ return [ 'content_text' => 'Düzyazı', 'test_send' => 'Test mesajı gönder', 'test_success' => 'Test mesajı başarılı şekilde gönderildi.', - 'return' => 'Şablon listesine geri dön', 'test_confirm' => 'Deneme mesajı :email eposta adresine gönderilecek. Devam etmek istiyor musunuz?', + 'creating' => 'Şablon Oluşturuluyor...', + 'creating_layout' => 'Layout Oluşturuluyor...', 'saving' => 'Şablon kaydediliyor...', + 'saving_layout' => 'Layout kaydediliyor...', + 'delete_confirm' => 'Bu şablonu silmek istediğinize emin misiniz?', + 'delete_layout_confirm' => 'Bu layout\'u silmek istediğinize emin misiniz?', + 'deleting' => 'Şablon Siliniyor...', + 'deleting_layout' => 'Layout Siliniyor...', 'sending' => 'Deneme mesajı gönderiliyor...', + 'return' => 'Şablon listesine geri dön' ], 'install' => [ 'project_label' => 'Projeye bağla', @@ -304,13 +318,15 @@ return [ ], 'permissions' => [ 'name' => 'Sistem', - 'manage_system_settings' => 'Sistem ayarlarını düzenleyebilsin', - 'manage_software_updates' => 'Sistem güncellemelerini yönetebilsin', - 'access_logs' => 'Sistem günlüğünü görüntüle', - 'manage_mail_templates' => 'E-posta şablonları yönetebilsin', - 'manage_mail_settings' => 'E-posta ayarlarını yönetebilsin', - 'manage_other_administrators' => 'Diğer yöneticileri düzenleyebilsin', - 'view_the_dashboard' => 'Panoyu görüntüleyebilsin', - 'manage_branding' => 'Back-end i özelleştir' + 'manage_system_settings' => 'Sistem ayarlarını düzenleyebilir', + 'manage_software_updates' => 'Sistem güncellemelerini yönetebilir', + 'access_logs' => 'Sistem günlüğünü görüntüleyebilir', + 'manage_mail_templates' => 'E-posta şablonları yönetebilir', + 'manage_mail_settings' => 'E-posta ayarlarını yönetebilir', + 'manage_other_administrators' => 'Diğer yöneticileri düzenleyebilir', + 'manage_preferences' => 'Yönetim paneli seçeneklerini düzenleyebilir', + 'manage_editor' => 'Kod editör ayarlarını düzenleyebilir', + 'view_the_dashboard' => 'Panoyu görüntüleyebilir', + 'manage_branding' => 'Yönetim Panelini özelleştirebilsin' ] ]; diff --git a/modules/system/lang/tr/validation.php b/modules/system/lang/tr/validation.php index d76c9486e..b37929516 100644 --- a/modules/system/lang/tr/validation.php +++ b/modules/system/lang/tr/validation.php @@ -1,6 +1,6 @@ ":attribute sadece harfler ve rakamlar içermelidir.", "array" => ":attribute dizi olmalıdır.", "before" => ":attribute şundan daha önceki bir tarih olmalıdır :date.", - "between" => array( + "between" => [ "numeric" => ":attribute :min - :max arasında olmalıdır.", "file" => ":attribute :min - :max arasındaki kilobayt değeri olmalıdır.", "string" => ":attribute :min - :max arasında karakterden oluşmalıdır.", "array" => ":attribute :min - :max arasında nesneye sahip olmalıdır." - ), - "confirmed" => ":attribute tekrarı eşleşmiyor.", - "date" => ":attribute geçerli bir tarih olmalıdır.", - "date_format" => ":attribute :format biçimi ile eşleşmiyor.", - "different" => ":attribute ile :other birbirinden farklı olmalıdır.", - "digits" => ":attribute :digits rakam olmalıdır.", - "digits_between" => ":attribute :min ile :max arasında rakam olmalıdır.", - "email" => ":attribute biçimi geçersiz.", - "exists" => "Seçili :attribute geçersiz.", - "image" => ":attribute alanı resim dosyası olmalıdır.", - "in" => ":attribute değeri geçersiz.", - "integer" => ":attribute rakam olmalıdır.", - "ip" => ":attribute geçerli bir IP adresi olmalıdır.", - "max" => array( + ], + "confirmed" => ":attribute tekrarı eşleşmiyor.", + "date" => ":attribute geçerli bir tarih olmalıdır.", + "date_format" => ":attribute :format biçimi ile eşleşmiyor.", + "different" => ":attribute ile :other birbirinden farklı olmalıdır.", + "digits" => ":attribute :digits rakam olmalıdır.", + "digits_between" => ":attribute :min ile :max arasında rakam olmalıdır.", + "email" => ":attribute biçimi geçersiz.", + "exists" => "Seçili :attribute geçersiz.", + "image" => ":attribute alanı resim dosyası olmalıdır.", + "in" => ":attribute değeri geçersiz.", + "integer" => ":attribute rakam olmalıdır.", + "ip" => ":attribute geçerli bir IP adresi olmalıdır.", + "max" => [ "numeric" => ":attribute değeri :max değerinden küçük olmalıdır.", "file" => ":attribute değeri :max kilobayt değerinden küçük olmalıdır.", "string" => ":attribute değeri :max karakter değerinden küçük olmalıdır.", "array" => ":attribute değeri :max adedinden az nesneye sahip olmalıdır." - ), - "mimes" => ":attribute dosya biçimi :values olmalıdır.", - "min" => array( + ], + "mimes" => ":attribute dosya biçimi :values olmalıdır.", + "extensions" => ":attribute , :values değerlerinden birinin eklentisi olmalıdır.", + "min" => [ "numeric" => ":attribute değeri :min değerinden büyük olmalıdır.", "file" => ":attribute değeri :min kilobayt değerinden büyük olmalıdır.", "string" => ":attribute değeri :min karakter değerinden büyük olmalıdır.", "array" => ":attribute en az :min nesneye sahip olmalıdır." - ), - "not_in" => "Seçili :attribute geçersiz.", - "numeric" => ":attribute rakam olmalıdır.", - "regex" => ":attribute biçimi geçersiz.", - "required" => ":attribute alanı gereklidir.", - "required_if" => ":attribute alanı, :other :value değerine sahip olduğunda zorunludur.", - "required_with" => ":attribute alanı :values varken zorunludur.", - "required_with_all" => ":attribute alanı :values varken zorunludur.", - "required_without" => ":attribute alanı :values yokken zorunludur.", - "required_without_all" => ":attribute alanı :values yokken zorunludur.", - "same" => ":attribute ile :other eşleşmelidir.", - "size" => array( + ], + "not_in" => "Seçili :attribute geçersiz.", + "numeric" => ":attribute rakam olmalıdır.", + "regex" => ":attribute biçimi geçersiz.", + "required" => ":attribute alanı gereklidir.", + "required_if" => ":attribute alanı, :other :value değerine sahip olduğunda zorunludur.", + "required_with" => ":attribute alanı :values varken zorunludur.", + "required_without" => ":attribute alanı :values yokken zorunludur.", + "same" => ":attribute ile :other eşleşmelidir.", + "size" => [ "numeric" => ":attribute :size olmalıdır.", "file" => ":attribute :size kilobyte olmalıdır.", "string" => ":attribute :size karakter olmalıdır.", "array" => ":attribute :size nesneye sahip olmalıdır." - ), + ], "unique" => ":attribute daha önceden kayıt edilmiş.", "url" => ":attribute biçimi geçersiz.", @@ -82,7 +81,7 @@ return array( | */ - 'custom' => array(), + 'custom' => [], /* |-------------------------------------------------------------------------- @@ -95,6 +94,6 @@ return array( | */ - 'attributes' => array(), + 'attributes' => [], -); \ No newline at end of file +]; diff --git a/plugins/october/demo/updates/version.yaml b/plugins/october/demo/updates/version.yaml new file mode 100644 index 000000000..867bbe886 --- /dev/null +++ b/plugins/october/demo/updates/version.yaml @@ -0,0 +1 @@ +1.0.1: First version of Demo \ No newline at end of file diff --git a/storage/.gitignore b/storage/.gitignore index a2d9e6f16..9b1dffd90 100644 --- a/storage/.gitignore +++ b/storage/.gitignore @@ -1,2 +1 @@ -system.log -laravel.log \ No newline at end of file +*.sqlite diff --git a/tests/fixtures/plugins/october/tester/Plugin.php b/tests/fixtures/plugins/october/tester/Plugin.php index a0c80bac0..c3d5506fb 100644 --- a/tests/fixtures/plugins/october/tester/Plugin.php +++ b/tests/fixtures/plugins/october/tester/Plugin.php @@ -20,7 +20,8 @@ class Plugin extends PluginBase 'October\Tester\Components\Archive' => 'testArchive', 'October\Tester\Components\Post' => 'testPost', 'October\Tester\Components\MainMenu' => 'testMainMenu', - 'October\Tester\Components\ContentBlock' => 'testContentBlock' + 'October\Tester\Components\ContentBlock' => 'testContentBlock', + 'October\Tester\Components\Comments' => 'testComments', ]; } diff --git a/tests/fixtures/plugins/october/tester/classes/Users.php b/tests/fixtures/plugins/october/tester/classes/Users.php new file mode 100644 index 000000000..9456f61dd --- /dev/null +++ b/tests/fixtures/plugins/october/tester/classes/Users.php @@ -0,0 +1,12 @@ + 'Arquitecht and Importer/Exporter', + 'Carl' => 'where is he?', + ]; + } +} diff --git a/tests/fixtures/plugins/october/tester/components/Categories.php b/tests/fixtures/plugins/october/tester/components/Categories.php new file mode 100644 index 000000000..dd2ab1be5 --- /dev/null +++ b/tests/fixtures/plugins/october/tester/components/Categories.php @@ -0,0 +1,34 @@ + 'Blog Categories Dummy Component', + 'description' => 'Displays the list of categories in the blog.' + ]; + } + + public function posts() + { + return [ + ['title' => 'Lorum ipsum', 'content' => 'Post Content #1'], + ['title' => 'La Playa Nudista', 'content' => 'Second Post Content'] + ]; + } + + public function onTestAjax() + { + $this->page['var'] = 'page'; + } + +} diff --git a/tests/fixtures/plugins/october/tester/components/Comments.php b/tests/fixtures/plugins/october/tester/components/Comments.php new file mode 100644 index 000000000..227b02863 --- /dev/null +++ b/tests/fixtures/plugins/october/tester/components/Comments.php @@ -0,0 +1,43 @@ +users = $users; + } + + public function componentDetails() + { + return [ + 'name' => 'Blog Comments Dummy Component', + 'description' => 'Displays the list of comments on a post.' + ]; + } + + public function posts() + { + return [ + ['title' => 'Lorum ipsum', 'content' => 'Post Content #1'], + ['title' => 'La Playa Nudista', 'content' => 'Second Post Content'] + ]; + } + + public function onTestAjax() + { + $this->page['var'] = 'page'; + } + + public function getUsers() + { + return $this->users; + } + +} diff --git a/tests/unit/cms/classes/ComponentManagerTest.php b/tests/unit/cms/classes/ComponentManagerTest.php index 99d3601d6..a12255580 100644 --- a/tests/unit/cms/classes/ComponentManagerTest.php +++ b/tests/unit/cms/classes/ComponentManagerTest.php @@ -9,6 +9,19 @@ use Cms\Classes\ComponentManager; class ComponentManagerTest extends TestCase { + public function setUp() + { + parent::setUp(); + + include_once base_path() . '/tests/fixtures/plugins/october/tester/components/Archive.php'; + include_once base_path() . '/tests/fixtures/plugins/october/tester/components/Post.php'; + include_once base_path() . '/tests/fixtures/plugins/october/tester/components/MainMenu.php'; + include_once base_path() . '/tests/fixtures/plugins/october/tester/components/ContentBlock.php'; + include_once base_path() . '/tests/fixtures/plugins/october/tester/components/Comments.php'; + include_once base_path() . '/tests/fixtures/plugins/october/tester/classes/Users.php'; + } + + public function testListComponents() { $manager = ComponentManager::instance(); @@ -20,14 +33,9 @@ class ComponentManagerTest extends TestCase public function testListComponentDetails() { - include_once base_path() . '/tests/fixtures/plugins/october/tester/components/Archive.php'; - include_once base_path() . '/tests/fixtures/plugins/october/tester/components/Post.php'; - include_once base_path() . '/tests/fixtures/plugins/october/tester/components/MainMenu.php'; - include_once base_path() . '/tests/fixtures/plugins/october/tester/components/ContentBlock.php'; - $manager = ComponentManager::instance(); $components = $manager->listComponentDetails(); - + $this->assertArrayHasKey('testArchive', $components); $this->assertArrayHasKey('name', $components['testArchive']); $this->assertArrayHasKey('description', $components['testArchive']); @@ -41,6 +49,26 @@ class ComponentManagerTest extends TestCase $this->assertEquals('Displays a blog post.', $components['testPost']['description']); } + public function testGetComponentWithFactoryUsingAutomaticResolution() + { + $manager = ComponentManager::instance(); + $components = $manager->listComponentDetails(); + + $this->assertArrayHasKey('testComments', $components); + $this->assertArrayHasKey('name', $components['testComments']); + $this->assertArrayHasKey('description', $components['testComments']); + $this->assertEquals('Blog Comments Dummy Component', $components['testComments']['name']); + $this->assertEquals('Displays the list of comments on a post.', $components['testComments']['description']); + + $comments = $manager->makeComponent('testComments', $this->spoofPageCode(), []); + $users = $comments->getUsers()->getUsers(); + + $this->assertArrayHasKey('Art Vandelay', $users); + $this->assertArrayHasKey('Carl', $users); + $this->assertEquals('Arquitecht and Importer/Exporter', $users['Art Vandelay']); + $this->assertEquals('where is he?', $users['Carl']); + } + public function testFindByAlias() { $manager = ComponentManager::instance(); @@ -50,7 +78,6 @@ class ComponentManagerTest extends TestCase $component = $manager->resolve('testPost'); $this->assertEquals('\October\Tester\Components\Post', $component); - } public function testHasComponent() diff --git a/tests/unit/cms/classes/MediaLibraryTest.php b/tests/unit/cms/classes/MediaLibraryTest.php new file mode 100644 index 000000000..5ce1ecb67 --- /dev/null +++ b/tests/unit/cms/classes/MediaLibraryTest.php @@ -0,0 +1,55 @@ +setExpectedException('ApplicationException'); + MediaLibrary::validatePath($path); + } + + /** + * @dataProvider validPathsProvider + */ + public function testValidPathsOnValidatePath($path) + { + MediaLibrary::validatePath($path); + } +}