|  |  | @ -61,7 +61,7 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 	protected static ?array $nextChatRequestParameters = null; | 
			
		
	
		
			
				
					|  |  |  | 	/** @var array<string, int> */ | 
			
		
	
		
			
				
					|  |  |  | 	protected static array $modifiedSince; | 
			
		
	
		
			
				
					|  |  |  | 	/** @var array<string, string> */ | 
			
		
	
		
			
				
					|  |  |  | 	/** @var array */ | 
			
		
	
		
			
				
					|  |  |  | 	protected static array $createdTeams = []; | 
			
		
	
		
			
				
					|  |  |  | 	/** @var array<string, int> */ | 
			
		
	
		
			
				
					|  |  |  | 	protected static array $userToBanId; | 
			
		
	
	
		
			
				
					|  |  | @ -86,9 +86,15 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 	/** @var CookieJar[] */ | 
			
		
	
		
			
				
					|  |  |  | 	private array $cookieJars; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	protected string $localServerUrl; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	protected string $localRemoteServerUrl; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	protected string $remoteServerUrl; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	protected string $baseUrl; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	protected string $baseRemoteUrl; | 
			
		
	
		
			
				
					|  |  |  | 	protected string $currentServer; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	/** @var string[] */ | 
			
		
	
		
			
				
					|  |  |  | 	protected array $createdUsers = []; | 
			
		
	
	
		
			
				
					|  |  | @ -106,9 +112,9 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	private ?SharingContext $sharingContext; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	private ?bool $guestsAppWasEnabled = null; | 
			
		
	
		
			
				
					|  |  |  | 	private array $guestsAppWasEnabled = []; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	private string $guestsOldWhitelist; | 
			
		
	
		
			
				
					|  |  |  | 	private array $guestsOldWhitelist = []; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	use CommandLineTrait; | 
			
		
	
		
			
				
					|  |  |  | 	use RecordingTrait; | 
			
		
	
	
		
			
				
					|  |  | @ -117,8 +123,8 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 		return self::$identifierToToken[$identifier]; | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	public static function getTeamIdForLabel(string $label): string { | 
			
		
	
		
			
				
					|  |  |  | 		return self::$createdTeams[$label] ?? throw new \RuntimeException('Unknown team: ' . $label); | 
			
		
	
		
			
				
					|  |  |  | 	public static function getTeamIdForLabel(string $server, string $label): string { | 
			
		
	
		
			
				
					|  |  |  | 		return self::$createdTeams[$server][$label] ?? throw new \RuntimeException('Unknown team: ' . $label); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	public static function getMessageIdForText(string $text): int { | 
			
		
	
	
		
			
				
					|  |  | @ -158,14 +164,21 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 	 */ | 
			
		
	
		
			
				
					|  |  |  | 	public function __construct() { | 
			
		
	
		
			
				
					|  |  |  | 		$this->cookieJars = []; | 
			
		
	
		
			
				
					|  |  |  | 		$this->baseUrl = getenv('TEST_SERVER_URL'); | 
			
		
	
		
			
				
					|  |  |  | 		$this->baseRemoteUrl = getenv('TEST_REMOTE_URL'); | 
			
		
	
		
			
				
					|  |  |  | 		$this->localServerUrl = getenv('TEST_SERVER_URL'); | 
			
		
	
		
			
				
					|  |  |  | 		$this->localRemoteServerUrl = getenv('TEST_LOCAL_REMOTE_URL'); | 
			
		
	
		
			
				
					|  |  |  | 		$this->remoteServerUrl = getenv('TEST_REMOTE_URL'); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		foreach (['LOCAL', 'REMOTE'] as $server) { | 
			
		
	
		
			
				
					|  |  |  | 			$this->changedConfigs[$server] = []; | 
			
		
	
		
			
				
					|  |  |  | 			$this->guestsAppWasEnabled[$server] = null; | 
			
		
	
		
			
				
					|  |  |  | 			$this->guestsOldWhitelist[$server] = ''; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	/** | 
			
		
	
		
			
				
					|  |  |  | 	 * @BeforeScenario | 
			
		
	
		
			
				
					|  |  |  | 	 */ | 
			
		
	
		
			
				
					|  |  |  | 	public function setUp() { | 
			
		
	
		
			
				
					|  |  |  | 	public function setUp(BeforeScenarioScope $scope) { | 
			
		
	
		
			
				
					|  |  |  | 		self::$identifierToToken = []; | 
			
		
	
		
			
				
					|  |  |  | 		self::$identifierToId = []; | 
			
		
	
		
			
				
					|  |  |  | 		self::$tokenToIdentifier = []; | 
			
		
	
	
		
			
				
					|  |  | @ -185,10 +198,18 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 		self::$phoneNumberToActorId = []; | 
			
		
	
		
			
				
					|  |  |  | 		self::$modifiedSince = []; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->createdUsers = []; | 
			
		
	
		
			
				
					|  |  |  | 		$this->createdGroups = []; | 
			
		
	
		
			
				
					|  |  |  | 		self::$createdTeams = []; | 
			
		
	
		
			
				
					|  |  |  | 		$this->createdGuestAccountUsers = []; | 
			
		
	
		
			
				
					|  |  |  | 		foreach (['LOCAL', 'REMOTE'] as $server) { | 
			
		
	
		
			
				
					|  |  |  | 			$this->createdUsers[$server] = []; | 
			
		
	
		
			
				
					|  |  |  | 			$this->createdGroups[$server] = []; | 
			
		
	
		
			
				
					|  |  |  | 			self::$createdTeams[$server] = []; | 
			
		
	
		
			
				
					|  |  |  | 			$this->createdGuestAccountUsers[$server] = []; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		// Force getting sibling contexts to ensure that sharingContext is set
 | 
			
		
	
		
			
				
					|  |  |  | 		// before using it.
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->getOtherRequiredSiblingContexts($scope); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->usingServer('LOCAL'); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	/** | 
			
		
	
	
		
			
				
					|  |  | @ -204,18 +225,37 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 	 * @AfterScenario | 
			
		
	
		
			
				
					|  |  |  | 	 */ | 
			
		
	
		
			
				
					|  |  |  | 	public function tearDown() { | 
			
		
	
		
			
				
					|  |  |  | 		foreach ($this->createdUsers as $user) { | 
			
		
	
		
			
				
					|  |  |  | 			$this->deleteUser($user); | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		foreach ($this->createdGroups as $group) { | 
			
		
	
		
			
				
					|  |  |  | 			$this->deleteGroup($group); | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		foreach (self::$createdTeams as $team => $id) { | 
			
		
	
		
			
				
					|  |  |  | 			$this->deleteTeam($team); | 
			
		
	
		
			
				
					|  |  |  | 		foreach (['LOCAL', 'REMOTE'] as $server) { | 
			
		
	
		
			
				
					|  |  |  | 			$this->usingServer($server); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 			foreach ($this->createdUsers[$server] as $user) { | 
			
		
	
		
			
				
					|  |  |  | 				$this->deleteUser($user); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			foreach ($this->createdGroups[$server] as $group) { | 
			
		
	
		
			
				
					|  |  |  | 				$this->deleteGroup($group); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			foreach (self::$createdTeams[$server] as $team => $id) { | 
			
		
	
		
			
				
					|  |  |  | 				$this->deleteTeam($team); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			foreach ($this->createdGuestAccountUsers[$server] as $user) { | 
			
		
	
		
			
				
					|  |  |  | 				$this->deleteGuestUser($user); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		foreach ($this->createdGuestAccountUsers as $user) { | 
			
		
	
		
			
				
					|  |  |  | 			$this->deleteGuestUser($user); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	/** | 
			
		
	
		
			
				
					|  |  |  | 	 * Given /^using server (LOCAL|REMOTE)$/ | 
			
		
	
		
			
				
					|  |  |  | 	 * @param string $server | 
			
		
	
		
			
				
					|  |  |  | 	 */ | 
			
		
	
		
			
				
					|  |  |  | 	public function usingServer(string $server) { | 
			
		
	
		
			
				
					|  |  |  | 		if ($server === 'LOCAL') { | 
			
		
	
		
			
				
					|  |  |  | 			$this->baseUrl = $this->localServerUrl; | 
			
		
	
		
			
				
					|  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  | 			$this->baseUrl = $this->remoteServerUrl; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		$this->currentServer = $server; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->sharingContext->setCurrentServer($this->currentServer, $this->localServerUrl); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	/** | 
			
		
	
	
		
			
				
					|  |  | @ -493,8 +533,9 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (isset($expectedRoom['lastMessageActorId'])) { | 
			
		
	
		
			
				
					|  |  |  | 				$data['lastMessageActorId'] = $room['lastMessage'] ? $room['lastMessage']['actorId'] : ''; | 
			
		
	
		
			
				
					|  |  |  | 				$data['lastMessageActorId'] = str_replace(rtrim($this->baseUrl, '/'), '{$BASE_URL}', $data['lastMessageActorId']); | 
			
		
	
		
			
				
					|  |  |  | 				$data['lastMessageActorId'] = str_replace(rtrim($this->baseRemoteUrl, '/'), '{$REMOTE_URL}', $data['lastMessageActorId']); | 
			
		
	
		
			
				
					|  |  |  | 				$data['lastMessageActorId'] = str_replace(rtrim($this->localServerUrl, '/'), '{$LOCAL_URL}', $data['lastMessageActorId']); | 
			
		
	
		
			
				
					|  |  |  | 				$data['lastMessageActorId'] = str_replace(rtrim($this->localRemoteServerUrl, '/'), '{$LOCAL_REMOTE_URL}', $data['lastMessageActorId']); | 
			
		
	
		
			
				
					|  |  |  | 				$data['lastMessageActorId'] = str_replace(rtrim($this->remoteServerUrl, '/'), '{$REMOTE_URL}', $data['lastMessageActorId']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (isset($expectedRoom['lastReadMessage'])) { | 
			
		
	
		
			
				
					|  |  |  | 				$data['lastReadMessage'] = self::$messageIdToText[(int) $room['lastReadMessage']] ?? (!$room['lastReadMessage'] ? 'ZERO': 'UNKNOWN_MESSAGE'); | 
			
		
	
	
		
			
				
					|  |  | @ -568,8 +609,12 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 		$verb = $acceptsDeclines === 'accepts' ? 'POST' : 'DELETE'; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->setCurrentUser($user); | 
			
		
	
		
			
				
					|  |  |  | 		if ($server === 'LOCAL') { | 
			
		
	
		
			
				
					|  |  |  | 			$this->sendRemoteRequest($verb, '/apps/spreed/api/' . $apiVersion . '/federation/invitation/' . $inviteId); | 
			
		
	
		
			
				
					|  |  |  | 		if ($this->currentServer === 'LOCAL' && $server === 'LOCAL') { | 
			
		
	
		
			
				
					|  |  |  | 			$this->baseUrl = $this->localRemoteServerUrl; | 
			
		
	
		
			
				
					|  |  |  | 			$this->sendRequest($verb, '/apps/spreed/api/' . $apiVersion . '/federation/invitation/' . $inviteId); | 
			
		
	
		
			
				
					|  |  |  | 			$this->baseUrl = $this->localServerUrl; | 
			
		
	
		
			
				
					|  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  | 			$this->sendRequest($verb, '/apps/spreed/api/' . $apiVersion . '/federation/invitation/' . $inviteId); | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		$this->assertStatusCode($this->response, $status); | 
			
		
	
		
			
				
					|  |  |  | 		$response = $this->getDataFromResponse($this->response); | 
			
		
	
	
		
			
				
					|  |  | @ -636,6 +681,9 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 			return 'LOCAL'; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		if ($server === 'localhost:8180') { | 
			
		
	
		
			
				
					|  |  |  | 			return 'LOCAL_REMOTE'; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		if ($server === 'localhost:8280') { | 
			
		
	
		
			
				
					|  |  |  | 			return 'REMOTE'; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		return 'unknown-server'; | 
			
		
	
	
		
			
				
					|  |  | @ -791,8 +839,18 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 					$attendee['actorId'] = sha1(self::$userToSessionId[trim($attendee['actorId'], '"')]); | 
			
		
	
		
			
				
					|  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 				if (isset($attendee['actorId'], $attendee['actorType']) && $attendee['actorType'] === 'federated_users') { | 
			
		
	
		
			
				
					|  |  |  | 					$attendee['actorId'] .= '@' . rtrim($this->baseRemoteUrl, '/'); | 
			
		
	
		
			
				
					|  |  |  | 				if (isset($attendee['actorId']) && str_ends_with($attendee['actorId'], '@{$LOCAL_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 					$attendee['actorId'] = str_replace('{$LOCAL_URL}', rtrim($this->localServerUrl, '/'), $attendee['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  | 				if (isset($attendee['actorId']) && str_ends_with($attendee['actorId'], '@{$LOCAL_REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 					$attendee['actorId'] = str_replace('{$LOCAL_REMOTE_URL}', rtrim($this->localRemoteServerUrl, '/'), $attendee['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  | 				if (isset($attendee['actorId']) && str_ends_with($attendee['actorId'], '@{$REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 					$attendee['actorId'] = str_replace('{$REMOTE_URL}', rtrim($this->remoteServerUrl, '/'), $attendee['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 				if (isset($attendee['actorId'], $attendee['actorType']) && $attendee['actorType'] === 'federated_users' && !str_contains($attendee['actorId'], '@')) { | 
			
		
	
		
			
				
					|  |  |  | 					$attendee['actorId'] .= '@' . rtrim($this->localRemoteServerUrl, '/'); | 
			
		
	
		
			
				
					|  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 				if (isset($attendee['actorId'], $attendee['actorType'], $attendee['phoneNumber']) | 
			
		
	
	
		
			
				
					|  |  | @ -1448,7 +1506,7 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 			$attendeeId = 123456789; | 
			
		
	
		
			
				
					|  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  | 			if ($actorType === 'remote') { | 
			
		
	
		
			
				
					|  |  |  | 				$actorId .= '@' . rtrim($this->baseRemoteUrl, '/'); | 
			
		
	
		
			
				
					|  |  |  | 				$actorId .= '@' . rtrim($this->localRemoteServerUrl, '/'); | 
			
		
	
		
			
				
					|  |  |  | 				$actorType = 'federated_user'; | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  | @ -1480,7 +1538,7 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 			$actorId = '123456789'; | 
			
		
	
		
			
				
					|  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  | 			if ($actorType === 'remote') { | 
			
		
	
		
			
				
					|  |  |  | 				$actorId .= '@' . rtrim($this->baseRemoteUrl, '/'); | 
			
		
	
		
			
				
					|  |  |  | 				$actorId .= '@' . rtrim($this->localRemoteServerUrl, '/'); | 
			
		
	
		
			
				
					|  |  |  | 				$actorType = 'federated_user'; | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
	
		
			
				
					|  |  | @ -1574,7 +1632,7 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 			$actorId = '123456789'; | 
			
		
	
		
			
				
					|  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  | 			if ($actorType === 'remote') { | 
			
		
	
		
			
				
					|  |  |  | 				$actorId .= '@' . rtrim($this->baseRemoteUrl, '/'); | 
			
		
	
		
			
				
					|  |  |  | 				$actorId .= '@' . rtrim($this->localRemoteServerUrl, '/'); | 
			
		
	
		
			
				
					|  |  |  | 				$actorType = 'federated_user'; | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
	
		
			
				
					|  |  | @ -1847,7 +1905,11 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 		$this->setCurrentUser($user); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if ($newType === 'federated_user') { | 
			
		
	
		
			
				
					|  |  |  | 			$newId .= '@' . $this->baseRemoteUrl; | 
			
		
	
		
			
				
					|  |  |  | 			if (!str_contains($newId, '@')) { | 
			
		
	
		
			
				
					|  |  |  | 				$newId .= '@' . $this->localRemoteServerUrl; | 
			
		
	
		
			
				
					|  |  |  | 			} else { | 
			
		
	
		
			
				
					|  |  |  | 				$newId = str_replace('REMOTE', $this->remoteServerUrl, $newId); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->sendRequest( | 
			
		
	
	
		
			
				
					|  |  | @ -2120,8 +2182,9 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 	public function userSendsMessageToRoom(string $user, string $sendingMode, string $message, string $identifier, string $statusCode, string $apiVersion = 'v1') { | 
			
		
	
		
			
				
					|  |  |  | 		$message = substr($message, 1, -1); | 
			
		
	
		
			
				
					|  |  |  | 		$message = str_replace('\n', "\n", $message); | 
			
		
	
		
			
				
					|  |  |  | 		$message = str_replace('{$BASE_URL}', $this->baseUrl, $message); | 
			
		
	
		
			
				
					|  |  |  | 		$message = str_replace('{$REMOTE_URL}', $this->baseRemoteUrl, $message); | 
			
		
	
		
			
				
					|  |  |  | 		$message = str_replace('{$LOCAL_URL}', $this->localServerUrl, $message); | 
			
		
	
		
			
				
					|  |  |  | 		$message = str_replace('{$LOCAL_REMOTE_URL}', $this->localRemoteServerUrl, $message); | 
			
		
	
		
			
				
					|  |  |  | 		$message = str_replace('{$REMOTE_URL}', $this->remoteServerUrl, $message); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if ($message === '413 Payload Too Large') { | 
			
		
	
		
			
				
					|  |  |  | 			$message .= "\n" . str_repeat('1', 32000); | 
			
		
	
	
		
			
				
					|  |  | @ -2403,19 +2466,25 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 			$expected['status'] = 1; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if (str_ends_with($expected['actorId'], '@{$BASE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 			$expected['actorId'] = str_replace('{$BASE_URL}', rtrim($this->baseUrl, '/'), $expected['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 		if (str_ends_with($expected['actorId'], '@{$LOCAL_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 			$expected['actorId'] = str_replace('{$LOCAL_URL}', rtrim($this->localServerUrl, '/'), $expected['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		if (str_ends_with($expected['actorId'], '@{$LOCAL_REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 			$expected['actorId'] = str_replace('{$LOCAL_REMOTE_URL}', rtrim($this->localRemoteServerUrl, '/'), $expected['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		if (str_ends_with($expected['actorId'], '@{$REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 			$expected['actorId'] = str_replace('{$REMOTE_URL}', rtrim($this->baseRemoteUrl, '/'), $expected['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 			$expected['actorId'] = str_replace('{$REMOTE_URL}', rtrim($this->remoteServerUrl, '/'), $expected['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if (isset($expected['details'])) { | 
			
		
	
		
			
				
					|  |  |  | 			if (str_contains($expected['details'], '@{$BASE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$expected['details'] = str_replace('{$BASE_URL}', rtrim($this->baseUrl, '/'), $expected['details']); | 
			
		
	
		
			
				
					|  |  |  | 			if (str_contains($expected['details'], '@{$LOCAL_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$expected['details'] = str_replace('{$LOCAL_URL}', rtrim($this->localServerUrl, '/'), $expected['details']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (str_contains($expected['details'], '@{$LOCAL_REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$expected['details'] = str_replace('{$LOCAL_REMOTE_URL}', rtrim($this->localRemoteServerUrl, '/'), $expected['details']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (str_contains($expected['details'], '@{$REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$expected['details'] = str_replace('{$REMOTE_URL}', rtrim($this->baseRemoteUrl, '/'), $expected['details']); | 
			
		
	
		
			
				
					|  |  |  | 				$expected['details'] = str_replace('{$REMOTE_URL}', rtrim($this->remoteServerUrl, '/'), $expected['details']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  | @ -2865,26 +2934,35 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			$expected[$i]['message'] = str_replace('\n', "\n", $expected[$i]['message']); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 			if (str_ends_with($expected[$i]['actorId'], '@{$BASE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$expected[$i]['actorId'] = str_replace('{$BASE_URL}', rtrim($this->baseUrl, '/'), $expected[$i]['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 			if (str_ends_with($expected[$i]['actorId'], '@{$LOCAL_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$expected[$i]['actorId'] = str_replace('{$LOCAL_URL}', rtrim($this->localServerUrl, '/'), $expected[$i]['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (str_ends_with($expected[$i]['actorId'], '@{$LOCAL_REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$expected[$i]['actorId'] = str_replace('{$LOCAL_REMOTE_URL}', rtrim($this->localRemoteServerUrl, '/'), $expected[$i]['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (str_ends_with($expected[$i]['actorId'], '@{$REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$expected[$i]['actorId'] = str_replace('{$REMOTE_URL}', rtrim($this->baseRemoteUrl, '/'), $expected[$i]['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 				$expected[$i]['actorId'] = str_replace('{$REMOTE_URL}', rtrim($this->remoteServerUrl, '/'), $expected[$i]['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 			if (str_contains($expected[$i]['messageParameters'], '{$BASE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$expected[$i]['messageParameters'] = str_replace('{$BASE_URL}', str_replace('/', '\/', rtrim($this->baseUrl, '/')), $expected[$i]['messageParameters']); | 
			
		
	
		
			
				
					|  |  |  | 			if (str_contains($expected[$i]['messageParameters'], '{$LOCAL_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$expected[$i]['messageParameters'] = str_replace('{$LOCAL_URL}', str_replace('/', '\/', rtrim($this->localServerUrl, '/')), $expected[$i]['messageParameters']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (str_contains($expected[$i]['messageParameters'], '{$LOCAL_REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$expected[$i]['messageParameters'] = str_replace('{$LOCAL_REMOTE_URL}', str_replace('/', '\/', rtrim($this->localRemoteServerUrl, '/')), $expected[$i]['messageParameters']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (str_contains($expected[$i]['messageParameters'], '{$REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$expected[$i]['messageParameters'] = str_replace('{$REMOTE_URL}', str_replace('/', '\/', rtrim($this->baseRemoteUrl, '/')), $expected[$i]['messageParameters']); | 
			
		
	
		
			
				
					|  |  |  | 				$expected[$i]['messageParameters'] = str_replace('{$REMOTE_URL}', str_replace('/', '\/', rtrim($this->remoteServerUrl, '/')), $expected[$i]['messageParameters']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 			if (isset($expected[$i]['lastEditActorId'])) { | 
			
		
	
		
			
				
					|  |  |  | 				if (str_ends_with($expected[$i]['lastEditActorId'], '@{$BASE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 					$expected[$i]['lastEditActorId'] = str_replace('{$BASE_URL}', rtrim($this->baseUrl, '/'), $expected[$i]['lastEditActorId']); | 
			
		
	
		
			
				
					|  |  |  | 				if (str_ends_with($expected[$i]['lastEditActorId'], '@{$LOCAL_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 					$expected[$i]['lastEditActorId'] = str_replace('{$LOCAL_URL}', rtrim($this->localServerUrl, '/'), $expected[$i]['lastEditActorId']); | 
			
		
	
		
			
				
					|  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  | 				if (str_ends_with($expected[$i]['lastEditActorId'], '@{$LOCAL_REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 					$expected[$i]['lastEditActorId'] = str_replace('{$LOCAL_REMOTE_URL}', rtrim($this->localRemoteServerUrl, '/'), $expected[$i]['lastEditActorId']); | 
			
		
	
		
			
				
					|  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  | 				if (str_ends_with($expected[$i]['lastEditActorId'], '@{$REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 					$expected[$i]['lastEditActorId'] = str_replace('{$REMOTE_URL}', rtrim($this->baseRemoteUrl, '/'), $expected[$i]['lastEditActorId']); | 
			
		
	
		
			
				
					|  |  |  | 					$expected[$i]['lastEditActorId'] = str_replace('{$REMOTE_URL}', rtrim($this->remoteServerUrl, '/'), $expected[$i]['lastEditActorId']); | 
			
		
	
		
			
				
					|  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  | @ -3113,17 +3191,23 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 				Assert::assertMatchesRegularExpression('/^guest\/[0-9a-f]{40}$/', $mentions[$key]['mentionId']); | 
			
		
	
		
			
				
					|  |  |  | 				$mentions[$key]['mentionId'] = 'GUEST_ID'; | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (str_ends_with($row['id'], '@{$BASE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$row['id'] = str_replace('{$BASE_URL}', rtrim($this->baseUrl, '/'), $row['id']); | 
			
		
	
		
			
				
					|  |  |  | 			if (str_ends_with($row['id'], '@{$LOCAL_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$row['id'] = str_replace('{$LOCAL_URL}', rtrim($this->localServerUrl, '/'), $row['id']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (str_ends_with($row['id'], '@{$LOCAL_REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$row['id'] = str_replace('{$LOCAL_REMOTE_URL}', rtrim($this->localRemoteServerUrl, '/'), $row['id']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (str_ends_with($row['id'], '@{$REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$row['id'] = str_replace('{$REMOTE_URL}', rtrim($this->baseRemoteUrl, '/'), $row['id']); | 
			
		
	
		
			
				
					|  |  |  | 				$row['id'] = str_replace('{$REMOTE_URL}', rtrim($this->remoteServerUrl, '/'), $row['id']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (str_ends_with($row['mentionId'], '@{$BASE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$row['mentionId'] = str_replace('{$BASE_URL}', rtrim($this->baseUrl, '/'), $row['mentionId']); | 
			
		
	
		
			
				
					|  |  |  | 				$row['mentionId'] = str_replace('{$BASE_URL}', rtrim($this->localServerUrl, '/'), $row['mentionId']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (str_ends_with($row['mentionId'], '@{$LOCAL_REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$row['mentionId'] = str_replace('{$LOCAL_REMOTE_URL}', rtrim($this->localRemoteServerUrl, '/'), $row['mentionId']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (str_ends_with($row['mentionId'], '@{$REMOTE_URL}')) { | 
			
		
	
		
			
				
					|  |  |  | 				$row['mentionId'] = str_replace('{$REMOTE_URL}', rtrim($this->baseRemoteUrl, '/'), $row['mentionId']); | 
			
		
	
		
			
				
					|  |  |  | 				$row['mentionId'] = str_replace('{$REMOTE_URL}', rtrim($this->remoteServerUrl, '/'), $row['mentionId']); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 			if (array_key_exists('avatar', $row)) { | 
			
		
	
		
			
				
					|  |  |  | 				Assert::assertMatchesRegularExpression('/' . self::$identifierToToken[$row['avatar']] . '\/avatar/', $mentions[$key]['avatar']); | 
			
		
	
	
		
			
				
					|  |  | @ -3497,7 +3581,7 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 			$this->sendRequest('POST', '/apps/provisioning_api/api/v1/config/apps/' . $appId . '/' . $row[0], [ | 
			
		
	
		
			
				
					|  |  |  | 				'value' => $row[1], | 
			
		
	
		
			
				
					|  |  |  | 			]); | 
			
		
	
		
			
				
					|  |  |  | 			$this->changedConfigs[$appId][] = $row[0]; | 
			
		
	
		
			
				
					|  |  |  | 			$this->changedConfigs[$this->currentServer][$appId][] = $row[0]; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		$this->setCurrentUser($currentUser); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
	
		
			
				
					|  |  | @ -3565,8 +3649,9 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 					[$roomToken, $message] = explode('/', $notification['object_id']); | 
			
		
	
		
			
				
					|  |  |  | 					$messageText = self::$messageIdToText[$message] ?? 'UNKNOWN_MESSAGE'; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 					$messageText = str_replace($this->baseUrl, '{$BASE_URL}', $messageText); | 
			
		
	
		
			
				
					|  |  |  | 					$messageText = str_replace($this->baseRemoteUrl, '{$REMOTE_URL}', $messageText); | 
			
		
	
		
			
				
					|  |  |  | 					$messageText = str_replace($this->localServerUrl, '{$LOCAL_URL}', $messageText); | 
			
		
	
		
			
				
					|  |  |  | 					$messageText = str_replace($this->localRemoteServerUrl, '{$LOCAL_REMOTE_URL}', $messageText); | 
			
		
	
		
			
				
					|  |  |  | 					$messageText = str_replace($this->remoteServerUrl, '{$REMOTE_URL}', $messageText); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 					$data['object_id'] = self::$tokenToIdentifier[$roomToken] . '/' . $messageText; | 
			
		
	
		
			
				
					|  |  |  | 				} elseif (strpos($expectedNotification['object_id'], 'INVITE_ID') !== false) { | 
			
		
	
	
		
			
				
					|  |  | @ -3609,9 +3694,9 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 		$this->sendRequest('GET', '/cloud/apps?filter=enabled'); | 
			
		
	
		
			
				
					|  |  |  | 		$this->assertStatusCode($this->response, 200); | 
			
		
	
		
			
				
					|  |  |  | 		$data = $this->getDataFromResponse($this->response); | 
			
		
	
		
			
				
					|  |  |  | 		$this->guestsAppWasEnabled = in_array('guests', $data['apps'], true); | 
			
		
	
		
			
				
					|  |  |  | 		$this->guestsAppWasEnabled[$this->currentServer] = in_array('guests', $data['apps'], true); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if (!$this->guestsAppWasEnabled) { | 
			
		
	
		
			
				
					|  |  |  | 		if (!$this->guestsAppWasEnabled[$this->currentServer]) { | 
			
		
	
		
			
				
					|  |  |  | 			// enable Guests app
 | 
			
		
	
		
			
				
					|  |  |  | 			/* | 
			
		
	
		
			
				
					|  |  |  | 			$this->sendRequest('POST', '/cloud/apps/guests'); | 
			
		
	
	
		
			
				
					|  |  | @ -3624,7 +3709,7 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 		// save previously set whitelist
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->sendRequest('GET', '/apps/provisioning_api/api/v1/config/apps/guests/whitelist'); | 
			
		
	
		
			
				
					|  |  |  | 		$this->assertStatusCode($this->response, 200); | 
			
		
	
		
			
				
					|  |  |  | 		$this->guestsOldWhitelist = $this->getDataFromResponse($this->response)['data']; | 
			
		
	
		
			
				
					|  |  |  | 		$this->guestsOldWhitelist[$this->currentServer] = $this->getDataFromResponse($this->response)['data']; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		// set whitelist to allow spreed only
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->sendRequest('POST', '/apps/provisioning_api/api/v1/config/apps/guests/whitelist', [ | 
			
		
	
	
		
			
				
					|  |  | @ -3639,46 +3724,57 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 	 * @AfterScenario | 
			
		
	
		
			
				
					|  |  |  | 	 */ | 
			
		
	
		
			
				
					|  |  |  | 	public function resetSpreedAppData() { | 
			
		
	
		
			
				
					|  |  |  | 		$currentUser = $this->setCurrentUser('admin'); | 
			
		
	
		
			
				
					|  |  |  | 		$this->sendRequest('DELETE', '/apps/spreedcheats/'); | 
			
		
	
		
			
				
					|  |  |  | 		foreach ($this->changedConfigs as $appId => $configs) { | 
			
		
	
		
			
				
					|  |  |  | 			foreach ($configs as $config) { | 
			
		
	
		
			
				
					|  |  |  | 				$this->sendRequest('DELETE', '/apps/provisioning_api/api/v1/config/apps/' . $appId . '/' . $config); | 
			
		
	
		
			
				
					|  |  |  | 		foreach (['LOCAL', 'REMOTE'] as $server) { | 
			
		
	
		
			
				
					|  |  |  | 			$this->usingServer($server); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 			$currentUser = $this->setCurrentUser('admin'); | 
			
		
	
		
			
				
					|  |  |  | 			$this->sendRequest('DELETE', '/apps/spreedcheats/'); | 
			
		
	
		
			
				
					|  |  |  | 			foreach ($this->changedConfigs[$server] as $appId => $configs) { | 
			
		
	
		
			
				
					|  |  |  | 				foreach ($configs as $config) { | 
			
		
	
		
			
				
					|  |  |  | 					$this->sendRequest('DELETE', '/apps/provisioning_api/api/v1/config/apps/' . $appId . '/' . $config); | 
			
		
	
		
			
				
					|  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->setCurrentUser($currentUser); | 
			
		
	
		
			
				
					|  |  |  | 		if ($this->changedBruteforceSetting) { | 
			
		
	
		
			
				
					|  |  |  | 			$this->enableDisableBruteForceProtection('disable'); | 
			
		
	
		
			
				
					|  |  |  | 			$this->setCurrentUser($currentUser); | 
			
		
	
		
			
				
					|  |  |  | 			if ($this->changedBruteforceSetting) { | 
			
		
	
		
			
				
					|  |  |  | 				$this->enableDisableBruteForceProtection('disable'); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->usingServer('LOCAL'); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	/** | 
			
		
	
		
			
				
					|  |  |  | 	 * @AfterScenario | 
			
		
	
		
			
				
					|  |  |  | 	 */ | 
			
		
	
		
			
				
					|  |  |  | 	public function resetGuestsAppState() { | 
			
		
	
		
			
				
					|  |  |  | 		if ($this->guestsAppWasEnabled === null) { | 
			
		
	
		
			
				
					|  |  |  | 			// Guests app was not touched
 | 
			
		
	
		
			
				
					|  |  |  | 			return; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 		foreach (['LOCAL', 'REMOTE'] as $server) { | 
			
		
	
		
			
				
					|  |  |  | 			$this->usingServer($server); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$currentUser = $this->setCurrentUser('admin'); | 
			
		
	
		
			
				
					|  |  |  | 			if ($this->guestsAppWasEnabled[$server] === null) { | 
			
		
	
		
			
				
					|  |  |  | 				// Guests app was not touched
 | 
			
		
	
		
			
				
					|  |  |  | 				return; | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		if ($this->guestsOldWhitelist) { | 
			
		
	
		
			
				
					|  |  |  | 			// restore old whitelist
 | 
			
		
	
		
			
				
					|  |  |  | 			$this->sendRequest('POST', '/apps/provisioning_api/api/v1/config/apps/guests/whitelist', [ | 
			
		
	
		
			
				
					|  |  |  | 				'value' => $this->guestsOldWhitelist, | 
			
		
	
		
			
				
					|  |  |  | 			]); | 
			
		
	
		
			
				
					|  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  | 			// restore to default
 | 
			
		
	
		
			
				
					|  |  |  | 			$this->sendRequest('DELETE', '/apps/provisioning_api/api/v1/config/apps/guests/whitelist'); | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 			$currentUser = $this->setCurrentUser('admin'); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		// restore app's enabled state
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->sendRequest($this->guestsAppWasEnabled ? 'POST' : 'DELETE', '/cloud/apps/guests'); | 
			
		
	
		
			
				
					|  |  |  | 			if ($this->guestsOldWhitelist[$server]) { | 
			
		
	
		
			
				
					|  |  |  | 				// restore old whitelist
 | 
			
		
	
		
			
				
					|  |  |  | 				$this->sendRequest('POST', '/apps/provisioning_api/api/v1/config/apps/guests/whitelist', [ | 
			
		
	
		
			
				
					|  |  |  | 					'value' => $this->guestsOldWhitelist[$server], | 
			
		
	
		
			
				
					|  |  |  | 				]); | 
			
		
	
		
			
				
					|  |  |  | 			} else { | 
			
		
	
		
			
				
					|  |  |  | 				// restore to default
 | 
			
		
	
		
			
				
					|  |  |  | 				$this->sendRequest('DELETE', '/apps/provisioning_api/api/v1/config/apps/guests/whitelist'); | 
			
		
	
		
			
				
					|  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->setCurrentUser($currentUser); | 
			
		
	
		
			
				
					|  |  |  | 		$this->guestsAppWasEnabled = null; | 
			
		
	
		
			
				
					|  |  |  | 			// restore app's enabled state
 | 
			
		
	
		
			
				
					|  |  |  | 			$this->sendRequest($this->guestsAppWasEnabled[$server] ? 'POST' : 'DELETE', '/cloud/apps/guests'); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 			$this->setCurrentUser($currentUser); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 			$this->guestsAppWasEnabled[$server] = null; | 
			
		
	
		
			
				
					|  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	/* | 
			
		
	
	
		
			
				
					|  |  | @ -3793,14 +3889,14 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 		$output = $this->getLastStdOut(); | 
			
		
	
		
			
				
					|  |  |  | 		$data = json_decode($output, true); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		self::$createdTeams[$team] = $data['id']; | 
			
		
	
		
			
				
					|  |  |  | 		self::$createdTeams[$this->currentServer][$team] = $data['id']; | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	/** | 
			
		
	
		
			
				
					|  |  |  | 	 * @Given /^add user "([^"]*)" to team "([^"]*)"$/ | 
			
		
	
		
			
				
					|  |  |  | 	 */ | 
			
		
	
		
			
				
					|  |  |  | 	public function addTeamMember(string $user, string $team): void { | 
			
		
	
		
			
				
					|  |  |  | 		$this->runOcc(['circles:members:add', '--type', '1', self::$createdTeams[$team], $user]); | 
			
		
	
		
			
				
					|  |  |  | 		$this->runOcc(['circles:members:add', '--type', '1', self::$createdTeams[$this->currentServer][$team], $user]); | 
			
		
	
		
			
				
					|  |  |  | 		$this->theCommandWasSuccessful(); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  | @ -3808,10 +3904,10 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 	 * @Given /^delete team "([^"]*)"$/
 | 
			
		
	
		
			
				
					|  |  |  | 	 */ | 
			
		
	
		
			
				
					|  |  |  | 	public function deleteTeam(string $team): void { | 
			
		
	
		
			
				
					|  |  |  | 		$this->runOcc(['circles:manage:destroy', self::$createdTeams[$team]]); | 
			
		
	
		
			
				
					|  |  |  | 		$this->runOcc(['circles:manage:destroy', self::$createdTeams[$this->currentServer][$team]]); | 
			
		
	
		
			
				
					|  |  |  | 		$this->theCommandWasSuccessful(); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		unset(self::$createdTeams[$team]); | 
			
		
	
		
			
				
					|  |  |  | 		unset(self::$createdTeams[$this->currentServer][$team]); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	/** | 
			
		
	
	
		
			
				
					|  |  | @ -3837,7 +3933,7 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 		]); | 
			
		
	
		
			
				
					|  |  |  | 		Assert::assertEquals(0, $lastCode, 'Guest creation succeeded for ' . $email); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->createdGuestAccountUsers[$email] = $email; | 
			
		
	
		
			
				
					|  |  |  | 		$this->createdGuestAccountUsers[$this->currentServer][$email] = $email; | 
			
		
	
		
			
				
					|  |  |  | 		$this->setCurrentUser($currentUser); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  | @ -3861,7 +3957,7 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 		$this->sendRequest('GET', '/cloud/users' . '/' . $user); | 
			
		
	
		
			
				
					|  |  |  | 		$this->assertStatusCode($this->response, 200, 'Failed to do first login'); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->createdUsers[$user] = $user; | 
			
		
	
		
			
				
					|  |  |  | 		$this->createdUsers[$this->currentServer][$user] = $user; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->setCurrentUser($currentUser); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
	
		
			
				
					|  |  | @ -3888,7 +3984,7 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 		$this->sendRequest('DELETE', '/cloud/users/' . $user); | 
			
		
	
		
			
				
					|  |  |  | 		$this->setCurrentUser($currentUser); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		unset($this->createdUsers[$user]); | 
			
		
	
		
			
				
					|  |  |  | 		unset($this->createdUsers[$this->currentServer][$user]); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		return $this->response; | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
	
		
			
				
					|  |  | @ -3898,7 +3994,7 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 		$this->sendRequest('DELETE', '/cloud/users/' . $user); | 
			
		
	
		
			
				
					|  |  |  | 		$this->setCurrentUser($currentUser); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		unset($this->createdGuestAccountUsers[$user]); | 
			
		
	
		
			
				
					|  |  |  | 		unset($this->createdGuestAccountUsers[$this->currentServer][$user]); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		return $this->response; | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
	
		
			
				
					|  |  | @ -3937,7 +4033,7 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->setCurrentUser($currentUser); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		$this->createdGroups[$group] = $group; | 
			
		
	
		
			
				
					|  |  |  | 		$this->createdGroups[$this->currentServer][$group] = $group; | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	/** | 
			
		
	
	
		
			
				
					|  |  | @ -3961,7 +4057,7 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 		$this->sendRequest('DELETE', '/cloud/groups/' . $group); | 
			
		
	
		
			
				
					|  |  |  | 		$this->setCurrentUser($currentUser); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 		unset($this->createdGroups[$group]); | 
			
		
	
		
			
				
					|  |  |  | 		unset($this->createdGroups[$this->currentServer][$group]); | 
			
		
	
		
			
				
					|  |  |  | 		$this->setCurrentUser($currentUser); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  | @ -4053,8 +4149,9 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 				unset($reaction['timestamp']); | 
			
		
	
		
			
				
					|  |  |  | 				$reaction['actorId'] = ($reaction['actorType'] === 'guests') ? self::$sessionIdToUser[$reaction['actorId']] : (string) $reaction['actorId']; | 
			
		
	
		
			
				
					|  |  |  | 				if ($reaction['actorType'] === 'federated_users') { | 
			
		
	
		
			
				
					|  |  |  | 					$reaction['actorId'] = str_replace(rtrim($this->baseUrl, '/'), '{$BASE_URL}', $reaction['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 					$reaction['actorId'] = str_replace(rtrim($this->baseRemoteUrl, '/'), '{$REMOTE_URL}', $reaction['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 					$reaction['actorId'] = str_replace(rtrim($this->localServerUrl, '/'), '{$LOCAL_URL}', $reaction['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 					$reaction['actorId'] = str_replace(rtrim($this->localRemoteServerUrl, '/'), '{$LOCAL_REMOTE_URL}', $reaction['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 					$reaction['actorId'] = str_replace(rtrim($this->remoteServerUrl, '/'), '{$REMOTE_URL}', $reaction['actorId']); | 
			
		
	
		
			
				
					|  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  | 				return $reaction; | 
			
		
	
		
			
				
					|  |  |  | 			}, $list); | 
			
		
	
	
		
			
				
					|  |  | @ -4663,17 +4760,6 @@ class FeatureContext implements Context, SnippetAcceptingContext { | 
			
		
	
		
			
				
					|  |  |  | 		$this->assertStatusCode($this->response, $statusCode); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	/** | 
			
		
	
		
			
				
					|  |  |  | 	 * @param string $verb | 
			
		
	
		
			
				
					|  |  |  | 	 * @param string $url | 
			
		
	
		
			
				
					|  |  |  | 	 * @param TableNode|array|null $body | 
			
		
	
		
			
				
					|  |  |  | 	 * @param array $headers | 
			
		
	
		
			
				
					|  |  |  | 	 */ | 
			
		
	
		
			
				
					|  |  |  | 	public function sendRemoteRequest($verb, $url, $body = null, array $headers = []) { | 
			
		
	
		
			
				
					|  |  |  | 		$fullUrl = $this->baseRemoteUrl . 'ocs/v2.php' . $url; | 
			
		
	
		
			
				
					|  |  |  | 		$this->sendRequestFullUrl($verb, $fullUrl, $body, $headers); | 
			
		
	
		
			
				
					|  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 	/** | 
			
		
	
		
			
				
					|  |  |  | 	 * @param string $verb | 
			
		
	
		
			
				
					|  |  |  | 	 * @param string $fullUrl | 
			
		
	
	
		
			
				
					|  |  | 
 |