WIP: Implement uploads
@@ -25,3 +25,7 @@
|
|||||||
npm-debug.log
|
npm-debug.log
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
###< symfony/webpack-encore-bundle ###
|
###< symfony/webpack-encore-bundle ###
|
||||||
|
|
||||||
|
###> liip/imagine-bundle ###
|
||||||
|
/public/media/cache/
|
||||||
|
###< liip/imagine-bundle ###
|
||||||
|
|||||||
@@ -24,8 +24,13 @@ export default class extends Controller {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.buttonTargets.forEach((element, index) => {
|
this.buttonTargets.forEach((element, index) => {
|
||||||
if (this.hasButtonActiveClass) {
|
if (false === this.hasButtonActiveClass) {
|
||||||
element.classList.toggle(this.buttonActiveClass, activeTab === index)
|
return
|
||||||
|
}
|
||||||
|
if (activeTab === index) {
|
||||||
|
element.classList.add(...this.buttonActiveClasses)
|
||||||
|
} else {
|
||||||
|
element.classList.remove(...this.buttonActiveClasses)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { Controller } from '@hotwired/stimulus'
|
||||||
|
import { useFetch } from '../mixins/use_fetch'
|
||||||
|
import Dropzone from 'dropzone'
|
||||||
|
import 'dropzone/dist/dropzone.css'
|
||||||
|
Dropzone.autoDiscover = false
|
||||||
|
|
||||||
|
/* stimulusFetch: 'lazy' */
|
||||||
|
export default class extends Controller {
|
||||||
|
|
||||||
|
static targets = [
|
||||||
|
'dropzone',
|
||||||
|
]
|
||||||
|
|
||||||
|
static values = {
|
||||||
|
endpointUpload: String,
|
||||||
|
endpointDelete: String,
|
||||||
|
maxFiles: Number,
|
||||||
|
maxFilesize: Number,
|
||||||
|
acceptedFiles: String,
|
||||||
|
chunking: Boolean,
|
||||||
|
params: Object,
|
||||||
|
}
|
||||||
|
|
||||||
|
connect () {
|
||||||
|
useFetch(this)
|
||||||
|
|
||||||
|
const dropzone = new Dropzone(this.dropzoneTarget, {
|
||||||
|
url: this.endpointUploadValue,
|
||||||
|
withCredentials: true,
|
||||||
|
maxFiles: this.maxFilesValue,
|
||||||
|
maxFilesize: this.maxFilesizeValue,
|
||||||
|
acceptedFiles: this.acceptedFilesValue,
|
||||||
|
chunking: this.chunkingValue,
|
||||||
|
chunkSize: 10000000,
|
||||||
|
parallelUploads: 3,
|
||||||
|
retryChunks: true,
|
||||||
|
disablePreviews: false,
|
||||||
|
createImageThumbnails: true,
|
||||||
|
autoProcessQueue: true,
|
||||||
|
addRemoveLinks: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
dropzone.on('sending', (file, xhr, formData) => {
|
||||||
|
if (this.hasParamsValue) {
|
||||||
|
let keys = Object.keys(this.paramsValue)
|
||||||
|
keys.forEach(key => {
|
||||||
|
formData.append(key, this.paramsValue[key])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
formData.append('uuid', file.upload.uuid)
|
||||||
|
formData.append('originalFilename', file.name)
|
||||||
|
window.dispatchEvent(new CustomEvent('dropzone:uploading'))
|
||||||
|
})
|
||||||
|
|
||||||
|
dropzone.on('queuecomplete', () => {
|
||||||
|
window.dispatchEvent(new CustomEvent('dropzone:complete'))
|
||||||
|
})
|
||||||
|
|
||||||
|
dropzone.on('removedfile', (file) => {
|
||||||
|
fetch(`${this.endpointDeleteValue}?uuid=${file.upload.uuid}`, { method: 'delete', credentials: 'include' })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
import { Controller } from '@hotwired/stimulus'
|
|
||||||
import Dropzone from 'dropzone'
|
|
||||||
Dropzone.autoDiscover = false
|
|
||||||
|
|
||||||
/* stimulusFetch: 'lazy' */
|
|
||||||
export default class extends Controller {
|
|
||||||
|
|
||||||
static targets = [
|
|
||||||
'dropzone',
|
|
||||||
'queue',
|
|
||||||
'previewTemplate',
|
|
||||||
'fieldsTemplate',
|
|
||||||
'fields',
|
|
||||||
'error',
|
|
||||||
'errorMessage',
|
|
||||||
'upload',
|
|
||||||
]
|
|
||||||
|
|
||||||
static values = {
|
|
||||||
endpoint: String,
|
|
||||||
maxFiles: Number,
|
|
||||||
maxFilesize: Number,
|
|
||||||
acceptedFiles: String,
|
|
||||||
chunking: Boolean,
|
|
||||||
language: Object,
|
|
||||||
params: Object,
|
|
||||||
uploads: Array,
|
|
||||||
error: String,
|
|
||||||
formName: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize() {
|
|
||||||
this.fieldsTemplate = this.fieldsTemplateTarget.innerHTML
|
|
||||||
}
|
|
||||||
|
|
||||||
connect () {
|
|
||||||
const dropzone = new Dropzone(this.dropzoneTarget, {
|
|
||||||
url: this.endpointValue,
|
|
||||||
withCredentials: true,
|
|
||||||
maxFiles: this.maxFilesValue,
|
|
||||||
maxFilesize: this.maxFilesizeValue,
|
|
||||||
acceptedFiles: this.acceptedFilesValue,
|
|
||||||
chunking: this.chunkingValue,
|
|
||||||
chunkSize: 10000000,
|
|
||||||
parallelUploads: 3,
|
|
||||||
retryChunks: true,
|
|
||||||
previewsContainer: this.queueTarget,
|
|
||||||
previewTemplate: this.previewTemplateTarget.innerHTML,
|
|
||||||
createImageThumbnails: true,
|
|
||||||
dictFileTooBig: this.languageValue.fileTooBig,
|
|
||||||
dictInvalidFileType: this.languageValue.invalidFileType,
|
|
||||||
dictMaxFilesExceeded: this.languageValue.maxFilesExceeded,
|
|
||||||
})
|
|
||||||
|
|
||||||
dropzone.on('addedfile', file => {
|
|
||||||
if (this.maxFilesValue > this.uploadsValue.length) {
|
|
||||||
this._removeFile(file.id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.errorValue = ''
|
|
||||||
const uploads = this.uploadsValue;
|
|
||||||
uploads.pop()
|
|
||||||
this.uploadsValue = uploads
|
|
||||||
})
|
|
||||||
|
|
||||||
dropzone.on('removedfile', file => {
|
|
||||||
this._removeFile(file.upload.uuid)
|
|
||||||
})
|
|
||||||
|
|
||||||
dropzone.on('maxfilesexceeded', file => {
|
|
||||||
this.errorValue = dropzone.options.dictMaxFilesExceeded
|
|
||||||
dropzone.removeFile(file);
|
|
||||||
})
|
|
||||||
|
|
||||||
dropzone.on('error', (file, errorMessage) => {
|
|
||||||
this.errorValue = errorMessage;
|
|
||||||
dropzone.removeFile(file)
|
|
||||||
})
|
|
||||||
|
|
||||||
dropzone.on('dragenter', () => {
|
|
||||||
this.errorValue = ''
|
|
||||||
})
|
|
||||||
|
|
||||||
dropzone.on('success', file => {
|
|
||||||
const response = JSON.parse(file.xhr.response)
|
|
||||||
const uploads = this.uploadsValue
|
|
||||||
uploads.push({
|
|
||||||
filename: response.filename,
|
|
||||||
originalFilename: response.originalFilename,
|
|
||||||
uploaderType: response.uploaderType,
|
|
||||||
size: response.size,
|
|
||||||
mimeType: response.mimeType,
|
|
||||||
fileId: file.upload.uuid
|
|
||||||
})
|
|
||||||
this.uploadsValue = uploads
|
|
||||||
window.dispatchEvent(new CustomEvent('dropzone', {
|
|
||||||
detail: 'success'
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
dropzone.on('sending', () => {
|
|
||||||
window.dispatchEvent(new CustomEvent('dropzone', {
|
|
||||||
detail: 'uploading'
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
errorValueChanged () {
|
|
||||||
if ('' === this.errorValue) {
|
|
||||||
this.errorTarget.classList.add('hidden')
|
|
||||||
} else {
|
|
||||||
this.errorMessageTarget.innerText = this.errorValue
|
|
||||||
this.errorTarget.classList.remove('hidden')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadsValueChanged (uploads) {
|
|
||||||
this.fieldsTarget.innerHTML = ''
|
|
||||||
uploads.forEach((upload, index) => {
|
|
||||||
const field = this.fieldsTemplate
|
|
||||||
.replace(/__formName__/g, this.formNameValue)
|
|
||||||
.replace(/__index__/g, index)
|
|
||||||
.replace(/__fileId__/g, upload.fileId)
|
|
||||||
.replace(/__originalFilename__/g, upload.originalFilename)
|
|
||||||
.replace(/__filename__/g, upload.filename)
|
|
||||||
.replace(/__mimeType__/g, upload.mimeType)
|
|
||||||
.replace(/__size__/g, upload.size)
|
|
||||||
this.fieldsTarget.insertAdjacentHTML('beforeend', field)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
removeFile ({ params }) {
|
|
||||||
const fileId = params.fileid
|
|
||||||
this._removeFile(fileId)
|
|
||||||
}
|
|
||||||
|
|
||||||
_removeFile(fileId) {
|
|
||||||
this.uploadsValue = this.uploadsValue.filter(upload => {
|
|
||||||
return upload.fileId !== fileId
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
removeUpload (event) {
|
|
||||||
event.preventDefault()
|
|
||||||
this.uploadTargets.forEach(element => {
|
|
||||||
if (element.contains(event.target)) {
|
|
||||||
element.remove()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
.btn {
|
.btn {
|
||||||
@apply inline-flex justify-center rounded-lg text-sm uppercase font-semibold py-2.5 px-4 bg-primary text-white hover:bg-primary/80 w-full;
|
@apply inline-flex justify-center rounded-lg text-sm uppercase font-semibold py-2.5 px-4 bg-primary text-white hover:bg-primary/80 w-full shadow-md;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn--secondary {
|
.btn--secondary {
|
||||||
@apply bg-secondary text-gray-800 hover:bg-secondary/80;
|
@apply bg-secondary text-gray-800 hover:bg-secondary/80;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn--active {
|
||||||
|
@apply shadow-none;
|
||||||
|
}
|
||||||
@@ -12,7 +12,9 @@
|
|||||||
"doctrine/doctrine-migrations-bundle": "^3.2",
|
"doctrine/doctrine-migrations-bundle": "^3.2",
|
||||||
"doctrine/orm": "^2.15",
|
"doctrine/orm": "^2.15",
|
||||||
"knplabs/knp-menu-bundle": "^3.2",
|
"knplabs/knp-menu-bundle": "^3.2",
|
||||||
|
"liip/imagine-bundle": "^2.11",
|
||||||
"nesbot/carbon": "^2.70",
|
"nesbot/carbon": "^2.70",
|
||||||
|
"oneup/uploader-bundle": "^4.0",
|
||||||
"phpdocumentor/reflection-docblock": "^5.3",
|
"phpdocumentor/reflection-docblock": "^5.3",
|
||||||
"phpstan/phpdoc-parser": "^1.22",
|
"phpstan/phpdoc-parser": "^1.22",
|
||||||
"symfony/apache-pack": "^1.0",
|
"symfony/apache-pack": "^1.0",
|
||||||
@@ -46,6 +48,7 @@
|
|||||||
"symfony/webpack-encore-bundle": "^2.0",
|
"symfony/webpack-encore-bundle": "^2.0",
|
||||||
"symfony/yaml": "6.3.*",
|
"symfony/yaml": "6.3.*",
|
||||||
"twig/extra-bundle": "^2.12|^3.0",
|
"twig/extra-bundle": "^2.12|^3.0",
|
||||||
|
"twig/html-extra": "^3.7",
|
||||||
"twig/twig": "^2.12|^3.0"
|
"twig/twig": "^2.12|^3.0"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "c7bd8e1f662fa638390820a36f96a7fd",
|
"content-hash": "2b10ee7954ba92748752ca9e16b1a17a",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "doctrine/cache",
|
"name": "doctrine/cache",
|
||||||
@@ -1386,6 +1386,68 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-01-14T14:17:03+00:00"
|
"time": "2023-01-14T14:17:03+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "imagine/imagine",
|
||||||
|
"version": "1.3.5",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-imagine/Imagine.git",
|
||||||
|
"reference": "7151d553edec4dc2bbac60419f7a74ff34700e7f"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-imagine/Imagine/zipball/7151d553edec4dc2bbac60419f7a74ff34700e7f",
|
||||||
|
"reference": "7151d553edec4dc2bbac60419f7a74ff34700e7f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.5"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5 || ^8.4 || ^9.3"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-exif": "to read EXIF metadata",
|
||||||
|
"ext-gd": "to use the GD implementation",
|
||||||
|
"ext-gmagick": "to use the Gmagick implementation",
|
||||||
|
"ext-imagick": "to use the Imagick implementation"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-develop": "1.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Imagine\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Bulat Shakirzyanov",
|
||||||
|
"email": "[email protected]",
|
||||||
|
"homepage": "http://avalanche123.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Image processing for PHP 5.3",
|
||||||
|
"homepage": "http://imagine.readthedocs.org/",
|
||||||
|
"keywords": [
|
||||||
|
"drawing",
|
||||||
|
"graphics",
|
||||||
|
"image manipulation",
|
||||||
|
"image processing"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/php-imagine/Imagine/issues",
|
||||||
|
"source": "https://github.com/php-imagine/Imagine/tree/1.3.5"
|
||||||
|
},
|
||||||
|
"time": "2023-06-07T14:49:52+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "knplabs/knp-menu",
|
"name": "knplabs/knp-menu",
|
||||||
"version": "v3.4.0",
|
"version": "v3.4.0",
|
||||||
@@ -1523,6 +1585,109 @@
|
|||||||
},
|
},
|
||||||
"time": "2021-10-24T07:53:34+00:00"
|
"time": "2021-10-24T07:53:34+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "liip/imagine-bundle",
|
||||||
|
"version": "2.11.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/liip/LiipImagineBundle.git",
|
||||||
|
"reference": "2e943e6be4309ec90fcff90227053898203c1c8e"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/liip/LiipImagineBundle/zipball/2e943e6be4309ec90fcff90227053898203c1c8e",
|
||||||
|
"reference": "2e943e6be4309ec90fcff90227053898203c1c8e",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"imagine/imagine": "^1.3.2",
|
||||||
|
"php": "^7.1|^8.0",
|
||||||
|
"symfony/filesystem": "^3.4|^4.4|^5.3|^6.0",
|
||||||
|
"symfony/finder": "^3.4|^4.4|^5.3|^6.0",
|
||||||
|
"symfony/framework-bundle": "^3.4.23|^4.4|^5.3|^6.0",
|
||||||
|
"symfony/mime": "^4.4|^5.3|^6.0",
|
||||||
|
"symfony/options-resolver": "^3.4|^4.4|^5.3|^6.0",
|
||||||
|
"symfony/process": "^3.4|^4.4|^5.3|^6.0",
|
||||||
|
"twig/twig": "^1.44|^2.9|^3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"amazonwebservices/aws-sdk-for-php": "^1.0",
|
||||||
|
"aws/aws-sdk-php": "^2.4",
|
||||||
|
"doctrine/cache": "^1.11|^2.0",
|
||||||
|
"doctrine/persistence": "^1.3|^2.0",
|
||||||
|
"enqueue/enqueue-bundle": "^0.9|^0.10",
|
||||||
|
"ext-gd": "*",
|
||||||
|
"league/flysystem": "^1.0|^2.0|^3.0",
|
||||||
|
"phpstan/phpstan": "^0.12.64",
|
||||||
|
"psr/cache": "^1.0|^2.0|^3.0",
|
||||||
|
"psr/log": "^1.0",
|
||||||
|
"symfony/browser-kit": "^3.4|^4.4|^5.3|^6.0",
|
||||||
|
"symfony/cache": "^3.4|^4.4|^5.3|^6.0",
|
||||||
|
"symfony/console": "^3.4|^4.4|^5.3|^6.0",
|
||||||
|
"symfony/dependency-injection": "^3.4|^4.4|^5.3|^6.0",
|
||||||
|
"symfony/form": "^3.4|^4.4|^5.3|^6.0",
|
||||||
|
"symfony/messenger": "^4.4|^5.3|^6.0",
|
||||||
|
"symfony/phpunit-bridge": "^5.3",
|
||||||
|
"symfony/templating": "^3.4|^4.4|^5.3|^6.0",
|
||||||
|
"symfony/validator": "^3.4|^4.4|^5.3|^6.0",
|
||||||
|
"symfony/yaml": "^3.4|^4.4|^5.3|^6.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"alcaeus/mongo-php-adapter": "required for mongodb components",
|
||||||
|
"amazonwebservices/aws-sdk-for-php": "required to use AWS version 1 cache resolver",
|
||||||
|
"aws/aws-sdk-php": "required to use AWS version 2/3 cache resolver",
|
||||||
|
"doctrine/mongodb-odm": "required to use mongodb-backed doctrine components",
|
||||||
|
"enqueue/enqueue-bundle": "^0.9 add if you like to process images in background",
|
||||||
|
"ext-exif": "required to read EXIF metadata from images",
|
||||||
|
"ext-gd": "required to use gd driver",
|
||||||
|
"ext-gmagick": "required to use gmagick driver",
|
||||||
|
"ext-imagick": "required to use imagick driver",
|
||||||
|
"ext-mongodb": "required for mongodb components",
|
||||||
|
"league/flysystem": "required to use FlySystem data loader or cache resolver",
|
||||||
|
"monolog/monolog": "A psr/log compatible logger is required to enable logging",
|
||||||
|
"rokka/imagine-vips": "required to use 'vips' driver",
|
||||||
|
"symfony/messenger": "If you like to process images in background",
|
||||||
|
"symfony/templating": "required to use deprecated Templating component instead of Twig"
|
||||||
|
},
|
||||||
|
"type": "symfony-bundle",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Liip\\ImagineBundle\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Liip and other contributors",
|
||||||
|
"homepage": "https://github.com/liip/LiipImagineBundle/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "This bundle provides an image manipulation abstraction toolkit for Symfony-based projects.",
|
||||||
|
"homepage": "http://liip.ch",
|
||||||
|
"keywords": [
|
||||||
|
"bundle",
|
||||||
|
"image",
|
||||||
|
"imagine",
|
||||||
|
"liip",
|
||||||
|
"manipulation",
|
||||||
|
"photos",
|
||||||
|
"pictures",
|
||||||
|
"symfony",
|
||||||
|
"transformation"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/liip/LiipImagineBundle/issues",
|
||||||
|
"source": "https://github.com/liip/LiipImagineBundle/tree/2.11.0"
|
||||||
|
},
|
||||||
|
"time": "2023-05-16T06:13:14+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "monolog/monolog",
|
"name": "monolog/monolog",
|
||||||
"version": "3.4.0",
|
"version": "3.4.0",
|
||||||
@@ -1730,6 +1895,100 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-09-07T16:43:50+00:00"
|
"time": "2023-09-07T16:43:50+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "oneup/uploader-bundle",
|
||||||
|
"version": "4.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/1up-lab/OneupUploaderBundle.git",
|
||||||
|
"reference": "34d22041d40ff45f87de56cd617a580d48cbdd8c"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/1up-lab/OneupUploaderBundle/zipball/34d22041d40ff45f87de56cd617a580d48cbdd8c",
|
||||||
|
"reference": "34d22041d40ff45f87de56cd617a580d48cbdd8c",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.4 || ^8.0",
|
||||||
|
"symfony/asset": "^4.4 || ^5.4 || ^6.0",
|
||||||
|
"symfony/event-dispatcher-contracts": "^1.0 || ^2.0 || ^3.0",
|
||||||
|
"symfony/finder": "^4.4 || ^5.4 || ^6.0",
|
||||||
|
"symfony/framework-bundle": "^4.4 || ^5.4 || ^6.0",
|
||||||
|
"symfony/mime": "^4.4 || ^5.4 || ^6.0",
|
||||||
|
"symfony/templating": "^4.4 || ^5.4 || ^6.0",
|
||||||
|
"symfony/translation": "^4.4 || ^5.4 || ^6.0",
|
||||||
|
"symfony/translation-contracts": "^1.0 || ^2.0 || ^3.0",
|
||||||
|
"symfony/yaml": "^4.4 || ^5.4 || ^6.0",
|
||||||
|
"twig/twig": "^2.4 || ^3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"amazonwebservices/aws-sdk-for-php": "1.5.*",
|
||||||
|
"doctrine/common": "^2.12 || ^3.0",
|
||||||
|
"doctrine/doctrine-bundle": "^2.4",
|
||||||
|
"friendsofphp/php-cs-fixer": "^2.16",
|
||||||
|
"knplabs/gaufrette": "^0.9",
|
||||||
|
"m2mtech/flysystem-stream-wrapper": "^1.0",
|
||||||
|
"oneup/flysystem-bundle": "^4.1",
|
||||||
|
"phpstan/phpstan": "^0.12.10",
|
||||||
|
"phpunit/phpunit": "^9.5",
|
||||||
|
"sensio/framework-extra-bundle": "^5.0 || ^6.0",
|
||||||
|
"symfony/browser-kit": "^4.4 || ^5.4 || ^6.0",
|
||||||
|
"symfony/phpunit-bridge": "^5.4",
|
||||||
|
"symfony/security-bundle": "^4.4 || ^5.4 || ^6.0",
|
||||||
|
"symfony/var-dumper": "^4.4 || ^5.4 || ^6.0",
|
||||||
|
"twistor/flysystem-stream-wrapper": "^1.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"knplabs/knp-gaufrette-bundle": "0.1.*",
|
||||||
|
"m2mtech/flysystem-stream-wrapper": "^1.0 (Required when using Flysystem)",
|
||||||
|
"oneup/flysystem-bundle": "^3.0"
|
||||||
|
},
|
||||||
|
"type": "symfony-bundle",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Oneup\\UploaderBundle\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jim Schmid",
|
||||||
|
"email": "[email protected]",
|
||||||
|
"homepage": "https://1up.io",
|
||||||
|
"role": "Developer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "David Greminger",
|
||||||
|
"email": "[email protected]",
|
||||||
|
"homepage": "https://1up.io",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "This Symfony bundle provides a server implementation for handling single and multiple file uploads using either FineUploader, jQuery File Uploader, YUI3 Uploader, Uploadify, FancyUpload, MooUpload, Plupload or Dropzone. Features include chunked uploads, orphanages, Gaufrette and Flysystem support.",
|
||||||
|
"homepage": "https://1up.io",
|
||||||
|
"keywords": [
|
||||||
|
"FancyUpload",
|
||||||
|
"FineUploader",
|
||||||
|
"MooUpload",
|
||||||
|
"Uploadify",
|
||||||
|
"YUI3 Uploader",
|
||||||
|
"blueimp",
|
||||||
|
"dropzone",
|
||||||
|
"fileupload",
|
||||||
|
"jQuery File Uploader",
|
||||||
|
"plupload",
|
||||||
|
"upload"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/1up-lab/OneupUploaderBundle/issues",
|
||||||
|
"source": "https://github.com/1up-lab/OneupUploaderBundle/tree/4.0.1"
|
||||||
|
},
|
||||||
|
"time": "2022-07-25T07:51:47+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "phpdocumentor/reflection-common",
|
"name": "phpdocumentor/reflection-common",
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
@@ -6654,6 +6913,71 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-03-21T21:06:29+00:00"
|
"time": "2023-03-21T21:06:29+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/templating",
|
||||||
|
"version": "v6.3.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/templating.git",
|
||||||
|
"reference": "27d79475d8bcba894235b5472df158e78c6419a3"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/templating/zipball/27d79475d8bcba894235b5472df158e78c6419a3",
|
||||||
|
"reference": "27d79475d8bcba894235b5472df158e78c6419a3",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.1",
|
||||||
|
"symfony/polyfill-ctype": "~1.8"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"psr/log": "^1|^2|^3"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Templating\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "[email protected]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Provides all the tools needed to build any kind of template system",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/templating/tree/v6.3.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-04-22T08:23:52+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/translation",
|
"name": "symfony/translation",
|
||||||
"version": "v6.3.0",
|
"version": "v6.3.0",
|
||||||
@@ -7644,6 +7968,70 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-05-06T11:11:46+00:00"
|
"time": "2023-05-06T11:11:46+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "twig/html-extra",
|
||||||
|
"version": "v3.7.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/twigphp/html-extra.git",
|
||||||
|
"reference": "95ceb36e70fa8d07af08cf5135ecbf5e0bd8f386"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/twigphp/html-extra/zipball/95ceb36e70fa8d07af08cf5135ecbf5e0bd8f386",
|
||||||
|
"reference": "95ceb36e70fa8d07af08cf5135ecbf5e0bd8f386",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.1.3",
|
||||||
|
"symfony/mime": "^5.4|^6.0",
|
||||||
|
"twig/twig": "^2.7|^3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/phpunit-bridge": "^5.4|^6.3"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Twig\\Extra\\Html\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "[email protected]",
|
||||||
|
"homepage": "http://fabien.potencier.org",
|
||||||
|
"role": "Lead Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A Twig extension for HTML",
|
||||||
|
"homepage": "https://twig.symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"html",
|
||||||
|
"twig"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/twigphp/html-extra/tree/v3.7.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-07-29T15:34:56+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "twig/twig",
|
"name": "twig/twig",
|
||||||
"version": "v3.6.1",
|
"version": "v3.6.1",
|
||||||
|
|||||||
@@ -14,4 +14,6 @@ return [
|
|||||||
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
|
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
|
||||||
Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
|
Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
|
||||||
Knp\Bundle\MenuBundle\KnpMenuBundle::class => ['all' => true],
|
Knp\Bundle\MenuBundle\KnpMenuBundle::class => ['all' => true],
|
||||||
|
Oneup\UploaderBundle\OneupUploaderBundle::class => ['all' => true],
|
||||||
|
Liip\ImagineBundle\LiipImagineBundle::class => ['all' => true],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
liip_imagine:
|
||||||
|
driver: "imagick"
|
||||||
|
resolvers:
|
||||||
|
default:
|
||||||
|
web_path: ~
|
||||||
|
cache: format_extension
|
||||||
|
loaders:
|
||||||
|
default:
|
||||||
|
filesystem:
|
||||||
|
data_root: '%kernel.project_dir%/uploads/photo'
|
||||||
|
twig:
|
||||||
|
mode: lazy
|
||||||
|
|
||||||
|
filter_sets:
|
||||||
|
cache: ~
|
||||||
|
thumbnail:
|
||||||
|
format: jpeg
|
||||||
|
jpeg_quality: 75
|
||||||
|
filters:
|
||||||
|
thumbnail: { size: [ 128, 128 ], mode: outbound }
|
||||||
|
profile:
|
||||||
|
format: jpeg
|
||||||
|
jpeg_quality: 75
|
||||||
|
filters:
|
||||||
|
thumbnail: { size: [ 128, 128 ], mode: outbound }
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
oneup_uploader:
|
||||||
|
mappings:
|
||||||
|
photo:
|
||||||
|
frontend: dropzone
|
||||||
|
use_orphanage: true
|
||||||
|
namer: app.upload_namer
|
||||||
|
storage:
|
||||||
|
directory: '%kernel.project_dir%/uploads/photo'
|
||||||
|
chunks:
|
||||||
|
maxage: 86400
|
||||||
|
storage:
|
||||||
|
directory: '%kernel.project_dir%/uploads/temp'
|
||||||
|
orphanage:
|
||||||
|
maxage: 3600
|
||||||
|
directory: '%kernel.project_dir%/uploads/orphanage'
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
_liip_imagine:
|
||||||
|
resource: "@LiipImagineBundle/Resources/config/routing.yaml"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
oneup_uploader:
|
||||||
|
resource: .
|
||||||
|
type: uploader
|
||||||
@@ -19,6 +19,14 @@ services:
|
|||||||
- '../src/Entity/'
|
- '../src/Entity/'
|
||||||
- '../src/Kernel.php'
|
- '../src/Kernel.php'
|
||||||
|
|
||||||
|
Liip\ImagineBundle\Imagine\Cache\Resolver\FormatExtensionResolver:
|
||||||
|
arguments:
|
||||||
|
- '@liip_imagine.cache.resolver.default'
|
||||||
|
- '@liip_imagine.filter.configuration'
|
||||||
|
tags:
|
||||||
|
- name: liip_imagine.cache.resolver
|
||||||
|
resolver: format_extension
|
||||||
|
|
||||||
App\EventListener\BlamableEntitySubscriber:
|
App\EventListener\BlamableEntitySubscriber:
|
||||||
tags:
|
tags:
|
||||||
- { name: 'doctrine.event_subscriber', connection: 'default' }
|
- { name: 'doctrine.event_subscriber', connection: 'default' }
|
||||||
@@ -27,6 +35,13 @@ services:
|
|||||||
tags:
|
tags:
|
||||||
- { name: 'doctrine.event_subscriber', connection: 'default' }
|
- { name: 'doctrine.event_subscriber', connection: 'default' }
|
||||||
|
|
||||||
|
App\EventListener\LogoutListener:
|
||||||
|
tags:
|
||||||
|
- name: kernel.event_listener
|
||||||
|
event: Symfony\Component\Security\Http\Event\LogoutEvent
|
||||||
|
method: onLogout
|
||||||
|
dispatcher: security.event_dispatcher.main
|
||||||
|
|
||||||
App\BusProNet\ApiClient:
|
App\BusProNet\ApiClient:
|
||||||
arguments:
|
arguments:
|
||||||
$logger: '@monolog.logger.bpn'
|
$logger: '@monolog.logger.bpn'
|
||||||
@@ -47,3 +62,30 @@ services:
|
|||||||
- name: knp_menu.menu_builder
|
- name: knp_menu.menu_builder
|
||||||
method: createMainMenu
|
method: createMainMenu
|
||||||
alias: main
|
alias: main
|
||||||
|
|
||||||
|
App\Service\Upload\UploadHandler:
|
||||||
|
arguments:
|
||||||
|
$orphanageManager: '@oneup_uploader.orphanage_manager'
|
||||||
|
$projectDir: '%kernel.project_dir%'
|
||||||
|
|
||||||
|
App\EventListener\UploadSessionListener:
|
||||||
|
tags:
|
||||||
|
- name: kernel.event_listener
|
||||||
|
event: oneup_uploader.post_upload
|
||||||
|
method: onUpload
|
||||||
|
|
||||||
|
App\EventListener\UploadSessionValidationListener:
|
||||||
|
tags:
|
||||||
|
- name: kernel.event_listener
|
||||||
|
event: oneup_uploader.validation
|
||||||
|
method: onValidate
|
||||||
|
|
||||||
|
App\EventListener\DeleteUploadListener:
|
||||||
|
tags:
|
||||||
|
- name: doctrine.event_listener
|
||||||
|
event: preRemove
|
||||||
|
|
||||||
|
app.upload_namer:
|
||||||
|
class: App\Service\Upload\UploadNamer
|
||||||
|
public: true
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ namespace App\Controller\Teamer;
|
|||||||
use App\BusProNet\ApiClient;
|
use App\BusProNet\ApiClient;
|
||||||
use App\BusProNet\ApiClientException;
|
use App\BusProNet\ApiClientException;
|
||||||
use App\Entity\Teamer;
|
use App\Entity\Teamer;
|
||||||
|
use App\Entity\Upload;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use App\Form\TeamerProfileType;
|
use App\Form\TeamerProfileType;
|
||||||
|
use App\Service\Upload\UploadHandler;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
@@ -18,7 +20,8 @@ class ProfileController extends AbstractController
|
|||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly EntityManagerInterface $entityManager,
|
private readonly EntityManagerInterface $entityManager,
|
||||||
private readonly ApiClient $apiClient
|
private readonly ApiClient $apiClient,
|
||||||
|
private readonly UploadHandler $uploadHandler
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,10 +39,22 @@ class ProfileController extends AbstractController
|
|||||||
$this->entityManager->persist($teamer);
|
$this->entityManager->persist($teamer);
|
||||||
}
|
}
|
||||||
|
|
||||||
$form = $this->createForm(TeamerProfileType::class, $teamer);
|
$uploadSession = $this->uploadHandler->getUploadSession();
|
||||||
|
|
||||||
|
$form = $this->createForm(TeamerProfileType::class, $teamer, ['upload_session' => $uploadSession]);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
if ($uploadSession->getCount() > 0) {
|
||||||
|
if (null !== $existingUpload = $teamer->getPhoto()) {
|
||||||
|
$this->entityManager->remove($existingUpload);
|
||||||
|
}
|
||||||
|
$upload = Upload::fromUploadDto($uploadSession->getUploads()->first(), $user, Upload::TYPE_PHOTO);
|
||||||
|
$teamer->setPhoto($upload);
|
||||||
|
$this->uploadHandler->moveUploadSessionFilesFromOrphanage('photo', $uploadSession);
|
||||||
|
$this->uploadHandler->destroyUploadSession();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$bpnPassword = $request->getSession()->get('bpn_password');
|
$bpnPassword = $request->getSession()->get('bpn_password');
|
||||||
$this->apiClient->updateProfile($user, $bpnPassword);
|
$this->apiClient->updateProfile($user, $bpnPassword);
|
||||||
@@ -47,6 +62,8 @@ class ProfileController extends AbstractController
|
|||||||
} catch (ApiClientException $e) {
|
} catch (ApiClientException $e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
$this->addFlash('success', 'Deine Daten wurden aktualisiert');
|
$this->addFlash('success', 'Deine Daten wurden aktualisiert');
|
||||||
|
|
||||||
return $this->redirectToRoute('app_teamer_profile');
|
return $this->redirectToRoute('app_teamer_profile');
|
||||||
@@ -54,6 +71,7 @@ class ProfileController extends AbstractController
|
|||||||
|
|
||||||
return $this->render('teamer/profile.html.twig', [
|
return $this->render('teamer/profile.html.twig', [
|
||||||
'form' => $form->createView(),
|
'form' => $form->createView(),
|
||||||
|
'teamer' => $teamer,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller\Upload;
|
||||||
|
|
||||||
|
use App\Service\Upload\UploadHandler;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
|
class DeleteController extends AbstractController
|
||||||
|
{
|
||||||
|
public function __construct(private readonly UploadHandler $uploadHandler)
|
||||||
|
{}
|
||||||
|
|
||||||
|
#[Route('/upload/delete', name: 'app_upload_delete', methods: ['DELETE'])]
|
||||||
|
#[IsGranted('ROLE_USER')]
|
||||||
|
public function index(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$uuid = $request->get('uuid');
|
||||||
|
|
||||||
|
$this->uploadHandler->removeUploadFromSession($uuid);
|
||||||
|
|
||||||
|
return $this->json([
|
||||||
|
'success' => true,
|
||||||
|
'uuid' => $uuid,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ namespace App\Entity;
|
|||||||
|
|
||||||
use App\Entity\Traits\BlameableEntity;
|
use App\Entity\Traits\BlameableEntity;
|
||||||
use App\Entity\Traits\TimestampableEntity;
|
use App\Entity\Traits\TimestampableEntity;
|
||||||
|
use App\Model\UploadDto;
|
||||||
use App\Repository\UploadRepository;
|
use App\Repository\UploadRepository;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Component\Uid\Uuid;
|
use Symfony\Component\Uid\Uuid;
|
||||||
@@ -14,6 +15,8 @@ class Upload implements BlameableEntityInterface, TimestampableEntityInterface
|
|||||||
use BlameableEntity;
|
use BlameableEntity;
|
||||||
use TimestampableEntity;
|
use TimestampableEntity;
|
||||||
|
|
||||||
|
public const TYPE_PHOTO = 'photo';
|
||||||
|
|
||||||
public const STATUS_NEW = 'new';
|
public const STATUS_NEW = 'new';
|
||||||
public const STATUS_IN_PROCESS = 'in_process';
|
public const STATUS_IN_PROCESS = 'in_process';
|
||||||
public const STATUS_CHECKED = 'checked';
|
public const STATUS_CHECKED = 'checked';
|
||||||
@@ -52,6 +55,21 @@ class Upload implements BlameableEntityInterface, TimestampableEntityInterface
|
|||||||
$this->uuid = Uuid::v4();
|
$this->uuid = Uuid::v4();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function fromUploadDto(UploadDto $uploadDto, User $owner, string $type): static
|
||||||
|
{
|
||||||
|
$instance = new static();
|
||||||
|
$instance
|
||||||
|
->setFilename($uploadDto->getFilename())
|
||||||
|
->setOriginalFilename($uploadDto->getOriginalFilename())
|
||||||
|
->setMimeType($uploadDto->getMimeType())
|
||||||
|
->setSize($uploadDto->getSize())
|
||||||
|
->setOwner($owner)
|
||||||
|
->setType($type)
|
||||||
|
;
|
||||||
|
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
|
||||||
public function getId(): ?int
|
public function getId(): ?int
|
||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\EventListener;
|
||||||
|
|
||||||
|
use App\Entity\Upload;
|
||||||
|
use App\Service\Upload\UploadHandler;
|
||||||
|
use Doctrine\ORM\Event\PreRemoveEventArgs;
|
||||||
|
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
|
||||||
|
|
||||||
|
class DeleteUploadListener
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly UploadHandler $uploadHandler,
|
||||||
|
private readonly CacheManager $cacheManager
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function preRemove(PreRemoveEventArgs $eventArgs): void
|
||||||
|
{
|
||||||
|
$object = $eventArgs->getObject();
|
||||||
|
|
||||||
|
if (!$object instanceof Upload) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove uploaded original
|
||||||
|
$this->uploadHandler->removeUploadedFile($object);
|
||||||
|
|
||||||
|
// Remove potential variants from public folders
|
||||||
|
$this->cacheManager->remove($object->getFilename());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\EventListener;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\Security\Http\Event\LogoutEvent;
|
||||||
|
|
||||||
|
class LogoutListener
|
||||||
|
{
|
||||||
|
public function __construct(private readonly LoggerInterface $authenticationLogger)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onLogout(LogoutEvent $event): void
|
||||||
|
{
|
||||||
|
$this->authenticationLogger->info('Logout', [
|
||||||
|
'user' => $event->getToken()->getUserIdentifier(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\EventListener;
|
||||||
|
|
||||||
|
use App\Model\UploadDto;
|
||||||
|
use App\Service\Upload\UploadHandler;
|
||||||
|
use Oneup\UploaderBundle\Event\PostUploadEvent;
|
||||||
|
use Symfony\Component\HttpFoundation\File\File;
|
||||||
|
|
||||||
|
class UploadSessionListener
|
||||||
|
{
|
||||||
|
public function __construct(private readonly UploadHandler $uploadHandler)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onUpload(PostUploadEvent $event): void
|
||||||
|
{
|
||||||
|
$request = $event->getRequest();
|
||||||
|
/** @var File $uploadedFile */
|
||||||
|
$uploadedFile = $event->getFile();
|
||||||
|
|
||||||
|
// Get upload uuid from Dropzone request
|
||||||
|
$uuid = $request->get('uuid');
|
||||||
|
|
||||||
|
// Get original filename from Dropzone request
|
||||||
|
$originalFileName = $request->get('originalFilename');
|
||||||
|
|
||||||
|
$upload = new UploadDto(
|
||||||
|
$uuid,
|
||||||
|
$uploadedFile->getFilename(),
|
||||||
|
$originalFileName,
|
||||||
|
$uploadedFile->getMimeType(),
|
||||||
|
$uploadedFile->getSize()
|
||||||
|
);
|
||||||
|
|
||||||
|
$uploadSession = $this->uploadHandler->addUploadToSession($upload);
|
||||||
|
|
||||||
|
$response = $event->getResponse();
|
||||||
|
$response['uploadedTotalSize'] = $uploadSession->getSize();
|
||||||
|
$response['uploadedTotalFiles'] = $uploadSession->getCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\EventListener;
|
||||||
|
|
||||||
|
use App\Model\UploadSessionDto;
|
||||||
|
use App\Service\Upload\UploadHandler;
|
||||||
|
use Oneup\UploaderBundle\Event\ValidationEvent;
|
||||||
|
use Oneup\UploaderBundle\Uploader\Exception\ValidationException;
|
||||||
|
|
||||||
|
class UploadSessionValidationListener
|
||||||
|
{
|
||||||
|
public function onValidate(ValidationEvent $event): void
|
||||||
|
{
|
||||||
|
if ('upload_collection' !== $event->getType()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$request = $event->getRequest();
|
||||||
|
$session = $request->getSession();
|
||||||
|
$uploadSessionId = $request->get(UploadHandler::SESSION_KEY);
|
||||||
|
|
||||||
|
if (null === $uploadSessionId || false === $session->has(UploadHandler::SESSION_KEY)) {
|
||||||
|
throw new ValidationException('Invalid upload session');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var UploadSessionDto $uploadSession */
|
||||||
|
$uploadSession = $session->get(UploadHandler::SESSION_KEY);
|
||||||
|
|
||||||
|
if (!$uploadSession instanceof UploadSessionDto || $uploadSession->getUid() !== $uploadSessionId) {
|
||||||
|
throw new ValidationException('Invalid upload session');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,12 +3,16 @@
|
|||||||
namespace App\Form;
|
namespace App\Form;
|
||||||
|
|
||||||
use App\Entity\Teamer;
|
use App\Entity\Teamer;
|
||||||
|
use App\Model\UploadSessionDto;
|
||||||
|
use App\Service\Upload\UploadHandler;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
|
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\Form\FormView;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
class TeamerProfileType extends AbstractType
|
class TeamerProfileType extends AbstractType
|
||||||
@@ -77,10 +81,23 @@ class TeamerProfileType extends AbstractType
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function buildView(FormView $view, FormInterface $form, array $options): void
|
||||||
|
{
|
||||||
|
/** @var UploadSessionDto $uploadSession */
|
||||||
|
$uploadSession = $options['upload_session'];
|
||||||
|
$view->vars['upload_session_params'] = [
|
||||||
|
UploadHandler::SESSION_KEY => $uploadSession->getUid(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver): void
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
{
|
{
|
||||||
$resolver->setDefaults([
|
$resolver
|
||||||
'data_class' => Teamer::class,
|
->setDefaults([
|
||||||
]);
|
'data_class' => Teamer::class,
|
||||||
|
])
|
||||||
|
->setRequired(['upload_session'])
|
||||||
|
->setAllowedTypes('upload_session', UploadSessionDto::class)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Model;
|
||||||
|
|
||||||
|
class UploadDto
|
||||||
|
{
|
||||||
|
private string $uuid;
|
||||||
|
private string $filename;
|
||||||
|
private string $originalFilename;
|
||||||
|
private string $mimeType;
|
||||||
|
private int $size;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
string $uuid,
|
||||||
|
string $filename,
|
||||||
|
string $originalFilename,
|
||||||
|
string $mimeType,
|
||||||
|
int $size
|
||||||
|
) {
|
||||||
|
$this->uuid = $uuid;
|
||||||
|
$this->filename = $filename;
|
||||||
|
$this->originalFilename = $originalFilename;
|
||||||
|
$this->mimeType = $mimeType;
|
||||||
|
$this->size = $size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUuid(): string
|
||||||
|
{
|
||||||
|
return $this->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFilename(): string
|
||||||
|
{
|
||||||
|
return $this->filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOriginalFilename(): string
|
||||||
|
{
|
||||||
|
return $this->originalFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMimeType(): string
|
||||||
|
{
|
||||||
|
return $this->mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSize(): int
|
||||||
|
{
|
||||||
|
return $this->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Model;
|
||||||
|
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
use Symfony\Component\Uid\Uuid;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class UploadSessionDto
|
||||||
|
{
|
||||||
|
private string $uid;
|
||||||
|
|
||||||
|
#[Assert\Count(min: 1, minMessage: 'Bitte mindestens eine Datei hochladen')]
|
||||||
|
private Collection $uploads;
|
||||||
|
|
||||||
|
public function __construct(string $uid = null)
|
||||||
|
{
|
||||||
|
$this->uid = $uid ?? Uuid::v4();
|
||||||
|
$this->uploads = new ArrayCollection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUid(): string
|
||||||
|
{
|
||||||
|
return $this->uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addUpload(UploadDto $upload): static
|
||||||
|
{
|
||||||
|
if (false === $this->uploads->contains($upload)) {
|
||||||
|
$this->uploads[] = $upload;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeUpload(string $uuid): static
|
||||||
|
{
|
||||||
|
$uploadToRemove = $this->uploads->filter(function (UploadDto $upload) use ($uuid) {
|
||||||
|
return $uuid === $upload->getUuid();
|
||||||
|
})->first();
|
||||||
|
|
||||||
|
if (null !== $uploadToRemove) {
|
||||||
|
$this->uploads->removeElement($uploadToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUploads(): Collection
|
||||||
|
{
|
||||||
|
return $this->uploads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flushUploads(): static
|
||||||
|
{
|
||||||
|
$this->uploads->clear();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSize(): int
|
||||||
|
{
|
||||||
|
$size = 0;
|
||||||
|
|
||||||
|
foreach ($this->uploads as $upload) {
|
||||||
|
$size += $upload->getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCount(): int
|
||||||
|
{
|
||||||
|
return $this->uploads->count();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\Upload;
|
||||||
|
|
||||||
|
use App\Entity\Upload;
|
||||||
|
use App\Model\UploadDto;
|
||||||
|
use App\Model\UploadSessionDto;
|
||||||
|
use Oneup\UploaderBundle\Uploader\Orphanage\OrphanageManager;
|
||||||
|
use Symfony\Component\Filesystem\Exception\IOException;
|
||||||
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
|
||||||
|
class UploadHandler
|
||||||
|
{
|
||||||
|
public const SESSION_KEY = 'myep_upload_session';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly RequestStack $requestStack,
|
||||||
|
private readonly OrphanageManager $orphanageManager,
|
||||||
|
private readonly string $projectDir
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUploadSession(): UploadSessionDto
|
||||||
|
{
|
||||||
|
$session = $this->requestStack->getSession();
|
||||||
|
|
||||||
|
if ($session->has(self::SESSION_KEY) && null !== $session->get(self::SESSION_KEY)) {
|
||||||
|
/** @var UploadSessionDto $uploadSession */
|
||||||
|
$uploadSession = $session->get(self::SESSION_KEY);
|
||||||
|
} else {
|
||||||
|
$uploadSession = new UploadSessionDto();
|
||||||
|
$session->set(self::SESSION_KEY, $uploadSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $uploadSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroyUploadSession(): void
|
||||||
|
{
|
||||||
|
$this->requestStack->getSession()->remove(self::SESSION_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flushUploadSession(UploadSessionDto $uploadSession): void
|
||||||
|
{
|
||||||
|
$uploadSession->flushUploads();
|
||||||
|
$session = $this->requestStack->getSession();
|
||||||
|
$session->set(self::SESSION_KEY, $uploadSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addUploadToSession(UploadDto $upload): UploadSessionDto
|
||||||
|
{
|
||||||
|
$uploadSession = $this->getUploadSession();
|
||||||
|
$uploadSession->addUpload($upload);
|
||||||
|
|
||||||
|
$session = $this->requestStack->getSession();
|
||||||
|
$session->set(self::SESSION_KEY, $uploadSession);
|
||||||
|
|
||||||
|
return $uploadSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeUploadFromSession(string $filename): UploadSessionDto
|
||||||
|
{
|
||||||
|
$uploadSession = $this->getUploadSession();
|
||||||
|
$uploadSession->removeUpload($filename);
|
||||||
|
|
||||||
|
$session = $this->requestStack->getSession();
|
||||||
|
$session->set(self::SESSION_KEY, $uploadSession);
|
||||||
|
|
||||||
|
return $uploadSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function moveUploadSessionFilesFromOrphanage(string $uploader, UploadSessionDto $uploadSession): void
|
||||||
|
{
|
||||||
|
$uploadSessionFilenames = $this->getUploadSessionFilenames($uploadSession, true);
|
||||||
|
$this->moveUploads($uploader, $uploadSessionFilenames);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function moveUploads(string $uploader, array $filenames = []): array
|
||||||
|
{
|
||||||
|
$manager = $this->orphanageManager->get($uploader);
|
||||||
|
|
||||||
|
if (0 === count($filenames)) {
|
||||||
|
return $manager->uploadFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
$files = $manager->getFiles();
|
||||||
|
$files->files()->name($filenames);
|
||||||
|
|
||||||
|
return $manager->uploadFiles(iterator_to_array($files));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeUploadedFile(Upload $upload): void
|
||||||
|
{
|
||||||
|
$filepath = $this->getUploadFilepath($upload);
|
||||||
|
|
||||||
|
$filesystem = new Filesystem();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$filesystem->remove($filepath);
|
||||||
|
} catch (IOException $e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUploadSessionFilenames(UploadSessionDto $uploadSession, bool $basename = false): array
|
||||||
|
{
|
||||||
|
$uploadSessionId = $uploadSession->getUid();
|
||||||
|
|
||||||
|
return $uploadSession
|
||||||
|
->getUploads()
|
||||||
|
->map(function (UploadDto $uploadDto) use ($basename, $uploadSessionId) {
|
||||||
|
return true === $basename ? $uploadDto->getFilename() : $this->getTempUploadFilepath($uploadDto, $uploadSessionId);
|
||||||
|
})
|
||||||
|
->toArray()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUploadFilepath(Upload $upload): string
|
||||||
|
{
|
||||||
|
return sprintf('%s/uploads/%s/%s', $this->projectDir, $upload->getType(), $upload->getFilename());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTempUploadFilepath(UploadDto $uploadDto, string $uploadSessionId): string
|
||||||
|
{
|
||||||
|
$tempUploadDir = $this->getTempUploadDir($uploadSessionId);
|
||||||
|
|
||||||
|
return sprintf('%s/%s', $tempUploadDir, $uploadDto->getFilename());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTempUploadDir(string $uploadSessionId): string
|
||||||
|
{
|
||||||
|
return sprintf('%s/uploads/temp/%s', $this->projectDir, $uploadSessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\Upload;
|
||||||
|
|
||||||
|
use Oneup\UploaderBundle\Uploader\File\FileInterface;
|
||||||
|
use Oneup\UploaderBundle\Uploader\Naming\NamerInterface;
|
||||||
|
use Symfony\Component\Uid\Uuid;
|
||||||
|
|
||||||
|
class UploadNamer implements NamerInterface
|
||||||
|
{
|
||||||
|
public function name(FileInterface $file): string
|
||||||
|
{
|
||||||
|
return sprintf('%s.%s', Uuid::v4(), strtolower($file->getExtension()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,32 @@
|
|||||||
"knplabs/knp-menu-bundle": {
|
"knplabs/knp-menu-bundle": {
|
||||||
"version": "v3.2.0"
|
"version": "v3.2.0"
|
||||||
},
|
},
|
||||||
|
"liip/imagine-bundle": {
|
||||||
|
"version": "2.11",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes-contrib",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "1.8",
|
||||||
|
"ref": "d1227d002b70d1a1f941d91845fcd7ac7fbfc929"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/liip_imagine.yaml",
|
||||||
|
"config/routes/liip_imagine.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"oneup/uploader-bundle": {
|
||||||
|
"version": "4.0",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes-contrib",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "2.0",
|
||||||
|
"ref": "b19678d1535b9fe7cdf4647fd3483455e4fca458"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/oneup_uploader.yaml",
|
||||||
|
"config/routes/oneup_uploader.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
"phpunit/phpunit": {
|
"phpunit/phpunit": {
|
||||||
"version": "9.6",
|
"version": "9.6",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<div {{ stimulus_controller('upload-collection', {
|
||||||
|
'endpointUpload': endpoint_upload,
|
||||||
|
'endpointDelete': path('app_upload_delete'),
|
||||||
|
'maxFiles': 1500,
|
||||||
|
'maxFilesize': 1000,
|
||||||
|
'acceptedFiles': null,
|
||||||
|
'chunking': true,
|
||||||
|
'params': upload_session_params,
|
||||||
|
'language': {
|
||||||
|
'fileTooBig': 'uploader.file_too_big'|trans({ '{maxFilesize}': 1000 }),
|
||||||
|
'invalidFileType': 'uploader.invalid_file_type'|trans,
|
||||||
|
'maxFilesExceeded': 'uploader.max_files_exceeded'|trans({ '{maxFiles}': 1500 })
|
||||||
|
}
|
||||||
|
}) }}>
|
||||||
|
<div {{ stimulus_target('upload-collection', 'dropzone') }} class="dropzone"></div>
|
||||||
|
</div>
|
||||||
@@ -16,18 +16,18 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<form action="{{ path('app_security_login') }}" method="post">
|
<form action="{{ path('app_security_login') }}" method="post">
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<label for="username" class="block text-sm font-semibold leading-6 text-gray-900">
|
<label for="username" class="block leading-6 text-gray-900">
|
||||||
E-Mail:
|
E-Mail:
|
||||||
</label>
|
</label>
|
||||||
<input type="text" id="username" name="_username" value="{{ last_username }}" class="mt-2 appearance-none text-slate-900 bg-white rounded-md block w-full px-3 h-10 shadow-sm sm:text-sm focus:outline-none placeholder:text-slate-400 focus:ring-2 focus:ring-primary ring-1 ring-slate-200">
|
<input type="text" id="username" name="_username" value="{{ last_username }}" class="mt-2 appearance-none text-slate-900 bg-white rounded-md block w-full px-3 h-10 shadow-sm sm:text-sm focus:outline-none placeholder:text-slate-400 focus:ring-2 focus:ring-primary ring-1 ring-slate-200">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<label for="password" class="block text-sm font-semibold leading-6 text-gray-900">
|
<label for="password" class="block leading-6 text-gray-900">
|
||||||
Passwort:
|
Passwort:
|
||||||
</label>
|
</label>
|
||||||
<input type="password" id="password" name="_password" class="mt-2 appearance-none text-slate-900 bg-white rounded-md block w-full px-3 h-10 shadow-sm sm:text-sm focus:outline-none placeholder:text-slate-400 focus:ring-2 focus:ring-primary ring-1 ring-slate-200">
|
<input type="password" id="password" name="_password" class="mt-2 appearance-none text-slate-900 bg-white rounded-md block w-full px-3 h-10 shadow-sm sm:text-sm focus:outline-none placeholder:text-slate-400 focus:ring-2 focus:ring-primary ring-1 ring-slate-200">
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="inline-flex justify-center rounded-lg text-sm font-semibold py-2.5 px-4 bg-slate-900 text-white hover:bg-slate-700 w-full">
|
<button type="submit" class="btn">
|
||||||
Login
|
Login
|
||||||
</button>
|
</button>
|
||||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
|
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
{{ form_widget(form.email) }}
|
{{ form_widget(form.email) }}
|
||||||
{{ form_errors(form.email) }}
|
{{ form_errors(form.email) }}
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="inline-flex justify-center rounded-lg text-sm font-semibold py-2.5 px-4 bg-slate-900 text-white hover:bg-slate-700 w-full">
|
<button type="submit" class="btn">
|
||||||
Passwort zurückseten
|
Passwort zurückseten
|
||||||
</button>
|
</button>
|
||||||
{{ form_rest(form) }}
|
{{ form_rest(form) }}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
{{ form_start(form) }}
|
{{ form_start(form) }}
|
||||||
|
|
||||||
<div {{ stimulus_controller('tabs', {}, { 'buttonActive': 'btn--secondary' }) }}>
|
<div {{ stimulus_controller('tabs', {}, { 'buttonActive': 'btn--secondary btn--active' }) }}>
|
||||||
|
|
||||||
<div class="grid lg:grid-cols-3 gap-y-8 lg:gap-y-0 lg:gap-x-16">
|
<div class="grid lg:grid-cols-3 gap-y-8 lg:gap-y-0 lg:gap-x-16">
|
||||||
<div class="flex flex-col space-y-2">
|
<div class="flex flex-col space-y-2">
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
Bankverbindung
|
Bankverbindung
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn" {{ stimulus_target('tabs', 'button') }} {{ stimulus_action('tabs', 'select', null, { 'tab': 3 }) }}>
|
<button type="button" class="btn" {{ stimulus_target('tabs', 'button') }} {{ stimulus_action('tabs', 'select', null, { 'tab': 3 }) }}>
|
||||||
Sonstiges
|
Sonstiges/Foto
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="lg:col-span-2">
|
<div class="lg:col-span-2">
|
||||||
@@ -94,11 +94,33 @@
|
|||||||
<h3 class="text-xl font-bold pb-2">
|
<h3 class="text-xl font-bold pb-2">
|
||||||
Sonstiges
|
Sonstiges
|
||||||
</h3>
|
</h3>
|
||||||
<div class="flex flex-col space-y-4">
|
<div class="flex flex-col space-y-4 pb-8">
|
||||||
{{ form_row(form.taxId) }}
|
{{ form_row(form.taxId) }}
|
||||||
{{ form_row(form.healthInsuranceCompany) }}
|
{{ form_row(form.healthInsuranceCompany) }}
|
||||||
{{ form_row(form.remarks) }}
|
{{ form_row(form.remarks) }}
|
||||||
</div>
|
</div>
|
||||||
|
<h3 class="text-xl font-bold pb-2">
|
||||||
|
Fotoupload
|
||||||
|
</h3>
|
||||||
|
<div class="grid md:grid-cols-2 gap-8">
|
||||||
|
<div>
|
||||||
|
{% include '_partials/_upload_collection_form.html.twig' with {
|
||||||
|
'endpoint_upload': path('_uploader_upload_photo'),
|
||||||
|
'upload_session_params': form.vars.upload_session_params,
|
||||||
|
} %}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{% if teamer.photo %}
|
||||||
|
<img src="{{ asset(teamer.photo.filename | imagine_filter('profile')) }}"
|
||||||
|
class="w-full h-auto rounded-full border-2 border-primary"
|
||||||
|
alt="{{ teamer.firstName }}">
|
||||||
|
{% else %}
|
||||||
|
<svg class="w-full h-auto text-gray-300" viewBox="0 0 10 10" fill="currentColor">
|
||||||
|
<circle r="5" cx="5" cy="5"/>
|
||||||
|
</svg>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="max-w-screen-md mx-auto">
|
<div class="max-w-screen-md mx-auto">
|
||||||
|
|||||||
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 846 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 174 KiB |