Merge branch 'master' of gogs-figureslibres.io:ouidade/dev-epau.archi.fr

This commit is contained in:
2021-03-29 17:06:22 +02:00
181 changed files with 10466 additions and 1586 deletions
-66
View File
@@ -1,66 +0,0 @@
name: Release Builds
on:
release:
types: [published]
jobs:
build:
if: "!github.event.release.prerelease"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 7.3
extensions: opcache, gd
coverage: none
env:
COMPOSER_TOKEN: ${{ secrets.GLOBAL_TOKEN }}
- name: Install Dependencies
run: |
sudo apt-get -y update -qq < /dev/null > /dev/null
sudo apt-get -y install -qq git zip < /dev/null > /dev/null
- name: Retrieval of Builder Scripts
run: |
# Real Grav URL
curl --silent -H "Authorization: token ${{ secrets.GLOBAL_TOKEN }}" -H "Accept: application/vnd.github.v3.raw" ${{ secrets.BUILD_SCRIPT_URL }} --output build-grav.sh
# Development Local URL
# curl ${{ secrets.BUILD_SCRIPT_URL }} --output build-grav.sh
- name: Grav Builder
run: |
bash ./build-grav.sh
- name: Upload Grav Release Assets
id: upload-release-asset
uses: alexellis/upload-assets@0.2.3
env:
GITHUB_TOKEN: ${{ secrets.GLOBAL_TOKEN }}
with:
asset_paths: '["./grav-dist/*.zip"]'
slack:
name: Slack
needs: build
runs-on: ubuntu-latest
if: always()
steps:
- uses: technote-space/workflow-conclusion-action@v2
- uses: 8398a7/action-slack@v3
with:
status: failure
fields: repo,message,author,action
icon_emoji: ':octocat:'
author_name: 'Github Action Build'
text: '🚚 Automated Build Failure'
env:
GITHUB_TOKEN: ${{ secrets.GLOBAL_TOKEN }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
if: env.WORKFLOW_CONCLUSION == 'failure'
-72
View File
@@ -1,72 +0,0 @@
name: PHP Tests
on:
push:
branches: [ develop ]
pull_request:
branches: [ develop ]
jobs:
unit-tests:
runs-on: ${{ matrix.os }}
strategy:
matrix:
php: [ 8.0, 7.4, 7.3]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: opcache, gd
coverage: none
env:
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# - name: Update composer
# run: composer update
#
# - name: Validate composer.json and composer.lock
# run: composer validate
- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install dependencies
run: composer install --prefer-dist --no-progress
- name: Run test suite
run: vendor/bin/codecept run
# slack:
# name: Slack
# needs: unit-tests
# runs-on: ubuntu-latest
# if: always()
# steps:
# - uses: technote-space/workflow-conclusion-action@v2
# - uses: 8398a7/action-slack@v3
# with:
# status: failure
# fields: repo,message,author,action
# icon_emoji: ':octocat:'
# author_name: 'Github Action Tests'
# text: '💥 Automated Test Failure'
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
# if: env.WORKFLOW_CONCLUSION == 'failure'
+50 -1
View File
@@ -1,8 +1,57 @@
# v1.7.9
## 03/19/2021
1. [](#new)
* Added `Media::hide()` method to hide files from media
* Added `Utils::getPathFromToken()` method which works also with `Flex Objects`
* Added `FlexMediaTrait::getMediaField()`, which can be used to access custom media set in the blueprint fields
* Added `FlexMediaTrait::getFieldSettings()`, which can be used to get media field settings
1. [](#improved)
* Method `Utils::getPagePathFromToken()` now calls the more generic `Utils::getPathFromToken()`
* Updated `SECURITY.md` to use security@getgrav.org
1. [](#bugfix)
* Fixed broken media upload in `Flex` with `@self/path`, `@page` and `@theme` destinations [#3275](https://github.com/getgrav/grav/issues/3275)
* Fixed media fields excluding newly deleted files before saving the object
* Fixed method `$pages->find()` should never redirect [#3266](https://github.com/getgrav/grav/pull/3266)
* Fixed `Page::activeChild()` throwing an error [#3276](https://github.com/getgrav/grav/issues/3276)
* Fixed `Flex Page` CRUD ACL when creating a new page (needs Flex Objects plugin update) [grav-plugin-flex-objects#115](https://github.com/trilbymedia/grav-plugin-flex-objects/issues/115)
* Fixed the list of pages not showing up in admin [#3280](https://github.com/getgrav/grav/issues/3280)
* Fixed text field min/max validation for UTF8 characters [#3281](https://github.com/getgrav/grav/issues/3281)
* Fixed redirects using wrong redirect code
# v1.7.8
## 03/17/2021
1. [](#new)
* Added `ControllerResponseTrait::createDownloadResponse()` method
* Added full blueprint support to theme if you move existing files in `blueprints/` to `blueprints/pages/` folder [#3255](https://github.com/getgrav/grav/issues/3255)
* Added support for `Theme::getFormFieldTypes()` just like in plugins
1. [](#improved)
* Optimized `Flex Pages` for speed
* Optimized saving visible/ordered pages when there are a lot of siblings [#3231](https://github.com/getgrav/grav/issues/3231)
* Clearing cache now deletes all clockwork files
* Improved `system.pages.redirect_default_route` and `system.pages.redirect_trailing_slash` configuration options to accept redirect code
1. [](#bugfix)
* Fixed clockwork error when clearing cache
* Fixed missing method `translated()` in `Flex Pages`
* Fixed missing `Flex Pages` in site if multi-language support has been enabled
* Fixed Grav using blueprints and form fields from disabled plugins
* Fixed `FlexIndex::sortBy(['key' => 'ASC'])` having no effect
* Fixed default Flex Pages collection ordering to order by filesystem path
* Fixed disappearing pages on save if `pages://` stream resolves to multiple folders where the preferred folder doesn't exist
* Fixed Markdown image attribute `loading` [#3251](https://github.com/getgrav/grav/pull/3251)
* Fixed `Uri::isValidExtension()` returning false positives
* Fixed `page.html` returning duplicated content with `system.pages.redirect_default_route` turned on [#3130](https://github.com/getgrav/grav/issues/3130)
* Fixed site redirect with redirect code failing when redirecting to sub-pages [#3035](https://github.com/getgrav/grav/pull/3035/files)
* Fixed `Uncaught ValueError: Path cannot be empty` when failing to upload a file [#3265](https://github.com/getgrav/grav/issues/3265)
* Fixed `Path cannot be empty` when viewing non-existent log file [#3270](https://github.com/getgrav/grav/issues/3270)
* Fixed `onAdminSave` original page having empty header [#3259](https://github.com/getgrav/grav/issues/3259)
# v1.7.7
## 02/23/2021
1. [](#new)
* Added `Utils::arrayToQueryParams()` to convert an array into query params
* Added `Utils::arrayToQueryParams()` to convert an array into query params
1. [](#improved)
* Added original image support for all flex objects and media fields
* Improved `Pagination` class to allow custom pagination query parameter
-23
View File
@@ -148,26 +148,3 @@ To run phpstan tests, you should run:
* `composer phpstan` for global tests
* `composer phpstan-framework` for more strict tests
* `composer phpstan-plugins` to test all installed plugins
# EPAU REad ME
- intall grav avec composer
composer create-project getgrav/grav ~/webroot/grav
- lance serveur local
cd ~/webroot/nomdusite
php -S localhost:8000 system/router.php
Fenêtre à laisser ouverte!
- dans autre fenetre, installer version admin
cd ~/webroot/nomdusite
bin/gpm selfupgrade (mise à jours)
bin/gpm install admin (installe ladmin)
bin/plugin login newuser (créer un nouvel utilisateur)
+8 -2
View File
@@ -7,9 +7,15 @@ We are focusing our security updates on the following versions
| Version | Supported |
| ------- | ------------------ |
| 1.7.x | :white_check_mark: |
| 1.6.x | :white_check_mark: |
| 1.6.x | :warning: |
| < 1.6 | :x: |
## :warning: Versions
Versions with :warning: will be supported for security issues, however you won't be able to update to them, you will need to manually update through the [`direct-install` command](https://learn.getgrav.org/17/admin-panel/tools).
If you cannot update to the latest stable version available because, for example, your server does not meet the minimum PHP requirements, you can manually install a previous version by downloading the package from our Releases directory (https://github.com/getgrav/grav/releases).
## Reporting a Vulnerability
Please contact contact@getgrav.org with a detailed explaination of the security issue found and we will work with you to get it resolved as fast as possible.
Please contact security@getgrav.org with a detailed explaination of the security issue found and we will work with you to get it resolved as fast as possible.
+5 -3
View File
@@ -26,7 +26,8 @@
"psr/simple-cache": "^1.0",
"psr/http-message": "^1.0",
"psr/http-server-middleware": "^1.0",
"kodus/psr7-server": "*",
"psr/container": "~1.0.0",
"nyholm/psr7-server": "^1.0",
"nyholm/psr7": "^1.3",
"twig/twig": "~1.44",
"erusev/parsedown": "^1.7",
@@ -46,7 +47,7 @@
"gregwar/image": "dev-php8",
"gregwar/cache": "dev-php8",
"donatj/phpuseragentparser": "~1.1",
"pimple/pimple": "~3.3",
"pimple/pimple": "~3.3.0",
"rockettheme/toolbox": "~1.5",
"maximebf/debugbar": "~1.16",
"league/climate": "^3.6",
@@ -68,7 +69,8 @@
"phpunit/php-code-coverage": "~9.2",
"victorjonsson/markdowndocs": "dev-master",
"codeception/module-asserts": "^1.3",
"codeception/module-phpbrowser": "^1.0"
"codeception/module-phpbrowser": "^1.0",
"symfony/service-contracts": "*"
},
"replace": {
"symfony/polyfill-php72": "*",
Generated
+193 -180
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "32b6cbbe234714397aea3c6ed1eddf6b",
"content-hash": "4ae6fc7274c018b1bb34bb1b80bd62c5",
"packages": [
{
"name": "antoligy/dom-string-iterators",
@@ -381,16 +381,16 @@
},
{
"name": "donatj/phpuseragentparser",
"version": "v1.2.0",
"version": "v1.4.0",
"source": {
"type": "git",
"url": "https://github.com/donatj/PhpUserAgent.git",
"reference": "978e66786bc392a09b24b152a8a695dadd230e60"
"reference": "246c1cf0a44f07168c702203bf30d5f48f17bab0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/donatj/PhpUserAgent/zipball/978e66786bc392a09b24b152a8a695dadd230e60",
"reference": "978e66786bc392a09b24b152a8a695dadd230e60",
"url": "https://api.github.com/repos/donatj/PhpUserAgent/zipball/246c1cf0a44f07168c702203bf30d5f48f17bab0",
"reference": "246c1cf0a44f07168c702203bf30d5f48f17bab0",
"shasum": ""
},
"require": {
@@ -433,11 +433,11 @@
],
"support": {
"issues": "https://github.com/donatj/PhpUserAgent/issues",
"source": "https://github.com/donatj/PhpUserAgent/tree/v1.2.0"
"source": "https://github.com/donatj/PhpUserAgent/tree/v1.4.0"
},
"funding": [
{
"url": "https://www.paypal.me/donatj/15",
"url": "https://www.paypal.me/donatj/5",
"type": "custom"
},
{
@@ -445,7 +445,7 @@
"type": "github"
}
],
"time": "2020-12-29T05:36:08+00:00"
"time": "2021-03-16T16:25:14+00:00"
},
{
"name": "dragonmantank/cron-expression",
@@ -642,16 +642,16 @@
},
{
"name": "filp/whoops",
"version": "2.9.2",
"version": "2.10.0",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
"reference": "df7933820090489623ce0be5e85c7e693638e536"
"reference": "6ecda5217bf048088b891f7403b262906be5a957"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/df7933820090489623ce0be5e85c7e693638e536",
"reference": "df7933820090489623ce0be5e85c7e693638e536",
"url": "https://api.github.com/repos/filp/whoops/zipball/6ecda5217bf048088b891f7403b262906be5a957",
"reference": "6ecda5217bf048088b891f7403b262906be5a957",
"shasum": ""
},
"require": {
@@ -701,7 +701,7 @@
],
"support": {
"issues": "https://github.com/filp/whoops/issues",
"source": "https://github.com/filp/whoops/tree/2.9.2"
"source": "https://github.com/filp/whoops/tree/2.10.0"
},
"funding": [
{
@@ -709,7 +709,7 @@
"type": "github"
}
],
"time": "2021-01-24T12:00:00+00:00"
"time": "2021-03-16T12:00:00+00:00"
},
{
"name": "gregwar/cache",
@@ -763,18 +763,18 @@
"source": {
"type": "git",
"url": "https://github.com/getgrav/Image.git",
"reference": "70afaa75ea19856813124142c51f5fb2e9f1a285"
"reference": "ea23859700f32447a85e79d96f331e3d6c8897a8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/getgrav/Image/zipball/70afaa75ea19856813124142c51f5fb2e9f1a285",
"reference": "70afaa75ea19856813124142c51f5fb2e9f1a285",
"url": "https://api.github.com/repos/getgrav/Image/zipball/ea23859700f32447a85e79d96f331e3d6c8897a8",
"reference": "ea23859700f32447a85e79d96f331e3d6c8897a8",
"shasum": ""
},
"require": {
"ext-gd": "*",
"gregwar/cache": "dev-php8",
"php": "^5.3 || ^7.0 || ^8.0"
"php": "^5.6 || ^7.0 || ^8.0"
},
"require-dev": {
"sllh/php-cs-fixer-styleci-bridge": "~1.0",
@@ -808,7 +808,7 @@
"support": {
"source": "https://github.com/getgrav/Image/tree/php8"
},
"time": "2020-12-02T14:04:28+00:00"
"time": "2021-03-15T17:03:52+00:00"
},
{
"name": "guzzlehttp/psr7",
@@ -887,16 +887,16 @@
},
{
"name": "itsgoingd/clockwork",
"version": "v5.0.6",
"version": "v5.0.7",
"source": {
"type": "git",
"url": "https://github.com/itsgoingd/clockwork.git",
"reference": "1de3f9f9fc22217aa024f79ecbdf0fde418fc0a1"
"reference": "e41ee368ff4dcc30d3f4563fe8bd80ed72b293b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/1de3f9f9fc22217aa024f79ecbdf0fde418fc0a1",
"reference": "1de3f9f9fc22217aa024f79ecbdf0fde418fc0a1",
"url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/e41ee368ff4dcc30d3f4563fe8bd80ed72b293b4",
"reference": "e41ee368ff4dcc30d3f4563fe8bd80ed72b293b4",
"shasum": ""
},
"require": {
@@ -944,7 +944,7 @@
],
"support": {
"issues": "https://github.com/itsgoingd/clockwork/issues",
"source": "https://github.com/itsgoingd/clockwork/tree/v5.0.6"
"source": "https://github.com/itsgoingd/clockwork/tree/v5.0.7"
},
"funding": [
{
@@ -952,65 +952,7 @@
"type": "github"
}
],
"time": "2020-12-27T00:18:25+00:00"
},
{
"name": "kodus/psr7-server",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/kodus/psr7-server.git",
"reference": "dcfd0116451b0f0e7c6b23b831757ed288347278"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/kodus/psr7-server/zipball/dcfd0116451b0f0e7c6b23b831757ed288347278",
"reference": "dcfd0116451b0f0e7c6b23b831757ed288347278",
"shasum": ""
},
"require": {
"php": "^7.1",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.0"
},
"replace": {
"nyholm/psr7-server": "^0.3"
},
"require-dev": {
"nyholm/nsa": "^1.1",
"nyholm/psr7": "^1.0",
"phpunit/phpunit": "^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Nyholm\\Psr7Server\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com"
},
{
"name": "Martijn van der Ven",
"email": "martijn@vanderven.se"
}
],
"description": "Helper classes to handle PSR-7 server requests",
"homepage": "http://tnyholm.se",
"keywords": [
"psr-17",
"psr-7"
],
"support": {
"source": "https://github.com/kodus/psr7-server/tree/master"
},
"time": "2019-06-17T10:48:13+00:00"
"time": "2021-03-14T16:29:40+00:00"
},
{
"name": "league/climate",
@@ -1421,16 +1363,16 @@
},
{
"name": "nyholm/psr7",
"version": "1.3.2",
"version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/Nyholm/psr7.git",
"reference": "a272953743c454ac4af9626634daaf5ab3ce1173"
"reference": "23ae1f00fbc6a886cbe3062ca682391b9cc7c37b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Nyholm/psr7/zipball/a272953743c454ac4af9626634daaf5ab3ce1173",
"reference": "a272953743c454ac4af9626634daaf5ab3ce1173",
"url": "https://api.github.com/repos/Nyholm/psr7/zipball/23ae1f00fbc6a886cbe3062ca682391b9cc7c37b",
"reference": "23ae1f00fbc6a886cbe3062ca682391b9cc7c37b",
"shasum": ""
},
"require": {
@@ -1452,7 +1394,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
"dev-master": "1.4-dev"
}
},
"autoload": {
@@ -1482,7 +1424,7 @@
],
"support": {
"issues": "https://github.com/Nyholm/psr7/issues",
"source": "https://github.com/Nyholm/psr7/tree/1.3.2"
"source": "https://github.com/Nyholm/psr7/tree/1.4.0"
},
"funding": [
{
@@ -1494,7 +1436,73 @@
"type": "github"
}
],
"time": "2020-11-14T17:35:34+00:00"
"time": "2021-02-18T15:41:32+00:00"
},
{
"name": "nyholm/psr7-server",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/Nyholm/psr7-server.git",
"reference": "5c134aeb5dd6521c7978798663470dabf0528c96"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Nyholm/psr7-server/zipball/5c134aeb5dd6521c7978798663470dabf0528c96",
"reference": "5c134aeb5dd6521c7978798663470dabf0528c96",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.0"
},
"require-dev": {
"nyholm/nsa": "^1.1",
"nyholm/psr7": "^1.3",
"phpunit/phpunit": "^7.0 || ^8.5 || ^9.3"
},
"type": "library",
"autoload": {
"psr-4": {
"Nyholm\\Psr7Server\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com"
},
{
"name": "Martijn van der Ven",
"email": "martijn@vanderven.se"
}
],
"description": "Helper classes to handle PSR-7 server requests",
"homepage": "http://tnyholm.se",
"keywords": [
"psr-17",
"psr-7"
],
"support": {
"issues": "https://github.com/Nyholm/psr7-server/issues",
"source": "https://github.com/Nyholm/psr7-server/tree/1.0.1"
},
"funding": [
{
"url": "https://github.com/Zegnat",
"type": "github"
},
{
"url": "https://github.com/nyholm",
"type": "github"
}
],
"time": "2020-11-15T15:26:20+00:00"
},
{
"name": "phive/twig-extensions-deferred",
@@ -2238,16 +2246,16 @@
},
{
"name": "symfony/console",
"version": "v4.4.19",
"version": "v4.4.20",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "24026c44fc37099fa145707fecd43672831b837a"
"reference": "c98349bda966c70d6c08b4cd8658377c94166492"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/24026c44fc37099fa145707fecd43672831b837a",
"reference": "24026c44fc37099fa145707fecd43672831b837a",
"url": "https://api.github.com/repos/symfony/console/zipball/c98349bda966c70d6c08b4cd8658377c94166492",
"reference": "c98349bda966c70d6c08b4cd8658377c94166492",
"shasum": ""
},
"require": {
@@ -2307,7 +2315,7 @@
"description": "Eases the creation of beautiful and testable command line interfaces",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/console/tree/v4.4.19"
"source": "https://github.com/symfony/console/tree/v4.4.20"
},
"funding": [
{
@@ -2323,7 +2331,7 @@
"type": "tidelift"
}
],
"time": "2021-01-27T09:09:26+00:00"
"time": "2021-02-22T18:44:15+00:00"
},
{
"name": "symfony/contracts",
@@ -2421,7 +2429,7 @@
},
{
"name": "symfony/event-dispatcher",
"version": "v4.4.19",
"version": "v4.4.20",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
@@ -2484,7 +2492,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v4.4.19"
"source": "https://github.com/symfony/event-dispatcher/tree/v4.4.20"
},
"funding": [
{
@@ -2504,16 +2512,16 @@
},
{
"name": "symfony/http-client",
"version": "v4.4.19",
"version": "v4.4.20",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
"reference": "d8df50fe9229576b254c6822eb5cfff36c02c967"
"reference": "67c5af7489b3c2eea771abd973243f5c58f5fb40"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client/zipball/d8df50fe9229576b254c6822eb5cfff36c02c967",
"reference": "d8df50fe9229576b254c6822eb5cfff36c02c967",
"url": "https://api.github.com/repos/symfony/http-client/zipball/67c5af7489b3c2eea771abd973243f5c58f5fb40",
"reference": "67c5af7489b3c2eea771abd973243f5c58f5fb40",
"shasum": ""
},
"require": {
@@ -2527,7 +2535,7 @@
"php-http/async-client-implementation": "*",
"php-http/client-implementation": "*",
"psr/http-client-implementation": "1.0",
"symfony/http-client-implementation": "1.1"
"symfony/http-client-implementation": "1.1|2.0"
},
"require-dev": {
"guzzlehttp/promises": "^1.4",
@@ -2564,7 +2572,7 @@
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-client/tree/v4.4.19"
"source": "https://github.com/symfony/http-client/tree/v4.4.20"
},
"funding": [
{
@@ -2580,7 +2588,7 @@
"type": "tidelift"
}
],
"time": "2021-01-27T09:09:26+00:00"
"time": "2021-02-25T18:06:45+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -2986,7 +2994,7 @@
},
{
"name": "symfony/process",
"version": "v4.4.19",
"version": "v4.4.20",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
@@ -3027,7 +3035,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v4.4.19"
"source": "https://github.com/symfony/process/tree/v4.4.20"
},
"funding": [
{
@@ -3047,7 +3055,7 @@
},
{
"name": "symfony/var-dumper",
"version": "v4.4.19",
"version": "v4.4.20",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
@@ -3116,7 +3124,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v4.4.19"
"source": "https://github.com/symfony/var-dumper/tree/v4.4.20"
},
"funding": [
{
@@ -3136,16 +3144,16 @@
},
{
"name": "symfony/yaml",
"version": "v4.4.19",
"version": "v4.4.20",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "17ed9f14c1aa05b1a5cf2e2c5ef2d0be28058ef9"
"reference": "29e61305e1c79d25f71060903982ead8f533e267"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/17ed9f14c1aa05b1a5cf2e2c5ef2d0be28058ef9",
"reference": "17ed9f14c1aa05b1a5cf2e2c5ef2d0be28058ef9",
"url": "https://api.github.com/repos/symfony/yaml/zipball/29e61305e1c79d25f71060903982ead8f533e267",
"reference": "29e61305e1c79d25f71060903982ead8f533e267",
"shasum": ""
},
"require": {
@@ -3187,7 +3195,7 @@
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/yaml/tree/v4.4.19"
"source": "https://github.com/symfony/yaml/tree/v4.4.20"
},
"funding": [
{
@@ -3203,7 +3211,7 @@
"type": "tidelift"
}
],
"time": "2021-01-27T09:09:26+00:00"
"time": "2021-02-22T15:36:50+00:00"
},
{
"name": "twig/twig",
@@ -3407,16 +3415,16 @@
},
{
"name": "codeception/codeception",
"version": "4.1.17",
"version": "4.1.18",
"source": {
"type": "git",
"url": "https://github.com/Codeception/Codeception.git",
"reference": "c153b1ab289b3e3109e685379aa8847c54ac2b68"
"reference": "f47547bac347dfb5ea5351ff91148cbcc08e6818"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/c153b1ab289b3e3109e685379aa8847c54ac2b68",
"reference": "c153b1ab289b3e3109e685379aa8847c54ac2b68",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/f47547bac347dfb5ea5351ff91148cbcc08e6818",
"reference": "f47547bac347dfb5ea5351ff91148cbcc08e6818",
"shasum": ""
},
"require": {
@@ -3490,7 +3498,7 @@
],
"support": {
"issues": "https://github.com/Codeception/Codeception/issues",
"source": "https://github.com/Codeception/Codeception/tree/4.1.17"
"source": "https://github.com/Codeception/Codeception/tree/4.1.18"
},
"funding": [
{
@@ -3498,7 +3506,7 @@
"type": "open_collective"
}
],
"time": "2021-02-01T07:30:47+00:00"
"time": "2021-02-23T17:11:42+00:00"
},
{
"name": "codeception/lib-asserts",
@@ -3556,16 +3564,16 @@
},
{
"name": "codeception/lib-innerbrowser",
"version": "1.4.0",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/Codeception/lib-innerbrowser.git",
"reference": "b7406c710684c255d9b067d7795269a5585a0406"
"reference": "693e116f81ef98eae98c43ef785a726faf87394e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Codeception/lib-innerbrowser/zipball/b7406c710684c255d9b067d7795269a5585a0406",
"reference": "b7406c710684c255d9b067d7795269a5585a0406",
"url": "https://api.github.com/repos/Codeception/lib-innerbrowser/zipball/693e116f81ef98eae98c43ef785a726faf87394e",
"reference": "693e116f81ef98eae98c43ef785a726faf87394e",
"shasum": ""
},
"require": {
@@ -3610,9 +3618,9 @@
],
"support": {
"issues": "https://github.com/Codeception/lib-innerbrowser/issues",
"source": "https://github.com/Codeception/lib-innerbrowser/tree/1.4.0"
"source": "https://github.com/Codeception/lib-innerbrowser/tree/1.4.1"
},
"time": "2021-01-29T18:17:25+00:00"
"time": "2021-03-02T08:01:54+00:00"
},
{
"name": "codeception/module-asserts",
@@ -3987,16 +3995,16 @@
},
{
"name": "guzzlehttp/promises",
"version": "1.4.0",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "60d379c243457e073cff02bc323a2a86cb355631"
"reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631",
"reference": "60d379c243457e073cff02bc323a2a86cb355631",
"url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d",
"reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d",
"shasum": ""
},
"require": {
@@ -4036,9 +4044,9 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/1.4.0"
"source": "https://github.com/guzzle/promises/tree/1.4.1"
},
"time": "2020-09-30T07:37:28+00:00"
"time": "2021-03-07T09:25:29+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -4216,16 +4224,16 @@
},
{
"name": "phar-io/version",
"version": "3.0.4",
"version": "3.1.0",
"source": {
"type": "git",
"url": "https://github.com/phar-io/version.git",
"reference": "e4782611070e50613683d2b9a57730e9a3ba5451"
"reference": "bae7c545bef187884426f042434e561ab1ddb182"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phar-io/version/zipball/e4782611070e50613683d2b9a57730e9a3ba5451",
"reference": "e4782611070e50613683d2b9a57730e9a3ba5451",
"url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182",
"reference": "bae7c545bef187884426f042434e561ab1ddb182",
"shasum": ""
},
"require": {
@@ -4261,9 +4269,9 @@
"description": "Library for handling version information and constraints",
"support": {
"issues": "https://github.com/phar-io/version/issues",
"source": "https://github.com/phar-io/version/tree/3.0.4"
"source": "https://github.com/phar-io/version/tree/3.1.0"
},
"time": "2020-12-13T23:18:30+00:00"
"time": "2021-02-23T14:00:09+00:00"
},
{
"name": "phpdocumentor/reflection-common",
@@ -4492,16 +4500,16 @@
},
{
"name": "phpstan/phpstan",
"version": "0.12.77",
"version": "0.12.81",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "1f10b8c8d118d01e7b492f9707999d456be5812c"
"reference": "0dd5b0ebeff568f7000022ea5f04aa86ad3124b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/1f10b8c8d118d01e7b492f9707999d456be5812c",
"reference": "1f10b8c8d118d01e7b492f9707999d456be5812c",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/0dd5b0ebeff568f7000022ea5f04aa86ad3124b8",
"reference": "0dd5b0ebeff568f7000022ea5f04aa86ad3124b8",
"shasum": ""
},
"require": {
@@ -4532,7 +4540,7 @@
"description": "PHPStan - PHP Static Analysis Tool",
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/0.12.77"
"source": "https://github.com/phpstan/phpstan/tree/0.12.81"
},
"funding": [
{
@@ -4548,7 +4556,7 @@
"type": "tidelift"
}
],
"time": "2021-02-17T16:22:19+00:00"
"time": "2021-03-08T22:03:02+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",
@@ -4921,16 +4929,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.5.2",
"version": "9.5.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "f661659747f2f87f9e72095bb207bceb0f151cb4"
"reference": "27241ac75fc37ecf862b6e002bf713b6566cbe41"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f661659747f2f87f9e72095bb207bceb0f151cb4",
"reference": "f661659747f2f87f9e72095bb207bceb0f151cb4",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/27241ac75fc37ecf862b6e002bf713b6566cbe41",
"reference": "27241ac75fc37ecf862b6e002bf713b6566cbe41",
"shasum": ""
},
"require": {
@@ -5008,7 +5016,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.2"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.3"
},
"funding": [
{
@@ -5020,7 +5028,7 @@
"type": "github"
}
],
"time": "2021-02-02T14:45:58+00:00"
"time": "2021-03-17T07:30:34+00:00"
},
{
"name": "psr/http-client",
@@ -6040,16 +6048,16 @@
},
{
"name": "symfony/browser-kit",
"version": "v5.2.3",
"version": "v5.2.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
"reference": "b03b2057ed53ee4eab2e8f372084d7722b7b8ffd"
"reference": "3ca3a57ce9860318b20a924fec5daf5c6db44d93"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/b03b2057ed53ee4eab2e8f372084d7722b7b8ffd",
"reference": "b03b2057ed53ee4eab2e8f372084d7722b7b8ffd",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/3ca3a57ce9860318b20a924fec5daf5c6db44d93",
"reference": "3ca3a57ce9860318b20a924fec5daf5c6db44d93",
"shasum": ""
},
"require": {
@@ -6091,7 +6099,7 @@
"description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/browser-kit/tree/v5.2.3"
"source": "https://github.com/symfony/browser-kit/tree/v5.2.4"
},
"funding": [
{
@@ -6107,11 +6115,11 @@
"type": "tidelift"
}
],
"time": "2021-01-27T12:56:27+00:00"
"time": "2021-02-22T06:48:33+00:00"
},
{
"name": "symfony/css-selector",
"version": "v5.2.3",
"version": "v5.2.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
@@ -6156,7 +6164,7 @@
"description": "Converts CSS selectors to XPath expressions",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/css-selector/tree/v5.2.3"
"source": "https://github.com/symfony/css-selector/tree/v5.2.4"
},
"funding": [
{
@@ -6176,16 +6184,16 @@
},
{
"name": "symfony/dom-crawler",
"version": "v5.2.3",
"version": "v5.2.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
"reference": "5d89ceb53ec65e1973a555072fac8ed5ecad3384"
"reference": "400e265163f65aceee7e904ef532e15228de674b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/5d89ceb53ec65e1973a555072fac8ed5ecad3384",
"reference": "5d89ceb53ec65e1973a555072fac8ed5ecad3384",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/400e265163f65aceee7e904ef532e15228de674b",
"reference": "400e265163f65aceee7e904ef532e15228de674b",
"shasum": ""
},
"require": {
@@ -6230,7 +6238,7 @@
"description": "Eases DOM navigation for HTML and XML documents",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/dom-crawler/tree/v5.2.3"
"source": "https://github.com/symfony/dom-crawler/tree/v5.2.4"
},
"funding": [
{
@@ -6246,20 +6254,20 @@
"type": "tidelift"
}
],
"time": "2021-01-27T10:01:46+00:00"
"time": "2021-02-15T18:55:04+00:00"
},
{
"name": "symfony/finder",
"version": "v5.2.3",
"version": "v5.2.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "4adc8d172d602008c204c2e16956f99257248e03"
"reference": "0d639a0943822626290d169965804f79400e6a04"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/4adc8d172d602008c204c2e16956f99257248e03",
"reference": "4adc8d172d602008c204c2e16956f99257248e03",
"url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04",
"reference": "0d639a0943822626290d169965804f79400e6a04",
"shasum": ""
},
"require": {
@@ -6291,7 +6299,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v5.2.3"
"source": "https://github.com/symfony/finder/tree/v5.2.4"
},
"funding": [
{
@@ -6307,7 +6315,7 @@
"type": "tidelift"
}
],
"time": "2021-01-28T22:06:19+00:00"
"time": "2021-02-15T18:55:04+00:00"
},
{
"name": "theseer/tokenizer",
@@ -6408,30 +6416,35 @@
},
{
"name": "webmozart/assert",
"version": "1.9.1",
"version": "1.10.0",
"source": {
"type": "git",
"url": "https://github.com/webmozarts/assert.git",
"reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389"
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389",
"reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25",
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0 || ^8.0",
"php": "^7.2 || ^8.0",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"phpstan/phpstan": "<0.12.20",
"vimeo/psalm": "<3.9.1"
"vimeo/psalm": "<4.6.1 || 4.6.2"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36 || ^7.5.13"
"phpunit/phpunit": "^8.5.13"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.10-dev"
}
},
"autoload": {
"psr-4": {
"Webmozart\\Assert\\": "src/"
@@ -6455,9 +6468,9 @@
],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/1.9.1"
"source": "https://github.com/webmozarts/assert/tree/1.10.0"
},
"time": "2020-07-08T17:02:28+00:00"
"time": "2021-03-09T10:59:23+00:00"
}
],
"aliases": [],
+39 -20
View File
@@ -177,39 +177,47 @@ form:
label: PLUGIN_ADMIN.APPEND_URL_EXT
help: PLUGIN_ADMIN.APPEND_URL_EXT_HELP
pages.redirect_default_route:
type: toggle
label: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE
help: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE_HELP
highlight: 0
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
pages.redirect_default_code:
type: select
size: medium
classes: fancy
label: PLUGIN_ADMIN.REDIRECT_DEFAULT_CODE
help: PLUGIN_ADMIN.REDIRECT_DEFAULT_CODE_HELP
default: 302
options:
301: 301 - Permanent
302: 302 - Found
303: 303 - Other
304: 304 - Not Modified
301: PLUGIN_ADMIN.REDIRECT_OPTION_301
302: PLUGIN_ADMIN.REDIRECT_OPTION_302
303: PLUGIN_ADMIN.REDIRECT_OPTION_303
pages.redirect_default_route:
type: select
size: medium
classes: fancy
label: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE
help: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE_HELP
default: 0
options:
0: PLUGIN_ADMIN.REDIRECT_OPTION_NO_REDIRECT
1: PLUGIN_ADMIN.REDIRECT_OPTION_DEFAULT_REDIRECT
301: PLUGIN_ADMIN.REDIRECT_OPTION_301
302: PLUGIN_ADMIN.REDIRECT_OPTION_302
validate:
type: int
pages.redirect_trailing_slash:
type: toggle
type: select
size: medium
classes: fancy
label: PLUGIN_ADMIN.REDIRECT_TRAILING_SLASH
help: PLUGIN_ADMIN.REDIRECT_TRAILING_SLASH_HELP
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
0: PLUGIN_ADMIN.REDIRECT_OPTION_NO_REDIRECT
1: PLUGIN_ADMIN.REDIRECT_OPTION_DEFAULT_REDIRECT
301: PLUGIN_ADMIN.REDIRECT_OPTION_301
302: PLUGIN_ADMIN.REDIRECT_OPTION_302
validate:
type: bool
type: int
pages.ignore_hidden:
type: toggle
@@ -1006,6 +1014,17 @@ form:
validate:
type: bool
assets.enable_asset_sri:
type: toggle
label: PLUGIN_ADMIN.ENABLED_SRI_ON_ASSETS
help: PLUGIN_ADMIN.ENABLED_SRI_ON_ASSETS_HELP
highlight: 0
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
assets.collections:
type: multilevel
label: PLUGIN_ADMIN.COLLECTIONS
+1 -1
View File
@@ -176,7 +176,7 @@ config:
indexed: true
# Set default ordering of the pages
ordering:
key: ASC
storage_key: ASC
search:
# Search options
options:
+8
View File
@@ -35,10 +35,18 @@ form:
validate:
type: textarea
header.media_order:
type: pagemedia
label: PLUGIN_ADMIN.PAGE_MEDIA
background_image:
type: filepicker
label: image pour fond parallax
options:
type: tab
title: PLUGIN_ADMIN.OPTIONS
+4 -3
View File
@@ -75,9 +75,9 @@ pages:
last_modified: false # Set the last modified date header based on file modification timestamp
etag: true # Set the etag header tag
vary_accept_encoding: false # Add `Vary: Accept-Encoding` header
redirect_default_route: false # Automatically redirect to a page's default route
redirect_default_code: 302 # Default code to use for redirects
redirect_trailing_slash: true # Handle automatically or 302 redirect a trailing / URL
redirect_default_code: 302 # Default code to use for redirects: 301|302|303
redirect_trailing_slash: 1 # Always redirect trailing slash with redirect code 0|1|301|302 (0: no redirect, 1: use default code)
redirect_default_route: 0 # Always redirect to page's default route using code 0|1|301|302, also removes .htm and .html extensions
ignore_files: [.DS_Store] # Files to ignore in Pages
ignore_folders: [.git, .idea] # Folders to ignore in Pages
ignore_hidden: true # Ignore all Hidden files and folders
@@ -127,6 +127,7 @@ assets: # Configuration for Assets Mana
js_pipeline_before_excludes: true # Render the pipeline before any excluded files
js_minify: true # Minify the JS during pipelining
enable_asset_timestamp: false # Enable asset timestamps
enable_asset_sri: false # Enable asset SRI
collections:
jquery: system://assets/jquery/jquery-2.x.min.js
+1 -1
View File
@@ -8,7 +8,7 @@
// Some standard defines
define('GRAV', true);
define('GRAV_VERSION', '1.7.7');
define('GRAV_VERSION', '1.7.9');
define('GRAV_SCHEMA', '1.7.0_2020-11-20_1');
define('GRAV_TESTING', false);
@@ -10,6 +10,7 @@
namespace Grav\Common\Assets;
use Grav\Common\Assets\Traits\AssetUtilsTrait;
use Grav\Common\Config\Config;
use Grav\Common\Grav;
use Grav\Common\Uri;
use Grav\Common\Utils;
@@ -171,6 +172,31 @@ abstract class BaseAsset extends PropertyObject
return $this;
}
/**
* Receive asset location and return the SRI integrity hash
*
* @param $input
*
* @return string
*/
public static function integrityHash( $input )
{
$grav = Grav::instance();
$assetsConfig = $grav['config']->get('system.assets');
if ( !empty($assetsConfig['enable_asset_sri']) && $assetsConfig['enable_asset_sri'] )
{
$dataToHash = file_get_contents( GRAV_ROOT . $input);
$hash = hash('sha256', $dataToHash, true);
$hash_base64 = base64_encode($hash);
return ' integrity="sha256-' . $hash_base64 . '"';
}
return '';
}
/**
+1 -1
View File
@@ -47,6 +47,6 @@ class Css extends BaseAsset
return "<style>\n" . trim($buffer) . "\n</style>\n";
}
return '<link href="' . trim($this->asset) . $this->renderQueryString() . '"' . $this->renderAttributes() . ">\n";
return '<link href="' . trim($this->asset) . $this->renderQueryString() . '"' . $this->renderAttributes() . $this->integrityHash($this->asset) . ">\n";
}
}
+1 -1
View File
@@ -43,6 +43,6 @@ class Js extends BaseAsset
return '<script' . $this->renderAttributes() . ">\n" . trim($buffer) . "\n</script>\n";
}
return '<script src="' . trim($this->asset) . $this->renderQueryString() . '"' . $this->renderAttributes() . "></script>\n";
return '<script src="' . trim($this->asset) . $this->renderQueryString() . '"' . $this->renderAttributes() . $this->integrityHash($this->asset) . "></script>\n";
}
}
+3 -2
View File
@@ -9,6 +9,7 @@
namespace Grav\Common\Assets;
use Grav\Common\Assets\BaseAsset;
use Grav\Common\Assets\Traits\AssetUtilsTrait;
use Grav\Common\Config\Config;
use Grav\Common\Grav;
@@ -148,7 +149,7 @@ class Pipeline extends PropertyObject
$output = "<style>\n" . $buffer . "\n</style>\n";
} else {
$this->asset = $relative_path;
$output = '<link href="' . $relative_path . $this->renderQueryString() . '"' . $this->renderAttributes() . ">\n";
$output = '<link href="' . $relative_path . $this->renderQueryString() . '"' . $this->renderAttributes() . BaseAsset::integrityHash($this->asset) . ">\n";
}
return $output;
@@ -211,7 +212,7 @@ class Pipeline extends PropertyObject
$output = '<script' . $this->renderAttributes(). ">\n" . $buffer . "\n</script>\n";
} else {
$this->asset = $relative_path;
$output = '<script src="' . $relative_path . $this->renderQueryString() . '"' . $this->renderAttributes() . "></script>\n";
$output = '<script src="' . $relative_path . $this->renderQueryString() . '"' . $this->renderAttributes() . BaseAsset::integrityHash($this->asset) . "></script>\n";
}
return $output;
+4 -2
View File
@@ -71,6 +71,7 @@ class Cache extends Getters
'cache://twig/',
'cache://doctrine/',
'cache://compiled/',
'cache://clockwork/',
'cache://validated-',
'cache://images',
'asset://',
@@ -80,6 +81,7 @@ class Cache extends Getters
'cache://twig/',
'cache://doctrine/',
'cache://compiled/',
'cache://clockwork/',
'cache://validated-',
'asset://',
];
@@ -311,7 +313,7 @@ class Cache extends Getters
if ($password && !$redis->auth($password)) {
throw new \RedisException('Redis authentication failed');
}
// Select alternate ( !=0 ) database ID if set
if ($databaseId && !$redis->select($databaseId)) {
throw new \RedisException('Could not select alternate Redis database ID');
@@ -498,7 +500,7 @@ class Cache extends Getters
$anything = true;
}
} elseif (is_dir($file)) {
if (Folder::delete($file)) {
if (Folder::delete($file, false)) {
$anything = true;
}
}
+14 -9
View File
@@ -27,7 +27,6 @@ use function is_bool;
use function is_float;
use function is_int;
use function is_string;
use function strlen;
/**
* Class Validation
@@ -239,16 +238,20 @@ class Validation
$value = trim($value);
}
if (isset($params['min']) && strlen($value) < $params['min']) {
$len = mb_strlen($value);
$min = (int)($params['min'] ?? 0);
if ($min && $len < $min) {
return false;
}
if (isset($params['max']) && strlen($value) > $params['max']) {
$max = (int)($params['max'] ?? 0);
if ($max && $len > $max) {
return false;
}
$min = $params['min'] ?? 0;
if (isset($params['step']) && (strlen($value) - $min) % $params['step'] === 0) {
$step = (int)($params['step'] ?? 0);
if ($step && ($len - $min) % $step === 0) {
return false;
}
@@ -271,11 +274,13 @@ class Validation
return '';
}
$value = (string)$value;
if (!empty($params['trim'])) {
$value = trim($value);
}
return (string) $value;
return $value;
}
/**
@@ -332,7 +337,7 @@ class Validation
*/
protected static function filterLower($value, array $params)
{
return strtolower($value);
return mb_strtolower($value);
}
/**
@@ -342,7 +347,7 @@ class Validation
*/
protected static function filterUpper($value, array $params)
{
return strtoupper($value);
return mb_strtoupper($value);
}
@@ -534,7 +539,7 @@ class Validation
*/
protected static function filterNumber($value, array $params, array $field)
{
return (string)(int)$value !== (string)(float)$value ? (float) $value : (int) $value;
return (string)(int)$value !== (string)(float)$value ? (float)$value : (int)$value;
}
/**
@@ -21,13 +21,16 @@ use Grav\Common\Grav;
use Grav\Common\Page\Header;
use Grav\Common\Page\Interfaces\PageCollectionInterface;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\User\Interfaces\UserInterface;
use Grav\Common\Utils;
use Grav\Framework\Flex\FlexDirectory;
use Grav\Framework\Flex\Interfaces\FlexCollectionInterface;
use Grav\Framework\Flex\Interfaces\FlexStorageInterface;
use Grav\Framework\Flex\Pages\FlexPageIndex;
use InvalidArgumentException;
use RuntimeException;
use function array_slice;
use function count;
use function in_array;
use function is_array;
use function is_string;
@@ -299,7 +302,33 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
'type' => ['root', 'dir'],
];
return $this->getLevelListingRecurse($options);
$key = 'page.idx.lev.' . sha1(json_encode($options, JSON_THROW_ON_ERROR) . $this->getCacheKey());
$checksum = $this->getCacheChecksum();
$cache = $this->getCache('object');
/** @var Debugger $debugger */
$debugger = Grav::instance()['debugger'];
$result = null;
try {
$cached = $cache->get($key);
$test = $cached[0] ?? null;
$result = $test === $checksum ? ($cached[1] ?? null) : null;
} catch (\Psr\SimpleCache\InvalidArgumentException $e) {
$debugger->addException($e);
}
try {
if (null === $result) {
$result = $this->getLevelListingRecurse($options);
$cache->set($key, [$checksum, $result]);
}
} catch (\Psr\SimpleCache\InvalidArgumentException $e) {
$debugger->addException($e);
}
return $result;
}
/**
@@ -429,6 +458,9 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
$selectedChildren = $selectedChildren->order($sortby, $order, $custom ?? null);
}
/** @var UserInterface|null $user */
$user = Grav::instance()['user'] ?? null;
/** @var PageObject $child */
foreach ($selectedChildren as $child) {
$selected = $child->path() === $extra;
@@ -482,7 +514,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
'visible' => $child->visible(),
'routable' => $child->routable(),
'tags' => $tags,
'actions' => $this->getListingActions($child),
'actions' => $this->getListingActions($child, $user),
];
$extras = array_filter($extras, static function ($v) {
return $v !== null;
@@ -490,12 +522,13 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
$tmp = $child->children()->getIndex();
$child_count = $tmp->count();
$count = $filters ? $tmp->filterBy($filters, true)->count() : null;
$route = $child->getRoute();
$payload = [
'item-key' => basename($child->rawRoute() ?? $child->getKey()),
'icon' => $icon,
'title' => htmlspecialchars($child->menu()),
'route' => [
'display' => $child->getRoute()->toString(false) ?: '/',
'display' => ($route ? ($route->toString(false) ?: '/') : null) ?? '',
'raw' => $child->rawRoute(),
],
'modified' => $this->jsDate($child->modified()),
@@ -535,20 +568,21 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
/**
* @param PageObject $object
* @param UserInterface $user
* @return array
*/
protected function getListingActions(PageObject $object): array
protected function getListingActions(PageObject $object, UserInterface $user): array
{
$actions = [];
if ($object->isAuthorized('read')) {
if ($object->isAuthorized('read', null, $user)) {
$actions[] = 'preview';
$actions[] = 'edit';
}
if ($object->isAuthorized('update')) {
if ($object->isAuthorized('update', null, $user)) {
$actions[] = 'copy';
$actions[] = 'move';
}
if ($object->isAuthorized('delete')) {
if ($object->isAuthorized('delete', null, $user)) {
$actions[] = 'delete';
}
@@ -22,6 +22,7 @@ use Grav\Common\Flex\Types\Pages\Traits\PageTranslateTrait;
use Grav\Common\Language\Language;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Page\Pages;
use Grav\Common\User\Interfaces\UserInterface;
use Grav\Common\Utils;
use Grav\Framework\Filesystem\Filesystem;
use Grav\Framework\Flex\FlexObject;
@@ -62,7 +63,6 @@ class PageObject extends FlexPageObject
/** @var string Language code, eg: 'en' */
protected $language;
/** @var string File format, eg. 'md' */
protected $format;
@@ -78,6 +78,7 @@ class PageObject extends FlexPageObject
'path' => true,
'full_order' => true,
'filterBy' => true,
'translated' => false,
] + parent::getCachedMethods();
}
@@ -92,6 +93,11 @@ class PageObject extends FlexPageObject
}
}
public function translated(): bool
{
return $this->translatedLanguages(true) ? true : false;
}
/**
* @param string|array $query
* @return Route|null
@@ -223,7 +229,7 @@ class PageObject extends FlexPageObject
}
// Reorder siblings.
$siblings = is_array($reorder) ? $this->reorderSiblings($reorder) : [];
$siblings = is_array($reorder) ? ($this->reorderSiblings($reorder) ?? []) : [];
$data = $this->prepareStorage();
unset($data['header']);
@@ -289,6 +295,9 @@ class PageObject extends FlexPageObject
$grav->fireEvent('onAdminAfterSave', new Event(['type' => 'flex', 'directory' => $this->getFlexDirectory(), 'object' => $this]));
}
// Reset original after save events have all been called.
$this->_original = null;
return $instance;
}
@@ -308,13 +317,36 @@ class PageObject extends FlexPageObject
$this->_reorder = [];
$this->setProperty('parent_key', $parent->getStorageKey());
$this->storeOriginal();
return $this;
}
/**
* @param UserInterface $user
* @param string $action
* @param string $scope
* @param bool $isMe
* @return bool|null
*/
protected function isAuthorizedOverride(UserInterface $user, string $action, string $scope, bool $isMe): ?bool
{
// Special case: creating a new page means checking parent for its permissions.
if ($action === 'create' && !$this->exists()) {
$parent = $this->parent();
if ($parent && method_exists($parent, 'isAuthorized')) {
return $parent->isAuthorized($action, $scope, $user);
}
return false;
}
return parent::isAuthorizedOverride($user, $action, $scope, $isMe);
}
/**
* @param array $ordering
* @return PageCollection
* @return PageCollection|null
*/
protected function reorderSiblings(array $ordering)
{
@@ -324,17 +356,35 @@ class PageObject extends FlexPageObject
$newParentKey = $this->getProperty('parent_key');
$isMoved = $oldParentKey !== $newParentKey;
$order = !$isMoved ? $this->order() : false;
if ($order !== false) {
$order = (int)$order;
}
$parent = $this->parent();
if (!$parent) {
throw new RuntimeException('Cannot reorder a page which has no parent');
}
/** @var PageCollection|null $siblings */
/** @var PageCollection $siblings */
$siblings = $parent->children();
$siblings = $siblings->getCollection()->withOrdered();
/** @var PageCollection|null $siblings */
$siblings = $siblings->getCollection()->withOrdered()->orderBy(['order' => 'ASC']);
// Handle special case where ordering isn't given.
if ($ordering === []) {
if ($order >= 999999) {
// Set ordering to point to be the last item.
$order = 0;
foreach ($siblings as $sibling) {
$order = max($order, (int)$sibling->order());
}
$this->order($order + 1);
}
// Do not change sibling ordering.
return null;
}
$siblings = $siblings->orderBy(['order' => 'ASC']);
if ($storageKey !== null) {
if ($order !== false) {
@@ -378,7 +428,9 @@ class PageObject extends FlexPageObject
throw new RuntimeException("New parent page '{$parentKey}' not found.");
}
}
$newSiblings = $newParent->children()->getCollection()->withOrdered();
/** @var PageCollection $newSiblings */
$newSiblings = $newParent->children();
$newSiblings = $newSiblings->getCollection()->withOrdered();
$order = 0;
foreach ($newSiblings as $sibling) {
$order = max($order, (int)$sibling->order());
@@ -584,14 +636,17 @@ class PageObject extends FlexPageObject
unset($elements['ordering'], $elements['order']);
} elseif (array_key_exists('ordering', $elements) && array_key_exists('order', $elements)) {
// Store ordering.
$this->_reorder = !empty($elements['order']) ? explode(',', $elements['order']) : [];
$ordering = $elements['order'] ?? null;
$this->_reorder = !empty($ordering) ? explode(',', $ordering) : [];
$order = false;
if ((bool)($elements['ordering'] ?? false)) {
$order = 999999;
$order = $this->order();
if ($order === false) {
$order = 999999;
}
}
$this->order();
$elements['order'] = $order;
}
@@ -110,6 +110,9 @@ class PageStorage extends FolderStorage
}
} catch (RuntimeException $e) {
$frontmatter = 'ERROR: ' . $e->getMessage();
} finally {
$file->free();
unset($file);
}
return $frontmatter;
@@ -127,6 +130,9 @@ class PageStorage extends FolderStorage
$raw = $file->raw();
} catch (RuntimeException $e) {
$raw = 'ERROR: ' . $e->getMessage();
} finally {
$file->free();
unset($file);
}
return $raw;
@@ -407,7 +413,7 @@ class PageStorage extends FolderStorage
if (!$isClone && $file->exists()) {
/** @var UniformResourceLocator $locator */
$locator = $grav['locator'];
$toPath = $locator->isStream($newFilepath) ? $locator->findResource($newFilepath, true, true) : $newFilepath;
$toPath = $locator->isStream($newFilepath) ? $locator->findResource($newFilepath, true, true) : GRAV_ROOT . "/{$newFilepath}";
$success = $file->rename($toPath);
if (!$success) {
throw new RuntimeException("Changing page template failed: {$oldFilepath} => {$newFilepath}");
@@ -439,16 +445,19 @@ class PageStorage extends FolderStorage
} else {
$debugger->addMessage('Page content has not been changed, do not update the file', 'debug');
}
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
if ($locator->isStream($newFolder)) {
$locator->clearCache();
}
} catch (RuntimeException $e) {
$name = isset($file) ? $file->filename() : $newKey;
throw new RuntimeException(sprintf('Flex saveRow(%s): %s', $name, $e->getMessage()));
} finally {
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
$locator->clearCache();
if (isset($file)) {
$file->free();
unset($file);
}
}
$row['__META'] = $this->getObjectMeta($newKey, true);
@@ -512,7 +521,11 @@ class PageStorage extends FolderStorage
$locator = Grav::instance()['locator'];
if (mb_strpos($key, '@@') === false) {
$path = $this->getStoragePath($key);
$path = $path ? $locator->findResource($path) : null;
if (is_string($path)) {
$path = $locator->isStream($path) ? $locator->findResource($path) : GRAV_ROOT . "/{$path}";
} else {
$path = null;
}
} else {
$path = null;
}
@@ -15,6 +15,7 @@ use Grav\Common\Grav;
use Grav\Common\Page\Interfaces\PageCollectionInterface;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Page\Pages;
use Grav\Common\Uri;
use Grav\Common\Utils;
use Grav\Framework\Filesystem\Filesystem;
use RuntimeException;
@@ -97,6 +98,7 @@ trait PageRoutableTrait
public function activeChild(): bool
{
$grav = Grav::instance();
/** @var Uri $uri */
$uri = $grav['uri'];
/** @var Pages $pages */
$pages = $grav['pages'];
@@ -67,7 +67,7 @@ trait PageTranslateTrait
if (!$folder) {
return [];
}
$folder = $locator($folder);
$folder = $locator->isStream($folder) ? $locator->getResource($folder) : GRAV_ROOT . "/{$folder}";
$list = array_fill_keys($languages, null);
foreach ($translated as $languageCode => $languageFile) {
+12 -6
View File
@@ -426,12 +426,18 @@ class Grav extends Container
// Clean route for redirect
$route = preg_replace("#^\/[\\\/]+\/#", '/', $route);
// Check for code in route
$regex = '/.*(\[(30[1-7])\])$/';
preg_match($regex, $route, $matches);
if ($matches) {
$route = str_replace($matches[1], '', $matches[0]);
$code = $matches[2];
if ($code < 300 || $code > 399) {
$code = null;
}
if (null === $code) {
// Check for redirect code in the route: e.g. /new/[301], /new[301]/route or /new[301].html
$regex = '/.*(\[(30[1-7])\])(.\w+|\/.*?)?$/';
preg_match($regex, $route, $matches);
if ($matches) {
$route = str_replace($matches[1], '', $matches[0]);
$code = $matches[2];
}
}
if ($code === null) {
+4 -4
View File
@@ -34,7 +34,7 @@ class LogViewer
public function objectTail($filepath, $lines = 1, $desc = true)
{
$data = $this->tail($filepath, $lines);
$tailed_log = explode(PHP_EOL, $data);
$tailed_log = $data ? explode(PHP_EOL, $data) : [];
$line_objects = [];
foreach ($tailed_log as $line) {
@@ -54,13 +54,13 @@ class LogViewer
public function tail($filepath, $lines = 1)
{
$f = @fopen($filepath, "rb");
$f = $filepath ? @fopen($filepath, 'rb') : false;
if ($f === false) {
return false;
} else {
$buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096));
}
$buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096));
fseek($f, -1, SEEK_END);
if (fread($f, 1) != "\n") {
$lines -= 1;
@@ -63,7 +63,7 @@ interface PageRoutableInterface
* the parents route and the current Page's slug.
*
* @param string|null $var Set new default route.
* @return string The route for the Page.
* @return string|null The route for the Page.
*/
public function route($var = null);
@@ -278,10 +278,10 @@ class Excerpts
);
}
$defaults = $config['images']['defaults'] ?? [];
$defaults = $this->config['images']['defaults'] ?? [];
if (count($defaults)) {
foreach ($defaults as $method => $params) {
if (!array_search($method, array_column($actions, 'method'))) {
if (array_search($method, array_column($actions, 'method')) === false) {
$actions[] = [
'method' => $method,
'params' => $params,
@@ -198,6 +198,17 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac
}
}
/**
* @param string $name
* @return void
*/
public function hide($name)
{
$this->offsetUnset($name);
unset($this->images[$name], $this->videos[$name], $this->audios[$name], $this->files[$name]);
}
/**
* Create Medium from a file.
*
+13 -11
View File
@@ -1875,7 +1875,7 @@ class Page implements PageInterface
* the parents route and the current Page's slug.
*
* @param string|null $var Set new default route.
* @return string The route for the Page.
* @return string|null The route for the Page.
*/
public function route($var = null)
{
@@ -2496,21 +2496,23 @@ class Page implements PageInterface
*/
public function activeChild()
{
$uri = Grav::instance()['uri'];
$pages = Grav::instance()['pages'];
$grav = Grav::instance();
/** @var Uri $uri */
$uri = $grav['uri'];
/** @var Pages $pages */
$pages = $grav['pages'];
$uri_path = rtrim(urldecode($uri->path()), '/');
$routes = Grav::instance()['pages']->routes();
$routes = $pages->routes();
if (isset($routes[$uri_path])) {
$page = $pages->find($uri->route());
/** @var PageInterface|null $child_page */
$child_page = $pages->find($uri->route())->parent();
if ($child_page) {
while (!$child_page->root()) {
if ($this->path() === $child_page->path()) {
return true;
}
$child_page = $child_page->parent();
$child_page = $page ? $page->parent() : null;
while ($child_page && !$child_page->root()) {
if ($this->path() === $child_page->path()) {
return true;
}
$child_page = $child_page->parent();
}
}
+146 -81
View File
@@ -769,6 +769,9 @@ class Pages
public function get($path)
{
$path = (string)$path;
if ($path === '') {
return null;
}
// Check for local instances first.
if (array_key_exists($path, $this->instances)) {
@@ -777,14 +780,26 @@ class Pages
$instance = $this->index[$path] ?? null;
if (is_string($instance)) {
/** @var Language $language */
$language = $this->grav['language'];
$lang = $language->getActive();
if ($lang) {
$instance .= ':' . $lang;
if ($this->directory) {
/** @var Language $language */
$language = $this->grav['language'];
$lang = $language->getActive();
if ($lang) {
$languages = $language->getFallbackLanguages($lang, true);
$key = $instance;
$instance = null;
foreach ($languages as $code) {
$test = $code ? $key . ':' . $code : $key;
if (($instance = $this->directory->getObject($test, 'flex_key')) !== null) {
break;
}
}
} else {
$instance = $this->directory->getObject($instance, 'flex_key');
}
}
$instance = $this->directory ? $this->directory->getObject($instance, 'flex_key') : null;
if ($instance) {
if ($instance instanceof PageInterface) {
if ($this->fire_events && method_exists($instance, 'initialize')) {
$instance->initialize();
}
@@ -865,103 +880,146 @@ class Pages
}
/**
* alias method to return find a page.
* Find a page based on route.
*
* @param string $route The relative URL of the page
* @param bool $all
* @param string $route The route of the page
* @param bool $all If true, return also non-routable pages, otherwise return null if page isn't routable
* @return PageInterface|null
*/
public function find($route, $all = false)
{
return $this->dispatch($route, $all, false);
$route = urldecode((string)$route);
// Fetch page if there's a defined route to it.
$path = $this->routes[$route] ?? null;
$page = null !== $path ? $this->get($path) : null;
// Try without trailing slash
if (null === $page && Utils::endsWith($route, '/')) {
$path = $this->routes[rtrim($route, '/')] ?? null;
$page = null !== $path ? $this->get($path) : null;
}
if (!$all && !isset($this->grav['admin'])) {
if (null === $page || !$page->routable()) {
// If the page cannot be accessed, look for the site wide routes and wildcards.
$page = $this->findSiteBasedRoute($route) ?? $page;
}
}
return $page;
}
/**
* Check site based routes.
*
* @param string $route
* @return PageInterface|null
*/
protected function findSiteBasedRoute($route)
{
/** @var Config $config */
$config = $this->grav['config'];
$site_routes = $config->get('site.routes');
if (!is_array($site_routes)) {
return null;
}
$page = null;
// See if route matches one in the site configuration
$site_route = $site_routes[$route] ?? null;
if ($site_route) {
$page = $this->find($site_route);
} else {
// Use reverse order because of B/C (previously matched multiple and returned the last match).
foreach (array_reverse($site_routes, true) as $pattern => $replace) {
$pattern = '#^' . str_replace('/', '\/', ltrim($pattern, '^')) . '#';
try {
$found = preg_replace($pattern, $replace, $route);
if ($found && $found !== $route) {
$page = $this->find($found);
if ($page) {
return $page;
}
}
} catch (ErrorException $e) {
$this->grav['log']->error('site.routes: ' . $pattern . '-> ' . $e->getMessage());
}
}
}
return $page;
}
/**
* Dispatch URI to a page.
*
* @param string $route The relative URL of the page
* @param bool $all
* @param bool $redirect
* @param bool $all If true, return also non-routable pages, otherwise return null if page isn't routable
* @param bool $redirect If true, allow redirects
* @return PageInterface|null
* @throws Exception
*/
public function dispatch($route, $all = false, $redirect = true)
{
$route = urldecode($route);
$page = $this->find($route, true);
// Fetch page if there's a defined route to it.
$path = $this->routes[$route] ?? null;
$page = null !== $path ? $this->get($path) : null;
// Try without trailing slash
if (!$page && Utils::endsWith($route, '/')) {
$path = $this->routes[rtrim($route, '/')] ?? null;
$page = null !== $path ? $this->get($path) : null;
// If we want all pages or are in admin, return what we already have.
if ($all || isset($this->grav['admin'])) {
return $page;
}
// Are we in the admin? this is important!
$not_admin = !isset($this->grav['admin']);
// If the page cannot be reached, look into site wide redirects, routes + wildcards
if (!$all && $not_admin) {
// If the page is a simple redirect, just do it.
if ($redirect && $page && $page->redirect()) {
$this->grav->redirectLangSafe($page->redirect());
}
// fall back and check site based redirects
if (!$page || !$page->routable()) {
// Redirect to the first child (placeholder page)
if ($redirect && $page && count($children = $page->children()->visible()->routable()->published()) > 0) {
$this->grav->redirectLangSafe($children->first()->route());
if ($page) {
$routable = $page->routable();
if ($redirect) {
if ($page->redirect()) {
// Follow a redirect page.
$this->grav->redirectLangSafe($page->redirect());
}
/** @var Config $config */
$config = $this->grav['config'];
if (!$routable && ($child = $page->children()->visible()->routable()->published()->first()) !== null) {
// Redirect to the first visible child as current page isn't routable.
$this->grav->redirectLangSafe($child->route());
}
}
// See if route matches one in the site configuration
$site_route = $config->get("site.routes.{$route}");
if ($site_route) {
$page = $this->dispatch($site_route, $all, $redirect);
} else {
/** @var Uri $uri */
$uri = $this->grav['uri'];
/** @var \Grav\Framework\Uri\Uri $source_url */
$source_url = $uri->uri(false);
if ($routable) {
return $page;
}
}
// Try Regex style redirects
$site_redirects = $config->get('site.redirects');
if (is_array($site_redirects)) {
foreach ((array)$site_redirects as $pattern => $replace) {
$pattern = ltrim($pattern, '^');
$pattern = '#^' . str_replace('/', '\/', $pattern) . '#';
try {
/** @var string $found */
$found = preg_replace($pattern, $replace, $source_url);
if ($found && $found !== $source_url) {
$this->grav->redirectLangSafe($found);
}
} catch (ErrorException $e) {
$this->grav['log']->error('site.redirects: ' . $pattern . '-> ' . $e->getMessage());
}
}
}
// Try Regex style routes
$site_routes = $config->get('site.routes');
if (is_array($site_routes)) {
foreach ((array)$site_routes as $pattern => $replace) {
$pattern = '#^' . str_replace('/', '\/', ltrim($pattern, '^')) . '#';
try {
/** @var string $found */
$found = preg_replace($pattern, $replace, $source_url);
if ($found && $found !== $source_url) {
$page = $this->dispatch($found, $all, $redirect);
}
} catch (ErrorException $e) {
$this->grav['log']->error('site.routes: ' . $pattern . '-> ' . $e->getMessage());
}
}
$route = urldecode((string)$route);
// The page cannot be reached, look into site wide redirects, routes and wildcards.
$redirectedPage = $this->findSiteBasedRoute($route);
if ($redirectedPage) {
$page = $this->dispatch($redirectedPage->route(), false, $redirect);
}
/** @var Config $config */
$config = $this->grav['config'];
/** @var Uri $uri */
$uri = $this->grav['uri'];
/** @var \Grav\Framework\Uri\Uri $source_url */
$source_url = $uri->uri(false);
// Try Regex style redirects
$site_redirects = $config->get('site.redirects');
if (is_array($site_redirects)) {
foreach ((array)$site_redirects as $pattern => $replace) {
$pattern = ltrim($pattern, '^');
$pattern = '#^' . str_replace('/', '\/', $pattern) . '#';
try {
/** @var string $found */
$found = preg_replace($pattern, $replace, $source_url);
if ($found && $found !== $source_url) {
$this->grav->redirectLangSafe($found);
}
} catch (ErrorException $e) {
$this->grav['log']->error('site.redirects: ' . $pattern . '-> ' . $e->getMessage());
}
}
}
@@ -1159,7 +1217,14 @@ class Pages
$event->types = $types;
$grav->fireEvent('onGetPageBlueprints', $event);
$types->scanBlueprints('theme://blueprints/');
$types->init();
// Try new location first.
$lookup = 'theme://blueprints/pages/';
if (!is_dir($lookup)) {
$lookup = 'theme://blueprints/';
}
$types->scanBlueprints($lookup);
// Scan templates
$event = new Event();
+21 -13
View File
@@ -32,22 +32,23 @@ class Types implements \ArrayAccess, \Iterator, \Countable
/** @var array */
protected $items;
/** @var array */
protected $systemBlueprints;
protected $systemBlueprints = [];
/**
* @param string $type
* @param Blueprint|null $blueprint
* @return void
*/
public function register($type, $blueprint = null)
{
if (!isset($this->items[$type])) {
$this->items[$type] = [];
} elseif (!$blueprint) {
} elseif (null === $blueprint) {
return;
}
if (!$blueprint && $this->systemBlueprints) {
$blueprint = $this->systemBlueprints[$type] ?? $this->systemBlueprints['default'];
if (null === $blueprint) {
$blueprint = $this->systemBlueprints[$type] ?? $this->systemBlueprints['default'] ?? null;
}
if ($blueprint) {
@@ -55,8 +56,23 @@ class Types implements \ArrayAccess, \Iterator, \Countable
}
}
/**
* @return void
*/
public function init()
{
if (null === $this->systemBlueprints) {
// Register all blueprints from the blueprints stream.
$this->systemBlueprints = $this->findBlueprints('blueprints://pages');
foreach ($this->systemBlueprints as $type => $blueprint) {
$this->register($type);
}
}
}
/**
* @param string $uri
* @return void
*/
public function scanBlueprints($uri)
{
@@ -64,15 +80,6 @@ class Types implements \ArrayAccess, \Iterator, \Countable
throw new InvalidArgumentException('First parameter must be URI');
}
if (null === $this->systemBlueprints) {
$this->systemBlueprints = $this->findBlueprints('blueprints://pages');
// Register default by default.
$this->register('default');
$this->register('external');
}
foreach ($this->findBlueprints($uri) as $type => $blueprint) {
$this->register($type, $blueprint);
}
@@ -80,6 +87,7 @@ class Types implements \ArrayAccess, \Iterator, \Countable
/**
* @param string $uri
* @return void
*/
public function scanTemplates($uri)
{
+53 -34
View File
@@ -16,6 +16,7 @@ use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Config\Config;
use LogicException;
use RocketTheme\Toolbox\File\YamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use function defined;
@@ -35,11 +36,11 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
/** @var Grav */
protected $grav;
/** @var Config */
/** @var Config|null */
protected $config;
/** @var bool */
protected $active = true;
/** @var Blueprint */
/** @var Blueprint|null */
protected $blueprint;
/**
@@ -127,21 +128,25 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
*/
protected function isPluginActiveAdmin($plugin_route)
{
$should_run = false;
$active = false;
/** @var Uri $uri */
$uri = $this->grav['uri'];
/** @var Config $config */
$config = $this->config ?? $this->grav['config'];
if (strpos($uri->path(), $this->config->get('plugins.admin.route') . '/' . $plugin_route) === false) {
$should_run = false;
if (strpos($uri->path(), $config->get('plugins.admin.route') . '/' . $plugin_route) === false) {
$active = false;
} elseif (isset($uri->paths()[1]) && $uri->paths()[1] === $plugin_route) {
$should_run = true;
$active = true;
}
return $should_run;
return $active;
}
/**
* @param array $events
* @return void
*/
protected function enable(array $events)
{
@@ -164,22 +169,18 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
/**
* @param array $params
* @param string $eventName
* @return int
*/
private function getPriority($params, $eventName)
{
$grav = Grav::instance();
$override = implode('.', ['priorities', $this->name, $eventName, $params[0]]);
if ($grav['config']->get($override) !== null) {
return $grav['config']->get($override);
}
if (isset($params[1])) {
return $params[1];
}
return 0;
return $this->grav['config']->get($override) ?? $params[1] ?? 0;
}
/**
* @param array $events
* @return void
*/
protected function disable(array $events)
{
@@ -207,12 +208,13 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
*/
public function offsetExists($offset)
{
$this->loadBlueprint();
if ($offset === 'title') {
$offset = 'name';
}
return isset($this->blueprint[$offset]);
$blueprint = $this->getBlueprint();
return isset($blueprint[$offset]);
}
/**
@@ -223,12 +225,13 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
*/
public function offsetGet($offset)
{
$this->loadBlueprint();
if ($offset === 'title') {
$offset = 'name';
}
return $this->blueprint[$offset] ?? null;
$blueprint = $this->getBlueprint();
return $blueprint[$offset] ?? null;
}
/**
@@ -281,9 +284,12 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
*/
protected function parseLinks($content, $function, $internal_regex = '(.*)')
{
$regex = '/\[plugin:(?:' . $this->name . ')\]\(' . $internal_regex . '\)/i';
$regex = '/\[plugin:(?:' . preg_quote($this->name, '/') . ')\]\(' . $internal_regex . '\)/i';
return preg_replace_callback($regex, $function, $content);
$result = preg_replace_callback($regex, $function, $content);
\assert($result !== null);
return $result;
}
/**
@@ -301,9 +307,12 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
*/
protected function mergeConfig(PageInterface $page, $deep = false, $params = [], $type = 'plugins')
{
/** @var Config $config */
$config = $this->config ?? $this->grav['config'];
$class_name = $this->name;
$class_name_merged = $class_name . '.merged';
$defaults = $this->config->get($type . '.' . $class_name, []);
$defaults = $config->get($type . '.' . $class_name, []);
$page_header = $page->header();
$header = [];
@@ -356,23 +365,26 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
/**
* Persists to disk the plugin parameters currently stored in the Grav Config object
*
* @param string $plugin_name The name of the plugin whose config it should store.
*
* @param string $name The name of the plugin whose config it should store.
* @return bool
*/
public static function saveConfig($plugin_name)
public static function saveConfig($name)
{
if (!$plugin_name) {
if (!$name) {
return false;
}
$grav = Grav::instance();
/** @var UniformResourceLocator $locator */
$locator = $grav['locator'];
$filename = 'config://plugins/' . $plugin_name . '.yaml';
$file = YamlFile::instance($locator->findResource($filename, true, true));
$content = $grav['config']->get('plugins.' . $plugin_name);
$filename = 'config://plugins/' . $name . '.yaml';
$file = YamlFile::instance((string)$locator->findResource($filename, true, true));
$content = $grav['config']->get('plugins.' . $name);
$file->save($content);
$file->free();
unset($file);
return true;
}
@@ -384,21 +396,28 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
*/
public function getBlueprint()
{
if (!$this->blueprint) {
if (null === $this->blueprint) {
$this->loadBlueprint();
\assert($this->blueprint instanceof Blueprint);
}
return $this->blueprint;
}
/**
* Load blueprints.
*
* @return void
*/
protected function loadBlueprint()
{
if (!$this->blueprint) {
if (null === $this->blueprint) {
$grav = Grav::instance();
/** @var Plugins $plugins */
$plugins = $grav['plugins'];
$this->blueprint = $plugins->get($this->name)->blueprints();
$data = $plugins->get($this->name);
\assert($data !== null);
$this->blueprint = $data->blueprints();
}
}
}
+27 -11
View File
@@ -17,6 +17,7 @@ use Grav\Common\File\CompiledYamlFile;
use Grav\Events\PluginsLoadedEvent;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use RuntimeException;
use SplFileInfo;
use Symfony\Component\EventDispatcher\EventDispatcher;
use function get_class;
use function is_object;
@@ -27,7 +28,7 @@ use function is_object;
*/
class Plugins extends Iterator
{
/** @var array */
/** @var array|null */
public $formFieldTypes;
/** @var bool */
@@ -46,6 +47,7 @@ class Plugins extends Iterator
$iterator = $locator->getIterator('plugins://');
$plugins = [];
/** @var SplFileInfo $directory */
foreach ($iterator as $directory) {
if (!$directory->isDir()) {
continue;
@@ -56,7 +58,10 @@ class Plugins extends Iterator
sort($plugins, SORT_NATURAL | SORT_FLAG_CASE);
foreach ($plugins as $plugin) {
$this->add($this->loadPlugin($plugin));
$object = $this->loadPlugin($plugin);
if ($object) {
$this->add($object);
}
}
}
@@ -68,13 +73,21 @@ class Plugins extends Iterator
$blueprints = [];
$formFields = [];
$grav = Grav::instance();
/** @var Config $config */
$config = $grav['config'];
/** @var Plugin $plugin */
foreach ($this->items as $plugin) {
if (isset($plugin->features['blueprints'])) {
$blueprints["plugin://{$plugin->name}/blueprints"] = $plugin->features['blueprints'];
}
if (method_exists($plugin, 'getFormFieldTypes')) {
$formFields[get_class($plugin)] = isset($plugin->features['formfields']) ? $plugin->features['formfields'] : 0;
// Setup only enabled plugins.
if ($config["plugins.{$plugin->name}.enabled"] && $plugin instanceof Plugin) {
if (isset($plugin->features['blueprints'])) {
$blueprints["plugin://{$plugin->name}/blueprints"] = $plugin->features['blueprints'];
}
if (method_exists($plugin, 'getFormFieldTypes')) {
$formFields[get_class($plugin)] = $plugin->features['formfields'] ?? 0;
}
}
}
@@ -83,7 +96,7 @@ class Plugins extends Iterator
arsort($blueprints, SORT_NUMERIC);
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
$locator = $grav['locator'];
$locator->addPath('blueprints', '', array_keys($blueprints), ['system', 'blueprints']);
}
@@ -150,6 +163,7 @@ class Plugins extends Iterator
* Add a plugin
*
* @param Plugin $plugin
* @return void
*/
public function add($plugin)
{
@@ -175,8 +189,8 @@ class Plugins extends Iterator
*/
public static function getPlugins(): array
{
$grav = Grav::instance();
$plugins = $grav['plugins'];
/** @var Plugins $plugins */
$plugins = Grav::instance()['plugins'];
$list = [];
foreach ($plugins as $instance) {
@@ -200,11 +214,13 @@ class Plugins extends Iterator
/**
* Return list of all plugin data with their blueprints.
*
* @return array<string,Data>
* @return Data[]
*/
public static function all()
{
$grav = Grav::instance();
/** @var Plugins $plugins */
$plugins = $grav['plugins'];
$list = [];
@@ -105,8 +105,9 @@ class InitializeProcessor extends ProcessorBase
$this->initializeUri($config);
// Grav may return redirect response right away.
if ($config->get('system.pages.redirect_trailing_slash', false)) {
$response = $this->handleRedirectRequest($request);
$redirectCode = (int)$config->get('system.pages.redirect_trailing_slash', 1);
if ($redirectCode) {
$response = $this->handleRedirectRequest($request, $redirectCode > 300 ? $redirectCode : null);
if ($response) {
$this->stopTimer('_init');
@@ -413,7 +414,7 @@ class InitializeProcessor extends ProcessorBase
$this->stopTimer('_init_uri');
}
protected function handleRedirectRequest(RequestInterface $request): ?ResponseInterface
protected function handleRedirectRequest(RequestInterface $request, int $code = null): ?ResponseInterface
{
if (!in_array($request->getMethod(), ['GET', 'HEAD'])) {
return null;
@@ -426,7 +427,7 @@ class InitializeProcessor extends ProcessorBase
if ($path !== $root && $path !== $root . '/' && Utils::endsWith($path, '/')) {
// Use permanent redirect for SEO reasons.
return $this->container->getRedirectResponse((string)$uri->withPath(rtrim($path, '/')), 301);
return $this->container->getRedirectResponse((string)$uri->withPath(rtrim($path, '/')), $code);
}
return null;
@@ -77,32 +77,46 @@ class PagesServiceProvider implements ServiceProviderInterface
}
}
$url = $pages->route($page->route());
$route = $page->route();
if ($route && \in_array($uri->method(), ['GET', 'HEAD'], true)) {
$pageExtension = $page->urlExtension();
$url = $pages->route($route) . $pageExtension;
if ($uri->params()) {
if ($url === '/') { //Avoid double slash
$url = $uri->params();
} else {
$url .= $uri->params();
if ($uri->params()) {
if ($url === '/') { //Avoid double slash
$url = $uri->params();
} else {
$url .= $uri->params();
}
}
if ($uri->query()) {
$url .= '?' . $uri->query();
}
if ($uri->fragment()) {
$url .= '#' . $uri->fragment();
}
}
if ($uri->query()) {
$url .= '?' . $uri->query();
}
if ($uri->fragment()) {
$url .= '#' . $uri->fragment();
}
/** @var Language $language */
$language = $grav['language'];
/** @var Language $language */
$language = $grav['language'];
// Language-specific redirection scenarios
if ($language->enabled() && ($language->isLanguageInUrl() xor $language->isIncludeDefaultLanguage())) {
$grav->redirect($url);
}
// Default route test and redirect
if ($config->get('system.pages.redirect_default_route') && $page->route() !== $path) {
$grav->redirect($url);
$redirectCode = (int)$config->get('system.pages.redirect_default_route', 0);
// Language-specific redirection scenarios
if ($language->enabled() && ($language->isLanguageInUrl() xor $language->isIncludeDefaultLanguage())) {
$grav->redirect($url, $redirectCode);
}
// Default route test and redirect
if ($redirectCode) {
$uriExtension = $uri->extension();
$uriExtension = null !== $uriExtension ? '.' . $uriExtension : '';
if ($route !== $path || ($pageExtension !== $uriExtension
&& \in_array($pageExtension, ['', '.htm', '.html'], true)
&& \in_array($uriExtension, ['', '.htm', '.html'], true))) {
$grav->redirect($url, $redirectCode);
}
}
}
}
+15 -35
View File
@@ -9,9 +9,9 @@
namespace Grav\Common;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Config\Config;
use RocketTheme\Toolbox\File\YamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* Class Theme
@@ -44,53 +44,30 @@ class Theme extends Plugin
/**
* Persists to disk the theme parameters currently stored in the Grav Config object
*
* @param string $theme_name The name of the theme whose config it should store.
* @param string $name The name of the theme whose config it should store.
* @return bool
*/
public static function saveConfig($theme_name)
public static function saveConfig($name)
{
if (!$theme_name) {
if (!$name) {
return false;
}
$grav = Grav::instance();
/** @var UniformResourceLocator $locator */
$locator = $grav['locator'];
$filename = 'config://themes/' . $theme_name . '.yaml';
$file = YamlFile::instance($locator->findResource($filename, true, true));
$content = $grav['config']->get('themes.' . $theme_name);
$filename = 'config://themes/' . $name . '.yaml';
$file = YamlFile::instance((string)$locator->findResource($filename, true, true));
$content = $grav['config']->get('themes.' . $name);
$file->save($content);
$file->free();
unset($file);
return true;
}
/**
* Override the mergeConfig method to work for themes
*
* @param PageInterface $page
* @param string $deep
* @param array $params
* @param string $type
* @return Data\Data
*/
protected function mergeConfig(PageInterface $page, $deep = 'merge', $params = [], $type = 'themes')
{
return parent::mergeConfig($page, $deep, $params, $type);
}
/**
* Simpler getter for the theme blueprint
*
* @return mixed
*/
public function getBlueprint()
{
if (!$this->blueprint) {
$this->loadBlueprint();
}
return $this->blueprint;
}
/**
* Load blueprints.
*
@@ -100,8 +77,11 @@ class Theme extends Plugin
{
if (!$this->blueprint) {
$grav = Grav::instance();
/** @var Themes $themes */
$themes = $grav['themes'];
$this->blueprint = $themes->get($this->name)->blueprints();
$data = $themes->get($this->name);
\assert($data !== null);
$this->blueprint = $data->blueprints();
}
}
}
+18 -3
View File
@@ -33,10 +33,8 @@ class Themes extends Iterator
{
/** @var Grav */
protected $grav;
/** @var Config */
protected $config;
/** @var bool */
protected $inited = false;
@@ -95,6 +93,20 @@ class Themes extends Iterator
$events->addSubscriber($instance);
}
// Register blueprints.
if (is_dir('theme://blueprints/pages')) {
/** @var UniformResourceLocator $locator */
$locator = $this->grav['locator'];
$locator->addPath('blueprints', '', ['theme://blueprints'], ['user', 'blueprints']);
}
// Register form fields.
if (method_exists($instance, 'getFormFieldTypes')) {
/** @var Plugins $plugins */
$plugins = $this->grav['plugins'];
$plugins->formFieldTypes = $instance->getFormFieldTypes() + $plugins->formFieldTypes;
}
$this->grav['theme'] = $instance;
$this->grav->fireEvent('onThemeInitialized');
@@ -382,7 +394,10 @@ class Themes extends Iterator
}
// Try Old style theme classes
$path = strtolower(preg_replace('#\\\|_(?!.+\\\)#', '/', $class));
$path = preg_replace('#\\\|_(?!.+\\\)#', '/', $class);
\assert(null !== $path);
$path = strtolower($path);
$file = $locator("themes://{$path}/theme.php") ?: $locator("themes://{$path}/{$path}.php");
// Load class
+7 -10
View File
@@ -21,6 +21,7 @@ use RocketTheme\Toolbox\Event\Event;
use RuntimeException;
use function array_key_exists;
use function count;
use function in_array;
use function is_array;
use function is_string;
use function strlen;
@@ -394,7 +395,7 @@ class Uri
* Return the Extension of the URI
*
* @param string|null $default
* @return string The extension of the URI
* @return string|null The extension of the URI
*/
public function extension($default = null)
{
@@ -518,7 +519,7 @@ class Uri
* Return the full uri
*
* @param bool $include_root
* @return mixed
* @return string
*/
public function uri($include_root = true)
{
@@ -1408,18 +1409,14 @@ class Uri
/**
* Check if this is a valid Grav extension
*
* @param string $extension
* @param string|null $extension
* @return bool
*/
public function isValidExtension($extension)
public function isValidExtension($extension): bool
{
$valid_page_types = implode('|', Utils::getSupportPageTypes());
$extension = (string)$extension;
// Strip the file extension for valid page types
if (preg_match('/(' . $valid_page_types . ')/', $extension)) {
return true;
}
return false;
return $extension !== '' && in_array($extension, Utils::getSupportPageTypes(), true);
}
/**
+112 -33
View File
@@ -12,11 +12,15 @@ namespace Grav\Common;
use DateTime;
use DateTimeZone;
use Exception;
use Grav\Common\Flex\Types\Pages\PageObject;
use Grav\Common\Helpers\Truncator;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Markdown\Parsedown;
use Grav\Common\Markdown\ParsedownExtra;
use Grav\Common\Page\Markdown\Excerpts;
use Grav\Common\Page\Pages;
use Grav\Framework\Flex\Flex;
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
use InvalidArgumentException;
use Negotiation\Accept;
use Negotiation\Negotiator;
@@ -1520,7 +1524,7 @@ abstract class Utils
}
/**
* Get path based on a token
* Get relative page path based on a token.
*
* @param string $path
* @param PageInterface|null $page
@@ -1529,47 +1533,122 @@ abstract class Utils
*/
public static function getPagePathFromToken($path, PageInterface $page = null)
{
$path_parts = pathinfo($path);
$grav = Grav::instance();
return static::getPathFromToken($path, $page);
}
$basename = '';
if (isset($path_parts['extension'])) {
$basename = '/' . $path_parts['basename'];
$path = rtrim($path_parts['dirname'], ':');
/**
* Get relative path based on a token.
*
* Path supports following syntaxes:
*
* 'self@', 'self@/path'
* 'page@:/route', 'page@:/route/filename.ext'
* 'theme@:', 'theme@:/path'
*
* @param string $path
* @param FlexObjectInterface|PageInterface|null $object
* @return string
* @throws RuntimeException
*/
public static function getPathFromToken($path, $object = null)
{
$matches = static::resolveTokenPath($path);
if (null === $matches) {
return $path;
}
$regex = '/(@self|self@)|((?:@page|page@):(?:.*))|((?:@theme|theme@):(?:.*))/';
preg_match($regex, $path, $matches);
$grav = Grav::instance();
if ($matches) {
if ($matches[1]) {
if (null === $page) {
throw new RuntimeException('Page not available for this self@ reference');
switch ($matches[0]) {
case 'self':
if (null === $object) {
throw new RuntimeException(sprintf('Page not available for self@ reference: %s', $path));
}
} elseif ($matches[2]) {
// page@
$parts = explode(':', $path);
$route = $parts[1];
$page = $grav['page']->find($route);
} elseif ($matches[3]) {
// theme@
$parts = explode(':', $path);
$route = $parts[1];
$theme = str_replace(ROOT_DIR, '', $grav['locator']->findResource('theme://'));
return $theme . $route . $basename;
if ($matches[2] === '') {
if ($object->exists()) {
$route = '/' . $matches[1];
if ($object instanceof PageInterface) {
return trim($object->relativePagePath() . $route, '/');
}
$folder = $object->getMediaFolder();
if ($folder) {
return trim($folder . $route, '/');
}
} else {
return '';
}
}
break;
case 'page':
if ($matches[1] === '') {
$route = '/' . $matches[2];
// Exclude filename from the page lookup.
if (pathinfo($route, PATHINFO_EXTENSION)) {
$basename = '/' . basename($route);
$route = \dirname($route);
} else {
$basename = '';
}
$key = trim($route === '/' ? $grav['config']->get('system.home.alias') : $route, '/');
if ($object instanceof PageObject) {
$object = $object->getFlexDirectory()->getObject($key);
} elseif (static::isAdminPlugin()) {
/** @var Flex|null $flex */
$flex = $grav['flex'] ?? null;
$object = $flex ? $flex->getObject($key, 'pages') : null;
} else {
/** @var Pages $pages */
$pages = $grav['pages'];
$object = $pages->find($route);
}
if ($object instanceof PageInterface) {
return trim($object->relativePagePath() . $basename, '/');
}
}
break;
case 'theme':
if ($matches[1] === '') {
$route = '/' . $matches[2];
$theme = $grav['locator']->findResource('theme://', false);
if (false !== $theme) {
return trim($theme . $route, '/');
}
}
break;
}
throw new RuntimeException(sprintf('Token path not found: %s', $path));
}
/**
* Returns [token, route, path] from '@token/route:/path'. Route and path are optional. If pattern does not match, return null.
*
* @param string $path
* @return string[]|null
*/
private static function resolveTokenPath(string $path): ?array
{
if (strpos($path, '@') !== false) {
$regex = '/^(@\w+|\w+@|@\w+@)([^:]*)(.*)$/u';
if (preg_match($regex, $path, $matches)) {
return [
trim($matches[1], '@'),
trim($matches[2], '/'),
trim($matches[3], ':/')
];
}
} else {
return $path . $basename;
}
if (!$page) {
throw new RuntimeException('Page route not found: ' . $path);
}
$path = str_replace($matches[0], rtrim($page->relativePagePath(), '/'), $path);
return $path . $basename;
return null;
}
/**
+3 -2
View File
@@ -154,8 +154,6 @@ class CleanCommand extends Command
'vendor/itsgoingd/clockwork/.gitattributes',
'vendor/itsgoingd/clockwork/CHANGELOG.md',
'vendor/itsgoingd/clockwork/composer.json',
'vendor/kodus/psr7-server/composer.json',
'vendor/kodus/psr7-server/CHANGELOG.md',
'vendor/league/climate/composer.json',
'vendor/league/climate/CHANGELOG.md',
'vendor/league/climate/CONTRIBUTING.md',
@@ -197,6 +195,9 @@ class CleanCommand extends Command
'vendor/nyholm/psr7/phpstan.neon.dist',
'vendor/nyholm/psr7/CHANGELOG.md',
'vendor/nyholm/psr7/psalm.xml',
'vendor/nyholm/psr7-server/.github',
'vendor/nyholm/psr7-server/composer.json',
'vendor/nyholm/psr7-server/CHANGELOG.md',
'vendor/phive/twig-extensions-deferred/.gitignore',
'vendor/phive/twig-extensions-deferred/.travis.yml',
'vendor/phive/twig-extensions-deferred/composer.json',
@@ -14,11 +14,13 @@ namespace Grav\Framework\Controller\Traits;
use Grav\Common\Config\Config;
use Grav\Common\Debugger;
use Grav\Common\Grav;
use Grav\Common\Utils;
use Grav\Framework\Psr7\Response;
use Grav\Framework\RequestHandler\Exception\RequestException;
use Grav\Framework\Route\Route;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Throwable;
use function get_class;
use function in_array;
@@ -76,6 +78,55 @@ trait ControllerResponseTrait
return new Response($code, $headers, json_encode($content));
}
/**
* @param string $filename
* @param string|resource|StreamInterface $resource
* @param array|null $headers
* @param array|null $options
* @return ResponseInterface
*/
protected function createDownloadResponse(string $filename, $resource, array $headers = null, array $options = null): ResponseInterface
{
// Required for IE, otherwise Content-Disposition may be ignored
if (ini_get('zlib.output_compression')) {
@ini_set('zlib.output_compression', 'Off');
}
$headers = $headers ?? [];
$options = $options ?? ['force_download' => true];
$file_parts = pathinfo($filename);
if (!isset($headers['Content-Type'])) {
$mimetype = Utils::getMimeByExtension($file_parts['extension']);
$headers['Content-Type'] = $mimetype;
}
// TODO: add multipart download support.
//$headers['Accept-Ranges'] = 'bytes';
if (!empty($options['force_download'])) {
$headers['Content-Disposition'] = 'attachment; filename="' . $file_parts['basename'] . '"';
}
if (!isset($headers['Content-Length'])) {
$realpath = realpath($filename);
if ($realpath) {
$headers['Content-Length'] = filesize($realpath);
}
}
$headers += [
'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
'Last-Modified' => gmdate('D, d M Y H:i:s') . ' GMT',
'Cache-Control' => 'no-store, no-cache, must-revalidate',
'Pragma' => 'no-cache'
];
return new Response(200, $headers, $resource);
}
/**
* @param string $url
* @param int|null $code
+1 -1
View File
@@ -380,7 +380,7 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
// Handle primary key alias.
$keyField = $this->getFlexDirectory()->getStorage()->getKeyField();
if (isset($orderings[$keyField])) {
if ($keyField !== 'key' && $keyField !== 'storage_key' && isset($orderings[$keyField])) {
$orderings['key'] = $orderings[$keyField];
unset($orderings[$keyField]);
}
@@ -885,6 +885,14 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
];
}
/**
* Clone object.
*/
public function __clone()
{
// Allows future compatibility as parent::__clone() works.
}
protected function markAsCopy(): void
{
$meta = $this->getMetaData();
@@ -16,7 +16,6 @@ use Grav\Common\Grav;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Page\Traits\PageFormTrait;
use Grav\Common\User\Interfaces\UserCollectionInterface;
use Grav\Framework\File\Formatter\YamlFormatter;
use Grav\Framework\Flex\FlexObject;
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
use Grav\Framework\Flex\Interfaces\FlexTranslateInterface;
@@ -50,6 +49,20 @@ class FlexPageObject extends FlexObject implements PageInterface, FlexTranslateI
/** @var array|null */
protected $_reorder;
/** @var FlexPageObject|null */
protected $_original;
/**
* Clone page.
*/
public function __clone()
{
parent::__clone();
if (isset($this->header)) {
$this->header = clone($this->header);
}
}
/**
* @return array
@@ -242,6 +255,32 @@ class FlexPageObject extends FlexObject implements PageInterface, FlexTranslateI
return parent::save();
}
/**
* Gets the Page Unmodified (original) version of the page.
*
* Assumes that object has been cloned before modifying it.
*
* @return FlexPageObject|null The original version of the page.
*/
public function getOriginal()
{
return $this->_original;
}
/**
* Store the Page Unmodified (original) version of the page.
*
* Can be called multiple times, only the first call matters.
*
* @return void
*/
public function storeOriginal(): void
{
if (null === $this->_original) {
$this->_original = clone $this;
}
}
/**
* Get display order for the associated media.
*
@@ -398,23 +437,6 @@ class FlexPageObject extends FlexObject implements PageInterface, FlexTranslateI
unset($elements['content']);
}
// TODO: Remove: RAW frontmatter support has been moved to Flex-Objects v1.0.2 controller.
if (isset($elements['frontmatter'])) {
$formatter = new YamlFormatter();
try {
// Replace the whole header except for media order, which is used in admin.
$media_order = $elements['media_order'] ?? null;
$elements['header'] = $formatter->decode($elements['frontmatter']);
if ($media_order) {
$elements['header']['media_order'] = $media_order;
}
} catch (RuntimeException $e) {
throw new RuntimeException('Badly formatted markdown');
}
unset($elements['frontmatter']);
}
if (!$extended) {
$folder = !empty($elements['folder']) ? trim($elements['folder']) : '';
@@ -27,6 +27,8 @@ trait PageAuthorsTrait
{
/** @var array<int,UserInterface> */
private $_authors;
/** @var array|null */
private $_permissionsCache;
/**
* Returns true if object has the named author.
@@ -70,15 +72,19 @@ trait PageAuthorsTrait
*/
public function getPermissions(bool $inherit = false)
{
$permissions = [];
if ($inherit && $this->getNestedProperty('header.permissions.inherit', true)) {
$parent = $this->parent();
if ($parent && method_exists($parent, 'getPermissions')) {
$permissions = $parent->getPermissions($inherit);
if (null === $this->_permissionsCache) {
$permissions = [];
if ($inherit && $this->getNestedProperty('header.permissions.inherit', true)) {
$parent = $this->parent();
if ($parent && method_exists($parent, 'getPermissions')) {
$permissions = $parent->getPermissions($inherit);
}
}
$this->_permissionsCache = $this->loadPermissions($permissions);
}
return $this->loadPermissions($permissions);
return $this->_permissionsCache;
}
/**
@@ -277,6 +277,8 @@ trait PageLegacyTrait
throw new RuntimeException('Failed: Cannot set page parent to a child of current page');
}
$this->storeOriginal();
// TODO:
throw new RuntimeException(__METHOD__ . '(): Not Implemented');
}
@@ -292,6 +294,8 @@ trait PageLegacyTrait
*/
public function copy(PageInterface $parent = null)
{
$this->storeOriginal();
$filesystem = Filesystem::getInstance(false);
$parentStorageKey = ltrim($filesystem->dirname("/{$this->getMasterKey()}"), '/');
@@ -715,8 +719,9 @@ trait PageLegacyTrait
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
$folder = $locator->isStream($folder) ? $locator->getResource($folder) : GRAV_ROOT . "/{$folder}";
return $locator->findResource($folder, true, true) . '/' . ($this->isPage() ? $this->name() : 'default.md');
return $folder . '/' . ($this->isPage() ? $this->name() : 'default.md');
}
/**
@@ -733,8 +738,9 @@ trait PageLegacyTrait
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
$folder = $locator->isStream($folder) ? $locator->getResource($folder, false) : $folder;
return $locator->findResource($folder, false, true) . '/' . ($this->isPage() ? $this->name() : 'default.md');
return $folder . '/' . ($this->isPage() ? $this->name() : 'default.md');
}
/**
@@ -1085,18 +1091,6 @@ trait PageLegacyTrait
return $this->exists() || is_dir($this->getStorageFolder() ?? '');
}
/**
* Gets the Page Unmodified (original) version of the page.
*
* Assumes that object has been cloned before modifying it.
*
* @return PageInterface|null The original version of the page.
*/
public function getOriginal()
{
return $this->getFlexDirectory()->getObject($this->getKey());
}
/**
* Gets the action.
*
@@ -18,6 +18,7 @@ use Grav\Common\Uri;
use Grav\Framework\Filesystem\Filesystem;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use RuntimeException;
use function dirname;
use function is_string;
/**
@@ -32,6 +33,8 @@ trait PageRoutableTrait
private $_route;
/** @var string|null */
private $_path;
/** @var PageInterface|null */
private $_parentCache;
/**
* Returns the page extension, got from the page `url_extension` config and falls back to the
@@ -317,7 +320,7 @@ trait PageRoutableTrait
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
$path = $locator->findResource($folder, false);
$path = $locator->isStream($folder) ? $locator->findResource($folder, false) : $folder;
return is_string($path) ? $path : null;
}
@@ -350,7 +353,7 @@ trait PageRoutableTrait
if ($folder) {
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
$folder = $locator($folder);
$folder = $locator->isStream($folder) ? $locator->getResource($folder) : GRAV_ROOT . "/{$folder}";
}
return $this->_path = is_string($folder) ? $folder : null;
@@ -413,26 +416,29 @@ trait PageRoutableTrait
throw new RuntimeException(__METHOD__ . '(PageInterface): Not Implemented');
}
if ($this->root()) {
return null;
if ($this->_parentCache || $this->root()) {
return $this->_parentCache;
}
// Use filesystem as \dirname() does not work in Windows because of '/foo' becomes '\'.
$filesystem = Filesystem::getInstance(false);
$directory = $this->getFlexDirectory();
$parentKey = ltrim($filesystem->dirname("/{$this->getKey()}"), '/');
if ($parentKey) {
if ('' !== $parentKey) {
$parent = $directory->getObject($parentKey);
$language = $this->getLanguage();
if ($language && $parent && method_exists($parent, 'getTranslation')) {
$parent = $parent->getTranslation($language) ?? $parent;
}
return $parent;
$this->_parentCache = $parent;
} else {
$index = $directory->getIndex();
$this->_parentCache = \is_callable([$index, 'getRoot']) ? $index->getRoot() : null;
}
$index = $directory->getIndex();
return method_exists($index, 'getRoot') ? $index->getRoot() : null;
return $this->_parentCache;
}
/**
@@ -493,22 +499,22 @@ trait PageRoutableTrait
public function activeChild(): bool
{
$grav = Grav::instance();
/** @var Uri $uri */
$uri = $grav['uri'];
/** @var Pages $pages */
$pages = $grav['pages'];
$uri_path = rtrim(urldecode($uri->path()), '/');
$routes = $pages->routes();
if (isset($routes[$uri_path])) {
/** @var PageInterface $child_page|null */
$child_page = $pages->find($uri->route())->parent();
if (null !== $child_page) {
while (!$child_page->root()) {
if ($this->path() === $child_page->path()) {
return true;
}
/** @var PageInterface $child_page|null */
$child_page = $child_page->parent();
$page = $pages->find($uri->route());
/** @var PageInterface|null $child_page */
$child_page = $page ? $page->parent() : null;
while ($child_page && !$child_page->root()) {
if ($this->path() === $child_page->path()) {
return true;
}
$child_page = $child_page->parent();
}
}
@@ -186,10 +186,10 @@ abstract class AbstractFilesystemStorage implements FlexStorageInterface
$locator = Grav::instance()['locator'];
if (!$locator->isStream($path)) {
return $path;
return GRAV_ROOT . "/{$path}";
}
return (string)($locator->findResource($path) ?: $locator->findResource($path, true, true));
return $locator->getResource($path);
}
/**
@@ -83,6 +83,8 @@ class FileStorage extends FolderStorage
$path = $this->getPathFromKey($src);
$file = $this->getFile($path);
$file->delete();
$file->free();
unset($file);
return true;
}
@@ -377,12 +377,14 @@ class FolderStorage extends AbstractFilesystemStorage
$file = $this->getFile($path);
try {
$data = (array)$file->content();
$file->free();
if (isset($data[0])) {
throw new RuntimeException('Broken object file');
}
} catch (RuntimeException $e) {
$data = ['__ERROR' => $e->getMessage()];
} finally {
$file->free();
unset($file);
}
$data['__META'] = $this->getObjectMeta($key);
@@ -426,13 +428,17 @@ class FolderStorage extends AbstractFilesystemStorage
$file->save($row);
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
if ($locator->isStream($path)) {
$locator->clearCache();
}
} catch (RuntimeException $e) {
throw new RuntimeException(sprintf('Flex saveFile(%s): %s', $path ?? $key, $e->getMessage()));
} finally {
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
$locator->clearCache();
if (isset($file)) {
$file->free();
unset($file);
}
}
$row['__META'] = $this->getObjectMeta($key, true);
@@ -452,14 +458,14 @@ class FolderStorage extends AbstractFilesystemStorage
if ($file->exists()) {
$file->delete();
}
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
if ($locator->isStream($filename)) {
$locator->clearCache($filename);
}
} catch (RuntimeException $e) {
throw new RuntimeException(sprintf('Flex deleteFile(%s): %s', $filename, $e->getMessage()));
} finally {
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
$locator->clearCache();
$file->free();
}
return $data;
@@ -474,14 +480,12 @@ class FolderStorage extends AbstractFilesystemStorage
{
try {
Folder::copy($this->resolvePath($src), $this->resolvePath($dst));
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
if ($locator->isStream($src) || $locator->isStream($dst)) {
$locator->clearCache();
}
} catch (RuntimeException $e) {
throw new RuntimeException(sprintf('Flex copyFolder(%s, %s): %s', $src, $dst, $e->getMessage()));
} finally {
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
$locator->clearCache();
}
return true;
@@ -496,14 +500,12 @@ class FolderStorage extends AbstractFilesystemStorage
{
try {
Folder::move($this->resolvePath($src), $this->resolvePath($dst));
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
if ($locator->isStream($src) || $locator->isStream($dst)) {
$locator->clearCache();
}
} catch (RuntimeException $e) {
throw new RuntimeException(sprintf('Flex moveFolder(%s, %s): %s', $src, $dst, $e->getMessage()));
} finally {
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
$locator->clearCache();
}
return true;
@@ -517,17 +519,13 @@ class FolderStorage extends AbstractFilesystemStorage
protected function deleteFolder(string $path, bool $include_target = false): bool
{
try {
$success = Folder::delete($this->resolvePath($path), $include_target);
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
if ($locator->isStream($path)) {
$locator->clearCache();
}
return $success;
return Folder::delete($this->resolvePath($path), $include_target);
} catch (RuntimeException $e) {
throw new RuntimeException(sprintf('Flex deleteFolder(%s): %s', $path, $e->getMessage()));
} finally {
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
$locator->clearCache();
}
}
@@ -669,7 +667,14 @@ class FolderStorage extends AbstractFilesystemStorage
/** @var string $pattern */
$pattern = !empty($options['pattern']) ? $options['pattern'] : $this->dataPattern;
$this->dataFolder = $options['folder'];
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
$folder = $options['folder'];
if ($locator->isStream($folder)) {
$folder = $locator->getResource($folder, false);
}
$this->dataFolder = $folder;
$this->dataFile = $options['file'] ?? 'item';
$this->dataExt = $extension;
if (mb_strpos($pattern, '{FILE}') === false && mb_strpos($pattern, '{EXT}') === false) {
@@ -414,9 +414,13 @@ class SimpleStorage extends AbstractFilesystemStorage
}
$file->save($content);
$this->modified = (int)$file->modified(); // cast false to 0
$file->free();
} catch (RuntimeException $e) {
throw new RuntimeException(sprintf('Flex save(): %s', $e->getMessage()));
} finally {
if (isset($file)) {
$file->free();
unset($file);
}
}
}
@@ -453,6 +457,10 @@ class SimpleStorage extends AbstractFilesystemStorage
$data = new Data($content);
$content = $data->get($this->prefix);
}
$file->free();
unset($file);
$this->data = $content;
$list = [];
@@ -14,8 +14,10 @@ use Grav\Common\Grav;
use Grav\Common\Media\Interfaces\MediaCollectionInterface;
use Grav\Common\Media\Interfaces\MediaUploadInterface;
use Grav\Common\Media\Traits\MediaTrait;
use Grav\Common\Page\Media;
use Grav\Common\Page\Medium\Medium;
use Grav\Common\Page\Medium\MediumFactory;
use Grav\Common\Utils;
use Grav\Framework\Cache\CacheInterface;
use Grav\Framework\Filesystem\Filesystem;
use Grav\Framework\Flex\FlexDirectory;
@@ -23,6 +25,7 @@ use Grav\Framework\Form\FormFlashFile;
use Psr\Http\Message\UploadedFileInterface;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use RuntimeException;
use function array_key_exists;
use function in_array;
use function is_array;
use function is_callable;
@@ -75,11 +78,40 @@ trait FlexMediaTrait
return $media;
}
/**
* @param string $field
* @return MediaCollectionInterface|null
*/
public function getMediaField(string $field): ?MediaCollectionInterface
{
// Field specific media.
$settings = $this->getFieldSettings($field);
if (!empty($settings['media_field'])) {
$var = 'destination';
} elseif (!empty($settings['media_picker_field'])) {
$var = 'folder';
}
if (empty($var)) {
// Not a media field.
$media = null;
} elseif ($settings['self']) {
// Uses main media.
$media = $this->getMedia();
} else {
// Uses custom media.
$media = new Media($settings[$var]);
$this->addUpdatedMedia($media);
}
return $media;
}
/**
* @param string $field
* @return array|null
*/
protected function getFieldSettings(string $field): ?array
public function getFieldSettings(string $field): ?array
{
if ($field === '') {
return null;
@@ -88,14 +120,32 @@ trait FlexMediaTrait
// Load settings for the field.
$schema = $this->getBlueprint()->schema();
$settings = $field && is_object($schema) ? (array)$schema->getProperty($field) : null;
if (!isset($settings) || !is_array($settings)) {
return null;
}
if (isset($settings['type']) && (in_array($settings['type'], ['avatar', 'file', 'pagemedia']) || !empty($settings['destination']))) {
// Set destination folder.
$type = $settings['type'] ?? '';
// Media field.
if (!empty($settings['media_field']) || array_key_exists('destination', $settings) || in_array($type, ['avatar', 'file', 'pagemedia'], true)) {
$settings['media_field'] = true;
if (empty($settings['destination']) || in_array($settings['destination'], ['@self', 'self@', '@self@'], true)) {
$settings['destination'] = $this->getMediaFolder();
$var = 'destination';
}
// Media picker field.
if (!empty($settings['media_picker_field']) || in_array($type, ['filepicker', 'pagemediaselect'], true)) {
$settings['media_picker_field'] = true;
$var = 'folder';
}
// Set media folder for media fields.
if (isset($var)) {
$folder = $settings[$var] ?? '';
if (in_array(rtrim($folder, '/'), ['', '@self', 'self@', '@self@'], true)) {
$settings[$var] = $this->getMediaFolder();
$settings['self'] = true;
} else {
$settings[$var] = Utils::getPathFromToken($folder, $this);
$settings['self'] = false;
}
}
@@ -115,7 +165,6 @@ trait FlexMediaTrait
return $settings + ['accept' => '*', 'limit' => 1000, 'self' => true];
}
protected function getMediaFields(): array
{
// Load settings for the field.
@@ -206,12 +255,13 @@ trait FlexMediaTrait
*/
public function uploadMediaFile(UploadedFileInterface $uploadedFile, string $filename = null, string $field = null): void
{
$media = $this->getMedia();
$settings = $this->getMediaFieldSettings($field ?? '');
$media = $field ? $this->getMediaField($field) : $this->getMedia();
if (!$media instanceof MediaUploadInterface) {
throw new RuntimeException("Media for {$this->getFlexDirectory()->getFlexType()} doesn't support file uploads.");
}
$settings = $this->getMediaFieldSettings($field ?? '');
$filename = $media->checkUploadedFile($uploadedFile, $filename, $settings);
$media->copyUploadedFile($uploadedFile, $filename, $settings);
$this->clearMediaCache();
@@ -322,13 +372,20 @@ trait FlexMediaTrait
foreach ($this->getUpdatedMedia() as $filename => $upload) {
if (is_array($upload)) {
// Uses new format with [UploadedFileInterface, array].
$upload = $upload[0];
$settings = $upload[1];
if ($settings['destination'] === $media->getPath()) {
$upload = $upload[0];
} else {
$upload = false;
}
}
if ($upload) {
$medium = MediumFactory::fromUploadedFile($upload);
if (false !== $upload) {
$medium = $upload ? MediumFactory::fromUploadedFile($upload) : null;
$updated = true;
if ($medium) {
$updated = true;
$media->add($filename, $medium);
} else {
$media->hide($filename);
}
}
}
@@ -356,7 +413,6 @@ trait FlexMediaTrait
return;
}
// Upload/delete altered files.
/**
* @var string $filename
@@ -1,87 +0,0 @@
form: flex-pages
unique_id: 73f35c84f67d9518064f6783910db89a
url: 'http://localhost:8000/admin/pages/gouvernance/conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration'
user:
username: admin
email: ouidade@figureslibres.io
timestamps:
created: 1614952271
updated: 1614952271
data:
header:
title: 'Membres du conseil d''administration'
media_order: null
body_classes: null
order_by: null
order_manual: null
published: null
date: null
publish_date: null
unpublish_date: null
metadata: null
taxonomy: null
dateformat: null
menu: null
slug: null
redirect: null
process: null
twig_first: null
never_cache_twig: null
child_type: null
routable: null
cache_enable: null
visible: null
debugger: null
template: null
append_url_extension: null
routes:
default: null
canonical: null
aliases: null
admin:
children_display_order: null
login:
visibility_requires_access: null
access: null
permissions:
inherit: null
authors: null
groups: null
content: "# Jean-Baptiste Butlen\r\nSous-directeur Aménagement\r\ndurable, Direction Générale de\r\nlAménagement, du Logement\r\net de la Nature, Ministère de la\r\nTransition écologique, Ministère\r\nde la Cohésion des territoires et\r\ndes Relations avec les\r\nCollectivités territoriales\r\n"
folder: membres-du-conseil-dadministration
route: /gouvernance/conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration
name: default
ordering: false
order: null
blueprint: null
lang: null
xss_check: null
value: null
_post_entries_save: null
files: { }
object:
type: pages
key: gouvernance/conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration
storage_key: 03.gouvernance/01.conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration
timestamp: 1614952229
serialized:
__META:
key: gouvernance/conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration
storage_key: 03.gouvernance/01.conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration
template: default
storage_timestamp: 1614952229
markdown:
'': { default: 1614952229 }
checksum: 9a001ef28e8a20154a0f4f09a46ddebf
storage_key: 03.gouvernance/01.conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration
parent_key: 03.gouvernance/01.conseil-dadministration/presidente-du-conseil-dadministration
order: false
folder: membres-du-conseil-dadministration
template: default
lang: ''
header:
title: 'Membres du conseil d''administration'
root: false
markdown: "# Jean-Baptiste Butlen\nSous-directeur Aménagement\ndurable, Direction Générale de\nlAménagement, du Logement\net de la Nature, Ministère de la\nTransition écologique, Ministère\nde la Cohésion des territoires et\ndes Relations avec les\nCollectivités territoriales\n"
slug: membres-du-conseil-dadministration
name: default.md
@@ -1,29 +0,0 @@
form: flex-pages
unique_id: ae2c7e0ffb4b4b1c4654412e6429a17c
url: '/pages/pr/:add'
user:
username: admin
email: ouidade@figureslibres.io
timestamps:
created: 1614944374
updated: 1614944374
data: null
files: { }
object:
type: pages
key: pr
storage_key: ''
timestamp: 0
serialized:
__META: { }
storage_key: ''
parent_key: ''
order: '05.'
folder: pr
template: blog
lang: ''
root: false
route: /
name: blog
header:
title: Pr
@@ -1,50 +0,0 @@
form: flex-pages-raw
unique_id: b24e06058e6bf2c3e455378b84824a00
url: 'http://localhost:8000/admin/pages/gouvernance-2'
user:
username: admin
email: ouidade@figureslibres.io
timestamps:
created: 1614944089
updated: 1614944198
data:
frontmatter: "---\r\ntitle: Gouvernance2\r\nmenu: GOUVERNANCE 2\r\nonpage_menu: true\r\nbody_classes: \"modular header-image fullwidth\"\r\n\r\ncontent:\r\n items: '@self.modular'\r\n order:\r\n by: default\r\n dir: asc\r\n custom:\r\n---"
content: null
ordering: true
folder: gouvernance-2
route: null
name: modular
order: null
blueprint: null
xss_check: null
header:
media_order: null
files: { }
object:
type: pages
key: gouvernance-2
storage_key: 04.gouvernance-2
timestamp: 1614943947
serialized:
__META:
key: gouvernance-2
storage_key: 04.gouvernance-2
template: modular
storage_timestamp: 1614943947
markdown:
'': { modular: 1614943947 }
checksum: 430b1700b40c2bea498e6dc4ba633605
storage_key: 04.gouvernance-2
parent_key: ''
order: '04.'
folder: gouvernance-2
template: modular
lang: ''
header:
title: Gouvernance-2
content:
items: '@self.modular'
root: false
markdown: ''
slug: gouvernance-2
name: modular.md
@@ -1,53 +0,0 @@
form: flex-pages-raw
unique_id: cdb3ae30b3dab66b186228ae772dd1a0
url: 'http://localhost:8000/admin/pages/programmes'
user:
username: admin
email: ouidade@figureslibres.io
timestamps:
created: 1614876264
updated: 1614876264
data:
frontmatter: "title: Gouvernance\r\ncontent:\r\n items: '@self.modular'\r\n"
content: null
ordering: true
folder: gouvernance
route: null
name: modular
order: 'home,gouvernance,gouvernance'
blueprint: null
xss_check: null
header:
media_order: null
files: { }
object:
type: pages
key: programmes
storage_key: 03.programmes
timestamp: 1614875485
serialized:
__META:
key: programmes
storage_key: 03.programmes
template: modular
storage_timestamp: 1614875485
markdown:
'': { modular: 1614875485 }
children:
_european: false
_popsu: false
checksum: 17d79b5a489014a479adac578c6eb693
storage_key: 03.programmes
parent_key: ''
order: '03.'
folder: programmes
template: modular
lang: ''
header:
title: Gouvernance
content:
items: '@self.modular'
root: false
markdown: ''
slug: programmes
name: modular.md
@@ -1,31 +0,0 @@
form: flex-pages
unique_id: e75346bd00d0b9954ac33c8fde35d73f
url: '/pages/gouvernance/conseil-dadministration/_president/:add'
user:
username: admin
email: ouidade@figureslibres.io
timestamps:
created: 1614874025
updated: 1614874025
data: null
files: { }
object:
type: pages
key: gouvernance/conseil-dadministration/_president
storage_key: ''
timestamp: 0
serialized:
__META: { }
storage_key: ''
parent_key: 03.gouvernance/01.conseil-dadministration
order: false
folder: _president
template: features
lang: ''
root: false
route: /gouvernance/conseil-dadministration
name: modular/features
modular: '1'
header:
title: president
body_classes: modular
@@ -1,84 +0,0 @@
form: flex-pages-raw
unique_id: a44b13d8025f9fb13b03184c68bd181f
url: 'http://localhost:8000/admin/pages/id%C3%A9e%20page%20simple'
user:
username: admin
email: ouidade@figureslibres.io
timestamps:
created: 1615307485
updated: 1615307507
data:
header:
title: null
media_order: null
body_classes: null
visible: false
order_by: null
order_manual: null
published: null
date: null
publish_date: null
unpublish_date: null
metadata: null
taxonomy: null
dateformat: null
menu: null
slug: null
redirect: null
process: null
twig_first: null
never_cache_twig: null
child_type: null
routable: null
cache_enable: null
debugger: null
template: null
append_url_extension: null
routes:
default: null
canonical: null
aliases: null
admin:
children_display_order: null
login:
visibility_requires_access: null
access: null
permissions:
inherit: null
authors: null
groups: null
content: null
folder: 'idée page simple'
route: null
name: default
ordering: true
order: null
blueprint: null
lang: null
xss_check: null
value: null
_post_entries_save: null
files: { }
object:
type: pages
key: 'idée page simple'
storage_key: '02.idée page simple'
timestamp: 1615307353
serialized:
__META:
key: 'idée page simple'
storage_key: '02.idée page simple'
template: null
storage_timestamp: 1615307353
checksum: 8fd86ee78271bf8fc34c0683a71a03f6
storage_key: '02.idée page simple'
parent_key: ''
order: '02.'
folder: 'idée page simple'
template: default
lang: ''
header: { }
root: false
markdown: ''
slug: 'idée page simple'
name: default.md
@@ -1,29 +0,0 @@
form: flex-pages
unique_id: e2b1fd25908ccd5d1621269a6a54fa1b
url: '/pages/gouvernanca/:add'
user:
username: admin
email: ouidade@figureslibres.io
timestamps:
created: 1615305090
updated: 1615305090
data: null
files: { }
object:
type: pages
key: gouvernanca
storage_key: ''
timestamp: 0
serialized:
__META: { }
storage_key: ''
parent_key: ''
order: '02.'
folder: gouvernanca
template: default
lang: ''
root: false
route: /
name: default
header:
title: Gouvernanca
@@ -1,31 +0,0 @@
form: flex-pages
unique_id: f8b847bb606447afa42e342e90a112bf
url: '/pages/programmes/_european/:add'
user:
username: admin
email: ouidade@figureslibres.io
timestamps:
created: 1615304429
updated: 1615304429
data: null
files: { }
object:
type: pages
key: programmes/_european
storage_key: ''
timestamp: 0
serialized:
__META: { }
storage_key: ''
parent_key: 02.programmes
order: false
folder: _european
template: features
lang: ''
root: false
route: /programmes
name: modular/features
modular: '1'
header:
title: European
body_classes: modular
+1 -1
View File
@@ -40,5 +40,5 @@ form:
type: markdown
label: Biographie
.portrait:
type: file
type: filepicker
label: Portrait
+14 -11
View File
@@ -19,22 +19,25 @@ form:
header.template:
default: modular/programmes
'@data-options': '\Grav\Common\Page\Pages::modularTypes'
features:
programmes:
type: tab
title: Programmes
fields:
header.features:
name: features
header.programmes:
name: programmes
type: list
label: Programmes
fields:
.icon:
.nom_du_programme:
type: text
label: Icon
.header:
type: text
label: Header
.text:
type: text
label: Text
label: Nom du programme
.texte_de_presentation:
type: markdown
label: Texte de présentation du programme
validate:
type: textarea
.logo:
name: logo_du_programme
type: filepicker
label: Logo
@@ -0,0 +1,48 @@
title: Rapport d'activitées
'@extends': default
form:
fields:
tabs:
fields:
advanced:
fields:
columns:
fields:
column1:
fields:
name:
default: modular/rapport_dactivitees
'@data-options': '\Grav\Common\Page\Pages::modularTypes'
overrides:
fields:
header.template:
default: modular/rapport_dactivitees
'@data-options': '\Grav\Common\Page\Pages::modularTypes'
rapports:
type: tab
title: Rapports d'activitées
fields:
header.rapports:
name: rapports
type: list
label: Rapports d'activitées
fields:
.titre_du_rapport:
type: text
label: Titre du rapport
.texte_de_presentation:
type: markdown
label: Texte de présentation du rapport
validate:
type: textarea
.couverture:
name: couv_du_rapport
type: filepicker
label: Image de couverture
.pdf:
type: filepicker
label: pdf à télécharger
accept:
- .pdf
+3 -3
View File
@@ -1,8 +1,8 @@
title: 'GIP EPAU'
default_lang: en
default_lang: fr
author:
name: 'Joe Bloggs'
email: joe@example.com
name: 'Ouidade Soussi Chiadmi'
email: ouidade@figureslibres.io
taxonomies:
- category
- tag
+11 -12
View File
@@ -1,6 +1,5 @@
absolute_urls: false
timezone: null
default_locale: null
param_sep: ':'
wrapped_site: false
reverse_proxy_setup: false
@@ -25,7 +24,6 @@ languages:
session_store_active: false
http_accept_language: false
override_locale: false
content_fallback: { }
pages_fallback_only: false
home:
alias: /home
@@ -45,17 +43,17 @@ pages:
publish_dates: true
process:
markdown: true
twig: false
twig: true
twig_first: false
never_cache_twig: false
never_cache_twig: true
events:
page: true
twig: true
markdown:
extra: false
auto_line_breaks: false
auto_url_links: false
escape_markup: false
extra: true
auto_line_breaks: true
auto_url_links: true
escape_markup: true
special_chars:
'>': gt
'<': lt
@@ -79,9 +77,9 @@ pages:
last_modified: false
etag: true
vary_accept_encoding: false
redirect_default_route: false
redirect_default_code: '302'
redirect_trailing_slash: true
redirect_trailing_slash: 1
redirect_default_route: 0
ignore_files:
- .DS_Store
ignore_folders:
@@ -98,7 +96,7 @@ pages:
cache:
enabled: true
check:
method: file
method: hash
driver: auto
prefix: g
purge_at: '0 4 * * *'
@@ -141,6 +139,7 @@ assets:
js_pipeline_before_excludes: true
js_minify: true
enable_asset_timestamp: false
enable_asset_sri: false
collections:
jquery: 'system://assets/jquery/jquery-2.x.min.js'
errors:
@@ -163,7 +162,7 @@ images:
cache_perms: '0755'
debug: false
auto_fix_orientation: true
seofriendly: false
seofriendly: true
defaults:
loading: auto
media:
+2 -2
View File
@@ -5,9 +5,9 @@ visible: true
debugger: true
---
# GIP EPAU
# EPAU
## GROUPEMENT D'INTÉRÊT PUBLIC L'EUROPE DES PROJETS ARCHITECTURAUX ET URBAINS
## L'EUROPE DES PROJETS ARCHITECTURAUX ET URBAINS
Organisme de recherche et dexpérimentation opérant des programmes nationaux sous tutelles des Ministères en charge de larchitecture et de lurbanisme, la Cité de larchitecture et du patrimoine et lAssociation Europan France.
Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

@@ -1,44 +0,0 @@
---
title: Programmes
body_classes: modular
features:
-
icon: null
header: POPSU
text: "Plateforme dobservation des projets et stratégies urbaine\_: Lieu de convergence des milieux de la recherche et de ceux qui font et gouvernent les villes, la Plateforme dobservation des projets et stratégies urbaines **POPSU** croise les savoirs scientifiques et lexpertise opérationnelle pour mieux comprendre les enjeux et les évolutions associés aux villes et aux territoires. _Elle capitalise, à des fins daction, les connaissances établies sur les _métropoles et en assure la diffusion auprès de publics divers : professionnels, académiques, grand public... Lien vers le site\_: [popsu](http://www.popsu.archi.fr)"
logo:
POPSU2018_LOGO_moinsde6cm_sscartouche.png:
name: POPSU2018_LOGO_moinsde6cm_sscartouche.png
type: image/png
size: 22288
path: POPSU2018_LOGO_moinsde6cm_sscartouche.png
-
icon: ;)
header: Europan
text: 'Europan est un concours didées darchitecture et durbanisme se déroulant tous les deux ans simultanément dans une vingtaine de pays européens, sur un thème et un règlement communs. Dans chaque pays des sites sont proposés par des collectivités territoriales et leurs partenaires. Ce concours est suivi de réalisation in-situ pour les équipes sélectionnées. Europan facilite le dialogue sur les modes de faire la ville à toutes les échelles. https://www.europanfrance.org/'
logo:
'Europan France.jpg':
name: 'Europan France.jpg'
type: image/jpeg
size: 41080
path: 'Europan France.jpg'
-
icon: null
header: 'Forum des Solutions'
text: 'Prolongement physique des programmes Action Cœur de Ville et Petites villes de demain, le Forum des solutions est une série de rendez-vous mensuels et thématiques conçues pour les villes du programme, mais qui sadresse également à toutes les collectivités qui souhaitent placer linnovation au cœur des stratégies de revitalisation urbaine. Chaque rendez-vous permet la présentation par leurs auteurs de projets réalisés répondant aux problématiques rencontrées par ces villes. Il est ouvert à tous les acteurs de laménagement du territoire. http://www.urbanisme-puca.gouv.fr/forums-des-solutions-en-videos-a1879.html'
logo:
forum_solution.png:
name: forum_solution.png
type: image/png
size: 135423
path: forum_solution.png
-
icon: null
header: Coubertin
text: 'Le programme de recherche-action Coubertin construit le récit, au fil de leau, de la conception des ouvrages et des opérations daménagement des Jeux Olympiques et Paralympiques de Paris 2024. À travers une observation embarquée au sein de la SOLIDEO, l’équipe de chercheurs analyse la production architecturale et urbaine et sa capacité à transformer les pratiques daménagement.'
logo: { }
visible: true
debugger: true
---
# Programmes
Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

@@ -0,0 +1,28 @@
---
title: Programmes
body_classes: 'modular-row programmes'
programmes:
-
nom_du_programme: 'Plateforme dobservation des projets et stratégies urbaine'
texte_de_presentation: "Lieu de convergence des milieux de la recherche et de ceux qui font et gouvernent les villes, la Plateforme dobservation des projets et stratégies urbaines **POPSU** croise les savoirs scientifiques et lexpertise opérationnelle pour mieux comprendre les enjeux et les évolutions associés aux villes et aux territoires. _Elle capitalise, à des fins daction, les connaissances établies sur les _métropoles et en assure la diffusion auprès de publics divers : professionnels, académiques, grand public... Lien vers le site\_: [popsu](http://www.popsu.archi.fr)"
logo: popsu.png
-
nom_du_programme: Europan
texte_de_presentation: 'Europan est un concours didées darchitecture et durbanisme se déroulant tous les deux ans simultanément dans une vingtaine de pays européens, sur un thème et un règlement communs. Dans chaque pays des sites sont proposés par des collectivités territoriales et leurs partenaires. Ce concours est suivi de réalisation in-situ pour les équipes sélectionnées. Europan facilite le dialogue sur les modes de faire la ville à toutes les échelles. https://www.europanfrance.org/'
logo: europan_france.jpg
-
nom_du_programme: 'Forum des Solutions'
texte_de_presentation: 'Prolongement physique des programmes Action Cœur de Ville et Petites villes de demain, le Forum des solutions est une série de rendez-vous mensuels et thématiques conçues pour les villes du programme, mais qui sadresse également à toutes les collectivités qui souhaitent placer linnovation au cœur des stratégies de revitalisation urbaine. Chaque rendez-vous permet la présentation par leurs auteurs de projets réalisés répondant aux problématiques rencontrées par ces villes. Il est ouvert à tous les acteurs de laménagement du territoire. http://www.urbanisme-puca.gouv.fr/forums-des-solutions-en-videos-a1879.html'
logo: forum_solution.png
-
nom_du_programme: Coubertin
texte_de_presentation: 'Le programme de recherche-action Coubertin construit le récit, au fil de leau, de la conception des ouvrages et des opérations daménagement des Jeux Olympiques et Paralympiques de Paris 2024. À travers une observation embarquée au sein de la SOLIDEO, l’équipe de chercheurs analyse la production architecturale et urbaine et sa capacité à transformer les pratiques daménagement.'
logo: logo_coubertin.png
visible: true
debugger: true
media_order: '14360_default_big.jpg,10361_web_01.jpg,hyperliens_marseille.PNG,popsu.png,forum_solution.png,europan_france.jpg,logo_coubertin.png'
process:
markdown: true
twig: false
---
Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

@@ -0,0 +1,39 @@
---
title: Ressources
body_classes: modular
media_order: 'rapport_activite_V1.pdf,rapport_activite_V1.png,rapport_activite_V1.pdf'
visible: true
debugger: true
rapports:
-
titre_du_rapport: 'rapport d''activité 2020'
texte_de_presentation: "Courte explicationVita estillis semper in fuga uxoresque mercenariae\r\n infugauxoresque mercenariae conductae ad tempus expacto atque, ut conductae ad tempus ex pacto atque, ut sit species matrimonii, dotis nomine futura coniunx hastam.\r\n"
couverture: rapport_activite_V1.png
pdf: rapport_activite_V1.pdf
-
titre_du_rapport: 'rapport 3'
texte_de_presentation: "Courte explicationVita estillis semper in fuga uxoresque mercenariae\r\n infugauxoresque mercenariae conductae ad tempus expacto atque, ut conductae ad tempus ex pacto atque, ut sit species matrimonii, dotis nomine futura coniunx hastam.\r\n"
couverture: rapport_activite_V1.png
pdf: rapport_activite_V1.pdf
-
titre_du_rapport: 'exemple 3'
texte_de_presentation: "Courte explicationVita estillis semper in fuga uxoresque mercenariae\r\n infugauxoresque mercenariae conductae ad tempus expacto atque, ut conductae ad tempus ex pacto atque, ut sit species matrimonii, dotis nomine futura coniunx hastam.\r\n"
couverture: rapport_activite_V1.png
pdf: rapport_activite_V1.pdf
-
titre_du_rapport: 'exemple 4'
texte_de_presentation: "Courte explicationVita estillis semper in fuga uxoresque mercenariae\r\n infugauxoresque mercenariae conductae ad tempus expacto atque, ut conductae ad tempus ex pacto atque, ut sit species matrimonii, dotis nomine futura coniunx hastam.\r\n"
couverture: rapport_activite_V1.png
pdf: rapport_activite_V1.pdf
-
titre_du_rapport: 'exempl 5'
texte_de_presentation: "Courte explicationVita estillis semper in fuga uxoresque mercenariae\r\n infugauxoresque mercenariae conductae ad tempus expacto atque, ut conductae ad tempus ex pacto atque, ut sit species matrimonii, dotis nomine futura coniunx hastam.\r\n"
couverture: rapport_activite_V1.png
pdf: rapport_activite_V1.pdf
template: modular/rapport_dactivitees
process:
markdown: true
twig: false
---
### Ressources
Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

@@ -1,13 +0,0 @@
---
title: 'Rapports d''activités'
body_classes: modular
media_order: images.jpeg
visible: true
debugger: true
---
###  Rapports dactivités de lEurope des projets architecturaux et urbains 
[Lien pour télécharger]()
![]images.jpeg(http://)+ images couv
@@ -0,0 +1,19 @@
---
title: Présidence
visible: true
body_classes: 'modular-row personnes'
personnes:
-
nom: 'Hélène Peskine'
fonction: 'Présidente du Conseil dadministration'
biographie: 'Secrétaire permanente du Plan Urbanisme Construction Architecture, Ministère de la Transition écologique, Ministère de la Cohésion des territoires et des Relations avec les Collectivités territoriales'
portrait: null
admin: { }
process:
markdown: true
twig: true
debugger: true
template: modular/personnes
---
### Présidence
@@ -0,0 +1,16 @@
---
title: 'Membres du conseil d''administration'
visible: true
body_classes: 'modular-row personnes'
personnes:
-
nom: 'Jean-Baptiste Butlen'
fonction: 'Membre du Conseil dadministration'
biographie: 'Sous-directeur Aménagement durable, Direction Générale de lAménagement, du Logement et de la Nature, Ministère de la Transition écologique, Ministère de la Cohésion des territoires et des Relations avec les Collectivités territoriales'
portrait: photo_butlen.jpeg
debugger: true
template: modular/personnes
media_order: photo_butlen.jpeg
---
### Membres du conseil d'administration
@@ -0,0 +1,20 @@
---
title: 'Conseil d''dadministration'
menu: 'Conseil d''dadministration'
visible: true
onpage_menu: true
body_classes: 'modular fullwidth title-center title-h1h2'
content:
items: '@self.modular'
order:
by: default
dir: asc
custom:
- _presidence
- _membres-du-conseil-dadministration
admin:
children_display_order: collection
debugger: true
---
## Conseil d'administration
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

@@ -1,35 +1,18 @@
---
title: Gouvernance
title: 'Équipe EPAU'
content:
items: '@self.modular'
visible: true
body_classes: 'modular personnes'
debugger: true
template: modular/personnes
body_classes: 'modular-row personnes'
personnes:
-
nom: 'Hélène Peskine'
fonction: 'Présidente du Conseil dadministration'
biographie: 'Secrétaire permanente du Plan Urbanisme Construction Architecture, Ministère de la Transition écologique, Ministère de la Cohésion des territoires et des Relations avec les Collectivités territoriales'
portrait: { }
-
nom: 'Jean-Baptiste Butlen'
fonction: 'Membre du Conseil dadministration'
biographie: 'Sous-directeur Aménagement durable, Direction Générale de lAménagement, du Logement et de la Nature, Ministère de la Transition écologique, Ministère de la Cohésion des territoires et des Relations avec les Collectivités territoriales'
portrait:
photo_butlen.jpeg:
name: photo_butlen.jpeg
type: image/jpeg
size: 37489
path: photo_butlen.jpeg
-
nom: 'Alain Maugard'
fonction: 'Président de lAssociation Europan France'
biographie: "Né le 23 avril 1943 à Nérac (Lot-et-Garonne), Alain Maugard est un ancien élève de l’École polytechnique et Ingénieur général des Ponts et Chaussées. Il débute sa carrière au ministère de l’Équipement au service des Affaires économiques et internationales et dans les services urbanisme construction des Directions Départementales. Chef du service de la politique technique à la direction de la Construction et secrétaire permanent du Plan Construction, de 1978 à 1981, il devient successivement directeur adjoint de cabinet des ministres de lUrbanisme et du Logement Roger Quilliot et Paul Quilès puis directeur de la Construction au ministère de l’Équipement, du Logement, des Transports et de la Mer. En 1990, il est nommé directeur général de l’Établissement public daménagement de la Défense (epad), jusquen 1993 où il prend la présidence du cstb. Il quitte ces fonctions en 2008 pour rejoindre le Conseil général de lenvironnement et du développement durable où il assure la présidence de la section « risques, sécurité, sûreté ». En septembre 2009, il accède à la présidence de Qualibat. \r\nEn outre, Alain Maugard est membre du conseil dadministration de lAdeme. Il a également piloté le Comité opérationnel (comop) du chantier n°1 « Bâtiments neufs publics et privés » du Grenelle de lEnvironnement. \r\n\r\nBibliographie\_:\r\n- Regards sur le bâtiment — Le futur en construction, éditions Le Moniteur, 2006\r\n - Regard sur la ville durable, Alain Maugard et Jean-Pierre Cuisinier, CSTB, mars 2010\r\n - Le BEPOS pour tous (livre électronique), http://outils.xpair.com/livre/bepos-pourtous/7.htm (25 juin 2015) \r\n"
portrait: { }
published: true
debugger: true
template: modular/personnes
portrait: 'Alain Maugard_TROUVE.jpg'
media_order: 'Alain Maugard_TROUVE.jpg'
---
# Gouvernance
#### Conseil d'administration
#### Equipe EPAU
## Équipe EPAU
@@ -0,0 +1,20 @@
---
title: Gouvernance
menu: Gouvernance
visible: true
onpage_menu: true
body_classes: 'modular fullwidth title-center title-h1h2'
content:
items: '@self.modular'
order:
by: default
dir: asc
custom:
- _conseil-dadministration
- _equipe-epau
admin:
children_display_order: collection
debugger: true
---
# Gouvernance
@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" id="svg2" width="464.19281" height="67.749725" viewBox="0 0 464.19281 67.749726" sodipodi:docname="EPAU_logo_EPAU_vecto-seul.svg" inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
<metadata id="metadata8"></metadata>
<defs id="defs6"></defs>
<g inkscape:groupmode="layer" inkscape:label="Image" id="g10" transform="translate(-1.9140933,-3.5854007)">
<g id="g2659" transform="translate(-0.24588468,-1.3522927)">
<g aria-label="GROUPEMENT D'INTÉRÊT PUBLIC" transform="matrix(1.3333333,0,0,1.3333333,-336.16364,140.52749)" id="text2223-1-7" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0.600073px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.300037">
<path d="m 369.98683,-93.541351 c -0.741,0.49875 -1.63875,0.78375 -2.4795,0.78375 -2.18025,0 -3.91875,-1.72425 -3.91875,-3.876 0,-2.1375 1.72425,-3.847499 3.9045,-3.847499 1.083,0 2.166,0.4275 2.964,1.168499 l 0.78375,-0.997499 c -0.969,-0.855 -2.35125,-1.38225 -3.74775,-1.38225 -2.97825,0 -5.28675,2.222999 -5.28675,5.058749 0,2.85 2.29425,5.1015 5.2155,5.1015 1.35375,0 2.77875,-0.52725 3.77625,-1.311 v -3.66225 h -1.21125 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2476"></path>
<path d="m 382.40014,-91.631851 -2.32275,-3.37725 c 1.41075,-0.4845 2.18025,-1.61025 2.18025,-3.23475 0,-2.137499 -1.43925,-3.362999 -3.9615,-3.362999 h -3.9045 v 9.974999 h 1.368 v -3.1065 h 2.5365 c 0.1995,0 0.38475,-0.01425 0.55575,-0.0285 l 1.98075,3.135 z m -6.6405,-4.34625 v -4.388999 h 2.5365 c 1.69575,0 2.6505,0.726749 2.6505,2.165999 0,1.482 -0.95475,2.223 -2.6505,2.223 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2478"></path>
<path d="m 389.65496,-101.69235 c -2.9355,0 -5.244,2.208749 -5.244,5.058749 0,2.85 2.3085,5.1015 5.244,5.1015 2.9355,0 5.244,-2.2515 5.244,-5.1015 0,-2.83575 -2.3085,-5.058749 -5.244,-5.058749 z m 0.0143,1.2255 c 2.109,0 3.83325,1.695749 3.83325,3.833249 0,2.1375 -1.72425,3.86175 -3.83325,3.86175 -2.109,0 -3.876,-1.72425 -3.876,-3.86175 0,-2.1375 1.75275,-3.833249 3.876,-3.833249 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2480"></path>
<path d="m 398.61976,-95.707351 v -5.899499 h -1.368 v 5.899499 c 0,2.60775 1.596,4.17525 4.23225,4.17525 2.622,0 4.20375,-1.5675 4.20375,-4.17525 v -5.899499 h -1.368 v 5.899499 c 0,1.8525 -1.06875,2.9355 -2.83575,2.9355 -1.767,0 -2.86425,-1.083 -2.86425,-2.9355 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2482"></path>
<path d="m 412.77157,-101.60685 h -3.8475 v 9.974999 h 1.368 v -3.1065 h 2.4795 c 2.4795,0 3.9045,-1.2825 3.9045,-3.5055 0,-2.137499 -1.425,-3.362999 -3.9045,-3.362999 z m -0.057,5.628749 h -2.4225 v -4.374749 l 2.4225,-0.0142 c 1.6815,0 2.6505,0.726749 2.6505,2.165999 0,1.482 -0.969,2.223 -2.6505,2.223 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2484"></path>
<path d="m 419.08588,-101.60685 v 9.974999 h 7.0965 v -1.23975 h -5.7285 v -3.17775 h 4.97325 v -1.23975 h -4.97325 v -3.077999 h 5.5575 v -1.23975 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2486"></path>
<path d="m 428.99121,-101.60685 v 9.974999 h 1.26825 v -7.96575 l 3.57675,6.91125 h 0.84075 l 3.54825,-6.91125 0.0143,7.96575 h 1.2825 v -9.974999 h -1.63875 l -3.6195,7.010999 -3.648,-7.010999 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2488"></path>
<path d="m 442.97201,-101.60685 v 9.974999 h 7.0965 v -1.23975 h -5.7285 v -3.17775 h 4.97325 v -1.23975 h -4.97325 v -3.077999 h 5.5575 v -1.23975 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2490"></path>
<path d="m 459.97384,-101.60685 v 7.737749 l -5.71425,-7.737749 h -1.38225 v 9.974999 h 1.368 v -7.7235 l 5.7,7.7235 h 1.38225 v -9.974999 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2492"></path>
<path d="m 463.50939,-101.60685 v 1.254 h 3.20625 v 8.720999 h 1.368 v -8.720999 h 3.2205 v -1.254 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2494"></path>
<path d="m 367.15108,-83.305179 h -4.06125 v 9.975 h 4.0185 c 2.964,0 5.187,-2.1375 5.187,-4.9875 0,-2.86425 -2.20875,-4.9875 -5.14425,-4.9875 z m 0.0285,8.73525 h -2.72175 v -7.4955 h 2.66475 c 2.12325,0 3.77625,1.596 3.77625,3.762 0,2.15175 -1.6245,3.7335 -3.71925,3.7335 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2496"></path>
<path d="m 374.27763,-83.305179 v 3.32025 h 1.04025 v -3.32025 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2498"></path>
<path d="m 378.19794,-83.305179 v 9.975 h 1.368 v -9.975 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2500"></path>
<path d="m 390.11251,-83.305179 v 7.73775 l -5.71425,-7.73775 h -1.38225 v 9.975 h 1.368 v -7.7235 l 5.7,7.7235 h 1.38225 v -9.975 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2502"></path>
<path d="m 393.64806,-83.305179 v 1.254 h 3.20625 v 8.721 h 1.368 v -8.721 h 3.2205 v -1.254 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2504"></path>
<path d="m 407.97088,-86.183679 -1.52475,1.8525 1.12575,0.1425 1.767,-1.3965 z m -4.3605,2.8785 v 9.975 h 7.0965 v -1.23975 h -5.7285 v -3.17775 h 4.97325 v -1.23975 h -4.97325 v -3.078 h 5.5575 v -1.23975 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2506"></path>
<path d="m 421.5242,-73.330179 -2.32275,-3.37725 c 1.41075,-0.4845 2.18025,-1.61025 2.18025,-3.23475 0,-2.1375 -1.43925,-3.363 -3.9615,-3.363 h -3.9045 v 9.975 h 1.368 v -3.1065 h 2.5365 c 0.1995,0 0.38475,-0.01425 0.55575,-0.0285 l 1.98075,3.135 z m -6.6405,-4.34625 v -4.389 h 2.5365 c 1.69575,0 2.6505,0.72675 2.6505,2.166 0,1.482 -0.95475,2.223 -2.6505,2.223 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2508"></path>
<path d="m 427.99527,-85.214679 0.86925,0.95475 h 1.32525 l -1.49625,-1.89525 h -1.3965 l -1.49625,1.89525 h 1.32525 z m -2.20875,10.64475 v -3.17775 h 4.97325 v -1.23975 h -4.97325 v -3.078 h 5.5575 v -1.23975 h -6.9255 v 9.975 h 7.0965 v -1.23975 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2510"></path>
<path d="m 433.04133,-83.305179 v 1.254 h 3.20625 v 8.721 h 1.368 v -8.721 h 3.2205 v -1.254 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2512"></path>
<path d="m 451.18472,-83.305179 h -3.8475 v 9.975 h 1.368 v -3.1065 h 2.4795 c 2.4795,0 3.9045,-1.2825 3.9045,-3.5055 0,-2.1375 -1.425,-3.363 -3.9045,-3.363 z m -0.057,5.62875 h -2.4225 v -4.37475 l 2.4225,-0.01425 c 1.6815,0 2.6505,0.72675 2.6505,2.166 0,1.482 -0.969,2.223 -2.6505,2.223 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2514"></path>
<path d="m 458.65328,-77.405679 v -5.8995 h -1.368 v 5.8995 c 0,2.60775 1.596,4.17525 4.23225,4.17525 2.622,0 4.20375,-1.5675 4.20375,-4.17525 v -5.8995 h -1.368 v 5.8995 c 0,1.8525 -1.06875,2.9355 -2.83575,2.9355 -1.767,0 -2.86425,-1.083 -2.86425,-2.9355 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2516"></path>
<path d="m 473.21834,-83.305179 h -4.26075 v 9.975 h 4.332 c 2.26575,0 3.6195,-1.01175 3.6195,-2.72175 0,-1.35375 -0.8265,-2.3085 -2.223,-2.52225 1.12575,-0.2565 1.80975,-1.09725 1.80975,-2.23725 0,-1.55325 -1.23975,-2.49375 -3.2775,-2.49375 z m -0.0713,4.23225 h -2.8215 v -2.97825 h 2.8215 c 1.2255,-0.01425 1.938,0.513 1.938,1.46775 0,0.969 -0.7125,1.5105 -1.938,1.5105 z m 0,4.48875 h -2.8215 v -3.249 h 2.8215 c 1.482,0 2.3655,0.5985 2.3655,1.61025 0,1.0545 -0.8835,1.653 -2.3655,1.63875 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2518"></path>
<path d="m 479.70366,-83.305179 v 9.975 h 5.7285 v -1.23975 h -4.3605 v -8.73525 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2520"></path>
<path d="m 487.77071,-83.305179 v 9.975 h 1.368 v -9.975 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2522"></path>
<path d="m 499.81352,-80.911179 0.81225,-0.98325 c -0.95475,-0.9405 -2.32275,-1.49625 -3.705,-1.49625 -2.92125,0 -5.2155,2.223 -5.2155,5.05875 0,2.85 2.26575,5.1015 5.1585,5.1015 1.3965,0 2.77875,-0.61275 3.77625,-1.58175 l -0.8265,-0.89775 c -0.7695,0.741 -1.824,1.197 -2.8785,1.197 -2.1375,0 -3.8475,-1.71 -3.8475,-3.83325 0,-2.1375 1.71,-3.83325 3.8475,-3.83325 1.06875,0 2.12325,0.4845 2.8785,1.26825 z" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:Montserrat;fill:#000000;fill-opacity:1;stroke-width:0.300037" id="path2524"></path>
</g>
<g aria-label="L'Europe des Projets Architecturaux et Urbains" transform="matrix(1.3333333,0,0,1.3333333,-336.16364,140.52749)" id="text2253-8-1" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;line-height:0;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0.15px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.997733">
<path d="m 254.7911,-63.733707 v 9.98925 h 6.84 v -2.223 h -4.23225 v -7.76625 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2527"></path>
<path d="m 262.84984,-63.733707 v 3.9615 h 1.9095 v -3.9615 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2529"></path>
<path d="m 266.73334,-63.733707 v 9.98925 h 8.02275 v -2.0805 h -5.415 v -1.881 l 4.7595,-0.01425 v -2.06625 h -4.7595 v -1.86675 h 5.2725 v -2.0805 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2531"></path>
<path d="m 281.48958,-61.453707 v 3.80475 c 0,1.01175 -0.5415,1.72425 -1.43925,1.7385 -0.75525,0 -1.23975,-0.52725 -1.23975,-1.3965 v -4.14675 h -2.5365 v 4.8735 c 0,1.7955 1.083,2.94975 2.75025,2.94975 1.09725,-0.01425 1.938,-0.47025 2.46525,-1.368 v 1.254 h 2.5365 v -7.70925 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2533"></path>
<path d="m 288.65057,-60.171207 v -1.2825 h -2.5365 v 7.70925 h 2.5365 v -3.933 c 0.12825,-1.06875 1.06875,-1.69575 2.4795,-1.55325 v -2.32275 c -1.083,0 -1.95225,0.49875 -2.4795,1.38225 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2535"></path>
<path d="m 295.9683,-61.539207 c -2.5365,0 -4.20375,1.5675 -4.20375,3.933 0,2.37975 1.66725,3.94725 4.20375,3.94725 2.5365,0 4.218,-1.5675 4.218,-3.94725 0,-2.3655 -1.6815,-3.933 -4.218,-3.933 z m 0,2.052 c 0.9975,0 1.66725,0.7695 1.66725,1.9095 0,1.15425 -0.66975,1.92375 -1.66725,1.92375 -0.98325,0 -1.653,-0.7695 -1.653,-1.92375 0,-1.14 0.66975,-1.9095 1.653,-1.9095 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2537"></path>
<path d="m 306.50653,-61.539207 c -0.95475,0 -1.72425,0.38475 -2.26575,1.083 v -0.9975 h -2.5365 v 10.47375 h 2.5365 v -3.762 c 0.5415,0.69825 1.3395,1.083 2.32275,1.083 2.1375,0 3.534,-1.55325 3.534,-3.9045 0,-2.394 -1.43925,-3.97575 -3.591,-3.97575 z m -0.627,5.82825 c -0.969,0 -1.63875,-0.7695 -1.63875,-1.9095 0,-1.14 0.66975,-1.92375 1.63875,-1.92375 0.9975,0 1.66725,0.78375 1.66725,1.92375 0,1.14 -0.66975,1.9095 -1.66725,1.9095 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2539"></path>
<path d="m 314.95002,-61.539207 c -2.40825,0 -4.0185,1.58175 -4.0185,3.97575 0,2.35125 1.55325,3.9045 4.0755,3.9045 1.425,0 2.57925,-0.4845 3.363,-1.368 l -1.32525,-1.32525 c -0.513,0.513 -1.15425,0.78375 -1.80975,0.78375 -0.86925,0 -1.5105,-0.4845 -1.75275,-1.35375 h 5.358 c 0.171,-2.80725 -1.197,-4.617 -3.89025,-4.617 z m -1.52475,3.26325 c 0.171,-0.8835 0.7125,-1.482 1.539,-1.482 0.855,0 1.425,0.5985 1.425,1.482 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2541"></path>
<path d="m 328.85872,-64.317957 v 3.876 c -0.5415,-0.69825 -1.3395,-1.09725 -2.337,-1.09725 -2.12325,0 -3.534,1.55325 -3.534,3.9045 0,2.394 1.425,3.99 3.591,3.99 0.969,0 1.75275,-0.38475 2.28,-1.09725 v 0.9975 h 2.5365 v -10.5735 z m -1.653,8.67825 c -0.9975,0 -1.66725,-0.78375 -1.66725,-1.92375 0,-1.14 0.66975,-1.92375 1.66725,-1.92375 0.98325,0 1.653,0.7695 1.653,1.92375 0,1.14 -0.66975,1.92375 -1.653,1.92375 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2543"></path>
<path d="m 336.94595,-61.539207 c -2.40825,0 -4.0185,1.58175 -4.0185,3.97575 0,2.35125 1.55325,3.9045 4.0755,3.9045 1.425,0 2.57925,-0.4845 3.363,-1.368 l -1.32525,-1.32525 c -0.513,0.513 -1.15425,0.78375 -1.80975,0.78375 -0.86925,0 -1.5105,-0.4845 -1.75275,-1.35375 h 5.358 c 0.171,-2.80725 -1.197,-4.617 -3.89025,-4.617 z m -1.52475,3.26325 c 0.171,-0.8835 0.7125,-1.482 1.539,-1.482 0.855,0 1.425,0.5985 1.425,1.482 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2545"></path>
<path d="m 347.44143,-59.016957 0.855,-1.653 c -0.969,-0.58425 -2.09475,-0.89775 -3.20625,-0.89775 -1.80975,0 -3.1635,0.8835 -3.1635,2.49375 0,2.66475 3.97575,2.1375 3.97575,3.192 0,0.3135 -0.342,0.47025 -0.81225,0.47025 -0.855,0 -1.8525,-0.342 -2.736,-0.95475 l -0.798,1.63875 c 0.9405,0.72675 2.18025,1.09725 3.477,1.09725 1.881,0 3.26325,-0.89775 3.26325,-2.4795 0.0143,-2.679 -4.03275,-2.1945 -4.03275,-3.20625 0,-0.32775 0.29925,-0.4845 0.72675,-0.4845 0.627,0 1.49625,0.285 2.451,0.78375 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2547"></path>
<path d="m 357.51688,-63.733707 h -4.389 v 9.98925 h 2.60775 v -2.7645 h 1.78125 c 2.55075,0 4.0185,-1.368 4.0185,-3.71925 0,-2.223 -1.46775,-3.5055 -4.0185,-3.5055 z m -0.12825,5.14425 h -1.653 v -3.06375 h 1.653 c 1.0545,0 1.66725,0.52725 1.66725,1.5105 0,1.01175 -0.61275,1.55325 -1.66725,1.55325 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2549"></path>
<path d="m 365.50436,-60.171207 v -1.2825 h -2.5365 v 7.70925 h 2.5365 v -3.933 c 0.12825,-1.06875 1.06875,-1.69575 2.4795,-1.55325 v -2.32275 c -1.083,0 -1.95225,0.49875 -2.4795,1.38225 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2551"></path>
<path d="m 372.82209,-61.539207 c -2.5365,0 -4.20375,1.5675 -4.20375,3.933 0,2.37975 1.66725,3.94725 4.20375,3.94725 2.5365,0 4.218,-1.5675 4.218,-3.94725 0,-2.3655 -1.6815,-3.933 -4.218,-3.933 z m 0,2.052 c 0.9975,0 1.66725,0.7695 1.66725,1.9095 0,1.15425 -0.66975,1.92375 -1.66725,1.92375 -0.98325,0 -1.653,-0.7695 -1.653,-1.92375 0,-1.14 0.66975,-1.9095 1.653,-1.9095 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2553"></path>
<path d="m 379.74081,-65.001957 c -0.78375,0 -1.3395,0.55575 -1.3395,1.35375 0,0.78375 0.55575,1.35375 1.3395,1.35375 0.78375,0 1.3395,-0.57 1.3395,-1.35375 0,-0.798 -0.55575,-1.35375 -1.3395,-1.35375 z m -2.622,12.01275 -0.49875,1.80975 c 0.4845,0.18525 1.0545,0.29925 1.66725,0.29925 1.69575,0.01425 2.7645,-0.95475 2.7645,-2.57925 v -7.99425 h -2.5365 v 7.6095 c 0,0.64125 -0.285,0.969 -0.798,0.95475 -0.1995,0 -0.399,-0.04275 -0.5985,-0.09975 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2555"></path>
<path d="m 386.47428,-61.539207 c -2.40825,0 -4.0185,1.58175 -4.0185,3.97575 0,2.35125 1.55325,3.9045 4.0755,3.9045 1.425,0 2.57925,-0.4845 3.363,-1.368 l -1.32525,-1.32525 c -0.513,0.513 -1.15425,0.78375 -1.80975,0.78375 -0.86925,0 -1.5105,-0.4845 -1.75275,-1.35375 h 5.358 c 0.171,-2.80725 -1.197,-4.617 -3.89025,-4.617 z m -1.52475,3.26325 c 0.171,-0.8835 0.7125,-1.482 1.539,-1.482 0.855,0 1.425,0.5985 1.425,1.482 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2557"></path>
<path d="m 396.35702,-55.938957 c -0.3705,0.15675 -0.69825,0.2565 -0.95475,0.2565 -0.44175,0.01425 -0.69825,-0.24225 -0.69825,-0.81225 v -2.907 h 1.995 v -1.6815 h -1.995 v -2.1375 h -2.52225 v 2.1375 h -1.06875 v 1.6815 h 1.06875 v 3.306 c 0,1.596 1.083,2.4795 2.57925,2.46525 0.75525,0 1.52475,-0.18525 2.0805,-0.513 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2559"></path>
<path d="m 403.347,-59.016957 0.855,-1.653 c -0.969,-0.58425 -2.09475,-0.89775 -3.20625,-0.89775 -1.80975,0 -3.1635,0.8835 -3.1635,2.49375 0,2.66475 3.97575,2.1375 3.97575,3.192 0,0.3135 -0.342,0.47025 -0.81225,0.47025 -0.855,0 -1.8525,-0.342 -2.736,-0.95475 l -0.798,1.63875 c 0.9405,0.72675 2.18025,1.09725 3.477,1.09725 1.881,0 3.26325,-0.89775 3.26325,-2.4795 0.0143,-2.679 -4.03275,-2.1945 -4.03275,-3.20625 0,-0.32775 0.29925,-0.4845 0.72675,-0.4845 0.627,0 1.49625,0.285 2.451,0.78375 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2561"></path>
<path d="m 416.3722,-53.744457 h 2.77875 l -4.1895,-9.98925 h -2.679 l -4.28925,9.98925 h 2.679 l 0.69825,-1.767 h 4.31775 z m -4.218,-3.762 1.3965,-3.5625 1.368,3.5625 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2563"></path>
<path d="m 422.73518,-60.171207 v -1.2825 h -2.5365 v 7.70925 h 2.5365 v -3.933 c 0.12825,-1.06875 1.06875,-1.69575 2.4795,-1.55325 v -2.32275 c -1.083,0 -1.95225,0.49875 -2.4795,1.38225 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2565"></path>
<path d="m 431.44941,-58.646457 1.83825,-1.06875 c -0.66975,-1.15425 -1.89525,-1.824 -3.4485,-1.824 -2.394,0 -3.99,1.58175 -3.99,3.97575 0,2.35125 1.58175,3.9045 3.9615,3.9045 1.63875,0 2.89275,-0.66975 3.5055,-1.8525 l -1.86675,-1.06875 c -0.3135,0.5985 -0.84075,0.86925 -1.5105,0.86925 -0.912,0 -1.539,-0.741 -1.539,-1.86675 0,-1.1115 0.627,-1.86675 1.539,-1.86675 0.6555,0 1.1685,0.29925 1.5105,0.798 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2567"></path>
<path d="m 439.79313,-61.553457 c -1.12575,0 -2.00925,0.47025 -2.55075,1.35375 v -4.11825 h -2.5365 v 10.5735 h 2.5365 v -3.80475 c 0,-1.01175 0.57,-1.72425 1.5105,-1.7385 0.81225,0 1.311,0.5415 1.311,1.41075 v 4.1325 h 2.5365 v -4.85925 c 0,-1.80975 -1.1115,-2.94975 -2.80725,-2.94975 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2569"></path>
<path d="m 445.70011,-65.001957 c -0.78375,0 -1.3395,0.55575 -1.3395,1.35375 0,0.78375 0.55575,1.35375 1.3395,1.35375 0.78375,0 1.3395,-0.57 1.3395,-1.35375 0,-0.798 -0.55575,-1.35375 -1.3395,-1.35375 z m -1.23975,3.54825 v 7.70925 h 2.52225 v -7.70925 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2571"></path>
<path d="m 453.60212,-55.938957 c -0.3705,0.15675 -0.69825,0.2565 -0.95475,0.2565 -0.44175,0.01425 -0.69825,-0.24225 -0.69825,-0.81225 v -2.907 h 1.995 v -1.6815 h -1.995 v -2.1375 h -2.52225 v 2.1375 h -1.06875 v 1.6815 h 1.06875 v 3.306 c 0,1.596 1.083,2.4795 2.57925,2.46525 0.75525,0 1.52475,-0.18525 2.0805,-0.513 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2573"></path>
<path d="m 458.7966,-61.539207 c -2.40825,0 -4.0185,1.58175 -4.0185,3.97575 0,2.35125 1.55325,3.9045 4.0755,3.9045 1.425,0 2.57925,-0.4845 3.363,-1.368 l -1.32525,-1.32525 c -0.513,0.513 -1.15425,0.78375 -1.80975,0.78375 -0.86925,0 -1.5105,-0.4845 -1.75275,-1.35375 h 5.358 c 0.171,-2.80725 -1.197,-4.617 -3.89025,-4.617 z m -1.52475,3.26325 c 0.171,-0.8835 0.7125,-1.482 1.539,-1.482 0.855,0 1.425,0.5985 1.425,1.482 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2575"></path>
<path d="m 469.12107,-58.646457 1.83825,-1.06875 c -0.66975,-1.15425 -1.89525,-1.824 -3.4485,-1.824 -2.394,0 -3.99,1.58175 -3.99,3.97575 0,2.35125 1.58175,3.9045 3.9615,3.9045 1.63875,0 2.89275,-0.66975 3.5055,-1.8525 l -1.86675,-1.06875 c -0.3135,0.5985 -0.84075,0.86925 -1.5105,0.86925 -0.912,0 -1.539,-0.741 -1.539,-1.86675 0,-1.1115 0.627,-1.86675 1.539,-1.86675 0.6555,0 1.1685,0.29925 1.5105,0.798 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2577"></path>
<path d="m 476.8378,-55.938957 c -0.3705,0.15675 -0.69825,0.2565 -0.95475,0.2565 -0.44175,0.01425 -0.69825,-0.24225 -0.69825,-0.81225 v -2.907 h 1.995 v -1.6815 h -1.995 v -2.1375 h -2.52225 v 2.1375 h -1.06875 v 1.6815 h 1.06875 v 3.306 c 0,1.596 1.083,2.4795 2.57925,2.46525 0.75525,0 1.52475,-0.18525 2.0805,-0.513 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2579"></path>
<path d="m 483.67102,-61.453707 v 3.80475 c 0,1.01175 -0.5415,1.72425 -1.43925,1.7385 -0.75525,0 -1.23975,-0.52725 -1.23975,-1.3965 v -4.14675 h -2.5365 v 4.8735 c 0,1.7955 1.083,2.94975 2.75025,2.94975 1.09725,-0.01425 1.938,-0.47025 2.46525,-1.368 v 1.254 h 2.5365 v -7.70925 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2581"></path>
<path d="m 490.83202,-60.171207 v -1.2825 h -2.5365 v 7.70925 h 2.5365 v -3.933 c 0.12825,-1.06875 1.06875,-1.69575 2.4795,-1.55325 v -2.32275 c -1.083,0 -1.95225,0.49875 -2.4795,1.38225 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2583"></path>
<path d="m 499.80274,-61.453707 v 0.9975 c -0.5415,-0.69825 -1.35375,-1.09725 -2.337,-1.083 -2.12325,0 -3.51975,1.55325 -3.51975,3.9045 0,2.394 1.425,3.99 3.591,3.99 0.95475,0 1.7385,-0.38475 2.26575,-1.06875 v 0.969 h 2.5365 v -7.70925 z m -1.63875,5.814 c -0.9975,0 -1.66725,-0.78375 -1.66725,-1.92375 0,-1.14 0.66975,-1.92375 1.66725,-1.92375 0.912,0 1.539,0.6555 1.63875,1.66725 v 0.513 c -0.0997,0.9975 -0.72675,1.66725 -1.63875,1.66725 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:'Montserrat Alternates';-inkscape-font-specification:'Montserrat Alternates Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2585"></path>
<path d="m 509.41474,-61.453707 v 3.80475 c 0,1.01175 -0.5415,1.72425 -1.43925,1.7385 -0.75525,0 -1.23975,-0.52725 -1.23975,-1.3965 v -4.14675 h -2.5365 v 4.8735 c 0,1.7955 1.083,2.94975 2.75025,2.94975 1.09725,-0.01425 1.938,-0.47025 2.46525,-1.368 v 1.254 h 2.5365 v -7.70925 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2587"></path>
<path d="m 513.28399,-61.453707 2.451,3.762 -2.622,3.94725 h 2.793 l 1.52475,-2.35125 1.368,2.35125 h 2.92125 l -2.60775,-3.94725 2.43675,-3.762 h -2.77875 l -1.3395,2.166 -1.23975,-2.166 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2589"></path>
<path d="m 529.60093,-61.539207 c -2.40825,0 -4.0185,1.58175 -4.0185,3.97575 0,2.35125 1.55325,3.9045 4.0755,3.9045 1.425,0 2.57925,-0.4845 3.363,-1.368 l -1.32525,-1.32525 c -0.513,0.513 -1.15425,0.78375 -1.80975,0.78375 -0.86925,0 -1.5105,-0.4845 -1.75275,-1.35375 h 5.358 c 0.171,-2.80725 -1.197,-4.617 -3.89025,-4.617 z m -1.52475,3.26325 c 0.171,-0.8835 0.7125,-1.482 1.539,-1.482 0.855,0 1.425,0.5985 1.425,1.482 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2591"></path>
<path d="m 539.48367,-55.938957 c -0.3705,0.15675 -0.69825,0.2565 -0.95475,0.2565 -0.44175,0.01425 -0.69825,-0.24225 -0.69825,-0.81225 v -2.907 h 1.995 v -1.6815 h -1.995 v -2.1375 h -2.52225 v 2.1375 h -1.06875 v 1.6815 h 1.06875 v 3.306 c 0,1.596 1.083,2.4795 2.57925,2.46525 0.75525,0 1.52475,-0.18525 2.0805,-0.513 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2593"></path>
<path d="m 547.07962,-57.862707 v -5.871 h -2.60775 v 5.871 c 0,2.622 1.7955,4.3035 4.56,4.3035 2.7645,0 4.503,-1.6815 4.503,-4.3035 v -5.871 h -2.60775 v 5.871 c 0,1.29675 -0.7695,2.0805 -1.881,2.0805 -1.12575,0 -1.9665,-0.798 -1.9665,-2.0805 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2595"></path>
<path d="m 558.00259,-60.171207 v -1.2825 h -2.5365 v 7.70925 h 2.5365 v -3.933 c 0.12825,-1.06875 1.06875,-1.69575 2.4795,-1.55325 v -2.32275 c -1.083,0 -1.95225,0.49875 -2.4795,1.38225 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2597"></path>
<path d="m 566.61708,-61.539207 c -0.95475,0 -1.72425,0.38475 -2.26575,1.083 v -3.86175 h -2.5365 v 10.5735 h 2.5365 v -0.9975 c 0.5415,0.69825 1.3395,1.083 2.32275,1.083 2.1375,0 3.534,-1.55325 3.534,-3.9045 0,-2.394 -1.43925,-3.97575 -3.591,-3.97575 z m -0.627,5.82825 c -0.969,0 -1.63875,-0.7695 -1.63875,-1.9095 0,-1.14 0.66975,-1.92375 1.63875,-1.92375 0.9975,0 1.66725,0.78375 1.66725,1.92375 0,1.14 -0.66975,1.9095 -1.66725,1.9095 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2599"></path>
<path d="m 576.89881,-61.453707 v 0.9975 c -0.5415,-0.69825 -1.35375,-1.09725 -2.337,-1.083 -2.12325,0 -3.51975,1.55325 -3.51975,3.9045 0,2.394 1.425,3.99 3.591,3.99 0.95475,0 1.7385,-0.38475 2.26575,-1.06875 v 0.969 h 2.5365 v -7.70925 z m -1.63875,5.814 c -0.9975,0 -1.66725,-0.78375 -1.66725,-1.92375 0,-1.14 0.66975,-1.92375 1.66725,-1.92375 0.912,0 1.539,0.6555 1.63875,1.66725 v 0.513 c -0.0997,0.9975 -0.72675,1.66725 -1.63875,1.66725 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:'Montserrat Alternates';-inkscape-font-specification:'Montserrat Alternates Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2601"></path>
<path d="m 582.76306,-65.001957 c -0.78375,0 -1.3395,0.55575 -1.3395,1.35375 0,0.78375 0.55575,1.35375 1.3395,1.35375 0.78375,0 1.3395,-0.57 1.3395,-1.35375 0,-0.798 -0.55575,-1.35375 -1.3395,-1.35375 z m -1.23975,3.54825 v 7.70925 h 2.52225 v -7.70925 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2603"></path>
<path d="m 591.22082,-61.553457 c -1.12575,0 -2.00925,0.47025 -2.55075,1.35375 v -1.254 h -2.5365 v 7.70925 h 2.5365 v -4.0755 c 0.0997,-0.86925 0.6555,-1.4535 1.5105,-1.46775 0.798,0 1.311,0.5415 1.311,1.41075 v 4.1325 h 2.52225 v -4.85925 c 0,-1.80975 -1.1115,-2.94975 -2.793,-2.94975 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2605"></path>
<path d="m 601.0323,-59.016957 0.855,-1.653 c -0.969,-0.58425 -2.09475,-0.89775 -3.20625,-0.89775 -1.80975,0 -3.1635,0.8835 -3.1635,2.49375 0,2.66475 3.97575,2.1375 3.97575,3.192 0,0.3135 -0.342,0.47025 -0.81225,0.47025 -0.855,0 -1.8525,-0.342 -2.736,-0.95475 l -0.798,1.63875 c 0.9405,0.72675 2.18025,1.09725 3.477,1.09725 1.881,0 3.26325,-0.89775 3.26325,-2.4795 0.0143,-2.679 -4.03275,-2.1945 -4.03275,-3.20625 0,-0.32775 0.29925,-0.4845 0.72675,-0.4845 0.627,0 1.49625,0.285 2.451,0.78375 z" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:14.25px;font-family:Montserrat;-inkscape-font-specification:'Montserrat Bold';fill:#000000;fill-opacity:1;stroke-width:0.997733" id="path2607"></path>
</g>
<path d="m 27.111978,43.20747 h -24.952 V 5.0568 h 24.952 v 8.85467 H 12.186645 v 5.569334 H 25.441311 V 28.33679 H 12.186645 v 6.01468 h 14.925333 z" style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333" id="path298-1-6"></path>
<path d="m 51.505177,18.032937 c 0,-1.3 -0.454667,-2.31068 -1.364,-3.03468 -0.910667,-0.723986 -2.164,-1.086653 -3.76,-1.086653 h -3.118666 v 8.242653 h 3.118666 c 1.596,0 2.849333,-0.362653 3.76,-1.086653 0.909333,-0.724 1.364,-1.734667 1.364,-3.034667 M 43.262511,43.207603 H 33.515844 V 5.056933 h 12.865333 c 4.604,0 8.28,1.169334 11.028,3.506671 2.746666,2.34 4.122666,5.497333 4.122666,9.469333 0,3.97332 -1.376,7.12932 -4.122666,9.469333 -2.748,2.33732 -6.424,3.506667 -11.028,3.506667 h -3.118666 z" style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333" id="path302-2-8"></path>
<path d="m 79.632776,16.918404 -4.4,11.751986 h 8.744 z M 99.850109,43.207723 H 89.435443 l -2.228,-5.959986 H 72.00211 l -2.228,5.959986 H 59.916777 L 74.95411,5.057067 h 9.858666 z" style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333" id="path306-3-9"></path>
<path d="m 118.06251,43.764803 c -4.864,0 -8.72532,-1.448 -11.584,-4.345333 -2.86,-2.896 -4.28932,-6.83068 -4.28932,-11.80668 V 5.0568 h 10.02532 v 22.445337 c 0,2.228 0.52,3.972 1.55868,5.234653 1.03865,1.26268 2.47065,1.893347 4.28932,1.893347 1.81868,0 3.24933,-0.630667 4.28933,-1.893347 1.03867,-1.262653 1.55867,-3.006653 1.55867,-5.234653 V 5.0568 h 10.02533 v 22.55599 c 0,4.976 -1.42933,8.91068 -4.28933,11.80668 -2.85867,2.897333 -6.72132,4.345333 -11.584,4.345333" style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333" id="path310-57-6"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

+2 -2
View File
@@ -11,9 +11,9 @@ content:
custom:
- _accueil
- _programmes
- _rapports-dactivites
- _rapports-dactivitees
- _gouvernance
- _contact
media_order: 'jeux-olypiques-paris-2024-village-athle-lot-e2.jpg,Logotype_GIP_EPAU.svg.png'
media_order: 'EPAU_logo_EPAU_vecto-seul.svg,Republique-francaise-logo.svg,popsu.png'
---

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

@@ -1,19 +0,0 @@
---
title: 'Plateforme dobservation des projets et stratégies urbaine'
media_order: POPSU2018_LOGO_moinsde6cm_sscartouche.png
content:
items: '@self.modular'
visible: false
---
Lieu de convergence des milieux de la recherche
et de ceux qui font et gouvernent les villes, la
Plateforme dobservation des projets et
stratégies urbaines POPSU croise les savoirs
scientifiques et lexpertise opérationnelle pour
mieux comprendre les enjeux et les évolutions
associés aux villes et aux territoires. Elle
capitalise, à des fins daction, les connaissances
établies sur les métropoles et en assure la
diffusion auprès de publics divers :
professionnels, académiques, grand public...
Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

@@ -1,18 +0,0 @@
---
title: European
media_order: 'Europan France.jpg'
visible: false
---
# Europan
Europan est un concours didées darchitecture
et durbanisme se déroulant tous les deux ans
simultanément dans une vingtaine de pays
européens, sur un thème et un règlement
communs. Dans chaque pays des sites sont
proposés par des collectivités territoriales et
leurs partenaires. Ce concours est suivi de
réalisation in-situ pour les équipes sélectionnées.
Europan facilite le dialogue sur les modes de
faire la ville à toutes les échelles.
@@ -1,16 +0,0 @@
---
title: Coubertin
visible: false
---
# Coubertin
Le programme de recherche-action Coubertin
construit le récit, au fil de leau, de la conception
des ouvrages et des opérations daménagement
des Jeux Olympiques et Paralympiques de Paris
2024. À travers une observation embarquée au
sein de la SOLIDEO, l’équipe de chercheurs
analyse la production architecturale et urbaine et
sa capacité à transformer les pratiques
daménagement.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

@@ -1,20 +0,0 @@
---
title: 'Forum des Solutions'
media_order: forum_solution.png
visible: false
---
# Forum des Solutions
Prolongement physique des programmes Action
Cœur de Ville et Petites villes de demain, le
Forum des solutions est une série de rendez-vous
mensuels et thématiques conçues pour les villes
du programme, mais qui sadresse également à
toutes les collectivités qui souhaitent placer
linnovation au cœur des stratégies de
revitalisation urbaine. Chaque rendez-vous
permet la présentation par leurs auteurs de
projets réalisés répondant aux problématiques
rencontrées par ces villes. Il est ouvert à tous les
acteurs de laménagement du territoire.
@@ -1,5 +0,0 @@
---
title: 'Rapports d''activités'
visible: false
---
-17
View File
@@ -1,17 +0,0 @@
---
title: Programmes
menu: Programmes
onpage_menu: true
body_classes: 'modular header-image fullwidth'
content:
items: '@self.modular'
order:
by: default
dir: asc
custom:
- _popsu
- _european
published: true
visible: false
---
@@ -1,7 +0,0 @@
---
title: 'Conseil d''administration de l''Europe des projets arcitecturaux et urbains'
content:
items: '@self.modular'
visible: false
---

Some files were not shown because too many files have changed in this diff Show More