mise en place de minio

This commit is contained in:
Arnaud Fornerot 2022-08-24 14:40:10 +02:00
parent f97bac6e5e
commit 953cee63eb
22 changed files with 938 additions and 106 deletions

12
.env
View File

@ -120,10 +120,14 @@ MERCURE_URL=https://127.0.0.1/.well-known/mercure
MERCURE_PUBLIC_URL=https://127.0.0.1/.well-known/mercure
MERCURE_JWT_SECRET="!ChangeMe!"
# Messenger
# MESSENGER_TRANSPORT_DSN=doctrine://default
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
# Minio
MINIO_URL=http://127.0.0.1:9000
MINIO_KEY=minio
MINIO_SECRET=changeme
MINIO_BUCKET=nine
MINIO_ROOT=
MINIO_PATH_STYLE=1
MINIO_SECURE=0
# Lock
LOCK_DSN="postgresql://symfony:ChangeMe@127.0.0.1:5432/app?serverVersion=13&charset=utf8"

View File

@ -7,6 +7,7 @@
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"aws/aws-sdk-php": "^3.234",
"doctrine/annotations": "^1.0",
"doctrine/doctrine-bundle": "^2.6",
"doctrine/doctrine-migrations-bundle": "^3.2",

331
composer.lock generated
View File

@ -4,8 +4,150 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "55a8fc0f19cbcfaa9fd74ecf5d8ff8d5",
"content-hash": "b10025eb97ca0ec25b18857a1f4c520f",
"packages": [
{
"name": "aws/aws-crt-php",
"version": "v1.0.2",
"source": {
"type": "git",
"url": "https://github.com/awslabs/aws-crt-php.git",
"reference": "3942776a8c99209908ee0b287746263725685732"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/3942776a8c99209908ee0b287746263725685732",
"reference": "3942776a8c99209908ee0b287746263725685732",
"shasum": ""
},
"require": {
"php": ">=5.5"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35|^5.4.3"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "AWS SDK Common Runtime Team",
"email": "aws-sdk-common-runtime@amazon.com"
}
],
"description": "AWS Common Runtime for PHP",
"homepage": "http://aws.amazon.com/sdkforphp",
"keywords": [
"amazon",
"aws",
"crt",
"sdk"
],
"support": {
"issues": "https://github.com/awslabs/aws-crt-php/issues",
"source": "https://github.com/awslabs/aws-crt-php/tree/v1.0.2"
},
"time": "2021-09-03T22:57:30+00:00"
},
{
"name": "aws/aws-sdk-php",
"version": "3.234.0",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "d2113f1e5ec9f7f19de2472f5063333b39a55280"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d2113f1e5ec9f7f19de2472f5063333b39a55280",
"reference": "d2113f1e5ec9f7f19de2472f5063333b39a55280",
"shasum": ""
},
"require": {
"aws/aws-crt-php": "^1.0.2",
"ext-json": "*",
"ext-pcre": "*",
"ext-simplexml": "*",
"guzzlehttp/guzzle": "^6.5.8 || ^7.4.5",
"guzzlehttp/promises": "^1.4.0",
"guzzlehttp/psr7": "^1.8.5 || ^2.3",
"mtdowling/jmespath.php": "^2.6",
"php": ">=5.5"
},
"require-dev": {
"andrewsville/php-token-reflection": "^1.4",
"aws/aws-php-sns-message-validator": "~1.0",
"behat/behat": "~3.0",
"composer/composer": "^1.10.22",
"doctrine/cache": "~1.4",
"ext-dom": "*",
"ext-openssl": "*",
"ext-pcntl": "*",
"ext-sockets": "*",
"nette/neon": "^2.3",
"paragonie/random_compat": ">= 2",
"phpunit/phpunit": "^4.8.35 || ^5.6.3",
"psr/cache": "^1.0",
"psr/simple-cache": "^1.0",
"sebastian/comparator": "^1.2.3"
},
"suggest": {
"aws/aws-php-sns-message-validator": "To validate incoming SNS notifications",
"doctrine/cache": "To use the DoctrineCacheAdapter",
"ext-curl": "To send requests using cURL",
"ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages",
"ext-sockets": "To use client-side monitoring"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"files": [
"src/functions.php"
],
"psr-4": {
"Aws\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Amazon Web Services",
"homepage": "http://aws.amazon.com"
}
],
"description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
"homepage": "http://aws.amazon.com/sdkforphp",
"keywords": [
"amazon",
"aws",
"cloud",
"dynamodb",
"ec2",
"glacier",
"s3",
"sdk"
],
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.234.0"
},
"time": "2022-08-22T18:20:42+00:00"
},
{
"name": "brick/math",
"version": "0.9.3",
@ -1962,6 +2104,130 @@
},
"time": "2022-01-11T08:28:06+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "7.4.5",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "1dd98b0564cb3f6bd16ce683cb755f94c10fbd82"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/1dd98b0564cb3f6bd16ce683cb755f94c10fbd82",
"reference": "1dd98b0564cb3f6bd16ce683cb755f94c10fbd82",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.5",
"guzzlehttp/psr7": "^1.9 || ^2.4",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
},
"provide": {
"psr/http-client-implementation": "1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.4.1",
"ext-curl": "*",
"php-http/client-integration-tests": "^3.0",
"phpunit/phpunit": "^8.5.5 || ^9.3.5",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {
"ext-curl": "Required for CURL handler support",
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
"psr/log": "Required for using the Log middleware"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "7.4-dev"
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Jeremy Lindblom",
"email": "jeremeamia@gmail.com",
"homepage": "https://github.com/jeremeamia"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle is a PHP HTTP client library",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"psr-18",
"psr-7",
"rest",
"web service"
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.4.5"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
"type": "tidelift"
}
],
"time": "2022-06-20T22:16:13+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "1.5.1",
@ -2701,6 +2967,67 @@
],
"time": "2022-06-09T09:09:00+00:00"
},
{
"name": "mtdowling/jmespath.php",
"version": "2.6.1",
"source": {
"type": "git",
"url": "https://github.com/jmespath/jmespath.php.git",
"reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/9b87907a81b87bc76d19a7fb2d61e61486ee9edb",
"reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb",
"shasum": ""
},
"require": {
"php": "^5.4 || ^7.0 || ^8.0",
"symfony/polyfill-mbstring": "^1.17"
},
"require-dev": {
"composer/xdebug-handler": "^1.4 || ^2.0",
"phpunit/phpunit": "^4.8.36 || ^7.5.15"
},
"bin": [
"bin/jp.php"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.6-dev"
}
},
"autoload": {
"files": [
"src/JmesPath.php"
],
"psr-4": {
"JmesPath\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Declaratively specify how to extract elements from a JSON document",
"keywords": [
"json",
"jsonpath"
],
"support": {
"issues": "https://github.com/jmespath/jmespath.php/issues",
"source": "https://github.com/jmespath/jmespath.php/tree/2.6.1"
},
"time": "2021-06-14T00:11:39+00:00"
},
{
"name": "nelmio/api-doc-bundle",
"version": "v4.9.0",
@ -12879,5 +13206,5 @@
"ext-iconv": "*"
},
"platform-dev": [],
"plugin-api-version": "2.2.0"
"plugin-api-version": "2.3.0"
}

View File

@ -18,11 +18,6 @@ app_modo_home:
controller: App\Controller\HomeController::homemodo
defaults: { access: modo }
app_ckeditor_upload:
path: /user/upload
controller: App\Controller\HomeController::upload
defaults: { access: user }
oneup_uploader:
resource: .
type: uploader
@ -160,6 +155,50 @@ app_user_crop02:
path: /user/crop02/{type}/{reportinput}
controller: App\Controller\CropController::crop02
#== Minio =======================================================================================================
#-- Access admin
app_admin_minio_image:
path: /admin/minio/image
controller: App\Controller\MinioController::image
app_admin_minio_document:
path: /admin/minio/document
controller: App\Controller\MinioController::document
#-- Access modo
app_modo_minio_image:
path: /modo/minio/image
controller: App\Controller\MinioController::image
app_modo_minio_document:
path: /modo/minio/document
controller: App\Controller\MinioController::document
#-- Access user
app_user_minio_image:
path: /user/minio/image
controller: App\Controller\MinioController::image
app_user_minio_document:
path: /user/minio/document
controller: App\Controller\MinioController::document
#-- Access public
app_minio_image:
path: /minio/image
controller: App\Controller\MinioController::image
app_minio_document:
path: /minio/document
controller: App\Controller\MinioController::document
#== Ckeditor ====================================================================================================
app_ckeditor_upload:
path: /user/upload
controller: App\Controller\MinioController::ckupload
defaults: { access: user }
#== Audit =======================================================================================================
#--Access admin
@ -168,7 +207,6 @@ app_admin_audit_renderid:
controller: App\Controller\AuditController::auditrender
defaults: { access: admin }
#--Access admin
app_admin_audit_render:
path: /admin/audit/{entityname}
controller: App\Controller\AuditController::list

View File

@ -92,6 +92,14 @@ parameters:
proxyHost: '%env(resolve:PROXY_HOST)%'
proxyPort: '%env(resolve:PROXY_PORT)%'
minioUrl: '%env(resolve:MINIO_URL)%'
minioKey: '%env(resolve:MINIO_KEY)%'
minioSecret: '%env(resolve:MINIO_SECRET)%'
minioBucket: '%env(resolve:MINIO_BUCKET)%'
minioRoot: '%env(resolve:MINIO_ROOT)%'
minioPathstyle: '%env(resolve:MINIO_PATH_STYLE)%'
minioSecure: '%env(resolve:MINIO_SECURE)%'
sondeUse: '%env(resolve:SONDE_USE)%'
sondeUrl: '%env(resolve:SONDE_URL)%'
@ -216,5 +224,9 @@ services:
App\Service\ApiService:
public: true
App\Service\MinioService:
public: true
arguments: ["%kernel.project_dir%","%minioUrl%","%minioKey%","%minioSecret%","%minioBucket%","%minioRoot%","%minioPathstyle%","%minioSecure%","%kernel.environment%"]
App\Controller\RestController:
public: true

View File

@ -0,0 +1,67 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
# include /etc/nginx/conf.d/*.conf;
upstream minio {
server minio1:9000;
server minio2:9000;
server minio3:9000;
server minio4:9000;
}
server {
listen 9000;
server_name localhost;
# To allow special characters in headers
ignore_invalid_headers off;
# Allow any size file to be uploaded.
# Set to a value such as 1000m; to restrict file size to a specific value
client_max_body_size 0;
# To disable buffering
proxy_buffering off;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 300;
# Default is HTTP/1, keepalive is only enabled in HTTP/1.1
proxy_http_version 1.1;
proxy_set_header Connection "";
chunked_transfer_encoding off;
proxy_pass http://minio;
}
}
}

View File

@ -55,8 +55,8 @@ services:
LDAP_LOG_LEVEL: "256"
LDAP_ORGANISATION: "nineskeletor"
LDAP_DOMAIN: "nine.fr"
LDAP_ADMIN_PASSWORD: "admin"
LDAP_CONFIG_PASSWORD: "config"
LDAP_ADMIN_PASSWORD: "changeme"
LDAP_CONFIG_PASSWORD: "changeme"
LDAP_READONLY_USER: "true"
LDAP_READONLY_USER_USERNAME: "readonly"
LDAP_READONLY_USER_PASSWORD: "readonly"
@ -80,7 +80,99 @@ services:
depends_on:
- openldap
minio1:
image: minio/minio:RELEASE.2021-01-16T02-19-44Z
container_name: minio1
volumes:
- data1-1:/data1
- data1-2:/data2
expose:
- "9000"
environment:
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: changeme
command: server http://minio{1...4}/data{1...2}
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
minio2:
image: minio/minio:RELEASE.2021-01-16T02-19-44Z
container_name: minio2
volumes:
- data2-1:/data1
- data2-2:/data2
expose:
- "9000"
environment:
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: changeme
command: server http://minio{1...4}/data{1...2}
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
minio3:
image: minio/minio:RELEASE.2021-01-16T02-19-44Z
container_name: minio3
volumes:
- data3-1:/data1
- data3-2:/data2
expose:
- "9000"
environment:
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: changeme
command: server http://minio{1...4}/data{1...2}
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
minio4:
image: minio/minio:RELEASE.2021-01-16T02-19-44Z
container_name: minio4
volumes:
- data4-1:/data1
- data4-2:/data2
expose:
- "9000"
environment:
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: changeme
command: server http://minio{1...4}/data{1...2}
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
nginx:
image: nginx:1.19.2-alpine
volumes:
- ./containers/minio/nginx.conf:/etc/nginx/nginx.conf:ro
ports:
- "9000:9000"
depends_on:
- minio1
- minio2
- minio3
- minio4
volumes:
db-data:
mercure_data:
mercure_config:
data1-1:
data1-2:
data2-1:
data2-2:
data3-1:
data3-2:
data4-1:
data4-2:

View File

@ -9,14 +9,17 @@ use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\HttpFoundation\Response;
use App\Service\MinioService;
class CropController extends AbstractController
{
private $appKernel;
private $minio;
public function __construct(KernelInterface $appKernel)
public function __construct(KernelInterface $appKernel, MinioService $minio)
{
$this->appKernel = $appKernel;
$this->minio = $minio;
}
// Etape 01 - Téléchargement de l'image
@ -102,6 +105,11 @@ class CropController extends AbstractController
$data = $form->getData();
$thumb_image_location = "uploads/$type/thumb_".$file;
$cropped = $this->resizeThumbnailImage($thumb_image_location, $large_image_location,$data["ws"],$data["hs"],$data["xs"],$data["ys"],$scale);
// Dépot des fichiers sur minio
$this->minio->upload($large_image_location,$large_image_location,true);
$this->minio->upload($thumb_image_location,$thumb_image_location,true);
$submited=true;
}
@ -117,32 +125,6 @@ class CropController extends AbstractController
]);
}
// Upload ckeditor
public function ckupload(Request $request) {
// Fichier temporaire uploadé
$tmpfile = $request->files->get('upload');
$extention = $tmpfile->getClientOriginalExtension();
// Répertoire de Destination
$fs = new Filesystem();
$rootdir = $this->appKernel->getProjectDir()."/public";
$fs->mkdir($rootdir."/uploads/ckeditor");
// Fichier cible
$targetName = uniqid().".".$extention;
$targetFile = $rootdir."/uploads/ckeditor/".$targetName;
$targetUrl = "/".$this->getParameter('appAlias')."/uploads/ckeditor/".$targetName;
$message = "";
move_uploaded_file($tmpfile,$targetFile);
$output["uploaded"]=1;
$output["fileName"]=$targetName;
$output["url"]=$targetUrl;
return new Response(json_encode($output));
}
// Calcul de la hauteur
protected function getHeight($image) {
$size = getimagesize($image);

View File

@ -160,10 +160,7 @@ class GroupController extends AbstractController
$userinfo="";
if($data->getOwner()) {
if(stripos($data->getOwner()->getAvatar(),"http")===0)
$userinfo.="<img src='".$data->getOwner()->getAvatar()."' class='avatar'>";
else
$userinfo.="<img src='".$this->getParameter('appAlias')."uploads/avatar/".$data->getOwner()->getAvatar()."' class='avatar'>";
$userinfo.="<img src='".$this->generateUrl('app_minio_image',["file"=>"uploads/avatar/".$data->getOwner()->getAvatar()])."' class='avatar'>";
$userinfo.="<br>".$data->getOwner()->getUsername();
}
@ -516,11 +513,7 @@ class GroupController extends AbstractController
$action.="<a style='cursor:pointer' onClick='addUsers(".$data->getId().")'><i class='fa fa-plus fa-fw'></i></a>";
// Avatar
if(stripos($data->getAvatar(),"http")===0)
$avatar="<img src='".$data->getAvatar()."' class='avatar'>";
else
$avatar="<img src='".$this->getParameter('appAlias')."uploads/avatar/".$data->getAvatar()."' class='avatar'>";
$avatar="<img src='".$this->generateUrl('app_minio_image',["file"=>"uploads/avatar/".$data->getAvatar()])."' class='avatar'>";
array_push($output["data"],array("DT_RowId"=>"user".$data->getId(),$action,$avatar,$data->getUsername(),$data->getEmail(),"",""));
}
@ -654,10 +647,7 @@ class GroupController extends AbstractController
$action.="<a style='cursor:pointer' onClick='delUsers(".$data->getId().")'><i class='fa fa-minus fa-fw'></i></a>";
// Avatar
if(stripos($data->getAvatar(),"http")===0)
$avatar="<img src='".$data->getAvatar()."' class='avatar'>";
else
$avatar="<img src='".$this->getParameter('appAlias')."uploads/avatar/".$data->getAvatar()."' class='avatar'>";
$avatar="<img src='".$this->generateUrl('app_minio_image',["file"=>"uploads/avatar/".$data->getAvatar()])."' class='avatar'>";
// Flag manager
$rolegroup="";

View File

@ -4,7 +4,7 @@ namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Filesystem\Filesystem;
class HomeController extends AbstractController
{
@ -52,30 +52,6 @@ class HomeController extends AbstractController
}
public function upload($access,Request $request): Response
{
// Fichier temporaire uploadé
$tmpfile = $request->files->get('upload');
$extention = $tmpfile->getClientOriginalExtension();
// Répertoire de Destination
$fs = new Filesystem();
$rootdir = $this->getParameter('kernel.project_dir') . '/public';
$fs->mkdir($rootdir."/uploads/ckeditor");
// Fichier cible
$targetName = uniqid().".".$extention;
$targetFile = $rootdir."/uploads/ckeditor/".$targetName;
$targetUrl = $this->getParameter('appAlias')."uploads/ckeditor/".$targetName;
$message = "";
move_uploaded_file($tmpfile,$targetFile);
$output["uploaded"]=1;
$output["fileName"]=$targetName;
$output["url"]=$targetUrl;
return new Response(json_encode($output));
}
}

View File

@ -0,0 +1,101 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use App\Service\MinioService;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Filesystem\Filesystem;
class MinioController extends AbstractController
{
private $minio;
public function __construct(KernelInterface $appKernel, MinioService $minio)
{
$this->appKernel = $appKernel;
$this->minio = $minio;
}
public function ckupload($access,Request $request): Response
{
// Fichier temporaire uploadé
$tmpfile = $request->files->get('upload');
$extention = $tmpfile->getClientOriginalExtension();
// Répertoire de Destination
$fs = new Filesystem();
$rootdir = $this->getParameter('kernel.project_dir') . '/public';
$fs->mkdir($rootdir."/uploads/ckeditor");
// Fichier cible
$targetName = uniqid().".".$extention;
$targetFile = "uploads/ckeditor/".$targetName;
$targetUrl = $this->getParameter('appAlias')."uploads/ckeditor/".$targetName;
$targetUrl = $this->generateUrl('app_minio_document',["file"=>"uploads/ckeditor/".$targetName]);
$message = "";
//move_uploaded_file($tmpfile,$targetFile);
$this->minio->upload($tmpfile,$targetFile,true);
$output["uploaded"]=1;
$output["fileName"]=$targetName;
$output["url"]=$targetUrl;
return new Response(json_encode($output));
}
public function image(Request $request): Response
{
$file=$request->query->get("file");
switch($file) {
case "uploads/avatar/admin.jpg":
case "uploads/avatar/noavatar.png":
case "uploads/avatar/system.jpg":
case "uploads/header/header.jpg":
case "uploads/logo/logo.png":
$filePath = $file;
$content = file_get_contents($file);
break;
default:
// C'est une url = on affiche l'url
if(stripos($file,"http")===0) {
$filePath = $file;
$content = file_get_contents($file);
}
// C'est du contenu dynamique on download depuis minio
elseif(stripos($file,"uploads")===0) {
$filePath = $this->minio->download($file, $file, true);
$content = file_get_contents($filePath);
}
// C'est du contenu statique on download depuis minio
else {
$filePath = $file;
$content = file_get_contents($file);
}
break;
}
return new Response($content, 200, [
'Content-Type' => mime_content_type($filePath),
'Cache-Control' => 'max-age='.(60 * 60 * 24 * 7),
'Expires' => gmdate(DATE_RFC1123, time() + 60 * 60 * 24 * 365),
]);
}
public function document(Request $request)
{
$file=$request->query->get("file");
$filePath = $this->minio->download($file, $file, true);
$content = file_get_contents($filePath);
return new Response($content, 200, [
'Content-Type' => mime_content_type($filePath),
'Cache-Control' => 'max-age='.(60 * 60 * 24 * 7),
'Expires' => gmdate(DATE_RFC1123, time() + 60 * 60 * 24 * 365),
]);
}
}

View File

@ -22,12 +22,8 @@ class PublishController extends AbstractController
$ret["from"]["id"]=$this->getUser()->getId();
$ret["from"]["username"]=$this->getUser()->getUsername();
$ret["from"]["displayname"]=$this->getUser()->getDisplayname();
$ret["from"]["avatar"]=$this->generateUrl('app_minio_image',["file"=>"uploads/avatar/".$this->getUser()->getAvatar()]);
if(stripos($this->getUser()->getAvatar(),"http")===0)
$ret["from"]["avatar"]=$this->getUser()->getAvatar();
else
$ret["from"]["avatar"]=$this->getParameter('appAlias')."uploads/avatar/".$this->getUser()->getAvatar();
$update = new Update(
$channel."-".$id,

View File

@ -399,8 +399,7 @@ class RestController extends AbstractFOSRestController
$output["userposition"]=$user->getPosition();
$output["userpostaladress"]=$user->getPostaladress();
$output["usertelephonenumber"]=$user->getTelephonenumber();
if(stripos($user->getAvatar(),"http")===0) $output["useravatar"]=$user->getAvatar();
else $output["useravatar"]="https://".$this->getParameter("appWeburl").$this->getParameter("appAlias")."uploads/avatar/".$user->getAvatar();
$output["useravatar"]="https://".str_replace("//","/",$this->getParameter("appWeburl").$this->getParameter("appAlias").$this->generateUrl('app_minio_image',["file"=>"uploads/avatar/".$user->getAvatar()],true));
$output["userniveau01"]=$this->niveau01Format($user->getNiveau01());
$output["userniveau02"]=$this->niveau02Format($user->getNiveau02());
$output["usergroups"]=[];

View File

@ -255,11 +255,8 @@ class UserController extends AbstractController
$tmp=array();
if($access=="admin"||$access=="modo") array_push($tmp,$action);
if(stripos($data->getAvatar(),"http")===0)
array_push($tmp,"<img src='".$data->getAvatar()."' class='avatar'>");
else
array_push($tmp,"<img src='".$this->getParameter('appAlias')."uploads/avatar/".$data->getAvatar()."' class='avatar'>");
array_push($tmp,"<img src='".$this->generateUrl('app_minio_image',["file"=>"uploads/avatar/".$data->getAvatar()])."' class='avatar'>");
array_push($tmp,$data->getUsername());
array_push($tmp,$data->getLastname());
array_push($tmp,$data->getFirstname());

View File

@ -0,0 +1,238 @@
<?php
namespace App\Service;
use Aws\S3\Exception\S3Exception;
use Exception;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Filesystem\Filesystem;
class MinioService
{
const ERR_UNAVAILABLE = 'Service de gestion de fichiers momentanément indisponible.';
const ERR_FILE_NOT_FOUND = 'messages.minio.404';
protected $client;
protected $listClient;
protected $minioBucket;
protected $minioRoot;
protected $minioPathStyle;
protected $minioSecure;
public function __construct($rootPath, $minioUrl, $minioKey, $minioSecret, $minioBucket, $minioRoot, $minioPathstyle, $minioSecure)
{
$this->rootPath = $rootPath;
$this->minioBucket = $minioBucket;
$this->minioPathStyle = ($minioPathstyle==1?true:false);
$this->minioRoot = $minioRoot;
$this->client = $this->getClient($minioUrl, $minioKey, $minioSecret, $minioPathstyle, $minioSecure);
$this->initBucket();
}
public function download(string $file, string $filename, bool $returnFile = false)
{
// On s'assure que le repertoire temporaire de destination existe bien
$fs = new Filesystem();
$tmpdir=$this->rootPath."/var/tmp";
$fs->mkdir($tmpdir."/".dirname($filename));
// Approche repassant par le serveur d'appel
try {
$result = $this->client->getObject([
'Bucket' => $this->minioBucket,
'Key' => $this->minioRoot.$file,
'SaveAs' => $tmpdir.'/'.$filename,
]);
} catch (S3Exception $e) {
dump($e);
switch ($e->getResponse()->getStatusCode()) {
case 404:
throw new NotFoundHttpException($this->translator->trans(self::ERR_FILE_NOT_FOUND, [], 'messages'));
break;
default:
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
break;
}
} catch (Exception $e) {
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
}
if ($returnFile) {
return $tmpdir.'/'.$filename;
} else {
//Suppression de la copie locale
unlink($tmpdir.'/'.$filename);
$res = new Response($result['Body'], 200);
$res->headers->set('Content-Type', 'application/pdf');
$res->headers->set('Content-Description', 'File Transfer');
$res->headers->set('Content-Disposition', 'attachment; filename='.$filename);
$res->headers->set('Expires', '0');
$res->headers->set('Cache-Control', 'must-revalidate');
$res->headers->set('Pragma', 'public');
return $res;
}
}
public function upload($file, $filename, $deleteSource = false)
{
try {
$this->client->putObject([
'Bucket' => $this->minioBucket,
'Key' => $this->minioRoot.$filename,
'SourceFile' => $file,
]);
} catch (Exception $e) {
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
}
if ($deleteSource) {
unlink($file);
}
}
/**
* move.
*
* @param bool $deleteSource
*
* @return void
*/
public function move(string $from, string $to, $deleteSource = false)
{
try {
$this->client->copyObject([
'Bucket' => $this->minioBucket,
'Key' => $this->minioRoot.$to,
'CopySource' => $this->minioBucket.'/'.$this->minioRoot.$from,
]);
} catch (Exception $e) {
\Sentry\captureException($e);
dump($this->minioRoot.$to);
dump($e->getMessage());
throw new Exception(self::ERR_UNAVAILABLE);
}
if ($deleteSource) {
$this->delete($from);
}
}
/**
* delete.
*
* @return void
*/
public function delete(string $file)
{
try {
$this->client->deleteObject([
'Bucket' => $this->minioBucket,
'Key' => $this->minioRoot.$file,
]);
} catch (Exception $e) {
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
}
}
/**
* countKeys.
*
* @return int
*/
public function countKeys(string $prefix)
{
//On utilise un path spécifique car listObjectsV2 utilise une autre config de client
try {
$response = $this->client->listObjectsV2([
'Bucket' => $this->minioBucket,
'Prefix' => $prefix,
]);
return $response->get('KeyCount');
} catch (Exception $e) {
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
}
}
/**
* listKeys.
*
* @return array
*/
public function listKeys(string $prefix)
{
//On utilise un path spécifique car listObjectsV2 utilise une autre config de client
try {
$response = $this->client->listObjectsV2([
'Bucket' => $this->minioBucket,
'Prefix' => $prefix,
]);
return $response->get('Contents');
} catch (Exception $e) {
\Sentry\captureException($e);
throw new Exception(self::ERR_UNAVAILABLE);
}
}
/**
* download.
*
* @param string $file Nom du fichier dans minio
* @param string $filename Nom du fichier dans la réponse
* @param bool $returnFile Retourner un fichier ou une réponse
*/
protected function getClient($minioUrl, $minioKey, $minioSecret, bool $minioPathstyle, bool $minioSecure)
{
$client = new \Aws\S3\S3Client([
'version' => 'latest',
'region' => 'eu-west-1',
'endpoint' => $minioUrl,
//On force le mode DNS
'use_path_style_endpoint' => $minioPathstyle,
'credentials' => [
'key' => $minioKey,
'secret' => $minioSecret,
],
//On désactive les checks SSL pour le moment
'http' => [
'verify' => $minioSecure,
],
]);
return $client;
}
protected function initBucket()
{
try {
$bucketExists = false;
$buckets = $this->client->listBuckets()->toArray()['Buckets'];
foreach ($buckets as $bucket) {
if ($this->minioBucket == $bucket['Name']) {
$bucketExists = true;
}
}
if (!$bucketExists) {
$this->client->createBucket([
'Bucket' => $this->minioBucket,
]);
}
} catch (Exception $e) {
dump($e->getMessage());
throw new Exception(self::ERR_UNAVAILABLE);
}
}
}

View File

@ -3,14 +3,17 @@ namespace App\Service;
use Doctrine\ORM\EntityManagerInterface;
use Oneup\UploaderBundle\Event\PostPersistEvent;
use App\Service\MinioService;
class UploadListener
{
private $em;
private $minio;
public function __construct(EntityManagerInterface $em)
public function __construct(EntityManagerInterface $em, MinioService $minio)
{
$this->em = $em;
$this->minio = $minio;
}
protected function getHeight($image) {
@ -76,6 +79,15 @@ class UploadListener
$type=$event->getType();
switch($type) {
case "logo":
$file=$event->getFile();
$filename=$file->getFilename();
$response = $event->getResponse();
$response['file'] = $filename;
$this->minio->upload($file,"uploads/logo/".$filename,true);
break;
default:
$file=$event->getFile();
$filename=$file->getFilename();

View File

@ -60,17 +60,17 @@
{% set color = app.session.get('colorbgbodylight') %}
{% endif %}
<img id="config_value_img" src="{{ appAlias }}uploads/logo/{{ config.value }}" style="background-color: {{color}}; width:90px;height:90px; margin:auto;display:block;">
<img id="config_value_img" src="{{ path("app_minio_image",{file:"uploads/logo/"~config.value}) }}" style="background-color: {{color}}; width:90px;height:90px; margin:auto;display:block;">
<a class="btn btn-info btn-modal" style="width:90px" data-modalid="mymodallarge" data-modaltitle="Logo" data-modalurl="{{ path('app_admin_config_logo') }}" title='Ajouter un Logo'>Modifier</a>
</div>
{% elseif config.type=="header" %}
<div style="margin:10px auto;">
<img id="config_value_img" src="{{ appAlias }}uploads/header/{{ config.value }}" style="width:100%;margin:auto;display:block;">
<img id="config_value_img" src="{{ path("app_minio_image",{file:"uploads/header/"~config.value}) }}" style="width:100%;margin:auto;display:block;">
<a class="btn btn-info btn-modal" style="width:100%" data-modalid="mymodallarge" data-modaltitle="Bannière" data-modalurl="{{ path('app_user_crop01', {"type": "header", "reportinput": "#config_value" }) }}" title='Ajouter une Bannière'>Modifier</a>
</div>
{% elseif config.type=="image" %}
<div style="margin:10px auto;">
<img id="config_value_img" src="{{ appAlias }}uploads/hero/{{ config.value }}" style="width:100%;margin:auto;display:block;">
<img id="config_value_img" src="{{ path("app_minio_image",{file:"uploads/hero/"~config.value}) }}" style="width:100%;margin:auto;display:block;">
<a class="btn btn-info btn-modal" style="width:100%" data-modalid="mymodallarge" data-modaltitle="Image" data-modalurl="{{ path('app_user_crop01', {"type": "image", "reportinput": "#config_value" }) }}" title='Ajouter une Image'>Modifier</a>
</div>
{% endif %}

View File

@ -24,7 +24,7 @@
<script>
function dropzonesuccess( file, response ) {
parent.$("#config_value").val(response["file"]);
parent.$("#config_value_img").attr("src","{{ appAlias }}uploads/logo/"+response["file"]);
parent.$("#config_value_img").attr("src","{{ path("app_minio_image",{file:"uploads/logo/"}) }}"+response["file"]);
closeModal();
}

View File

@ -68,11 +68,11 @@
{%endif%}
{% elseif config.type=="logo" %}
{%if not val is empty %}
<img src="{{appAlias}}uploads/logo/{{ val }}" height=50px>
<img src="{{path("app_minio_image",{file:"uploads/logo/"~val}) }}" height=50px>
{% endif %}
{% elseif config.type=="header" %}
{%if not val is empty %}
<img src="{{appAlias}}uploads/header/{{ val }}" width="100%">
<img src="{{ path("app_minio_image",{file:"uploads/header/"~val}) }}" width="100%">
{% endif %}
{% else %}
{{ val|raw }}

View File

@ -79,7 +79,7 @@
window.parent.location.reload();
{% elseif reportinput != "none" %}
window.parent.$("{{ reportinput }}").val("thumb_{{ file }}");
window.parent.$("{{ reportinput }}_img").attr("src","{{ appAlias }}uploads/{{ type }}/thumb_{{ file }}");
window.parent.$("{{ reportinput }}_img").attr("src","{{ path("app_minio_image",{file:"uploads/"~type~"/thumb_"~file}) }}");
{% endif %}
closeModal();

View File

@ -65,7 +65,7 @@
{% if user.avatar %}
{% set avatar= user.avatar %}
{% endif %}
<img id="user_avatar_img" src="{{ avatar|urlavatar }}" style="max-width:90px;background-color:var(--colorbgbodydark);">
<img id="user_avatar_img" src="{{ path('app_minio_image',{file:"uploads/avatar/"~avatar}) }}" style="max-width:90px;background-color:var(--colorbgbodydark);">
{{ form_widget(form.avatar) }}
<a class="btn btn-info btn-modal" style="width:100%" data-modalid="mymodallarge" data-modaltitle="Avatar" data-modalurl="{{ path('app_user_crop01', {"type": "avatar", "reportinput": "#user_avatar" }) }}" title='Ajouter un Avatar'>Modifier</a>
</div>

View File

@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html"; charset="utf-8" />
<title>{% block title %}{{app.session.get("appname")}}{% endblock %}</title>
<link rel="shortcut icon" href="{{ appAlias }}uploads/logo/{{app.session.get("logolight")}}" />
<link rel="shortcut icon" href="{{ path('app_minio_image',{file:"uploads/logo/"~app.session.get("logodark")}) }}" />
{{ encore_entry_link_tags('app') }}
@ -23,9 +23,9 @@
{% if (useheader is defined and useheader) or (usemenu is defined and usemenu) %}
<div class="header sticky-top">
{% if useheader is defined and useheader and (app.session.get("fgheader") or not app.user) %}
<div id="header" class="d-flex align-items-center" style="height:{{app.session.get("headerheight")}}px; background-image: linear-gradient(90deg,rgba(var(--colorbgbodydark-rgb),1),rgba(var(--colorbgbodydark-rgb),0.1)),url({{appAlias}}{{app.session.get("headerimage")}});background-size:cover">
<div id="header" class="d-flex align-items-center" style="height:{{app.session.get("headerheight")}}px; background-image: linear-gradient(90deg,rgba(var(--colorbgbodydark-rgb),1),rgba(var(--colorbgbodydark-rgb),0.1)),url({{ path('app_minio_image',{file:app.session.get("headerimage")}) }});background-size:cover">
<a href="{{ path('app_home')}}">
<img src="{{ appAlias }}uploads/logo/{{app.session.get("logodark")}}" style="height:{{app.session.get("headerheight")-20}}px;margin-left:10px; max-height:120px;">
<img src="{{ path('app_minio_image',{file:"uploads/logo/"~app.session.get("logodark")}) }}" style="height:{{app.session.get("headerheight")-20}}px;margin-left:10px; max-height:120px;">
</a>
<h1 class="flex-grow-1">
@ -40,7 +40,7 @@
<nav class="nav">
{% if app.user %}
<a class="nav-link" href="{{path("app_user_user")}}" title="Mon Profil">
<img src="{{app.user.avatar|urlavatar}}" class="avatar" style="width:35px;height:35px;">
<img src="{{ path('app_minio_image',{file:"uploads/avatar/"~app.user.avatar}) }}" class="avatar" style="width:35px;height:35px;">
</a>
{% if is_granted('ROLE_ADMIN') %}
@ -80,7 +80,7 @@
<nav id="menu" class="navbar navbar-expand p-0" style="{{style}}">
<a class="nav-link navbar-logo" href="{{ path('app_home')}}" style="display:none">
<img src="{{ appAlias }}uploads/logo/{{app.session.get("logodark")}}">
<img src="{{ path('app_minio_image',{file:"uploads/logo/"~app.session.get("logodark")}) }}">
</a>
<a class="nav-link " href="{{ path('app_home')}}">Accueil</a>
@ -98,7 +98,7 @@
<ul id="menulink" class="nav navbar-right pe-3" style="display:none;">
{% if app.user %}
<a href="{{path("app_user_user")}}">
<img src="{{app.user.avatar|urlavatar}}" class="avatar" style="width:25px; height:25px; margin-top:-3px; margin-right:3px;">
<img src="{{ path('app_minio_image',{file:"uploads/avatar/"~app.user.avatar}) }}" class="avatar" style="width:25px; height:25px; margin-top:-3px; margin-right:3px;">
</a>
{% if is_granted('ROLE_ADMIN') %}