mirror of
				https://github.com/Mibew/java.git
				synced 2025-10-31 10:31:07 +03:00 
			
		
		
		
	Added classes that implements plugin system and tests for them
This commit is contained in:
		
							parent
							
								
									3e121c675f
								
							
						
					
					
						commit
						66a0d6ddca
					
				
							
								
								
									
										157
									
								
								src/messenger/tests/webim/libs/classes/EventDispatcherTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								src/messenger/tests/webim/libs/classes/EventDispatcherTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,157 @@ | ||||
| <?php | ||||
| 
 | ||||
| require_once dirname(__FILE__) . '/../../../../webim/libs/classes/event_dispatcher.php'; | ||||
| require_once dirname(__FILE__) . '/../../../../webim/libs/classes/plugin.php'; | ||||
| require_once dirname(__FILE__) . '/phpunit_autotest_plugin_manager/plugin.mibew.inc.php'; | ||||
| 
 | ||||
| /** | ||||
|  * Test class for EventDispatcher. | ||||
|  * Generated by PHPUnit on 2012-07-17 at 16:09:00. | ||||
|  */ | ||||
| class EventDispatcherTest extends PHPUnit_Framework_TestCase { | ||||
| 
 | ||||
| 	protected static $plugin = null; | ||||
| 
 | ||||
| 	public static function setUpBeforeClass() { | ||||
| 		self::$plugin = new Phpunit_autotest_plugin_managerPlugin(); | ||||
| 	} | ||||
| 
 | ||||
| 	public static function tearDownAfterClass() { | ||||
| 		self::$plugin = null; | ||||
| 	} | ||||
| 
 | ||||
| 	public function testGetInstance() { | ||||
| 		$dispatcher = EventDispatcher::getInstance(); | ||||
| 		$another_dispatcher = EventDispatcher::getInstance(); | ||||
| 		$this->assertSame($dispatcher, $another_dispatcher); | ||||
| 		unset($another_dispatcher); | ||||
| 		return $dispatcher; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @depends testGetInstance | ||||
| 	 */ | ||||
| 	public function testRegisterEvent($dispatcher) { | ||||
| 		// Try to register new event
 | ||||
| 		$this->assertTrue($dispatcher->registerEvent('some_test_event')); | ||||
| 		$this->assertTrue($dispatcher->registerEvent('some_another_test_event')); | ||||
| 
 | ||||
| 		// Try to register already registered event
 | ||||
| 		// Following code wait for trigger user error, which converts by PHPUnit to an
 | ||||
| 		// Exception
 | ||||
| 		try{ | ||||
| 			$dispatcher->registerEvent('some_test_event'); | ||||
| 			$this->fail("Error expected!"); | ||||
| 		} catch(Exception $e) {} | ||||
| 		return $dispatcher; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @depends testRegisterEvent | ||||
| 	 */ | ||||
| 	public function testAttachListener($dispatcher) { | ||||
| 		// Try to attach listener to unregistered event
 | ||||
| 		// Following code wait for trigger user error, which converts by PHPUnit to an
 | ||||
| 		// Exception
 | ||||
| 		try{ | ||||
| 			$dispatcher->attachListener( | ||||
| 				'unreginstered_event', | ||||
| 				self::$plugin, | ||||
| 				'testEventListener' | ||||
| 			); | ||||
| 			$this->fail("Error expected!"); | ||||
| 		} catch(Exception $e) {} | ||||
| 
 | ||||
| 		// Try to Attach wrong method as listener to event
 | ||||
| 		// Following code wait for trigger user error, which converts by PHPUnit to an
 | ||||
| 		// Exception
 | ||||
| 		try{ | ||||
| 			$dispatcher->attachListener( | ||||
| 				'some_test_event', | ||||
| 				self::$plugin, | ||||
| 				'wrongEventListener' | ||||
| 			); | ||||
| 			$this->fail("Error expected!"); | ||||
| 		} catch(Exception $e) {} | ||||
| 
 | ||||
| 		// Try to attach listener to registered event
 | ||||
| 		$this->assertTrue( | ||||
| 			$dispatcher->attachListener( | ||||
| 				'some_test_event', | ||||
| 				self::$plugin, | ||||
| 				'testEventListener' | ||||
| 			) | ||||
| 		); | ||||
| 
 | ||||
| 		// Try to attach listener to registered event
 | ||||
| 		$this->assertTrue( | ||||
| 			$dispatcher->attachListener( | ||||
| 				'some_another_test_event', | ||||
| 				self::$plugin, | ||||
| 				'testEventListener' | ||||
| 			) | ||||
| 		); | ||||
| 
 | ||||
| 		return $dispatcher; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @depends testAttachListener | ||||
| 	 */ | ||||
| 	public function testDetachListener($dispatcher) { | ||||
| 		// Try to detach listener for unregistered event.
 | ||||
| 		// Following code wait for trigger user error, which converts by PHPUnit to an
 | ||||
| 		// Exception
 | ||||
| 		try{ | ||||
| 			$dispatcher->detachListener( | ||||
| 				'unreginstered_event', | ||||
| 				self::$plugin, | ||||
| 				'testEventListener' | ||||
| 			); | ||||
| 			$this->fail("Error expected!"); | ||||
| 		} catch(Exception $e) {} | ||||
| 
 | ||||
| 		// Try to detach listner that was not attached to registerd event
 | ||||
| 		$this->assertFalse( | ||||
| 			$dispatcher->detachListener( | ||||
| 				'some_test_event', | ||||
| 				self::$plugin, | ||||
| 				'wrongEventListener' | ||||
| 			) | ||||
| 		); | ||||
| 
 | ||||
| 		// Try to detach listener that was attached to registered
 | ||||
| 		$this->assertTrue( | ||||
| 			$dispatcher->detachListener( | ||||
| 				'some_test_event', | ||||
| 				self::$plugin, | ||||
| 				'testEventListener' | ||||
| 			) | ||||
| 		); | ||||
| 		return $dispatcher; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @depends testDetachListener | ||||
| 	 */ | ||||
| 	public function testTriggerEvent($dispatcher) { | ||||
| 		// Try to trigger unregistered event
 | ||||
| 		// Following code wait for trigger user error, which converts by PHPUnit to an
 | ||||
| 		// Exception
 | ||||
| 		try{ | ||||
| 			$dispatcher->triggerEvent('unregistered_event', array()); | ||||
| 			$this->fail("Error expected!"); | ||||
| 		} catch(Exception $e) {} | ||||
| 
 | ||||
| 		// Try to thrigger registered event
 | ||||
| 		// Wait for exception thrown by
 | ||||
| 		// Phpunit_autotest_plugin_managerPlugin::testEventListener()
 | ||||
| 		try{ | ||||
| 			$dispatcher->triggerEvent('some_another_test_event', array()); | ||||
| 			$this->fail("Exception excpected!"); | ||||
| 		} catch(Exception $e) {} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
							
								
								
									
										28
									
								
								src/messenger/tests/webim/libs/classes/PluginManagerTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/messenger/tests/webim/libs/classes/PluginManagerTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| <?php | ||||
| 
 | ||||
| require_once dirname(__FILE__) . '/../../../../webim/libs/classes/plugin_manager.php'; | ||||
| require_once dirname(__FILE__) . '/../../../../webim/libs/classes/plugin.php'; | ||||
| 
 | ||||
| /** | ||||
|  * Test class for PluginManager. | ||||
|  * Generated by PHPUnit on 2012-07-17 at 16:09:18. | ||||
|  */ | ||||
| class PluginManagerTest extends PHPUnit_Framework_TestCase { | ||||
| 
 | ||||
| 	public function testLoadPlugins() { | ||||
| 		set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__)); | ||||
| 		PluginManager::loadPlugins( | ||||
| 			array( | ||||
| 				array( | ||||
| 					'name' => 'phpunit_autotest_plugin_manager' | ||||
| 				) | ||||
| 			) | ||||
| 		); | ||||
| 		if(empty($GLOBALS['phpunit_autotest_plugin_manager'])) { | ||||
| 			$this->fail('Plugin not loaded and initialize correctly'); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
| @ -0,0 +1,37 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * Test plugin for PHPUnit tests | ||||
|  */ | ||||
| Class Phpunit_autotest_plugin_managerPlugin implements Plugin{ | ||||
| 
 | ||||
| 	public $eventsRegistered = false; | ||||
| 	public $listenersRegistered = false; | ||||
| 
 | ||||
| 	public function getWeight() { | ||||
| 		return 10; | ||||
| 	} | ||||
| 
 | ||||
| 	public function registerEvents() { | ||||
| 		$this->eventsRegistered = true; | ||||
| 		$this->checkRegistration(); | ||||
| 	} | ||||
| 
 | ||||
| 	public function registerListeners() { | ||||
| 		$this->listenersRegistered = true; | ||||
| 		$this->checkRegistration(); | ||||
| 	} | ||||
| 
 | ||||
| 	public function checkRegistration() { | ||||
| 		if ($this->eventsRegistered && $this->listenersRegistered) { | ||||
| 			$GLOBALS['phpunit_autotest_plugin_manager'] = true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public function testEventListener($vars) { | ||||
| 		throw new Exception(); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
							
								
								
									
										1
									
								
								src/messenger/webim/libs/classes/.htaccess
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/messenger/webim/libs/classes/.htaccess
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| Deny from all | ||||
							
								
								
									
										163
									
								
								src/messenger/webim/libs/classes/event_dispatcher.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								src/messenger/webim/libs/classes/event_dispatcher.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,163 @@ | ||||
| <?php | ||||
| /* | ||||
|  * Copyright 2005-2013 the original author or authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Provide event-related functionality. | ||||
|  * Implements singleton pattern. | ||||
|  */ | ||||
| Class EventDispatcher { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * An instance of EventDispatcher class. | ||||
| 	 * @var EventDispatcher | ||||
| 	 */ | ||||
| 	protected static $instance = null; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Events and listeners array. | ||||
| 	 * @var array | ||||
| 	 */ | ||||
| 	protected $events = array(); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Increments any time when plugin adds. Use for determine plugins order for plugins with | ||||
| 	 * equal priority. | ||||
| 	 * @var int | ||||
| 	 */ | ||||
| 	protected $offset = 0; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns an instance of EventDispatcher class. | ||||
| 	 * | ||||
| 	 * @return EventDispatcher | ||||
| 	 */ | ||||
| 	public static function getInstance(){ | ||||
| 		if (self::$instance === null) { | ||||
| 			self::$instance = new self(); | ||||
| 		} | ||||
| 		return self::$instance; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Make constructor unavailable for client code | ||||
| 	 */ | ||||
| 	protected function __constructor() {} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Attaches listener function to event. | ||||
| 	 * | ||||
| 	 * @param string $event_name Event's name | ||||
| 	 * @param Plugin $plugin Plugin object, that handles the event | ||||
| 	 * @param string $listener Plugins method, that handles the event | ||||
| 	 * @param int $priority Priority of listener. If $priority = null, the plugin weight will | ||||
| 	 * use instead. | ||||
| 	 * @return boolean true on success or false on failure. | ||||
| 	 * | ||||
| 	 * @see Plugin::getWeight() | ||||
| 	 */ | ||||
| 	public function attachListener($event_name, Plugin $plugin, $listener, $priority = null){ | ||||
| 		// Check event exists
 | ||||
| 		if (! array_key_exists($event_name, $this->events)) { | ||||
| 			trigger_error("Event '{$event_name}' does not exists!", E_USER_WARNING); | ||||
| 			return false; | ||||
| 		} | ||||
| 		// Check method is callable
 | ||||
| 		if (! is_callable(array($plugin, $listener))) { | ||||
| 			trigger_error("Method '{$listener}' is not callable!", E_USER_WARNING); | ||||
| 			return false; | ||||
| 		} | ||||
| 		// Check priority
 | ||||
| 		if (is_null($priority)) { | ||||
| 			$priority = $plugin->getWeight(); | ||||
| 		} | ||||
| 		// Attach listener
 | ||||
| 		$this->events[$event_name][$priority . "_" . $this->offset] = array( | ||||
| 			'plugin' => $plugin, | ||||
| 			'listener' => $listener | ||||
| 		); | ||||
| 		$this->offset++; | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Detach listener function from event | ||||
| 	 * | ||||
| 	 * @param string $event_name Event's name | ||||
| 	 * @param Plugin $plugin Plugin object, that handles the event | ||||
| 	 * @param string $listener Plugins method, that handles the event | ||||
| 	 * @return boolean true on success or false on failure. | ||||
| 	 */ | ||||
| 	public function detachListener($event_name, Plugin $plugin, $listener){ | ||||
| 		// Check event exists
 | ||||
| 		if (! array_key_exists($event_name, $this->events)) { | ||||
| 			trigger_error("Event '{$event_name}' does not exists!", E_USER_WARNING); | ||||
| 			return false; | ||||
| 		} | ||||
| 		// Search event and $plugin->$listener
 | ||||
| 		foreach ($this->events[$event_name] as $index => $event) { | ||||
| 			if ($event['plugin'] === $plugin && $event['listener'] == $listener) { | ||||
| 				// Detach listener
 | ||||
| 				unset($this->events[$event_name][$index]); | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Registers new event | ||||
| 	 * | ||||
| 	 * @param string $event_name Event's name | ||||
| 	 * @return boolean true on success or false on failure | ||||
| 	 */ | ||||
| 	public function registerEvent($event_name){ | ||||
| 		// Check event exists
 | ||||
| 		if (array_key_exists($event_name, $this->events)) { | ||||
| 			trigger_error("Event '{$event_name}' already exists!", E_USER_WARNING); | ||||
| 			return false; | ||||
| 		} | ||||
| 		// register event
 | ||||
| 		$this->events[$event_name] = array(); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Triggers the event | ||||
| 	 * | ||||
| 	 * @param string $event_name Event's name | ||||
| 	 * @param array $arguments Arguments passed to listener | ||||
| 	 * @return boolean true on success or false on failure | ||||
| 	 */ | ||||
| 	public function triggerEvent($event_name, $arguments = array()){ | ||||
| 		// Check event exists
 | ||||
| 		if (! array_key_exists($event_name, $this->events)) { | ||||
| 			trigger_error("Event '{$event_name}' does not exists!", E_USER_WARNING); | ||||
| 			return false; | ||||
| 		} | ||||
| 		// Sorting listeners by priority
 | ||||
| 		uksort($this->events[$event_name], 'strnatcmp'); | ||||
| 		// Invoke listeners
 | ||||
| 		foreach ($this->events[$event_name] as $event) { | ||||
| 			$plugin = $event['plugin']; | ||||
| 			$listener = $event['listener']; | ||||
| 			$plugin->$listener($arguments); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
							
								
								
									
										43
									
								
								src/messenger/webim/libs/classes/plugin.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/messenger/webim/libs/classes/plugin.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| <?php | ||||
| /* | ||||
|  * Copyright 2005-2013 the original author or authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Base plugin interface | ||||
|  */ | ||||
| interface Plugin { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns plugin weight. Weight is used for determine loading order and as default | ||||
| 	 * listner priority. | ||||
| 	 * | ||||
| 	 * @return int Plugin weight | ||||
| 	 */ | ||||
| 	public function getWeight(); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Register events | ||||
| 	 */ | ||||
| 	public function registerEvents(); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Register listeners | ||||
| 	 */ | ||||
| 	public function registerListeners(); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
							
								
								
									
										94
									
								
								src/messenger/webim/libs/classes/plugin_manager.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/messenger/webim/libs/classes/plugin_manager.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,94 @@ | ||||
| <?php | ||||
| /* | ||||
|  * Copyright 2005-2013 the original author or authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Manage plugins | ||||
|  */ | ||||
| Class PluginManager { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Loads plugins and invokes Plugin::registerEvents() and Plugin::registerListeners() | ||||
| 	 * | ||||
| 	 * @param array $plugins_list List of plugins' names and configurations. For example: | ||||
| 	 * <code> | ||||
| 	 * $plugins_list = array(); | ||||
| 	 * $plugins_list[] = array( | ||||
| 	 *	'name' => 'plugin_name', // Obligatory value
 | ||||
| 	 *	'config' => array( // Pass to plugin constructor
 | ||||
| 	 *		'weight' => 100, | ||||
| 	 *		'some_configurable_value' => 'value' | ||||
| 	 *	) | ||||
| 	 * ) | ||||
| 	 * </code> | ||||
| 	 * | ||||
| 	 * @see Plugin::registerEvents() | ||||
| 	 * @see Plugin::registerListeners() | ||||
| 	 */ | ||||
| 	public static function loadPlugins($plugins_list){ | ||||
| 		// Add include path
 | ||||
| 		$include_path = get_include_path(); | ||||
| 		$include_path .= empty($include_path) ? '' : PATH_SEPARATOR ; | ||||
| 		set_include_path($include_path . realpath(dirname(__FILE__) . "/../../plugins/")); | ||||
| 
 | ||||
| 		// Load plugins
 | ||||
| 		$loading_queue = array(); | ||||
| 		$offset = 0; | ||||
| 		foreach ($plugins_list as $plugin) { | ||||
| 			if (empty($plugin['name'])) { | ||||
| 				trigger_error("Plugin name undefined!", E_USER_WARNING); | ||||
| 				continue; | ||||
| 			} | ||||
| 			$plugin_name = $plugin['name']; | ||||
| 			$plugin_config = isset($plugin['config']) ? $plugin['config'] : array(); | ||||
| 			$plugin_classname = ucfirst($plugin_name) . "Plugin"; | ||||
| 			// Try to load plugin file
 | ||||
| 			if (! (include_once $plugin_name."/plugin.mibew.inc.php")) { | ||||
| 				trigger_error("Cannot load plugin file!", E_USER_ERROR); | ||||
| 			} | ||||
| 			// Check plugin class name
 | ||||
| 			if (! class_exists($plugin_classname)) { | ||||
| 				trigger_error( | ||||
| 					"Plugin class '{$plugin_classname}' does not defined!", | ||||
| 					E_USER_WARNING | ||||
| 				); | ||||
| 				continue; | ||||
| 			} | ||||
| 			// Check if plugin implements 'Plugin' interface
 | ||||
| 			if (! in_array('Plugin', class_implements($plugin_classname))) { | ||||
| 				trigger_error( | ||||
| 					"Plugin class '{$plugin_classname}' does not implement " . | ||||
| 					"'Plugin' interface!", | ||||
| 					E_USER_WARNING | ||||
| 				); | ||||
| 				continue; | ||||
| 			} | ||||
| 			// Add plugin to loading queue
 | ||||
| 			$plugin_instance = new $plugin_classname($plugin_config); | ||||
| 			$loading_queue[$plugin_instance->getWeight() . "_" . $offset] = $plugin_instance; | ||||
| 			$offset++; | ||||
| 		} | ||||
| 		// Sort queue in order to plugins' weights
 | ||||
| 		uksort($loading_queue, 'strnatcmp'); | ||||
| 		// Add events and listeners
 | ||||
| 		foreach ($loading_queue as $plugin) { | ||||
| 			$plugin->registerEvents(); | ||||
| 			$plugin->registerListeners(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
							
								
								
									
										1
									
								
								src/messenger/webim/plugins/.htaccess
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/messenger/webim/plugins/.htaccess
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| Deny from all | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user