3 use Wikimedia\TestingAccessWrapper
;
6 * Test class for ChangesListSpecialPage class
8 * Copyright © 2011-, Antoine Musso, Stephane Bisson, Matthew Flaschen
10 * @author Antoine Musso
11 * @author Stephane Bisson
12 * @author Matthew Flaschen
15 * @covers ChangesListSpecialPage
17 class ChangesListSpecialPageTest
extends AbstractChangesListSpecialPageTestCase
{
18 protected function getPage() {
19 $mock = $this->getMockBuilder( ChangesListSpecialPage
::class )
22 'ChangesListSpecialPage',
26 ->setMethods( [ 'getPageTitle' ] )
27 ->getMockForAbstractClass();
29 $mock->method( 'getPageTitle' )->willReturn(
30 Title
::makeTitle( NS_SPECIAL
, 'ChangesListSpecialPage' )
33 $mock = TestingAccessWrapper
::newFromObject(
40 private function buildQuery(
41 $requestOptions = null,
44 $context = new RequestContext
;
45 $context->setRequest( new FauxRequest( $requestOptions ) );
47 $context->setUser( $user );
50 $this->changesListSpecialPage
->setContext( $context );
51 $this->changesListSpecialPage
->filterGroups
= [];
52 $formOptions = $this->changesListSpecialPage
->setup( null );
54 # Filter out rc_timestamp conditions which depends on the test runtime
55 # This condition is not needed as of march 2, 2011 -- hashar
56 # @todo FIXME: Find a way to generate the correct rc_timestamp
60 $queryConditions = [];
65 [ $this->changesListSpecialPage
, 'buildQuery' ],
76 $queryConditions = array_filter(
78 'ChangesListSpecialPageTest::filterOutRcTimestampCondition'
81 return $queryConditions;
84 /** helper to test SpecialRecentchanges::buildQuery() */
85 private function assertConditions(
87 $requestOptions = null,
91 $queryConditions = $this->buildQuery( $requestOptions, $user );
94 self
::normalizeCondition( $expected ),
95 self
::normalizeCondition( $queryConditions ),
100 private static function normalizeCondition( $conds ) {
101 $dbr = wfGetDB( DB_REPLICA
);
102 $normalized = array_map(
103 function ( $k, $v ) use ( $dbr ) {
104 if ( is_array( $v ) ) {
107 // (Ab)use makeList() to format only this entry
108 return $dbr->makeList( [ $k => $v ], Database
::LIST_AND
);
110 array_keys( $conds ),
117 /** return false if condition begins with 'rc_timestamp ' */
118 private static function filterOutRcTimestampCondition( $var ) {
119 return ( is_array( $var ) ||
strpos( $var, 'rc_timestamp ' ) === false );
122 public function testRcNsFilter() {
123 $this->assertConditions(
125 "rc_namespace = '0'",
128 'namespace' => NS_MAIN
,
130 "rc conditions with one namespace"
134 public function testRcNsFilterInversion() {
135 $this->assertConditions(
137 "rc_namespace != '0'",
140 'namespace' => NS_MAIN
,
143 "rc conditions with namespace inverted"
147 public function testRcNsFilterMultiple() {
148 $this->assertConditions(
150 "rc_namespace IN ('1','2','3')",
153 'namespace' => '1;2;3',
155 "rc conditions with multiple namespaces"
159 public function testRcNsFilterMultipleAssociated() {
160 $this->assertConditions(
162 "rc_namespace IN ('0','1','4','5','6','7')",
165 'namespace' => '1;4;7',
168 "rc conditions with multiple namespaces and associated"
172 public function testRcNsFilterMultipleAssociatedInvert() {
173 $this->assertConditions(
175 "rc_namespace NOT IN ('2','3','8','9')",
178 'namespace' => '2;3;9',
182 "rc conditions with multiple namespaces, associated and inverted"
186 public function testRcNsFilterMultipleInvert() {
187 $this->assertConditions(
189 "rc_namespace NOT IN ('1','2','3')",
192 'namespace' => '1;2;3',
195 "rc conditions with multiple namespaces inverted"
199 public function testRcHidemyselfFilter() {
200 $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW
);
201 $this->overrideMwServices();
203 $user = $this->getTestUser()->getUser();
204 $user->getActorId( wfGetDB( DB_MASTER
) );
205 $this->assertConditions(
207 "NOT((rc_actor = '{$user->getActorId()}'))",
212 "rc conditions: hidemyself=1 (logged in)",
216 $user = User
::newFromName( '10.11.12.13', false );
217 $id = $user->getActorId( wfGetDB( DB_MASTER
) );
218 $this->assertConditions(
220 "NOT((rc_actor = '{$user->getActorId()}'))",
225 "rc conditions: hidemyself=1 (anon)",
230 public function testRcHidemyselfFilter_old() {
232 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
234 $this->overrideMwServices();
236 $user = $this->getTestUser()->getUser();
237 $user->getActorId( wfGetDB( DB_MASTER
) );
238 $this->assertConditions(
240 "NOT((rc_user = '{$user->getId()}'))",
245 "rc conditions: hidemyself=1 (logged in)",
249 $user = User
::newFromName( '10.11.12.13', false );
250 $id = $user->getActorId( wfGetDB( DB_MASTER
) );
251 $this->assertConditions(
253 "NOT((rc_user_text = '10.11.12.13'))",
258 "rc conditions: hidemyself=1 (anon)",
263 public function testRcHidebyothersFilter() {
264 $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW
);
265 $this->overrideMwServices();
267 $user = $this->getTestUser()->getUser();
268 $user->getActorId( wfGetDB( DB_MASTER
) );
269 $this->assertConditions(
271 "(rc_actor = '{$user->getActorId()}')",
276 "rc conditions: hidebyothers=1 (logged in)",
280 $user = User
::newFromName( '10.11.12.13', false );
281 $id = $user->getActorId( wfGetDB( DB_MASTER
) );
282 $this->assertConditions(
284 "(rc_actor = '{$user->getActorId()}')",
289 "rc conditions: hidebyothers=1 (anon)",
294 public function testRcHidebyothersFilter_old() {
296 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
298 $this->overrideMwServices();
300 $user = $this->getTestUser()->getUser();
301 $user->getActorId( wfGetDB( DB_MASTER
) );
302 $this->assertConditions(
304 "(rc_user_text = '{$user->getName()}')",
309 "rc conditions: hidebyothers=1 (logged in)",
313 $user = User
::newFromName( '10.11.12.13', false );
314 $id = $user->getActorId( wfGetDB( DB_MASTER
) );
315 $this->assertConditions(
317 "(rc_user_text = '10.11.12.13')",
322 "rc conditions: hidebyothers=1 (anon)",
327 public function testRcHidepageedits() {
328 $this->assertConditions(
333 'hidepageedits' => 1,
335 "rc conditions: hidepageedits=1"
339 public function testRcHidenewpages() {
340 $this->assertConditions(
347 "rc conditions: hidenewpages=1"
351 public function testRcHidelog() {
352 $this->assertConditions(
359 "rc conditions: hidelog=1"
363 public function testRcHidehumans() {
364 $this->assertConditions(
372 "rc conditions: hidebots=0 hidehumans=1"
376 public function testRcHidepatrolledDisabledFilter() {
377 $this->setMwGlobals( 'wgUseRCPatrol', false );
378 $user = $this->getTestUser()->getUser();
379 $this->assertConditions(
383 'hidepatrolled' => 1,
385 "rc conditions: hidepatrolled=1 (user not allowed)",
390 public function testRcHideunpatrolledDisabledFilter() {
391 $this->setMwGlobals( 'wgUseRCPatrol', false );
392 $user = $this->getTestUser()->getUser();
393 $this->assertConditions(
397 'hideunpatrolled' => 1,
399 "rc conditions: hideunpatrolled=1 (user not allowed)",
404 public function testRcHidepatrolledFilter() {
405 $user = $this->getTestSysop()->getUser();
406 $this->assertConditions(
411 'hidepatrolled' => 1,
413 "rc conditions: hidepatrolled=1",
418 public function testRcHideunpatrolledFilter() {
419 $user = $this->getTestSysop()->getUser();
420 $this->assertConditions(
422 'rc_patrolled' => [ 1, 2 ],
425 'hideunpatrolled' => 1,
427 "rc conditions: hideunpatrolled=1",
432 public function testRcReviewStatusFilter() {
433 $user = $this->getTestSysop()->getUser();
434 $this->assertConditions(
439 'reviewStatus' => 'manual'
441 "rc conditions: reviewStatus=manual",
444 $this->assertConditions(
446 'rc_patrolled' => [ 0, 2 ],
449 'reviewStatus' => 'unpatrolled;auto'
451 "rc conditions: reviewStatus=unpatrolled;auto",
456 public function testRcHideminorFilter() {
457 $this->assertConditions(
464 "rc conditions: hideminor=1"
468 public function testRcHidemajorFilter() {
469 $this->assertConditions(
476 "rc conditions: hidemajor=1"
480 public function testHideCategorization() {
481 $this->assertConditions(
487 'hidecategorization' => 1
489 "rc conditions: hidecategorization=1"
493 public function testFilterUserExpLevelAll() {
494 $this->assertConditions(
499 'userExpLevel' => 'registered;unregistered;newcomer;learner;experienced',
501 "rc conditions: userExpLevel=registered;unregistered;newcomer;learner;experienced"
505 public function testFilterUserExpLevelRegisteredUnregistered() {
506 $this->assertConditions(
511 'userExpLevel' => 'registered;unregistered',
513 "rc conditions: userExpLevel=registered;unregistered"
517 public function testFilterUserExpLevelRegisteredUnregisteredLearner() {
518 $this->assertConditions(
523 'userExpLevel' => 'registered;unregistered;learner',
525 "rc conditions: userExpLevel=registered;unregistered;learner"
529 public function testFilterUserExpLevelAllExperienceLevels() {
530 $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW
);
531 $this->overrideMwServices();
533 $this->assertConditions(
536 'actor_rc_user.actor_user IS NOT NULL',
539 'userExpLevel' => 'newcomer;learner;experienced',
541 "rc conditions: userExpLevel=newcomer;learner;experienced"
545 public function testFilterUserExpLevelAllExperienceLevels_old() {
547 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
549 $this->overrideMwServices();
551 $this->assertConditions(
557 'userExpLevel' => 'newcomer;learner;experienced',
559 "rc conditions: userExpLevel=newcomer;learner;experienced"
563 public function testFilterUserExpLevelRegistrered() {
564 $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW
);
565 $this->overrideMwServices();
567 $this->assertConditions(
570 'actor_rc_user.actor_user IS NOT NULL',
573 'userExpLevel' => 'registered',
575 "rc conditions: userExpLevel=registered"
579 public function testFilterUserExpLevelRegistrered_old() {
581 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
583 $this->overrideMwServices();
585 $this->assertConditions(
591 'userExpLevel' => 'registered',
593 "rc conditions: userExpLevel=registered"
597 public function testFilterUserExpLevelUnregistrered() {
598 $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW
);
599 $this->overrideMwServices();
601 $this->assertConditions(
604 'actor_rc_user.actor_user IS NULL',
607 'userExpLevel' => 'unregistered',
609 "rc conditions: userExpLevel=unregistered"
613 public function testFilterUserExpLevelUnregistrered_old() {
615 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
617 $this->overrideMwServices();
619 $this->assertConditions(
625 'userExpLevel' => 'unregistered',
627 "rc conditions: userExpLevel=unregistered"
631 public function testFilterUserExpLevelRegistreredOrLearner() {
632 $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW
);
633 $this->overrideMwServices();
635 $this->assertConditions(
638 'actor_rc_user.actor_user IS NOT NULL',
641 'userExpLevel' => 'registered;learner',
643 "rc conditions: userExpLevel=registered;learner"
647 public function testFilterUserExpLevelRegistreredOrLearner_old() {
649 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
651 $this->overrideMwServices();
653 $this->assertConditions(
659 'userExpLevel' => 'registered;learner',
661 "rc conditions: userExpLevel=registered;learner"
665 public function testFilterUserExpLevelUnregistreredOrExperienced() {
666 $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW
);
667 $this->overrideMwServices();
669 $conds = $this->buildQuery( [ 'userExpLevel' => 'unregistered;experienced' ] );
672 '/\(actor_rc_user\.actor_user IS NULL\) OR '
673 . '\(\(user_editcount >= 500\) AND \(user_registration <= \'[^\']+\'\)\)/',
675 "rc conditions: userExpLevel=unregistered;experienced"
679 public function testFilterUserExpLevelUnregistreredOrExperienced_old() {
681 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
683 $this->overrideMwServices();
685 $conds = $this->buildQuery( [ 'userExpLevel' => 'unregistered;experienced' ] );
688 '/\(rc_user = 0\) OR '
689 . '\(\(user_editcount >= 500\) AND \(user_registration <= \'[^\']+\'\)\)/',
691 "rc conditions: userExpLevel=unregistered;experienced"
695 public function testFilterUserExpLevel() {
697 $this->setMwGlobals( [
698 'wgLearnerEdits' => 10,
699 'wgLearnerMemberSince' => 4,
700 'wgExperiencedUserEdits' => 500,
701 'wgExperiencedUserMemberSince' => 30,
704 $this->createUsers( [
705 'Newcomer1' => [ 'edits' => 2, 'days' => 2 ],
706 'Newcomer2' => [ 'edits' => 12, 'days' => 3 ],
707 'Newcomer3' => [ 'edits' => 8, 'days' => 5 ],
708 'Learner1' => [ 'edits' => 15, 'days' => 10 ],
709 'Learner2' => [ 'edits' => 450, 'days' => 20 ],
710 'Learner3' => [ 'edits' => 460, 'days' => 33 ],
711 'Learner4' => [ 'edits' => 525, 'days' => 28 ],
712 'Experienced1' => [ 'edits' => 538, 'days' => 33 ],
716 $this->assertArrayEquals(
717 [ 'Newcomer1', 'Newcomer2', 'Newcomer3' ],
718 $this->fetchUsers( [ 'newcomer' ], $now )
721 // newcomers and learner
722 $this->assertArrayEquals(
724 'Newcomer1', 'Newcomer2', 'Newcomer3',
725 'Learner1', 'Learner2', 'Learner3', 'Learner4',
727 $this->fetchUsers( [ 'newcomer', 'learner' ], $now )
730 // newcomers and more learner
731 $this->assertArrayEquals(
733 'Newcomer1', 'Newcomer2', 'Newcomer3',
736 $this->fetchUsers( [ 'newcomer', 'experienced' ], $now )
740 $this->assertArrayEquals(
741 [ 'Learner1', 'Learner2', 'Learner3', 'Learner4' ],
742 $this->fetchUsers( [ 'learner' ], $now )
745 // more experienced only
746 $this->assertArrayEquals(
748 $this->fetchUsers( [ 'experienced' ], $now )
751 // learner and more experienced
752 $this->assertArrayEquals(
754 'Learner1', 'Learner2', 'Learner3', 'Learner4',
757 $this->fetchUsers( [ 'learner', 'experienced' ], $now )
761 private function createUsers( $specs, $now ) {
762 $dbw = wfGetDB( DB_MASTER
);
763 foreach ( $specs as $name => $spec ) {
767 'editcount' => $spec['edits'],
768 'registration' => $dbw->timestamp( $this->daysAgo( $spec['days'], $now ) ),
775 private function fetchUsers( $filters, $now ) {
784 call_user_func_array(
785 [ $this->changesListSpecialPage
, 'filterOnUserExperienceLevel' ],
787 get_class( $this->changesListSpecialPage
),
788 $this->changesListSpecialPage
->getContext(),
789 $this->changesListSpecialPage
->getDB(),
800 // @todo: This is not at all safe or sane. It just blindly assumes
801 // nothing in $conds depends on any other tables.
802 $result = wfGetDB( DB_MASTER
)->select(
805 array_filter( $conds ) +
[ 'user_email' => 'ut' ]
809 foreach ( $result as $row ) {
810 $usernames[] = $row->user_name
;
816 private function daysAgo( $days, $now ) {
817 $secondsPerDay = 86400;
818 return $now - $days * $secondsPerDay;
821 public function testGetStructuredFilterJsData() {
822 $this->changesListSpecialPage
->filterGroups
= [];
826 'name' => 'gub-group',
827 'title' => 'gub-group-title',
828 'class' => ChangesListBooleanFilterGroup
::class,
832 'label' => 'foo-label',
833 'description' => 'foo-description',
835 'showHide' => 'showhidefoo',
840 'label' => 'bar-label',
841 'description' => 'bar-description',
849 'name' => 'des-group',
850 'title' => 'des-group-title',
851 'class' => ChangesListStringOptionsFilterGroup
::class,
852 'isFullCoverage' => true,
856 'label' => 'grault-label',
857 'description' => 'grault-description',
861 'label' => 'garply-label',
862 'description' => 'garply-description',
865 'queryCallable' => function () {
867 'default' => ChangesListStringOptionsFilterGroup
::NONE
,
871 'name' => 'unstructured',
872 'class' => ChangesListBooleanFilterGroup
::class,
875 'name' => 'hidethud',
876 'showHide' => 'showhidethud',
882 'showHide' => 'showhidemos',
890 $this->changesListSpecialPage
->registerFiltersFromDefinitions( $definition );
892 $this->assertArrayEquals(
894 // Filters that only display in the unstructured UI are
895 // are not included, and neither are groups that would
896 // be empty due to the above.
899 'name' => 'gub-group',
900 'title' => 'gub-group-title',
901 'type' => ChangesListBooleanFilterGroup
::TYPE
,
906 'label' => 'bar-label',
907 'description' => 'bar-description',
913 'defaultHighlightColor' => null
917 'label' => 'foo-label',
918 'description' => 'foo-description',
924 'defaultHighlightColor' => null
927 'fullCoverage' => true,
932 'name' => 'des-group',
933 'title' => 'des-group-title',
934 'type' => ChangesListStringOptionsFilterGroup
::TYPE
,
936 'fullCoverage' => true,
940 'label' => 'grault-label',
941 'description' => 'grault-description',
946 'defaultHighlightColor' => null
950 'label' => 'garply-label',
951 'description' => 'garply-description',
956 'defaultHighlightColor' => null
961 'default' => ChangesListStringOptionsFilterGroup
::NONE
,
972 'grault-description',
974 'garply-description',
977 $this->changesListSpecialPage
->getStructuredFilterJsData(),
978 /** ordered= */ false,
983 public function provideParseParameters() {
985 [ 'hidebots', [ 'hidebots' => true ] ],
987 [ 'bots', [ 'hidebots' => false ] ],
989 [ 'hideminor', [ 'hideminor' => true ] ],
991 [ 'minor', [ 'hideminor' => false ] ],
993 [ 'hidemajor', [ 'hidemajor' => true ] ],
995 [ 'hideliu', [ 'hideliu' => true ] ],
997 [ 'hidepatrolled', [ 'hidepatrolled' => true ] ],
999 [ 'hideunpatrolled', [ 'hideunpatrolled' => true ] ],
1001 [ 'hideanons', [ 'hideanons' => true ] ],
1003 [ 'hidemyself', [ 'hidemyself' => true ] ],
1005 [ 'hidebyothers', [ 'hidebyothers' => true ] ],
1007 [ 'hidehumans', [ 'hidehumans' => true ] ],
1009 [ 'hidepageedits', [ 'hidepageedits' => true ] ],
1011 [ 'pagedits', [ 'hidepageedits' => false ] ],
1013 [ 'hidenewpages', [ 'hidenewpages' => true ] ],
1015 [ 'hidecategorization', [ 'hidecategorization' => true ] ],
1017 [ 'hidelog', [ 'hidelog' => true ] ],
1020 'userExpLevel=learner;experienced',
1022 'userExpLevel' => 'learner;experienced'
1026 // A few random combos
1028 'bots,hideliu,hidemyself',
1030 'hidebots' => false,
1032 'hidemyself' => true,
1037 'minor,hideanons,categorization',
1039 'hideminor' => false,
1040 'hideanons' => true,
1041 'hidecategorization' => false,
1046 'hidehumans,bots,hidecategorization',
1048 'hidehumans' => true,
1049 'hidebots' => false,
1050 'hidecategorization' => true,
1055 'hidemyself,userExpLevel=newcomer;learner,hideminor',
1057 'hidemyself' => true,
1058 'hideminor' => true,
1059 'userExpLevel' => 'newcomer;learner',
1065 public function provideGetFilterConflicts() {
1069 "expectedConflicts" => false,
1074 "userExpLevel" => "newcomer",
1076 "expectedConflicts" => false,
1080 "hideanons" => true,
1081 "userExpLevel" => "learner",
1083 "expectedConflicts" => false,
1087 "hidemajor" => true,
1088 "hidenewpages" => true,
1089 "hidepageedits" => true,
1090 "hidecategorization" => false,
1092 "hideWikidata" => true,
1094 "expectedConflicts" => true,
1098 "hidemajor" => true,
1099 "hidenewpages" => false,
1100 "hidepageedits" => true,
1101 "hidecategorization" => false,
1103 "hideWikidata" => true,
1105 "expectedConflicts" => true,
1109 "hidemajor" => true,
1110 "hidenewpages" => false,
1111 "hidepageedits" => false,
1112 "hidecategorization" => true,
1114 "hideWikidata" => true,
1116 "expectedConflicts" => false,
1120 "hideminor" => true,
1121 "hidenewpages" => true,
1122 "hidepageedits" => true,
1123 "hidecategorization" => false,
1125 "hideWikidata" => true,
1127 "expectedConflicts" => false,
1133 * @dataProvider provideGetFilterConflicts
1135 public function testGetFilterConflicts( $parameters, $expectedConflicts ) {
1136 $context = new RequestContext
;
1137 $context->setRequest( new FauxRequest( $parameters ) );
1138 $this->changesListSpecialPage
->setContext( $context );
1140 $this->assertEquals(
1142 $this->changesListSpecialPage
->areFiltersInConflict()
1146 public function validateOptionsProvider() {
1149 [ 'hideanons' => 1, 'hideliu' => 1, 'hidebots' => 1 ],
1151 [ 'userExpLevel' => 'unregistered', 'hidebots' => 1, ],
1155 [ 'hideanons' => 1, 'hideliu' => 1, 'hidebots' => 0 ],
1157 [ 'hidebots' => 0, 'hidehumans' => 1 ],
1161 [ 'hideanons' => 1 ],
1163 [ 'userExpLevel' => 'registered' ],
1169 [ 'userExpLevel' => 'unregistered' ],
1173 [ 'hideanons' => 1, 'hidebots' => 1 ],
1175 [ 'userExpLevel' => 'registered', 'hidebots' => 1 ],
1179 [ 'hideliu' => 1, 'hidebots' => 0 ],
1181 [ 'userExpLevel' => 'unregistered', 'hidebots' => 0 ],
1185 [ 'hidemyself' => 1, 'hidebyothers' => 1 ],
1191 [ 'hidebots' => 1, 'hidehumans' => 1 ],
1197 [ 'hidepatrolled' => 1, 'hideunpatrolled' => 1 ],
1203 [ 'hideminor' => 1, 'hidemajor' => 1 ],
1210 [ 'hidepageedits' => 1, 'hidenewpages' => 1, 'hidecategorization' => 1, 'hidelog' => 1, ],