From: Benjamin Auder Date: Thu, 5 Feb 2015 10:57:31 +0000 (+0100) Subject: first commit after reset X-Git-Url: https://git.auder.net/?p=mixstore.git;a=commitdiff_plain;h=929ca0664edba8cc305d0b0033febd3fa06a7e73 first commit after reset --- 929ca0664edba8cc305d0b0033febd3fa06a7e73 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0fe0b8c --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +/web/bundles/ +/app/bootstrap.php.cache +/app/cache/* +/app/config/parameters.yml +/app/logs/* +!app/cache/.gitkeep +!app/logs/.gitkeep +/build/ +/vendor/ +/bin/ +*~ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..955248a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: php + +php: + - 5.3.3 + - 5.3 + - 5.4 + +before_script: composer install -n + +script: phpunit -c app diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d128d49 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 Benjamin Auder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README b/README new file mode 100644 index 0000000..faa8be4 --- /dev/null +++ b/README @@ -0,0 +1,12 @@ +mixstore utilise Symfony2 ; organisation des répertoires : + + app/: La configuration de l'application, + src/: Le code PHP du projet, + vendor/: Les bibliothèques tierces, + web/: Le répertoire Web racine. + +Le répertoire Web racine est l'endroit ou se situent tous les fichiers statiques +et publics comme les images, les feuilles de styles et les fichiers javascript. +C'est aussi le dossier contenant le point d'entrée web/app.php + +[Voir http://symfony.com/fr/doc/current/quick_tour/the_architecture.html] diff --git a/TODO b/TODO new file mode 100644 index 0000000..9289471 --- /dev/null +++ b/TODO @@ -0,0 +1,8 @@ +Sure : + - translations + - add defensive checks at many places to avoid ugly error screens (duplicate key, ...etc) + - (re)factor some controllers code + +Maybe : + - redirect after page access http://knplabs.com/blog/2012/01/13/redirect-after-registration-in-symfony2/ + - move assets to bundles instead of web/mixstore diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 0000000..fb1de45 --- /dev/null +++ b/app/.htaccess @@ -0,0 +1,7 @@ + + Require all denied + + + Order deny,allow + Deny from all + diff --git a/app/AppCache.php b/app/AppCache.php new file mode 100644 index 0000000..ddb51db --- /dev/null +++ b/app/AppCache.php @@ -0,0 +1,9 @@ +getEnvironment(), array('dev', 'test'))) { + $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); + $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle(); + $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle(); + } + + return $bundles; + } + + public function registerContainerConfiguration(LoaderInterface $loader) + { + $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); + } +} diff --git a/app/Resources/views/Form/fields.html.twig b/app/Resources/views/Form/fields.html.twig new file mode 100644 index 0000000..90fc47b --- /dev/null +++ b/app/Resources/views/Form/fields.html.twig @@ -0,0 +1,32 @@ +{# Global styles for forms (uniform display) #} + +{% block form_widget_simple %} + {% set type = type|default('text') %} +
+ +
+{% endblock form_widget_simple %} + +{% block form_row %} +{% spaceless %} +
+ {{ form_label(form) }} + {{ form_widget(form) }} + {{ form_errors(form) }} +
+{% endspaceless %} +{% endblock form_row %} + +{% block form_errors %} +{% spaceless %} + {% if errors|length > 0 %} +
+ +
+ {% endif %} +{% endspaceless %} +{% endblock form_errors %} diff --git a/app/Resources/views/base.html.twig b/app/Resources/views/base.html.twig new file mode 100644 index 0000000..a1730a2 --- /dev/null +++ b/app/Resources/views/base.html.twig @@ -0,0 +1,76 @@ + + + + + + {% block title %}mixstore - {% endblock %} + {% block header %} + + + + {% endblock %} + + + + + + + +
+ {% block content %}{% endblock %} +
+ + + +{% block javascripts %} + + +{% endblock %} + + + + diff --git a/app/SymfonyRequirements.php b/app/SymfonyRequirements.php new file mode 100644 index 0000000..fb70f80 --- /dev/null +++ b/app/SymfonyRequirements.php @@ -0,0 +1,687 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/* + * Users of PHP 5.2 should be able to run the requirements checks. + * This is why the file and all classes must be compatible with PHP 5.2+ + * (e.g. not using namespaces and closures). + * + * ************** CAUTION ************** + * + * DO NOT EDIT THIS FILE as it will be overridden by Composer as part of + * the installation/update process. The original file resides in the + * SensioDistributionBundle. + * + * ************** CAUTION ************** + */ + +/** + * Represents a single PHP requirement, e.g. an installed extension. + * It can be a mandatory requirement or an optional recommendation. + * There is a special subclass, named PhpIniRequirement, to check a php.ini configuration. + * + * @author Tobias Schultze + */ +class Requirement +{ + private $fulfilled; + private $testMessage; + private $helpText; + private $helpHtml; + private $optional; + + /** + * Constructor that initializes the requirement. + * + * @param Boolean $fulfilled Whether the requirement is fulfilled + * @param string $testMessage The message for testing the requirement + * @param string $helpHtml The help text formatted in HTML for resolving the problem + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + * @param Boolean $optional Whether this is only an optional recommendation not a mandatory requirement + */ + public function __construct($fulfilled, $testMessage, $helpHtml, $helpText = null, $optional = false) + { + $this->fulfilled = (Boolean) $fulfilled; + $this->testMessage = (string) $testMessage; + $this->helpHtml = (string) $helpHtml; + $this->helpText = null === $helpText ? strip_tags($this->helpHtml) : (string) $helpText; + $this->optional = (Boolean) $optional; + } + + /** + * Returns whether the requirement is fulfilled. + * + * @return Boolean true if fulfilled, otherwise false + */ + public function isFulfilled() + { + return $this->fulfilled; + } + + /** + * Returns the message for testing the requirement. + * + * @return string The test message + */ + public function getTestMessage() + { + return $this->testMessage; + } + + /** + * Returns the help text for resolving the problem + * + * @return string The help text + */ + public function getHelpText() + { + return $this->helpText; + } + + /** + * Returns the help text formatted in HTML. + * + * @return string The HTML help + */ + public function getHelpHtml() + { + return $this->helpHtml; + } + + /** + * Returns whether this is only an optional recommendation and not a mandatory requirement. + * + * @return Boolean true if optional, false if mandatory + */ + public function isOptional() + { + return $this->optional; + } +} + +/** + * Represents a PHP requirement in form of a php.ini configuration. + * + * @author Tobias Schultze + */ +class PhpIniRequirement extends Requirement +{ + /** + * Constructor that initializes the requirement. + * + * @param string $cfgName The configuration name used for ini_get() + * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false, + or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement + * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. + This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. + Example: You require a config to be true but PHP later removes this config and defaults it to true internally. + * @param string|null $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived) + * @param string|null $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a Boolean a default help is derived) + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + * @param Boolean $optional Whether this is only an optional recommendation not a mandatory requirement + */ + public function __construct($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null, $optional = false) + { + $cfgValue = ini_get($cfgName); + + if (is_callable($evaluation)) { + if (null === $testMessage || null === $helpHtml) { + throw new InvalidArgumentException('You must provide the parameters testMessage and helpHtml for a callback evaluation.'); + } + + $fulfilled = call_user_func($evaluation, $cfgValue); + } else { + if (null === $testMessage) { + $testMessage = sprintf('%s %s be %s in php.ini', + $cfgName, + $optional ? 'should' : 'must', + $evaluation ? 'enabled' : 'disabled' + ); + } + + if (null === $helpHtml) { + $helpHtml = sprintf('Set %s to %s in php.ini*.', + $cfgName, + $evaluation ? 'on' : 'off' + ); + } + + $fulfilled = $evaluation == $cfgValue; + } + + parent::__construct($fulfilled || ($approveCfgAbsence && false === $cfgValue), $testMessage, $helpHtml, $helpText, $optional); + } +} + +/** + * A RequirementCollection represents a set of Requirement instances. + * + * @author Tobias Schultze + */ +class RequirementCollection implements IteratorAggregate +{ + private $requirements = array(); + + /** + * Gets the current RequirementCollection as an Iterator. + * + * @return Traversable A Traversable interface + */ + public function getIterator() + { + return new ArrayIterator($this->requirements); + } + + /** + * Adds a Requirement. + * + * @param Requirement $requirement A Requirement instance + */ + public function add(Requirement $requirement) + { + $this->requirements[] = $requirement; + } + + /** + * Adds a mandatory requirement. + * + * @param Boolean $fulfilled Whether the requirement is fulfilled + * @param string $testMessage The message for testing the requirement + * @param string $helpHtml The help text formatted in HTML for resolving the problem + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + */ + public function addRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null) + { + $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, false)); + } + + /** + * Adds an optional recommendation. + * + * @param Boolean $fulfilled Whether the recommendation is fulfilled + * @param string $testMessage The message for testing the recommendation + * @param string $helpHtml The help text formatted in HTML for resolving the problem + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + */ + public function addRecommendation($fulfilled, $testMessage, $helpHtml, $helpText = null) + { + $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, true)); + } + + /** + * Adds a mandatory requirement in form of a php.ini configuration. + * + * @param string $cfgName The configuration name used for ini_get() + * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false, + or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement + * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. + This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. + Example: You require a config to be true but PHP later removes this config and defaults it to true internally. + * @param string $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived) + * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a Boolean a default help is derived) + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + */ + public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) + { + $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, false)); + } + + /** + * Adds an optional recommendation in form of a php.ini configuration. + * + * @param string $cfgName The configuration name used for ini_get() + * @param Boolean|callback $evaluation Either a Boolean indicating whether the configuration should evaluate to true or false, + or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement + * @param Boolean $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. + This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. + Example: You require a config to be true but PHP later removes this config and defaults it to true internally. + * @param string $testMessage The message for testing the requirement (when null and $evaluation is a Boolean a default message is derived) + * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a Boolean a default help is derived) + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + */ + public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) + { + $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, true)); + } + + /** + * Adds a requirement collection to the current set of requirements. + * + * @param RequirementCollection $collection A RequirementCollection instance + */ + public function addCollection(RequirementCollection $collection) + { + $this->requirements = array_merge($this->requirements, $collection->all()); + } + + /** + * Returns both requirements and recommendations. + * + * @return array Array of Requirement instances + */ + public function all() + { + return $this->requirements; + } + + /** + * Returns all mandatory requirements. + * + * @return array Array of Requirement instances + */ + public function getRequirements() + { + $array = array(); + foreach ($this->requirements as $req) { + if (!$req->isOptional()) { + $array[] = $req; + } + } + + return $array; + } + + /** + * Returns the mandatory requirements that were not met. + * + * @return array Array of Requirement instances + */ + public function getFailedRequirements() + { + $array = array(); + foreach ($this->requirements as $req) { + if (!$req->isFulfilled() && !$req->isOptional()) { + $array[] = $req; + } + } + + return $array; + } + + /** + * Returns all optional recommendations. + * + * @return array Array of Requirement instances + */ + public function getRecommendations() + { + $array = array(); + foreach ($this->requirements as $req) { + if ($req->isOptional()) { + $array[] = $req; + } + } + + return $array; + } + + /** + * Returns the recommendations that were not met. + * + * @return array Array of Requirement instances + */ + public function getFailedRecommendations() + { + $array = array(); + foreach ($this->requirements as $req) { + if (!$req->isFulfilled() && $req->isOptional()) { + $array[] = $req; + } + } + + return $array; + } + + /** + * Returns whether a php.ini configuration is not correct. + * + * @return Boolean php.ini configuration problem? + */ + public function hasPhpIniConfigIssue() + { + foreach ($this->requirements as $req) { + if (!$req->isFulfilled() && $req instanceof PhpIniRequirement) { + return true; + } + } + + return false; + } + + /** + * Returns the PHP configuration file (php.ini) path. + * + * @return string|false php.ini file path + */ + public function getPhpIniConfigPath() + { + return get_cfg_var('cfg_file_path'); + } +} + +/** + * This class specifies all requirements and optional recommendations that + * are necessary to run the Symfony Standard Edition. + * + * @author Tobias Schultze + * @author Fabien Potencier + */ +class SymfonyRequirements extends RequirementCollection +{ + const REQUIRED_PHP_VERSION = '5.3.3'; + + /** + * Constructor that initializes the requirements. + */ + public function __construct() + { + /* mandatory requirements follow */ + + $installedPhpVersion = phpversion(); + + $this->addRequirement( + version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>='), + sprintf('PHP version must be at least %s (%s installed)', self::REQUIRED_PHP_VERSION, $installedPhpVersion), + sprintf('You are running PHP version "%s", but Symfony needs at least PHP "%s" to run. + Before using Symfony, upgrade your PHP installation, preferably to the latest version.', + $installedPhpVersion, self::REQUIRED_PHP_VERSION), + sprintf('Install PHP %s or newer (installed version is %s)', self::REQUIRED_PHP_VERSION, $installedPhpVersion) + ); + + $this->addRequirement( + version_compare($installedPhpVersion, '5.3.16', '!='), + 'PHP version must not be 5.3.16 as Symfony won\'t work properly with it', + 'Install PHP 5.3.17 or newer (or downgrade to an earlier PHP version)' + ); + + $this->addRequirement( + is_dir(__DIR__.'/../vendor/composer'), + 'Vendor libraries must be installed', + 'Vendor libraries are missing. Install composer following instructions from http://getcomposer.org/. ' . + 'Then run "php composer.phar install" to install them.' + ); + + $baseDir = basename(__DIR__); + + $this->addRequirement( + is_writable(__DIR__.'/cache'), + "$baseDir/cache/ directory must be writable", + "Change the permissions of the \"$baseDir/cache/\" directory so that the web server can write into it." + ); + + $this->addRequirement( + is_writable(__DIR__.'/logs'), + "$baseDir/logs/ directory must be writable", + "Change the permissions of the \"$baseDir/logs/\" directory so that the web server can write into it." + ); + + $this->addPhpIniRequirement( + 'date.timezone', true, false, + 'date.timezone setting must be set', + 'Set the "date.timezone" setting in php.ini* (like Europe/Paris).' + ); + + if (version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>=')) { + $timezones = array(); + foreach (DateTimeZone::listAbbreviations() as $abbreviations) { + foreach ($abbreviations as $abbreviation) { + $timezones[$abbreviation['timezone_id']] = true; + } + } + + $this->addRequirement( + isset($timezones[date_default_timezone_get()]), + sprintf('Configured default timezone "%s" must be supported by your installation of PHP', date_default_timezone_get()), + 'Your default timezone is not supported by PHP. Check for typos in your php.ini file and have a look at the list of deprecated timezones at http://php.net/manual/en/timezones.others.php.' + ); + } + + $this->addRequirement( + function_exists('json_encode'), + 'json_encode() must be available', + 'Install and enable the JSON extension.' + ); + + $this->addRequirement( + function_exists('session_start'), + 'session_start() must be available', + 'Install and enable the session extension.' + ); + + $this->addRequirement( + function_exists('ctype_alpha'), + 'ctype_alpha() must be available', + 'Install and enable the ctype extension.' + ); + + $this->addRequirement( + function_exists('token_get_all'), + 'token_get_all() must be available', + 'Install and enable the Tokenizer extension.' + ); + + $this->addRequirement( + function_exists('simplexml_import_dom'), + 'simplexml_import_dom() must be available', + 'Install and enable the SimpleXML extension.' + ); + + if (function_exists('apc_store') && ini_get('apc.enabled')) { + if (version_compare($installedPhpVersion, '5.4.0', '>=')) { + $this->addRequirement( + version_compare(phpversion('apc'), '3.1.13', '>='), + 'APC version must be at least 3.1.13 when using PHP 5.4', + 'Upgrade your APC extension (3.1.13+).' + ); + } else { + $this->addRequirement( + version_compare(phpversion('apc'), '3.0.17', '>='), + 'APC version must be at least 3.0.17', + 'Upgrade your APC extension (3.0.17+).' + ); + } + } + + $this->addPhpIniRequirement('detect_unicode', false); + + if (extension_loaded('suhosin')) { + $this->addPhpIniRequirement( + 'suhosin.executor.include.whitelist', + create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'), + false, + 'suhosin.executor.include.whitelist must be configured correctly in php.ini', + 'Add "phar" to suhosin.executor.include.whitelist in php.ini*.' + ); + } + + if (extension_loaded('xdebug')) { + $this->addPhpIniRequirement( + 'xdebug.show_exception_trace', false, true + ); + + $this->addPhpIniRequirement( + 'xdebug.scream', false, true + ); + + $this->addPhpIniRecommendation( + 'xdebug.max_nesting_level', + create_function('$cfgValue', 'return $cfgValue > 100;'), + true, + 'xdebug.max_nesting_level should be above 100 in php.ini', + 'Set "xdebug.max_nesting_level" to e.g. "250" in php.ini* to stop Xdebug\'s infinite recursion protection erroneously throwing a fatal error in your project.' + ); + } + + $pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null; + + $this->addRequirement( + null !== $pcreVersion, + 'PCRE extension must be available', + 'Install the PCRE extension (version 8.0+).' + ); + + /* optional recommendations follow */ + + $this->addRecommendation( + file_get_contents(__FILE__) === file_get_contents(__DIR__.'/../vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle/Resources/skeleton/app/SymfonyRequirements.php'), + 'Requirements file should be up-to-date', + 'Your requirements file is outdated. Run composer install and re-check your configuration.' + ); + + $this->addRecommendation( + version_compare($installedPhpVersion, '5.3.4', '>='), + 'You should use at least PHP 5.3.4 due to PHP bug #52083 in earlier versions', + 'Your project might malfunction randomly due to PHP bug #52083 ("Notice: Trying to get property of non-object"). Install PHP 5.3.4 or newer.' + ); + + $this->addRecommendation( + version_compare($installedPhpVersion, '5.3.8', '>='), + 'When using annotations you should have at least PHP 5.3.8 due to PHP bug #55156', + 'Install PHP 5.3.8 or newer if your project uses annotations.' + ); + + $this->addRecommendation( + version_compare($installedPhpVersion, '5.4.0', '!='), + 'You should not use PHP 5.4.0 due to the PHP bug #61453', + 'Your project might not work properly due to the PHP bug #61453 ("Cannot dump definitions which have method calls"). Install PHP 5.4.1 or newer.' + ); + + $this->addRecommendation( + version_compare($installedPhpVersion, '5.4.11', '>='), + 'When using the logout handler from the Symfony Security Component, you should have at least PHP 5.4.11 due to PHP bug #63379 (as a workaround, you can also set invalidate_session to false in the security logout handler configuration)', + 'Install PHP 5.4.11 or newer if your project uses the logout handler from the Symfony Security Component.' + ); + + $this->addRecommendation( + (version_compare($installedPhpVersion, '5.3.18', '>=') && version_compare($installedPhpVersion, '5.4.0', '<')) + || + version_compare($installedPhpVersion, '5.4.8', '>='), + 'You should use PHP 5.3.18+ or PHP 5.4.8+ to always get nice error messages for fatal errors in the development environment due to PHP bug #61767/#60909', + 'Install PHP 5.3.18+ or PHP 5.4.8+ if you want nice error messages for all fatal errors in the development environment.' + ); + + if (null !== $pcreVersion) { + $this->addRecommendation( + $pcreVersion >= 8.0, + sprintf('PCRE extension should be at least version 8.0 (%s installed)', $pcreVersion), + 'PCRE 8.0+ is preconfigured in PHP since 5.3.2 but you are using an outdated version of it. Symfony probably works anyway but it is recommended to upgrade your PCRE extension.' + ); + } + + $this->addRecommendation( + class_exists('DomDocument'), + 'PHP-XML module should be installed', + 'Install and enable the PHP-XML module.' + ); + + $this->addRecommendation( + function_exists('mb_strlen'), + 'mb_strlen() should be available', + 'Install and enable the mbstring extension.' + ); + + $this->addRecommendation( + function_exists('iconv'), + 'iconv() should be available', + 'Install and enable the iconv extension.' + ); + + $this->addRecommendation( + function_exists('utf8_decode'), + 'utf8_decode() should be available', + 'Install and enable the XML extension.' + ); + + if (!defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->addRecommendation( + function_exists('posix_isatty'), + 'posix_isatty() should be available', + 'Install and enable the php_posix extension (used to colorize the CLI output).' + ); + } + + $this->addRecommendation( + class_exists('Locale'), + 'intl extension should be available', + 'Install and enable the intl extension (used for validators).' + ); + + if (class_exists('Collator')) { + $this->addRecommendation( + null !== new Collator('fr_FR'), + 'intl extension should be correctly configured', + 'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.' + ); + } + + if (class_exists('Locale')) { + if (defined('INTL_ICU_VERSION')) { + $version = INTL_ICU_VERSION; + } else { + $reflector = new ReflectionExtension('intl'); + + ob_start(); + $reflector->info(); + $output = strip_tags(ob_get_clean()); + + preg_match('/^ICU version +(?:=> )?(.*)$/m', $output, $matches); + $version = $matches[1]; + } + + $this->addRecommendation( + version_compare($version, '4.0', '>='), + 'intl ICU version should be at least 4+', + 'Upgrade your intl extension with a newer ICU version (4+).' + ); + } + + $accelerator = + (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable')) + || + (extension_loaded('apc') && ini_get('apc.enabled')) + || + (extension_loaded('Zend OPcache') && ini_get('opcache.enable')) + || + (extension_loaded('xcache') && ini_get('xcache.cacher')) + || + (extension_loaded('wincache') && ini_get('wincache.ocenabled')) + ; + + $this->addRecommendation( + $accelerator, + 'a PHP accelerator should be installed', + 'Install and enable a PHP accelerator like APC (highly recommended).' + ); + + $this->addPhpIniRecommendation('short_open_tag', false); + + $this->addPhpIniRecommendation('magic_quotes_gpc', false, true); + + $this->addPhpIniRecommendation('register_globals', false, true); + + $this->addPhpIniRecommendation('session.auto_start', false); + + $this->addRecommendation( + class_exists('PDO'), + 'PDO should be installed', + 'Install PDO (mandatory for Doctrine).' + ); + + if (class_exists('PDO')) { + $drivers = PDO::getAvailableDrivers(); + $this->addRecommendation( + count($drivers), + sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'), + 'Install PDO drivers (mandatory for Doctrine).' + ); + } + } +} diff --git a/app/autoload.php b/app/autoload.php new file mode 100644 index 0000000..70526bb --- /dev/null +++ b/app/autoload.php @@ -0,0 +1,13 @@ +getPhpIniConfigPath(); + +echo "********************************\n"; +echo "* *\n"; +echo "* Symfony requirements check *\n"; +echo "* *\n"; +echo "********************************\n\n"; + +echo $iniPath ? sprintf("* Configuration file used by PHP: %s\n\n", $iniPath) : "* WARNING: No configuration file (php.ini) used by PHP!\n\n"; + +echo "** ATTENTION **\n"; +echo "* The PHP CLI can use a different php.ini file\n"; +echo "* than the one used with your web server.\n"; +if ('\\' == DIRECTORY_SEPARATOR) { + echo "* (especially on the Windows platform)\n"; +} +echo "* To be on the safe side, please also launch the requirements check\n"; +echo "* from your web server using the web/config.php script.\n"; + +echo_title('Mandatory requirements'); + +$checkPassed = true; +foreach ($symfonyRequirements->getRequirements() as $req) { + /** @var $req Requirement */ + echo_requirement($req); + if (!$req->isFulfilled()) { + $checkPassed = false; + } +} + +echo_title('Optional recommendations'); + +foreach ($symfonyRequirements->getRecommendations() as $req) { + echo_requirement($req); +} + +exit($checkPassed ? 0 : 1); + +/** + * Prints a Requirement instance + */ +function echo_requirement(Requirement $requirement) +{ + $result = $requirement->isFulfilled() ? 'OK' : ($requirement->isOptional() ? 'WARNING' : 'ERROR'); + echo ' ' . str_pad($result, 9); + echo $requirement->getTestMessage() . "\n"; + + if (!$requirement->isFulfilled()) { + echo sprintf(" %s\n\n", $requirement->getHelpText()); + } +} + +function echo_title($title) +{ + echo "\n** $title **\n\n"; +} diff --git a/app/config/config.yml b/app/config/config.yml new file mode 100644 index 0000000..1972a0e --- /dev/null +++ b/app/config/config.yml @@ -0,0 +1,83 @@ +imports: + - { resource: parameters.yml } + - { resource: security.yml } + +framework: + #esi: ~ + translator: { fallback: "%locale%" } + secret: "%secret%" + router: + resource: "%kernel.root_dir%/config/routing.yml" + strict_requirements: ~ + form: ~ + csrf_protection: ~ + validation: { enable_annotations: true } + templating: + engines: ['twig'] + #assets_base_url: './' + #assets_version: SomeVersionScheme + default_locale: "%locale%" + trusted_hosts: ~ + trusted_proxies: ~ + session: + # handler_id set to null will use default session handler from php.ini + handler_id: ~ + fragments: ~ + http_method_override: true + +# Twig Configuration +twig: + debug: "%kernel.debug%" + strict_variables: "%kernel.debug%" + +# Assetic Configuration +assetic: + debug: "%kernel.debug%" + use_controller: false + bundles: [ ] + #java: /usr/bin/java + filters: + cssrewrite: ~ + #closure: + # jar: "%kernel.root_dir%/Resources/java/compiler.jar" + #yui_css: + # jar: "%kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar" + +# Doctrine Configuration +doctrine: + dbal: + driver: "%database_driver%" + host: "%database_host%" + port: "%database_port%" + dbname: "%database_name%" + user: "%database_user%" + password: "%database_password%" + charset: UTF8 + # if using pdo_sqlite as your database driver, add the path in parameters.yml + # e.g. database_path: "%kernel.root_dir%/data/data.db3" + # path: "%database_path%" + + orm: + auto_generate_proxy_classes: "%kernel.debug%" + auto_mapping: true + +# Swiftmailer Configuration +swiftmailer: + transport: "%mailer_transport%" + host: "%mailer_host%" + username: "%mailer_user%" + password: "%mailer_password%" + spool: { type: memory } + +fos_user: + db_driver: orm + firewall_name: main + user_class: Mixstore\UserBundle\Entity\User + registration: + form: + type: mixstore_user_registration + validation_groups: [MixstoreRegistration] + profile: + form: + type: mixstore_user_profile + validation_groups: [MixstoreProfile] diff --git a/app/config/config_dev.yml b/app/config/config_dev.yml new file mode 100644 index 0000000..914c34a --- /dev/null +++ b/app/config/config_dev.yml @@ -0,0 +1,36 @@ +imports: + - { resource: config.yml } + +framework: + router: + resource: "%kernel.root_dir%/config/routing_dev.yml" + strict_requirements: true + profiler: { only_exceptions: false } + +web_profiler: + toolbar: true + intercept_redirects: false + +monolog: + handlers: + main: + type: stream + path: "%kernel.logs_dir%/%kernel.environment%.log" + level: debug + console: + type: console + bubble: false + # uncomment to get logging in your browser + # you may have to allow bigger header sizes in your Web server configuration + #firephp: + # type: firephp + # level: info + #chromephp: + # type: chromephp + # level: info + +assetic: + use_controller: true + +#swiftmailer: +# delivery_address: me@example.com diff --git a/app/config/config_prod.yml b/app/config/config_prod.yml new file mode 100644 index 0000000..342837a --- /dev/null +++ b/app/config/config_prod.yml @@ -0,0 +1,25 @@ +imports: + - { resource: config.yml } + +#framework: +# validation: +# cache: apc + +#doctrine: +# orm: +# metadata_cache_driver: apc +# result_cache_driver: apc +# query_cache_driver: apc + +monolog: + handlers: + main: + type: fingers_crossed + action_level: error + handler: nested + nested: + type: stream + path: "%kernel.logs_dir%/%kernel.environment%.log" + level: debug + console: + type: console diff --git a/app/config/config_test.yml b/app/config/config_test.yml new file mode 100644 index 0000000..2f6d925 --- /dev/null +++ b/app/config/config_test.yml @@ -0,0 +1,16 @@ +imports: + - { resource: config_dev.yml } + +framework: + test: ~ + session: + storage_id: session.storage.mock_file + profiler: + collect: false + +web_profiler: + toolbar: false + intercept_redirects: false + +swiftmailer: + disable_delivery: true diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist new file mode 100644 index 0000000..8b317c2 --- /dev/null +++ b/app/config/parameters.yml.dist @@ -0,0 +1,15 @@ +parameters: + database_driver: pdo_mysql + database_host: 127.0.0.1 + database_port: ~ + database_name: symfony + database_user: root + database_password: ~ + + mailer_transport: smtp + mailer_host: 127.0.0.1 + mailer_user: ~ + mailer_password: ~ + + locale: en + secret: ThisTokenIsNotSoSecretChangeIt diff --git a/app/config/routing.yml b/app/config/routing.yml new file mode 100644 index 0000000..5b942db --- /dev/null +++ b/app/config/routing.yml @@ -0,0 +1,8 @@ +mixstore_static: + resource: "@MixstoreStaticBundle/Resources/config/routing.yml" + +mixstore_store: + resource: "@MixstoreStoreBundle/Resources/config/routing.yml" + +mixstore_user: + resource: "@MixstoreUserBundle/Resources/config/routing.yml" diff --git a/app/config/routing_dev.yml b/app/config/routing_dev.yml new file mode 100644 index 0000000..ff93a02 --- /dev/null +++ b/app/config/routing_dev.yml @@ -0,0 +1,14 @@ +_wdt: + resource: "@WebProfilerBundle/Resources/config/routing/wdt.xml" + prefix: /_wdt + +_profiler: + resource: "@WebProfilerBundle/Resources/config/routing/profiler.xml" + prefix: /_profiler + +_configurator: + resource: "@SensioDistributionBundle/Resources/config/routing/webconfigurator.xml" + prefix: /_configurator + +_main: + resource: routing.yml diff --git a/app/config/security.yml b/app/config/security.yml new file mode 100644 index 0000000..65642a4 --- /dev/null +++ b/app/config/security.yml @@ -0,0 +1,37 @@ +security: + encoders: + FOS\UserBundle\Model\UserInterface: sha512 + + role_hierarchy: + ROLE_ADMIN: ROLE_USER + ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] + + providers: + fos_userbundle: + id: fos_user.user_provider.username + + firewalls: + main: + pattern: ^/ + form_login: + provider: fos_userbundle + csrf_provider: form.csrf_provider + login_path: fos_user_security_login + check_path: fos_user_security_check + #http://fr.openclassrooms.com/forum/sujet/redirection-after-login-fosuser-96549 + always_use_default_target_path: true + default_target_path: /board + logout: + path: /security/logout + target: / + anonymous: true + dev: + pattern: ^/(_(profiler|wdt)|css|images|js)/ + security: false + + access_control: + - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY } + - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } + - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY } + - { path: ^/admin/, role: ROLE_ADMIN } + #- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https } diff --git a/app/console b/app/console new file mode 100755 index 0000000..fa6a36e --- /dev/null +++ b/app/console @@ -0,0 +1,27 @@ +#!/usr/bin/env php +getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev'); +$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod'; + +if ($debug) { + Debug::enable(); +} + +$kernel = new AppKernel($env, $debug); +$application = new Application($kernel); +$application->run($input); diff --git a/app/logs/.gitkeep b/app/logs/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/app/phpunit.xml.dist b/app/phpunit.xml.dist new file mode 100644 index 0000000..82a3a08 --- /dev/null +++ b/app/phpunit.xml.dist @@ -0,0 +1,41 @@ + + + + + + + + ../src/*/*Bundle/Tests + ../src/*/Bundle/*Bundle/Tests + + + + + + + + ../src + + ../src/*/*Bundle/Resources + ../src/*/*Bundle/Tests + ../src/*/Bundle/*Bundle/Resources + ../src/*/Bundle/*Bundle/Tests + + + + + diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..f3dc0d5 --- /dev/null +++ b/composer.json @@ -0,0 +1,53 @@ +{ + "name": "symfony/framework-standard-edition", + "license": "MIT", + "type": "project", + "description": "The \"Symfony Standard Edition\" distribution", + "autoload": { + "psr-0": { "": "src/" } + }, + "require": { + "php": ">=5.3.3", + "symfony/symfony": "~2.4", + "doctrine/orm": "~2.2,>=2.2.3", + "doctrine/doctrine-bundle": "~1.2", + "twig/extensions": "~1.0", + "symfony/assetic-bundle": "~2.3", + "symfony/swiftmailer-bundle": "~2.3", + "symfony/monolog-bundle": "~2.4", + "sensio/distribution-bundle": "~2.3", + "sensio/framework-extra-bundle": "~3.0", + "sensio/generator-bundle": "~2.3", + "incenteev/composer-parameter-handler": "~2.0", + "friendsofsymfony/user-bundle": "~2.0@dev" + }, + "scripts": { + "post-install-cmd": [ + "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile" + ], + "post-update-cmd": [ + "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile" + ] + }, + "config": { + "bin-dir": "bin" + }, + "extra": { + "symfony-app-dir": "app", + "symfony-web-dir": "web", + "incenteev-parameters": { + "file": "app/config/parameters.yml" + }, + "branch-alias": { + "dev-master": "2.4-dev" + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..648c638 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1657 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "297297b8355018bf874ad9e6c8129078", + "packages": [ + { + "name": "doctrine/annotations", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "d9b1a37e9351ddde1f19f09a02e3d6ee92e82efd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/d9b1a37e9351ddde1f19f09a02e3d6ee92e82efd", + "reference": "d9b1a37e9351ddde1f19f09a02e3d6ee92e82efd", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "php": ">=5.3.2" + }, + "require-dev": { + "doctrine/cache": "1.*", + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Annotations\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/", + "role": "Creator" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "http://jmsyst.com", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "time": "2014-07-06 15:52:21" + }, + { + "name": "doctrine/cache", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "e16d7adf45664a50fa86f515b6d5e7f670130449" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/e16d7adf45664a50fa86f515b6d5e7f670130449", + "reference": "e16d7adf45664a50fa86f515b6d5e7f670130449", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "phpunit/phpunit": ">=3.7", + "satooshi/php-coveralls": "~0.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Cache\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/", + "role": "Creator" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "http://jmsyst.com", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Caching library offering an object-oriented API for many cache backends", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2013-10-25 19:04:14" + }, + { + "name": "doctrine/collections", + "version": "v1.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "b99c5c46c87126201899afe88ec490a25eedd6a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/b99c5c46c87126201899afe88ec490a25eedd6a2", + "reference": "b99c5c46c87126201899afe88ec490a25eedd6a2", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Collections\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan H. Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/", + "role": "Creator" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Collections Abstraction library", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "array", + "collections", + "iterator" + ], + "time": "2014-02-03 23:07:43" + }, + { + "name": "doctrine/common", + "version": "v2.4.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/common.git", + "reference": "5db6ab40e4c531f14dad4ca96a394dfce5d4255b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/common/zipball/5db6ab40e4c531f14dad4ca96a394dfce5d4255b", + "reference": "5db6ab40e4c531f14dad4ca96a394dfce5d4255b", + "shasum": "" + }, + "require": { + "doctrine/annotations": "1.*", + "doctrine/cache": "1.*", + "doctrine/collections": "1.*", + "doctrine/inflector": "1.*", + "doctrine/lexer": "1.*", + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~3.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/", + "role": "Creator" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "http://jmsyst.com", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Common Library for Doctrine projects", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "collections", + "eventmanager", + "persistence", + "spl" + ], + "time": "2014-05-21 19:28:51" + }, + { + "name": "doctrine/dbal", + "version": "v2.4.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/dbal.git", + "reference": "fec965d330c958e175c39e61c3f6751955af32d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/fec965d330c958e175c39e61c3f6751955af32d0", + "reference": "fec965d330c958e175c39e61c3f6751955af32d0", + "shasum": "" + }, + "require": { + "doctrine/common": "~2.4", + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*", + "symfony/console": "~2.0" + }, + "suggest": { + "symfony/console": "Allows use of the command line interface" + }, + "type": "library", + "autoload": { + "psr-0": { + "Doctrine\\DBAL\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/", + "role": "Creator" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + } + ], + "description": "Database Abstraction Layer", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "dbal", + "persistence", + "queryobject" + ], + "time": "2014-01-01 16:43:57" + }, + { + "name": "doctrine/doctrine-bundle", + "version": "v1.2.0", + "target-dir": "Doctrine/Bundle/DoctrineBundle", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineBundle.git", + "reference": "765b0d87fcc3e839c74817b7211258cbef3a4fb9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/765b0d87fcc3e839c74817b7211258cbef3a4fb9", + "reference": "765b0d87fcc3e839c74817b7211258cbef3a4fb9", + "shasum": "" + }, + "require": { + "doctrine/dbal": ">=2.2,<2.5-dev", + "jdorn/sql-formatter": "~1.1", + "php": ">=5.3.2", + "symfony/doctrine-bridge": "~2.2", + "symfony/framework-bundle": "~2.2" + }, + "require-dev": { + "doctrine/orm": ">=2.2,<2.5-dev", + "symfony/validator": "~2.2", + "symfony/yaml": "~2.2" + }, + "suggest": { + "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.", + "symfony/web-profiler-bundle": "to use the data collector" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Bundle\\DoctrineBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + } + ], + "description": "Symfony DoctrineBundle", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "dbal", + "orm", + "persistence" + ], + "time": "2013-03-25 20:13:59" + }, + { + "name": "doctrine/inflector", + "version": "v1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "54b8333d2a5682afdc690060c1cf384ba9f47f08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/54b8333d2a5682afdc690060c1cf384ba9f47f08", + "reference": "54b8333d2a5682afdc690060c1cf384ba9f47f08", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "autoload": { + "psr-0": { + "Doctrine\\Common\\Inflector\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/", + "role": "Creator" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "http://jmsyst.com", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Common String Manipulations with regard to casing and singular/plural rules.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "inflection", + "pluarlize", + "singuarlize", + "string" + ], + "time": "2013-01-10 21:49:15" + }, + { + "name": "doctrine/lexer", + "version": "v1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "2f708a85bb3aab5d99dab8be435abd73e0b18acb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/2f708a85bb3aab5d99dab8be435abd73e0b18acb", + "reference": "2f708a85bb3aab5d99dab8be435abd73e0b18acb", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "http://jmsyst.com", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ], + "time": "2013-01-12 18:59:04" + }, + { + "name": "doctrine/orm", + "version": "v2.4.4", + "source": { + "type": "git", + "url": "https://github.com/doctrine/doctrine2.git", + "reference": "fc19c3b53dcd00e6584db40669fdd699c4671f97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/fc19c3b53dcd00e6584db40669fdd699c4671f97", + "reference": "fc19c3b53dcd00e6584db40669fdd699c4671f97", + "shasum": "" + }, + "require": { + "doctrine/collections": "~1.1", + "doctrine/dbal": "~2.4", + "ext-pdo": "*", + "php": ">=5.3.2", + "symfony/console": "~2.0" + }, + "require-dev": { + "satooshi/php-coveralls": "dev-master", + "symfony/yaml": "~2.1" + }, + "suggest": { + "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" + }, + "bin": [ + "bin/doctrine", + "bin/doctrine.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\ORM\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/", + "role": "Creator" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + } + ], + "description": "Object-Relational-Mapper for PHP", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "orm" + ], + "time": "2014-07-11 03:05:53" + }, + { + "name": "friendsofsymfony/user-bundle", + "version": "dev-master", + "target-dir": "FOS/UserBundle", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfSymfony/FOSUserBundle.git", + "reference": "ef7ca325929ff102fff521653a2e3b88c7a40361" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfSymfony/FOSUserBundle/zipball/ef7ca325929ff102fff521653a2e3b88c7a40361", + "reference": "ef7ca325929ff102fff521653a2e3b88c7a40361", + "shasum": "" + }, + "require": { + "php": ">=5.3.2", + "symfony/form": "~2.1", + "symfony/framework-bundle": "~2.1", + "symfony/security-bundle": "~2.1" + }, + "require-dev": { + "doctrine/doctrine-bundle": "*", + "swiftmailer/swiftmailer": ">=4.3, <6.0", + "symfony/validator": "~2.1", + "symfony/yaml": "~2.1", + "twig/twig": "~1.5", + "willdurand/propel-typehintable-behavior": "dev-master" + }, + "suggest": { + "willdurand/propel-typehintable-behavior": "Needed when using the propel implementation" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "FOS\\UserBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + }, + { + "name": "Thibault Duplessis", + "email": "thibault.duplessis@gmail.com", + "homepage": "http://ornicar.github.com" + }, + { + "name": "FriendsOfSymfony Community", + "homepage": "https://github.com/friendsofsymfony/FOSUserBundle/contributors" + } + ], + "description": "Symfony FOSUserBundle", + "homepage": "http://friendsofsymfony.github.com", + "keywords": [ + "User management" + ], + "time": "2014-07-09 10:33:42" + }, + { + "name": "incenteev/composer-parameter-handler", + "version": "v2.1.0", + "target-dir": "Incenteev/ParameterHandler", + "source": { + "type": "git", + "url": "https://github.com/Incenteev/ParameterHandler.git", + "reference": "143272a0a09c62616a3c8011fc165a10c6b35241" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Incenteev/ParameterHandler/zipball/143272a0a09c62616a3c8011fc165a10c6b35241", + "reference": "143272a0a09c62616a3c8011fc165a10c6b35241", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/yaml": "~2.0" + }, + "require-dev": { + "composer/composer": "1.0.*@dev", + "phpspec/prophecy-phpunit": "~1.0", + "symfony/filesystem": "~2.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Incenteev\\ParameterHandler": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + } + ], + "description": "Composer script handling your ignored parameter file", + "homepage": "https://github.com/Incenteev/ParameterHandler", + "keywords": [ + "parameters management" + ], + "time": "2013-12-07 10:10:39" + }, + { + "name": "jdorn/sql-formatter", + "version": "v1.2.17", + "source": { + "type": "git", + "url": "https://github.com/jdorn/sql-formatter.git", + "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jdorn/sql-formatter/zipball/64990d96e0959dff8e059dfcdc1af130728d92bc", + "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc", + "shasum": "" + }, + "require": { + "php": ">=5.2.4" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "lib" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Dorn", + "email": "jeremy@jeremydorn.com", + "homepage": "http://jeremydorn.com/" + } + ], + "description": "a PHP SQL highlighting library", + "homepage": "https://github.com/jdorn/sql-formatter/", + "keywords": [ + "highlight", + "sql" + ], + "time": "2014-01-12 16:20:24" + }, + { + "name": "kriswallsmith/assetic", + "version": "v1.1.2", + "source": { + "type": "git", + "url": "https://github.com/kriswallsmith/assetic.git", + "reference": "735cffd3982c6e8cdebe292d5db39d077f65890f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kriswallsmith/assetic/zipball/735cffd3982c6e8cdebe292d5db39d077f65890f", + "reference": "735cffd3982c6e8cdebe292d5db39d077f65890f", + "shasum": "" + }, + "require": { + "php": ">=5.3.1", + "symfony/process": "~2.1" + }, + "require-dev": { + "cssmin/cssmin": "*", + "joliclic/javascript-packer": "*", + "kamicane/packager": "*", + "leafo/lessphp": "*", + "leafo/scssphp": "*", + "leafo/scssphp-compass": "*", + "mrclay/minify": "*", + "phpunit/phpunit": "~3.7", + "ptachoire/cssembed": "*", + "twig/twig": "~1.6" + }, + "suggest": { + "leafo/lessphp": "Assetic provides the integration with the lessphp LESS compiler", + "leafo/scssphp": "Assetic provides the integration with the scssphp SCSS compiler", + "leafo/scssphp-compass": "Assetic provides the integration with the SCSS compass plugin", + "ptachoire/cssembed": "Assetic provides the integration with phpcssembed to embed data uris", + "twig/twig": "Assetic provides the integration with the Twig templating engine" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-0": { + "Assetic": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kris Wallsmith", + "email": "kris.wallsmith@gmail.com", + "homepage": "http://kriswallsmith.net/" + } + ], + "description": "Asset Management for PHP", + "homepage": "https://github.com/kriswallsmith/assetic", + "keywords": [ + "assets", + "compression", + "minification" + ], + "time": "2013-07-19 00:03:27" + }, + { + "name": "monolog/monolog", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "25b16e801979098cb2f120e697bfce454b18bf23" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/25b16e801979098cb2f120e697bfce454b18bf23", + "reference": "25b16e801979098cb2f120e697bfce454b18bf23", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "require-dev": { + "aws/aws-sdk-php": "~2.4, >2.4.8", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "phpunit/phpunit": "~3.7.0", + "raven/raven": "~0.5", + "ruflin/elastica": "0.90.*" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "raven/raven": "Allow sending log messages to a Sentry server", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be", + "role": "Developer" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2014-06-04 16:30:04" + }, + { + "name": "psr/log", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2012-12-21 11:40:51" + }, + { + "name": "sensio/distribution-bundle", + "version": "v2.3.4", + "target-dir": "Sensio/Bundle/DistributionBundle", + "source": { + "type": "git", + "url": "https://github.com/sensiolabs/SensioDistributionBundle.git", + "reference": "66df91b4bd637a83299d8072aed3658bfd3b3021" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sensiolabs/SensioDistributionBundle/zipball/66df91b4bd637a83299d8072aed3658bfd3b3021", + "reference": "66df91b4bd637a83299d8072aed3658bfd3b3021", + "shasum": "" + }, + "require": { + "symfony/framework-bundle": "~2.2" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Sensio\\Bundle\\DistributionBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "The base bundle for the Symfony Distributions", + "keywords": [ + "configuration", + "distribution" + ], + "time": "2013-08-22 05:04:53" + }, + { + "name": "sensio/framework-extra-bundle", + "version": "v3.0.1", + "target-dir": "Sensio/Bundle/FrameworkExtraBundle", + "source": { + "type": "git", + "url": "https://github.com/sensiolabs/SensioFrameworkExtraBundle.git", + "reference": "dbc1e5aa830f3bf8063b29102add3c1e476d616e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/dbc1e5aa830f3bf8063b29102add3c1e476d616e", + "reference": "dbc1e5aa830f3bf8063b29102add3c1e476d616e", + "shasum": "" + }, + "require": { + "doctrine/common": "~2.2", + "symfony/framework-bundle": "~2.5" + }, + "require-dev": { + "symfony/expression-language": "~2.4", + "symfony/security-bundle": "~2.4" + }, + "suggest": { + "symfony/expression-language": "", + "symfony/security-bundle": "" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Sensio\\Bundle\\FrameworkExtraBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "This bundle provides a way to configure your controllers with annotations", + "keywords": [ + "annotations", + "controllers" + ], + "time": "2014-05-22 23:27:44" + }, + { + "name": "sensio/generator-bundle", + "version": "v2.3.5", + "target-dir": "Sensio/Bundle/GeneratorBundle", + "source": { + "type": "git", + "url": "https://github.com/sensiolabs/SensioGeneratorBundle.git", + "reference": "8b7a33aa3d22388443b6de0b0cf184122e9f60d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sensiolabs/SensioGeneratorBundle/zipball/8b7a33aa3d22388443b6de0b0cf184122e9f60d2", + "reference": "8b7a33aa3d22388443b6de0b0cf184122e9f60d2", + "shasum": "" + }, + "require": { + "symfony/console": "~2.0", + "symfony/framework-bundle": "~2.2" + }, + "require-dev": { + "doctrine/orm": "~2.2,>=2.2.3", + "symfony/doctrine-bridge": "~2.2", + "twig/twig": "~1.11" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Sensio\\Bundle\\GeneratorBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "This bundle generates code for you", + "time": "2014-04-28 14:01:06" + }, + { + "name": "swiftmailer/swiftmailer", + "version": "v5.2.1", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "2b9af56cc676c338d52fca4c657e5bdff73bb7af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/2b9af56cc676c338d52fca4c657e5bdff73bb7af", + "reference": "2b9af56cc676c338d52fca4c657e5bdff73bb7af", + "shasum": "" + }, + "require": { + "php": ">=5.2.4" + }, + "require-dev": { + "mockery/mockery": "~0.9.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.2-dev" + } + }, + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Chris Corbyn" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.org", + "keywords": [ + "mail", + "mailer" + ], + "time": "2014-06-13 11:44:54" + }, + { + "name": "symfony/assetic-bundle", + "version": "v2.3.0", + "target-dir": "Symfony/Bundle/AsseticBundle", + "source": { + "type": "git", + "url": "https://github.com/symfony/AsseticBundle.git", + "reference": "146dd3cb46b302bd471560471c6aaa930483dac1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/AsseticBundle/zipball/146dd3cb46b302bd471560471c6aaa930483dac1", + "reference": "146dd3cb46b302bd471560471c6aaa930483dac1", + "shasum": "" + }, + "require": { + "kriswallsmith/assetic": "~1.1", + "php": ">=5.3.0", + "symfony/framework-bundle": "~2.1" + }, + "require-dev": { + "symfony/class-loader": "~2.1", + "symfony/console": "~2.1", + "symfony/css-selector": "~2.1", + "symfony/dom-crawler": "~2.1", + "symfony/form": "~2.1", + "symfony/twig-bundle": "~2.1", + "symfony/yaml": "~2.1" + }, + "suggest": { + "symfony/twig-bundle": "~2.1" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Bundle\\AsseticBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kris Wallsmith", + "email": "kris.wallsmith@gmail.com", + "homepage": "http://kriswallsmith.net/" + } + ], + "description": "Integrates Assetic into Symfony2", + "homepage": "https://github.com/symfony/AsseticBundle", + "keywords": [ + "assets", + "compression", + "minification" + ], + "time": "2013-05-16 05:32:23" + }, + { + "name": "symfony/icu", + "version": "v1.2.1", + "target-dir": "Symfony/Component/Icu", + "source": { + "type": "git", + "url": "https://github.com/symfony/Icu.git", + "reference": "98e197da54df1f966dd5e8a4992135703569c987" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Icu/zipball/98e197da54df1f966dd5e8a4992135703569c987", + "reference": "98e197da54df1f966dd5e8a4992135703569c987", + "shasum": "" + }, + "require": { + "lib-icu": ">=4.4", + "php": ">=5.3.3", + "symfony/intl": "~2.3" + }, + "type": "library", + "autoload": { + "psr-0": { + "Symfony\\Component\\Icu\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Contains an excerpt of the ICU data and classes to load it.", + "homepage": "http://symfony.com", + "keywords": [ + "icu", + "intl" + ], + "time": "2013-10-04 10:06:38" + }, + { + "name": "symfony/monolog-bundle", + "version": "v2.6.0", + "target-dir": "Symfony/Bundle/MonologBundle", + "source": { + "type": "git", + "url": "https://github.com/symfony/MonologBundle.git", + "reference": "e1d4aa99c7440b11e9dfbfef7ed63084401dbc6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/MonologBundle/zipball/e1d4aa99c7440b11e9dfbfef7ed63084401dbc6a", + "reference": "e1d4aa99c7440b11e9dfbfef7ed63084401dbc6a", + "shasum": "" + }, + "require": { + "monolog/monolog": "~1.8", + "php": ">=5.3.2", + "symfony/config": "~2.3", + "symfony/dependency-injection": "~2.3", + "symfony/http-kernel": "~2.3", + "symfony/monolog-bridge": "~2.3" + }, + "require-dev": { + "symfony/console": "~2.3", + "symfony/yaml": "~2.3" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Bundle\\MonologBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony MonologBundle", + "homepage": "http://symfony.com", + "keywords": [ + "log", + "logging" + ], + "time": "2014-06-04 16:49:13" + }, + { + "name": "symfony/swiftmailer-bundle", + "version": "v2.3.7", + "target-dir": "Symfony/Bundle/SwiftmailerBundle", + "source": { + "type": "git", + "url": "https://github.com/symfony/SwiftmailerBundle.git", + "reference": "e98defd402f72e8b54a029ba4d3ac4cb51dc3577" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/SwiftmailerBundle/zipball/e98defd402f72e8b54a029ba4d3ac4cb51dc3577", + "reference": "e98defd402f72e8b54a029ba4d3ac4cb51dc3577", + "shasum": "" + }, + "require": { + "php": ">=5.3.2", + "swiftmailer/swiftmailer": ">=4.2.0,~5.0", + "symfony/swiftmailer-bridge": "~2.1" + }, + "require-dev": { + "symfony/config": "~2.1", + "symfony/dependency-injection": "~2.1", + "symfony/http-kernel": "~2.1", + "symfony/yaml": "~2.1" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Bundle\\SwiftmailerBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony SwiftmailerBundle", + "homepage": "http://symfony.com", + "time": "2014-04-05 17:15:52" + }, + { + "name": "symfony/symfony", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/symfony.git", + "reference": "e66ee967571b89234c90946fe0d50dad195ad29c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/symfony/zipball/e66ee967571b89234c90946fe0d50dad195ad29c", + "reference": "e66ee967571b89234c90946fe0d50dad195ad29c", + "shasum": "" + }, + "require": { + "doctrine/common": "~2.2", + "php": ">=5.3.3", + "psr/log": "~1.0", + "symfony/icu": "~1.0", + "twig/twig": "~1.12" + }, + "replace": { + "symfony/browser-kit": "self.version", + "symfony/class-loader": "self.version", + "symfony/config": "self.version", + "symfony/console": "self.version", + "symfony/css-selector": "self.version", + "symfony/debug": "self.version", + "symfony/dependency-injection": "self.version", + "symfony/doctrine-bridge": "self.version", + "symfony/dom-crawler": "self.version", + "symfony/event-dispatcher": "self.version", + "symfony/expression-language": "self.version", + "symfony/filesystem": "self.version", + "symfony/finder": "self.version", + "symfony/form": "self.version", + "symfony/framework-bundle": "self.version", + "symfony/http-foundation": "self.version", + "symfony/http-kernel": "self.version", + "symfony/intl": "self.version", + "symfony/locale": "self.version", + "symfony/monolog-bridge": "self.version", + "symfony/options-resolver": "self.version", + "symfony/process": "self.version", + "symfony/propel1-bridge": "self.version", + "symfony/property-access": "self.version", + "symfony/proxy-manager-bridge": "self.version", + "symfony/routing": "self.version", + "symfony/security": "self.version", + "symfony/security-acl": "self.version", + "symfony/security-bundle": "self.version", + "symfony/security-core": "self.version", + "symfony/security-csrf": "self.version", + "symfony/security-http": "self.version", + "symfony/serializer": "self.version", + "symfony/stopwatch": "self.version", + "symfony/swiftmailer-bridge": "self.version", + "symfony/templating": "self.version", + "symfony/translation": "self.version", + "symfony/twig-bridge": "self.version", + "symfony/twig-bundle": "self.version", + "symfony/validator": "self.version", + "symfony/web-profiler-bundle": "self.version", + "symfony/yaml": "self.version" + }, + "require-dev": { + "doctrine/data-fixtures": "1.0.*", + "doctrine/dbal": "~2.2", + "doctrine/orm": "~2.2,>=2.2.3", + "egulias/email-validator": "1.1.0", + "ircmaxell/password-compat": "1.0.*", + "monolog/monolog": "~1.3", + "ocramius/proxy-manager": ">=0.3.1,<0.6-dev", + "propel/propel1": "1.6.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\": "src/" + }, + "classmap": [ + "src/Symfony/Component/HttpFoundation/Resources/stubs", + "src/Symfony/Component/Intl/Resources/stubs" + ], + "files": [ + "src/Symfony/Component/Intl/Resources/stubs/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "The Symfony PHP framework", + "homepage": "http://symfony.com", + "keywords": [ + "framework" + ], + "time": "2014-07-15 15:39:46" + }, + { + "name": "twig/extensions", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/fabpot/Twig-extensions.git", + "reference": "c0ab818595338dd5569369bfce2552d02cec5d50" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fabpot/Twig-extensions/zipball/c0ab818595338dd5569369bfce2552d02cec5d50", + "reference": "c0ab818595338dd5569369bfce2552d02cec5d50", + "shasum": "" + }, + "require": { + "twig/twig": "~1.12" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Twig_Extensions_": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "Common additional features for Twig that do not directly belong in core", + "homepage": "https://github.com/fabpot/Twig-extensions", + "keywords": [ + "i18n", + "text" + ], + "time": "2014-07-05 10:01:35" + }, + { + "name": "twig/twig", + "version": "v1.16.0", + "source": { + "type": "git", + "url": "https://github.com/fabpot/Twig.git", + "reference": "8ce37115802e257a984a82d38254884085060024" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fabpot/Twig/zipball/8ce37115802e257a984a82d38254884085060024", + "reference": "8ce37115802e257a984a82d38254884085060024", + "shasum": "" + }, + "require": { + "php": ">=5.2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.16-dev" + } + }, + "autoload": { + "psr-0": { + "Twig_": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Armin Ronacher2", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + }, + { + "name": "Twig Team", + "homepage": "https://github.com/fabpot/Twig/graphs/contributors", + "role": "Contributors" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "http://twig.sensiolabs.org", + "keywords": [ + "templating" + ], + "time": "2014-07-05 12:19:05" + } + ], + "packages-dev": [ + + ], + "aliases": [ + + ], + "minimum-stability": "stable", + "stability-flags": { + "friendsofsymfony/user-bundle": 20 + }, + "platform": { + "php": ">=5.3.3" + }, + "platform-dev": [ + + ] +} diff --git a/resetCacheLogs.php b/resetCacheLogs.php new file mode 100644 index 0000000..b72cb18 --- /dev/null +++ b/resetCacheLogs.php @@ -0,0 +1,12 @@ + + Require all denied + + + Order deny,allow + Deny from all + diff --git a/src/Mixstore/StaticBundle/Controller/MainController.php b/src/Mixstore/StaticBundle/Controller/MainController.php new file mode 100644 index 0000000..c73ce03 --- /dev/null +++ b/src/Mixstore/StaticBundle/Controller/MainController.php @@ -0,0 +1,39 @@ +getDoctrine() + ->getManager() + ->getRepository('MixstoreStoreBundle:Package'); + + //get news + $news = $pkgRepository + ->getLastNews(); + + //get images sources for carousel + $bannersArray = $pkgRepository + ->getBannersUrls(); + + return $this->render('MixstoreStaticBundle::home.html.twig', array( + 'bannersArray' => $bannersArray, + 'news' => $news, + )); + } + + public function aboutAction() + { + return $this->render('MixstoreStaticBundle::about.html.twig'); + } + + public function policyAction() + { + return $this->render('MixstoreStaticBundle::policy.html.twig'); + } +} diff --git a/src/Mixstore/StaticBundle/DependencyInjection/Configuration.php b/src/Mixstore/StaticBundle/DependencyInjection/Configuration.php new file mode 100644 index 0000000..1707288 --- /dev/null +++ b/src/Mixstore/StaticBundle/DependencyInjection/Configuration.php @@ -0,0 +1,29 @@ +root('mixstore_static'); + + // Here you should define the parameters that are allowed to + // configure your bundle. See the documentation linked above for + // more information on that topic. + + return $treeBuilder; + } +} diff --git a/src/Mixstore/StaticBundle/DependencyInjection/MixstoreStoreExtension.php b/src/Mixstore/StaticBundle/DependencyInjection/MixstoreStoreExtension.php new file mode 100644 index 0000000..1fa333d --- /dev/null +++ b/src/Mixstore/StaticBundle/DependencyInjection/MixstoreStoreExtension.php @@ -0,0 +1,28 @@ +processConfiguration($configuration, $configs); + + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->load('services.yml'); + } +} diff --git a/src/Mixstore/StaticBundle/MixstoreStaticBundle.php b/src/Mixstore/StaticBundle/MixstoreStaticBundle.php new file mode 100644 index 0000000..afb1c94 --- /dev/null +++ b/src/Mixstore/StaticBundle/MixstoreStaticBundle.php @@ -0,0 +1,9 @@ + +{% endblock %} + +{% block content %} + +
+ +
+ +

Origins

+ +In the late 1990's, three researchers wrote some code in MATLAB to classify data using +mixture models. Initially named XEM for "EM-algorithms on miXture models", +it was quickly renamed into mixmod, and rewritten in C++ from 2001. +Since then, mixmod has been extended in several directions including: +
    +
  • supervised classification
  • +
  • categorical data handling
  • +
  • heterogeneous data handling
  • +
+...and the code is constantly evolving. {# still in constant evolution #} +More details can be found on the dedicated website. + +There exist now many packages related to mixture models, each of them specialized in +some domain. Although mixmod can (arguably) be considered as one of the first of its kind, +it would be rather arbitrary to give him a central position. +That is why mixmod is "only" part of the mix-store. + +{# (mixmod permet de faire + de choses : renvoyer au site web + doc...) #} + +

Summary

+ +Mixstore is a website gathering libraries dedicated to data modeling as +a mixture of probabilistic components. The computed mixture can be used +for various purposes including +
    +
  • density estimation
  • +
  • clustering (unsupervised classification)
  • +
  • (supervised) classification
  • +
  • regression, ...
  • +
+ +

Example

+ +

+To start using any of the softwares present in the store, we need a dataset. +We choose here an old classic: the Iris dataset introduced by Ronald Fisher in 1936. +Despite its classicity this dataset is not so easy to analyze, as we will see in the following. +

+ +

+The Iris dataset +contains 150 rows, each of them composed of 4 continuous attributes which +corresponds to some flowers measurements. 3 species are equally represented : (Iris) +Setosa, Versicolor and Virginica. +

+ +

+

+ PCA components of iris dataset
+ The two first PCA components of Iris dataset (image found + here) +
+

+ +

+As the figure suggests the goal on this dataset is to discriminate Iris species. +That is to say, our goal is to find a way to answer these questions: +"are two given elements in the same group ?", "which group does a given element belongs to ?". +

+ +

+The mixstore packages take a more general approach: they (try to) learn the data generation +process, and then deduce the groups compositions. Thus, the two above questions can easily +be answered by using the mathematical formulas describing the classes. +Although this approach has several advantages (low sensitivity to outliers, likelihood +to rank models...), finding the adequate model is challenging. +We will not dive into such model selection details. +{# This is a more general and harder problem. #} +

+ +
+ +
+ +

+Density for 2 groups: +££f^{(2)}(x) = \pi_1^{(2)} g_1^{(2)}(x) + \pi_2^{(2)} g_2^{(2)}(x)££ +where £g_i^{(2)} = (2 \pi)^{-d/2} \left| \Sigma_i^{(2)} \right|^{-1/2} \mbox{exp}\left( -\frac{1}{2} \, {}^T(x - \mu_i^{(2)}) (\Sigma_i^{(2)})^{-1} (x - \mu_i^{(2)}) \right)£.
+£x = (x_1,x_2,x_3,x_4)£ with the following correspondances. +

    +
  • £x_1£: sepal length;
  • +
  • £x_2£: sepal width;
  • +
  • £x_3£: petal length;
  • +
  • £x_4£: petal width.
  • +
+

+ +
+ +
+\begin{align*} +\pi_1^{(2)} &= 0.33\\ +\mu_1^{(2)} &= (5.01 3.43 1.46 0.25)\\ +\Sigma_1^{(2)} &= + \begin{pmatrix} + 0.15&0.13&0.02&0.01\\ + 0.13&0.18&0.02&0.01\\ + 0.02&0.02&0.03&0.01\\ + 0.01&0.01&0.01&0.01 + \end{pmatrix} +\end{align*} +
+ +
+\begin{align*} +\pi_2^{(2)} &= 0.67\\ +\mu_2^{(2)} &= (6.26 2.87 4.91 1.68)\\ +\Sigma_2^{(2)} &= + \begin{pmatrix} + 0.40&0.11&0.40&0.14\\ + 0.11&0.11&0.12&0.07\\ + 0.40&0.12&0.61&0.26\\ + 0.14&0.07&0.26&0.17 + \end{pmatrix} +\end{align*} +
+ +
+Penalized log-likelihood (BIC): -561.73 +
+ +
+ +

+Density for 3 groups: +££f^{(3)}(x) = \pi_1^{(3)} g_1^{(3)}(x) + \pi_2^{(3)} g_2^{(3)}(x) + \pi_3^{(3)} g_3^{(3)}(x)££ +(Same parameterizations for cluster densities £g_i^{(3)}£).
+

+ +
+ +
+\begin{align*} +\pi_1^{(3)} &= 0.33\\ +\mu_1^{(3)} &= (5.01 3.43 1.46 0.25)\\ +\Sigma_1^{(3)} &= + \begin{pmatrix} + 0.13&0.11&0.02&0.01\\ + 0.11&0.15&0.01&0.01\\ + 0.02&0.01&0.03&0.01\\ + 0.01&0.01&0.01&0.01 + \end{pmatrix} +\end{align*} +
+ +
+\begin{align*} +\pi_2^{(3)} &= 0.30\\ +\mu_2^{(3)} &= (5.91 2.78 4.20 1.30)\\ +\Sigma_2^{(3)} &= + \begin{pmatrix} + 0.23&0.08&0.15&0.04\\ + 0.08&0.08&0.07&0.03\\ + 0.15&0.07&0.17&0.05\\ + 0.04&0.03&0.05&0.03 + \end{pmatrix} +\end{align*} +
+ +
+\begin{align*} +\pi_3^{(3)} &= 0.37\\ +\mu_3^{(3)} &= (6.55 2.95 5.48 1.96)\\ +\Sigma_3^{(3)} &= + \begin{pmatrix} + 0.43&0.11&0.33&0.07\\ + 0.11&0.12&0.09&0.06\\ + 0.33&0.09&0.36&0.09\\ + 0.07&0.06&0.09&0.09 + \end{pmatrix} +\end{align*} +
+ +
+Penalized log-likelihood (BIC): -562.55 +
+ +
+ +

+As initially stated, the dataset is difficult to cluster because although we know there are +3 species, 2 of them are almost undinstinguishable. That is why log-likelihood values are very close. +We usually consider that a method is good on Iris dataset when it finds 3 clusters, +but 2 is also a correct answer. +

+ +
+ +
+ +{% endblock %} + +{% block javascripts %} +{{ parent() }} + + +{% endblock %} diff --git a/src/Mixstore/StaticBundle/Resources/views/home.html.twig b/src/Mixstore/StaticBundle/Resources/views/home.html.twig new file mode 100644 index 0000000..6d4cc1c --- /dev/null +++ b/src/Mixstore/StaticBundle/Resources/views/home.html.twig @@ -0,0 +1,100 @@ +{% extends "::base.html.twig" %} + +{% block title %}{{ parent() }}home{% endblock %} + +{% block header %} +{{ parent() }} + +{% endblock %} + +{% block content %} + + + +
+ +
+

What ?

+

Every software, library or package referenced here attempts to cluster data + into groups defined as the components of a mixture of probabilistic models. + The resulting classes can be used e.g. for supervised classification or regression.

+

Read more details.

+
+ +
+

Where ?

+ In the store ! +
+ +
+ +
+ +
+

How ?

+

Policy to add a package or feedback.

+
+ +
+

News

+ + {% for newsItem in news %} + + + + + {% endfor %} +
{{ newsItem.created | date('Y-m-d / H:i:s') }}{{ newsItem.name }}
+
+ +
+ +{% endblock %} + +{% block javascripts %} +{{ parent() }} + +{% endblock %} diff --git a/src/Mixstore/StaticBundle/Resources/views/policy.html.twig b/src/Mixstore/StaticBundle/Resources/views/policy.html.twig new file mode 100644 index 0000000..f88668e --- /dev/null +++ b/src/Mixstore/StaticBundle/Resources/views/policy.html.twig @@ -0,0 +1,74 @@ +{% extends "::base.html.twig" %} + +{% block title %}{{ parent() }}policy{% endblock %} + +{% block header %} +{{ parent() }} + +{% endblock %} + +{% block content %} + +
+ +

Procedure to add and maintain packages or usecases

+ +
    +
  1. + Registration is mandatory: follow this link, + and fill in your name and email address. Neither of them will ever be displayed on the website, + but internally we like to identify people modifying the mixstore pages. +
  2. + +
  3. + Once signed up you should be able to login. + Logging in gets you to the main board. + All your actions on the website start from here. +
  4. + +
  5. + Both sections (packages and usecases) have a link "add some new thing". Click on either of them + to add for example a new package. The following fields are mandatory : +
      +
    • Name: the name of your package. +
    • +
    • Headline: a few words to describe what the package does. +
    • +
    • Url: a web link to (at least) download the package. +
    • +
    • Authors: a (unstructured) list of authors. +
    • +
    • Contact: an email address for any exchange related to the package. +
    • +
    +

    + Only the description field is optional, because you might already have the description page + on your own website. But even in this case it might be good for SEO, and to give a preview + of your website to mixstore users. +

    +

    + Mixstore improves the visibility of your package. In return, we kindly ask + you to provide a visible link to Mixstore on your website. +

  6. + +
  7. + Finally, a usecase has the following fields (all mandatory): +
      +
    • Institution: the structure where the work took place. Either academic, + industry (please be more specific) or personal usage. +
    • +
    • Softwares: a list of packages involved (all in the store). +
    • +
    • Headline: a few words describing the context of the usecase. +
    • +
    • Description: an extended abstract showing how the softwares were used. +
    • +
    • Contact: an email address for any exchange related to the usecase. +
    • +
    +
  8. +
+ +
+ +{% endblock %} diff --git a/src/Mixstore/StoreBundle/Controller/PackageController.php b/src/Mixstore/StoreBundle/Controller/PackageController.php new file mode 100644 index 0000000..8538f4d --- /dev/null +++ b/src/Mixstore/StoreBundle/Controller/PackageController.php @@ -0,0 +1,222 @@ +getDoctrine() + ->getManager(); + + $package = $em + ->getRepository('MixstoreStoreBundle:Package') + ->find($id); + + //pass usecases count + rating (to link with feedbacks) + $countAndRating = $em + ->getRepository('MixstoreStoreBundle:Usecase') + ->countByPkgId($id); + if ($countAndRating['rating'] == '') + $countAndRating['rating'] = 'NA'; + $package->rating = $countAndRating['rating']; + $package->ucscount = $countAndRating['ucscount']; + + $user = $this->getUser(); + $owner = (!is_null($user) && $package->getUser()->getId() == $user->getId()); + + return $this->render('MixstoreStoreBundle:Package:view.html.twig', array( + 'pkg' => $package, + 'owner' => $owner, + )); + } + + public function listAction() + { + $em = $this + ->getDoctrine() + ->getManager(); + + $packages = $em + ->getRepository('MixstoreStoreBundle:Package') + ->findAll(); + + $ucsRepository = $em + ->getRepository('MixstoreStoreBundle:Usecase'); + + for ($i=0; $icountByPkgId($packages[$i]->getId()); + if ($countAndRating['rating'] == '') + $countAndRating['rating'] = 'NA'; + $packages[$i]->ucscount = $countAndRating['ucscount']; + $packages[$i]->rating = $countAndRating['rating']; + } + + return $this->render('MixstoreStoreBundle:Package:list.html.twig', array( + 'packages' => $packages, + )); + } + + public function upsertAction($id) + { + $em = $this + ->getDoctrine() + ->getManager(); + + $package = $em + ->getRepository('MixstoreStoreBundle:Package') + ->safeFindById($id); + + //TODO: place this at another location to avoid code redundancy + $user = $this->getUser(); + if (is_null($user) || ( + !in_array('ROLE_ADMIN', $user->getRoles()) && + !is_null($package->getUser()) && + $package->getUser()->getId() != $this->getUser()->getId())) + { + //TODO: nice error page + return $this->redirect($this->generateUrl('mixstore_static_home')); + } + + $formBuilder = $this->createFormBuilder($package); + $formBuilder + ->add('name', 'text') + ->add('headline', 'text') + ->add('url', 'text') + ->add('description', 'textarea', array('required' => false)) + ->add('dependencies', 'text', array('required' => false)) + ->add('authors', 'text') + ->add('contact', 'text') + ->add('language', 'entity', array( + 'class' => 'MixstoreStoreBundle:Language', + 'property' => 'name', + 'query_builder' => function(\Doctrine\ORM\EntityRepository $er) { + return $er->createQueryBuilder('l') + ->orderBy('l.name', 'ASC'); + })) + ->add('bannerfile', 'file', array('label' => 'Banner (1000x300)', 'required' => false)) + ->add('removebanner', 'checkbox', array('label' => 'Remove banner', 'required' => false)); + $form = $formBuilder->getForm(); + + $request = $this->get('request'); + if ($request->getMethod() == 'POST') { + // Link request <-> form ; $package contains data entered in the form + $form->bind($request); + if ($form->isValid()) { + $package->setUser($this->getUser()); + $package->setModified(new \DateTime('now')); + + //HACK: text editor insert extra


tags for an empty description + $description = $package->getDescription(); + if (trim(str_replace('
','', str_replace('

','', str_replace('

','', $description)))) == '') + $package->setDescription(''); + + $bannerfile = $form['bannerfile']->getData(); + $extension = (is_null($bannerfile) ? null : $bannerfile->guessExtension()); + + $bannersDir = $this->get('kernel')->getRootDir().'/../web/mixstore/images/pkg_banners'; + + if (!is_null($extension) && ($extension == 'jpeg' || $extension == 'png')) + { + if (is_null($package->getBannerPath())) + { + $filename = uniqid(rand(), true); + $package->setBannerpath($filename); + } + else + $filename = $package->getBannerpath(); + $bannerfile->move($bannersDir, $filename); + + //HACK: currently hard-coded + $newwidth = 1000; + $newheight = 300; + + $source = ($extension == 'jpeg' + ? imagecreatefromjpeg($bannersDir.'/'.$filename) + : imagecreatefrompng($bannersDir.'/'.$filename)); + + $resizedFile = imagecreatetruecolor($newwidth, $newheight); + list($width, $height) = getimagesize($bannersDir.'/'.$filename); + imagecopyresized($resizedFile, $source, 0, 0, 0, 0, $newwidth, $newheight, $width, $height); + + ($extension == 'jpeg' + ? imagejpeg($resizedFile, $bannersDir.'/'.$filename) + : imagepng($resizedFile, $bannersDir.'/'.$filename)); + + imagedestroy($resizedFile); + } + else if ($package->removebanner == TRUE) + { + unlink($bannersDir.'/'.$package->getBannerpath()); + $package->setBannerpath(null); + } + + $em->persist($package); + $em->flush(); + return $this->redirect($this->generateUrl('mixstore_store_package_view', array('id' => $package->getId()))); + } + } + + //Email notifications [temporary ??!!] + $users = $em + ->getRepository('MixstoreUserBundle:User') + ->findAll(); + $receivers = array(); + foreach ($users as $user) + { + if ($user->getEmailnotif1() || ($id <= 0 && $user->getEmailNotif0())) + $receivers[] = $user->getEmail(); + } + if (count($receivers) > 0) + { + $message = \Swift_Message::newInstance() + ->setSubject('Package '.($id > 0 ? 'update' : 'creation')) + ->setFrom('contact@mixstore.org') + ->setTo($receivers) + ->setBody($this->renderView('MixstoreStoreBundle::upsert-email.txt.twig', array( + 'name' => $this->getUser()->getName(), + 'surname' => $this->getUser()->getSurname(), + 'email' => $this->getUser()->getEmail(), + 'type' => 'Package', + 'id' => $package->getId(), + ))); + $this->get('mailer')->send($message); + } + + return $this->render('MixstoreStoreBundle::upsert.html.twig', array( + 'title' => ($id > 0 ? 'Edit package' : 'New package'), + 'form' => $form->createView(), + )); + } + + public function deleteAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $package = $em + ->getRepository('MixstoreStoreBundle:Package') + ->findById($id)[0]; + + $user = $this->getUser(); + if (is_null($user) || ( + !in_array('ROLE_ADMIN', $user->getRoles()) && + $package->getUser()->getId() != $this->getUser()->getId())) + { + //TODO: nice error page + return $this->redirect($this->generateUrl('mixstore_static_home')); + } + + $em->remove($package); + $em->flush(); + return $this->redirect($this->generateUrl('mixstore_user_board')); + } +} diff --git a/src/Mixstore/StoreBundle/Controller/UsecaseController.php b/src/Mixstore/StoreBundle/Controller/UsecaseController.php new file mode 100644 index 0000000..6db9709 --- /dev/null +++ b/src/Mixstore/StoreBundle/Controller/UsecaseController.php @@ -0,0 +1,169 @@ +getDoctrine() + ->getManager() + ->getRepository('MixstoreStoreBundle:Usecase') + ->find($id); + + $user = $this->getUser(); + $owner = (!is_null($user) && $usecase->getUser()->getId() == $user->getId()); + + return $this->render('MixstoreStoreBundle:Usecase:view.html.twig', array( + 'ucs' => $usecase, + 'owner' => $owner, + )); + } + + public function listAction($pkgid) + { + $em = $this + ->getDoctrine() + ->getManager(); + + $pkgName = $em + ->getRepository('MixstoreStoreBundle:Package') + ->find($pkgid) + ->getName(); + + return $this->render('MixstoreStoreBundle:Usecase:list.html.twig', array( + 'usecases' => $em + ->getRepository('MixstoreStoreBundle:Usecase') + ->findByPackage($pkgid), + 'pkgname' => $pkgName, + )); + } + + public function upsertAction($id, $pkgid) + { + $em = $this + ->getDoctrine() + ->getManager(); + + $usecase = $em + ->getRepository('MixstoreStoreBundle:Usecase') + ->safeFindById($id); + + //TODO: place this in an external service (used at several locations) + $user = $this->getUser(); + if (is_null($user) || ( + !in_array('ROLE_ADMIN', $user->getRoles()) && + !is_null($usecase->getUser()) && + $usecase->getUser()->getId() != $this->getUser()->getId())) + { + //TODO: nice error page + return $this->redirect($this->generateUrl('mixstore_static_home')); + } + + //http://symfony.com/doc/current/reference/forms/types/entity.html + if ($pkgid > 0) + { + $package = $em + ->getRepository('MixstoreStoreBundle:Package') + ->findById($pkgid); + } + + $formBuilder = $this->createFormBuilder($usecase); + if ($pkgid > 0) + { + $formBuilder + ->add('package', 'entity', array( + 'class' => 'MixstoreStoreBundle:Package', + 'choices' => $package, + 'property' => 'name', + 'read_only' => true)); + } + else + { + $formBuilder + ->add('package', 'entity', array( + 'class' => 'MixstoreStoreBundle:Package', + 'property' => 'name')); + } + $formBuilder + ->add('institution', 'text') + ->add('headline', 'text') + ->add('description', 'textarea') + ->add('contact', 'text') + ->add('grade', 'choice', array('choices' => range(0, 10))); + $form = $formBuilder->getForm(); + + $request = $this->get('request'); + if ($request->getMethod() == 'POST') { + // Link request <-> form ; $usecase contains data entered in the form + $form->bind($request); + if ($form->isValid()) { + $usecase->setUser($this->getUser()); + $usecase->setModified(new \DateTime('now')); + $em->persist($usecase); + $em->flush(); + return $this->redirect($this->generateUrl('mixstore_store_usecase_view', array('id' => $usecase->getId()))); + } + } + + //Email notifications [temporary ??!!] + $users = $em + ->getRepository('MixstoreUserBundle:User') + ->findAll(); + $receivers = array(); + foreach ($users as $user) + { + if ($user->getEmailnotif1() || ($id <= 0 && $user->getEmailNotif0())) + $receivers[] = $user->getEmail(); + } + if (count($receivers) > 0) + { + $message = \Swift_Message::newInstance() + ->setSubject('Usecase '.($id > 0 ? 'update' : 'creation')) + ->setFrom('contact@mixstore.org') + ->setTo($receivers) + ->setBody($this->renderView('MixstoreStoreBundle::upsert-email.txt.twig', array( + 'name' => $this->getUser()->getName(), + 'surname' => $this->getUser()->getSurname(), + 'email' => $this->getUser()->getEmail(), + 'type' => 'Usecase', + 'id' => $usecase->getId(), + ))); + $this->get('mailer')->send($message); + } + + return $this->render('MixstoreStoreBundle::upsert.html.twig', array( + 'title' => ($id > 0 ? 'Edit usecase' : 'New usecase'), + 'form' => $form->createView(), + )); + } + + public function deleteAction($id) + { + $usecase = $this + ->getDoctrine() + ->getManager() + ->getRepository('MixstoreStoreBundle:Usecase') + ->findById($id)[0]; + + $user = $this->getUser(); + if (is_null($user) || ( + !in_array('ROLE_ADMIN', $user->getRoles()) && + $usecase->getUser()->getId() != $this->getUser()->getId())) + { + //TODO: nice error page + return $this->redirect($this->generateUrl('mixstore_static_home')); + } + + $em = $this->getDoctrine()->getManager(); + $em->remove($usecase); + $em->flush(); + return $this->redirect($this->generateUrl('mixstore_user_board')); + } +} diff --git a/src/Mixstore/StoreBundle/DependencyInjection/Configuration.php b/src/Mixstore/StoreBundle/DependencyInjection/Configuration.php new file mode 100644 index 0000000..8e6dc7d --- /dev/null +++ b/src/Mixstore/StoreBundle/DependencyInjection/Configuration.php @@ -0,0 +1,29 @@ +root('mixstore_store'); + + // Here you should define the parameters that are allowed to + // configure your bundle. See the documentation linked above for + // more information on that topic. + + return $treeBuilder; + } +} diff --git a/src/Mixstore/StoreBundle/DependencyInjection/MixstoreStoreExtension.php b/src/Mixstore/StoreBundle/DependencyInjection/MixstoreStoreExtension.php new file mode 100644 index 0000000..36f03cf --- /dev/null +++ b/src/Mixstore/StoreBundle/DependencyInjection/MixstoreStoreExtension.php @@ -0,0 +1,28 @@ +processConfiguration($configuration, $configs); + + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->load('services.yml'); + } +} diff --git a/src/Mixstore/StoreBundle/Entity/Language.php b/src/Mixstore/StoreBundle/Entity/Language.php new file mode 100644 index 0000000..4607953 --- /dev/null +++ b/src/Mixstore/StoreBundle/Entity/Language.php @@ -0,0 +1,75 @@ +name = $name; + } + + /** + * Get id + * + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * Set name + * + * @param string $name + * @return Language + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * Get name + * + * @return string + */ + public function getName() + { + return $this->name; + } +} + +/* +* current languages +C, C#, C++, Java, Julia, Python, R, Fortran, Lua, Matlab, Octave, Scilab +* others +Javascript,Objective-C,Perl, PHP,Ruby,Shell,Scala, Go,Groovy,Ada, Android,Boo, Clojure, Common Lisp, Delphi, Eiffel, Erlang, Fantom,Haskell,Node.js, OCaml,Prolog +*/ diff --git a/src/Mixstore/StoreBundle/Entity/Package.php b/src/Mixstore/StoreBundle/Entity/Package.php new file mode 100644 index 0000000..cf05bb5 --- /dev/null +++ b/src/Mixstore/StoreBundle/Entity/Package.php @@ -0,0 +1,397 @@ +user = null; + $this->id = 0; + $this->created = new \DateTime('now'); + $this->modified = new \DateTime('now'); + } + + /** + * Get id + * + * @return integer + */ + public function getId() + { + return $this->id; + } + + //un package a un "webmaster ID" (masqué sur la page du package, mais permettant de savoir qui a le droit de l'éditer) + + /** + * Set name + * + * @param string $name + * @return Package + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * Get name + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Set url + * + * @param string $url + * @return Package + */ + public function setUrl($url) + { + $this->url = $url; + + return $this; + } + + /** + * Get url + * + * @return string + */ + public function getUrl() + { + return $this->url; + } + + /** + * Set description + * + * @param string $description + * @return Package + */ + public function setDescription($description) + { + $this->description = $description; + + return $this; + } + + /** + * Get description + * + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * Set authors + * + * @param string $authors + * @return Package + */ + public function setAuthors($authors) + { + $this->authors = $authors; + + return $this; + } + + /** + * Get authors + * + * @return string + */ + public function getAuthors() + { + return $this->authors; + } + + /** + * Set contact + * + * @param string $contact + * @return Package + */ + public function setContact($contact) + { + $this->contact = $contact; + + return $this; + } + + /** + * Get contact + * + * @return string + */ + public function getContact() + { + return $this->contact; + } + + /** + * Set user + * + * @param \Mixstore\UserBundle\Entity\User $user + * @return Package + */ + public function setUser(\Mixstore\UserBundle\Entity\User $user) + { + $this->user = $user; + + return $this; + } + + /** + * Get user + * + * @return \Mixstore\UserBundle\Entity\User + */ + public function getUser() + { + return $this->user; + } + + /** + * Set headline + * + * @param string $headline + * @return Package + */ + public function setHeadline($headline) + { + $this->headline = $headline; + + return $this; + } + + /** + * Get headline + * + * @return string + */ + public function getHeadline() + { + return $this->headline; + } + + /** + * Set bannerpath + * + * @param string $bannerpath + * @return Package + */ + public function setBannerpath($bannerpath) + { + $this->bannerpath = $bannerpath; + + return $this; + } + + /** + * Get bannerpath + * + * @return string + */ + public function getBannerpath() + { + return $this->bannerpath; + } + + /** + * Set modified + * + * @param \DateTime $modified + * @return Package + */ + public function setModified($modified) + { + $this->modified = $modified; + + return $this; + } + + /** + * Get modified + * + * @return \DateTime + */ + public function getModified() + { + return $this->modified; + } + + /** + * Set language + * + * @param \Mixstore\StoreBundle\Entity\Language $language + * @return Package + */ + public function setLanguage(\Mixstore\StoreBundle\Entity\Language $language) + { + $this->language = $language; + + return $this; + } + + /** + * Get language + * + * @return \Mixstore\StoreBundle\Entity\Language + */ + public function getLanguage() + { + return $this->language; + } + + /** + * Set created + * + * @param \DateTime $created + * @return Package + */ + public function setCreated($created) + { + $this->created = $created; + + return $this; + } + + /** + * Get created + * + * @return \DateTime + */ + public function getCreated() + { + return $this->created; + } + + /** + * Set dependencies + * + * @param string $dependencies + * @return Package + */ + public function setDependencies($dependencies) + { + $this->dependencies = $dependencies; + + return $this; + } + + /** + * Get dependencies + * + * @return string + */ + public function getDependencies() + { + return $this->dependencies; + } +} diff --git a/src/Mixstore/StoreBundle/Entity/PackageRepository.php b/src/Mixstore/StoreBundle/Entity/PackageRepository.php new file mode 100644 index 0000000..fc2a332 --- /dev/null +++ b/src/Mixstore/StoreBundle/Entity/PackageRepository.php @@ -0,0 +1,56 @@ + 0) + { + $qb = $this->createQueryBuilder('p'); + $qb->where('p.id = '.$id); + $package = $qb->getQuery()->getResult()[0]; + } + else + $package = new Package(); + + return $package; + } + + function getAllNames() + { + return $this + ->createQueryBuilder('p') + ->select('p.id, p.name') + ->getQuery() + ->getResult(); + } + + function getBannersUrls() + { + $bannersUrls = $this + ->createQueryBuilder('p') + ->select('p.id, p.bannerpath') + ->where('p.bannerpath IS NOT NULL') + ->getQuery() + ->getResult(); + $result = array(); + for ($i=0; $icreateQueryBuilder('p') + ->select('p.id, p.name, p.created') + ->orderBy('p.created', 'DESC') + ->setMaxResults(3) //currently hard-coded + ->getQuery() + ->getResult(); + } +} diff --git a/src/Mixstore/StoreBundle/Entity/Usecase.php b/src/Mixstore/StoreBundle/Entity/Usecase.php new file mode 100644 index 0000000..3f06b4b --- /dev/null +++ b/src/Mixstore/StoreBundle/Entity/Usecase.php @@ -0,0 +1,304 @@ +user = null; + $this->id = 0; + $this->created = new \DateTime("now"); + $this->modified = new \DateTime("now"); + } + + /** + * Get id + * + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * Set institution + * + * @param string $institution + * @return Usecase + */ + public function setInstitution($institution) + { + $this->institution = $institution; + + return $this; + } + + /** + * Get institution + * + * @return string + */ + public function getInstitution() + { + return $this->institution; + } + + /** + * Set description + * + * @param string $description + * @return Usecase + */ + public function setDescription($description) + { + $this->description = $description; + + return $this; + } + + /** + * Get description + * + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * Set contact + * + * @param string $contact + * @return Usecase + */ + public function setContact($contact) + { + $this->contact = $contact; + + return $this; + } + + /** + * Get contact + * + * @return string + */ + public function getContact() + { + return $this->contact; + } + + /** + * Set user + * + * @param \Mixstore\UserBundle\Entity\User $user + * @return Usecase + */ + public function setUser(\Mixstore\UserBundle\Entity\User $user) + { + $this->user = $user; + + return $this; + } + + /** + * Get user + * + * @return \Mixstore\UserBundle\Entity\User + */ + public function getUser() + { + return $this->user; + } + + /** + * Set headline + * + * @param string $headline + * @return Usecase + */ + public function setHeadline($headline) + { + $this->headline = $headline; + + return $this; + } + + /** + * Get headline + * + * @return string + */ + public function getHeadline() + { + return $this->headline; + } + + /** + * Set package + * + * @param \Mixstore\StoreBundle\Entity\Package $package + * @return Usecase + */ + public function setPackage(\Mixstore\StoreBundle\Entity\Package $package) + { + $this->package = $package; + + return $this; + } + + /** + * Get package + * + * @return \Mixstore\StoreBundle\Entity\Package + */ + public function getPackage() + { + return $this->package; + } + + /** + * Set grade + * + * @param boolean $happy + * @return Usecase + */ + public function setGrade($grade) + { + $this->grade = $grade; + + return $this; + } + + /** + * Get grade + * + * @return boolean + */ + public function getGrade() + { + return $this->grade; + } + + /** + * Set created + * + * @param \DateTime $created + * @return Usecase + */ + public function setCreated($created) + { + $this->created = $created; + + return $this; + } + + /** + * Get created + * + * @return \DateTime + */ + public function getCreated() + { + return $this->created; + } + + /** + * Set modified + * + * @param \DateTime $modified + * @return Usecase + */ + public function setModified($modified) + { + $this->modified = $modified; + + return $this; + } + + /** + * Get modified + * + * @return \DateTime + */ + public function getModified() + { + return $this->modified; + } +} diff --git a/src/Mixstore/StoreBundle/Entity/UsecaseRepository.php b/src/Mixstore/StoreBundle/Entity/UsecaseRepository.php new file mode 100644 index 0000000..df339a4 --- /dev/null +++ b/src/Mixstore/StoreBundle/Entity/UsecaseRepository.php @@ -0,0 +1,33 @@ + 0) + { + $qb = $this->createQueryBuilder('u'); + $qb->where('u.id = '.$id); + $usecase = $qb->getQuery()->getResult()[0]; + } + else + $usecase = new Usecase(); + + return $usecase; + } + + function countByPkgId($pkgid) + { + return $this + ->createQueryBuilder('u') + ->select('COUNT(u.id) AS ucscount, AVG(u.grade) AS rating') + ->where('u.package = '.$pkgid) + ->getQuery() + ->getResult()[0]; + //->getSingleScalarResult(); + } +} diff --git a/src/Mixstore/StoreBundle/MixstoreStoreBundle.php b/src/Mixstore/StoreBundle/MixstoreStoreBundle.php new file mode 100644 index 0000000..85b55ef --- /dev/null +++ b/src/Mixstore/StoreBundle/MixstoreStoreBundle.php @@ -0,0 +1,9 @@ + +{% endblock %} + +{% block content %} + +
+

All packages

+ {% include "MixstoreStoreBundle:Package:list_content.html.twig" %} +
+ +{% endblock %} + +{% block javascripts %} +{{ parent() }} + + +{% endblock %} diff --git a/src/Mixstore/StoreBundle/Resources/views/Package/list_content.html.twig b/src/Mixstore/StoreBundle/Resources/views/Package/list_content.html.twig new file mode 100644 index 0000000..fe79a6f --- /dev/null +++ b/src/Mixstore/StoreBundle/Resources/views/Package/list_content.html.twig @@ -0,0 +1,22 @@ + + + + + + + + + {% for pkg in packages %} + + + + + + + {% endfor %} + +
NameHeadlineLanguageGrade/10 – #feedbacks
{{ pkg.name }}{{ pkg.headline }}{{ pkg.language.name }} + + {% if pkg.rating != 'NA' %} {{ pkg.rating | number_format(2, '.', '') }} {% else %} NA {% endif %} – {{ pkg.ucscount }} + +
diff --git a/src/Mixstore/StoreBundle/Resources/views/Package/view.html.twig b/src/Mixstore/StoreBundle/Resources/views/Package/view.html.twig new file mode 100644 index 0000000..497853d --- /dev/null +++ b/src/Mixstore/StoreBundle/Resources/views/Package/view.html.twig @@ -0,0 +1,66 @@ +{% extends "::base.html.twig" %} + +{% block title %}{{ parent() }}package{% endblock %} + +{% block header %} +{{ parent() }} + +{% endblock %} + +{% block content %} + +{% if pkg.bannerpath != '' %} +
+ +
+{% endif %} + + + +{% if pkg.description != '' %} +
+ {{ pkg.description | raw }} +
+{% endif %} + +{% if pkg.dependencies != '' %} +
+ Dependencies: {{ pkg.dependencies }} +
+{% endif %} + +
+

+ Authors: {{ pkg.authors }} +

+

+ Contact +

+
+ + + +{% if owner or is_granted('ROLE_ADMIN') %} +
+
+ +
+
+ +
+
+{% endif %} + +{% endblock %} diff --git a/src/Mixstore/StoreBundle/Resources/views/Usecase/list.html.twig b/src/Mixstore/StoreBundle/Resources/views/Usecase/list.html.twig new file mode 100644 index 0000000..ca76db3 --- /dev/null +++ b/src/Mixstore/StoreBundle/Resources/views/Usecase/list.html.twig @@ -0,0 +1,28 @@ +{% extends "::base.html.twig" %} + +{% block title %}{{ parent() }}usecases{% endblock %} + +{% block header %} +{{ parent() }} + +{% endblock %} + +{% block content %} + +
+

Usecases for package {{ pkgname }}

+ {% include "MixstoreStoreBundle:Usecase:list_content.html.twig" %} +
+ +{% endblock %} + +{% block javascripts %} +{{ parent() }} + + +{% endblock %} diff --git a/src/Mixstore/StoreBundle/Resources/views/Usecase/list_content.html.twig b/src/Mixstore/StoreBundle/Resources/views/Usecase/list_content.html.twig new file mode 100644 index 0000000..bf9b219 --- /dev/null +++ b/src/Mixstore/StoreBundle/Resources/views/Usecase/list_content.html.twig @@ -0,0 +1,16 @@ + + + + + + + + {% for ucs in usecases %} + + + + + + {% endfor %} + +
PackageHeadlineGrade/10
{{ ucs.package.name }}{{ ucs.headline }}{{ ucs.grade }}
diff --git a/src/Mixstore/StoreBundle/Resources/views/Usecase/view.html.twig b/src/Mixstore/StoreBundle/Resources/views/Usecase/view.html.twig new file mode 100644 index 0000000..9fe1f31 --- /dev/null +++ b/src/Mixstore/StoreBundle/Resources/views/Usecase/view.html.twig @@ -0,0 +1,45 @@ +{% extends "::base.html.twig" %} + +{% block title %}{{ parent() }}Usecase{% endblock %} + +{% block header %} +{{ parent() }} + +{% endblock %} + +{% block content %} + + + +
+ {{ ucs.description | raw }} +
+ +
+ Contact +
+ +
+

+ Grade: {{ ucs.grade }} +

+

+ Last updated: {{ ucs.modified | date('Y-m-d / H:i:s') }} +

+
+ +{% if owner or is_granted('ROLE_ADMIN') %} +
+
+ +
+
+ +
+
+{% endif %} + +{% endblock %} diff --git a/src/Mixstore/StoreBundle/Resources/views/upsert-email.txt.twig b/src/Mixstore/StoreBundle/Resources/views/upsert-email.txt.twig new file mode 100644 index 0000000..f11db01 --- /dev/null +++ b/src/Mixstore/StoreBundle/Resources/views/upsert-email.txt.twig @@ -0,0 +1,5 @@ +{% if is_granted('ROLE_ADMIN') %} +By {{ name }} {{ surname }} ({{ email }}). +{% endif %} + +View online : {% if type == 'Package' %} {{ url('mixstore_store_package_view', { id: id }) }} {% else %} {{ url('mixstore_store_usecase_view', { id: id }) }} {% endif %}. diff --git a/src/Mixstore/StoreBundle/Resources/views/upsert.html.twig b/src/Mixstore/StoreBundle/Resources/views/upsert.html.twig new file mode 100644 index 0000000..d8b92d8 --- /dev/null +++ b/src/Mixstore/StoreBundle/Resources/views/upsert.html.twig @@ -0,0 +1,81 @@ +{% extends "::base.html.twig" %} + +{% block title %}{{ parent() }}upsert package{% endblock %} + +{% block header %} +{{ parent() }} + + + + + + + + + + + + +{% endblock %} + +{% block content %} + +{% form_theme form ':Form:fields.html.twig' %} + +
+

{{ title }}

+ {% if 'ackage' in title %}

Please don't forget to add a link to mixstore on your website. Thanks !

{% endif %} +
+ +
+ {{ form_widget(form) }} +
+
+ +
+
+
+ +{% endblock content %} + +{%block javascripts %} +{{ parent() }} + + + + +{% endblock %} diff --git a/src/Mixstore/UserBundle/Controller/BoardController.php b/src/Mixstore/UserBundle/Controller/BoardController.php new file mode 100644 index 0000000..4e36e0e --- /dev/null +++ b/src/Mixstore/UserBundle/Controller/BoardController.php @@ -0,0 +1,48 @@ +getUser())) + //TODO: nice error page + return $this->redirect($this->generateUrl('mixstore_static_home')); + + $em = $this + ->getDoctrine() + ->getManager(); + + $ucsRepository = $em + ->getRepository('MixstoreStoreBundle:Usecase'); + + $usecases = $ucsRepository + ->findByUser($this->getUser()->getId()); + + for ($i=0; $isoftware = $usecases[$i]->getPackage()->getName(); + + $packages = $em + ->getRepository('MixstoreStoreBundle:Package') + ->findByUser($this->getUser()->getId()); + + //TODO: fix code redundancy (see PackageController.php) + for ($i=0; $icountByPkgId($packages[$i]->getId()); + if (is_null($countAndRating['rating']) || $countAndRating['rating'] == '') + $countAndRating['rating'] = 'NA'; + $packages[$i]->ucscount = $countAndRating['ucscount']; + $packages[$i]->rating = $countAndRating['rating']; + } + + return $this->render('MixstoreUserBundle:Board:index.html.twig', array( + 'packages' => $packages, + 'usecases' => $usecases, + )); + } +} diff --git a/src/Mixstore/UserBundle/Controller/MyAdminController.php b/src/Mixstore/UserBundle/Controller/MyAdminController.php new file mode 100644 index 0000000..a025dab --- /dev/null +++ b/src/Mixstore/UserBundle/Controller/MyAdminController.php @@ -0,0 +1,110 @@ +getUser(); + if (is_null($sadmin) || !in_array('ROLE_SUPER_ADMIN', $sadmin->getRoles())) + //TODO: nice error page + return $this->redirect($this->generateUrl('mixstore_static_home')); + } + + //set initial languages + public function setLanguageAction() + { + $this->checkSuperAdmin(); + + $em = $this->getDoctrine()->getManager(); + foreach (array('C', 'C#', 'C++', 'Fortran', 'Java', 'Julia', 'Lua', 'MATLAB', 'Octave', 'Python', 'R', 'Scilab') as $lgName) + $em->persist(new Language($lgName)); + $em->flush(); + + return new Response('OK'); + } + + public function addLanguageAction($lgname) + { + $this->checkSuperAdmin(); + + $em = $this->getDoctrine()->getManager(); + $em->persist(new Language($lgname)); + $em->flush(); + + return new Response('OK'); + } + + public function usersAction() + { + $this->checkSuperAdmin(); + + return $this->render('MixstoreUserBundle:Admin:users.html.twig', array( + 'users' => $this + ->getDoctrine() + ->getManager() + ->getRepository('MixstoreUserBundle:User') + ->findAll(), + )); + } + + public function toggleAction() + { + $this->checkSuperAdmin(); + + //get id of user to toggle + $userId = $this->getRequest()->get('id'); + //get user to toggle + $em = $this->getDoctrine()->getManager(); + $user = $em + ->getRepository('MixstoreUserBundle:User') + ->findById($userId)[0]; + + if (in_array('ROLE_ADMIN', $user->getRoles())) + $user->setRoles(array('ROLE_USER')); + else + $user->setRoles(array('ROLE_ADMIN')); + + //save new state + $em->persist($user); + $em->flush(); + + //dummy unused answer (no error case for the moment) + return new Response('OK'); + } + + public function deleteAction($id) + { + $this->checkSuperAdmin(); + + $em = $this->getDoctrine()->getManager(); + $user = $em + ->getRepository('MixstoreUserBundle:User') + ->findById($id)[0]; + $em->remove($user); + $em->flush(); + + return new Response('OK'); + } + + //unique usage: set super admin + public function setsaAction() + { + $em = $this->getDoctrine()->getManager(); + $sadmin = $em + ->getRepository('MixstoreUserBundle:User') + ->findById(1)[0]; //HACK: hard-coded ID + + $sadmin->setRoles(array('ROLE_ADMIN', 'ROLE_SUPER_ADMIN')); + $em->persist($sadmin); + $em->flush(); + + return new response('OK'); + } +} diff --git a/src/Mixstore/UserBundle/DependencyInjection/Configuration.php b/src/Mixstore/UserBundle/DependencyInjection/Configuration.php new file mode 100644 index 0000000..99c2d0d --- /dev/null +++ b/src/Mixstore/UserBundle/DependencyInjection/Configuration.php @@ -0,0 +1,29 @@ +root('mixstore_user'); + + // Here you should define the parameters that are allowed to + // configure your bundle. See the documentation linked above for + // more information on that topic. + + return $treeBuilder; + } +} diff --git a/src/Mixstore/UserBundle/DependencyInjection/MixstoreUserExtension.php b/src/Mixstore/UserBundle/DependencyInjection/MixstoreUserExtension.php new file mode 100644 index 0000000..0e9711b --- /dev/null +++ b/src/Mixstore/UserBundle/DependencyInjection/MixstoreUserExtension.php @@ -0,0 +1,28 @@ +processConfiguration($configuration, $configs); + + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->load('services.yml'); + } +} diff --git a/src/Mixstore/UserBundle/Entity/User.php b/src/Mixstore/UserBundle/Entity/User.php new file mode 100644 index 0000000..0d8e5f0 --- /dev/null +++ b/src/Mixstore/UserBundle/Entity/User.php @@ -0,0 +1,163 @@ +id; + } + + /** + * Set name + * + * @param string $name + * @return User + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * Get name + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Set surname + * + * @param string $surname + * @return User + */ + public function setSurname($surname) + { + $this->surname = $surname; + + return $this; + } + + /** + * Get surname + * + * @return string + */ + public function getSurname() + { + return $this->surname; + } + + /** + * Set email (override base behavior) + * + * @param string $email + * @return User + */ + public function setEmail($email) + { + //http://stackoverflow.com/questions/8832916/remove-replace-the-username-field-with-email-using-fosuserbundle-in-symfony2 + $email = is_null($email) ? '' : $email; + parent::setEmail($email); + $this->setUsername($email); + + return $this; + } + + /** + * Set emailnotif0 + * + * @param boolean $emailnotif0 + * @return User + */ + public function setEmailnotif0($emailnotif0) + { + $this->emailnotif0 = $emailnotif0; + + return $this; + } + + /** + * Get emailnotif0 + * + * @return boolean + */ + public function getEmailnotif0() + { + return $this->emailnotif0; + } + + /** + * Set emailnotif1 + * + * @param boolean $emailnotif1 + * @return User + */ + public function setEmailnotif1($emailnotif1) + { + $this->emailnotif1 = $emailnotif1; + + return $this; + } + + /** + * Get emailnotif1 + * + * @return boolean + */ + public function getEmailnotif1() + { + return $this->emailnotif1; + } +} diff --git a/src/Mixstore/UserBundle/Form/Type/ProfileFormType.php b/src/Mixstore/UserBundle/Form/Type/ProfileFormType.php new file mode 100644 index 0000000..12e4bc2 --- /dev/null +++ b/src/Mixstore/UserBundle/Form/Type/ProfileFormType.php @@ -0,0 +1,31 @@ +remove('username'); // we use email as the username + $builder->add('name'); // first name + $builder->add('surname'); // last name + + //$user = $this->securityContext->getToken()->getUser(); + // email notifications on packages/usecases creation + $builder->add('emailnotif0', 'checkbox', array('label' => 'Email notifications', 'required' => false)); + // ...also on updates + $builder->add('emailnotif1', 'checkbox', array('label' => 'Also on updates', 'required' => false)); + } + + public function getName() + { + return 'mixstore_user_profile'; + } +} diff --git a/src/Mixstore/UserBundle/Form/Type/RegistrationFormType.php b/src/Mixstore/UserBundle/Form/Type/RegistrationFormType.php new file mode 100644 index 0000000..3d2c9f6 --- /dev/null +++ b/src/Mixstore/UserBundle/Form/Type/RegistrationFormType.php @@ -0,0 +1,24 @@ +remove('username'); // we use email as the username + $builder->add('name'); // first name + $builder->add('surname'); // last name + } + + public function getName() + { + return 'mixstore_user_registration'; + } +} diff --git a/src/Mixstore/UserBundle/MixstoreUserBundle.php b/src/Mixstore/UserBundle/MixstoreUserBundle.php new file mode 100644 index 0000000..754248d --- /dev/null +++ b/src/Mixstore/UserBundle/MixstoreUserBundle.php @@ -0,0 +1,13 @@ + +{% endblock %} + +{% block content %} + +{% if is_granted('ROLE_SUPER_ADMIN') %} + +
+

All users

+

Click on a line to toggle privileges. Admins in blue. Super-admin(s) in red

+ + + + + + + + + {% for user in users %} + + + + + + + {% endfor %} + +
First nameLast nameEmail
{{ user.name }}{{ user.surname }}{{ user.email }}Delete
+
+ +{% endif %} + +{% endblock %} + +{% block javascripts %} +{{ parent() }} + +{% endblock %} diff --git a/src/Mixstore/UserBundle/Resources/views/Board/index.html.twig b/src/Mixstore/UserBundle/Resources/views/Board/index.html.twig new file mode 100644 index 0000000..a343f21 --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/Board/index.html.twig @@ -0,0 +1,36 @@ +{% extends "::base.html.twig" %} + +{% block title %}{{ parent() }}user board{% endblock %} + +{% block header %} +{{ parent() }} + + +{% endblock %} + +{% block content %} + +
+

My packages

+ {% include "MixstoreStoreBundle:Package:list_content.html.twig" %} + +
+ +
+

My usecases

+ {% include "MixstoreStoreBundle:Usecase:list_content.html.twig" %} + +
+ +{% endblock %} + +{% block javascripts %} +{{ parent() }} + + +{% endblock %} diff --git a/src/Mixstore/UserBundle/Resources/views/ChangePassword/changePassword.html.twig b/src/Mixstore/UserBundle/Resources/views/ChangePassword/changePassword.html.twig new file mode 100644 index 0000000..c0b4e7f --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/ChangePassword/changePassword.html.twig @@ -0,0 +1,18 @@ +{% extends "FOSUserBundle::layout.html.twig" %} + +{% block title %}{{ parent() }}change password{% endblock %} + +{% block fos_user_content %} +{% trans_default_domain 'FOSUserBundle' %} + +
+ {# TODO: do not ask for current password (?!) #} + {{ form_widget(form) }} +
+
+ +
+
+
+ +{% endblock fos_user_content %} diff --git a/src/Mixstore/UserBundle/Resources/views/Profile/edit.html.twig b/src/Mixstore/UserBundle/Resources/views/Profile/edit.html.twig new file mode 100644 index 0000000..66946ba --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/Profile/edit.html.twig @@ -0,0 +1,18 @@ +{% extends "FOSUserBundle::layout.html.twig" %} + +{% block title %}{{ parent() }}edit profile{% endblock %} + +{% block fos_user_content %} +{% trans_default_domain 'FOSUserBundle' %} + + + +{% endblock fos_user_content %} diff --git a/src/Mixstore/UserBundle/Resources/views/Profile/show.html.twig b/src/Mixstore/UserBundle/Resources/views/Profile/show.html.twig new file mode 100644 index 0000000..442af44 --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/Profile/show.html.twig @@ -0,0 +1,21 @@ +{% extends "FOSUserBundle::layout.html.twig" %} + +{% block title %}{{ parent() }}profile{% endblock %} + +{% block fos_user_content %} +{% trans_default_domain 'FOSUserBundle' %} + +
+
+

{{ 'profile.show.email'|trans }}: {{ user.email }}

+

First name: {{ user.name }}

+

Last name: {{ user.surname }}

+ {% if user.emailnotif1 %} +

Notifications enabled for any creation or update

+ {% elseif user.emailnotif0 %} +

Notifications enabled on packages/usecases creations

+ {% endif %} +
+
+ +{% endblock fos_user_content %} diff --git a/src/Mixstore/UserBundle/Resources/views/Registration/checkEmail.html.twig b/src/Mixstore/UserBundle/Resources/views/Registration/checkEmail.html.twig new file mode 100644 index 0000000..f92f0b1 --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/Registration/checkEmail.html.twig @@ -0,0 +1,10 @@ +{% extends "FOSUserBundle::layout.html.twig" %} + +{% block title %}{{ parent() }}check email{% endblock %} + +{% block fos_user_content %} +{% trans_default_domain 'FOSUserBundle' %} + +
{{ 'registration.check_email'|trans({'%email%': user.email}) }}
+ +{% endblock fos_user_content %} diff --git a/src/Mixstore/UserBundle/Resources/views/Registration/confirmed.html.twig b/src/Mixstore/UserBundle/Resources/views/Registration/confirmed.html.twig new file mode 100644 index 0000000..b18c00a --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/Registration/confirmed.html.twig @@ -0,0 +1,14 @@ +{% extends "FOSUserBundle::layout.html.twig" %} + +{% block title %}{{ parent() }}registration confirmed{% endblock %} + +{% block fos_user_content %} +{% trans_default_domain 'FOSUserBundle' %} + +
{{ 'registration.confirmed'|trans({'%username%': user.username}) }}
+ {% if app.session is not empty %} + {% set targetUrl = app.session.get('_security.' ~ app.security.token.providerKey ~ '.target_path') %} + {% if targetUrl is not empty %}{% endif %} + {% endif %} + +{% endblock fos_user_content %} diff --git a/src/Mixstore/UserBundle/Resources/views/Registration/email.txt.twig b/src/Mixstore/UserBundle/Resources/views/Registration/email.txt.twig new file mode 100644 index 0000000..726f539 --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/Registration/email.txt.twig @@ -0,0 +1,12 @@ +{% trans_default_domain 'FOSUserBundle' %} +{% block subject %} +{% autoescape false %} +{{ 'registration.email.subject'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}) }} +{% endautoescape %} +{% endblock %} +{% block body_text %} +{% autoescape false %} +{{ 'registration.email.message'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}) }} +{% endautoescape %} +{% endblock %} +{% block body_html %}{% endblock %} diff --git a/src/Mixstore/UserBundle/Resources/views/Registration/register.html.twig b/src/Mixstore/UserBundle/Resources/views/Registration/register.html.twig new file mode 100644 index 0000000..3514b25 --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/Registration/register.html.twig @@ -0,0 +1,17 @@ +{% extends "FOSUserBundle::layout.html.twig" %} + +{% block title %}{{ parent() }}register{% endblock %} + +{% block fos_user_content %} +{% trans_default_domain 'FOSUserBundle' %} + +
+ {{ form_widget(form) }} +
+
+ +
+
+
+ +{% endblock fos_user_content %} diff --git a/src/Mixstore/UserBundle/Resources/views/Resetting/checkEmail.html.twig b/src/Mixstore/UserBundle/Resources/views/Resetting/checkEmail.html.twig new file mode 100644 index 0000000..70e036f --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/Resetting/checkEmail.html.twig @@ -0,0 +1,14 @@ +{% extends "FOSUserBundle::layout.html.twig" %} + +{% block title %}{{ parent() }}check email{% endblock %} + +{% block fos_user_content %} +{% trans_default_domain 'FOSUserBundle' %} + +
+
+ {{ 'resetting.check_email'|trans({'%email%': email}) }} +
+
+ +{% endblock %} diff --git a/src/Mixstore/UserBundle/Resources/views/Resetting/email.txt.twig b/src/Mixstore/UserBundle/Resources/views/Resetting/email.txt.twig new file mode 100644 index 0000000..409aeeb --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/Resetting/email.txt.twig @@ -0,0 +1,12 @@ +{% trans_default_domain 'FOSUserBundle' %} +{% block subject %} +{% autoescape false %} +{{ 'resetting.email.subject'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}) }} +{% endautoescape %} +{% endblock %} +{% block body_text %} +{% autoescape false %} +{{ 'resetting.email.message'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}) }} +{% endautoescape %} +{% endblock %} +{% block body_html %}{% endblock %} diff --git a/src/Mixstore/UserBundle/Resources/views/Resetting/passwordAlreadyRequested.html.twig b/src/Mixstore/UserBundle/Resources/views/Resetting/passwordAlreadyRequested.html.twig new file mode 100644 index 0000000..7e71a0c --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/Resetting/passwordAlreadyRequested.html.twig @@ -0,0 +1,12 @@ +{% extends "FOSUserBundle::layout.html.twig" %} + +{% block title %}{{ parent() }}password already requested{% endblock %} + +{% block fos_user_content %} +{% trans_default_domain 'FOSUserBundle' %} + +
+
{{ 'resetting.password_already_requested'|trans }}
+
+ +{% endblock fos_user_content %} diff --git a/src/Mixstore/UserBundle/Resources/views/Resetting/request.html.twig b/src/Mixstore/UserBundle/Resources/views/Resetting/request.html.twig new file mode 100644 index 0000000..2fa5cf5 --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/Resetting/request.html.twig @@ -0,0 +1,25 @@ +{% extends "FOSUserBundle::layout.html.twig" %} + +{% block title %}{{ parent() }}request{% endblock %} + +{% block fos_user_content %} +{% trans_default_domain 'FOSUserBundle' %} + +
+
+ {% if invalid_username is defined %} +

{{ 'resetting.request.invalid_username'|trans({'%username%': invalid_username}) }}

+ {% endif %} + +
+ +
+
+
+
+ +
+
+
+ +{% endblock fos_user_content %} diff --git a/src/Mixstore/UserBundle/Resources/views/Resetting/reset.html.twig b/src/Mixstore/UserBundle/Resources/views/Resetting/reset.html.twig new file mode 100644 index 0000000..8c8527c --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/Resetting/reset.html.twig @@ -0,0 +1,17 @@ +{% extends "FOSUserBundle::layout.html.twig" %} + +{% block title %}{{ parent() }}reset{% endblock %} + +{% block fos_user_content %} +{% trans_default_domain 'FOSUserBundle' %} + +
+ {{ form_widget(form) }} +
+
+ +
+
+
+ +{% endblock fos_user_content %} diff --git a/src/Mixstore/UserBundle/Resources/views/Security/login.html.twig b/src/Mixstore/UserBundle/Resources/views/Security/login.html.twig new file mode 100644 index 0000000..dd985b0 --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/Security/login.html.twig @@ -0,0 +1,54 @@ +{% extends "FOSUserBundle::layout.html.twig" %} + +{% block title %}{{ parent() }}login{% endblock %} + +{% block fos_user_content %} +{% trans_default_domain 'FOSUserBundle' %} + +{% if error %} +
+
{{ error|trans }}
+
+{% endif %} + +
+ + + +
+ +
+ +
+

New user ? Sign up first !

+

I have forgotten my password

+
+ +
+ +{% endblock fos_user_content %} diff --git a/src/Mixstore/UserBundle/Resources/views/layout.html.twig b/src/Mixstore/UserBundle/Resources/views/layout.html.twig new file mode 100644 index 0000000..0bab823 --- /dev/null +++ b/src/Mixstore/UserBundle/Resources/views/layout.html.twig @@ -0,0 +1,39 @@ +{% extends "::base.html.twig" %} + +{% block title %}{{ parent() }}user / {% endblock %} + +{% block header %} +{{ parent() }} + + +{% endblock %} + +{% block content %} + +{% for type, messages in app.session.flashbag.all() %} + {% for key, message in messages %} +
+
+ {{ message|trans({}, 'FOSUserBundle') }} +
+
+ {% endfor %} +{% endfor %} + +{% if form is defined %} + {% form_theme form ':Form:fields.html.twig' %} +{% endif %} + +{% block fos_user_content %} +{% endblock fos_user_content %} + +{% endblock %} + +{% block javascripts %} +{{ parent() }} + +{% endblock %} diff --git a/web/.htaccess b/web/.htaccess new file mode 100644 index 0000000..0c5f37d --- /dev/null +++ b/web/.htaccess @@ -0,0 +1,52 @@ +# Use the front controller as index file. It serves as a fallback solution when +# every other rewrite/redirect fails (e.g. in an aliased environment without +# mod_rewrite). Additionally, this reduces the matching process for the +# start page (path "/") because otherwise Apache will apply the rewriting rules +# to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl). +DirectoryIndex app.php + + + RewriteEngine On + + # Determine the RewriteBase automatically and set it as environment variable. + # If you are using Apache aliases to do mass virtual hosting or installed the + # project in a subdirectory, the base path will be prepended to allow proper + # resolution of the app.php file and to redirect to the correct URI. It will + # work in environments without path prefix as well, providing a safe, one-size + # fits all solution. But as you do not need it in this case, you can comment + # the following 2 lines to eliminate the overhead. + RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ + RewriteRule ^(.*) - [E=BASE:%1] + + # Redirect to URI without front controller to prevent duplicate content + # (with and without `/app.php`). Only do this redirect on the initial + # rewrite by Apache and not on subsequent cycles. Otherwise we would get an + # endless redirect loop (request -> rewrite to front controller -> + # redirect -> request -> ...). + # So in case you get a "too many redirects" error or you always get redirected + # to the start page because your Apache does not expose the REDIRECT_STATUS + # environment variable, you have 2 choices: + # - disable this feature by commenting the following 2 lines or + # - use Apache >= 2.3.9 and replace all L flags by END flags and remove the + # following RewriteCond (best solution) + RewriteCond %{ENV:REDIRECT_STATUS} ^$ + RewriteRule ^app\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L] + + # If the requested filename exists, simply serve it. + # We only want to let Apache serve files and not directories. + RewriteCond %{REQUEST_FILENAME} -f + RewriteRule .? - [L] + + # Rewrite all other queries to the front controller. + RewriteRule .? %{ENV:BASE}/app.php [L] + + + + + # When mod_rewrite is not available, we instruct a temporary redirect of + # the start page to the front controller explicitly so that the website + # and the generated links can still be used. + RedirectMatch 302 ^/$ /app.php/ + # RedirectTemp cannot be used instead + + diff --git a/web/app.php b/web/app.php new file mode 100644 index 0000000..4f591c1 --- /dev/null +++ b/web/app.php @@ -0,0 +1,29 @@ +unregister(); +$apcLoader->register(true); +*/ + +require_once __DIR__.'/../app/AppKernel.php'; +//require_once __DIR__.'/../app/AppCache.php'; + +$kernel = new AppKernel('prod', false); +$kernel->loadClassCache(); +//$kernel = new AppCache($kernel); + +// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter +//Request::enableHttpMethodParameterOverride(); +$request = Request::createFromGlobals(); +$response = $kernel->handle($request); +$response->send(); +$kernel->terminate($request, $response); diff --git a/web/app_dev.php b/web/app_dev.php new file mode 100644 index 0000000..872a882 --- /dev/null +++ b/web/app_dev.php @@ -0,0 +1,30 @@ +loadClassCache(); +$request = Request::createFromGlobals(); +$response = $kernel->handle($request); +$response->send(); +$kernel->terminate($request, $response); diff --git a/web/apple-touch-icon.png b/web/apple-touch-icon.png new file mode 100644 index 0000000..11f17e6 Binary files /dev/null and b/web/apple-touch-icon.png differ diff --git a/web/config.php b/web/config.php new file mode 100644 index 0000000..162acfc --- /dev/null +++ b/web/config.php @@ -0,0 +1,124 @@ +getFailedRequirements(); +$minorProblems = $symfonyRequirements->getFailedRecommendations(); + +?> + + + + + + Symfony Configuration + + + + + +
+
+ + + +
+ +
+
+
+

Welcome!

+

Welcome to your new Symfony project.

+

+ This script will guide you through the basic configuration of your project. + You can also do the same by editing the ‘app/config/parameters.yml’ file directly. +

+ + +

Major problems

+

Major problems have been detected and must be fixed before continuing:

+
    + +
  1. getHelpHtml() ?>
  2. + +
+ + + +

Recommendations

+

+ Additionally, toTo enhance your Symfony experience, + it’s recommended that you fix the following: +

+
    + +
  1. getHelpHtml() ?>
  2. + +
+ + + hasPhpIniConfigIssue()): ?> +

* + getPhpIniConfigPath()): ?> + Changes to the php.ini file must be done in "getPhpIniConfigPath() ?>". + + To change settings, create a "php.ini". + +

+ + + +

Your configuration looks good to run Symfony.

+ + + +
+
+
+
Symfony Standard Edition
+
+ + diff --git a/web/favicon.ico b/web/favicon.ico new file mode 100644 index 0000000..8648036 Binary files /dev/null and b/web/favicon.ico differ diff --git a/web/mixstore/css/base.css b/web/mixstore/css/base.css new file mode 100644 index 0000000..8605f5c --- /dev/null +++ b/web/mixstore/css/base.css @@ -0,0 +1,129 @@ +html { + position: relative; + min-height: 100%; +} + +body { + /* Margin bottom by footer height + 15px (??) */ + margin-bottom: 65px; + font-size: 16px; + overflow-x: hidden; /* fix extra margin; +http://stackoverflow.com/questions/23768152/using-container-fluid-within-bootstrap-cause-horizontal-scrollbar */ +} + +/* +div { + font-size: 1.1em; +}*/ + +div.container-fluid { + margin-left: -15px; + margin-right: -15px; +} + +div.row { + margin-left: 0; + margin-right: 0; +} + +footer { + position: absolute; + bottom: 0; + width: 100%; + /* Set the fixed height of the footer here */ + height: 65px; + background-color: #dd4814; + padding-top: 25px; + color: white; + text-align: center; +} + +footer a { + color: black; +} + +footer a:hover { + color: darkgrey; +} + +/* +.navbar-header { + padding-left: 5px; +} +.navbar-right { + padding-right: 5px; +} +*/ + +.navbar { + border-radius: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; +} + +.navbar-default .navbar-brand { + font-style: italic; + color: #C0C0C0; +} + +@media screen and (min-width: 768px) { +li#storemenu { + display: block; + position: absolute; + top: 0; + left: 46%; +} +} + +@media (min-width: 768px) { +.navbar-nav>li>a {/* middle between dd4814 and 97310e */ +background-color:#ba3c11; +} +} + +li#storemenu > a { + font-family: 'Merienda One', sans-serif; +} + +li#loginmenu > a { + font-family: 'Merienda One', sans-serif; +} + +div.navbar { + margin-bottom: 0; +} + +@media screen and (max-width: 767px) { +div.navbar-collapse { + padding-left: 0; + padding-right: 0; +} +ul.nav { + margin: 0; + padding: 0; +} +} + +.center-txt { + text-align: center; +} + +.justify { + text-align: justify; +} + +.bold { + font-weight: bold; +} + +.red { + color: #ff0000; +} + +.blue { + color: #0000ff; +} + +.top-spaced { + margin-top: 20px; +} diff --git a/web/mixstore/css/form.css b/web/mixstore/css/form.css new file mode 100644 index 0000000..3830495 --- /dev/null +++ b/web/mixstore/css/form.css @@ -0,0 +1,20 @@ +form { + margin-top: 25px; +} + +div#afterform { + margin-top: 20px; +} + +select { + margin-top: 9px; +} + +input[type="checkbox"] { + margin-top: 13px; +} + +input[type="file"] { + margin-top: 5px; + /*height: 48px; doesn't work well - TOFIX */ +} diff --git a/web/mixstore/css/static/about.css b/web/mixstore/css/static/about.css new file mode 100644 index 0000000..2bc4d18 --- /dev/null +++ b/web/mixstore/css/static/about.css @@ -0,0 +1,40 @@ +div#maintext { + padding-left: 5%; + padding-right: 5%; + padding-bottom: 15px; +} + +figure { + text-align: center; +} + +figure img { + width: 75%; +} + +@media screen and (max-width: 500px) { +figure img { + width: 95%; + width: 95%; +} +} + +@media screen and (min-width: 768px) { +figure img { + width: 60%; + width: 60%; +} +} + +@media screen and (min-width: 1024px) { +figure img { + width: 600px; + width: 500px; +} +} + +div.borderbottom { + border-bottom: 1px solid grey; + margin-bottom: 20px; + padding-bottom: 15px; +} diff --git a/web/mixstore/css/static/home.css b/web/mixstore/css/static/home.css new file mode 100644 index 0000000..774987e --- /dev/null +++ b/web/mixstore/css/static/home.css @@ -0,0 +1,114 @@ +div#carousel-example-generic { + border-bottom: 1px solid black; +} + +h2, h3 { + text-align: center; +} + +h2 { + font-size: 48px; +} + +p, table { + font-size: 17px; /*1.3em*/ +} + +table { + margin: 0 auto; + width: 95%; + margin-top: 15px; +} + +td { + border: 1px solid grey; + padding: 5px; +} + +div.column { + text-align: center; + height: 350px; + padding-top: 30px; +} + +@media screen and (max-width: 400px) { +div.column { + padding-top: 15px; +} +} + +@media screen and (max-width: 767px) { +div.column { + background-color: white; + border-bottom: 1px solid black; +} +div.xs-shrink { + height: 200px; +} +h2 { + padding-bottom: 15px; +} +} + +@media screen and (min-width: 768px) { +div.column { + padding-left: 3%; + padding-right: 3%; +} +h2 { + padding-bottom: 24px; +} +} + +@media screen and (min-width: 1024px) { +div.column { + padding-left: 5%; + padding-right: 5%; +} +} + +div.borderbottom { + border-bottom: 1px solid grey; +} + +.grey-bg { + background-color: lightgrey; +} + +div#home-carousel { + margin-top: 0; + width: 100%; +} + +div.carousel-playpause { + position: absolute; + bottom: 1px; + z-index: 15; + width: 100%; + text-align: center; + list-style: none; + margin-bottom: 0; +} + +div.carousel-playpause span { + padding-left: 0; + padding-right: 0; + font-size: 115%; + cursor: pointer; +} + +@media screen and (min-width: 768px) { +div.carousel-playpause span { + font-size: 150%; +} +} + +div.carousel-inner div.item img { + width: 100%; +} + +@media screen and (max-width: 515px) { +div.carousel-inner div.item img { + height: 150px; +} +} diff --git a/web/mixstore/css/static/policy.css b/web/mixstore/css/static/policy.css new file mode 100644 index 0000000..1900030 --- /dev/null +++ b/web/mixstore/css/static/policy.css @@ -0,0 +1,18 @@ +div#maintext { + padding-left: 5%; + padding-right: 5%; +} + +ol.policy li { + padding-top: 10px; + padding-bottom: 10px; +} + +ol.policy li ul { + margin-bottom: 3px; +} + +ol.policy li ul li { + padding-top: 1px; + padding-bottom: 1px; +} diff --git a/web/mixstore/css/store/table.css b/web/mixstore/css/store/table.css new file mode 100644 index 0000000..bb1cca0 --- /dev/null +++ b/web/mixstore/css/store/table.css @@ -0,0 +1,50 @@ +table { + margin-left: auto; + margin-right: auto; + width: 100%; +} + +@media screen and (min-width: 768px) { +table { + width: 95%; +} +} + +table, th, td { + text-align: center; +} + +table > thead > tr > th { + border: 1px solid #ccc; + background-color: #E6FFCC; + padding: 13px 5px 13px 5px; +} + +table > tbody > tr > td { + border: 1px solid #ccc; +} + +tr:nth-of-type(even) { + background: #eee; +} + +tr:nth-of-type(odd) { + background: #fff; +} + +td a { + color: #2C3E50; + text-decoration: none; + display: block; + padding: 13px 5px 13px 5px; +} + +td a:hover { + text-decoration: none; + color: #2C3E50; +} + +th[data-sort]{ + cursor:pointer; + color: #480000; +} diff --git a/web/mixstore/css/store/upsert.css b/web/mixstore/css/store/upsert.css new file mode 100644 index 0000000..278b91b --- /dev/null +++ b/web/mixstore/css/store/upsert.css @@ -0,0 +1,29 @@ +.btn-default { + background-color: #333 +} + +.note-editor { + padding-left: 0; + padding-right: 0; +} + +.note-editor .note-editable { + background-color: #eee; +} + +.note-editor .note-codable { + color: white; + background-color: #333; +} + +/* next 2 rules should be used, but do not work with summernote [TOFIX] */ +/* +.CodeMirror { + border: 1px solid #eee; + height: auto; +} +.CodeMirror-scroll { + overflow-y: hidden; + overflow-x: auto; +} +*/ diff --git a/web/mixstore/css/store/view-package.css b/web/mixstore/css/store/view-package.css new file mode 100644 index 0000000..64f7e8e --- /dev/null +++ b/web/mixstore/css/store/view-package.css @@ -0,0 +1,44 @@ +#pkgimage { + display: block; + width: 100%; +} + +#header { + text-align: center; + padding-top: 15px; + padding-bottom: 15px; + border-bottom: 1px solid #ccc; +} + +#description { + border-bottom: 1px solid #ccc; + padding: 15px 0 15px 15px; +} + +#dependencies { + border-bottom: 1px solid #ccc; + padding: 15px 0 15px 15px; +} + +#contact { + margin-top: 20px; + padding-left: 15px; +} + +#moreinfo { + padding-left: 15px; +} + +.flush-right { + text-align: right; +} + +@media screen and (max-width: 515px) { +img#pkgimage { + height: 150px; +} +} + +#admin { + margin-bottom: 20px; +} diff --git a/web/mixstore/css/store/view-usecase.css b/web/mixstore/css/store/view-usecase.css new file mode 100644 index 0000000..115f433 --- /dev/null +++ b/web/mixstore/css/store/view-usecase.css @@ -0,0 +1,30 @@ +/* TODO: merge with view-package.css */ + +#header { + text-align: center; + padding-top: 15px; + padding-bottom: 15px; + border-bottom: 1px solid #ccc; +} + +#description { + border-bottom: 1px solid #ccc; + padding: 15px 0 15px 15px; + margin-bottom: 20px; +} + +#contact { + padding-left: 15px; +} + +#moreinfo { + padding-left: 15px; +} + +.flush-right { + text-align: right; +} + +#admin { + margin-bottom: 20px; +} diff --git a/web/mixstore/css/summernote.min.css b/web/mixstore/css/summernote.min.css new file mode 100644 index 0000000..4dc3d1b --- /dev/null +++ b/web/mixstore/css/summernote.min.css @@ -0,0 +1 @@ +.note-editor{border:1px solid #a9a9a9}.note-editor .note-dropzone{position:absolute;z-index:1;display:none;color:#87cefa;background-color:white;border:2px dashed #87cefa;opacity:.95;pointer-event:none}.note-editor .note-dropzone .note-dropzone-message{display:table-cell;font-size:28px;font-weight:bold;text-align:center;vertical-align:middle}.note-editor .note-dropzone.hover{color:#098ddf;border:2px dashed #098ddf}.note-editor.dragover .note-dropzone{display:table}.note-editor.fullscreen{position:fixed;top:0;left:0;z-index:1050;width:100%}.note-editor.fullscreen .note-editable{background-color:white}.note-editor.fullscreen .note-resizebar{display:none}.note-editor.codeview .note-editable{display:none}.note-editor.codeview .note-codable{display:block}.note-editor .note-toolbar{padding-bottom:5px;padding-left:5px;margin:0;background-color:#f5f5f5;border-bottom:1px solid #a9a9a9}.note-editor .note-toolbar>.btn-group{margin-top:5px;margin-right:5px;margin-left:0}.note-editor .note-toolbar .note-table .dropdown-menu{min-width:0;padding:5px}.note-editor .note-toolbar .note-table .dropdown-menu .note-dimension-picker{font-size:18px}.note-editor .note-toolbar .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-mousecatcher{position:absolute!important;z-index:3;width:10em;height:10em;cursor:pointer}.note-editor .note-toolbar .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-unhighlighted{position:relative!important;z-index:1;width:5em;height:5em;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIj4+Pjp6ekKlAqjAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKhmnaJzPAAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat}.note-editor .note-toolbar .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-highlighted{position:absolute!important;z-index:2;width:1em;height:1em;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIjd6vvD2f9LKLW+AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKwNDEVT0AAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat}.note-editor .note-toolbar .note-style h1,.note-editor .note-toolbar .note-style h2,.note-editor .note-toolbar .note-style h3,.note-editor .note-toolbar .note-style h4,.note-editor .note-toolbar .note-style h5,.note-editor .note-toolbar .note-style h6,.note-editor .note-toolbar .note-style blockquote{margin:0}.note-editor .note-toolbar .note-color .dropdown-toggle{width:20px;padding-left:5px}.note-editor .note-toolbar .note-color .dropdown-menu{min-width:290px}.note-editor .note-toolbar .note-color .dropdown-menu .btn-group{margin:0}.note-editor .note-toolbar .note-color .dropdown-menu .btn-group:first-child{margin:0 5px}.note-editor .note-toolbar .note-color .dropdown-menu .btn-group .note-palette-title{margin:2px 7px;font-size:12px;text-align:center;border-bottom:1px solid #eee}.note-editor .note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset{padding:0 3px;margin:5px;font-size:12px;cursor:pointer;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.note-editor .note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset:hover{background:#eee}.note-editor .note-toolbar .note-para .dropdown-menu{min-width:216px;padding:5px}.note-editor .note-toolbar .note-para .dropdown-menu>div:first-child{margin-right:5px}.note-editor .note-statusbar{background-color:#f5f5f5}.note-editor .note-statusbar .note-resizebar{width:100%;height:8px;cursor:s-resize;border-top:1px solid #a9a9a9}.note-editor .note-statusbar .note-resizebar .note-icon-bar{width:20px;margin:1px auto;border-top:1px solid #a9a9a9}.note-editor .note-popover .popover{max-width:none}.note-editor .note-popover .popover .popover-content{padding:5px}.note-editor .note-popover .popover .popover-content a{display:inline-block;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.note-editor .note-popover .popover .popover-content .btn-group+.btn-group{margin-left:5px}.note-editor .note-popover .popover .arrow{left:20px}.note-editor .note-handle .note-control-selection{position:absolute;display:none;border:1px solid black}.note-editor .note-handle .note-control-selection>div{position:absolute}.note-editor .note-handle .note-control-selection .note-control-selection-bg{width:100%;height:100%;background-color:black;-webkit-opacity:.3;-khtml-opacity:.3;-moz-opacity:.3;opacity:.3;-ms-filter:alpha(opacity=30);filter:alpha(opacity=30)}.note-editor .note-handle .note-control-selection .note-control-handle{width:7px;height:7px;border:1px solid black}.note-editor .note-handle .note-control-selection .note-control-holder{width:7px;height:7px;border:1px solid black}.note-editor .note-handle .note-control-selection .note-control-sizing{width:7px;height:7px;background-color:white;border:1px solid black}.note-editor .note-handle .note-control-selection .note-control-nw{top:-5px;left:-5px;border-right:0;border-bottom:0}.note-editor .note-handle .note-control-selection .note-control-ne{top:-5px;right:-5px;border-bottom:0;border-left:none}.note-editor .note-handle .note-control-selection .note-control-sw{bottom:-5px;left:-5px;border-top:0;border-right:0}.note-editor .note-handle .note-control-selection .note-control-se{right:-5px;bottom:-5px;cursor:se-resize}.note-editor .note-handle .note-control-selection .note-control-selection-info{right:0;bottom:0;padding:5px;margin:5px;font-size:12px;color:white;background-color:black;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-opacity:.7;-khtml-opacity:.7;-moz-opacity:.7;opacity:.7;-ms-filter:alpha(opacity=70);filter:alpha(opacity=70)}.note-editor .note-dialog>div{display:none}.note-editor .note-dialog .note-image-dialog .note-dropzone{min-height:100px;margin-bottom:10px;font-size:30px;line-height:4;color:lightgray;text-align:center;border:4px dashed lightgray}.note-editor .note-dialog .note-help-dialog{font-size:12px;color:#ccc;background:transparent;background-color:#222!important;border:0;-webkit-opacity:.9;-khtml-opacity:.9;-moz-opacity:.9;opacity:.9;-ms-filter:alpha(opacity=90);filter:alpha(opacity=90)}.note-editor .note-dialog .note-help-dialog .modal-content{background:transparent;border:1px solid white;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.note-editor .note-dialog .note-help-dialog a{font-size:12px;color:white}.note-editor .note-dialog .note-help-dialog .title{padding-bottom:5px;font-size:14px;font-weight:bold;color:white;border-bottom:white 1px solid}.note-editor .note-dialog .note-help-dialog .modal-close{font-size:14px;color:#dd0;cursor:pointer}.note-editor .note-dialog .note-help-dialog .note-shortcut-layout{width:100%}.note-editor .note-dialog .note-help-dialog .note-shortcut-layout td{vertical-align:top}.note-editor .note-dialog .note-help-dialog .note-shortcut{margin-top:8px}.note-editor .note-dialog .note-help-dialog .note-shortcut th{font-size:13px;color:#dd0;text-align:left}.note-editor .note-dialog .note-help-dialog .note-shortcut td:first-child{min-width:110px;padding-right:10px;font-family:"Courier New";color:#dd0;text-align:right}.note-editor .note-editable{padding:10px;overflow:auto;outline:0}.note-editor .note-editable[contenteditable="false"]{background-color:#e5e5e5}.note-editor .note-codable{display:none;width:100%;padding:10px;margin-bottom:0;font-family:Menlo,Monaco,monospace,sans-serif;font-size:14px;color:#ccc;background-color:#222;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;box-shadow:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;resize:none}.note-editor .dropdown-menu{min-width:90px}.note-editor .dropdown-menu.right{right:0;left:auto}.note-editor .dropdown-menu.right::before{right:9px;left:auto!important}.note-editor .dropdown-menu.right::after{right:10px;left:auto!important}.note-editor .dropdown-menu li a i{color:deepskyblue;visibility:hidden}.note-editor .dropdown-menu li a.checked i{visibility:visible}.note-editor .note-fontsize-10{font-size:10px}.note-editor .note-color-palette{line-height:1}.note-editor .note-color-palette div .note-color-btn{width:17px;height:17px;padding:0;margin:0;border:1px solid #fff}.note-editor .note-color-palette div .note-color-btn:hover{border:1px solid #000} \ No newline at end of file diff --git a/web/mixstore/css/user/admin.css b/web/mixstore/css/user/admin.css new file mode 100644 index 0000000..2231dd7 --- /dev/null +++ b/web/mixstore/css/user/admin.css @@ -0,0 +1,26 @@ +tr.user { + cursor: pointer; +} + +h2, h4 { + text-align: center; +} + +table { + margin: 0 auto; + width: 75%; + margin-top: 15px; +} + +td { + border: 1px solid grey; + padding: 5px; +} + +tr:nth-child(even) { + background-color: #eee; +} + +tr:nth-child(odd) { + background-color: #fff; +} diff --git a/web/mixstore/css/user/board.css b/web/mixstore/css/user/board.css new file mode 100644 index 0000000..4e8be2e --- /dev/null +++ b/web/mixstore/css/user/board.css @@ -0,0 +1,18 @@ +a.addnew { + display: block; + text-align: center; + margin-top: 10px; +} + +h2 { + text-align: center; +} + +#packages { + border-bottom: 1px solid #ccc; + padding-bottom: 25px; +} + +#usecases { + padding-bottom: 10px; +} diff --git a/web/mixstore/css/user/common.css b/web/mixstore/css/user/common.css new file mode 100644 index 0000000..08137e2 --- /dev/null +++ b/web/mixstore/css/user/common.css @@ -0,0 +1,23 @@ +div.fos_user_user_show { + padding-top: 15px; + margin-bottom: 0; +} + +h1 { + color: grey; + text-align: center; + margin-top: 15px; + margin-bottom: 15px; +} + +div.flash-message { + text-align: center; + margin-top: 20px; + color: blue; +} + +div.error { + text-align: center; + margin-top: 20px; + color: red; +} diff --git a/web/mixstore/fonts/glyphicons-halflings-regular.eot b/web/mixstore/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000..4a4ca86 Binary files /dev/null and b/web/mixstore/fonts/glyphicons-halflings-regular.eot differ diff --git a/web/mixstore/fonts/glyphicons-halflings-regular.svg b/web/mixstore/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 0000000..e3e2dc7 --- /dev/null +++ b/web/mixstore/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/mixstore/fonts/glyphicons-halflings-regular.ttf b/web/mixstore/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000..67fa00b Binary files /dev/null and b/web/mixstore/fonts/glyphicons-halflings-regular.ttf differ diff --git a/web/mixstore/fonts/glyphicons-halflings-regular.woff b/web/mixstore/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 0000000..8c54182 Binary files /dev/null and b/web/mixstore/fonts/glyphicons-halflings-regular.woff differ diff --git a/web/mixstore/images/banner.png b/web/mixstore/images/banner.png new file mode 100644 index 0000000..34735c0 Binary files /dev/null and b/web/mixstore/images/banner.png differ diff --git a/web/mixstore/images/favicon.png b/web/mixstore/images/favicon.png new file mode 100644 index 0000000..4c01f14 Binary files /dev/null and b/web/mixstore/images/favicon.png differ diff --git a/web/mixstore/images/iris_pca.png b/web/mixstore/images/iris_pca.png new file mode 100644 index 0000000..71fe470 Binary files /dev/null and b/web/mixstore/images/iris_pca.png differ diff --git a/web/mixstore/images/pkg_banners/.gitignore b/web/mixstore/images/pkg_banners/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/web/mixstore/images/pkg_banners/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/web/mixstore/js/stupidtable.min.js b/web/mixstore/js/stupidtable.min.js new file mode 100644 index 0000000..f735a65 --- /dev/null +++ b/web/mixstore/js/stupidtable.min.js @@ -0,0 +1 @@ +(function(c){c.fn.stupidtable=function(b){return this.each(function(){var a=c(this);b=b||{};b=c.extend({},c.fn.stupidtable.default_sort_fns,b);a.on("click.stupidtable","th",function(){var d=c(this),f=0,g=c.fn.stupidtable.dir;a.find("th").slice(0,d.index()).each(function(){var a=c(this).attr("colspan")||1;f+=parseInt(a,10)});var e=d.data("sort-default")||g.ASC;d.data("sort-dir")&&(e=d.data("sort-dir")===g.ASC?g.DESC:g.ASC);var l=d.data("sort")||null;null!==l&&(a.trigger("beforetablesort",{column:f, direction:e}),a.css("display"),setTimeout(function(){var h=[],m=b[l],k=a.children("tbody").children("tr");k.each(function(a,b){var d=c(b).children().eq(f),e=d.data("sort-value"),d="undefined"!==typeof e?e:d.text();h.push([d,b])});h.sort(function(a,b){return m(a[0],b[0])});e!=g.ASC&&h.reverse();k=c.map(h,function(a){return a[1]});a.children("tbody").append(k);a.find("th").data("sort-dir",null).removeClass("sorting-desc sorting-asc");d.data("sort-dir",e).addClass("sorting-"+e);a.trigger("aftertablesort", {column:f,direction:e});a.css("display")},10))})})};c.fn.stupidtable.dir={ASC:"asc",DESC:"desc"};c.fn.stupidtable.default_sort_fns={"int":function(b,a){return parseInt(b,10)-parseInt(a,10)},"float":function(b,a){return parseFloat(b)-parseFloat(a)},string:function(b,a){return ba?1:0},"string-ins":function(b,a){b=b.toLowerCase();a=a.toLowerCase();return ba?1:0}}})(jQuery); diff --git a/web/mixstore/js/summernote.min.js b/web/mixstore/js/summernote.min.js new file mode 100644 index 0000000..f7b9287 --- /dev/null +++ b/web/mixstore/js/summernote.min.js @@ -0,0 +1,2 @@ +!function(a){"function"==typeof define&&define.amd?define(["jquery","codemirror"],a):a(window.jQuery,window.CodeMirror)}(function(a,b){"function"!=typeof Array.prototype.reduce&&(Array.prototype.reduce=function(a,b){var c,d,e=this.length>>>0,f=!1;for(1c;++c)this.hasOwnProperty(c)&&(f?d=a(d,this[c],c,this):(d=this[c],f=!0));if(!f)throw new TypeError("Reduce of empty array with no initial value");return d});var c={bMac:navigator.appVersion.indexOf("Mac")>-1,bMSIE:navigator.userAgent.indexOf("MSIE")>-1,bFF:navigator.userAgent.indexOf("Firefox")>-1,jqueryVersion:parseFloat(a.fn.jquery),bCodeMirror:!!b},d=function(){var a=function(a){return function(b){return a===b}},b=function(a,b){return a===b},c=function(){return!0},d=function(){return!1},e=function(a){return function(){return!a.apply(a,arguments)}},f=function(a){return a};return{eq:a,eq2:b,ok:c,fail:d,not:e,self:f}}(),e=function(){var a=function(a){return a[0]},b=function(a){return a[a.length-1]},c=function(a){return a.slice(0,a.length-1)},e=function(a){return a.slice(1)},f=function(a,b){var c=a.indexOf(b);return-1===c?null:a[c+1]},g=function(a,b){var c=a.indexOf(b);return-1===c?null:a[c-1]},h=function(a,b){return b=b||d.self,a.reduce(function(a,c){return a+b(c)},0)},i=function(a){for(var b=[],c=-1,d=a.length;++cc;c++)a[c]&&b.push(a[c]);return b};return{head:a,last:b,initial:c,tail:e,prev:g,next:f,sum:h,from:i,compact:k,clusterBy:j}}(),f=function(){var b=function(b){return b&&a(b).hasClass("note-editable")},g=function(b){return b&&a(b).hasClass("note-control-sizing")},h=function(a){var b=function(b){return function(){return a.find(b)}};return{editor:function(){return a},dropzone:b(".note-dropzone"),toolbar:b(".note-toolbar"),editable:b(".note-editable"),codable:b(".note-codable"),statusbar:b(".note-statusbar"),popover:b(".note-popover"),handle:b(".note-handle"),dialog:b(".note-dialog")}},i=function(a){return function(b){return b&&b.nodeName===a}},j=function(a){return a&&/^DIV|^P|^LI|^H[1-7]/.test(a.nodeName)},k=function(a){return a&&/^UL|^OL/.test(a.nodeName)},l=function(a){return a&&/^TD|^TH/.test(a.nodeName)},m=function(a,c){for(;a;){if(c(a))return a;if(b(a))break;a=a.parentNode}return null},n=function(a,b){b=b||d.fail;var c=[];return m(a,function(a){return c.push(a),b(a)}),c},o=function(b,c){for(var d=n(b),e=c;e;e=e.parentNode)if(a.inArray(e,d)>-1)return e;return null},p=function(a,b){var c=[],d=!1,e=!1;return function f(g){if(g){if(g===a&&(d=!0),d&&!e&&c.push(g),g===b)return void(e=!0);for(var h=0,i=g.childNodes.length;i>h;h++)f(g.childNodes[h])}}(o(a,b)),c},q=function(a,b){b=b||d.fail;for(var c=[];a&&(c.push(a),!b(a));)a=a.previousSibling;return c},r=function(a,b){b=b||d.fail;for(var c=[];a&&(c.push(a),!b(a));)a=a.nextSibling;return c},s=function(a,b){var c=[];return b=b||d.ok,function e(d){a!==d&&b(d)&&c.push(d);for(var f=0,g=d.childNodes.length;g>f;f++)e(d.childNodes[f])}(a),c},t=function(a,b){var c=b.nextSibling,d=b.parentNode;return c?d.insertBefore(a,c):d.appendChild(a),a},u=function(b,c){return a.each(c,function(a,c){b.appendChild(c)}),b},v=i("#text"),w=function(a){return v(a)?a.nodeValue.length:a.childNodes.length},x=function(a){for(var b=0;a=a.previousSibling;)b+=1;return b},y=function(b,c){var f=e.initial(n(c,d.eq(b)));return a.map(f,x).reverse()},z=function(a,b){for(var c=a,d=0,e=b.length;e>d;d++)c=c.childNodes[b[d]];return c},A=function(a,b){if(0===b)return a;if(b>=w(a))return a.nextSibling;if(v(a))return a.splitText(b);var c=a.childNodes[b];return a=t(a.cloneNode(!1),a),u(a,r(c))},B=function(a,b,c){var e=n(b,d.eq(a));return 1===e.length?A(b,c):e.reduce(function(a,d){var e=d.cloneNode(!1);return t(e,d),a===b&&(a=A(a,c)),u(e,r(a)),e})},C=function(a,b){if(a&&a.parentNode){if(a.removeNode)return a.removeNode(b);var c=a.parentNode;if(!b){var d,e,f=[];for(d=0,e=a.childNodes.length;e>d;d++)f.push(a.childNodes[d]);for(d=0,e=f.length;e>d;d++)c.insertBefore(f[d],a)}c.removeChild(a)}},D=function(a){return f.isTextarea(a[0])?a.val():a.html()};return{blank:c.bMSIE?" ":"
",emptyPara:"


",isEditable:b,isControlSizing:g,buildLayoutInfo:h,isText:v,isPara:j,isList:k,isTable:i("TABLE"),isCell:l,isAnchor:i("A"),isDiv:i("DIV"),isLi:i("LI"),isSpan:i("SPAN"),isB:i("B"),isU:i("U"),isS:i("S"),isI:i("I"),isImg:i("IMG"),isTextarea:i("TEXTAREA"),ancestor:m,listAncestor:n,listNext:r,listPrev:q,listDescendant:s,commonAncestor:o,listBetween:p,insertAfter:t,position:x,makeOffsetPath:y,fromOffsetPath:z,split:B,remove:C,html:D}}(),g={version:"0.5.1",options:{width:null,height:null,focus:!1,tabsize:null,styleWithSpan:!0,disableLinkTarget:!1,disableDragAndDrop:!1,codemirror:null,lang:"en-US",direction:null,toolbar:[["style",["style"]],["font",["bold","italic","underline","clear"]],["fontname",["fontname"]],["color",["color"]],["para",["ul","ol","paragraph"]],["height",["height"]],["table",["table"]],["insert",["link","picture","video"]],["view",["fullscreen","codeview"]],["help",["help"]]],oninit:null,onfocus:null,onblur:null,onenter:null,onkeyup:null,onkeydown:null,onImageUpload:null,onImageUploadError:null,onToolbarClick:null,keyMap:{pc:{"CTRL+Z":"undo","CTRL+Y":"redo",TAB:"tab","SHIFT+TAB":"untab","CTRL+B":"bold","CTRL+I":"italic","CTRL+U":"underline","CTRL+SHIFT+S":"strikethrough","CTRL+BACKSLASH":"removeFormat","CTRL+SHIFT+L":"justifyLeft","CTRL+SHIFT+E":"justifyCenter","CTRL+SHIFT+R":"justifyRight","CTRL+SHIFT+J":"justifyFull","CTRL+SHIFT+NUM7":"insertUnorderedList","CTRL+SHIFT+NUM8":"insertOrderedList","CTRL+LEFTBRACKET":"outdent","CTRL+RIGHTBRACKET":"indent","CTRL+NUM0":"formatPara","CTRL+NUM1":"formatH1","CTRL+NUM2":"formatH2","CTRL+NUM3":"formatH3","CTRL+NUM4":"formatH4","CTRL+NUM5":"formatH5","CTRL+NUM6":"formatH6","CTRL+ENTER":"insertHorizontalRule"},mac:{"CMD+Z":"undo","CMD+SHIFT+Z":"redo",TAB:"tab","SHIFT+TAB":"untab","CMD+B":"bold","CMD+I":"italic","CMD+U":"underline","CMD+SHIFT+S":"strikethrough","CMD+BACKSLASH":"removeFormat","CMD+SHIFT+L":"justifyLeft","CMD+SHIFT+E":"justifyCenter","CMD+SHIFT+R":"justifyRight","CMD+SHIFT+J":"justifyFull","CMD+SHIFT+NUM7":"insertUnorderedList","CMD+SHIFT+NUM8":"insertOrderedList","CMD+LEFTBRACKET":"outdent","CMD+RIGHTBRACKET":"indent","CMD+NUM0":"formatPara","CMD+NUM1":"formatH1","CMD+NUM2":"formatH2","CMD+NUM3":"formatH3","CMD+NUM4":"formatH4","CMD+NUM5":"formatH5","CMD+NUM6":"formatH6","CMD+ENTER":"insertHorizontalRule"}}},lang:{"en-US":{font:{bold:"Bold",italic:"Italic",underline:"Underline",strike:"Strike",clear:"Remove Font Style",height:"Line Height",name:"Font Family",size:"Font Size"},image:{image:"Picture",insert:"Insert Image",resizeFull:"Resize Full",resizeHalf:"Resize Half",resizeQuarter:"Resize Quarter",floatLeft:"Float Left",floatRight:"Float Right",floatNone:"Float None",dragImageHere:"Drag an image here",selectFromFiles:"Select from files",url:"Image URL",remove:"Remove Image"},link:{link:"Link",insert:"Insert Link",unlink:"Unlink",edit:"Edit",textToDisplay:"Text to display",url:"To what URL should this link go?",openInNewWindow:"Open in new window"},video:{video:"Video",videoLink:"Video Link",insert:"Insert Video",url:"Video URL?",providers:"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)"},table:{table:"Table"},hr:{insert:"Insert Horizontal Rule"},style:{style:"Style",normal:"Normal",blockquote:"Quote",pre:"Code",h1:"Header 1",h2:"Header 2",h3:"Header 3",h4:"Header 4",h5:"Header 5",h6:"Header 6"},lists:{unordered:"Unordered list",ordered:"Ordered list"},options:{help:"Help",fullscreen:"Full Screen",codeview:"Code View"},paragraph:{paragraph:"Paragraph",outdent:"Outdent",indent:"Indent",left:"Align left",center:"Align center",right:"Align right",justify:"Justify full"},color:{recent:"Recent Color",more:"More Color",background:"BackColor",foreground:"FontColor",transparent:"Transparent",setTransparent:"Set transparent",reset:"Reset",resetToDefault:"Reset to default"},shortcut:{shortcuts:"Keyboard shortcuts",close:"Close",textFormatting:"Text formatting",action:"Action",paragraphFormatting:"Paragraph formatting",documentStyle:"Document Style"},history:{undo:"Undo",redo:"Redo"}}}},h=function(){var b=function(b){return a.Deferred(function(c){a.extend(new FileReader,{onload:function(a){var b=a.target.result;c.resolve(b)},onerror:function(){c.reject(this)}}).readAsDataURL(b)}).promise()},c=function(b){return a.Deferred(function(c){a("").one("load",function(){c.resolve(a(this))}).one("error abort",function(){c.reject(a(this))}).css({display:"none"}).appendTo(document.body).attr("src",b)}).promise()};return{readFileAsDataURL:b,createImage:c}}(),i={isEdit:function(a){return-1!==[8,9,13,32].indexOf(a)},nameFromCode:{8:"BACKSPACE",9:"TAB",13:"ENTER",32:"SPACE",48:"NUM0",49:"NUM1",50:"NUM2",51:"NUM3",52:"NUM4",53:"NUM5",54:"NUM6",55:"NUM7",56:"NUM8",66:"B",69:"E",73:"I",74:"J",75:"K",76:"L",82:"R",83:"S",85:"U",89:"Y",90:"Z",191:"SLASH",219:"LEFTBRACKET",220:"BACKSLASH",221:"RIGHTBRACKET"}},j=function(){var b=function(b,d){if(c.jqueryVersion<1.9){var e={};return a.each(d,function(a,c){e[c]=b.css(c)}),e}return b.css.call(b,d)};this.stylePara=function(b,c){a.each(b.nodes(f.isPara),function(b,d){a(d).css(c)})},this.current=function(c,d){var e=a(f.isText(c.sc)?c.sc.parentNode:c.sc),g=["font-family","font-size","text-align","list-style-type","line-height"],h=b(e,g)||{};if(h["font-size"]=parseInt(h["font-size"]),h["font-bold"]=document.queryCommandState("bold")?"bold":"normal",h["font-italic"]=document.queryCommandState("italic")?"italic":"normal",h["font-underline"]=document.queryCommandState("underline")?"underline":"normal",c.isOnList()){var i=["circle","disc","disc-leading-zero","square"],j=a.inArray(h["list-style-type"],i)>-1;h["list-style"]=j?"unordered":"ordered"}else h["list-style"]="none";var k=f.ancestor(c.sc,f.isPara);if(k&&k.style["line-height"])h["line-height"]=k.style.lineHeight;else{var l=parseInt(h["line-height"])/parseInt(h["font-size"]);h["line-height"]=l.toFixed(1)}return h.image=f.isImg(d)&&d,h.anchor=c.isOnAnchor()&&f.ancestor(c.sc,f.isAnchor),h.aAncestor=f.listAncestor(c.sc,f.isEditable),h}},k=function(){var b=!!document.createRange,c=function(a,b){var c,d,g=a.parentElement(),h=document.body.createTextRange(),i=e.from(g.childNodes);for(c=0;c=0)break;d=i[c]}if(0!==c&&f.isText(i[c-1])){var j=document.body.createTextRange(),k=null;j.moveToElementText(d||g),j.collapse(!d),k=d?d.nextSibling:g.firstChild;var l=a.duplicate();l.setEndPoint("StartToStart",j);for(var m=l.text.replace(/[\r\n]/g,"").length;m>k.nodeValue.length&&k.nextSibling;)m-=k.nodeValue.length,k=k.nextSibling;{k.nodeValue}b&&k.nextSibling&&f.isText(k.nextSibling)&&m===k.nodeValue.length&&(m-=k.nodeValue.length,k=k.nextSibling),g=k,c=m}return{cont:g,offset:c}},g=function(a){var b=function(a,c){var g,h;if(f.isText(a)){var i=f.listPrev(a,d.not(f.isText)),j=e.last(i).previousSibling;g=j||a.parentNode,c+=e.sum(e.tail(i),f.length),h=!j}else{if(g=a.childNodes[c]||a,f.isText(g))return b(g,c);c=0,h=!1}return{cont:g,collapseToStart:h,offset:c}},c=document.body.createTextRange(),g=b(a.cont,a.offset);return c.moveToElementText(g.cont),c.collapse(g.collapseToStart),c.moveStart("character",g.offset),c},h=function(c,h,i,j){this.sc=c,this.so=h,this.ec=i,this.eo=j;var k=function(){if(b){var a=document.createRange();return a.setStart(c,h),a.setEnd(i,j),a}var d=g({cont:c,offset:h});return d.setEndPoint("EndToEnd",g({cont:i,offset:j})),d};this.select=function(){var a=k();if(b){var c=document.getSelection();c.rangeCount>0&&c.removeAllRanges(),c.addRange(a)}else a.select()},this.nodes=function(b){var g=f.listBetween(c,i),h=e.compact(a.map(g,function(a){return f.ancestor(a,b)}));return a.map(e.clusterBy(h,d.eq2),e.head)},this.commonAncestor=function(){return f.commonAncestor(c,i)};var l=function(a){return function(){var b=f.ancestor(c,a);return!!b&&b===f.ancestor(i,a)}};this.isOnEditable=l(f.isEditable),this.isOnList=l(f.isList),this.isOnAnchor=l(f.isAnchor),this.isOnCell=l(f.isCell),this.isCollapsed=function(){return c===i&&h===j},this.insertNode=function(a){var c=k();b?c.insertNode(a):c.pasteHTML(a.outerHTML)},this.toString=function(){var a=k();return b?a.toString():a.text},this.bookmark=function(a){return{s:{path:f.makeOffsetPath(a,c),offset:h},e:{path:f.makeOffsetPath(a,i),offset:j}}}};return{create:function(a,d,e,f){if(0===arguments.length)if(b){var g=document.getSelection();if(0===g.rangeCount)return null;var i=g.getRangeAt(0);a=i.startContainer,d=i.startOffset,e=i.endContainer,f=i.endOffset}else{var j=document.selection.createRange(),k=j.duplicate();k.collapse(!1);var l=j;l.collapse(!0);var m=c(l,!0),n=c(k,!1);a=m.cont,d=m.offset,e=n.cont,f=n.offset}else 2===arguments.length&&(e=a,f=d);return new h(a,d,e,f)},createFromNode:function(a){return this.create(a,0,a,1)},createFromBookmark:function(a,b){var c=f.fromOffsetPath(a,b.s.path),d=b.s.offset,e=f.fromOffsetPath(a,b.e.path),g=b.e.offset;return new h(c,d,e,g)}}}(),l=function(){this.tab=function(a,b){var c=f.ancestor(a.commonAncestor(),f.isCell),d=f.ancestor(c,f.isTable),g=f.listDescendant(d,f.isCell),h=e[b?"prev":"next"](g,c);h&&k.create(h,0).select()},this.createTable=function(b,c){for(var d,e=[],g=0;b>g;g++)e.push(""+f.blank+"");d=e.join("");for(var h,i=[],j=0;c>j;j++)i.push(""+d+"");h=i.join("");var k=''+h+"
";return a(k)[0]}},m=function(){var b=new j,d=new l;this.saveRange=function(a){a.data("range",k.create())},this.restoreRange=function(a){var b=a.data("range");b&&b.select()},this.currentStyle=function(a){var c=k.create();return c.isOnEditable()&&b.current(c,a)},this.undo=function(a){a.data("NoteHistory").undo(a)},this.redo=function(a){a.data("NoteHistory").redo(a)};for(var e=this.recordUndo=function(a){a.data("NoteHistory").recordUndo(a)},g=["bold","italic","underline","strikethrough","justifyLeft","justifyCenter","justifyRight","justifyFull","insertOrderedList","insertUnorderedList","indent","outdent","formatBlock","removeFormat","backColor","foreColor","insertHorizontalRule","fontName"],i=0,m=g.length;m>i;i++)this[g[i]]=function(a){return function(b,c){e(b),document.execCommand(a,!1,c)}}(g[i]);var n=function(b,c,d){e(b);var g=new Array(d+1).join(" ");c.insertNode(a(''+g+"")[0]);var h=a("#noteTab").removeAttr("id");c=k.create(h[0],1),c.select(),f.remove(h[0])};this.tab=function(a,b){var c=k.create();c.isCollapsed()&&c.isOnCell()?d.tab(c):n(a,c,b.tabsize)},this.untab=function(){var a=k.create();a.isCollapsed()&&a.isOnCell()&&d.tab(a,!0)},this.insertImage=function(a,b){h.createImage(b).then(function(b){e(a),b.css({display:"",width:Math.min(a.width(),b.width())}),k.create().insertNode(b[0])}).fail(function(){var b=a.data("callbacks");b.onImageUploadError&&b.onImageUploadError()})},this.insertVideo=function(b,c){e(b);var d,f=/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/,g=c.match(f),h=/\/\/instagram.com\/p\/(.[a-zA-Z0-9]*)/,i=c.match(h),j=/\/\/vine.co\/v\/(.[a-zA-Z0-9]*)/,l=c.match(j),m=/\/\/(player.)?vimeo.com\/([a-z]*\/)*([0-9]{6,11})[?]?.*/,n=c.match(m),o=/.+dailymotion.com\/(video|hub)\/([^_]+)[^#]*(#video=([^_&]+))?/,p=c.match(o);if(g&&11===g[2].length){var q=g[2];d=a("