Merge branch '4.0' into 4

This commit is contained in:
Damian Mooyman 2017-12-07 13:52:00 +13:00
commit 6b384f4b35
No known key found for this signature in database
GPG Key ID: 78B823A10DE27D1A
27 changed files with 672 additions and 279 deletions

View File

@ -0,0 +1,88 @@
# 4.0.1-rc1
<!--- Changes below this line will be automatically regenerated -->
## Change Log
### Security
* 2017-11-30 [f1dd3d6f0]() Prevent disclosure of sensitive information via LoginAttempt (Damian Mooyman) - See [ss-2017-009](http://www.silverstripe.org/download/security-releases/ss-2017-009)
* 2017-11-29 [cfe1d4f48]() Ensure xls formulae are safely sanitised on output (Damian Mooyman) - See [ss-2017-007](http://www.silverstripe.org/download/security-releases/ss-2017-007)
* 2017-11-27 [7a79cd039]() Prevent install.php from disclosing system passwords (Damian Mooyman) - See [ss-2017-010](http://www.silverstripe.org/download/security-releases/ss-2017-010)
* 2017-11-20 [099a5a3c2]() SQL injection in full text search (Damian Mooyman) - See [ss-2017-008](http://www.silverstripe.org/download/security-releases/ss-2017-008)
### API Changes
* 2017-11-07 [96dfc95](https://github.com/silverstripe/silverstripe-versioned/commit/96dfc951c7bb76a112cb49af7f0aebf75bd29af4) Remove MemberExtension, functionality is replaced by framework update (Robbie Averill)
### Features and Enhancements
* 2017-12-04 [8ee35f4](https://github.com/silverstripe/silverstripe-asset-admin/commit/8ee35f46cbc9ae96e7927af46ea7ca8f067e55e1) added loadComponent fix for asset-admin entwine components (Christopher Joe)
* 2017-12-01 [259ae3f78]() Add ViewableData::getViewerTemplates() (Loz Calver)
* 2017-11-27 [b418616](https://github.com/silverstripe/silverstripe-admin/commit/b4186162769cee0c4fe7ab2df50781241b4e17ad) Use recipes for test configuration (Damian Mooyman)
* 2017-11-27 [33a39666b]() Promote portugese (portugal) as primary locale (Damian Mooyman)
* 2017-11-20 [3d5f4b3](https://github.com/silverstripe/silverstripe-assets/commit/3d5f4b38952d3b4d9fbf3a53767a942065490a0d) Hide Image_Backend construction behind image manipulations to improve performance (Damian Mooyman)
* 2017-11-20 [dea77c7](https://github.com/silverstripe/silverstripe-assets/commit/dea77c7792f9ee92f6c2ac600978c16cf7bf222c) Disable force_resample by default (Damian Mooyman)
* 2017-11-20 [0a37ff3](https://github.com/silverstripe/silverstripe-asset-admin/commit/0a37ff30c0d747e89dbcbd1a2a42411392aeb118) Don't request unused width / height from graphql (Damian Mooyman)
* 2017-11-15 [6a6cf2f9e]() Raise warning if DBField::create_field() would behave unpredictably and improve PHPDoc (Damian Mooyman)
* 2017-11-15 [8b063026f]() Ensure that non-writable assets files are notified during install (Damian Mooyman)
### Bugfixes
* 2017-12-05 [7efe667a](https://github.com/silverstripe/silverstripe-cms/commit/7efe667a487b4551dc21c0435b83cdced6290fc6) VirtualPage not using target page's template (fixes #2039) (#2041) (Loz Calver)
* 2017-12-03 [9fcebe7](https://github.com/silverstripe/silverstripe-asset-admin/commit/9fcebe7f317d2bdc7c1371ec4b4f6f20f6687e02) Fix unit tests (Christopher Joe)
* 2017-12-02 [3a4c6705c]() db autodiscover comment on loading behavior. (Russell Maclean)
* 2017-12-01 [91bd92df3]() Remove some unnecessary ClassInfo calls in DataObjectSchema (Loz Calver)
* 2017-12-01 [69295a6e2]() Ensure that all tinymce_lang mappings are valid (Damian Mooyman)
* 2017-11-28 [b3a51aa8d]() Fix broken scrutinizer (Damian Mooyman)
* 2017-11-28 [0de9b07](https://github.com/silverstripe/silverstripe-admin/commit/0de9b074fe6ac1e2d44c67b16f76fe3e01224131) Fix typo in Menu.scss (Damian Mooyman)
* 2017-11-27 [c4b366828]() Restore BackURL preservation on log out (closes #7636) (Loz Calver)
* 2017-11-27 [83cf147](https://github.com/silverstripe/silverstripe-admin/commit/83cf147649095f35ea6421a583153587c4afd8d9) Issue where logging out from the CMS presents you with a login form with no BackURL (Daniel Hensby)
* 2017-11-27 [b7ea05900]() Support self::class text collection (Robbie Averill)
* 2017-11-27 [cc72b5c85]() Added warning for auto-generated table_name for non-test classes (Christopher Joe)
* 2017-11-24 [09a003bc1]() deprecated usage of getMock in unit tests (Daniel Hensby)
* 2017-11-22 [ef6d86f2c]() Allow lowercase and uppercase delcaration of legacy Int class (Daniel Hensby)
* 2017-11-22 [d9e7a92b3]() Fix regressions in asset resize behaviour change (Damian Mooyman)
* 2017-11-21 [966622263]() Fix _configure_database.php being ignored (Damian Mooyman)
* 2017-11-21 [14b2641](https://github.com/silverstripe/silverstripe-config/commit/14b2641d0e10641817c15f1cda183b046fb86232) Fix added module fluid-prefix so module config will not require the full path to match (Christopher Joe)
* 2017-11-21 [27c079c](https://github.com/silverstripe/silverstripe-asset-admin/commit/27c079c307cb4d7ea4f0c176ad5105f37ecf3c27) Fix change in resampled config setting (Christopher Joe)
* 2017-11-21 [b1dc681](https://github.com/silverstripe/silverstripe-admin/commit/b1dc681d369899b2205340d1522441d6ccce5d24) Ensure changetracker safely defers to other init scripts (Damian Mooyman)
* 2017-11-20 [1e96989](https://github.com/silverstripe/silverstripe-config/commit/1e96989b99b108356ef349ce3a40f8681b71e925) Fix parameter order (Christopher Joe)
* 2017-11-20 [4fb0911](https://github.com/silverstripe/silverstripe-admin/commit/4fb0911290506d63d61c5a285f6ad6102cd3384f) Fix for buttons in change tracking and gridfield reloading (Christopher Joe)
* 2017-11-19 [694d2589](https://github.com/silverstripe/silverstripe-cms/commit/694d2589579f944ec714dac6aff7b888e5c42a96) Fix allowed children types now load properly (Christopher Joe)
* 2017-11-17 [509a590](https://github.com/silverstripe/silverstripe-admin/commit/509a590362d815f7d680c14a747e09674b3651b4) fix ignore `no-change-track` marked fields in changetracker (Christopher Joe)
* 2017-11-16 [cbf9e4011]() Fix postgres / PDO support (Damian Mooyman)
* 2017-11-16 [dda14e895]() HTTP::get_mime_type with uppercase filenames. (Roman Schmid)
* 2017-11-16 [52f0eadd3]() for #7606: Ensure the object we're handling is actually an Image instance before calling methods specific to that class (e.g. in case of using SVG's in &lt;img&gt; tag which may be File instances). (Patrick Nelson)
* 2017-11-16 [8de154d9](https://github.com/silverstripe/silverstripe-cms/commit/8de154d92cc9b044824205216683c0a187d17e5b) Restore missing '(Choose Page)' text in link insert modal (Damian Mooyman)
* 2017-11-15 [ef5879910]() Fix DBEnum ignoring empty defaults (Damian Mooyman)
* 2017-11-15 [ce3fd370f]() ManyMany link table joined with LEFT JOIN (Daniel Hensby)
* 2017-11-15 [3ad6a93](https://github.com/silverstripe/silverstripe-admin/commit/3ad6a937b8ae499f2f401c4cc1dd1193442f971e) page header center aligns when site tree is closed (Saophalkun Ponlu)
* 2017-11-15 [1c81430](https://github.com/silverstripe/silverstripe-admin/commit/1c8143078048bc0bdd516aeefcb171ec527359f2) fix show empty string title when relevant - rather than null when no options (Christopher Joe)
* 2017-11-14 [2bc7edbf4]() Fix don't treat zero-date as invalid (Christopher Joe)
* 2017-11-14 [b7e96fc](https://github.com/silverstripe/silverstripe-assets/commit/b7e96fcf3e39777d75740468ee39c224318ec68d) Prevent .htaccess operations from users in the same group failing (Damian Mooyman)
* 2017-11-14 [2e3bbe4](https://github.com/silverstripe/silverstripe-asset-admin/commit/2e3bbe437c5c7234a590c514c56b2c5674eaa051) Fix shortcodes not being parsed (Damian Mooyman)
* 2017-11-13 [3b5cee8](https://github.com/silverstripe/silverstripe-admin/commit/3b5cee8135ed444dba05bf66676ecf90c4b220e3) unsaved change dialog display just after creating a record (Saophalkun Ponlu)
* 2017-11-13 [d60f4a3](https://github.com/silverstripe/silverstripe-admin/commit/d60f4a30795a7d40d0b766bf62ed55c8291efe69) fix missing chosen sprites added to dist folder (Christopher Joe)
* 2017-11-09 [bf20d59cb]() Fixes SapphireTest masking userland coding errors. (Russell Michell)
* 2017-11-09 [1053de7ec]() Don't redirect in force_redirect() in CLI (Damian Mooyman)
* 2017-11-08 [0a87ad2](https://github.com/silverstripe/silverstripe-assets/commit/0a87ad270214563e7a90338b0a090da28dce6e1a) Remove whitespace around download link title (Robbie Averill)
* 2017-11-08 [6139de868]() Make sure plain parts are rendered when re-rendering emails (Daniel Hensby)
* 2017-11-06 [d3ff0d7](https://github.com/silverstripe/silverstripe-asset-admin/commit/d3ff0d74d2d49a2294b40f532174351bdef58101) Fix buttons in upload field to be proper button types (Christopher Joe)
* 2017-11-05 [d8b4ca91d]() Fix ContextSummary behaviour with UTF8 chars (Sam Minnee)
* 2017-11-03 [1d5cd20](https://github.com/silverstripe/silverstripe-admin/commit/1d5cd20ac553278396600e848f5482633c96a52c) Fix react-select does not return the true value when the option is missing (Christopher Joe)
* 2017-11-02 [457e653](https://github.com/silverstripe/silverstripe-asset-admin/commit/457e653867631d1fcec5676beb48ed01e05caaee) Fix native upload dialog appearing in entwine sections and added a canUpload condition for UploadField (Christopher Joe)
* 2017-11-01 [1bdfd056](https://github.com/silverstripe/silverstripe-cms/commit/1bdfd056482f1ba2c682e683a3582c682ec3dbbe) Remove usage of deprecated each() (Damian Mooyman)
* 2017-11-01 [5bc4f3d1f]() Remove usage of deprecated each() and use a helper method instead (Damian Mooyman)
* 2017-10-31 [f952ef747]() ed array/object mismatch bug in PaginatedList (Colin Tucker)
* 2017-10-25 [dd54e04](https://github.com/silverstripe/silverstripe-asset-admin/commit/dd54e04a4998ffb1968ab1e38423752f8e44b426) Fix usability issue, can tab to the upload field item even when it doesn't do anything by default (Christopher Joe)
* 2017-10-25 [cbac37559]() Helpful warning when phpunit bootstrap appears misconfigured (Daniel Hensby)
* 2017-10-25 [32cef975e]() Use self::inst() for Injector/Config nest methods (Daniel Hensby)
* 2017-10-25 [23316fc](https://github.com/silverstripe/silverstripe-asset-admin/commit/23316fccf2e1da907251614f6aaf40f58a6427ac) Fix wrong mouse cursor for description text in upload field area (Christopher Joe)
* 2017-10-19 [4965dc4](https://github.com/silverstripe/silverstripe-admin/commit/4965dc4fcb1cf650b1b4840f13e25aca39fd286f) stop bothering people with pop-ups (Christopher Joe)
* 2017-10-19 [a73d5b41](https://github.com/silverstripe/silverstripe-cms/commit/a73d5b4177be445128a6fa42e20dd8df13eaf554) revert to this button after archiving (Christopher Joe)
* 2017-10-12 [fd39faee](https://github.com/silverstripe/silverstripe-cms/commit/fd39faeefd5241cf96313e968142183de767c51b) UploadField overwriteWarning isn't working in AssetAdmin (Jason)
* 2017-10-09 [264cec123]() Dont use var_export for cache key generation as it fails on circular references (Daniel Hensby)
* 2017-10-04 [24e190ea](https://github.com/silverstripe/silverstripe-cms/commit/24e190ea8265d16445a3210f7b06de191e474004) TreeDropdownField showing broken page icons (fixes silverstripe/silverstripe-framework#7420) (Loz Calver)
* 2017-08-13 [2f579b64c]() Files without extensions (folders) do not have a trailing period added (Robbie Averill)
* 2017-07-04 [00f1ad5d6]() Fixes #7116 Improves server requirements docs viz: OpCaches. (Russell Michell)

View File

@ -211,6 +211,7 @@ en:
many_many_Members: Members
SilverStripe\Security\LoginAttempt:
Email: 'Email Address'
EmailHashed: 'Email Address (hashed)'
IP: 'IP Address'
PLURALNAME: 'Login Attempts'
PLURALS:
@ -269,6 +270,8 @@ en:
SilverStripe\Security\MemberAuthenticator\MemberAuthenticator:
ERRORWRONGCRED: 'The provided details don''t seem to be correct. Please try again.'
NoPassword: 'There is no password on this member.'
SilverStripe\Security\MemberAuthenticator\MemberLoginForm:
AUTHENTICATORNAME: 'E-mail &amp; Password'
SilverStripe\Security\MemberPassword:
PLURALNAME: 'Member Passwords'
PLURALS:

View File

@ -100,6 +100,8 @@ fi:
Save: Tallenna
SilverStripe\Forms\GridField\GridFieldEditButton_ss:
EDIT: Muokkaa
SilverStripe\Forms\GridField\GridFieldGroupDeleteAction:
UnlinkSelfFailure: 'Et voi siirtää itseäsi pois tästä ryhmästä: menettäisit pääkäyttäjän oikeudet'
SilverStripe\Forms\GridField\GridFieldPaginator:
OF: /
Page: Sivu
@ -250,6 +252,7 @@ fi:
SUBJECTPASSWORDCHANGED: 'Salasanasi on vaihdettu'
SUBJECTPASSWORDRESET: 'Salasanasi palautuslinkki'
SURNAME: Sukunimi
VALIDATIONADMINLOSTACCESS: 'Ylläpitäjäryhmää ei voi poistaa profiilistasi'
ValidationIdentifierFailed: 'Olemassa olevan käyttäjän id:n #{id} päälle ei voida kirjoittaa samalla tunnisteella ({name} = {value}))'
WELCOMEBACK: 'Tervetuloa takaisin, {firstname}'
YOUROLDPASSWORD: 'Vanha salasanasi'

View File

@ -1,63 +1,84 @@
fr:
SilverStripe\Admin\LeftAndMain:
VersionUnknown: Inconnu
SilverStripe\AssetAdmin\Forms\UploadField:
Dimensions: Dimensions
EDIT: Éditer
EDITINFO: 'Éditer ce fichier'
REMOVE: Retirer
SilverStripe\Control\ChangePasswordEmail_ss:
CHANGEPASSWORDFOREMAIL: 'Le mot de passe du compte correspondant à l''adresse {email} a été modifié. Si vous n''avez pas modifié votre mot de passe, merci de le changer à l''aide du lien suivant'
CHANGEPASSWORDTEXT1: 'Votre mot de passe est maintenant'
CHANGEPASSWORDTEXT3: 'Changer le mot de passe'
HELLO: Bonjour
SilverStripe\Control\Email\ForgotPasswordEmail_ss:
HELLO: Bonjour
TEXT1: 'Voici votre'
TEXT2: 'Lien de réinitialisation de mot de passe'
TEXT3: pour
SilverStripe\Control\RequestProcessor:
INVALID_REQUEST: 'Requête invalide'
REQUEST_ABORTED: 'Requête non aboutie'
SilverStripe\Core\Manifest\VersionProvider:
VERSIONUNKNOWN: Inconnu
SilverStripe\Forms\CheckboxField:
NOANSWER: Non
YESANSWER: Oui
SilverStripe\Forms\CheckboxSetField_ss:
NOOPTIONSAVAILABLE: 'Aucune option disponible'
SilverStripe\Forms\ConfirmedPasswordField:
ATLEAST: 'Le mot de passe doit comporter au moins {min} caractères.'
BETWEEN: 'Le mot de passe doit comporter entre {min} et {max} caractères.'
CURRENT_PASSWORD_ERROR: 'Le mot de passe que vous avez saisi n''est pas correct'
CURRENT_PASSWORD_MISSING: 'Vous devez saisir votre mot de passe actuel.'
LOGGED_IN_ERROR: 'Vous devez être connecté pour pouvoir changer votre mot de passe'
MAXIMUM: 'Le mot de passe ne doit comporter plus de {max} caractères.'
MAXIMUM: 'Le mot de passe ne doit pas comporter plus de {max} caractères.'
SHOWONCLICKTITLE: 'Changer le mot de passe'
SilverStripe\Forms\CurrencyField:
CURRENCYSYMBOL: $
SilverStripe\Forms\DateField:
NOTSET: 'non renseigné'
TODAY: 'aujourd''hui'
VALIDDATEFORMAT2: 'Saisissez la date au format valide ({format})'
VALIDDATEMAXDATE: 'La date doit être antérieure ou égale à celle qui a été autorisée ({date})'
VALIDDATEMINDATE: 'La date doit être plus récente ou égale à celle qui a été autorisée ({date})'
VALIDDATEFORMAT2: 'Saisissez une date au format valide ({format})'
VALIDDATEMAXDATE: 'La date doit être antérieure ou égale à celle autorisée ({date})'
VALIDDATEMINDATE: 'La date doit être postérieure ou égale à celle autorisée ({date})'
SilverStripe\Forms\DatetimeField:
VALIDDATEMAXDATETIME: 'La date doit être antérieure ou égale à celle autorisée ({datetime})'
VALIDDATETIMEFORMAT: 'Saisissez un format de date et d''heure valide ({format})'
VALIDDATETIMEMINDATE: 'La date doit être postérieure ou égale à celle autorisée ({datetime})'
SilverStripe\Forms\DropdownField:
CHOOSE: (Choisir)
CHOOSE_MODEL: '(Choisir {name})'
SOURCE_VALIDATION: 'Merci de choisir une valeur parmi celles proposées dans la liste. {value} n''est pas une option valide'
SilverStripe\Forms\EmailField:
VALIDATION: 'Saisissez une adresse de courrier électronique'
VALIDATION: 'Merci de saisir une adresse email'
SilverStripe\Forms\FileUploadReceiver:
FIELDNOTSET: 'Informations concernant le fichiers non-trouvées'
FIELDNOTSET: 'Information sur le fichier introuvable'
SilverStripe\Forms\Form:
CSRF_EXPIRED_MESSAGE: 'Votre session a expiré. Renvoyez le formulaire.'
BAD_METHOD: 'Ce formulaire requiert une action {method}'
CSRF_EXPIRED_MESSAGE: 'Votre session a expiré. Merci de renvoyer le formulaire.'
CSRF_FAILED_MESSAGE: 'Un problème technique est probablement survenu. Merci de cliquer sur le bouton "retour", de rafraîchir la page de votre navigateur, et de réessayer.'
VALIDATIONPASSWORDSDONTMATCH: 'Les mots de passe ne correspondent pas'
VALIDATIONPASSWORDSNOTEMPTY: 'Les mots de passe peuvent être vides'
VALIDATIONPASSWORDSNOTEMPTY: 'Les mots de passe ne peuvent pas être vides'
VALIDATIONSTRONGPASSWORD: 'Le mot de passe doit comporter au moins un chiffre et un caractère alphanumérique'
VALIDATOR: Validateur
VALIDCURRENCY: 'Saisissez une monnaie valide'
SilverStripe\Forms\FormField:
EXAMPLE: 'Par ex. {format}'
NONE: aucun
SilverStripe\Forms\FormScaffolder:
TABMAIN: Principal
SilverStripe\Forms\GridField\GridField:
Add: 'Ajouter {name}'
CSVEXPORT: 'Exporter vers un fichier CSV'
CSVIMPORT: 'Importer un fichier CSV'
Filter: Filtrer
FilterBy: 'Filtrer par'
Find: Trouver
LinkExisting: 'Lien existant'
NewRecord: 'Nouveau {type}'
NoItemsFound: 'Aucun élément na été trouvé.'
PRINTEDAT: 'Imprimé le'
PRINTEDAT: 'Imprimé à'
PRINTEDBY: 'Imprimé par'
PlaceHolder: 'Rechercher {type}'
PlaceHolderWithLabels: 'Rechercher {type} par {name}'
@ -65,7 +86,7 @@ fr:
RelationSearch: 'Rechercher relations'
ResetFilter: Réinitialiser
SilverStripe\Forms\GridField\GridFieldDeleteAction:
DELETE_DESCRIPTION: Supprime
DELETE_DESCRIPTION: Supprimer
Delete: Supprimer
DeletePermissionsFailure: 'Vous navez pas les autorisations pour supprimer'
EditPermissionsFailure: 'Pas de permissions pour délier l''enregistrement'
@ -79,52 +100,110 @@ fr:
Save: Enregistrer
SilverStripe\Forms\GridField\GridFieldEditButton_ss:
EDIT: Editer
SilverStripe\Forms\GridField\GridFieldGroupDeleteAction:
UnlinkSelfFailure: 'Impossible de retirer votre propre profil de ce groupe, vous perdriez vos droits d''administration'
SilverStripe\Forms\GridField\GridFieldPaginator:
OF: de
Page: Page
View: Vue
SilverStripe\Forms\GridField\GridFieldVersionedState:
ADDEDTODRAFTHELP: 'L''élément n''a pas encore été publié'
ADDEDTODRAFTSHORT: Brouillon
ARCHIVEDPAGEHELP: 'Elément retiré du brouillon et du site public'
ARCHIVEDPAGESHORT: Archivé
MODIFIEDONDRAFTHELP: 'L''élément comporte des modifications non sauvegardées'
MODIFIEDONDRAFTSHORT: Modifié
ONLIVEONLYSHORT: 'Site public uniquement'
ONLIVEONLYSHORTHELP: 'L''élément a été publié, mais sa version brouillon a été supprimée'
SilverStripe\Forms\MoneyField:
FIELDLABELAMOUNT: Quantité
FIELDLABELCURRENCY: Devise
INVALID_CURRENCY: '{currency} ne figure pas dans la liste des devises autorisées'
SilverStripe\Forms\MultiSelectField:
SOURCE_VALIDATION: 'Merci de choisir des valeurs parmi celles proposées dans la liste. Option(s) {value} non valide(s)'
SilverStripe\Forms\NullableField:
IsNullLabel: 'Est Null'
SilverStripe\Forms\NumericField:
VALIDATION: "«\_{value}\_» nest pas un chiffre, seule donnée acceptée dans ce champ "
VALIDATION: "«\_{value}\_» nest pas un nombre, seul type de donnée acceptée dans ce champ "
SilverStripe\Forms\TimeField:
VALIDATEFORMAT: 'Saisissez lheure au format valide ({format})'
VALIDATEFORMAT: 'Merci de saisir un format de date valide ({format})'
SilverStripe\ORM\DataObject:
PLURALNAME: 'Modèles de donnée'
PLURALS:
one: 'Un modèle de donnée'
other: '{count} modèles de donnée'
SINGULARNAME: 'Modèle de donnée'
SilverStripe\ORM\FieldType\DBBoolean:
ANY: Tout
NOANSWER: Non
YESANSWER: Oui
SilverStripe\ORM\FieldType\DBDate:
DAYS_SHORT_PLURALS:
one: '{count} jour'
other: '{count} jours'
HOURS_SHORT_PLURALS:
one: '{count} heure'
other: '{count} heures'
LessThanMinuteAgo: 'moins d''une minute'
MINUTES_SHORT_PLURALS:
one: '{count} min.'
other: '{count} min.'
MONTHS_SHORT_PLURALS:
one: '{count} mois'
other: '{count} mois'
SECONDS_SHORT_PLURALS:
one: '{count} sec.'
other: '{count} sec.'
TIMEDIFFAGO: 'Il y a {difference}'
TIMEDIFFIN: 'Dans {difference}'
YEARS_SHORT_PLURALS:
one: '{count} année'
other: '{count} années'
SilverStripe\ORM\FieldType\DBEnum:
ANY: Tous
ANY: Tout
SilverStripe\ORM\Hierarchy:
LIMITED_TITLE: 'Enfants trop nombreux ({count})'
SilverStripe\ORM\Hierarchy\Hierarchy:
InfiniteLoopNotAllowed: "Une boucle infinie sest produite dans la hiérarchie «\_{type}\_». Modifiez le parent pour le résoudre."
InfiniteLoopNotAllowed: "Une boucle sans fin sest produite dans la hiérarchie «\_{type}\_». Merci de modifier le parent pour résoudre le problème."
LIMITED_TITLE: 'Enfants trop nombreux ({count})'
SilverStripe\ORM\ValidationException:
DEFAULT_ERROR: 'Erreur de validation'
SilverStripe\Security\BasicAuth:
ENTERINFO: 'Entrer un identifiant et un mot de passe s''il vous plaît.'
ENTERINFO: 'Merci d''entrer un identifiant et un mot de passe.'
ERRORNOTADMIN: 'Cet utilisateur n''est pas un administrateur.'
ERRORNOTREC: 'Cet identifiant / mot de passe n''est pas reconnu'
ERRORNOTREC: 'Identifiant et/ou mot de passe non reconnus'
SilverStripe\Security\CMSMemberLoginForm:
PASSWORDEXPIRED: '<p>Votre mot de passe a expiré. <a target="_top" href="{link}">Merci d''en choisir un nouveau.</a></p>'
SilverStripe\Security\CMSSecurity:
INVALIDUSER: '<p>Utilisateur non valide. <a target="_top" href="{link}">Merci de vous authentifier de nouveau ici</a> pour poursuivre.</p>'
LOGIN_MESSAGE: '<p>Votre session a expiré pour cause d''inactivité</p>'
LOGIN_TITLE: 'Retournez là où vous en étiez en vos connectant de nouveau'
SUCCESS: Succès
SUCCESSCONTENT: '<p>Connexion réussie. Si vous n''êtes pas automatiquement redirigé <a target="_top" href="{link}">cliquez ici</a></p>'
SUCCESS_TITLE: 'Connexion réussie'
SilverStripe\Security\DefaultAdminService:
DefaultAdminFirstname: 'Administrateur par défaut'
SilverStripe\Security\Group:
AddRole: 'Ajouter un rôle pour ce groupe'
Code: 'Code de groupe'
Code: 'Code du groupe'
DefaultGroupTitleAdministrators: Administrateur
DefaultGroupTitleContentAuthors: 'Auteurs du contenu'
Description: Description
GROUPNAME: 'Nom du groupe'
GroupReminder: 'Si vous choisissez un groupe parent, ce groupe prendra tous ses rôles'
HierarchyPermsError: 'Impossible d''attribuer des autorisations au groupe parent "{group}" (requiert un accès en tant qu''administrateur)'
Locked: 'Verrouillé?'
MEMBERS: Membres
NEWGROUP: 'Nouveau groupe'
NoRoles: 'Vous navez pas la permission pour faire ça'
NoRoles: 'Aucun rôle trouvé'
PERMISSIONS: Permissions
PLURALNAME: Groupes
PLURALS:
one: 'Un groupe'
other: '{count} groupes'
Parent: 'Groupe parent'
ROLES: Rôles
ROLESDESCRIPTION: 'Les rôles sont des ensembles de permissions prédéfinies, et ils peuvent être attribués à des groupes. <br />Si nécessaire, ils peuvent hériter de groupes parents.'
RolesAddEditLink: 'Ajouter/éditer les rôles'
SINGULARNAME: Groupe
Sort: 'Ordre de tri'
@ -133,80 +212,125 @@ fr:
SilverStripe\Security\LoginAttempt:
Email: 'Adresse email'
IP: 'Adresse IP'
PLURALNAME: 'Tentatives de connexion'
PLURALS:
one: 'Une tentative de connexion'
other: '{count} tentatives de connexion'
SINGULARNAME: 'Tentative de connexion'
Status: Statut
SilverStripe\Security\Member:
ADDGROUP: 'Ajouter un groupe'
BUTTONCHANGEPASSWORD: 'Changer mot de passe'
BUTTONLOGIN: 'Se connecter'
BUTTONLOGINOTHER: 'Connectez vous avec un différent identifiant'
BUTTONLOGINOTHER: 'Se connecter avec un identifiant différent'
BUTTONLOGOUT: Déconnexion
BUTTONLOSTPASSWORD: 'J''ai perdu mon mot de passe'
CONFIRMNEWPASSWORD: 'Confirmer nouveau mot de passe'
CONFIRMPASSWORD: 'Confirmer Mot De Passe'
CURRENT_PASSWORD: 'Mot de passe actuel'
EDIT_PASSWORD: 'Nouveau mot de passe'
EMAIL: Email
EMPTYNEWPASSWORD: 'Le champs nouveau mot de passe ne peut être vide, essayez de nouveau'
ENTEREMAIL: 'Veuillez écrire une adresse email pour obtenir le lien de réinitialisation du mot de passe.'
ERRORLOCKEDOUT2: 'Votre compte a été temporairement désactivé à cause de trop nombreux échecs d''identification. Veuillez réessayer dans {count} minutes.'
EMPTYNEWPASSWORD: 'Le champs nouveau mot de passe ne peut être vide, merci de réessayer'
ENTEREMAIL: 'Veuillez entrer une adresse email pour obtenir un lien de réinitialisation du mot de passe.'
ERRORLOCKEDOUT2: 'Votre compte a été temporairement désactivé en raison d''un nombre trop élevé d''échecs d''identification. Veuillez réessayer dans {count} minutes.'
ERRORNEWPASSWORD: 'Vous avez entré votre nouveau mot de passe différemment, réessayez'
ERRORPASSWORDNOTMATCH: 'Votre actuel mot de passe ne correspond pas, essayez encore s''il vous plaît'
ERRORWRONGCRED: 'Il semble que ce ne soit pas le bon email ou mot de passe. Essayez encore s''il vous plaît.'
ERRORPASSWORDNOTMATCH: 'Votre actuel mot de passe ne correspond pas, merci de réessayer'
ERRORWRONGCRED: 'Il semble que ce ne soit pas le bon email ou mot de passe. Merci de réessayer.'
FIRSTNAME: Prénom
INTERFACELANG: 'Langue de l''interface'
KEEPMESIGNEDIN: 'Se souvenir de moi'
LOGGEDINAS: 'Vous êtes connecté comme {name}.'
LOGGEDINAS: 'Vous êtes connecté en tant que {name}.'
NEWPASSWORD: 'Nouveau mot de passe'
PASSWORD: 'Mot de passe'
PASSWORDEXPIRED: 'Votre mot de passe a expiré. Choisissez-en un nouveau.'
PASSWORDEXPIRED: 'Votre mot de passe a expiré. Merci d''en choisir un nouveau.'
PLURALNAME: Membres
PLURALS:
one: 'Un membre'
other: '{count} membres'
REMEMBERME: 'Se souvenir de moi la prochaine fois ? (pour une durée de {count} jours sur cet appareil)'
SINGULARNAME: Membre
SUBJECTPASSWORDCHANGED: 'Votre mot de passe a été changé'
SUBJECTPASSWORDRESET: 'Lien pour modifier votre mot de passe'
SURNAME: 'Nom de famille'
ValidationIdentifierFailed: 'On ne peut pas réenregistrer le membre nº {id} avec un identifiant identique ({name} = {value}))'
WELCOMEBACK: 'Bienvenue {firstname}'
VALIDATIONADMINLOSTACCESS: 'Impossible de retirer tous les groupes d''administrateur à partir de votre profil'
ValidationIdentifierFailed: 'Impossible de réenregistrer le membre nº {id} avec un identifiant identique ({name} = {value}))'
WELCOMEBACK: 'Bienvenue de nouveau, {firstname}'
YOUROLDPASSWORD: 'Votre ancien mot de passe'
belongs_many_many_Groups: Groupes
db_Locale: 'Langue de l''Interface'
db_LockedOutUntil: 'Verrouillé jusqu''à'
db_Password: 'Mot de passe'
db_PasswordExpiry: 'Date d''expiration du mot de passe'
SilverStripe\Security\MemberAuthenticator\CMSMemberLoginForm:
AUTHENTICATORNAME: 'Formulaire de connexion pour un utilisateur du CMS'
BUTTONFORGOTPASSWORD: 'Mot de passe oublié'
BUTTONLOGIN: 'De retour dans'
BUTTONLOGOUT: 'Se déconnecter'
SilverStripe\Security\MemberAuthenticator\MemberAuthenticator:
ERRORWRONGCRED: 'Les renseignements fournis semblent incorrects. Merci de réessayer.'
NoPassword: 'Ce membre n''a pas de mot de passe'
SilverStripe\Security\MemberPassword:
PLURALNAME: 'Mots de passe du membre'
SINGULARNAME: 'Mot de passe du membre'
PLURALNAME: 'Mots de passe utilisateur'
PLURALS:
one: 'Un mot de passe utilisateur'
other: '{count} mots de passe utilisateur'
SINGULARNAME: 'Mot de passe utilisateur'
SilverStripe\Security\PasswordValidator:
LOWCHARSTRENGTH: 'Veuillez augmenter la force de votre mot de passe en ajoutant certains caractères suivants : {chars}'
LOWCHARSTRENGTH: 'Veuillez renforcer votre mot de passe en ajoutant certains des caractères suivants : {chars}'
PREVPASSWORD: 'Vous avez déjà utilisé ce mot de passe par le passé, veuillez en choisir un autre'
TOOSHORT: 'Le mot de passe est trop court, il doit contenir au moins {minimum} caractères'
SilverStripe\Security\Permission:
AdminGroup: Administrateur
CONTENT_CATEGORY: 'Permissions du contenu'
CMS_ACCESS_CATEGORY: 'Accès au CMS'
CONTENT_CATEGORY: 'Permissions de contenu'
FULLADMINRIGHTS: 'Droits d''administration complets'
FULLADMINRIGHTS_HELP: 'Implique et prévaut sur toutes les autres autorisations assignées.'
FULLADMINRIGHTS_HELP: 'Prévaut sur toutes les autres autorisations assignées.'
PERMISSIONS_CATEGORY: 'Rôles et autorisations daccès'
PLURALNAME: Permissions
PLURALS:
one: 'Une autorisation'
other: '{count} autorisations'
SINGULARNAME: Permission
UserPermissionsIntro: "Assigner des groupes à cet utilisateur modifiera les autorisations dont il dispose. Consultez la section «\_Groupes\_» pour plus de détails sur les autorisations associées à chaque groupe."
SilverStripe\Security\PermissionCheckboxSetField:
AssignedTo: 'assignée au groupe « {title} »'
FromGroup: "hérité du groupe «\_{title}\_»"
FromRole: "héritée du rôle «\_{title}\_»"
FromRoleOnGroup: "hérité du rôle «\_{roletitle}\_» du groupe «\_{grouptitle}\_»"
AssignedTo: 'assigné au groupe « {title} »'
FromGroup: "hérite du groupe «\_{title}\_»"
FromRole: "hérite du rôle «\_{title}\_»"
FromRoleOnGroup: "hérite du rôle «\_{roletitle}\_» du groupe «\_{grouptitle}\_»"
SilverStripe\Security\PermissionRole:
OnlyAdminCanApply: 'Limité aux administrateurs'
PLURALNAME: Rôles
PLURALS:
one: 'Un rôle'
other: '{count} rôles'
SINGULARNAME: Rôle
Title: Titre
SilverStripe\Security\PermissionRoleCode:
PLURALNAME: 'Codes d''autorisations liés au rôle'
PLURALS:
one: 'Un code d''autorisation lié au rôle'
other: '{count} codes d''autorisation liés au rôle'
PermsError: 'Impossible d''attribuer le code "{code}" (requiert un accès en tant qu''administrateur)'
SINGULARNAME: 'Code d''autorisation lié au rôle'
SilverStripe\Security\RememberLoginHash:
PLURALNAME: 'Signatures de mot de passe'
PLURALS:
one: 'Une signature de mot de passe'
other: '{count} signatures de mot de passe'
SINGULARNAME: 'Signature de mot de passe'
SilverStripe\Security\Security:
ALREADYLOGGEDIN: 'Vous n''avez pas accès à cette page. Si vous avez un autre identifiant pouvant accéder à cette page, vous pouvez l''utiliser ci-dessous.'
ALREADYLOGGEDIN: 'Vous n''avez pas accès à cette page. Si un autre de vos identifiants vous permet d''accéder à cette page, merci de vous reconnecter ci-dessous en l''utilisant.'
BUTTONSEND: 'Envoyer moi le lien pour modifier le mot de passe'
CHANGEPASSWORDBELOW: 'Vous pouvez modifier votre mot de passe ci-dessous.'
CHANGEPASSWORDHEADER: 'Modifier votre mot de passe'
CONFIRMLOGOUT: 'Merci de cliquer le bouton ci-dessous pour confirmer que vous souhaitez vous déconnecter.'
ENTERNEWPASSWORD: 'Entrer un nouveau mot de passe s''il vous plaît.'
ERRORPASSWORDPERMISSION: 'Vous devez être connecté pour modifier votre mot de passe !'
LOGIN: Connectez-vous
LOGIN: 'Se connecter'
LOGOUT: 'Se déconnecter'
LOSTPASSWORDHEADER: 'Mot de passe oublié'
NOTEPAGESECURED: 'Cette page est sécurisée. Entrer vos détails ci-dessous et nous vous enverrons directement.'
NOTEPAGESECURED: 'Cette page est sécurisée. Entrez vos identifiants ci-dessous et vous pourrez y avoir accès.'
NOTERESETLINKINVALID: '<p>Le lien de réinitialisation du mot de passe nest pas valide ou a expiré.</p><p>Vous pouvez en demander un nouveau <a href="{link1}">en suivant ce lien</a> ou changer de mot de passe après <a href="{link2}">connexion</a>.</p>'
NOTERESETPASSWORD: 'Entrer votre adresse email et nous vous enverrons un lien pour modifier votre mot de passe'
NOTERESETPASSWORD: 'Entrez votre adresse email et nous vous enverrons un lien pour modifier votre mot de passe'
PASSWORDSENTHEADER: "Lien de réinitialisation de mot de passe envoyé à «\_{email}\_»"
PASSWORDSENTTEXT: "Merci\_! Un lien de réinitialisation vient dêtre envoyé à «\_{email}\_», à condition que cette adresse existe."

View File

@ -1,7 +1,31 @@
sk:
SilverStripe\Admin\LeftAndMain:
VersionUnknown: neznáma
SilverStripe\AssetAdmin\Forms\UploadField:
Dimensions: Rozmery
EDIT: Editovať
EDITINFO: 'Editovať súbor'
REMOVE: Odstrániť
SilverStripe\Control\ChangePasswordEmail_ss:
CHANGEPASSWORDFOREMAIL: 'Heslo pre účet s e-mailovou adresou {email} bolo zmenené. Ak ste nemenili vaše heslo, tak ho zmeňte pomocou odkazu uvedeného nižšie, prosím.'
CHANGEPASSWORDTEXT1: 'Vaše heslo bolo zmenené pre'
CHANGEPASSWORDTEXT3: 'Zmeniť heslo'
HELLO: Ahoj
SilverStripe\Control\Email\ForgotPasswordEmail_ss:
HELLO: Ahoj
TEXT1: 'Tu je váš'
TEXT2: 'odkaz na resetovanie hesla'
TEXT3: pre
SilverStripe\Control\RequestProcessor:
INVALID_REQUEST: 'Neplatná požiadavka'
REQUEST_ABORTED: 'Požiadavka prerušená'
SilverStripe\Core\Manifest\VersionProvider:
VERSIONUNKNOWN: Neznáma
SilverStripe\Forms\CheckboxField:
NOANSWER: Nie
YESANSWER: Áno
SilverStripe\Forms\CheckboxSetField_ss:
NOOPTIONSAVAILABLE: 'Žiadne dostupné možnosti'
SilverStripe\Forms\ConfirmedPasswordField:
ATLEAST: 'Heslá musia byť nejmenej {min} znakov dlhé.'
BETWEEN: 'Heslá musia byť {min} až {max} znakov dlhé.'
@ -34,6 +58,8 @@ sk:
VALIDCURRENCY: 'Prosím zadajte platnú menu'
SilverStripe\Forms\FormField:
NONE: žiadne
SilverStripe\Forms\FormScaffolder:
TABMAIN: Hlavné
SilverStripe\Forms\GridField\GridField:
Add: 'Pridať {name}'
CSVEXPORT: 'Exportovať do CSV'
@ -66,6 +92,10 @@ sk:
Save: Uložiť
SilverStripe\Forms\GridField\GridFieldEditButton_ss:
EDIT: Editovať
SilverStripe\Forms\GridField\GridFieldPaginator:
Page: Stránka
SilverStripe\Forms\GridField\GridFieldVersionedState:
ONLIVEONLYSHORT: 'Len publikované'
SilverStripe\Forms\MoneyField:
FIELDLABELAMOUNT: Množstvo
FIELDLABELCURRENCY: Mena
@ -104,6 +134,8 @@ sk:
INVALIDUSER: '<p>Neplatný užívateľ. <a target="_top" href="{link}">Prosím overte sa znovu tu</a> pre pokračovanie.</p>'
SUCCESS: Úspešné
SUCCESSCONTENT: '<p>Úspešné prihlásenie. Ak nebudete automaticky presmerovaní <a target="_top" href="{link}">kliknite tu</a></p>'
SilverStripe\Security\DefaultAdminService:
DefaultAdminFirstname: 'Predvolený administrátor'
SilverStripe\Security\Group:
AddRole: 'Pridať úlohu pre túto skupinu'
Code: 'Kód skupiny'
@ -113,6 +145,7 @@ sk:
GroupReminder: 'Ak vyberiete nadriadenú skupinu, bude táto skupina mať všetky úlohy'
HierarchyPermsError: 'Nie je možné pripojiť nadriadenú skupinu "{group}" s privilegovanými právami (vyžaduje ADMIN prístup)'
Locked: 'Zamknuté?'
MEMBERS: Členovia
NoRoles: 'Nenašli sa úlohy'
PLURALNAME: Skupiny
Parent: 'Nadradená skupina'
@ -168,7 +201,7 @@ sk:
SINGULARNAME: 'Heslo člena'
SilverStripe\Security\PasswordValidator:
LOWCHARSTRENGTH: 'Prosím posilnite heslo pridaním z týchto niektorých znakov: {chars}'
PREVPASSWORD: 'Už ste použili toto heslo v minulosti, vyberte nové hoslo, prosím'
PREVPASSWORD: 'Už ste použili toto heslo v minulosti, vyberte nové heslo, prosím'
TOOSHORT: 'Heslo je príliš krátke, musí byť {minimum} alebo viacej znakov dlhé'
SilverStripe\Security\Permission:
AdminGroup: Administrátor

View File

@ -260,7 +260,9 @@ class CSVParser implements Iterator
array($this->enclosure, $this->delimiter),
$value
);
// Trim leading tab
// [SS-2017-007] Ensure all cells with leading [@=+] have a leading tab
$value = ltrim($value, "\t");
if (array_key_exists($i, $this->headerRow)) {
if ($this->headerRow[$i]) {
$row[$this->headerRow[$i]] = $value;

View File

@ -26,18 +26,23 @@ class InstallConfig
*
* @param array $request Request object
* @param array $databaseClasses Supported database config
* @param bool $realPassword Set to true to get the real password. If false, any non-posted
* password will be redacted as '********'. Note: Posted passwords are considered disclosed and
* never redacted.
* @return array
*/
public function getDatabaseConfig($request, $databaseClasses)
public function getDatabaseConfig($request, $databaseClasses, $realPassword = true)
{
// Get config from request
if (isset($request['db']['type'])) {
$type = $request['db']['type'];
if (isset($request['db'][$type])) {
return array_merge(
[ 'type' => $type ],
$request['db'][$type]
);
$config = $request['db'][$type];
// The posted placeholder must be substituted with the real password
if (isset($config['password']) && $config['password'] === Installer::PASSWORD_PLACEHOLDER) {
$config['password'] = Environment::getEnv('SS_DATABASE_PASSWORD') ?: '';
}
return array_merge([ 'type' => $type ], $config);
}
}
@ -46,8 +51,16 @@ class InstallConfig
'type' => $this->getDatabaseClass($databaseClasses),
'server' => Environment::getEnv('SS_DATABASE_SERVER') ?: 'localhost',
'username' => Environment::getEnv('SS_DATABASE_USERNAME') ?: 'root',
'password' => Environment::getEnv('SS_DATABASE_PASSWORD') ?: '',
'password' => $realPassword
? (Environment::getEnv('SS_DATABASE_PASSWORD') ?: '')
: Installer::PASSWORD_PLACEHOLDER, // Avoid password disclosure
'database' => Environment::getEnv('SS_DATABASE_NAME') ?: 'SS_mysite',
'path' => Environment::getEnv('SS_DATABASE_PATH')
?: Environment::getEnv('SS_SQLITE_DATABASE_PATH') // sqlite compat
?: null,
'key' => Environment::getEnv('SS_DATABASE_KEY')
?: Environment::getEnv('SS_SQLITE_DATABASE_KEY') // sqlite compat
?: null,
];
}
@ -55,17 +68,26 @@ class InstallConfig
* Get admin config from the environment
*
* @param array $request
* @param bool $realPassword Set to true to get the real password. If false, any non-posted
* password will be redacted as '********'. Note: Posted passwords are considered disclosed and
* never redacted.
* @return array
*/
public function getAdminConfig($request)
public function getAdminConfig($request, $realPassword = true)
{
if (isset($request['admin'])) {
$config = $request['admin'];
if (isset($config['password']) && $config['password'] === Installer::PASSWORD_PLACEHOLDER) {
$config['password'] = Environment::getEnv('SS_DEFAULT_ADMIN_PASSWORD') ?: '';
}
return $request['admin'];
}
return [
'username' => Environment::getEnv('SS_DEFAULT_ADMIN_USERNAME') ?: 'admin',
'password' => Environment::getEnv('SS_DEFAULT_ADMIN_PASSWORD') ?: '',
'password' => $realPassword
? (Environment::getEnv('SS_DEFAULT_ADMIN_PASSWORD') ?: '')
: Installer::PASSWORD_PLACEHOLDER, // Avoid password disclosure
];
}

View File

@ -20,6 +20,11 @@ use SilverStripe\Security\Security;
*/
class Installer extends InstallRequirements
{
/**
* value='' attribute placeholder for password fields
*/
const PASSWORD_PLACEHOLDER = '********';
protected function installHeader()
{
?>

View File

@ -123,14 +123,15 @@
echo $checked ? '<div class="dbfields">' : '<div class="dbfields" style="display: none;">';
if(isset($details['fields'])) foreach($details['fields'] as $fieldName => $fieldSpec) {
$fieldTitle = $fieldSpec['title'];
$fieldType = ($fieldName == 'password') ? 'password' : 'text';
// values
$defaultValue = (isset($fieldSpec['default'])) ? $fieldSpec['default'] : null;
if($usingEnv && isset($fieldSpec['envVar']) && $envVar = getenv($fieldSpec['envVar'])) {
$value = $envVar;
} else {
$value = (isset($databaseConfig[$fieldName]) && $databaseConfig['type'] == $class) ? $databaseConfig[$fieldName] : $defaultValue;
}
$fieldType = ($fieldName === 'password') ? 'password' : 'text';
// Get display value
if (isset($databaseConfig[$fieldName]) && $databaseConfig['type'] == $class) {
$value = $databaseConfig[$fieldName];
} elseif (isset($fieldSpec['default'])) {
$value = $fieldSpec['default'];
} else {
$value = null;
}
// attributes
$attrs = array(

View File

@ -56,8 +56,8 @@ foreach ($databaseClasses as $class => $details) {
// Build config from config / environment / request
$config = new InstallConfig();
$databaseConfig = $config->getDatabaseConfig($_REQUEST, $databaseClasses);
$adminConfig = $config->getAdminConfig($_REQUEST);
$databaseConfig = $config->getDatabaseConfig($_REQUEST, $databaseClasses, true);
$adminConfig = $config->getAdminConfig($_REQUEST, true);
$alreadyInstalled = $config->alreadyInstalled();
$silverstripe_version = $config->getFrameworkVersion();
$sendStats = $config->canSendStats($_REQUEST);
@ -107,22 +107,6 @@ if ($installFromCli && ($req->hasErrors() || $dbReq->hasErrors())) {
// Path to client resources (copied through silverstripe/vendor-plugin)
$clientPath = 'resources/silverstripe/framework/src/Dev/Install/client';
// config-form.html vars (placeholder to prevent deletion)
[
$theme,
$clientPath,
$adminConfig,
$usingEnv,
$silverstripe_version,
$locale,
$locales,
$webserverConfigFile,
$hasErrorOtherThanDatabase,
$hasOnlyWarnings, // If warnings but not errors
$phpIniLocation
];
// If already installed, ensure the user clicked "reinstall"
$expectedArg = $alreadyInstalled ? 'reinstall' : 'go';
if ((isset($_REQUEST[$expectedArg]) || $installFromCli)
@ -142,7 +126,27 @@ if ((isset($_REQUEST[$expectedArg]) || $installFromCli)
'admin' => $adminConfig,
'stats' => $sendStats,
]);
// Show the config form
} else {
include(__DIR__ . '/config-form.html');
return;
}
// Sanitise config prior to rendering config-form.html
$databaseConfig = $config->getDatabaseConfig($_REQUEST, $databaseClasses, false);
$adminConfig = $config->getAdminConfig($_REQUEST, false);
// config-form.html vars (placeholder to prevent deletion)
[
$theme,
$clientPath,
$adminConfig,
$databaseConfig,
$usingEnv,
$silverstripe_version,
$locale,
$locales,
$webserverConfigFile,
$hasErrorOtherThanDatabase,
$hasOnlyWarnings, // If warnings but not errors
$phpIniLocation,
];
include(__DIR__ . '/config-form.html');

View File

@ -4,6 +4,7 @@ namespace SilverStripe\Forms\GridField;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Config\Config;
use SilverStripe\ORM\DataObject;
/**
@ -11,7 +12,6 @@ use SilverStripe\ORM\DataObject;
*/
class GridFieldExportButton implements GridField_HTMLProvider, GridField_ActionProvider, GridField_URLHandler
{
/**
* @var array Map of a property name on the exported objects, with values being the column title in the CSV file.
* Note that titles are only used when {@link $csvHasHeader} is set to TRUE.
@ -38,6 +38,15 @@ class GridFieldExportButton implements GridField_HTMLProvider, GridField_ActionP
*/
protected $targetFragment;
/**
* Set to true to disable XLS sanitisation
* [SS-2017-007] Ensure all cells with leading [@=+] have a leading tab
*
* @config
* @var bool
*/
private static $xls_export_disabled = false;
/**
* @param string $targetFragment The HTML fragment to write the button into
* @param array $exportColumns The columns to include in the export
@ -170,7 +179,7 @@ class GridFieldExportButton implements GridField_HTMLProvider, GridField_ActionP
}
//Remove GridFieldPaginator as we're going to export the entire list.
$gridField->getConfig()->removeComponentsByType('SilverStripe\\Forms\\GridField\\GridFieldPaginator');
$gridField->getConfig()->removeComponentsByType(GridFieldPaginator::class);
$items = $gridField->getManipulatedList();
@ -203,6 +212,12 @@ class GridFieldExportButton implements GridField_HTMLProvider, GridField_ActionP
}
}
// [SS-2017-007] Sanitise XLS executable column values with a leading tab
if (!Config::inst()->get(get_class($this), 'xls_export_disabled')
&& preg_match('/^[-@=+].*/', $value)
) {
$value = "\t" . $value;
}
$columnData[] = $value;
}

View File

@ -34,7 +34,7 @@ class TinyMCEConfig extends HTMLEditorConfig
'cy_GB' => 'cy',
'da_DK' => 'da',
'da_GL' => 'da',
'de_AT' => 'de',
'de_AT' => 'de_AT',
'de_BE' => 'de',
'de_CH' => 'de',
'de_DE' => 'de',
@ -56,7 +56,7 @@ class TinyMCEConfig extends HTMLEditorConfig
'es_GQ' => 'es',
'es_GT' => 'es',
'es_HN' => 'es',
'es_MX' => 'es',
'es_MX' => 'es_MX',
'es_NI' => 'es',
'es_PA' => 'es',
'es_PE' => 'es',
@ -69,11 +69,9 @@ class TinyMCEConfig extends HTMLEditorConfig
'es_AD' => 'es',
'es_BZ' => 'es',
'es_US' => 'es',
'fa_AF' => 'fa',
'fa_IR' => 'fa',
'fa_PK' => 'fa',
'fi_FI' => 'fi',
'fi_SE' => 'fi',
'fa_AF' => 'fa_IR',
'fa_IR' => 'fa_IR',
'fa_PK' => 'fa_IR',
'fr_BE' => 'fr_FR',
'fr_BF' => 'fr_FR',
'fr_BI' => 'fr_FR',
@ -117,12 +115,11 @@ class TinyMCEConfig extends HTMLEditorConfig
'fr_YT' => 'fr_FR',
'fr_GB' => 'fr_FR',
'fr_US' => 'fr_FR',
'he_IL' => 'he',
'hu_HU' => 'hu',
'hu_AT' => 'hu',
'hu_RO' => 'hu',
'hu_RS' => 'hu',
'is_IS' => 'is',
'he_IL' => 'he_IL',
'hu_HU' => 'hu_HU',
'hu_AT' => 'hu_HU',
'hu_RO' => 'hu_HU',
'hu_RS' => 'hu_HU',
'it_CH' => 'it',
'it_IT' => 'it',
'it_SM' => 'it',
@ -131,28 +128,26 @@ class TinyMCEConfig extends HTMLEditorConfig
'it_US' => 'it',
'it_VA' => 'it',
'ja_JP' => 'ja',
'ko_KP' => 'ko',
'ko_KR' => 'ko',
'ko_CN' => 'ko',
'mi_NZ' => 'mi_NZ',
'nb_NO' => 'nb',
'nb_SJ' => 'nb',
'ko_KP' => 'ko_KR',
'ko_KR' => 'ko_KR',
'ko_CN' => 'ko_KR',
'nb_NO' => 'nb_NO',
'nb_SJ' => 'nb_NO',
'nl_AN' => 'nl',
'nl_AW' => 'nl',
'nl_BE' => 'nl',
'nl_NL' => 'nl',
'nl_SR' => 'nl',
'nn_NO' => 'nn',
'pl_PL' => 'pl',
'pl_UA' => 'pl',
'pt_AO' => 'pt',
'pt_BR' => 'pt',
'pt_CV' => 'pt',
'pt_GW' => 'pt',
'pt_MZ' => 'pt',
'pt_PT' => 'pt',
'pt_ST' => 'pt',
'pt_TL' => 'pt',
'pt_AO' => 'pt_PT',
'pt_BR' => 'pt_BR',
'pt_CV' => 'pt_PT',
'pt_GW' => 'pt_PT',
'pt_MZ' => 'pt_PT',
'pt_PT' => 'pt_PT',
'pt_ST' => 'pt_PT',
'pt_TL' => 'pt_PT',
'ro_MD' => 'ro',
'ro_RO' => 'ro',
'ro_RS' => 'ro',
@ -162,31 +157,26 @@ class TinyMCEConfig extends HTMLEditorConfig
'ru_RU' => 'ru',
'ru_SJ' => 'ru',
'ru_UA' => 'ru',
'si_LK' => 'si',
'sk_SK' => 'sk',
'sk_RS' => 'sk',
'sq_AL' => 'sq',
'sr_BA' => 'sr',
'sr_ME' => 'sr',
'sr_RS' => 'sr',
'sv_FI' => 'sv',
'sv_SE' => 'sv',
'sv_FI' => 'sv_SE',
'sv_SE' => 'sv_SE',
'tr_CY' => 'tr',
'tr_TR' => 'tr',
'tr_TR' => 'tr_TR',
'tr_DE' => 'tr',
'tr_MK' => 'tr',
'uk_UA' => 'uk',
'vi_VN' => 'vi',
'vi_US' => 'vi',
'zh_CN' => 'zh-cn',
'zh_HK' => 'zh-cn',
'zh_MO' => 'zh-cn',
'zh_SG' => 'zh-cn',
'zh_TW' => 'zh-tw',
'zh_ID' => 'zh-cn',
'zh_MY' => 'zh-cn',
'zh_TH' => 'zh-cn',
'zh_US' => 'zn-cn',
'uk_UA' => 'uk_UA',
'vi_VN' => 'vi_VN',
'vi_US' => 'vi_VN',
'zh_CN' => 'zh_CN',
'zh_HK' => 'zh_CN',
'zh_MO' => 'zh_CN',
'zh_SG' => 'zh_CN',
'zh_TW' => 'zh_TW',
'zh_ID' => 'zh_CN',
'zh_MY' => 'zh_CN',
'zh_TH' => 'zh_CN',
'zh_US' => 'zh_CN',
];
/**

View File

@ -2,6 +2,8 @@
namespace SilverStripe\ORM\Connect;
use SilverStripe\Assets\File;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Convert;
use SilverStripe\ORM\PaginatedList;
@ -144,7 +146,7 @@ class MySQLDatabase extends Database
* @param bool $booleanSearch
* @param string $alternativeFileFilter
* @param bool $invertedMatch
* @return \SilverStripe\ORM\PaginatedList
* @return PaginatedList
* @throws Exception
*/
public function searchEngine(
@ -158,10 +160,8 @@ class MySQLDatabase extends Database
$alternativeFileFilter = "",
$invertedMatch = false
) {
$pageClass = 'SilverStripe\\CMS\\Model\\SiteTree';
$fileClass = 'SilverStripe\\Assets\\File';
$pageTable = DataObject::getSchema()->tableName($pageClass);
$fileTable = DataObject::getSchema()->tableName($fileClass);
$pageClass = SiteTree::class;
$fileClass = File::class;
if (!class_exists($pageClass)) {
throw new Exception('MySQLDatabase->searchEngine() requires "SiteTree" class');
}
@ -194,12 +194,13 @@ class MySQLDatabase extends Database
// File.ShowInSearch was added later, keep the database driver backwards compatible
// by checking for its existence first
$fileTable = DataObject::getSchema()->tableName($fileClass);
$fields = $this->getSchemaManager()->fieldList($fileTable);
if (array_key_exists('ShowInSearch', $fields)) {
$extraFilters[$fileClass] .= " AND ShowInSearch <> 0";
}
$limit = $start . ", " . (int) $pageLength;
$limit = (int)$start . ", " . (int)$pageLength;
$notMatch = $invertedMatch
? "NOT "
@ -257,7 +258,6 @@ class MySQLDatabase extends Database
$queryParameters = array();
$totalCount = 0;
foreach ($lists as $class => $list) {
$table = DataObject::getSchema()->tableName($class);
/** @var SQLSelect $query */
$query = $list->dataQuery()->query();

View File

@ -2,35 +2,36 @@
namespace SilverStripe\ORM;
use BadMethodCallException;
use Exception;
use InvalidArgumentException;
use LogicException;
use SilverStripe\Control\HTTP;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Resettable;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Dev\Debug;
use SilverStripe\Control\HTTP;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\FormField;
use SilverStripe\Forms\FormScaffolder;
use SilverStripe\i18n\i18n;
use SilverStripe\i18n\i18nEntityProvider;
use SilverStripe\ORM\Connect\MySQLSchemaManager;
use SilverStripe\ORM\Filters\SearchFilter;
use SilverStripe\ORM\Search\SearchContext;
use SilverStripe\ORM\Queries\SQLInsert;
use SilverStripe\ORM\Queries\SQLDelete;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\FieldType\DBComposite;
use SilverStripe\ORM\FieldType\DBClassName;
use SilverStripe\ORM\FieldType\DBComposite;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\Filters\SearchFilter;
use SilverStripe\ORM\Queries\SQLDelete;
use SilverStripe\ORM\Queries\SQLInsert;
use SilverStripe\ORM\Search\SearchContext;
use SilverStripe\Security\Member;
use SilverStripe\Security\Permission;
use SilverStripe\Security\Security;
use SilverStripe\View\SSViewer;
use SilverStripe\View\ViewableData;
use LogicException;
use InvalidArgumentException;
use BadMethodCallException;
use Exception;
use stdClass;
/**
@ -2154,6 +2155,11 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
return $untabbedFields;
}
public function getViewerTemplates($suffix = '')
{
return SSViewer::get_templates_by_class(static::class, $suffix, $this->baseClass());
}
/**
* Gets the value of a field.
* Called by {@link __get()} and any getFieldName() methods you might create.

View File

@ -138,11 +138,11 @@ class DataObjectSchema
*/
public function baseDataClass($class)
{
$class = ClassInfo::class_name($class);
$current = $class;
while ($next = get_parent_class($current)) {
if ($next === DataObject::class) {
return $current;
// Only use ClassInfo::class_name() to format the class if we've not used get_parent_class()
return ($current === $class) ? ClassInfo::class_name($current) : $current;
}
$current = $next;
}
@ -201,6 +201,11 @@ class DataObjectSchema
$db = [];
$classes = $uninherited ? [$class] : ClassInfo::ancestry($class);
foreach ($classes as $tableClass) {
// Skip irrelevant parent classes
if (!is_subclass_of($tableClass, DataObject::class)) {
continue;
}
// Find all fields on this class
$fields = $this->databaseFields($tableClass, false);
// Merge with composite fields
@ -394,6 +399,10 @@ class DataObjectSchema
*/
public function classHasTable($class)
{
if (!is_subclass_of($class, DataObject::class)) {
return false;
}
$fields = $this->databaseFields($class, false);
return !empty($fields);
}

View File

@ -87,7 +87,7 @@ class PaginatedList extends ListDecorator
*/
public function setPageLength($length)
{
$this->pageLength = $length;
$this->pageLength = (int)$length;
return $this;
}
@ -99,7 +99,7 @@ class PaginatedList extends ListDecorator
*/
public function setCurrentPage($page)
{
$this->pageStart = ($page - 1) * $this->getPageLength();
$this->pageStart = ((int)$page - 1) * $this->getPageLength();
return $this;
}
@ -134,7 +134,7 @@ class PaginatedList extends ListDecorator
*/
public function setPageStart($start)
{
$this->pageStart = $start;
$this->pageStart = (int)$start;
return $this;
}
@ -161,7 +161,7 @@ class PaginatedList extends ListDecorator
*/
public function setTotalItems($items)
{
$this->totalItems = $items;
$this->totalItems = (int)$items;
return $this;
}

View File

@ -2,6 +2,7 @@
namespace SilverStripe\Security;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DataObject;
/**
@ -14,11 +15,11 @@ use SilverStripe\ORM\DataObject;
* complies with your privacy standards. We're logging
* username and IP.
*
* @property string Email Email address used for login attempt
* @property string Status Status of the login attempt, either 'Success' or 'Failure'
* @property string IP IP address of user attempting to login
*
* @property int MemberID ID of the Member, only if Member with Email exists
* @property string $Email Email address used for login attempt. @deprecated 3.0...5.0
* @property string $EmailHashed sha1 hashed Email address used for login attempt
* @property string $Status Status of the login attempt, either 'Success' or 'Failure'
* @property string $IP IP address of user attempting to login
* @property int $MemberID ID of the Member, only if Member with Email exists
*
* @method Member Member() Member object of the user trying to log in, only if Member with Email exists
*/
@ -35,7 +36,8 @@ class LoginAttempt extends DataObject
const FAILURE = 'Failure';
private static $db = array(
'Email' => 'Varchar(255)',
'Email' => 'Varchar(255)', // Remove in 5.0
'EmailHashed' => 'Varchar(255)',
'Status' => "Enum('Success,Failure')",
'IP' => 'Varchar(255)',
);
@ -55,9 +57,37 @@ class LoginAttempt extends DataObject
{
$labels = parent::fieldLabels($includerelations);
$labels['Email'] = _t(__CLASS__.'.Email', 'Email Address');
$labels['EmailHashed'] = _t(__CLASS__.'.EmailHashed', 'Email Address (hashed)');
$labels['Status'] = _t(__CLASS__.'.Status', 'Status');
$labels['IP'] = _t(__CLASS__.'.IP', 'IP Address');
return $labels;
}
/**
* Set email used for this attempt
*
* @param string $email
* @return $this
*/
public function setEmail($email)
{
// Store hashed email only
$this->EmailHashed = sha1($email);
return $this;
}
/**
* Get all login attempts for the given email address
*
* @param string $email
* @return DataList|LoginAttempt[]
*/
public static function getByEmail($email)
{
return static::get()->filterAny(array(
'Email' => $email,
'EmailHashed' => sha1($email),
));
}
}

View File

@ -384,8 +384,7 @@ class Member extends DataObject
}
$idField = static::config()->get('unique_identifier_field');
$attempts = LoginAttempt::get()
->filter('Email', $this->{$idField})
$attempts = LoginAttempt::getByEmail($this->{$idField})
->sort('Created', 'DESC')
->limit($maxAttempts);

View File

@ -2,25 +2,26 @@
namespace SilverStripe\View;
use ArrayIterator;
use Exception;
use InvalidArgumentException;
use IteratorAggregate;
use LogicException;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Manifest\ModuleResourceLoader;
use SilverStripe\Dev\Debug;
use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\ArrayLib;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\Debug;
use IteratorAggregate;
use LogicException;
use InvalidArgumentException;
use SilverStripe\View\SSViewer;
use UnexpectedValueException;
use ArrayIterator;
/**
* A ViewableData object is any object that can be rendered into a template/view.
@ -578,6 +579,17 @@ class ViewableData implements IteratorAggregate
// UTILITY METHODS -------------------------------------------------------------------------------------------------
/**
* Find appropriate templates for SSViewer to use to render this object
*
* @param string $suffix
* @return array
*/
public function getViewerTemplates($suffix = '')
{
return SSViewer::get_templates_by_class(static::class, $suffix, self::class);
}
/**
* When rendering some objects it is necessary to iterate over the object being rendered, to do this, you need
* access to itself.

View File

@ -29,31 +29,44 @@ class CSVParserTest extends SapphireTest
$firstNames = $birthdays = $biographies = $registered = array();
foreach ($csv as $record) {
/* Each row in the CSV file will be keyed with the header row */
$this->assertEquals(array('FirstName','Biography','Birthday','IsRegistered'), array_keys($record));
$this->assertEquals(
['FirstName','Biography','Birthday','IsRegistered'],
array_keys($record)
);
$firstNames[] = $record['FirstName'];
$biographies[] = $record['Biography'];
$birthdays[] = $record['Birthday'];
$registered[] = $record['IsRegistered'];
}
$this->assertEquals(array('John','Jane','Jamie','Järg'), $firstNames);
$this->assertEquals(
['John','Jane','Jamie','Järg','Jacob'],
$firstNames
);
$this->assertEquals(
array(
"He's a good guy",
"She is awesome." . PHP_EOL
. "So awesome that she gets multiple rows and \"escaped\" strings in her biography",
"Pretty old, with an escaped comma",
"Unicode FTW"),
[
"He's a good guy",
"She is awesome."
. PHP_EOL
. "So awesome that she gets multiple rows and \"escaped\" strings in her biography",
"Pretty old, with an escaped comma",
"Unicode FTW",
"Likes leading tabs in his biography",
],
$biographies
);
$this->assertEquals([
"1988-01-31",
"1982-01-31",
"1882-01-31",
"1982-06-30"
"1982-06-30",
"2000-04-30",
], $birthdays);
$this->assertEquals(array('1', '0', '1', '1'), $registered);
$this->assertEquals(
['1', '0', '1', '1', '0'],
$registered
);
}
public function testParsingWithHeadersAndColumnMap()
@ -62,41 +75,43 @@ class CSVParserTest extends SapphireTest
$csv = new CSVParser($this->csvPath . 'PlayersWithHeader.csv');
/* We can set up column remapping. The keys are case-insensitive. */
$csv->mapColumns(
array(
$csv->mapColumns([
'FirstName' => '__fn',
'bIoGrApHy' => '__BG',
)
);
]);
$firstNames = $birthdays = $biographies = $registered = array();
foreach ($csv as $record) {
/* Each row in the CSV file will be keyed with the renamed columns. Any unmapped column names will be
* left as-is. */
$this->assertEquals(array('__fn','__BG','Birthday','IsRegistered'), array_keys($record));
$this->assertEquals(['__fn','__BG','Birthday','IsRegistered'], array_keys($record));
$firstNames[] = $record['__fn'];
$biographies[] = $record['__BG'];
$birthdays[] = $record['Birthday'];
$registered[] = $record['IsRegistered'];
}
$this->assertEquals(array('John','Jane','Jamie','Järg'), $firstNames);
$this->assertEquals(['John','Jane','Jamie','Järg','Jacob'], $firstNames);
$this->assertEquals(
array(
"He's a good guy",
"She is awesome."
. PHP_EOL . "So awesome that she gets multiple rows and \"escaped\" strings in her biography",
"Pretty old, with an escaped comma",
"Unicode FTW"),
[
"He's a good guy",
"She is awesome."
. PHP_EOL
. "So awesome that she gets multiple rows and \"escaped\" strings in her biography",
"Pretty old, with an escaped comma",
"Unicode FTW",
"Likes leading tabs in his biography",
],
$biographies
);
$this->assertEquals([
"1988-01-31",
"1982-01-31",
"1882-01-31",
"1982-06-30"
"1982-06-30",
"2000-04-30",
], $birthdays);
$this->assertEquals(array('1', '0', '1', '1'), $registered);
$this->assertEquals(array('1', '0', '1', '1', '0'), $registered);
}
public function testParsingWithExplicitHeaderRow()
@ -117,15 +132,18 @@ class CSVParserTest extends SapphireTest
}
/* And the first row will be returned in the data */
$this->assertEquals(array('FirstName','John','Jane','Jamie','Järg'), $firstNames);
$this->assertEquals(['FirstName','John','Jane','Jamie','Järg','Jacob'], $firstNames);
$this->assertEquals(
array(
'Biography',
"He's a good guy",
"She is awesome." . PHP_EOL
. "So awesome that she gets multiple rows and \"escaped\" strings in her biography",
"Pretty old, with an escaped comma",
"Unicode FTW"),
[
'Biography',
"He's a good guy",
"She is awesome."
. PHP_EOL
. "So awesome that she gets multiple rows and \"escaped\" strings in her biography",
"Pretty old, with an escaped comma",
"Unicode FTW",
"Likes leading tabs in his biography"
],
$biographies
);
$this->assertEquals([
@ -133,8 +151,9 @@ class CSVParserTest extends SapphireTest
"1988-01-31",
"1982-01-31",
"1882-01-31",
"1982-06-30"
"1982-06-30",
"2000-04-30",
], $birthdays);
$this->assertEquals(array('IsRegistered', '1', '0', '1', '1'), $registered);
$this->assertEquals(['IsRegistered', '1', '0', '1', '1', '0'], $registered);
}
}

View File

@ -50,7 +50,7 @@ class CsvBulkLoaderTest extends SapphireTest
$results = $loader->load($filepath);
// Test that right amount of columns was imported
$this->assertEquals(4, $results->Count(), 'Test correct count of imported data');
$this->assertEquals(5, $results->Count(), 'Test correct count of imported data');
// Test that columns were correctly imported
$obj = DataObject::get_one(
@ -76,7 +76,7 @@ class CsvBulkLoaderTest extends SapphireTest
$filepath = $this->csvPath . 'PlayersWithHeader.csv';
$loader->deleteExistingRecords = true;
$results1 = $loader->load($filepath);
$this->assertEquals(4, $results1->Count(), 'Test correct count of imported data on first load');
$this->assertEquals(5, $results1->Count(), 'Test correct count of imported data on first load');
//delete existing data before doing second CSV import
$results2 = $loader->load($filepath);
@ -84,7 +84,7 @@ class CsvBulkLoaderTest extends SapphireTest
$resultDataObject = DataObject::get(Player::class);
$this->assertEquals(
4,
5,
$resultDataObject->count(),
'Test if existing data is deleted before new data is added'
);

View File

@ -4,3 +4,4 @@
So awesome that she gets multiple rows and \"escaped\" strings in her biography","1982-01-31","0"
"Jamie","Pretty old\, with an escaped comma","1882-01-31","1"
"Järg","Unicode FTW","1982-06-30","1"
"Jacob"," Likes leading tabs in his biography","2000-04-30","0"

Can't render this file because it contains an unexpected character in line 4 and column 45.

View File

@ -12,22 +12,27 @@ use SilverStripe\Forms\GridField\GridFieldConfig;
use SilverStripe\Forms\GridField\GridFieldExportButton;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldPaginator;
use SilverStripe\ORM\FieldType\DBField;
class GridFieldExportButtonTest extends SapphireTest
{
/**
* @var DataList
*/
protected $list;
/**
* @var GridField
*/
protected $gridField;
protected $form;
protected static $fixture_file = 'GridFieldExportButtonTest.yml';
protected static $extra_dataobjects = array(
protected static $extra_dataobjects = [
Team::class,
NoView::class,
);
];
protected function setUp()
{
@ -44,7 +49,7 @@ class GridFieldExportButtonTest extends SapphireTest
$list = new DataList(NoView::class);
$button = new GridFieldExportButton();
$button->setExportColumns(array('Name' => 'My Name'));
$button->setExportColumns(['Name' => 'My Name']);
$config = GridFieldConfig::create()->addComponent(new GridFieldExportButton());
$gridField = new GridField('testfield', 'testfield', $list, $config);
@ -58,7 +63,7 @@ class GridFieldExportButtonTest extends SapphireTest
public function testGenerateFileDataBasicFields()
{
$button = new GridFieldExportButton();
$button->setExportColumns(array('Name' => 'My Name'));
$button->setExportColumns(['Name' => 'My Name']);
$this->assertEquals(
'"My Name"'."\n".
@ -68,17 +73,32 @@ class GridFieldExportButtonTest extends SapphireTest
);
}
public function testXLSSanitisation()
{
// Create risky object
$object = new Team();
$object->Name = '=SUM(1, 2)';
$object->write();
// Export
$button = new GridFieldExportButton();
$button->setExportColumns(['Name' => 'My Name']);
$this->assertEquals(
"\"My Name\"\n\"\t=SUM(1, 2)\"\nTest\nTest2\n",
$button->generateExportFileData($this->gridField)
);
}
public function testGenerateFileDataAnonymousFunctionField()
{
$button = new GridFieldExportButton();
$button->setExportColumns(
array(
$button->setExportColumns([
'Name' => 'Name',
'City' => function ($obj) {
'City' => function (DBField $obj) {
return $obj->getValue() . ' city';
}
)
);
]);
$this->assertEquals(
'Name,City'."\n".
@ -91,12 +111,10 @@ class GridFieldExportButtonTest extends SapphireTest
public function testBuiltInFunctionNameCanBeUsedAsHeader()
{
$button = new GridFieldExportButton();
$button->setExportColumns(
array(
$button->setExportColumns([
'Name' => 'Name',
'City' => 'strtolower'
)
);
'City' => 'strtolower',
]);
$this->assertEquals(
'Name,strtolower'."\n".
@ -109,12 +127,10 @@ class GridFieldExportButtonTest extends SapphireTest
public function testNoCsvHeaders()
{
$button = new GridFieldExportButton();
$button->setExportColumns(
array(
$button->setExportColumns([
'Name' => 'Name',
'City' => 'City'
)
);
'City' => 'City',
]);
$button->setCsvHasHeader(false);
$this->assertEquals(
@ -132,9 +148,7 @@ class GridFieldExportButtonTest extends SapphireTest
//Create an ArrayList 1 greater the Paginator's default 15 rows
$arrayList = new ArrayList();
for ($i = 1; $i <= 16; $i++) {
$dataobject = new DataObject(
array ( 'ID' => $i )
);
$dataobject = new DataObject(['ID' => $i]);
$arrayList->add($dataobject);
}
$this->gridField->setList($arrayList);
@ -164,11 +178,9 @@ class GridFieldExportButtonTest extends SapphireTest
public function testZeroValue()
{
$button = new GridFieldExportButton();
$button->setExportColumns(
array(
$button->setExportColumns([
'RugbyTeamNumber' => 'Rugby Team Number'
)
);
]);
$this->assertEquals(
"\"Rugby Team Number\"\n2\n0\n",

View File

@ -0,0 +1,40 @@
<?php
namespace SilverStripe\Forms\Tests\HTMLEditor;
use SilverStripe\Control\Director;
use SilverStripe\Core\Manifest\ModuleResourceLoader;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\HTMLEditor\TinyMCEConfig;
class TinyMCEConfigTest extends SapphireTest
{
/**
* Ensure that all TinyMCEConfig.tinymce_lang are valid
*/
public function testLanguagesValid()
{
$configDir = TinyMCEConfig::config()->get('base_dir');
if (!$configDir) {
$this->markTestSkipped("Test skipped without TinyMCE resources folder being installed");
}
$langs = Director::baseFolder().'/'.ModuleResourceLoader::resourcePath($configDir).'/langs';
// Test all langs exist as real files
foreach (TinyMCEConfig::config()->get('tinymce_lang') as $locale => $resource) {
// Check valid
$this->assertFileExists(
"{$langs}/{$resource}.js",
"Locale code {$locale} maps to {$resource}.js which exists"
);
// Check we don't simplify to locale when a specific version exists
if (strpos($resource, '_') === false) {
$this->assertFileNotExists(
"{$langs}/{$locale}.js",
"Locale code {$locale} doesn't map to simple {$resource}.js when a better {$locale}.js is available"
);
}
}
}
}

View File

@ -1342,10 +1342,7 @@ class DataObjectTest extends SapphireTest
$this->assertFalse($schema->classHasTable(DataObject::class));
$this->assertFalse($schema->classHasTable(ViewableData::class));
// Invalid class
$this->expectException(ReflectionException::class);
$this->expectExceptionMessage('Class ThisIsntADataObject does not exist');
/* Invalid class name */
$this->assertFalse($schema->classHasTable("ThisIsntADataObject"));
}

View File

@ -265,7 +265,8 @@ class MemberAuthenticatorTest extends SapphireTest
$this->assertNull($member);
$this->assertCount(1, LoginAttempt::get());
$attempt = LoginAttempt::get()->first();
$this->assertEquals($email, $attempt->Email);
$this->assertEmpty($attempt->Email); // Doesn't store potentially sensitive data
$this->assertEquals(sha1($email), $attempt->EmailHashed);
$this->assertEquals(LoginAttempt::FAILURE, $attempt->Status);
}

View File

@ -3,7 +3,6 @@
namespace SilverStripe\Security\Tests;
use Page;
use PageController;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPRequest;
@ -615,34 +614,21 @@ class SecurityTest extends FunctionalTest
/* UNSUCCESSFUL ATTEMPTS WITH WRONG PASSWORD FOR EXISTING USER ARE LOGGED */
$this->doTestLoginForm('testuser@example.com', 'wrongpassword');
/** @var LoginAttempt $attempt */
$attempt = DataObject::get_one(
LoginAttempt::class,
array(
'"LoginAttempt"."Email"' => 'testuser@example.com'
)
);
$attempt = LoginAttempt::getByEmail('testuser@example.com')->first();
$this->assertInstanceOf(LoginAttempt::class, $attempt);
$member = DataObject::get_one(
Member::class,
array(
'"Member"."Email"' => 'testuser@example.com'
)
);
$member = Member::get()->filter('Email', 'testuser@example.com')->first();
$this->assertEquals($attempt->Status, 'Failure');
$this->assertEquals($attempt->Email, 'testuser@example.com');
$this->assertEmpty($attempt->Email); // Doesn't store potentially sensitive data
$this->assertEquals($attempt->EmailHashed, sha1('testuser@example.com'));
$this->assertEquals($attempt->Member()->toMap(), $member->toMap());
/* UNSUCCESSFUL ATTEMPTS WITH NONEXISTING USER ARE LOGGED */
$this->doTestLoginForm('wronguser@silverstripe.com', 'wrongpassword');
$attempt = DataObject::get_one(
LoginAttempt::class,
array(
'"LoginAttempt"."Email"' => 'wronguser@silverstripe.com'
)
);
$this->assertTrue(is_object($attempt));
$attempt = LoginAttempt::getByEmail('wronguser@silverstripe.com')->first();
$this->assertInstanceOf(LoginAttempt::class, $attempt);
$this->assertEquals($attempt->Status, 'Failure');
$this->assertEquals($attempt->Email, 'wronguser@silverstripe.com');
$this->assertEmpty($attempt->Email); // Doesn't store potentially sensitive data
$this->assertEquals($attempt->EmailHashed, sha1('wronguser@silverstripe.com'));
$this->assertNotEmpty($this->getValidationResult()->getMessages(), 'An invalid email returns a message.');
}
@ -653,22 +639,12 @@ class SecurityTest extends FunctionalTest
/* SUCCESSFUL ATTEMPTS ARE LOGGED */
$this->doTestLoginForm('testuser@example.com', '1nitialPassword');
/** @var LoginAttempt $attempt */
$attempt = DataObject::get_one(
LoginAttempt::class,
array(
'"LoginAttempt"."Email"' => 'testuser@example.com'
)
);
/** @var Member $member */
$member = DataObject::get_one(
Member::class,
array(
'"Member"."Email"' => 'testuser@example.com'
)
);
$this->assertTrue(is_object($attempt));
$attempt = LoginAttempt::getByEmail('testuser@example.com')->first();
$member = Member::get()->filter('Email', 'testuser@example.com')->first();
$this->assertInstanceOf(LoginAttempt::class, $attempt);
$this->assertEquals($attempt->Status, 'Success');
$this->assertEquals($attempt->Email, 'testuser@example.com');
$this->assertEmpty($attempt->Email); // Doesn't store potentially sensitive data
$this->assertEquals($attempt->EmailHashed, sha1('testuser@example.com'));
$this->assertEquals($attempt->Member()->toMap(), $member->toMap());
}
@ -725,6 +701,7 @@ class SecurityTest extends FunctionalTest
// Ensure page shares the same controller as security
$securityClass = Config::inst()->get(Security::class, 'page_class');
/** @var Page $securityPage */
$securityPage = new $securityClass();
$this->assertInstanceOf($securityPage->getControllerName(), $result);
$this->assertEquals($request, $result->getRequest());