template rapport_dactivitees avec pdf à télécharger

This commit is contained in:
2021-03-23 13:58:22 +01:00
parent 66f835e1ff
commit f8ecbbe597
39 changed files with 526 additions and 205 deletions
+21
View File
@@ -1,3 +1,24 @@
# 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 -1
View File
@@ -18,4 +18,4 @@ If you cannot update to the latest stable version available because, for example
## 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.
Generated
+18 -18
View File
@@ -381,16 +381,16 @@
},
{
"name": "donatj/phpuseragentparser",
"version": "v1.3.0",
"version": "v1.4.0",
"source": {
"type": "git",
"url": "https://github.com/donatj/PhpUserAgent.git",
"reference": "f9a521726b2ce4c5173281ceaab5a02c05b691ef"
"reference": "246c1cf0a44f07168c702203bf30d5f48f17bab0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/donatj/PhpUserAgent/zipball/f9a521726b2ce4c5173281ceaab5a02c05b691ef",
"reference": "f9a521726b2ce4c5173281ceaab5a02c05b691ef",
"url": "https://api.github.com/repos/donatj/PhpUserAgent/zipball/246c1cf0a44f07168c702203bf30d5f48f17bab0",
"reference": "246c1cf0a44f07168c702203bf30d5f48f17bab0",
"shasum": ""
},
"require": {
@@ -433,7 +433,7 @@
],
"support": {
"issues": "https://github.com/donatj/PhpUserAgent/issues",
"source": "https://github.com/donatj/PhpUserAgent/tree/v1.3.0"
"source": "https://github.com/donatj/PhpUserAgent/tree/v1.4.0"
},
"funding": [
{
@@ -445,7 +445,7 @@
"type": "github"
}
],
"time": "2021-02-18T04:30:49+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",
@@ -4929,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": {
@@ -5016,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": [
{
@@ -5028,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",
+1 -1
View File
@@ -8,7 +8,7 @@
// Some standard defines
define('GRAV', true);
define('GRAV_VERSION', '1.7.8');
define('GRAV_VERSION', '1.7.9');
define('GRAV_SCHEMA', '1.7.0_2020-11-20_1');
define('GRAV_TESTING', false);
+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;
}
/**
@@ -522,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()),
@@ -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;
@@ -321,6 +322,28 @@ class PageObject extends FlexPageObject
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|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'];
+1 -1
View File
@@ -426,7 +426,7 @@ class Grav extends Container
// Clean route for redirect
$route = preg_replace("#^\/[\\\/]+\/#", '/', $route);
if (null !== $code || $code < 300 || $code > 399) {
if ($code < 300 || $code > 399) {
$code = null;
}
@@ -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.
*
+12 -10
View File
@@ -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();
}
}
+116 -73
View File
@@ -880,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());
}
}
}
+1 -1
View File
@@ -519,7 +519,7 @@ class Uri
* Return the full uri
*
* @param bool $include_root
* @return mixed
* @return string
*/
public function uri($include_root = 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;
}
/**
@@ -420,9 +420,11 @@ trait PageRoutableTrait
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(dirname("/{$this->getKey()}"), '/');
if ($parentKey) {
$parentKey = ltrim($filesystem->dirname("/{$this->getKey()}"), '/');
if ('' !== $parentKey) {
$parent = $directory->getObject($parentKey);
$language = $this->getLanguage();
if ($language && $parent && method_exists($parent, 'getTranslation')) {
@@ -433,7 +435,7 @@ trait PageRoutableTrait
} else {
$index = $directory->getIndex();
$this->_parentCache = method_exists($index, 'getRoot') ? $index->getRoot() : null;
$this->_parentCache = \is_callable([$index, 'getRoot']) ? $index->getRoot() : null;
}
return $this->_parentCache;
@@ -497,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();
}
}
@@ -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
@@ -42,4 +42,3 @@ form:
.portrait:
type: filepicker
label: Portrait
folder: 'user/pages/01.home/04._gouvernance'
@@ -41,4 +41,3 @@ form:
name: logo_du_programme
type: filepicker
label: Logo
folder: 'user/pages/01.home/02._programmes'
@@ -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
+1 -1
View File
@@ -1,7 +1,7 @@
title: 'GIP EPAU'
default_lang: fr
author:
name: 'Ouidade Soussi'
name: 'Ouidade Soussi Chiadmi'
email: ouidade@figureslibres.io
taxonomies:
- category
+1 -1
View File
@@ -96,7 +96,7 @@ pages:
cache:
enabled: true
check:
method: file
method: hash
driver: auto
prefix: g
purge_at: '0 4 * * *'
Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

@@ -17,10 +17,10 @@ programmes:
-
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: null
logo: logo_coubertin.png
visible: true
debugger: true
media_order: 'popsu.png,forum_solution.png,europan_france.jpg'
media_order: 'popsu.png,forum_solution.png,europan_france.jpg,logo_coubertin.png'
process:
markdown: true
twig: false

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

@@ -0,0 +1,19 @@
---
title: 'Rapports d''activitées'
body_classes: modular
media_order: 'images.jpeg,190410_events2event.pdf'
visible: true
debugger: true
rapports:
-
titre_du_rapport: 'rapport d''activitées POPSU 2019'
texte_de_presentation: "#### # ozMIHEFMJBZNDKCJbnW NX;, \r\noipouepuoaiejhrglnk\r\n_loremnksjdqs _\r\n"
couverture: images.jpeg
pdf: 190410_events2event.pdf
template: modular/rapport_dactivitees
process:
markdown: true
twig: false
---
###  Rapports dactivitées
@@ -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
@@ -10,6 +10,7 @@ personnes:
portrait: photo_butlen.jpeg
debugger: true
template: modular/personnes
media_order: photo_butlen.jpeg
---
### Membres du conseil d'administration

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

@@ -12,6 +12,7 @@ personnes:
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: 'Alain Maugard_TROUVE.jpg'
media_order: 'Alain Maugard_TROUVE.jpg'
---
## Équipe EPAU
Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

@@ -15,7 +15,6 @@ content:
admin:
children_display_order: collection
debugger: true
media_order: '1612260288596.jpg,Alain Maugard_TROUVE.jpg,aurelie-cousi-nommee-aux-fonctions-de-directrice.jpg,catherine-chevillot-nouvelle-presidente-de-cite.JPG,photo_butlen.jpeg'
---
# Gouvernance
+1 -1
View File
@@ -11,7 +11,7 @@ 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'
@@ -3,12 +3,7 @@
<div class="feature-items">
{% for personne in page.header.personnes %}
<div class="feature">
{% if personne.icon %}
<i class="fa fa-fw fa-{{ personne.icon }}"></i>
<div class="feature-content icon-offset">
{% else %}
<div class="feature-content">
{% endif %}
{% if personne.nom %}
<h5>{{ personne.nom }}</h5>
{% endif %}
@@ -16,11 +11,13 @@
<h6>{{ personne.fonction }}</h6>
{% endif %}
{% if personne.biographie %}
<p>{{ personne.biographie }}</p>
<p>{{ personne.biographie|markdown }}</p>
{% endif %}
{% if personne.portrait %}
<img src="/user/pages/01.home/04._gouvernance/{{personne.portrait}}" alt="portrait de {{personne.nom}}" />
<img src="{{page.media[personne.portrait].url|e }}" alt="portrait de {{personne.nom}}" />
{% endif %}
</div>
</div>
{% endfor %}
@@ -3,17 +3,18 @@
<div class="">
{% for programme in page.header.programmes %}
<div class="">
<div class="">
{% if programme.nom_du_programme %}
<h4>{{ programme.nom_du_programme }}</h4>
{% endif %}
{% if programme.texte_de_presentation %}
<p>{{ programme.texte_de_presentation }}</p>
<p>{{ programme.texte_de_presentation|markdown }}</p>
{% endif %}
{% if programme.logo %}
<img src="/user/pages/01.home/02._programmes/{{programme.logo}} " alt="logo du programme {{programme.nom_du_programme}}" />
{{ dump(programme.logo) }}
<img src="{{page.media[programme.logo].url|e }}" alt="logo du programme {{programme.nom_du_programme}}" />
{% endif %}
</div>
@@ -0,0 +1,25 @@
<div class="modular-row {{ page.header.class}}">
{{ content|raw }}
<div class="">
{% for rapport in page.header.rapports %}
<div class="">
<div class="">
{% if rapport.titre_du_rapport %}
<h4>{{ rapport.titre_du_rapport }}</h4>
{% endif %}
{% if rapport.texte_de_presentation %}
<p>{{ rapport.texte_de_presentation|markdown }}</p>
{% endif %}
{% if rapport.couverture and rapport.pdf %}
<a href="{{page.media[rapport.pdf].url|e }}" {{rapport.titre_du_rapport}}>
<img src="{{page.media[rapport.couverture].url|e }}" alt="couverture du {{rapport.titre_du_rapport}}" />
</a>
{% endif %}
{{ dump(rapport)}}
</div>
</div>
{% endfor %}
</div>
</div>