mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-10-31 09:18:24 +00:00 
			
		
		
		
	Compare commits
	
		
			99 Commits
		
	
	
		
			bootstrap-
			...
			dune-risky
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 915a2e7284 | |||
| cb99074d1f | |||
| cfd9f1bab1 | |||
| 358410cde1 | |||
| 06c74ed5ed | |||
| 25c986cc61 | |||
| cad8174333 | |||
| 75c586fbf8 | |||
| 2cb9dfc250 | |||
| 5350a09951 | |||
| 9b1a66c992 | |||
| 74541f360b | |||
| ea477a9842 | |||
| 73653744d7 | |||
| c3ef8d112c | |||
|  | 8c98f2cf6e | ||
| e1c8278f71 | |||
|  | ed3f46ce7f | ||
| 7503c845df | |||
| 3686a294d3 | |||
| 2db847ada2 | |||
|  | 7819c1204c | ||
|  | e470a6a97e | ||
|  | cd8c47449b | ||
| d6e7fadb4f | |||
|  | 2be1c08c44 | ||
|  | d426d28ba0 | ||
|  | 72e69fc0b3 | ||
| 52472b0ec3 | |||
| cab3b1059d | |||
| 4c82e65c1f | |||
| cf4d7df7ad | |||
| 86d13410c3 | |||
| 19fdf2a503 | |||
|  | 5448238697 | ||
|  | c5250a1059 | ||
| b2c1a7b8de | |||
| 49c6915c0a | |||
| b4583fc6dc | |||
| f7c508939c | |||
| a2160bef7d | |||
| 8641d6bdce | |||
| 5f4d513aa6 | |||
| f47b15de39 | |||
| 7426dc02cf | |||
| a570160aed | |||
| 6e81ef0065 | |||
| e3cc76c689 | |||
| b43f43fa0b | |||
| 7596bd5a06 | |||
| f02d6df262 | |||
| e4e2138765 | |||
| 395735e6f7 | |||
| 2c96c02261 | |||
| 53813f8f29 | |||
|  | b8ef0d28f5 | ||
|  | e973c4013f | ||
|  | 0f9a395dfc | ||
|  | 38ac3badef | ||
|  | cda32fb925 | ||
|  | 58cb34f39b | ||
| 66426f5102 | |||
| 3445335b2d | |||
| e52a9a4330 | |||
| 8adb05c24f | |||
| b1207cbd3e | |||
|  | 09ed671734 | ||
| 93260ea36f | |||
|  | 8756982a78 | ||
| a8f55e064d | |||
| 7df753f1cb | |||
| b0fc4e190f | |||
| 928e0e1eed | |||
| 28e4b2abaf | |||
| c5b21f360c | |||
| 2de8338651 | |||
| fbec64664f | |||
| 6c81fe4ef2 | |||
| 520c0e0f96 | |||
| 2647d4c6a7 | |||
| e7df62b373 | |||
| b2ff470720 | |||
| 69ea88a4d5 | |||
| 9566ea89b1 | |||
| 425d51649f | |||
| c32f730713 | |||
| a48d6d2a0a | |||
| 16b155d449 | |||
| 083f56bff0 | |||
| f526453ba3 | |||
|  | 03243605da | ||
|  | 48e2d2ceab | ||
|  | 777fb25860 | ||
|  | 03601b9707 | ||
| 89d95a0eae | |||
| 6bcdbaf668 | |||
| 0a0895584c | |||
| d7d8f2a60a | |||
| c205bbddd3 | 
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,7 +1,8 @@ | ||||
| .composer/* | ||||
| composer.phar | ||||
| composer.lock | ||||
|  | ||||
| docs/build/ | ||||
| .php_cs.cache | ||||
|  | ||||
| ###> symfony/framework-bundle ### | ||||
| /.env.local | ||||
| @@ -18,3 +19,4 @@ composer.lock | ||||
| /phpunit.xml | ||||
| .phpunit.result.cache | ||||
| ###< phpunit/phpunit ### | ||||
|  | ||||
|   | ||||
| @@ -30,6 +30,10 @@ variables: | ||||
|   POSTGRES_PASSWORD: postgres | ||||
|   # fetch the chill-app using git submodules | ||||
|   GIT_SUBMODULE_STRATEGY: recursive | ||||
|   REDIS_HOST: redis | ||||
|   REDIS_PORT: 6379 | ||||
|   REDIS_URL: redis://redis:6379 | ||||
|  | ||||
|  | ||||
| # Run our tests | ||||
| test: | ||||
|   | ||||
							
								
								
									
										9
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| # Chill framework | ||||
|  | ||||
| Documentation of the Chill software. | ||||
|  | ||||
| The online documentation can be found at http://docs.chill.social | ||||
|  | ||||
| See the [`docs`][1] directory for more. | ||||
|  | ||||
| [1]: docs/README.md | ||||
| @@ -42,6 +42,7 @@ | ||||
|         "symfony/validator": "4.*", | ||||
|         "sensio/framework-extra-bundle": "^5.5", | ||||
|         "symfony/yaml": "4.*", | ||||
|         "symfony/webpack-encore-bundle": "^1.11", | ||||
|         "knplabs/knp-menu": "^3.1", | ||||
|         "knplabs/knp-menu-bundle": "^3.0", | ||||
|         "symfony/templating": "4.*", | ||||
| @@ -56,7 +57,8 @@ | ||||
|         "symfony/browser-kit": "^5.2", | ||||
|         "symfony/css-selector": "^5.2", | ||||
|         "twig/markdown-extra": "^3.3", | ||||
|         "erusev/parsedown": "^1.7" | ||||
|         "erusev/parsedown": "^1.7", | ||||
|         "symfony/serializer": "^5.2" | ||||
|     }, | ||||
|     "conflict": { | ||||
|         "symfony/symfony": "*" | ||||
|   | ||||
| @@ -10,10 +10,19 @@ Compilation into HTML | ||||
|  | ||||
| To compile this documentation : | ||||
|  | ||||
| 1. Install [sphinx-doc](http://sphinx-doc.org) (eg. pip install sphinx &  pip install sphinx_rtd_theme) | ||||
| 1. Install [sphinx-doc](http://sphinx-doc.org) | ||||
|     ``` bash | ||||
|             $ virtualenv .venv # creation of the virtual env (only the first time) | ||||
|             $ source .venv/bin/activate # activate the virtual env | ||||
|     (.venv) $ pip install -r requirements.txt | ||||
|     ``` | ||||
| 2. Install submodules : $ git submodule update --init; | ||||
| 3. run `make html` from the root directory | ||||
| 4. The base file is located on build/html/index.html | ||||
|     ``` bash | ||||
|     $ cd build/html | ||||
|     $ python -m http.server 8888 # will serve the site on the port 8888 | ||||
|     ``` | ||||
|  | ||||
| Contribute | ||||
| =========== | ||||
|   | ||||
| @@ -29,7 +29,7 @@ As Chill rely on the `symfony <http://symfony.com>`_ framework, reading the fram | ||||
|     Timelines <timelines.rst> | ||||
|     Exports <exports.rst> | ||||
|     Embeddable comments <embeddable-comments.rst> | ||||
|     Testing <make-test-working.rst> | ||||
|     Run tests <run-tests.rst> | ||||
|     Useful snippets <useful-snippets.rst> | ||||
|     manual/index.rst | ||||
|     Assets <assets.rst> | ||||
|   | ||||
| @@ -1,231 +0,0 @@ | ||||
| .. Copyright (C)  2014 Champs Libres Cooperative SCRLFS | ||||
|    Permission is granted to copy, distribute and/or modify this document | ||||
|    under the terms of the GNU Free Documentation License, Version 1.3 | ||||
|    or any later version published by the Free Software Foundation; | ||||
|    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. | ||||
|    A copy of the license is included in the section entitled "GNU | ||||
|    Free Documentation License". | ||||
|  | ||||
| Make tests working | ||||
| ****************** | ||||
|  | ||||
| Unit and functional tests are important to ensure that bundle may be deployed securely. | ||||
|  | ||||
| In reason of the Chill architecture, test should be runnable from the bundle's directory and works correctly: this will allow continuous integration tools to run tests automatically.  | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     Integration tools (i.e. `travis-ci <https://travis-ci.org>`_) works like this :  | ||||
|  | ||||
|     * they clone the bundle repository in a virtual machine, using git | ||||
|     * they optionnaly run `composer` to download and install depedencies | ||||
|     * they optionnaly run other command to prepare a database, insert fixtures, ... | ||||
|     * they run test | ||||
|  | ||||
| On the developer's machine test should be runnable with two or three commands **runned from the bundle directory** :  | ||||
|  | ||||
| .. code-block:: bash | ||||
|  | ||||
|    $ composer install --dev | ||||
|    $ // command to insert fixtures, ... | ||||
|    $ phpunit | ||||
|  | ||||
| This chapter has been inspired by `this useful blog post <http://blog.kevingomez.fr/2013/01/09/functional-testing-standalone-symfony2-bundles/>`_. | ||||
|  | ||||
| Bootstrap phpunit for a standalone bundle | ||||
| ========================================== | ||||
|  | ||||
| Unit tests should run after achieving this step. | ||||
|  | ||||
|  | ||||
| phpunit.xml | ||||
| ----------- | ||||
|  | ||||
| A `phpunit.xml.dist` file should be present at the bundle root. | ||||
|  | ||||
| .. code-block:: xml | ||||
|  | ||||
|    <?xml version="1.0" encoding="UTF-8"?> | ||||
|  | ||||
|    <phpunit bootstrap="./Tests/bootstrap.php" colors="true"> | ||||
|         <!-- the file "./Tests/boostrap.php" will be created on the next step --> | ||||
|        <testsuites> | ||||
|            <testsuite name="ChillMain test suite"> | ||||
|                <directory suffix="Test.php">./Tests</directory> | ||||
|            </testsuite> | ||||
|        </testsuites> | ||||
|        <filter> | ||||
|            <whitelist> | ||||
|                <directory>./</directory> | ||||
|                <exclude> | ||||
|                    <directory>./Resources</directory> | ||||
|                    <directory>./Tests</directory> | ||||
|                    <directory>./vendor</directory> | ||||
|                </exclude> | ||||
|           </whitelist> | ||||
|       </filter> | ||||
|    </phpunit> | ||||
|  | ||||
|  | ||||
| bootstrap.php | ||||
| -------------- | ||||
|  | ||||
| A file `boostrap.php`, located in the `Tests` directory, will allow phpunit to resolve class autoloading : | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|    <?php | ||||
|  | ||||
|    if (!is_file($autoloadFile = __DIR__.'/../vendor/autoload.php')) { | ||||
|        throw new \LogicException('Could not find autoload.php in vendor/. Did you run "composer install --dev"?'); | ||||
|    } | ||||
|  | ||||
|    require $autoloadFile; | ||||
|  | ||||
|  | ||||
| composer.json | ||||
| ------------- | ||||
|  | ||||
| The `composer.json` file **located at the bundle's root** should contains all depencies needed to run test (and to execute bundle functions). | ||||
|  | ||||
| Ensure that all dependencies are included in the `require` and `require-dev` sections. | ||||
|  | ||||
|  | ||||
| Functional tests | ||||
| ================ | ||||
|  | ||||
| If you want to access services, database, and run functional tests, you will have to bootstrap a symfony app, with the minimal configuration. Three files are required :  | ||||
|  | ||||
| * a `config_test.yml` file (eventually with a `config.yml`); | ||||
| * a `routing.yml` file | ||||
| * an `AppKernel.php` file | ||||
|  | ||||
| Adapt phpunit.xml | ||||
| ----------------- | ||||
|  | ||||
| You should add reference to the new application within `phpunit.xml.dist`. The directive `<php>` should be added like this, if your `AppKernel.php` file is located in `Tests/Fixtures/App` directory: | ||||
|  | ||||
| .. code-block:: xml | ||||
|  | ||||
|     <?xml version="1.0" encoding="UTF-8"?> | ||||
|  | ||||
|     <phpunit bootstrap="./Tests/bootstrap.php" colors="true"> | ||||
|         <testsuites> | ||||
|             <testsuite name="ChillMain test suite"> | ||||
|                 <directory suffix="Test.php">./Tests</directory> | ||||
|             </testsuite> | ||||
|         </testsuites> | ||||
|         <filter> | ||||
|             <whitelist> | ||||
|                 <directory>./</directory> | ||||
|                 <exclude> | ||||
|                     <directory>./Resources</directory> | ||||
|                     <directory>./Tests</directory> | ||||
|                     <directory>./vendor</directory> | ||||
|                 </exclude> | ||||
|             </whitelist> | ||||
|         </filter> | ||||
|         <!-- the lines we added -->  | ||||
|        <php> | ||||
|             <server name="KERNEL_DIR" value="./Tests/Fixtures/App/" /> | ||||
|         </php> | ||||
|     </phpunit> | ||||
|  | ||||
| AppKernel.php | ||||
| ------------- | ||||
|  | ||||
| This file boostrap the app. It contains three functions. This is the file used in the ChillMain bundle : | ||||
|  | ||||
| .. code-block:: php | ||||
|                                                                                                                                                                                                                   | ||||
|     <?php | ||||
|  | ||||
|     use Symfony\Component\HttpKernel\Kernel; | ||||
|     use Symfony\Component\Config\Loader\LoaderInterface; | ||||
|  | ||||
|     class AppKernel extends Kernel | ||||
|     { | ||||
|         public function registerBundles() | ||||
|         {    | ||||
|             return array( | ||||
|                 new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), | ||||
|                 new Chill\MainBundle\ChillMainBundle(), | ||||
|                 new Symfony\Bundle\SecurityBundle\SecurityBundle(), | ||||
|                 new Symfony\Bundle\TwigBundle\TwigBundle(), | ||||
|                 new \Symfony\Bundle\AsseticBundle\AsseticBundle(), | ||||
|                 #add here all the required bundle (some bundle are not required) | ||||
|             ); | ||||
|         }    | ||||
|  | ||||
|         public function registerContainerConfiguration(LoaderInterface $loader) | ||||
|         {    | ||||
|             $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); | ||||
|         }    | ||||
|  | ||||
|         /**  | ||||
|          * @return string | ||||
|          */ | ||||
|         public function getCacheDir() | ||||
|         {    | ||||
|             return sys_get_temp_dir().'/ChillMainBundle/cache'; | ||||
|         }    | ||||
|  | ||||
|         /**  | ||||
|          * @return string | ||||
|          */ | ||||
|         public function getLogDir() | ||||
|         {    | ||||
|             return sys_get_temp_dir().'/ChillMainBundle/logs'; | ||||
|         }    | ||||
|     } | ||||
|  | ||||
| config_test.yml | ||||
| --------------- | ||||
|  | ||||
| There are only few parameters required for the config file. This is a basic version for ChillMain : | ||||
|  | ||||
| .. code-block:: yaml | ||||
|  | ||||
|     # config/config_test.yml | ||||
|     imports: | ||||
|         - { resource: config.yml } #here we import a config.yml file, this is not required | ||||
|  | ||||
|     framework: | ||||
|         test: ~ | ||||
|         session: | ||||
|             storage_id: session.storage.filesystem | ||||
|  | ||||
| .. code-block:: yaml | ||||
|  | ||||
|    # config/config.yml | ||||
|    framework:  | ||||
|     secret:          Not very secret | ||||
|     router:          { resource: "%kernel.root_dir%/config/routing.yml" } | ||||
|     form:            true | ||||
|     csrf_protection: true | ||||
|     session:         ~ | ||||
|     default_locale:  fr   | ||||
|     translator:      { fallback: fr } | ||||
|     profiler:        { only_exceptions: false } | ||||
|     templating: #required for assetic. Remove if not needed | ||||
|         engines: ['twig'] | ||||
|  | ||||
| .. note::  | ||||
|  | ||||
|     You must adapt config.yml file according to your required bundle. Some options will be missing, other may be removed... | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     If you would like to tests different environments, with differents configuration, you could create differents config_XXX.yml files. | ||||
|  | ||||
| routing.yml | ||||
| ------------ | ||||
|  | ||||
| You should add there all routing information needed for your bundle.  | ||||
|  | ||||
| .. code-block: yaml | ||||
|  | ||||
|     chill_main_bundle: | ||||
|       resource: "@CLChillMainBundle/Resources/config/routing.yml" | ||||
|  | ||||
| That's it. Tests should pass. | ||||
							
								
								
									
										68
									
								
								docs/source/development/run-tests.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								docs/source/development/run-tests.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| .. Copyright (C)  2014 Champs Libres Cooperative SCRLFS | ||||
|    Permission is granted to copy, distribute and/or modify this document | ||||
|    under the terms of the GNU Free Documentation License, Version 1.3 | ||||
|    or any later version published by the Free Software Foundation; | ||||
|    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. | ||||
|    A copy of the license is included in the section entitled "GNU | ||||
|    Free Documentation License". | ||||
|  | ||||
| Run tests | ||||
| ********* | ||||
|  | ||||
| In reason of the Chill architecture, test should be runnable from the bundle's directory and works correctly: this will allow continuous integration tools to run tests automatically.  | ||||
|  | ||||
| From chill app | ||||
| ============== | ||||
|  | ||||
| This is the most convenient method for developer: run test for chill bundle from the main app. | ||||
|  | ||||
| .. code-block:: bash | ||||
|  | ||||
|    # run into a container | ||||
|    docker-compose exec --user $(id -u) php bash | ||||
|    # execute all tests suites | ||||
|    bin/phpunit | ||||
|    # .. or execute a single test | ||||
|    bin/phpunit vendor/chill-project/chill-bundles/src/Bundle/ChillMainBundle/Tests/path/to/FileTest.php | ||||
|  | ||||
| You can also run tests in a single command: | ||||
|  | ||||
| .. code-block:: bash | ||||
|  | ||||
|    docker-compose exec --user $(id -u) php bin/phpunit | ||||
|  | ||||
|  | ||||
| Tests from a bundle (chill-bundles) | ||||
| ----------------------------------- | ||||
|  | ||||
| Those tests needs the whole symfony app to execute Application Tests (which test html page). | ||||
|  | ||||
| For ease, the app is cloned using a :code:`git submodule`, which clone the main app into :code:`tests/app`, and tests are bootstrapped to this app. The dependencies are also installed into `tests/app/vendor` to ensure compliance with relative path from this symfony application. | ||||
|  | ||||
| You may boostrap the tests fro the chill bundle this way: | ||||
|  | ||||
| .. code-block:: bash | ||||
|  | ||||
|    # ensure to be located into the environement (provided by docker suits well) | ||||
|    docker-compose exec --user $(id -u) php bash | ||||
|    # go to chill subdirectory | ||||
|    cd vendor/chill-project/chill-bundles | ||||
|    # install submodule | ||||
|    git submodule init | ||||
|    git submodule update | ||||
|    # install composer and dependencies | ||||
|    curl -sS https://getcomposer.org/installer | php | ||||
|    # run tests | ||||
|    bin/phpunit | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|    If you are on a fresh install, you will need to migrate database schema.  | ||||
|  | ||||
|    The path to console tool must be adapted to the app. To load migration and add fixtures, one can execute the following commands: | ||||
|  | ||||
|    .. code-block:: bash | ||||
|        | ||||
|       tests/app/bin/console doctrine:migrations:migrate | ||||
|       tests/app/bin/console doctrine:fixtures:load | ||||
|  | ||||
| @@ -97,7 +97,7 @@ The has the following signature : | ||||
|          *  | ||||
|          * @param string $context | ||||
|          * @param mixed[] $args the argument to the context. | ||||
|          * @return string[] | ||||
|          * @return TimelineSingleQuery | ||||
|          * @throw  \LogicException if the context is not supported | ||||
|          */ | ||||
|         public function fetchQuery($context, array $args); | ||||
| @@ -163,18 +163,16 @@ The has the following signature : | ||||
| The `fetchQuery` function | ||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ | ||||
|  | ||||
| The fetchQuery function help to build the UNION query to gather events. This function should return an associative array MUST have the following key : | ||||
| The fetchQuery function help to build the UNION query to gather events. This function should return an instance of :code:`TimelineSingleQuery`. For you convenience, this object may be build using an associative array with the following keys: | ||||
|  | ||||
| * `id` : the name of the id column | ||||
| * `type`: a string to indicate the type | ||||
| * `date`: the name of the datetime column, used to order entities by date | ||||
| * `FROM` (in capital) : the FROM clause. May contains JOIN instructions | ||||
| * `FROM`: the FROM clause. May contains JOIN instructions | ||||
| * `WHERE`: the WHERE clause; | ||||
| * `parameters`: the parameters to pass to the query | ||||
|  | ||||
| Those key are optional: | ||||
|  | ||||
| * `WHERE` (in capital) : the WHERE clause.  | ||||
|  | ||||
|  Where relevant, the data must be quoted to avoid SQL injection. | ||||
| The parameters should be replaced into the query by :code:`?`. They will be replaced into the query using prepared statements. | ||||
|  | ||||
| `$context` and `$args` are defined by the bundle which will call the timeline rendering. You may use them to build a different query depending on this context. | ||||
|  | ||||
| @@ -186,6 +184,15 @@ For instance, if the context is `'person'`, the args will be this array : | ||||
|         'person' => $person //a \Chill\PersonBundle\Entity\Person entity | ||||
|     ); | ||||
|  | ||||
| For the context :code:`center`, the args will be: | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     array( | ||||
|         'centers' => [ ]  // an array of \Chill\MainBundle\Entity\Center entities | ||||
|     ); | ||||
|  | ||||
|  | ||||
| You should find in the bundle documentation which contexts are arguments the bundle defines. | ||||
|  | ||||
| .. note:: | ||||
| @@ -199,13 +206,12 @@ Example of an implementation : | ||||
|     namespace Chill\ReportBundle\Timeline; | ||||
|  | ||||
|     use Chill\MainBundle\Timeline\TimelineProviderInterface; | ||||
|     use Chill\MainBundle\Timeline\TimelineSingleQuery; | ||||
|     use Doctrine\ORM\EntityManager; | ||||
|  | ||||
|     /** | ||||
|      * Provide report for inclusion in timeline | ||||
|      * | ||||
|      * @author Julien Fastré <julien.fastre@champs-libres.coop> | ||||
|      * @author Champs Libres <info@champs-libres.coop> | ||||
|      */ | ||||
|     class TimelineReportProvider implements TimelineProviderInterface | ||||
|     { | ||||
| @@ -227,16 +233,17 @@ Example of an implementation : | ||||
|                  | ||||
|                 $metadata = $this->em->getClassMetadata('ChillReportBundle:Report'); | ||||
|                  | ||||
|                 return array( | ||||
|                 return TimelineSingleQuery::fromArray([ | ||||
|                    'id' => $metadata->getColumnName('id'), | ||||
|                    'type' => 'report', | ||||
|                    'date' => $metadata->getColumnName('date'), | ||||
|                    'FROM' => $metadata->getTableName(), | ||||
|                    'WHERE' => sprintf('%s = %d', | ||||
|                    'WHERE' => sprintf('%s = ?', | ||||
|                          $metadata | ||||
|                             ->getAssociationMapping('person')['joinColumns'][0]['name'], | ||||
|                          $args['person']->getId()) | ||||
|                 ); | ||||
|                             ->getAssociationMapping('person')['joinColumns'][0]['name']) | ||||
|                          ) | ||||
|                    'parameters' => [ $args['person']->getId() ] | ||||
|                 ]); | ||||
|             } | ||||
|  | ||||
|         //.... | ||||
|   | ||||
| @@ -18,11 +18,11 @@ | ||||
|        <testsuite name="MainBundle"> | ||||
|          <directory suffix="Test.php">src/Bundle/ChillMainBundle/Tests/</directory> | ||||
|        </testsuite> | ||||
|  | ||||
|        <!-- | ||||
|        <testsuite name="PersonBundle"> | ||||
|          <directory suffix="Test.php">src/Bundle/ChillPersonBundle/Tests/</directory> | ||||
|         </testsuite> | ||||
|  | ||||
|       --> | ||||
|       </testsuites> | ||||
|  | ||||
|     <listeners> | ||||
|   | ||||
| @@ -38,7 +38,7 @@ use Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency; | ||||
|  * Class Activity | ||||
|  * | ||||
|  * @package Chill\ActivityBundle\Entity | ||||
|  * @ORM\Entity() | ||||
|  * @ORM\Entity(repositoryClass="Chill\ActivityBundle\Repository\ActivityRepository") | ||||
|  * @ORM\Table(name="activity") | ||||
|  * @ORM\HasLifecycleCallbacks() | ||||
|  * @UserCircleConsistency( | ||||
|   | ||||
| @@ -0,0 +1,169 @@ | ||||
| <?php | ||||
|  | ||||
| /* | ||||
|  * Chill is a software for social workers | ||||
|  * | ||||
|  * Copyright (C) 2021, Champs Libres Cooperative SCRLFS, | ||||
|  * <http://www.champs-libres.coop>, <info@champs-libres.coop> | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as | ||||
|  * published by the Free Software Foundation, either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\ActivityBundle\Repository; | ||||
|  | ||||
| use Chill\ActivityBundle\Entity\Activity; | ||||
| use Chill\PersonBundle\Entity\Person; | ||||
| use Chill\ActivityBundle\Repository\ActivityRepository; | ||||
| use Chill\ActivityBundle\Security\Authorization\ActivityVoter; | ||||
| use Chill\MainBundle\Entity\Scope; | ||||
| use Doctrine\ORM\QueryBuilder; | ||||
| use Doctrine\ORM\Query\Expr\Orx; | ||||
| use Chill\MainBundle\Security\Authorization\AuthorizationHelper; | ||||
| use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | ||||
| use Symfony\Component\Security\Core\Role\Role; | ||||
| use Doctrine\ORM\EntityManagerInterface; | ||||
|  | ||||
|  | ||||
| final class ActivityACLAwareRepository  | ||||
| { | ||||
|     private AuthorizationHelper $authorizationHelper; | ||||
|  | ||||
|     private TokenStorageInterface $tokenStorage; | ||||
|  | ||||
|     private ActivityRepository $repository; | ||||
|  | ||||
|     private EntityManagerInterface $em; | ||||
|  | ||||
|     public function __construct( | ||||
|         AuthorizationHelper $authorizationHelper, | ||||
|         TokenStorageInterface $tokenStorage, | ||||
|         ActivityRepository $repository, | ||||
|         EntityManagerInterface $em | ||||
|     ) { | ||||
|         $this->authorizationHelper = $authorizationHelper; | ||||
|         $this->tokenStorage = $tokenStorage; | ||||
|         $this->repository = $repository; | ||||
|         $this->em = $em; | ||||
|     } | ||||
|  | ||||
|     public function queryTimelineIndexer(string $context, array $args = []): array | ||||
|     { | ||||
|         $metadataActivity = $this->em->getClassMetadata(Activity::class); | ||||
|  | ||||
|         $from = $this->getFromClauseCenter($args); | ||||
|         [$where, $parameters] = $this->getWhereClause($context, $args); | ||||
|  | ||||
|         return [ | ||||
|            'id' => $metadataActivity->getTableName() | ||||
|                 .'.'.$metadataActivity->getColumnName('id'), | ||||
|            'type' => 'activity', | ||||
|            'date' => $metadataActivity->getTableName() | ||||
|                 .'.'.$metadataActivity->getColumnName('date'), | ||||
|            'FROM' => $from, | ||||
|            'WHERE' => $where, | ||||
|            'parameters' => $parameters | ||||
|        ]; | ||||
|     } | ||||
|  | ||||
|     private function getFromClauseCenter(array $args): string | ||||
|     { | ||||
|         $metadataActivity = $this->em->getClassMetadata(Activity::class); | ||||
|         $metadataPerson = $this->em->getClassMetadata(Person::class); | ||||
|         $associationMapping = $metadataActivity->getAssociationMapping('person'); | ||||
|          | ||||
|         return $metadataActivity->getTableName().' JOIN ' | ||||
|             .$metadataPerson->getTableName().' ON ' | ||||
|             .$metadataPerson->getTableName().'.'. | ||||
|                 $associationMapping['joinColumns'][0]['referencedColumnName'] | ||||
|             .' = ' | ||||
|             .$associationMapping['joinColumns'][0]['name'] | ||||
|             ; | ||||
|     } | ||||
|  | ||||
|     private function getWhereClause(string $context, array $args): array | ||||
|     { | ||||
|         $where = ''; | ||||
|         $parameters = []; | ||||
|          | ||||
|         $metadataActivity = $this->em->getClassMetadata(Activity::class); | ||||
|         $metadataPerson = $this->em->getClassMetadata(Person::class); | ||||
|         $activityToPerson = $metadataActivity->getAssociationMapping('person')['joinColumns'][0]['name']; | ||||
|         $activityToScope  = $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name']; | ||||
|         $personToCenter = $metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name']; | ||||
|  | ||||
|  | ||||
|         // acls: | ||||
|         $role = new Role(ActivityVoter::SEE); | ||||
|         $reachableCenters = $this->authorizationHelper->getReachableCenters($this->tokenStorage->getToken()->getUser(),  | ||||
|                 $role); | ||||
|          | ||||
|         if (count($reachableCenters) === 0) { | ||||
|             // insert a dummy condition | ||||
|             return 'FALSE = TRUE'; | ||||
|         } | ||||
|  | ||||
|         if ($context === 'person') {  | ||||
|             // we start with activities having the person_id linked to person  | ||||
|             $where .= sprintf('%s = ? AND ', $activityToPerson); | ||||
|             $parameters[] = $person->getId(); | ||||
|         } | ||||
|          | ||||
|         // we add acl (reachable center and scopes) | ||||
|         $where .= '('; // first loop for the for centers | ||||
|         $centersI = 0; // like centers#i | ||||
|         foreach ($reachableCenters as $center) { | ||||
|             // we pass if not in centers | ||||
|             if (!\in_array($center, $args['centers'])) { | ||||
|                 continue; | ||||
|             } | ||||
|             // we get all the reachable scopes for this center | ||||
|             $reachableScopes = $this->authorizationHelper->getReachableScopes($this->tokenStorage->getToken()->getUser(), $role, $center); | ||||
|             // we get the ids for those scopes | ||||
|             $reachablesScopesId = array_map( | ||||
|                 function(Scope $scope) { return $scope->getId(); },  | ||||
|                 $reachableScopes | ||||
|             ); | ||||
|  | ||||
|             // if not the first center | ||||
|             if ($centersI > 0) { | ||||
|                 $where .= ') OR ('; | ||||
|             } | ||||
|  | ||||
|             // condition for the center | ||||
|             $where .= sprintf(' %s.%s = ? ', $metadataPerson->getTableName(), $personToCenter); | ||||
|             $parameters[] = $center->getId(); | ||||
|  | ||||
|             // begin loop for scopes | ||||
|             $where .= ' AND ('; | ||||
|             $scopesI = 0; //like scope#i | ||||
|  | ||||
|             foreach ($reachablesScopesId as $scopeId) { | ||||
|                 if ($scopesI > 0) { | ||||
|                     $where .= ' OR '; | ||||
|                 } | ||||
|                 $where .= sprintf(' %s.%s = ? ', $metadataActivity->getTableName(), $activityToScope); | ||||
|                 $parameters[] = $scopeId; | ||||
|                 $scopesI ++; | ||||
|             } | ||||
|             // close loop for scopes | ||||
|             $where .= ') '; | ||||
|             $centersI++; | ||||
|         } | ||||
|         // close loop for centers | ||||
|         $where .= ')'; | ||||
|          | ||||
|         return [$where, $parameters]; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,42 @@ | ||||
| <?php | ||||
|  | ||||
| /* | ||||
|  * Chill is a software for social workers | ||||
|  * | ||||
|  * Copyright (C) 2021, Champs Libres Cooperative SCRLFS, | ||||
|  * <http://www.champs-libres.coop>, <info@champs-libres.coop> | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as | ||||
|  * published by the Free Software Foundation, either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\ActivityBundle\Repository; | ||||
|  | ||||
| use Chill\ActivityBundle\Entity\Activity; | ||||
| use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; | ||||
| use Doctrine\Persistence\ManagerRegistry; | ||||
|  | ||||
| /** | ||||
|  * @method AccompanyingPeriodParticipation|null find($id, $lockMode = null, $lockVersion = null) | ||||
|  * @method AccompanyingPeriodParticipation|null findOneBy(array $criteria, array $orderBy = null) | ||||
|  * @method AccompanyingPeriodParticipation[]    findAll() | ||||
|  * @method AccompanyingPeriodParticipation[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) | ||||
|  */ | ||||
| class ActivityRepository extends ServiceEntityRepository | ||||
| { | ||||
|     public function __construct(ManagerRegistry $registry) | ||||
|     { | ||||
|         parent::__construct($registry, Activity::class); | ||||
|     } | ||||
|      | ||||
| } | ||||
| @@ -1,11 +1,11 @@ | ||||
| {% import 'ChillActivityBundle:ActivityReason:macro.html.twig' as m %} | ||||
|  | ||||
| <div> | ||||
|     <h3>{{ activity.date|format_date('long') }}<span class="activity"> / {{ 'Activity'|trans }}</span></h3> | ||||
|   <h3>{{ activity.date|format_date('long') }}<span class="activity"> / {{ 'Activity'|trans }}</span>{% if 'person' != context %} / {{ activity.person|chill_entity_render_box({'addLink': true}) }}{% endif %}</h3> | ||||
|     <div class="statement"> | ||||
|         <span class="statement">{{ '%user% has done an %activity_type%'|trans( | ||||
|            { | ||||
|              '%user%' : user, | ||||
|              '%user%' : activity.user, | ||||
|              '%activity_type%': activity.type.name|localize_translatable_string, | ||||
|              '%date%' : activity.date|format_date('long') } | ||||
|         ) }}</span> | ||||
| @@ -29,13 +29,13 @@ | ||||
|  | ||||
|     <ul class="record_actions"> | ||||
|         <li> | ||||
|             <a href="{{ path('chill_activity_activity_show', { 'person_id': person.id, 'id': activity.id} ) }}" class="sc-button bt-view"> | ||||
|             <a href="{{ path('chill_activity_activity_show', { 'person_id': activity.person.id, 'id': activity.id} ) }}" class="sc-button bt-view"> | ||||
|                 {{ 'Show the activity'|trans }} | ||||
|             </a> | ||||
|         </li> | ||||
|         {% if is_granted('CHILL_ACTIVITY_UPDATE', activity) %} | ||||
|         <li> | ||||
|             <a href="{{ path('chill_activity_activity_edit', { 'person_id': person.id, 'id': activity.id} ) }}" class="sc-button bt-edit"> | ||||
|             <a href="{{ path('chill_activity_activity_edit', { 'person_id': activity.person.id, 'id': activity.id} ) }}" class="sc-button bt-edit"> | ||||
|                 {{ 'Edit the activity'|trans }} | ||||
|             </a> | ||||
|         </li> | ||||
|   | ||||
| @@ -21,6 +21,7 @@ | ||||
| namespace Chill\ActivityBundle\Timeline; | ||||
|  | ||||
| use Chill\MainBundle\Timeline\TimelineProviderInterface; | ||||
| use Chill\ActivityBundle\Repository\ActivityACLAwareRepository; | ||||
| use Doctrine\ORM\EntityManager; | ||||
| use Chill\MainBundle\Security\Authorization\AuthorizationHelper; | ||||
| use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | ||||
| @@ -28,13 +29,13 @@ use Symfony\Component\Security\Core\Role\Role; | ||||
| use Doctrine\ORM\Mapping\ClassMetadata; | ||||
| use Chill\PersonBundle\Entity\Person; | ||||
| use Chill\MainBundle\Entity\Scope; | ||||
| use Chill\ActivityBundle\Entity\Activity; | ||||
| use Chill\MainBundle\Timeline\TimelineSingleQuery; | ||||
|  | ||||
| /** | ||||
|  * Provide activity for inclusion in timeline | ||||
|  * | ||||
|  * @author Julien Fastré <julien.fastre@champs-libres.coop> | ||||
|  * @author Champs Libres <info@champs-libres.coop> | ||||
|  */ | ||||
| */ | ||||
| class TimelineActivityProvider implements TimelineProviderInterface | ||||
| { | ||||
|      | ||||
| @@ -55,6 +56,10 @@ class TimelineActivityProvider implements TimelineProviderInterface | ||||
|      * @var \Chill\MainBundle\Entity\User  | ||||
|      */ | ||||
|     protected $user; | ||||
|  | ||||
|     protected ActivityACLAwareRepository $aclAwareRepository; | ||||
|  | ||||
|     private const SUPPORTED_CONTEXTS = [ 'center', 'person']; | ||||
|      | ||||
|     /** | ||||
|      * TimelineActivityProvider constructor. | ||||
| @@ -66,11 +71,13 @@ class TimelineActivityProvider implements TimelineProviderInterface | ||||
|     public function __construct( | ||||
|         EntityManager $em, | ||||
|         AuthorizationHelper $helper, | ||||
|         TokenStorageInterface $storage | ||||
|         TokenStorageInterface $storage, | ||||
|         ActivityACLAwareRepository $aclAwareRepository | ||||
|     ) | ||||
|     { | ||||
|         $this->em = $em; | ||||
|         $this->helper = $helper; | ||||
|         $this->aclAwareRepository = $aclAwareRepository; | ||||
|          | ||||
|         if (!$storage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User) | ||||
|         { | ||||
| @@ -86,67 +93,69 @@ class TimelineActivityProvider implements TimelineProviderInterface | ||||
|      */ | ||||
|     public function fetchQuery($context, array $args) | ||||
|     { | ||||
|         $this->checkContext($context); | ||||
|         if ('center' === $context) { | ||||
|             return TimelineSingleQuery::fromArray($this->aclAwareRepository | ||||
|                 ->queryTimelineIndexer($context, $args)); | ||||
|         } | ||||
|          | ||||
|         $metadataActivity = $this->em->getClassMetadata('ChillActivityBundle:Activity'); | ||||
|         $metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person'); | ||||
|         $metadataActivity = $this->em->getClassMetadata(Activity::class); | ||||
|  | ||||
|         [$where, $parameters] =  $this->getWhereClauseForPerson($args['person']); | ||||
|          | ||||
|         return array( | ||||
|         return TimelineSingleQuery::fromArray([ | ||||
|            'id' => $metadataActivity->getTableName() | ||||
|                 .'.'.$metadataActivity->getColumnName('id'), | ||||
|            'type' => 'activity', | ||||
|            'date' => $metadataActivity->getTableName() | ||||
|                 .'.'.$metadataActivity->getColumnName('date'), | ||||
|            'FROM' => $this->getFromClause($metadataActivity, $metadataPerson), | ||||
|            'WHERE' => $this->getWhereClause($metadataActivity, $metadataPerson, | ||||
|                    $args['person']) | ||||
|         ); | ||||
|            'FROM' => $this->getFromClausePerson($args['person']), | ||||
|            'WHERE' => $where, | ||||
|            'parameters' => $parameters | ||||
|        ]); | ||||
|     } | ||||
|      | ||||
|     private function getWhereClause(ClassMetadata $metadataActivity,  | ||||
|             ClassMetadata $metadataPerson, Person $person) | ||||
|     private function getWhereClauseForPerson(Person $person) | ||||
|     { | ||||
|         $role = new Role('CHILL_ACTIVITY_SEE'); | ||||
|         $reachableCenters = $this->helper->getReachableCenters($this->user,  | ||||
|                 $role); | ||||
|         $parameters = []; | ||||
|         $metadataActivity = $this->em->getClassMetadata(Activity::class); | ||||
|         $associationMapping = $metadataActivity->getAssociationMapping('person'); | ||||
|          | ||||
|         if (count($reachableCenters) === 0) { | ||||
|             return 'FALSE = TRUE'; | ||||
|         $role = new Role('CHILL_ACTIVITY_SEE'); | ||||
|         $reachableScopes =  $this->helper->getReachableScopes($this->user, | ||||
|             $role, $person->getCenter()); | ||||
|         $whereClause = sprintf(' {activity.person_id} = ? AND {activity.scope_id} IN ({scopes_ids}) '); | ||||
|         $scopes_ids = []; | ||||
|  | ||||
|         // first parameter: activity.person_id  | ||||
|         $parameters[] = $person->getId(); | ||||
|  | ||||
|         // loop on reachable scopes  | ||||
|         foreach ($reachableScopes as $scope) { | ||||
|             if (\in_array($scope->getId(), $scopes_ids)) { | ||||
|                 continue; | ||||
|             } | ||||
|             $scopes_ids[] = '?';  | ||||
|             $parameters[] = $scope->getId(); | ||||
|         } | ||||
|          | ||||
|         // we start with activities having the person_id linked to person  | ||||
|         // (currently only context "person" is supported) | ||||
|         $whereClause = sprintf('%s = %d', | ||||
|                  $associationMapping['joinColumns'][0]['name'], | ||||
|                  $person->getId()); | ||||
|          | ||||
|         // we add acl (reachable center and scopes) | ||||
|         $centerAndScopeLines = array(); | ||||
|         foreach ($reachableCenters as $center) { | ||||
|             $reachablesScopesId = array_map( | ||||
|                     function(Scope $scope) { return $scope->getId(); }, | ||||
|                     $this->helper->getReachableScopes($this->user, $role,  | ||||
|                         $person->getCenter()) | ||||
|                 ); | ||||
|                      | ||||
|             $centerAndScopeLines[] = sprintf('(%s = %d AND %s IN (%s))', | ||||
|                     $metadataPerson->getTableName().'.'. | ||||
|                         $metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'], | ||||
|                     $center->getId(), | ||||
|                     $metadataActivity->getTableName().'.'. | ||||
|  | ||||
|         return [ | ||||
|             \strtr( | ||||
|                 $whereClause, | ||||
|                 [ | ||||
|                     '{activity.person_id}' => $associationMapping['joinColumns'][0]['name'], | ||||
|                     '{activity.scope_id}' => $metadataActivity->getTableName().'.'. | ||||
|                         $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'], | ||||
|                     implode(',', $reachablesScopesId)); | ||||
|              | ||||
|         } | ||||
|         $whereClause .= ' AND ('.implode(' OR ', $centerAndScopeLines).')'; | ||||
|          | ||||
|         return $whereClause; | ||||
|                     '{scopes_ids}' => \implode(", ", $scopes_ids) | ||||
| , | ||||
|                 ] | ||||
|             ), | ||||
|             $parameters | ||||
|         ]; | ||||
|     } | ||||
|      | ||||
|     private function getFromClause(ClassMetadata $metadataActivity, | ||||
|             ClassMetadata $metadataPerson) | ||||
|     private function getFromClausePerson() | ||||
|     { | ||||
|         $metadataActivity = $this->em->getClassMetadata(Activity::class); | ||||
|         $metadataPerson = $this->em->getClassMetadata(Person::class); | ||||
|         $associationMapping = $metadataActivity->getAssociationMapping('person'); | ||||
|          | ||||
|         return $metadataActivity->getTableName().' JOIN ' | ||||
| @@ -157,14 +166,14 @@ class TimelineActivityProvider implements TimelineProviderInterface | ||||
|             .$associationMapping['joinColumns'][0]['name'] | ||||
|             ; | ||||
|     } | ||||
|  | ||||
|      | ||||
|     /** | ||||
|      *  | ||||
|      * {@inheritDoc} | ||||
|      */ | ||||
|     public function getEntities(array $ids) | ||||
|     { | ||||
|         $activities = $this->em->getRepository('ChillActivityBundle:Activity') | ||||
|         $activities = $this->em->getRepository(Activity::class) | ||||
|               ->findBy(array('id' => $ids)); | ||||
|          | ||||
|         $result = array(); | ||||
| @@ -183,14 +192,13 @@ class TimelineActivityProvider implements TimelineProviderInterface | ||||
|     { | ||||
|         $this->checkContext($context); | ||||
|          | ||||
|         return array( | ||||
|         return [ | ||||
|            'template' => 'ChillActivityBundle:Timeline:activity_person_context.html.twig', | ||||
|            'template_data' => array( | ||||
|            'template_data' => [ | ||||
|               'activity' => $entity, | ||||
|               'person' => $args['person'], | ||||
|               'user' => $entity->getUser() | ||||
|            ) | ||||
|         ); | ||||
|               'context' => $context | ||||
|             ] | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -210,7 +218,7 @@ class TimelineActivityProvider implements TimelineProviderInterface | ||||
|      */ | ||||
|     private function checkContext($context) | ||||
|     { | ||||
|         if ($context !== 'person') { | ||||
|         if (FALSE === \in_array($context, self::SUPPORTED_CONTEXTS)) { | ||||
|             throw new \LogicException("The context '$context' is not " | ||||
|                   . "supported. Currently only 'person' is supported"); | ||||
|         } | ||||
|   | ||||
| @@ -22,6 +22,8 @@ services: | ||||
|             - '@doctrine.orm.entity_manager' | ||||
|             - '@chill.main.security.authorization.helper' | ||||
|             - '@security.token_storage' | ||||
|             - '@Chill\ActivityBundle\Repository\ActivityACLAwareRepository' | ||||
|         public: true | ||||
|         tags: | ||||
|             - { name: chill.timeline, context: 'person' } | ||||
|             - { name: chill.timeline, context: 'center' } | ||||
|   | ||||
| @@ -1,18 +1,32 @@ | ||||
| --- | ||||
| services: | ||||
|     chill_activity.repository.activity_type: | ||||
|         class: Doctrine\ORM\EntityRepository | ||||
|         factory: ['@doctrine.orm.entity_manager', getRepository] | ||||
|         arguments: | ||||
|             - 'Chill\ActivityBundle\Entity\ActivityType' | ||||
|              | ||||
|  | ||||
|     chill_activity.repository.reason: | ||||
|         class: Doctrine\ORM\EntityRepository | ||||
|         factory: ['@doctrine.orm.entity_manager', getRepository] | ||||
|         arguments: | ||||
|             - 'Chill\ActivityBundle\Entity\ActivityReason' | ||||
|              | ||||
|  | ||||
|     chill_activity.repository.reason_category: | ||||
|         class: Doctrine\ORM\EntityRepository | ||||
|         factory: ['@doctrine.orm.entity_manager', getRepository] | ||||
|         arguments: | ||||
|             - 'Chill\ActivityBundle\Entity\ActivityReasonCategory' | ||||
|  | ||||
|     Chill\ActivityBundle\Repository\ActivityRepository: | ||||
|         tags: [doctrine.repository_service] | ||||
|         arguments: | ||||
|             - '@Doctrine\Persistence\ManagerRegistry' | ||||
|  | ||||
|     Chill\ActivityBundle\Repository\ActivityACLAwareRepository: | ||||
|         arguments: | ||||
|             $tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface' | ||||
|             $authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper' | ||||
|             $repository: '@Chill\ActivityBundle\Repository\ActivityRepository' | ||||
|             $em: '@Doctrine\ORM\EntityManagerInterface' | ||||
|  | ||||
|   | ||||
| @@ -22,13 +22,12 @@ class ChoiceWithOtherType extends AbstractType | ||||
|      */ | ||||
|     public function buildForm(FormBuilderInterface $builder, array $options) | ||||
|     { | ||||
|  | ||||
|         //add an 'other' entry in choices array | ||||
|         $options['choices'][$this->otherValueLabel] = '_other'; | ||||
|         //ChoiceWithOther must always be expanded | ||||
|         $options['expanded'] = true; | ||||
|         // adding a default value for choice | ||||
|         $options['empty_data'] = null; | ||||
|         $options['empty_data'] = $options['multiple'] ? [] : null; | ||||
|  | ||||
|         $builder | ||||
|             ->add('_other', TextType::class, array('required' => false)) | ||||
|   | ||||
| @@ -23,6 +23,7 @@ namespace Chill\EventBundle\Timeline; | ||||
| use Chill\EventBundle\Entity\Event; | ||||
| use Chill\MainBundle\Entity\Scope; | ||||
| use Chill\MainBundle\Timeline\TimelineProviderInterface; | ||||
| use Chill\MainBundle\Timeline\TimelineSingleQuery; | ||||
| use Doctrine\ORM\EntityManager; | ||||
| use Chill\MainBundle\Security\Authorization\AuthorizationHelper; | ||||
| use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | ||||
| @@ -88,13 +89,14 @@ class TimelineEventProvider implements TimelineProviderInterface | ||||
|         $metadataParticipation = $this->em->getClassMetadata('ChillEventBundle:Participation'); | ||||
|         $metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person'); | ||||
|          | ||||
|         $query = array( | ||||
|         $query = TimelineSingleQuery::fromArray([ | ||||
|             'id' => $metadataEvent->getTableName().'.'.$metadataEvent->getColumnName('id'), | ||||
|             'type' => 'event', | ||||
|             'date' => $metadataEvent->getTableName().'.'.$metadataEvent->getColumnName('date'), | ||||
|             'FROM' => $this->getFromClause($metadataEvent, $metadataParticipation, $metadataPerson), | ||||
|             'WHERE' => $this->getWhereClause($metadataEvent, $metadataParticipation, $metadataPerson, $args['person']) | ||||
|         ); | ||||
|             'WHERE' => $this->getWhereClause($metadataEvent, $metadataParticipation, $metadataPerson, $args['person']), | ||||
|             'parameters' => [] | ||||
|         ]); | ||||
|          | ||||
|         return $query; | ||||
|     } | ||||
| @@ -238,4 +240,4 @@ class TimelineEventProvider implements TimelineProviderInterface | ||||
|         ); | ||||
|     } | ||||
|      | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,91 @@ | ||||
| <?php | ||||
|  | ||||
| /* | ||||
|  * Copyright (C) 2015 Champs-Libres Coopérative <info@champs-libres.coop> | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\MainBundle\Controller; | ||||
|  | ||||
| use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | ||||
| use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||||
| use Symfony\Component\HttpFoundation\Response; | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
| use Chill\MainBundle\Timeline\TimelineBuilder; | ||||
| use Chill\MainBundle\Pagination\PaginatorFactory; | ||||
| use Chill\PersonBundle\Security\Authorization\PersonVoter; | ||||
| use Chill\MainBundle\Security\Authorization\AuthorizationHelper; | ||||
| use Symfony\Component\Security\Core\Role\Role; | ||||
| use Symfony\Component\Routing\Annotation\Route; | ||||
| use Symfony\Component\Security\Core\Security; | ||||
|  | ||||
| class TimelineCenterController extends AbstractController | ||||
| { | ||||
|      | ||||
|     protected TimelineBuilder $timelineBuilder; | ||||
|      | ||||
|     protected PaginatorFactory $paginatorFactory; | ||||
|  | ||||
|     private Security $security; | ||||
|      | ||||
|     public function __construct( | ||||
|         TimelineBuilder $timelineBuilder, | ||||
|         PaginatorFactory $paginatorFactory, | ||||
|         Security $security | ||||
|     ) { | ||||
|         $this->timelineBuilder = $timelineBuilder; | ||||
|         $this->paginatorFactory = $paginatorFactory; | ||||
|         $this->security = $security; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @Route("/{_locale}/center/timeline", | ||||
|      *    name="chill_center_timeline", | ||||
|      *    methods={"GET"} | ||||
|      *  ) | ||||
|      */  | ||||
|     public function centerAction(Request $request) | ||||
|     { | ||||
|         // collect reachable center for each group | ||||
|         $user = $this->security->getUser(); | ||||
|         $centers = []; | ||||
|         foreach ($user->getGroupCenters() as $group) { | ||||
|             $centers[] = $group->getCenter(); | ||||
|         } | ||||
|  | ||||
|         if (0 === count($centers)) { | ||||
|             throw $this->createNotFoundException(); | ||||
|         } | ||||
|          | ||||
|         $nbItems = $this->timelineBuilder->countItems('center',  | ||||
|             [ 'centers' => $centers ] | ||||
|             ); | ||||
|          | ||||
|         $paginator = $this->paginatorFactory->create($nbItems); | ||||
|          | ||||
|         return $this->render('@ChillMain/Timeline/index.html.twig', array | ||||
|             ( | ||||
|                 'timeline' => $this->timelineBuilder->getTimelineHTML( | ||||
|                     'center',  | ||||
|                     [ 'centers' => $centers ], | ||||
|                     $paginator->getCurrentPage()->getFirstItemNumber(), | ||||
|                     $paginator->getItemsPerPage() | ||||
|                     ), | ||||
|                 'nb_items' => $nbItems, | ||||
|                 'paginator' => $paginator | ||||
|             ) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -47,11 +47,11 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, | ||||
| { | ||||
|     /** | ||||
|      * widget factory | ||||
|      *  | ||||
|      * | ||||
|      * @var WidgetFactoryInterface[] | ||||
|      */ | ||||
|     protected $widgetFactories = array(); | ||||
|      | ||||
|  | ||||
|     /** | ||||
|      * @param WidgetFactoryInterface $factory | ||||
|      */ | ||||
| @@ -59,7 +59,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, | ||||
|     { | ||||
|         $this->widgetFactories[] = $factory; | ||||
|     } | ||||
|      | ||||
|  | ||||
|     /** | ||||
|      * @return WidgetFactoryInterface[] | ||||
|      */ | ||||
| @@ -67,7 +67,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, | ||||
|     { | ||||
|         return $this->widgetFactories; | ||||
|     } | ||||
|      | ||||
|  | ||||
|     /** | ||||
|      * {@inheritDoc} | ||||
|      * @param array $configs | ||||
| @@ -79,31 +79,31 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, | ||||
|         // configuration for main bundle | ||||
|         $configuration = $this->getConfiguration($configs, $container); | ||||
|         $config = $this->processConfiguration($configuration, $configs); | ||||
|          | ||||
|  | ||||
|         $container->setParameter('chill_main.installation_name', | ||||
|             $config['installation_name']); | ||||
|  | ||||
|         $container->setParameter('chill_main.available_languages', | ||||
|             $config['available_languages']); | ||||
|          | ||||
|         $container->setParameter('chill_main.routing.resources',  | ||||
|             $config['routing']['resources']);  | ||||
|          | ||||
|  | ||||
|         $container->setParameter('chill_main.routing.resources', | ||||
|             $config['routing']['resources']); | ||||
|  | ||||
|         $container->setParameter('chill_main.pagination.item_per_page', | ||||
|             $config['pagination']['item_per_page']); | ||||
|          | ||||
|         $container->setParameter('chill_main.notifications',  | ||||
|  | ||||
|         $container->setParameter('chill_main.notifications', | ||||
|             $config['notifications']); | ||||
|          | ||||
|         $container->setParameter('chill_main.redis',  | ||||
|  | ||||
|         $container->setParameter('chill_main.redis', | ||||
|             $config['redis']); | ||||
|          | ||||
|         $container->setParameter('chill_main.phone_helper',  | ||||
|  | ||||
|         $container->setParameter('chill_main.phone_helper', | ||||
|             $config['phone_helper'] ?? []); | ||||
|          | ||||
|  | ||||
|         // add the key 'widget' without the key 'enable' | ||||
|         $container->setParameter('chill_main.widgets',  | ||||
|             isset($config['widgets']['homepage']) ?  | ||||
|         $container->setParameter('chill_main.widgets', | ||||
|             isset($config['widgets']['homepage']) ? | ||||
|                 array('homepage' => $config['widgets']['homepage']): | ||||
|                 array() | ||||
|                 ); | ||||
| @@ -131,10 +131,11 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, | ||||
|         $loader->load('services/templating.yaml'); | ||||
|         $loader->load('services/timeline.yaml'); | ||||
|         $loader->load('services/search.yaml'); | ||||
|          | ||||
|         $loader->load('services/serializer.yaml'); | ||||
|  | ||||
|         $this->configureCruds($container, $config['cruds'], $loader); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     /** | ||||
|      * @param array $config | ||||
|      * @param ContainerBuilder $container | ||||
| @@ -144,11 +145,11 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, | ||||
|     { | ||||
|         return new Configuration($this->widgetFactories, $container); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     /** | ||||
|      * @param ContainerBuilder $container | ||||
|      */ | ||||
|     public function prepend(ContainerBuilder $container)  | ||||
|     public function prepend(ContainerBuilder $container) | ||||
|     { | ||||
|         //add installation_name and date_format to globals | ||||
|         $chillMainConfig = $container->getExtensionConfig($this->getAlias()); | ||||
| @@ -163,7 +164,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, | ||||
|             'form_themes' => array('@ChillMain/Form/fields.html.twig') | ||||
|         ); | ||||
|         $container->prependExtensionConfig('twig', $twigConfig); | ||||
|          | ||||
|  | ||||
|         //add DQL function to ORM (default entity_manager) | ||||
|         $container->prependExtensionConfig('doctrine', array( | ||||
|            'orm' => array( | ||||
| @@ -182,7 +183,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, | ||||
|               ) | ||||
|            ) | ||||
|         )); | ||||
|          | ||||
|  | ||||
|         //add dbal types (default entity_manager) | ||||
|         $container->prependExtensionConfig('doctrine', array( | ||||
|            'dbal' => [ | ||||
| @@ -191,23 +192,23 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, | ||||
|                ] | ||||
|            ] | ||||
|         )); | ||||
|          | ||||
|  | ||||
|         //add current route to chill main | ||||
|         $container->prependExtensionConfig('chill_main', array( | ||||
|            'routing' => array( | ||||
|               'resources' => array( | ||||
|                  '@ChillMainBundle/config/routes.yaml' | ||||
|               ) | ||||
|                | ||||
|  | ||||
|            ) | ||||
|         )); | ||||
|          | ||||
|  | ||||
|         //add a channel to log app events | ||||
|         $container->prependExtensionConfig('monolog', array( | ||||
|             'channels' => array('chill') | ||||
|         )); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     /** | ||||
|      * @param ContainerBuilder $container | ||||
|      * @param array $config the config under 'cruds' key | ||||
| @@ -218,31 +219,31 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, | ||||
|         if (count($config) === 0) { | ||||
|             return; | ||||
|         } | ||||
|          | ||||
|  | ||||
|         $loader->load('services/crud.yaml'); | ||||
|          | ||||
|  | ||||
|         $container->setParameter('chill_main_crud_route_loader_config', $config); | ||||
|          | ||||
|  | ||||
|         $definition = new Definition(); | ||||
|         $definition | ||||
|             ->setClass(\Chill\MainBundle\CRUD\Routing\CRUDRoutesLoader::class) | ||||
|             ->addArgument('%chill_main_crud_route_loader_config%') | ||||
|             ; | ||||
|          | ||||
|  | ||||
|         $container->setDefinition('chill_main_crud_route_loader', $definition); | ||||
|          | ||||
|  | ||||
|         $alreadyExistingNames = []; | ||||
|          | ||||
|  | ||||
|         foreach ($config as $crudEntry) { | ||||
|             $controller = $crudEntry['controller']; | ||||
|             $controllerServiceName = 'cscrud_'.$crudEntry['name'].'_controller'; | ||||
|             $name = $crudEntry['name']; | ||||
|              | ||||
|  | ||||
|             // check for existing crud names | ||||
|             if (\in_array($name, $alreadyExistingNames)) { | ||||
|                 throw new LogicException(sprintf("the name %s is defined twice in CRUD", $name)); | ||||
|             } | ||||
|              | ||||
|  | ||||
|             if (!$container->has($controllerServiceName)) { | ||||
|                 $controllerDefinition = new Definition($controller); | ||||
|                 $controllerDefinition->addTag('controller.service_arguments'); | ||||
| @@ -250,7 +251,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, | ||||
|                 $controllerDefinition->setClass($crudEntry['controller']); | ||||
|                 $container->setDefinition($controllerServiceName, $controllerDefinition); | ||||
|             } | ||||
|              | ||||
|  | ||||
|             $container->setParameter('chill_main_crud_config_'.$name, $crudEntry); | ||||
|             $container->getDefinition($controllerServiceName) | ||||
|                 ->addMethodCall('setCrudConfig', ['%chill_main_crud_config_'.$name.'%']); | ||||
|   | ||||
| @@ -27,6 +27,7 @@ use Symfony\Component\Form\FormBuilderInterface; | ||||
| use Chill\MainBundle\Form\Type\DataTransformer\ObjectToIdTransformer; | ||||
| use Doctrine\Persistence\ObjectManager; | ||||
| use Chill\MainBundle\Form\Type\Select2ChoiceType; | ||||
| use Chill\MainBundle\Templating\TranslatableStringHelper; | ||||
|  | ||||
| /** | ||||
|  * Extends choice to allow adding select2 library on widget | ||||
| @@ -41,15 +42,26 @@ class Select2CountryType extends AbstractType | ||||
|      */ | ||||
|     private $requestStack; | ||||
|  | ||||
|     /** | ||||
|      * | ||||
|      * @var TranslatableStringHelper | ||||
|      */ | ||||
|     protected $translatableStringHelper; | ||||
|  | ||||
|     /** | ||||
|      * @var ObjectManager | ||||
|      */ | ||||
|     private $em; | ||||
|  | ||||
|     public function __construct(RequestStack $requestStack,ObjectManager $em) | ||||
|     public function __construct( | ||||
|         RequestStack $requestStack, | ||||
|         ObjectManager $em, | ||||
|         TranslatableStringHelper $translatableStringHelper | ||||
|         ) | ||||
|     { | ||||
|         $this->requestStack = $requestStack; | ||||
|         $this->em = $em; | ||||
|         $this->translatableStringHelper = $translatableStringHelper; | ||||
|     } | ||||
|  | ||||
|     public function getBlockPrefix() | ||||
| @@ -75,7 +87,7 @@ class Select2CountryType extends AbstractType | ||||
|         $choices = array(); | ||||
|  | ||||
|         foreach ($countries as $c) { | ||||
|             $choices[$c->getId()] = $c->getName()[$locale]; | ||||
|             $choices[$c->getId()] = $this->translatableStringHelper->localize($c->getName()); | ||||
|         } | ||||
|  | ||||
|         asort($choices, SORT_STRING | SORT_FLAG_CASE); | ||||
|   | ||||
| @@ -27,6 +27,7 @@ use Symfony\Component\Form\FormBuilderInterface; | ||||
| use Chill\MainBundle\Form\Type\DataTransformer\MultipleObjectsToIdTransformer; | ||||
| use Doctrine\Persistence\ObjectManager; | ||||
| use Chill\MainBundle\Form\Type\Select2ChoiceType; | ||||
| use Chill\MainBundle\Templating\TranslatableStringHelper; | ||||
|  | ||||
| /** | ||||
|  * Extends choice to allow adding select2 library on widget for languages (multiple) | ||||
| @@ -43,10 +44,21 @@ class Select2LanguageType extends AbstractType | ||||
|      */ | ||||
|     private $em; | ||||
|  | ||||
|     public function __construct(RequestStack $requestStack,ObjectManager $em) | ||||
|     /** | ||||
|      * | ||||
|      * @var TranslatableStringHelper | ||||
|      */ | ||||
|     protected $translatableStringHelper; | ||||
|  | ||||
|     public function __construct( | ||||
|         RequestStack $requestStack, | ||||
|         ObjectManager $em, | ||||
|         TranslatableStringHelper $translatableStringHelper | ||||
|         ) | ||||
|     { | ||||
|         $this->requestStack = $requestStack; | ||||
|         $this->em = $em; | ||||
|         $this->translatableStringHelper = $translatableStringHelper; | ||||
|     } | ||||
|  | ||||
|     public function getBlockPrefix() | ||||
| @@ -72,7 +84,7 @@ class Select2LanguageType extends AbstractType | ||||
|         $choices = array(); | ||||
|  | ||||
|         foreach ($languages as $l) { | ||||
|             $choices[$l->getId()] = $l->getName()[$locale]; | ||||
|             $choices[$l->getId()] = $this->translatableStringHelper->localize($l->getName()); | ||||
|         } | ||||
|  | ||||
|         asort($choices, SORT_STRING | SORT_FLAG_CASE); | ||||
|   | ||||
| @@ -104,7 +104,7 @@ class Mailer | ||||
|      * @param \User $to | ||||
|      * @param array $subject Subject of the message [ 0 => $message (required), 1 => $parameters (optional), 3 => $domain (optional) ] | ||||
|      * @param array $bodies The bodies. An array where keys are the contentType and values the bodies | ||||
|      * @param \callable $callback a callback to customize the message (add attachment, etc.) | ||||
|      * @param callable $callback a callback to customize the message (add attachment, etc.) | ||||
|      */ | ||||
|     public function sendNotification( | ||||
|         $recipient, | ||||
|   | ||||
| @@ -21,9 +21,7 @@ global.chill = chill; | ||||
| /* | ||||
|  * load requirements in chill entrypoint | ||||
|  */ | ||||
|  | ||||
| require('./sass/scratch.scss'); | ||||
|  | ||||
| require('./scss/chillmain.scss'); | ||||
| require('./css/chillmain.css'); | ||||
| require('./css/pikaday.css'); | ||||
|  | ||||
| @@ -37,10 +35,11 @@ require('./modules/download-report/index.js'); | ||||
| require('./modules/select_interactive_loading/index.js'); | ||||
| require('./modules/export-list/export-list.scss'); | ||||
| require('./modules/entity/index.js'); | ||||
| //require('./modules/tabs/index.js'); | ||||
|  | ||||
| /* | ||||
|  * load img | ||||
|  */ | ||||
| require('./img/favicon.ico'); | ||||
| require('./img/logo-chill-sans-slogan_white.png'); | ||||
| require('./img/logo-chill-outil-accompagnement_white.png'); | ||||
| require('./img/logo-chill-outil-accompagnement_white.png'); | ||||
|   | ||||
| @@ -0,0 +1,4 @@ | ||||
| /* | ||||
|  *  These custom styles will override bootstrap enabled stylesheets | ||||
|  */ | ||||
|  | ||||
							
								
								
									
										47
									
								
								src/Bundle/ChillMainBundle/Resources/public/modules/bootstrap/bootstrap.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/Bundle/ChillMainBundle/Resources/public/modules/bootstrap/bootstrap.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| /* | ||||
|  *  Enable / disable bootstrap assets | ||||
|  */ | ||||
|  | ||||
| @import "bootstrap/scss/functions"; | ||||
|  | ||||
| /* replace variables */ | ||||
| // @import "bootstrap/scss/variables"; | ||||
| @import "custom/_variables"; | ||||
|  | ||||
| @import "bootstrap/scss/mixins"; | ||||
| // @import "bootstrap/scss/root"; | ||||
| // @import "bootstrap/scss/reboot"; | ||||
| // @import "bootstrap/scss/type"; | ||||
| // @import "bootstrap/scss/images"; | ||||
| // @import "bootstrap/scss/code"; | ||||
| // @import "bootstrap/scss/grid"; | ||||
| // @import "bootstrap/scss/tables"; | ||||
| // @import "bootstrap/scss/forms"; | ||||
| // @import "bootstrap/scss/buttons"; | ||||
| // @import "bootstrap/scss/transitions"; | ||||
| // @import "bootstrap/scss/dropdown"; | ||||
| // @import "bootstrap/scss/button-group"; | ||||
| // @import "bootstrap/scss/input-group"; | ||||
| // @import "bootstrap/scss/custom-forms"; | ||||
| // @import "bootstrap/scss/nav"; | ||||
| // @import "bootstrap/scss/navbar"; | ||||
| // @import "bootstrap/scss/card"; | ||||
| // @import "bootstrap/scss/breadcrumb"; | ||||
| // @import "bootstrap/scss/pagination"; | ||||
| // @import "bootstrap/scss/badge"; | ||||
| // @import "bootstrap/scss/jumbotron"; | ||||
| // @import "bootstrap/scss/alert"; | ||||
| // @import "bootstrap/scss/progress"; | ||||
| // @import "bootstrap/scss/media"; | ||||
| // @import "bootstrap/scss/list-group"; | ||||
| // @import "bootstrap/scss/close"; | ||||
| // @import "bootstrap/scss/toasts"; | ||||
| @import "bootstrap/scss/modal"; | ||||
| // @import "bootstrap/scss/tooltip"; | ||||
| // @import "bootstrap/scss/popover"; | ||||
| // @import "bootstrap/scss/carousel"; | ||||
| // @import "bootstrap/scss/spinners"; | ||||
| // @import "bootstrap/scss/utilities"; | ||||
| // @import "bootstrap/scss/print"; | ||||
|  | ||||
| @import "custom"; | ||||
| @@ -1,42 +0,0 @@ | ||||
| /* | ||||
| *   when bootstrap.css comes after chill.css | ||||
| *   we have to disable conflict classes | ||||
| */ | ||||
|  | ||||
| @import "bootstrap/scss/functions"; | ||||
| @import "bootstrap/scss/variables"; | ||||
| @import "bootstrap/scss/mixins"; | ||||
| @import "bootstrap/scss/root"; | ||||
| //@import "bootstrap/scss/reboot";  // h1, h2, h3, ... | ||||
| //@import "bootstrap/scss/type";    // h1, h2, h3, ... | ||||
| @import "bootstrap/scss/images"; | ||||
| @import "bootstrap/scss/code"; | ||||
| //@import "bootstrap/scss/grid";    // container | ||||
| @import "bootstrap/scss/tables"; | ||||
| @import "bootstrap/scss/forms"; | ||||
| @import "bootstrap/scss/buttons"; | ||||
| @import "bootstrap/scss/transitions"; | ||||
| @import "bootstrap/scss/dropdown"; | ||||
| @import "bootstrap/scss/button-group"; | ||||
| @import "bootstrap/scss/input-group"; | ||||
| @import "bootstrap/scss/custom-forms"; | ||||
| @import "bootstrap/scss/nav"; | ||||
| @import "bootstrap/scss/navbar"; | ||||
| @import "bootstrap/scss/card"; | ||||
| @import "bootstrap/scss/breadcrumb"; | ||||
| @import "bootstrap/scss/pagination"; | ||||
| @import "bootstrap/scss/badge"; | ||||
| @import "bootstrap/scss/jumbotron"; | ||||
| @import "bootstrap/scss/alert"; | ||||
| @import "bootstrap/scss/progress"; | ||||
| @import "bootstrap/scss/media"; | ||||
| @import "bootstrap/scss/list-group"; | ||||
| @import "bootstrap/scss/close"; | ||||
| @import "bootstrap/scss/toasts"; | ||||
| @import "bootstrap/scss/modal"; | ||||
| @import "bootstrap/scss/tooltip"; | ||||
| @import "bootstrap/scss/popover"; | ||||
| @import "bootstrap/scss/carousel"; | ||||
| @import "bootstrap/scss/spinners"; | ||||
| @import "bootstrap/scss/utilities"; | ||||
| @import "bootstrap/scss/print"; | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,9 +1,9 @@ | ||||
| // Compile all bootstrap assets from nodes-modules | ||||
| //require('bootstrap/scss/bootstrap.scss') | ||||
|  | ||||
| // Compile custom styles to adapt bootstrap in chill context | ||||
| require('./custom.scss') | ||||
| // Or compile bootstrap only enabled assets | ||||
| require('./bootstrap.scss'); | ||||
|  | ||||
| // You can specify which plugins you need | ||||
| //import { Tooltip, Toast, Popover } from 'bootstrap'; | ||||
| //import Alert from 'bootstrap/js/dist/alert'; | ||||
| import Modal from 'bootstrap/js/dist/modal'; | ||||
|   | ||||
| @@ -1,3 +1,9 @@ | ||||
| /* | ||||
|  * NOTE 2021.04 | ||||
|  * scss/chill.scss is the main sass file for the new chill.2 | ||||
|  * scratch will be replaced by bootstrap, please avoid to edit in modules/scratch/_custom.scss | ||||
|  */ | ||||
| 
 | ||||
| // YOUR CUSTOM SCSS | ||||
| @import 'custom/config/colors'; | ||||
| @import 'custom/config/variables'; | ||||
| @@ -156,7 +162,6 @@ dl.chill_view_data { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| blockquote.chill-user-quote, | ||||
| div.chill-user-quote { | ||||
|     border-left: 10px solid $chill-yellow; | ||||
| @@ -164,12 +169,12 @@ div.chill-user-quote { | ||||
|     padding: 0.5em 10px; | ||||
|     quotes: "\201C""\201D""\2018""\2019"; | ||||
|     background-color: $chill-llight-gray; | ||||
|      | ||||
| 
 | ||||
|     blockquote { | ||||
|         margin: 1.5em 10px; | ||||
|         padding: 0.5em 10px; | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     blockquote:before { | ||||
|         color: #ccc; | ||||
|         content: open-quote; | ||||
| @@ -182,5 +187,4 @@ div.chill-user-quote { | ||||
| 
 | ||||
| .chill-no-data-statement { | ||||
|     font-style: italic; | ||||
| 
 | ||||
| } | ||||
| @@ -1,42 +1,42 @@ | ||||
| @charset "UTF-8"; | ||||
| 
 | ||||
| /// Outputs the spec and prefixed versions of the `::selection` pseudo-element. | ||||
| /// | ||||
| /// @param {Bool} $current-selector [false] | ||||
| ///   If set to `true`, it takes the current element into consideration. | ||||
| /// | ||||
| /// @example scss - Usage | ||||
| ///   .element { | ||||
| ///     @include selection(true) { | ||||
| ///       background-color: #ffbb52; | ||||
| ///     } | ||||
| ///   } | ||||
| /// | ||||
| /// @example css - CSS Output | ||||
| ///   .element::-moz-selection { | ||||
| ///     background-color: #ffbb52; | ||||
| ///   } | ||||
| /// | ||||
| ///   .element::selection { | ||||
| ///     background-color: #ffbb52; | ||||
| ///   } | ||||
| 
 | ||||
| @mixin selection($current-selector: false) { | ||||
|   @if $current-selector { | ||||
|     &::-moz-selection { | ||||
|       @content; | ||||
|     } | ||||
| 
 | ||||
|     &::selection { | ||||
|       @content; | ||||
|     } | ||||
|   } @else { | ||||
|     ::-moz-selection { | ||||
|       @content; | ||||
|     } | ||||
| 
 | ||||
|     ::selection { | ||||
|       @content; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @charset "UTF-8"; | ||||
| 
 | ||||
| /// Outputs the spec and prefixed versions of the `::selection` pseudo-element. | ||||
| /// | ||||
| /// @param {Bool} $current-selector [false] | ||||
| ///   If set to `true`, it takes the current element into consideration. | ||||
| /// | ||||
| /// @example scss - Usage | ||||
| ///   .element { | ||||
| ///     @include selection(true) { | ||||
| ///       background-color: #ffbb52; | ||||
| ///     } | ||||
| ///   } | ||||
| /// | ||||
| /// @example css - CSS Output | ||||
| ///   .element::-moz-selection { | ||||
| ///     background-color: #ffbb52; | ||||
| ///   } | ||||
| /// | ||||
| ///   .element::selection { | ||||
| ///     background-color: #ffbb52; | ||||
| ///   } | ||||
| 
 | ||||
| @mixin selection($current-selector: false) { | ||||
|   @if $current-selector { | ||||
|     &::-moz-selection { | ||||
|       @content; | ||||
|     } | ||||
| 
 | ||||
|     &::selection { | ||||
|       @content; | ||||
|     } | ||||
|   } @else { | ||||
|     ::-moz-selection { | ||||
|       @content; | ||||
|     } | ||||
| 
 | ||||
|     ::selection { | ||||
|       @content; | ||||
|     } | ||||
|   } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user