mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge branch '5.2' into 5
This commit is contained in:
commit
cdde36bb9a
61
lang/de.yml
61
lang/de.yml
@ -27,9 +27,22 @@ de:
|
|||||||
SilverStripe\Control\RequestProcessor:
|
SilverStripe\Control\RequestProcessor:
|
||||||
INVALID_REQUEST: 'Ungültige Anfrage'
|
INVALID_REQUEST: 'Ungültige Anfrage'
|
||||||
REQUEST_ABORTED: 'Anfrage abgebrochen'
|
REQUEST_ABORTED: 'Anfrage abgebrochen'
|
||||||
|
SilverStripe\Dev\DevBuildController:
|
||||||
|
CAN_DEV_BUILD_DESCRIPTION: 'Darf /dev/build ausführen'
|
||||||
|
CAN_DEV_BUILD_HELP: 'Darf den Build-Befehl ausführen (/dev/build).'
|
||||||
|
SilverStripe\Dev\DevConfigController:
|
||||||
|
CAN_DEV_CONFIG_DESCRIPTION: 'Darf /dev/config anzeigen'
|
||||||
|
CAN_DEV_CONFIG_HELP: 'Darf die gesamte Anwendungskonfiguration einsehen (/dev/config).'
|
||||||
SilverStripe\Dev\DevConfirmationController:
|
SilverStripe\Dev\DevConfirmationController:
|
||||||
INFO_DESCRIPTION: 'Bestätige potenziell gefährliche Aktion'
|
INFO_DESCRIPTION: 'Bestätige potenziell gefährliche Aktion'
|
||||||
INFO_TITLE: Sicherheitsbestätigung
|
INFO_TITLE: Sicherheitsbestätigung
|
||||||
|
SilverStripe\Dev\DevelopmentAdmin:
|
||||||
|
ALL_DEV_ADMIN_DESCRIPTION: 'Darf alle /dev-Endpunkte anzeigen und ausführen'
|
||||||
|
ALL_DEV_ADMIN_HELP: 'Darf alle /dev-Endpunkte anzeigen und ausführen'
|
||||||
|
PERMISSIONS_CATEGORY: 'Dev Berechtigungen'
|
||||||
|
SilverStripe\Dev\TaskRunner:
|
||||||
|
BUILDTASK_CAN_RUN_DESCRIPTION: 'Darf alle /dev/tasks anzeigen und ausführen'
|
||||||
|
BUILDTASK_CAN_RUN_HELP: 'Darf alle /dev/tasks anzeigen und ausführen (/dev/tasks). Dies kann noch durch individuelle Berechtigungen für die Tasks überschrieben werden'
|
||||||
SilverStripe\Forms\CheckboxField:
|
SilverStripe\Forms\CheckboxField:
|
||||||
NOANSWER: Nein
|
NOANSWER: Nein
|
||||||
YESANSWER: Ja
|
YESANSWER: Ja
|
||||||
@ -42,6 +55,7 @@ de:
|
|||||||
CURRENT_PASSWORD_MISSING: 'Bitte geben Sie Ihr derzeitiges Passwort ein.'
|
CURRENT_PASSWORD_MISSING: 'Bitte geben Sie Ihr derzeitiges Passwort ein.'
|
||||||
LOGGED_IN_ERROR: 'Sie müssen eingeloggt sein, um Ihr Passwort ändern zu können!'
|
LOGGED_IN_ERROR: 'Sie müssen eingeloggt sein, um Ihr Passwort ändern zu können!'
|
||||||
MAXIMUM: 'Passwörter dürfen maximal {max} Zeichen lang sein.'
|
MAXIMUM: 'Passwörter dürfen maximal {max} Zeichen lang sein.'
|
||||||
|
RANDOM_IF_EMPTY: 'Wenn dieses Feld leer gelassen wird, wird automatisch ein Zufallspasswort generiert.'
|
||||||
SHOWONCLICKTITLE: 'Passwort ändern'
|
SHOWONCLICKTITLE: 'Passwort ändern'
|
||||||
SilverStripe\Forms\DateField:
|
SilverStripe\Forms\DateField:
|
||||||
NOTSET: 'Nicht gesetzt'
|
NOTSET: 'Nicht gesetzt'
|
||||||
@ -103,7 +117,7 @@ de:
|
|||||||
Create: Erstellen
|
Create: Erstellen
|
||||||
Delete: Löschen
|
Delete: Löschen
|
||||||
DeletePermissionsFailure: 'Keine Berechtigungen zum löschen'
|
DeletePermissionsFailure: 'Keine Berechtigungen zum löschen'
|
||||||
Deleted: 'Gelöscht {type} {name}'
|
Deleted: 'Gelöscht {type} "{name}"'
|
||||||
Save: Speichern
|
Save: Speichern
|
||||||
Saved: '{name} {link} gespeichert'
|
Saved: '{name} {link} gespeichert'
|
||||||
SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest:
|
SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest:
|
||||||
@ -111,6 +125,8 @@ de:
|
|||||||
NEW: 'Neuen Eintrag hinzufügen'
|
NEW: 'Neuen Eintrag hinzufügen'
|
||||||
NEXT: 'Gehe zu nächstem Eintrag'
|
NEXT: 'Gehe zu nächstem Eintrag'
|
||||||
PREVIOUS: 'Gehe zu vorherigem Eintrag'
|
PREVIOUS: 'Gehe zu vorherigem Eintrag'
|
||||||
|
SAVEDUP: 'Erfolgreich gespeichert'
|
||||||
|
SAVETOASTMESSAGE: '{type} "{title}" erfolgreich gespeichert.'
|
||||||
ViewPermissionsFailure: 'Sie haben nicht die nötigen Berechtigungen um {ObjectTitle} aufzurufen.'
|
ViewPermissionsFailure: 'Sie haben nicht die nötigen Berechtigungen um {ObjectTitle} aufzurufen.'
|
||||||
SilverStripe\Forms\GridField\GridFieldEditButton:
|
SilverStripe\Forms\GridField\GridFieldEditButton:
|
||||||
EDIT: Bearbeiten
|
EDIT: Bearbeiten
|
||||||
@ -138,6 +154,10 @@ de:
|
|||||||
IsNullLabel: 'ist NULL'
|
IsNullLabel: 'ist NULL'
|
||||||
SilverStripe\Forms\NumericField:
|
SilverStripe\Forms\NumericField:
|
||||||
VALIDATION: "'{value}' ist kein numerischer Wert, nur nummerische Werte sind in diesem Feld erlaubt"
|
VALIDATION: "'{value}' ist kein numerischer Wert, nur nummerische Werte sind in diesem Feld erlaubt"
|
||||||
|
SilverStripe\Forms\SearchableDropdownTrait:
|
||||||
|
SELECT: Auswählen...
|
||||||
|
SELECT_OR_TYPE_TO_SEARCH: 'Auswählen oder tippen um zu suchen...'
|
||||||
|
TYPE_TO_SEARCH: 'Tippen um zu suchen...'
|
||||||
SilverStripe\Forms\TextField:
|
SilverStripe\Forms\TextField:
|
||||||
VALIDATEMAXLENGTH: 'Der für {name} eingegebene Wert darf nicht mehr als {maxLength} Zeichen lang sein'
|
VALIDATEMAXLENGTH: 'Der für {name} eingegebene Wert darf nicht mehr als {maxLength} Zeichen lang sein'
|
||||||
SilverStripe\Forms\TimeField:
|
SilverStripe\Forms\TimeField:
|
||||||
@ -145,11 +165,14 @@ de:
|
|||||||
SilverStripe\Forms\UrlField:
|
SilverStripe\Forms\UrlField:
|
||||||
INVALID: 'Bitte geben Sie eine gültige URL ein'
|
INVALID: 'Bitte geben Sie eine gültige URL ein'
|
||||||
SilverStripe\ORM\DataObject:
|
SilverStripe\ORM\DataObject:
|
||||||
|
GENERALSEARCH: 'Generelle Suche'
|
||||||
PLURALNAME: DatenObjekte
|
PLURALNAME: DatenObjekte
|
||||||
PLURALS:
|
PLURALS:
|
||||||
one: 'Ein DatenObjekt'
|
one: 'Ein DatenObjekt'
|
||||||
other: '{count} DatenObjekte'
|
other: '{count} DatenObjekte'
|
||||||
SINGULARNAME: DatenObjekt
|
SINGULARNAME: DatenObjekt
|
||||||
|
many_many_FileTracking: Datei-Verfolgung
|
||||||
|
many_many_LinkTracking: Link-Verfolgung
|
||||||
SilverStripe\ORM\FieldType\DBBoolean:
|
SilverStripe\ORM\FieldType\DBBoolean:
|
||||||
ANY: alle
|
ANY: alle
|
||||||
NOANSWER: Nein
|
NOANSWER: Nein
|
||||||
@ -233,7 +256,11 @@ de:
|
|||||||
RolesAddEditLink: 'Rollen hinzufügen/editieren'
|
RolesAddEditLink: 'Rollen hinzufügen/editieren'
|
||||||
SINGULARNAME: Gruppe
|
SINGULARNAME: Gruppe
|
||||||
Sort: Sortierreihenfolge
|
Sort: Sortierreihenfolge
|
||||||
|
ValidationIdentifierAlreadyExists: 'Es existiert bereits eine Gruppe ({group}) mit dem selben {identifier}'
|
||||||
|
db_AccessAllSubsites: 'Zugang zu allen Unterseiten'
|
||||||
db_Description: Beschreibung
|
db_Description: Beschreibung
|
||||||
|
db_LastSynced: 'Zuletzt aktualisiert'
|
||||||
|
db_Locked: Gesperrt
|
||||||
db_Sort: Sortierung
|
db_Sort: Sortierung
|
||||||
db_Title: Titel
|
db_Title: Titel
|
||||||
has_many_Groups: Gruppe
|
has_many_Groups: Gruppe
|
||||||
@ -241,6 +268,13 @@ de:
|
|||||||
has_one_Parent: Übergeordnet
|
has_one_Parent: Übergeordnet
|
||||||
many_many_Members: Mitglieder
|
many_many_Members: Mitglieder
|
||||||
many_many_Roles: Rollen
|
many_many_Roles: Rollen
|
||||||
|
SilverStripe\Security\InheritedPermissionsExtension:
|
||||||
|
db_CanEditType: 'Kann Typ bearbeiten'
|
||||||
|
db_CanViewType: 'Kann Typ ansehen'
|
||||||
|
many_many_EditorGroups: Bearbeitungsgruppen
|
||||||
|
many_many_EditorMembers: Bearbeitungsnutzer
|
||||||
|
many_many_ViewerGroups: Betrachtergruppen
|
||||||
|
many_many_ViewerMembers: Betrachtungsnutzer
|
||||||
SilverStripe\Security\LoginAttempt:
|
SilverStripe\Security\LoginAttempt:
|
||||||
Email: E-Mail-Adresse
|
Email: E-Mail-Adresse
|
||||||
EmailHashed: 'E-Mail-Adresse (gehashed)'
|
EmailHashed: 'E-Mail-Adresse (gehashed)'
|
||||||
@ -263,6 +297,7 @@ de:
|
|||||||
CURRENT_PASSWORD: 'Derzeitiges Passwort'
|
CURRENT_PASSWORD: 'Derzeitiges Passwort'
|
||||||
EDIT_PASSWORD: 'Neues Passwort'
|
EDIT_PASSWORD: 'Neues Passwort'
|
||||||
EMAIL: E-Mail
|
EMAIL: E-Mail
|
||||||
|
EMAIL_FAILED: 'Beim Versuch, Ihnen einen Link zum Zurücksetzen des Passworts per E-Mail zu schicken, ist ein Fehler aufgetreten.'
|
||||||
EMPTYNEWPASSWORD: 'Das neue Passwort darf nicht leer sein. Bitte versuchen Sie es erneut.'
|
EMPTYNEWPASSWORD: 'Das neue Passwort darf nicht leer sein. Bitte versuchen Sie es erneut.'
|
||||||
ENTEREMAIL: 'Bitte geben Sie eine E-Mail-Adresse ein, um einen Link zum Zurücksetzen des Passworts zu erhalten.'
|
ENTEREMAIL: 'Bitte geben Sie eine E-Mail-Adresse ein, um einen Link zum Zurücksetzen des Passworts zu erhalten.'
|
||||||
ERRORLOCKEDOUT2: 'Ihr Zugang wurde auf Grund von einer unzulässig hohen Anzahl von falschen Zugangsversuchen gesperrt. Bitte versuchen Sie es in {count} Minuten noch einmal.'
|
ERRORLOCKEDOUT2: 'Ihr Zugang wurde auf Grund von einer unzulässig hohen Anzahl von falschen Zugangsversuchen gesperrt. Bitte versuchen Sie es in {count} Minuten noch einmal.'
|
||||||
@ -281,6 +316,7 @@ de:
|
|||||||
PLURALS:
|
PLURALS:
|
||||||
one: 'Ein Mitglied'
|
one: 'Ein Mitglied'
|
||||||
other: '{count} Mitglieder'
|
other: '{count} Mitglieder'
|
||||||
|
RequiresPasswordChangeOnNextLogin: 'Erfordert Passwortänderung bei nächster Anmeldung'
|
||||||
SINGULARNAME: Benutzer
|
SINGULARNAME: Benutzer
|
||||||
SUBJECTPASSWORDCHANGED: 'Ihr Passwort wurde geändert'
|
SUBJECTPASSWORDCHANGED: 'Ihr Passwort wurde geändert'
|
||||||
SUBJECTPASSWORDRESET: 'Ihr Link zur Passwortrücksetzung'
|
SUBJECTPASSWORDRESET: 'Ihr Link zur Passwortrücksetzung'
|
||||||
@ -290,15 +326,34 @@ de:
|
|||||||
ValidationIdentifierFailed: 'Das vorhandene Mitglied #{id} mit identischer Bezeichnung kann nicht überschrieben werden ({name} = {value}))'
|
ValidationIdentifierFailed: 'Das vorhandene Mitglied #{id} mit identischer Bezeichnung kann nicht überschrieben werden ({name} = {value}))'
|
||||||
WELCOMEBACK: 'Hallo {firstname}. Schön, dass du wieder da bist'
|
WELCOMEBACK: 'Hallo {firstname}. Schön, dass du wieder da bist'
|
||||||
YOUROLDPASSWORD: 'Ihr altes Passwort'
|
YOUROLDPASSWORD: 'Ihr altes Passwort'
|
||||||
|
belongs_many_many_BlogPosts: Blogbeiträge
|
||||||
belongs_many_many_Groups: Gruppe
|
belongs_many_many_Groups: Gruppe
|
||||||
|
db_AccountResetExpired: 'Zurücksetzen des Kontos ist abgelaufen'
|
||||||
|
db_AccountResetHash: 'Hash zum zurücksetzen des Accounts'
|
||||||
|
db_AutoLoginExpired: 'Automatische Anmeldung abgelaufen'
|
||||||
|
db_AutoLoginHash: 'Hash für die automatische Anmeldung'
|
||||||
|
db_BlogProfileSummary: 'Zusammenfassung für das Blogprofil'
|
||||||
db_Email: E-Mail
|
db_Email: E-Mail
|
||||||
|
db_FailedLoginCount: 'Anzahl der fehlgeschlagenen Anmeldungen'
|
||||||
db_FirstName: Vorname
|
db_FirstName: Vorname
|
||||||
|
db_HasSkippedMFARegistration: 'Hat die MFA-Registrierung übersprungen'
|
||||||
|
db_IsExpired: 'Ist abgelaufen'
|
||||||
|
db_LastSynced: 'Zuletzt aktualisiert'
|
||||||
db_Locale: 'Interface Sprachumgebung'
|
db_Locale: 'Interface Sprachumgebung'
|
||||||
db_LockedOutUntil: 'Gesperrt bis'
|
db_LockedOutUntil: 'Gesperrt bis'
|
||||||
db_Password: Passwort
|
db_Password: Passwort
|
||||||
|
db_PasswordEncryption: Passwortverschlüsselung
|
||||||
db_PasswordExpiry: 'Ablaufdatum des Passworts'
|
db_PasswordExpiry: 'Ablaufdatum des Passworts'
|
||||||
|
db_Salt: Salz
|
||||||
db_Surname: Nachname
|
db_Surname: Nachname
|
||||||
db_URLSegment: URL-Segment
|
db_URLSegment: URL-Segment
|
||||||
|
db_Username: Nutzername
|
||||||
|
has_many_LoggedPasswords: 'Protokollierte Passwörter'
|
||||||
|
has_many_LoginSessions: Login-Sitzungen
|
||||||
|
has_many_RegisteredMFAMethods: 'Registrierte MFA-Methoden'
|
||||||
|
has_one_AFile: 'Eine Datei'
|
||||||
|
has_one_AImage: 'Ein Bild'
|
||||||
|
has_one_BlogProfileImage: 'Blogprofil Bild'
|
||||||
SilverStripe\Security\MemberAuthenticator\CMSMemberLoginForm:
|
SilverStripe\Security\MemberAuthenticator\CMSMemberLoginForm:
|
||||||
AUTHENTICATORNAME: 'CMS Benutzer Login Formular'
|
AUTHENTICATORNAME: 'CMS Benutzer Login Formular'
|
||||||
BUTTONFORGOTPASSWORD: 'Passwort vergessen'
|
BUTTONFORGOTPASSWORD: 'Passwort vergessen'
|
||||||
@ -316,6 +371,8 @@ de:
|
|||||||
other: '{count} Benutzerpasswörter'
|
other: '{count} Benutzerpasswörter'
|
||||||
SINGULARNAME: Benutzerpasswort
|
SINGULARNAME: Benutzerpasswort
|
||||||
db_Password: Passwort
|
db_Password: Passwort
|
||||||
|
db_PasswordEncryption: Passwortverschlüsselung
|
||||||
|
db_Salt: Salz
|
||||||
has_one_Member: Benutzer
|
has_one_Member: Benutzer
|
||||||
SilverStripe\Security\PasswordValidator:
|
SilverStripe\Security\PasswordValidator:
|
||||||
LOWCHARSTRENGTH: 'Bitte erhöhen Sie die Sicherheit des Passworts, indem Sie auch einige der folgenden Zeichen verwenden: {chars}'
|
LOWCHARSTRENGTH: 'Bitte erhöhen Sie die Sicherheit des Passworts, indem Sie auch einige der folgenden Zeichen verwenden: {chars}'
|
||||||
@ -363,6 +420,8 @@ de:
|
|||||||
PLURALS:
|
PLURALS:
|
||||||
one: 'Ein Login Hash'
|
one: 'Ein Login Hash'
|
||||||
other: '{count} Login Hashes'
|
other: '{count} Login Hashes'
|
||||||
|
db_DeviceID: 'Geräte ID'
|
||||||
|
db_ExpiryDate: Ablaufdatum
|
||||||
has_one_Member: Benutzer
|
has_one_Member: Benutzer
|
||||||
SilverStripe\Security\Security:
|
SilverStripe\Security\Security:
|
||||||
ALREADYLOGGEDIN: 'Sie haben keinen Zugriff auf diese Seite. Wenn Sie ein anderes Konto besitzen, mit dem Sie auf diese Seite zugreifen können, melden Sie sich bitte unten an.'
|
ALREADYLOGGEDIN: 'Sie haben keinen Zugriff auf diese Seite. Wenn Sie ein anderes Konto besitzen, mit dem Sie auf diese Seite zugreifen können, melden Sie sich bitte unten an.'
|
||||||
|
@ -680,6 +680,18 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
|
|||||||
*/
|
*/
|
||||||
public static function normaliseTrailingSlash(string $url): string
|
public static function normaliseTrailingSlash(string $url): string
|
||||||
{
|
{
|
||||||
|
// Do not normalise external urls
|
||||||
|
// Note that urls without a scheme such as "www.example.com" will be counted as a relative file
|
||||||
|
if (!Director::is_site_url($url)) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not modify files
|
||||||
|
$extension = pathinfo(Director::makeRelative($url), PATHINFO_EXTENSION);
|
||||||
|
if ($extension) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
$querystring = null;
|
$querystring = null;
|
||||||
$fragmentIdentifier = null;
|
$fragmentIdentifier = null;
|
||||||
|
|
||||||
@ -694,14 +706,9 @@ class Controller extends RequestHandler implements TemplateGlobalProvider
|
|||||||
|
|
||||||
// Normlise trailing slash
|
// Normlise trailing slash
|
||||||
$shouldHaveTrailingSlash = Controller::config()->uninherited('add_trailing_slash');
|
$shouldHaveTrailingSlash = Controller::config()->uninherited('add_trailing_slash');
|
||||||
if ($shouldHaveTrailingSlash
|
if ($shouldHaveTrailingSlash && !str_ends_with($url, '/')) {
|
||||||
&& !str_ends_with($url, '/')
|
|
||||||
&& !preg_match('/^(.*)\.([^\/]*)$/', Director::makeRelative($url))
|
|
||||||
) {
|
|
||||||
// Add trailing slash if enabled and url does not end with a file extension
|
|
||||||
$url .= '/';
|
$url .= '/';
|
||||||
} elseif (!$shouldHaveTrailingSlash) {
|
} elseif (!$shouldHaveTrailingSlash) {
|
||||||
// Remove trailing slash if it shouldn't be there
|
|
||||||
$url = rtrim($url, '/');
|
$url = rtrim($url, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -821,7 +821,16 @@ class Director implements TemplateGlobalProvider
|
|||||||
|
|
||||||
// Allow extensions to weigh in
|
// Allow extensions to weigh in
|
||||||
$isSiteUrl = false;
|
$isSiteUrl = false;
|
||||||
static::singleton()->extend('updateIsSiteUrl', $isSiteUrl, $url);
|
// Not using static::singleton() here because it can break
|
||||||
|
// functional tests such as those in HTTPCacheControlIntegrationTest
|
||||||
|
// This happens because a singleton of Director is instantiating prior to tests being run,
|
||||||
|
// because Controller::normaliseTrailingSlash() is called during SapphireTest::setUp(),
|
||||||
|
// which in turn calls Director::is_site_url()
|
||||||
|
// For this specific use case we don't need to use dependency injection because the
|
||||||
|
// chance of the extend() method being customised in projects is low.
|
||||||
|
// Any extension hooks implementing updateIsSiteUrl() will still be called as expected
|
||||||
|
$director = new static();
|
||||||
|
$director->extend('updateIsSiteUrl', $isSiteUrl, $url);
|
||||||
if ($isSiteUrl) {
|
if ($isSiteUrl) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -750,6 +750,7 @@ class TinyMCEConfig extends HTMLEditorConfig implements i18nEntityProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($preset['i18n'])) {
|
if (isset($preset['i18n'])) {
|
||||||
|
/** @phpstan-ignore translation.key (we need the key to be dynamic here) */
|
||||||
$preset['text'] = _t(
|
$preset['text'] = _t(
|
||||||
$preset['i18n'],
|
$preset['i18n'],
|
||||||
isset($preset['text']) ? $preset['text'] : ''
|
isset($preset['text']) ? $preset['text'] : ''
|
||||||
|
@ -29,7 +29,7 @@ trait SearchableDropdownTrait
|
|||||||
'search',
|
'search',
|
||||||
];
|
];
|
||||||
|
|
||||||
private bool $isClearable = false;
|
private bool $isClearable = true;
|
||||||
|
|
||||||
private bool $isLazyLoaded = false;
|
private bool $isLazyLoaded = false;
|
||||||
|
|
||||||
|
@ -24,6 +24,5 @@ class SearchableMultiDropdownField extends MultiSelectField
|
|||||||
$this->setLabelField($labelField);
|
$this->setLabelField($labelField);
|
||||||
$this->addExtraClass('ss-searchable-dropdown-field');
|
$this->addExtraClass('ss-searchable-dropdown-field');
|
||||||
$this->setIsMultiple(true);
|
$this->setIsMultiple(true);
|
||||||
$this->setIsClearable(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -566,6 +566,26 @@ class MySQLDatabase extends Database implements TransactionManager
|
|||||||
*/
|
*/
|
||||||
public function clearTable($table)
|
public function clearTable($table)
|
||||||
{
|
{
|
||||||
$this->query("TRUNCATE TABLE \"$table\"");
|
// Not simply using "TRUNCATE TABLE \"$table\"" because DELETE is a lot quicker
|
||||||
|
// than TRUNCATE which is very relevant during unit testing. Using TRUNCATE will lead to an
|
||||||
|
// approximately 50% increase it the total time of running unit tests.
|
||||||
|
//
|
||||||
|
// Using max(ID) to determine if the table should reset its auto-increment, rather than using
|
||||||
|
// SELECT "AUTO_INCREMENT" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
|
||||||
|
// after deleting from the table, because in MySQL 8, under certain conditions, notably
|
||||||
|
// when running behat, sometimes the auto-increment was being reset to 2 for unknown reasons
|
||||||
|
$self = $this;
|
||||||
|
$fn = function () use ($self, $table) {
|
||||||
|
$maxID = $self->query("SELECT MAX(ID) FROM \"$table\"")->value();
|
||||||
|
$self->query("DELETE FROM \"$table\"");
|
||||||
|
if ($maxID > 0) {
|
||||||
|
$self->query("ALTER TABLE \"$table\" AUTO_INCREMENT = 1");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if ($this->supportsTransactions()) {
|
||||||
|
$this->withTransaction($fn);
|
||||||
|
} else {
|
||||||
|
$fn();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3959,6 +3959,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
}
|
}
|
||||||
foreach ($types as $type => $attrs) {
|
foreach ($types as $type => $attrs) {
|
||||||
foreach ($attrs as $name => $spec) {
|
foreach ($attrs as $name => $spec) {
|
||||||
|
/** @phpstan-ignore translation.key (we need the key to be dynamic here) */
|
||||||
$autoLabels[$name] = _t(
|
$autoLabels[$name] = _t(
|
||||||
"{$ancestorClass}.{$type}_{$name}",
|
"{$ancestorClass}.{$type}_{$name}",
|
||||||
FormField::name_to_label($name)
|
FormField::name_to_label($name)
|
||||||
|
@ -203,6 +203,7 @@ class PasswordValidator
|
|||||||
if (preg_match($tests[$name] ?? '', $password ?? '')) {
|
if (preg_match($tests[$name] ?? '', $password ?? '')) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
/** @phpstan-ignore translation.key (we need the key to be dynamic here) */
|
||||||
$missedTests[] = _t(
|
$missedTests[] = _t(
|
||||||
__CLASS__ . '.STRENGTHTEST' . strtoupper($name ?? ''),
|
__CLASS__ . '.STRENGTHTEST' . strtoupper($name ?? ''),
|
||||||
$name,
|
$name,
|
||||||
|
@ -276,14 +276,17 @@ class ControllerTest extends FunctionalTest
|
|||||||
{
|
{
|
||||||
/* Controller::join_links() will reliably join two URL-segments together so that they will be
|
/* Controller::join_links() will reliably join two URL-segments together so that they will be
|
||||||
* appropriately parsed by the URL parser */
|
* appropriately parsed by the URL parser */
|
||||||
|
Director::config()->set('alternate_base_url', 'https://www.internal.com');
|
||||||
Controller::config()->set('add_trailing_slash', false);
|
Controller::config()->set('add_trailing_slash', false);
|
||||||
$this->assertEquals("admin/crm/MyForm", Controller::join_links("admin/crm", "MyForm"));
|
$this->assertEquals("admin/crm/MyForm", Controller::join_links("admin/crm", "MyForm"));
|
||||||
$this->assertEquals("admin/crm/MyForm", Controller::join_links("admin/crm/", "MyForm"));
|
$this->assertEquals("admin/crm/MyForm", Controller::join_links("admin/crm/", "MyForm"));
|
||||||
$this->assertEquals("https://www.test.com/admin/crm/MyForm", Controller::join_links("https://www.test.com", "admin/crm/", "MyForm"));
|
$this->assertEquals("https://www.internal.com/admin/crm/MyForm", Controller::join_links("https://www.internal.com", "admin/crm/", "MyForm"));
|
||||||
|
$this->assertEquals("https://www.external.com/admin/crm/MyForm", Controller::join_links("https://www.external.com", "admin/crm/", "MyForm"));
|
||||||
Controller::config()->set('add_trailing_slash', true);
|
Controller::config()->set('add_trailing_slash', true);
|
||||||
$this->assertEquals("admin/crm/MyForm/", Controller::join_links("admin/crm", "MyForm"));
|
$this->assertEquals("admin/crm/MyForm/", Controller::join_links("admin/crm", "MyForm"));
|
||||||
$this->assertEquals("admin/crm/MyForm/", Controller::join_links("admin/crm/", "MyForm"));
|
$this->assertEquals("admin/crm/MyForm/", Controller::join_links("admin/crm/", "MyForm"));
|
||||||
$this->assertEquals("https://www.test.com/admin/crm/MyForm/", Controller::join_links("https://www.test.com", "admin/crm/", "MyForm"));
|
$this->assertEquals("https://www.internal.com/admin/crm/MyForm/", Controller::join_links("https://www.internal.com", "admin/crm/", "MyForm"));
|
||||||
|
$this->assertEquals("https://www.external.com/admin/crm/MyForm", Controller::join_links("https://www.external.com", "admin/crm/", "MyForm"));
|
||||||
|
|
||||||
/* It will also handle appropriate combination of querystring variables */
|
/* It will also handle appropriate combination of querystring variables */
|
||||||
Controller::config()->set('add_trailing_slash', false);
|
Controller::config()->set('add_trailing_slash', false);
|
||||||
@ -293,7 +296,8 @@ class ControllerTest extends FunctionalTest
|
|||||||
"admin/crm/MyForm?field=1&other=1",
|
"admin/crm/MyForm?field=1&other=1",
|
||||||
Controller::join_links("admin/crm/?field=1", "MyForm?other=1")
|
Controller::join_links("admin/crm/?field=1", "MyForm?other=1")
|
||||||
);
|
);
|
||||||
$this->assertEquals("https://www.test.com/admin/crm/MyForm?flush=1", Controller::join_links("https://www.test.com", "admin/crm/", "MyForm?flush=1"));
|
$this->assertEquals("https://www.internal.com/admin/crm/MyForm?flush=1", Controller::join_links("https://www.internal.com", "admin/crm/", "MyForm?flush=1"));
|
||||||
|
$this->assertEquals("https://www.external.com/admin/crm/MyForm?flush=1", Controller::join_links("https://www.external.com", "admin/crm/", "MyForm?flush=1"));
|
||||||
Controller::config()->set('add_trailing_slash', true);
|
Controller::config()->set('add_trailing_slash', true);
|
||||||
$this->assertEquals("admin/crm/MyForm/?flush=1", Controller::join_links("admin/crm/?flush=1", "MyForm"));
|
$this->assertEquals("admin/crm/MyForm/?flush=1", Controller::join_links("admin/crm/?flush=1", "MyForm"));
|
||||||
$this->assertEquals("admin/crm/MyForm/?flush=1", Controller::join_links("admin/crm/", "MyForm?flush=1"));
|
$this->assertEquals("admin/crm/MyForm/?flush=1", Controller::join_links("admin/crm/", "MyForm?flush=1"));
|
||||||
@ -301,7 +305,8 @@ class ControllerTest extends FunctionalTest
|
|||||||
"admin/crm/MyForm/?field=1&other=1",
|
"admin/crm/MyForm/?field=1&other=1",
|
||||||
Controller::join_links("admin/crm/?field=1", "MyForm?other=1")
|
Controller::join_links("admin/crm/?field=1", "MyForm?other=1")
|
||||||
);
|
);
|
||||||
$this->assertEquals("https://www.test.com/admin/crm/MyForm/?flush=1", Controller::join_links("https://www.test.com", "admin/crm/", "MyForm?flush=1"));
|
$this->assertEquals("https://www.internal.com/admin/crm/MyForm/?flush=1", Controller::join_links("https://www.internal.com", "admin/crm/", "MyForm?flush=1"));
|
||||||
|
$this->assertEquals("https://www.external.com/admin/crm/MyForm?flush=1", Controller::join_links("https://www.external.com", "admin/crm/", "MyForm?flush=1"));
|
||||||
|
|
||||||
/* It can handle arbitrary numbers of components, and will ignore empty ones */
|
/* It can handle arbitrary numbers of components, and will ignore empty ones */
|
||||||
Controller::config()->set('add_trailing_slash', false);
|
Controller::config()->set('add_trailing_slash', false);
|
||||||
@ -340,8 +345,12 @@ class ControllerTest extends FunctionalTest
|
|||||||
Controller::join_links("admin/crm?foo=1&bar=1&baz=1", "?foo=2&bar=3")
|
Controller::join_links("admin/crm?foo=1&bar=1&baz=1", "?foo=2&bar=3")
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
"https://www.test.com/admin/crm?foo=2&bar=3&baz=1",
|
"https://www.internal.com/admin/crm?foo=2&bar=3&baz=1",
|
||||||
Controller::join_links("https://www.test.com", "admin/crm?foo=1&bar=1&baz=1", "?foo=2&bar=3")
|
Controller::join_links("https://www.internal.com", "admin/crm?foo=1&bar=1&baz=1", "?foo=2&bar=3")
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
"https://www.external.com/admin/crm?foo=2&bar=3&baz=1",
|
||||||
|
Controller::join_links("https://www.external.com", "admin/crm?foo=1&bar=1&baz=1", "?foo=2&bar=3")
|
||||||
);
|
);
|
||||||
Controller::config()->set('add_trailing_slash', true);
|
Controller::config()->set('add_trailing_slash', true);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
@ -349,8 +358,12 @@ class ControllerTest extends FunctionalTest
|
|||||||
Controller::join_links("admin/crm?foo=1&bar=1&baz=1", "?foo=2&bar=3")
|
Controller::join_links("admin/crm?foo=1&bar=1&baz=1", "?foo=2&bar=3")
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
"https://www.test.com/admin/crm/?foo=2&bar=3&baz=1",
|
"https://www.internal.com/admin/crm/?foo=2&bar=3&baz=1",
|
||||||
Controller::join_links("https://www.test.com", "admin/crm?foo=1&bar=1&baz=1", "?foo=2&bar=3")
|
Controller::join_links("https://www.internal.com", "admin/crm?foo=1&bar=1&baz=1", "?foo=2&bar=3")
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
"https://www.external.com/admin/crm?foo=2&bar=3&baz=1",
|
||||||
|
Controller::join_links("https://www.external.com", "admin/crm?foo=1&bar=1&baz=1", "?foo=2&bar=3")
|
||||||
);
|
);
|
||||||
|
|
||||||
Controller::config()->set('add_trailing_slash', false);
|
Controller::config()->set('add_trailing_slash', false);
|
||||||
@ -361,8 +374,13 @@ class ControllerTest extends FunctionalTest
|
|||||||
);
|
);
|
||||||
$this->assertEquals('/admin/action', Controller::join_links('/admin', 'action'));
|
$this->assertEquals('/admin/action', Controller::join_links('/admin', 'action'));
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'https://www.test.com/admin/action',
|
'https://www.internal.com/admin/action',
|
||||||
Controller::join_links('https://www.test.com', '/', '/admin/', '/', '/action'),
|
Controller::join_links('https://www.internal.com', '/', '/admin/', '/', '/action'),
|
||||||
|
'Test that multiple slashes are trimmed.'
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
'https://www.external.com/admin/action',
|
||||||
|
Controller::join_links('https://www.external.com', '/', '/admin/', '/', '/action'),
|
||||||
'Test that multiple slashes are trimmed.'
|
'Test that multiple slashes are trimmed.'
|
||||||
);
|
);
|
||||||
Controller::config()->set('add_trailing_slash', true);
|
Controller::config()->set('add_trailing_slash', true);
|
||||||
@ -373,8 +391,13 @@ class ControllerTest extends FunctionalTest
|
|||||||
);
|
);
|
||||||
$this->assertEquals('/admin/action/', Controller::join_links('/admin', 'action'));
|
$this->assertEquals('/admin/action/', Controller::join_links('/admin', 'action'));
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'https://www.test.com/admin/action/',
|
'https://www.internal.com/admin/action/',
|
||||||
Controller::join_links('https://www.test.com', '/', '/admin/', '/', '/action'),
|
Controller::join_links('https://www.internal.com', '/', '/admin/', '/', '/action'),
|
||||||
|
'Test that multiple slashes are trimmed.'
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
'https://www.external.com/admin/action',
|
||||||
|
Controller::join_links('https://www.external.com', '/', '/admin/', '/', '/action'),
|
||||||
'Test that multiple slashes are trimmed.'
|
'Test that multiple slashes are trimmed.'
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -391,8 +414,12 @@ class ControllerTest extends FunctionalTest
|
|||||||
Controller::join_links("my-page#subsection", "?arg=var", "#second-section")
|
Controller::join_links("my-page#subsection", "?arg=var", "#second-section")
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
"https://www.test.com/my-page?arg=var#second-section",
|
"https://www.internal.com/my-page?arg=var#second-section",
|
||||||
Controller::join_links("https://www.test.com", "my-page#subsection", "?arg=var", "#second-section")
|
Controller::join_links("https://www.internal.com", "my-page#subsection", "?arg=var", "#second-section")
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
"https://www.external.com/my-page?arg=var#second-section",
|
||||||
|
Controller::join_links("https://www.external.com", "my-page#subsection", "?arg=var", "#second-section")
|
||||||
);
|
);
|
||||||
Controller::config()->set('add_trailing_slash', true);
|
Controller::config()->set('add_trailing_slash', true);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
@ -400,8 +427,12 @@ class ControllerTest extends FunctionalTest
|
|||||||
Controller::join_links("my-page#subsection", "?arg=var", "#second-section")
|
Controller::join_links("my-page#subsection", "?arg=var", "#second-section")
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
"https://www.test.com/my-page/?arg=var#second-section",
|
"https://www.internal.com/my-page/?arg=var#second-section",
|
||||||
Controller::join_links("https://www.test.com", "my-page#subsection", "?arg=var", "#second-section")
|
Controller::join_links("https://www.internal.com", "my-page#subsection", "?arg=var", "#second-section")
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
"https://www.external.com/my-page?arg=var#second-section",
|
||||||
|
Controller::join_links("https://www.external.com", "my-page#subsection", "?arg=var", "#second-section")
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Does type-safe checks for zero value */
|
/* Does type-safe checks for zero value */
|
||||||
@ -413,60 +444,245 @@ class ControllerTest extends FunctionalTest
|
|||||||
// Test array args
|
// Test array args
|
||||||
Controller::config()->set('add_trailing_slash', false);
|
Controller::config()->set('add_trailing_slash', false);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
"https://www.test.com/admin/crm/MyForm?a=1&b=2&c=3",
|
"https://www.internal.com/admin/crm/MyForm?a=1&b=2&c=3",
|
||||||
Controller::join_links(["https://www.test.com", "?a=1", "admin/crm", "?b=2", "MyForm?c=3"])
|
Controller::join_links(["https://www.internal.com", "?a=1", "admin/crm", "?b=2", "MyForm?c=3"])
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
"https://www.external.com/admin/crm/MyForm?a=1&b=2&c=3",
|
||||||
|
Controller::join_links(["https://www.external.com", "?a=1", "admin/crm", "?b=2", "MyForm?c=3"])
|
||||||
);
|
);
|
||||||
Controller::config()->set('add_trailing_slash', true);
|
Controller::config()->set('add_trailing_slash', true);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
"https://www.test.com/admin/crm/MyForm/?a=1&b=2&c=3",
|
"https://www.internal.com/admin/crm/MyForm/?a=1&b=2&c=3",
|
||||||
Controller::join_links(["https://www.test.com", "?a=1", "admin/crm", "?b=2", "MyForm?c=3"])
|
Controller::join_links(["https://www.internal.com", "?a=1", "admin/crm", "?b=2", "MyForm?c=3"])
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
"https://www.external.com/admin/crm/MyForm?a=1&b=2&c=3",
|
||||||
|
Controller::join_links(["https://www.external.com", "?a=1", "admin/crm", "?b=2", "MyForm?c=3"])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNormaliseTrailingSlash()
|
public function provideNormaliseTrailingSlash(): array
|
||||||
{
|
{
|
||||||
foreach ([true, false] as $withTrailingSlash) {
|
// note 93.184.215.14 is the IP address for example.com
|
||||||
Controller::config()->set('add_trailing_slash', $withTrailingSlash);
|
return [
|
||||||
$slash = $withTrailingSlash ? '/' : '';
|
|
||||||
|
|
||||||
// Correctly gives slash to a relative root path
|
// Correctly gives slash to a relative root path
|
||||||
$this->assertEquals('/', Controller::normaliseTrailingSlash(''));
|
[
|
||||||
$this->assertEquals('/', Controller::normaliseTrailingSlash('/'));
|
'path' => '',
|
||||||
|
'withSlash' => '/',
|
||||||
|
'withoutSlash' => '/',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => '/',
|
||||||
|
'withSlash' => '/',
|
||||||
|
'withoutSlash' => '/',
|
||||||
|
],
|
||||||
// Correctly adds or removes trailing slash
|
// Correctly adds or removes trailing slash
|
||||||
$this->assertEquals("some/path{$slash}", Controller::normaliseTrailingSlash('some/path/'));
|
[
|
||||||
$this->assertEquals("some/path{$slash}", Controller::normaliseTrailingSlash('some/path'));
|
'path' => 'some/path/',
|
||||||
|
'withSlash' => 'some/path/',
|
||||||
|
'withoutSlash' => 'some/path',
|
||||||
|
],
|
||||||
// Retains leading slash, if there is one
|
// Retains leading slash, if there is one
|
||||||
$this->assertEquals("/some/path{$slash}", Controller::normaliseTrailingSlash('/some/path/'));
|
[
|
||||||
$this->assertEquals("/some/path{$slash}", Controller::normaliseTrailingSlash('/some/path'));
|
'path' => '/some/path/',
|
||||||
|
'withSlash' => '/some/path/',
|
||||||
// Effectively treats absolute URL as relative
|
'withoutSlash' => '/some/path',
|
||||||
$this->assertEquals("https://www.google.com/some/path{$slash}", Controller::normaliseTrailingSlash('https://www.google.com/some/path/'));
|
],
|
||||||
$this->assertEquals("//www.google.com/some/path{$slash}", Controller::normaliseTrailingSlash('//www.google.com/some/path'));
|
// Treat absolute URLs pointing to the current site as relative
|
||||||
$this->assertEquals("www.google.com/some/path{$slash}", Controller::normaliseTrailingSlash('www.google.com/some/path'));
|
[
|
||||||
$this->assertEquals("https://www.google.com{$slash}", Controller::normaliseTrailingSlash('https://www.google.com'));
|
'path' => '<AbsoluteBaseUrl>/some/path/',
|
||||||
$this->assertEquals("//www.google.com{$slash}", Controller::normaliseTrailingSlash('//www.google.com/'));
|
'withSlash' => '<AbsoluteBaseUrl>/some/path/',
|
||||||
|
'withoutSlash' => '<AbsoluteBaseUrl>/some/path',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => '<AbsoluteBaseUrl>/',
|
||||||
|
'withSlash' => '<AbsoluteBaseUrl>/',
|
||||||
|
'withoutSlash' => '<AbsoluteBaseUrl>',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => '<AbsoluteBaseUrl>',
|
||||||
|
'withSlash' => '<AbsoluteBaseUrl>/',
|
||||||
|
'withoutSlash' => '<AbsoluteBaseUrl>',
|
||||||
|
],
|
||||||
|
// External links never get normalised
|
||||||
|
[
|
||||||
|
'path' => 'https://www.example.com/some/path',
|
||||||
|
'withSlash' => 'https://www.example.com/some/path',
|
||||||
|
'withoutSlash' => 'https://www.example.com/some/path',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'https://www.example.com/some/path/',
|
||||||
|
'withSlash' => 'https://www.example.com/some/path/',
|
||||||
|
'withoutSlash' => 'https://www.example.com/some/path/',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'https://www.example.com',
|
||||||
|
'withSlash' => 'https://www.example.com',
|
||||||
|
'withoutSlash' => 'https://www.example.com',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'https://www.example.com/',
|
||||||
|
'withSlash' => 'https://www.example.com/',
|
||||||
|
'withoutSlash' => 'https://www.example.com/',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => '//www.example.com/some/path',
|
||||||
|
'withSlash' => '//www.example.com/some/path',
|
||||||
|
'withoutSlash' => '//www.example.com/some/path',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => '//www.example.com/some/path/',
|
||||||
|
'withSlash' => '//www.example.com/some/path/',
|
||||||
|
'withoutSlash' => '//www.example.com/some/path/',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => '//www.example.com',
|
||||||
|
'withSlash' => '//www.example.com',
|
||||||
|
'withoutSlash' => '//www.example.com',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => '//www.example.com/',
|
||||||
|
'withSlash' => '//www.example.com/',
|
||||||
|
'withoutSlash' => '//www.example.com/',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'https://93.184.215.14/some/path',
|
||||||
|
'withSlash' => 'https://93.184.215.14/some/path',
|
||||||
|
'withoutSlash' => 'https://93.184.215.14/some/path',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'https://93.184.215.14/some/path/',
|
||||||
|
'withSlash' => 'https://93.184.215.14/some/path/',
|
||||||
|
'withoutSlash' => 'https://93.184.215.14/some/path/',
|
||||||
|
],
|
||||||
|
// Links without a scheme with a path are treated as relative
|
||||||
|
// Note: content authors should be specifying a scheme in these cases themselves
|
||||||
|
[
|
||||||
|
'path' => 'www.example.com/some/path',
|
||||||
|
'withSlash' => 'www.example.com/some/path/',
|
||||||
|
'withoutSlash' => 'www.example.com/some/path',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'www.example.com/some/path/',
|
||||||
|
'withSlash' => 'www.example.com/some/path/',
|
||||||
|
'withoutSlash' => 'www.example.com/some/path',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => '93.184.215.14/some/path',
|
||||||
|
'withSlash' => '93.184.215.14/some/path/',
|
||||||
|
'withoutSlash' => '93.184.215.14/some/path',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => '93.184.215.14/some/path/',
|
||||||
|
'withSlash' => '93.184.215.14/some/path/',
|
||||||
|
'withoutSlash' => '93.184.215.14/some/path',
|
||||||
|
],
|
||||||
|
// Links without a scheme or path are treated like files i.e. not altered
|
||||||
|
// Note: content authors should be specifying a scheme in these cases themselves
|
||||||
|
[
|
||||||
|
'path' => 'www.example.com',
|
||||||
|
'withSlash' => 'www.example.com',
|
||||||
|
'withoutSlash' => 'www.example.com',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'www.example.com/',
|
||||||
|
'withSlash' => 'www.example.com/',
|
||||||
|
'withoutSlash' => 'www.example.com/',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => '93.184.215.14',
|
||||||
|
'withSlash' => '93.184.215.14',
|
||||||
|
'withoutSlash' => '93.184.215.14',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => '93.184.215.14/',
|
||||||
|
'withSlash' => '93.184.215.14/',
|
||||||
|
'withoutSlash' => '93.184.215.14/',
|
||||||
|
],
|
||||||
// Retains query string and anchor if present
|
// Retains query string and anchor if present
|
||||||
$this->assertEquals("some/path{$slash}?key=value&key2=value2", Controller::normaliseTrailingSlash('some/path/?key=value&key2=value2'));
|
[
|
||||||
$this->assertEquals("some/path{$slash}#some-id", Controller::normaliseTrailingSlash('some/path/#some-id'));
|
'path' => 'some/path/?key=value&key2=value2',
|
||||||
$this->assertEquals("some/path{$slash}?key=value&key2=value2#some-id", Controller::normaliseTrailingSlash('some/path/?key=value&key2=value2#some-id'));
|
'withSlash' => 'some/path/?key=value&key2=value2',
|
||||||
$this->assertEquals("some/path{$slash}?key=value&key2=value2", Controller::normaliseTrailingSlash('some/path?key=value&key2=value2'));
|
'withoutSlash' => 'some/path?key=value&key2=value2',
|
||||||
$this->assertEquals("some/path{$slash}#some-id", Controller::normaliseTrailingSlash('some/path#some-id'));
|
],
|
||||||
$this->assertEquals("some/path{$slash}?key=value&key2=value2#some-id", Controller::normaliseTrailingSlash('some/path?key=value&key2=value2#some-id'));
|
[
|
||||||
|
'path' => 'some/path/#some-id',
|
||||||
|
'withSlash' => 'some/path/#some-id',
|
||||||
|
'withoutSlash' => 'some/path#some-id',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'some/path?key=value&key2=value2#some-id',
|
||||||
|
'withSlash' => 'some/path/?key=value&key2=value2#some-id',
|
||||||
|
'withoutSlash' => 'some/path?key=value&key2=value2#some-id',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'some/path?key=value&key2=value2',
|
||||||
|
'withSlash' => 'some/path/?key=value&key2=value2',
|
||||||
|
'withoutSlash' => 'some/path?key=value&key2=value2',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'some/path#some-id',
|
||||||
|
'withSlash' => 'some/path/#some-id',
|
||||||
|
'withoutSlash' => 'some/path#some-id',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'some/path?key=value&key2=value2#some-id',
|
||||||
|
'withSlash' => 'some/path/?key=value&key2=value2#some-id',
|
||||||
|
'withoutSlash' => 'some/path?key=value&key2=value2#some-id',
|
||||||
|
],
|
||||||
// Don't ever add a trailing slash to the end of a URL that looks like a file
|
// Don't ever add a trailing slash to the end of a URL that looks like a file
|
||||||
$this->assertEquals("https://www.google.com/some/file.txt", Controller::normaliseTrailingSlash('https://www.google.com/some/file.txt'));
|
[
|
||||||
$this->assertEquals("//www.google.com/some/file.txt", Controller::normaliseTrailingSlash('//www.google.com/some/file.txt'));
|
'path' => 'https://www.example.com/some/file.txt',
|
||||||
$this->assertEquals("www.google.com/some/file.txt", Controller::normaliseTrailingSlash('www.google.com/some/file.txt'));
|
'withSlash' => 'https://www.example.com/some/file.txt',
|
||||||
$this->assertEquals("/some/file.txt", Controller::normaliseTrailingSlash('/some/file.txt'));
|
'withoutSlash' => 'https://www.example.com/some/file.txt',
|
||||||
$this->assertEquals("some/file.txt", Controller::normaliseTrailingSlash('some/file.txt'));
|
],
|
||||||
$this->assertEquals("file.txt", Controller::normaliseTrailingSlash('file.txt'));
|
[
|
||||||
$this->assertEquals("some/file.txt?key=value&key2=value2#some-id", Controller::normaliseTrailingSlash('some/file.txt?key=value&key2=value2#some-id'));
|
'path' => '//www.example.com/some/file.txt',
|
||||||
// NOTE: `www.google.com` is already treated as "relative" by Director::makeRelative(), which means we can't tell that it's a host (and not a file).
|
'withSlash' => '//www.example.com/some/file.txt',
|
||||||
$this->assertEquals("www.google.com", Controller::normaliseTrailingSlash('www.google.com'));
|
'withoutSlash' => '//www.example.com/some/file.txt',
|
||||||
}
|
],
|
||||||
|
[
|
||||||
|
'path' => 'www.example.com/some/file.txt',
|
||||||
|
'withSlash' => 'www.example.com/some/file.txt',
|
||||||
|
'withoutSlash' => 'www.example.com/some/file.txt',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => '/some/file.txt',
|
||||||
|
'withSlash' => '/some/file.txt',
|
||||||
|
'withoutSlash' => '/some/file.txt',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'some/file.txt',
|
||||||
|
'withSlash' => 'some/file.txt',
|
||||||
|
'withoutSlash' => 'some/file.txt',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'file.txt',
|
||||||
|
'withSlash' => 'file.txt',
|
||||||
|
'withoutSlash' => 'file.txt',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'path' => 'some/file.txt?key=value&key2=value2#some-id',
|
||||||
|
'withSlash' => 'some/file.txt?key=value&key2=value2#some-id',
|
||||||
|
'withoutSlash' => 'some/file.txt?key=value&key2=value2#some-id',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideNormaliseTrailingSlash
|
||||||
|
*/
|
||||||
|
public function testNormaliseTrailingSlash(string $path, string $withSlash, string $withoutSlash): void
|
||||||
|
{
|
||||||
|
$absBaseUrlNoSlash = rtrim(Director::absoluteBaseURL(), '/');
|
||||||
|
$path = str_replace('<AbsoluteBaseUrl>', $absBaseUrlNoSlash, $path);
|
||||||
|
$withSlash = str_replace('<AbsoluteBaseUrl>', $absBaseUrlNoSlash, $withSlash);
|
||||||
|
$withoutSlash = str_replace('<AbsoluteBaseUrl>', $absBaseUrlNoSlash, $withoutSlash);
|
||||||
|
Controller::config()->set('add_trailing_slash', true);
|
||||||
|
$this->assertEquals($withSlash, Controller::normaliseTrailingSlash($path), 'With trailing slash test');
|
||||||
|
Controller::config()->set('add_trailing_slash', false);
|
||||||
|
$this->assertEquals($withoutSlash, Controller::normaliseTrailingSlash($path), 'Without trailing slash test');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLink()
|
public function testLink()
|
||||||
|
@ -109,21 +109,21 @@ class DirectorTest extends SapphireTest
|
|||||||
|
|
||||||
// Test Director::BASE
|
// Test Director::BASE
|
||||||
$this->assertEquals("http://www.mysite.com:9090{$slash}", Director::absoluteURL('http://www.mysite.com:9090/', Director::BASE));
|
$this->assertEquals("http://www.mysite.com:9090{$slash}", Director::absoluteURL('http://www.mysite.com:9090/', Director::BASE));
|
||||||
$this->assertEquals("http://www.mytest.com{$slash}", Director::absoluteURL('http://www.mytest.com', Director::BASE));
|
$this->assertEquals("http://www.mytest.com", Director::absoluteURL('http://www.mytest.com', Director::BASE));
|
||||||
$this->assertEquals("http://www.mysite.com:9090/test{$slash}", Director::absoluteURL("http://www.mysite.com:9090/test", Director::BASE));
|
$this->assertEquals("http://www.mysite.com:9090/test{$slash}", Director::absoluteURL("http://www.mysite.com:9090/test", Director::BASE));
|
||||||
$this->assertEquals("http://www.mysite.com:9090/root{$slash}", Director::absoluteURL("/root", Director::BASE));
|
$this->assertEquals("http://www.mysite.com:9090/root{$slash}", Director::absoluteURL("/root", Director::BASE));
|
||||||
$this->assertEquals("http://www.mysite.com:9090/root/url{$slash}", Director::absoluteURL("/root/url", Director::BASE));
|
$this->assertEquals("http://www.mysite.com:9090/root/url{$slash}", Director::absoluteURL("/root/url", Director::BASE));
|
||||||
|
|
||||||
// Test Director::ROOT
|
// Test Director::ROOT
|
||||||
$this->assertEquals("http://www.mysite.com:9090{$slash}", Director::absoluteURL('http://www.mysite.com:9090/', Director::ROOT));
|
$this->assertEquals("http://www.mysite.com:9090{$slash}", Director::absoluteURL('http://www.mysite.com:9090/', Director::ROOT));
|
||||||
$this->assertEquals("http://www.mytest.com{$slash}", Director::absoluteURL('http://www.mytest.com', Director::ROOT));
|
$this->assertEquals("http://www.mytest.com", Director::absoluteURL('http://www.mytest.com', Director::ROOT));
|
||||||
$this->assertEquals("http://www.mysite.com:9090/test{$slash}", Director::absoluteURL("http://www.mysite.com:9090/test", Director::ROOT));
|
$this->assertEquals("http://www.mysite.com:9090/test{$slash}", Director::absoluteURL("http://www.mysite.com:9090/test", Director::ROOT));
|
||||||
$this->assertEquals("http://www.mysite.com:9090/root{$slash}", Director::absoluteURL("/root", Director::ROOT));
|
$this->assertEquals("http://www.mysite.com:9090/root{$slash}", Director::absoluteURL("/root", Director::ROOT));
|
||||||
$this->assertEquals("http://www.mysite.com:9090/root/url{$slash}", Director::absoluteURL("/root/url", Director::ROOT));
|
$this->assertEquals("http://www.mysite.com:9090/root/url{$slash}", Director::absoluteURL("/root/url", Director::ROOT));
|
||||||
|
|
||||||
// Test Director::REQUEST
|
// Test Director::REQUEST
|
||||||
$this->assertEquals("http://www.mysite.com:9090{$slash}", Director::absoluteURL('http://www.mysite.com:9090/', Director::REQUEST));
|
$this->assertEquals("http://www.mysite.com:9090{$slash}", Director::absoluteURL('http://www.mysite.com:9090/', Director::REQUEST));
|
||||||
$this->assertEquals("http://www.mytest.com{$slash}", Director::absoluteURL('http://www.mytest.com', Director::REQUEST));
|
$this->assertEquals("http://www.mytest.com", Director::absoluteURL('http://www.mytest.com', Director::REQUEST));
|
||||||
$this->assertEquals("http://www.mysite.com:9090/test{$slash}", Director::absoluteURL("http://www.mysite.com:9090/test", Director::REQUEST));
|
$this->assertEquals("http://www.mysite.com:9090/test{$slash}", Director::absoluteURL("http://www.mysite.com:9090/test", Director::REQUEST));
|
||||||
$this->assertEquals("http://www.mysite.com:9090/root{$slash}", Director::absoluteURL("/root", Director::REQUEST));
|
$this->assertEquals("http://www.mysite.com:9090/root{$slash}", Director::absoluteURL("/root", Director::REQUEST));
|
||||||
$this->assertEquals("http://www.mysite.com:9090/root/url{$slash}", Director::absoluteURL("/root/url", Director::REQUEST));
|
$this->assertEquals("http://www.mysite.com:9090/root/url{$slash}", Director::absoluteURL("/root/url", Director::REQUEST));
|
||||||
|
@ -8,6 +8,7 @@ use SilverStripe\Control\HTTPResponse;
|
|||||||
use SilverStripe\Control\Middleware\CanonicalURLMiddleware;
|
use SilverStripe\Control\Middleware\CanonicalURLMiddleware;
|
||||||
use SilverStripe\Core\Environment;
|
use SilverStripe\Core\Environment;
|
||||||
use SilverStripe\Dev\SapphireTest;
|
use SilverStripe\Dev\SapphireTest;
|
||||||
|
use SilverStripe\Control\Director;
|
||||||
|
|
||||||
class CanonicalURLMiddlewareTest extends SapphireTest
|
class CanonicalURLMiddlewareTest extends SapphireTest
|
||||||
{
|
{
|
||||||
@ -121,6 +122,7 @@ class CanonicalURLMiddlewareTest extends SapphireTest
|
|||||||
|
|
||||||
private function performRedirectTest(string $requestURL, CanonicalURLMiddleware $middleware, bool $shouldRedirect, bool $addTrailingSlash)
|
private function performRedirectTest(string $requestURL, CanonicalURLMiddleware $middleware, bool $shouldRedirect, bool $addTrailingSlash)
|
||||||
{
|
{
|
||||||
|
Director::config()->set('alternate_base_url', 'https://www.example.com');
|
||||||
Environment::setEnv('REQUEST_URI', $requestURL);
|
Environment::setEnv('REQUEST_URI', $requestURL);
|
||||||
$request = new HTTPRequest('GET', $requestURL);
|
$request = new HTTPRequest('GET', $requestURL);
|
||||||
$request->setScheme('https');
|
$request->setScheme('https');
|
||||||
|
@ -205,16 +205,16 @@ class SearchableDropdownTraitTest extends SapphireTest
|
|||||||
$field->setForm($form);
|
$field->setForm($form);
|
||||||
$schema = $field->getSchemaDataDefaults();
|
$schema = $field->getSchemaDataDefaults();
|
||||||
$this->assertFalse($schema['lazyLoad']);
|
$this->assertFalse($schema['lazyLoad']);
|
||||||
$this->assertFalse($schema['clearable']);
|
$this->assertTrue($schema['clearable']);
|
||||||
$this->assertSame('Select or type to search...', $schema['placeholder']);
|
$this->assertSame('Select or type to search...', $schema['placeholder']);
|
||||||
$this->assertTrue($schema['searchable']);
|
$this->assertTrue($schema['searchable']);
|
||||||
$field->setIsLazyLoaded(true);
|
$field->setIsLazyLoaded(true);
|
||||||
$field->setIsClearable(true);
|
$field->setIsClearable(false);
|
||||||
$field->setPlaceholder('My placeholder');
|
$field->setPlaceholder('My placeholder');
|
||||||
$field->setIsSearchable(false);
|
$field->setIsSearchable(false);
|
||||||
$schema = $field->getSchemaDataDefaults();
|
$schema = $field->getSchemaDataDefaults();
|
||||||
$this->assertTrue($schema['lazyLoad']);
|
$this->assertTrue($schema['lazyLoad']);
|
||||||
$this->assertTrue($schema['clearable']);
|
$this->assertFalse($schema['clearable']);
|
||||||
$this->assertSame('My placeholder', $schema['placeholder']);
|
$this->assertSame('My placeholder', $schema['placeholder']);
|
||||||
$this->assertFalse($schema['searchable']);
|
$this->assertFalse($schema['searchable']);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user