mirror of
https://github.com/silverstripe/silverstripe-userforms.git
synced 2024-09-28 20:29:27 +02:00
ENHANCEMENT: added test coverage for populateFromPostData()
This commit is contained in:
parent
4ff4aa561f
commit
7eef5646e5
@ -24,6 +24,7 @@ class EditableCheckbox extends EditableFormField {
|
|||||||
|
|
||||||
public function getValueFromData($data) {
|
public function getValueFromData($data) {
|
||||||
$value = (isset($data[$this->Name])) ? $data[$this->Name] : false;
|
$value = (isset($data[$this->Name])) ? $data[$this->Name] : false;
|
||||||
|
|
||||||
return ($value) ? _t('EditableFormField.YES', 'Yes') : _t('EditableFormField.NO', 'No');
|
return ($value) ? _t('EditableFormField.YES', 'Yes') : _t('EditableFormField.NO', 'No');
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -210,18 +210,18 @@ class EditableFormField extends DataObject {
|
|||||||
$fields = $this->Parent()->Fields();
|
$fields = $this->Parent()->Fields();
|
||||||
|
|
||||||
// check for existing ones
|
// check for existing ones
|
||||||
if($this->CustomRules) {
|
if($rules = $this->Dependencies()) {
|
||||||
$rules = unserialize($this->CustomRules);
|
|
||||||
|
|
||||||
if($rules) {
|
|
||||||
foreach($rules as $rule => $data) {
|
foreach($rules as $rule => $data) {
|
||||||
// recreate all the field object to prevent caching
|
// recreate all the field object to prevent caching
|
||||||
$outputFields = new DataObjectSet();
|
$outputFields = new DataObjectSet();
|
||||||
|
|
||||||
foreach($fields as $field) {
|
foreach($fields as $field) {
|
||||||
$new = clone $field;
|
$new = clone $field;
|
||||||
|
|
||||||
$new->isSelected = ($new->Name == $data['ConditionField']) ? true : false;
|
$new->isSelected = ($new->Name == $data['ConditionField']) ? true : false;
|
||||||
$outputFields->push($new);
|
$outputFields->push($new);
|
||||||
}
|
}
|
||||||
|
|
||||||
$output->push(new ArrayData(array(
|
$output->push(new ArrayData(array(
|
||||||
'FieldName' => $this->getFieldName(),
|
'FieldName' => $this->getFieldName(),
|
||||||
'Display' => $data['Display'],
|
'Display' => $data['Display'],
|
||||||
@ -232,7 +232,7 @@ class EditableFormField extends DataObject {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,13 +242,12 @@ class EditableFormField extends DataObject {
|
|||||||
* @return TextField
|
* @return TextField
|
||||||
*/
|
*/
|
||||||
function TitleField() {
|
function TitleField() {
|
||||||
$titleAttr = Convert::raw2att($this->Title);
|
$field = new TextField('Title', _t('EditableFormField.ENTERQUESTION', 'Enter Question'), Convert::raw2att($this->Title));
|
||||||
$readOnlyAttr = (!$this->canEdit()) ? ' disabled="disabled"' : '';
|
|
||||||
|
|
||||||
$field = new TextField('Title', _t('EditableFormField.ENTERQUESTION', 'Enter Question'), $this->Title);
|
|
||||||
$field->setName($this->getFieldName('Title'));
|
$field->setName($this->getFieldName('Title'));
|
||||||
|
|
||||||
if(!$this->canEdit()) $field->setReadonly(true);
|
if(!$this->canEdit()) {
|
||||||
|
return $field->performReadonlyTransformation();
|
||||||
|
}
|
||||||
|
|
||||||
return $field;
|
return $field;
|
||||||
}
|
}
|
||||||
@ -305,6 +304,7 @@ class EditableFormField extends DataObject {
|
|||||||
// custom validation
|
// custom validation
|
||||||
if(isset($data['CustomRules'])) {
|
if(isset($data['CustomRules'])) {
|
||||||
$rules = array();
|
$rules = array();
|
||||||
|
|
||||||
foreach($data['CustomRules'] as $key => $value) {
|
foreach($data['CustomRules'] as $key => $value) {
|
||||||
|
|
||||||
if(is_array($value)) {
|
if(is_array($value)) {
|
||||||
@ -325,6 +325,7 @@ class EditableFormField extends DataObject {
|
|||||||
|
|
||||||
$this->CustomRules = serialize($rules);
|
$this->CustomRules = serialize($rules);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->write();
|
$this->write();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,11 +121,6 @@ class FieldEditor extends FormField {
|
|||||||
$name = $this->name;
|
$name = $this->name;
|
||||||
$fieldSet = $record->$name();
|
$fieldSet = $record->$name();
|
||||||
|
|
||||||
// @todo shouldn't we deal with customFormActions on that object?
|
|
||||||
$record->EmailOnSubmit = isset($_REQUEST[$name]['EmailOnSubmit']) ? "1" : "0";
|
|
||||||
$record->SubmitButtonText = isset($_REQUEST[$name]['SubmitButtonText']) ? $_REQUEST[$name]['SubmitButtonText'] : "";
|
|
||||||
$record->ShowClearButton = isset($_REQUEST[$name]['ShowClearButton']) ? "1" : "0";
|
|
||||||
|
|
||||||
// store the field IDs and delete the missing fields
|
// store the field IDs and delete the missing fields
|
||||||
// alternatively, we could delete all the fields and re add them
|
// alternatively, we could delete all the fields and re add them
|
||||||
$missingFields = array();
|
$missingFields = array();
|
||||||
@ -169,10 +164,6 @@ class FieldEditor extends FormField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($record->hasMethod('customFormSave')) {
|
|
||||||
$record->customFormSave($_REQUEST[$name], $record);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,6 +174,7 @@ class FieldEditor extends FormField {
|
|||||||
*/
|
*/
|
||||||
public function addfield() {
|
public function addfield() {
|
||||||
// get the last field in this form editor
|
// get the last field in this form editor
|
||||||
|
Debug::show($this->form->getRecord());
|
||||||
$parentID = $this->form->getRecord()->ID;
|
$parentID = $this->form->getRecord()->ID;
|
||||||
|
|
||||||
if($parentID) {
|
if($parentID) {
|
||||||
|
@ -6,7 +6,190 @@
|
|||||||
|
|
||||||
class EditableFormFieldTest extends FunctionalTest {
|
class EditableFormFieldTest extends FunctionalTest {
|
||||||
|
|
||||||
static $fixture_file = 'userforms/tests/EditableFormFields.yml';
|
static $fixture_file = 'userforms/tests/UserDefinedFormTest.yml';
|
||||||
|
|
||||||
|
function testFormFieldPermissions() {
|
||||||
|
$text = $this->objFromFixture('EditableTextField', 'basic-text');
|
||||||
|
|
||||||
|
$this->logInWithPermission('ADMIN');
|
||||||
|
$this->assertTrue($text->canEdit());
|
||||||
|
$this->assertTrue($text->canDelete());
|
||||||
|
|
||||||
|
$text->setReadonly(true);
|
||||||
|
$this->assertFalse($text->canEdit());
|
||||||
|
$this->assertFalse($text->canDelete());
|
||||||
|
|
||||||
|
$text->setReadonly(false);
|
||||||
|
$this->assertTrue($text->canEdit());
|
||||||
|
$this->assertTrue($text->canDelete());
|
||||||
|
|
||||||
|
$member = Member::currentUser();
|
||||||
|
$member->logout();
|
||||||
|
|
||||||
|
$this->logInWithPermission('SITETREE_VIEW_ALL');
|
||||||
|
$text->setReadonly(false);
|
||||||
|
$this->assertFalse($text->canEdit());
|
||||||
|
$this->assertFalse($text->canDelete());
|
||||||
|
|
||||||
|
$text->setReadonly(true);
|
||||||
|
$this->assertFalse($text->canEdit());
|
||||||
|
$this->assertFalse($text->canDelete());
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGettingAndSettingSettings() {
|
||||||
|
$text = $this->objFromFixture('EditableTextField', 'basic-text');
|
||||||
|
|
||||||
|
$this->logInWithPermission('ADMIN');
|
||||||
|
|
||||||
|
$this->assertEquals($text->getSettings(), array());
|
||||||
|
$text->setSetting('Test', 'Value');
|
||||||
|
$text->write();
|
||||||
|
|
||||||
|
$this->assertEquals($text->getSetting('Test'), 'Value');
|
||||||
|
$this->assertEquals($text->getSettings(), array('Test' => 'Value'));
|
||||||
|
|
||||||
|
$text->setSetting('Foo', 'Bar');
|
||||||
|
$text->write();
|
||||||
|
|
||||||
|
$this->assertEquals($text->getSetting('Foo'), 'Bar');
|
||||||
|
$this->assertEquals($text->getSettings(), array('Test' => 'Value', 'Foo' => 'Bar'));
|
||||||
|
|
||||||
|
// test overridding an existing setting
|
||||||
|
$text->setSetting('Foo', 'Baz');
|
||||||
|
$text->write();
|
||||||
|
|
||||||
|
$this->assertEquals($text->getSetting('Foo'), 'Baz');
|
||||||
|
$this->assertEquals($text->getSettings(), array('Test' => 'Value', 'Foo' => 'Baz'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testShowOnLoad() {
|
||||||
|
$text = $this->objFromFixture('EditableTextField', 'basic-text');
|
||||||
|
|
||||||
|
$this->logInWithPermission('ADMIN');
|
||||||
|
$this->assertTrue($text->getShowOnLoad());
|
||||||
|
|
||||||
|
$text->setSetting('ShowOnLoad', 'Show');
|
||||||
|
$this->assertTrue($text->getShowOnLoad());
|
||||||
|
|
||||||
|
$text->setSetting('ShowOnLoad', 'Hide');
|
||||||
|
$this->assertFalse($text->getShowOnLoad());
|
||||||
|
|
||||||
|
$text->setSetting('ShowOnLoad', '');
|
||||||
|
$this->assertTrue($text->getShowOnLoad());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function testPopulateFromPostData() {
|
||||||
|
$this->logInWithPermission('ADMIN');
|
||||||
|
$set = new DataObjectSet();
|
||||||
|
|
||||||
|
$field = new EditableFormField();
|
||||||
|
|
||||||
|
$data = array(
|
||||||
|
'Title' => 'Field Title',
|
||||||
|
'Default' => 'Default Value',
|
||||||
|
'Sort' => '2',
|
||||||
|
'Required' => 0,
|
||||||
|
'CustomErrorMessage' => 'Custom'
|
||||||
|
);
|
||||||
|
|
||||||
|
$field->populateFromPostData($data);
|
||||||
|
$set->push($field);
|
||||||
|
$this->assertDOSEquals(array($data), $set);
|
||||||
|
|
||||||
|
// test the custom settings
|
||||||
|
$data['CustomSettings'] = array(
|
||||||
|
'Foo' => 'Bar'
|
||||||
|
);
|
||||||
|
|
||||||
|
$checkbox = new EditableCheckbox();
|
||||||
|
$checkbox->write();
|
||||||
|
|
||||||
|
$checkbox->populateFromPostData(array('Title' => 'Checkbox'));
|
||||||
|
|
||||||
|
$field->populateFromPostData($data);
|
||||||
|
|
||||||
|
$this->assertEquals($field->getSettings(), array('Foo' => 'Bar'));
|
||||||
|
|
||||||
|
$rule = array(
|
||||||
|
'Display' => 'Hide',
|
||||||
|
'ConditionField' => $checkbox->Name,
|
||||||
|
'ConditionOption' => 'HasValue',
|
||||||
|
'Value' => 6
|
||||||
|
);
|
||||||
|
|
||||||
|
// test the custom rules
|
||||||
|
$data['CustomRules'] = array(
|
||||||
|
'Rule1' => $rule
|
||||||
|
);
|
||||||
|
|
||||||
|
$field->populateFromPostData($data);
|
||||||
|
|
||||||
|
$rules = unserialize($field->CustomRules);
|
||||||
|
|
||||||
|
$this->assertEquals($rules[0], $rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testCustomRules() {
|
||||||
|
$this->logInWithPermission('ADMIN');
|
||||||
|
$form = $this->objFromFixture('UserDefinedForm', 'custom-rules-form');
|
||||||
|
|
||||||
|
$checkbox = $form->Fields()->find('ClassName', 'EditableCheckbox');
|
||||||
|
$field = $form->Fields()->find('ClassName', 'EditableTextField');
|
||||||
|
|
||||||
|
$rule = array(
|
||||||
|
'Display' => 'Hide',
|
||||||
|
'ConditionField' => $checkbox->Name,
|
||||||
|
'ConditionOption' => 'HasValue',
|
||||||
|
'Value' => 6
|
||||||
|
);
|
||||||
|
|
||||||
|
$data['CustomRules'] = array(
|
||||||
|
'Rule1' => $rule
|
||||||
|
);
|
||||||
|
|
||||||
|
$field->populateFromPostData($data);
|
||||||
|
|
||||||
|
$rules = $field->CustomRules();
|
||||||
|
|
||||||
|
// form has 2 fields - a checkbox and a text field
|
||||||
|
// it has 1 rule - when ticked the checkbox hides the text field
|
||||||
|
$this->assertEquals($rules->Count(), 1);
|
||||||
|
|
||||||
|
// rules are ArrayDatas not dataobjects
|
||||||
|
// $this->assertDOSEquals(array($rule), $rules);
|
||||||
|
|
||||||
|
$checkboxRule = $rules->First();
|
||||||
|
$this->assertEquals($checkboxRule->Display, 'Hide');
|
||||||
|
$this->assertEquals($checkboxRule->ConditionField, $checkbox->Name);
|
||||||
|
$this->assertEquals($checkboxRule->ConditionOption, 'HasValue');
|
||||||
|
$this->assertEquals($checkboxRule->Value, '6');
|
||||||
|
|
||||||
|
foreach($checkboxRule->Fields as $condition) {
|
||||||
|
if($checkbox->Name == $condition->Name) {
|
||||||
|
$this->assertTrue($condition->isSelected);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->assertFalse($condition->isSelected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['CustomRules'] = array(
|
||||||
|
'Rule2' => array(
|
||||||
|
'Display' => 'Hide',
|
||||||
|
'ConditionField' => $checkbox->Name,
|
||||||
|
'ConditionOption' => 'Blank'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$field->populateFromPostData($data);
|
||||||
|
|
||||||
|
$rules = $field->CustomRules();
|
||||||
|
|
||||||
|
// test that saving additional rules deletes the old one
|
||||||
|
$this->assertEquals($rules->Count(), 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function testEditableDropdownField() {
|
function testEditableDropdownField() {
|
||||||
$dropdown = $this->objFromFixture('EditableDropdown', 'basic-dropdown');
|
$dropdown = $this->objFromFixture('EditableDropdown', 'basic-dropdown');
|
||||||
@ -42,4 +225,34 @@ class EditableFormFieldTest extends FunctionalTest {
|
|||||||
|
|
||||||
$this->assertEquals(array('Option 1' => 'Option 1', 'Option 2' => 'Option 2'), $values);
|
$this->assertEquals(array('Option 1' => 'Option 1', 'Option 2' => 'Option 2'), $values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testTitleField() {
|
||||||
|
$text = $this->objFromFixture('EditableTextField', 'basic-text');
|
||||||
|
$this->logInWithPermission('ADMIN');
|
||||||
|
|
||||||
|
$title = $text->TitleField();
|
||||||
|
|
||||||
|
$this->assertThat($title, $this->isInstanceOf('TextField'));
|
||||||
|
$this->assertEquals($title->Title(), "Enter Question");
|
||||||
|
$this->assertEquals($title->Value(), "Basic Text Field");
|
||||||
|
|
||||||
|
$member = Member::currentUser();
|
||||||
|
$member->logOut();
|
||||||
|
|
||||||
|
// read only version
|
||||||
|
$title = $text->TitleField();
|
||||||
|
|
||||||
|
$this->assertThat($title, $this->isInstanceOf('ReadonlyField'));
|
||||||
|
$this->assertEquals($title->Title(), "Enter Question");
|
||||||
|
$this->assertEquals($title->Value(), "Basic Text Field");
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGettingFieldAndSettingNames() {
|
||||||
|
$text = $this->objFromFixture('EditableTextField', 'basic-text');
|
||||||
|
|
||||||
|
$this->assertEquals($text->getFieldName(), "Fields[". $text->ID ."]");
|
||||||
|
$this->assertEquals($text->getFieldName('Setting'), "Fields[". $text->ID ."][Setting]");
|
||||||
|
|
||||||
|
$this->assertEquals($text->getSettingFieldName('Foo'), "Fields[". $text->ID ."][CustomSettings][Foo]");
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,62 +0,0 @@
|
|||||||
EditableOption:
|
|
||||||
option-1:
|
|
||||||
Name: Option1
|
|
||||||
Title: Option 1
|
|
||||||
Sort: 1
|
|
||||||
|
|
||||||
option-2:
|
|
||||||
Name: Option2
|
|
||||||
Title: Option 2
|
|
||||||
Sort: 2
|
|
||||||
|
|
||||||
department-1:
|
|
||||||
Name: dept1
|
|
||||||
Title: sales@example.com
|
|
||||||
|
|
||||||
department-2:
|
|
||||||
Name: dept2
|
|
||||||
Title: accounts@example.com
|
|
||||||
|
|
||||||
EditableTextField:
|
|
||||||
basic-text:
|
|
||||||
Name: basic-text-name
|
|
||||||
Title: Basic Text Field
|
|
||||||
|
|
||||||
required-text:
|
|
||||||
Name: required-text-field
|
|
||||||
Title: Required Text Field
|
|
||||||
CustomErrorMessage: Custom Error Message
|
|
||||||
RightTitle: Right Title
|
|
||||||
Required: true
|
|
||||||
|
|
||||||
EditableRadioField:
|
|
||||||
radio-field:
|
|
||||||
Name: radio-option
|
|
||||||
Title: Radio Option
|
|
||||||
|
|
||||||
EditableDropdown:
|
|
||||||
basic-dropdown:
|
|
||||||
Name: basic-dropdown
|
|
||||||
Title: Basic Dropdown Field
|
|
||||||
Options: =>EditableOption.option-1, =>EditableOption.option-2
|
|
||||||
|
|
||||||
department-dropdown:
|
|
||||||
Name: department
|
|
||||||
Title: Department
|
|
||||||
Options: =>EditableOption.department-1, =>EditableOption.department-2
|
|
||||||
|
|
||||||
EditableCheckbox:
|
|
||||||
checkbox-1:
|
|
||||||
Name: checkbox-1
|
|
||||||
Title: Checkbox 1
|
|
||||||
|
|
||||||
EditableEmailField:
|
|
||||||
email-field:
|
|
||||||
Name: email-field
|
|
||||||
Title: Email
|
|
||||||
|
|
||||||
EditableCheckboxGroupField:
|
|
||||||
checkbox-group:
|
|
||||||
Name: check-box-group
|
|
||||||
Title: Check box group
|
|
||||||
Options: =>EditableOption.option-1, =>EditableOption.option-2
|
|
@ -11,27 +11,36 @@ class FieldEditorTest extends FunctionalTest {
|
|||||||
|
|
||||||
static $fixture_file = 'userforms/tests/UserDefinedFormTest.yml';
|
static $fixture_file = 'userforms/tests/UserDefinedFormTest.yml';
|
||||||
|
|
||||||
function testPerformReadonlyTransformation() {
|
protected $editor;
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
|
||||||
|
|
||||||
|
$controller = new FieldEditorTest_Controller($form);
|
||||||
|
|
||||||
|
$fields = $controller->Form()->Fields();
|
||||||
|
|
||||||
|
$this->editor = $fields->fieldByName('Fields');
|
||||||
}
|
}
|
||||||
|
|
||||||
function testSaveInto() {
|
function testSaveInto() {
|
||||||
|
$this->logInWithPermission('ADMIN');
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testAddField() {
|
function testAddField() {
|
||||||
|
$this->logInWithPermission('ADMIN');
|
||||||
|
|
||||||
}
|
// Debug::show($this->editor->addfield());
|
||||||
|
|
||||||
function testAddOptionField() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function testCreatableFields() {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FieldEditorTest_Controller extends Controller {
|
class FieldEditorTest_Controller extends Controller {
|
||||||
|
|
||||||
|
function Form() {
|
||||||
|
return new Form($this, 'Form', new FieldSet(new FieldEditor('Fields')), new FieldSet());
|
||||||
|
}
|
||||||
}
|
}
|
@ -39,6 +39,10 @@ EditableTextField:
|
|||||||
Name: basic-text-name
|
Name: basic-text-name
|
||||||
Title: Basic Text Field
|
Title: Basic Text Field
|
||||||
|
|
||||||
|
basic-text-2:
|
||||||
|
Name: basic-text-name
|
||||||
|
Title: Basic Text Field
|
||||||
|
|
||||||
required-text:
|
required-text:
|
||||||
Name: required-text-field
|
Name: required-text-field
|
||||||
Title: Required Text Field
|
Title: Required Text Field
|
||||||
@ -61,11 +65,29 @@ EditableCheckbox:
|
|||||||
Name: checkbox-1
|
Name: checkbox-1
|
||||||
Title: Checkbox 1
|
Title: Checkbox 1
|
||||||
|
|
||||||
|
checkbox-2:
|
||||||
|
Name: checkbox-1
|
||||||
|
Title: Checkbox 1
|
||||||
|
|
||||||
|
EditableCheckboxGroupField:
|
||||||
|
checkbox-group:
|
||||||
|
Name: check-box-group
|
||||||
|
Title: Check box group
|
||||||
|
Options: =>EditableOption.option-1, =>EditableOption.option-2
|
||||||
|
|
||||||
EditableEmailField:
|
EditableEmailField:
|
||||||
email-field:
|
email-field:
|
||||||
Name: email-field
|
Name: email-field
|
||||||
Title: Email
|
Title: Email
|
||||||
|
|
||||||
|
|
||||||
|
EditableRadioField:
|
||||||
|
radio-field:
|
||||||
|
Name: radio-option
|
||||||
|
Title: Radio Option
|
||||||
|
Options: =>EditableOption.option-1, =>EditableOption.option-2
|
||||||
|
|
||||||
|
|
||||||
UserDefinedForm:
|
UserDefinedForm:
|
||||||
basic-form-page:
|
basic-form-page:
|
||||||
Title: User Defined Form
|
Title: User Defined Form
|
||||||
@ -81,6 +103,10 @@ UserDefinedForm:
|
|||||||
Title: Validation Form
|
Title: Validation Form
|
||||||
Fields: =>EditableTextField.required-text
|
Fields: =>EditableTextField.required-text
|
||||||
|
|
||||||
|
custom-rules-form:
|
||||||
|
Title: Custom Rules Form
|
||||||
|
Fields: =>EditableCheckbox.checkbox-2, =>EditableTextField.basic-text-2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user