From 5ee0e859035e903414c354cf97b8f9ed7080d921 Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 16:31:06 +0100 Subject: [PATCH 01/17] symlinked --- templates/themes/default/_footer.html.twig | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 templates/themes/default/_footer.html.twig diff --git a/templates/themes/default/_footer.html.twig b/templates/themes/default/_footer.html.twig deleted file mode 100644 index a7208df..0000000 --- a/templates/themes/default/_footer.html.twig +++ /dev/null @@ -1,15 +0,0 @@ -<footer class="footer"> - <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-bottom navbar-bottom"> - <div class="d-flex justify-content-xl-around"> - <div class="ms-5">powered by - <a href="#"> - <img class="mx-1" src="{{ asset('build/images/Spookie/spookie_64x64.png') }}" alt="Spookie"> - </a> - </div> - <div id="legal"> - <a href="{{ path('pages_display', { 'slug': 'imprint' }) }}">Imprint</a> - <a href="{{ path('pages_display', { 'slug': 'privacy' }) }}">Privacy Policy</a> - </div> - </div> - </nav> -</footer> \ No newline at end of file From 1d783f0cc6d273c0715fa45883b88ab74bdf6ae3 Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 16:34:59 +0100 Subject: [PATCH 02/17] symlinked default --- assets/controllers/crop_avatar_controller.js | 34 ++++ assets/controllers/hello_controller.js | 16 -- .../controllers/upload-avatar_controller.js | 158 ++++++++++++++++++ templates/themes/24unix.net/_footer.html.twig | 15 ++ templates/themes/24unix.net/_header.html.twig | 79 +++++++++ templates/themes/24unix.net/base.html.twig | 117 +++++++++++++ .../themes/24unix.net/pages/index.html.twig | 13 ++ .../24unix.net/projects/index.html.twig | 74 ++++++++ .../themes/24unix.net/projects/show.html.twig | 35 ++++ .../security/forgot_password.html.twig | 22 +++ .../24unix.net/security/login.html.twig | 60 +++++++ .../security/mail/recovery.html.twig | 9 + .../security/mail/registration.html.twig | 39 +++++ .../security/recovery_mail_sent.html.twig | 11 ++ .../24unix.net/security/register.html.twig | 60 +++++++ .../security/registration_finished.html.twig | 19 +++ .../security/resend_activation.html.twig | 20 +++ .../security/reset_password.html.twig | 12 ++ .../24unix.net/user/edit_profile.html.twig | 62 +++++++ .../24unix.net/user/list_users.html.twig | 49 ++++++ .../24unix.net/user/show_profile.html.twig | 46 +++++ 21 files changed, 934 insertions(+), 16 deletions(-) create mode 100644 assets/controllers/crop_avatar_controller.js delete mode 100644 assets/controllers/hello_controller.js create mode 100644 assets/controllers/upload-avatar_controller.js create mode 100644 templates/themes/24unix.net/_footer.html.twig create mode 100644 templates/themes/24unix.net/_header.html.twig create mode 100644 templates/themes/24unix.net/base.html.twig create mode 100644 templates/themes/24unix.net/pages/index.html.twig create mode 100644 templates/themes/24unix.net/projects/index.html.twig create mode 100644 templates/themes/24unix.net/projects/show.html.twig create mode 100644 templates/themes/24unix.net/security/forgot_password.html.twig create mode 100644 templates/themes/24unix.net/security/login.html.twig create mode 100644 templates/themes/24unix.net/security/mail/recovery.html.twig create mode 100644 templates/themes/24unix.net/security/mail/registration.html.twig create mode 100644 templates/themes/24unix.net/security/recovery_mail_sent.html.twig create mode 100644 templates/themes/24unix.net/security/register.html.twig create mode 100644 templates/themes/24unix.net/security/registration_finished.html.twig create mode 100644 templates/themes/24unix.net/security/resend_activation.html.twig create mode 100644 templates/themes/24unix.net/security/reset_password.html.twig create mode 100644 templates/themes/24unix.net/user/edit_profile.html.twig create mode 100644 templates/themes/24unix.net/user/list_users.html.twig create mode 100644 templates/themes/24unix.net/user/show_profile.html.twig diff --git a/assets/controllers/crop_avatar_controller.js b/assets/controllers/crop_avatar_controller.js new file mode 100644 index 0000000..2393657 --- /dev/null +++ b/assets/controllers/crop_avatar_controller.js @@ -0,0 +1,34 @@ +import { Controller } from '@hotwired/stimulus' +import Swal from 'sweetalert2' + +export default class extends Controller { + static values = { + cropImage: String + } + + connect() { + console.log('crop', this.cropImageValue) + window.CropAvatar = this + } + + open() { + console.log('open crop') + Swal.fire({ + title: 'Are you sure?', + text: "You won't be able to revert this!", + icon: 'warning', + showCancelButton: true, + confirmButtonColor: '#3085d6', + cancelButtonColor: '#d33', + confirmButtonText: 'Yes, delete it!', + }).then((result) => { + if (result.isConfirmed) { + Swal.fire( + 'Deleted!', + 'Your file has been deleted.', + 'success', + ) + } + }) + } +} diff --git a/assets/controllers/hello_controller.js b/assets/controllers/hello_controller.js deleted file mode 100644 index e847027..0000000 --- a/assets/controllers/hello_controller.js +++ /dev/null @@ -1,16 +0,0 @@ -import { Controller } from '@hotwired/stimulus'; - -/* - * This is an example Stimulus controller! - * - * Any element with a data-controller="hello" attribute will cause - * this controller to be executed. The name "hello" comes from the filename: - * hello_controller.js -> "hello" - * - * Delete this file or adapt it for your use! - */ -export default class extends Controller { - connect() { - this.element.textContent = 'Hello Stimulus! Edit me in assets/controllers/hello_controller.js'; - } -} diff --git a/assets/controllers/upload-avatar_controller.js b/assets/controllers/upload-avatar_controller.js new file mode 100644 index 0000000..96d9dd3 --- /dev/null +++ b/assets/controllers/upload-avatar_controller.js @@ -0,0 +1,158 @@ +import { Controller } from '@hotwired/stimulus' +import { Dropzone } from 'dropzone' +import Cropper from 'cropperjs' + +export default class extends Controller { + static values = { + avatarImage: String, + userId: Number + } + + connect() { + console.log('image', this.avatarImageValue) + console.log('id', this.userIdValue) + + /* + const formElement = document.getElementById('avatarDropzone') + const dzMessage = document.getElementsByClassName('dz-message') + formElement.style.backgroundImage = `url('${this.avatarImageValue}')` + formElement.style.backgroundRepeat = 'no-repeat' + formElement.style.backgroundPosition = 'center center' + formElement.style.backgroundSize = 'auto' + formElement.style.borderRadius = '25px' + console.log('formelement', formElement) +*/ + + console.log('init Dropzone') + let avatarDropzone = new Dropzone('#avatarDropzone', { + url: `/user/upload/avatar/${this.userIdValue}`, + avatarUrl: this.avatarImageValue, + acceptedFiles: '.jpg, .jpeg, .png, gif', + maxFiles: 1, + dictDefaultMessage: '', + init() { + avatarDropzone = this + // If the thumbnail is already in the right size on your server: + const mockFile = { name: 'Filename', size: 12345 } + const callback = null // Optional callback when it's done + const crossOrigin = null // Added to the `img` tag for crossOrigin handling + const resizeThumbnail = false // Tells Dropzone whether it should resize the image first + avatarDropzone.displayExistingFile(mockFile, avatarDropzone.options.avatarUrl, callback, crossOrigin, resizeThumbnail); + avatarDropzone.files.push(mockFile); // line missing in official docs + + /* + console.log('url', avatarDropzone.options.foo) + this.hiddenFileInput.removeAttribute('multiple') + this.on('maxfilesexceeded', (file) => { + this.removeAllFiles() + this.addFile(file) + }) + this.on('error', (file, data) => { + console.log('error') + if (data.detail) { + this.emit('error', file, data.detail) + } + }) + console.log('beforemock') + const mockFile = { name: 'Name Image', size: 12345, type: 'image/jpeg' } + this.emit('addedfile', mockFile) + this.emit('success', mockFile) + console.log('avi', this.avatarImageValue) + this.emit('thumbnail', mockFile, avatarDropzone.options.avatarUrl) + console.log('aftermock') + this.emit('complete', mockFile); + this.files.push(mockFile); + */ + }, + transformFile(file, done) { + // Create the image editor overlay + const editor = document.createElement('div') + editor.style.position = 'fixed' + editor.style.left = '25px' + editor.style.right = '25px' + editor.style.top = '25px' + editor.style.bottom = '25px' + editor.style.zIndex = '9999' + editor.style.borderRadius = '15px;' + editor.style.borderColor = '#FF8844' + editor.style.backgroundColor = '#000' + document.body.appendChild(editor) + + // Create an image node for Cropper.js + const image = new Image() + image.src = URL.createObjectURL(file) + editor.appendChild(image) + + // Create Cropper.js + const cropper = new Cropper(image, {aspectRatio: 1}) + + // Create confirm button at the top left of the viewport + const buttonCrop = document.createElement('button') + buttonCrop.style.position = 'absolute' + buttonCrop.style.right = '10px' + buttonCrop.style.bottom = '50px' + buttonCrop.style.zIndex = '9999' + buttonCrop.textContent = 'Crop' + buttonCrop.className = 'btn btn-secondary' + editor.appendChild(buttonCrop) + buttonCrop.addEventListener('click', () => { + // clear preview + //formElement.style.backgroundImage = '' + + const canvas = cropper.getCroppedCanvas({ + width: 256, + height: 256 + }) + canvas.toBlob((blob) => { + avatarDropzone.createThumbnail( + blob, + avatarDropzone.options.thumbnailWidth, + avatarDropzone.options.thumbnailHeight, + avatarDropzone.options.thumbnailMethod, + false, + (dataURL) => { + avatarDropzone.emit('thumbnail', file, dataURL) + done(blob) + } + ) + }) + + // Remove the editor from the view + document.body.removeChild(editor) + }) + + // Create keep original button + const buttonKeep = document.createElement('button') + buttonKeep.style.position = 'absolute' + buttonKeep.style.right = '100px' + buttonKeep.style.bottom = '50px' + buttonKeep.style.zIndex = '9999' + buttonKeep.textContent = 'Keep Original' + buttonKeep.className = 'btn btn-primary' + buttonKeep.focus() + editor.appendChild(buttonKeep) + buttonKeep.addEventListener('click', () => { + //formElement.style.backgroundImage = '' + + // Remove the editor from the view + this.removeAllFiles() + + done(file) + document.body.removeChild(editor) + }) + + // info text + const infoText = document.createElement('span') + infoText.style.position = 'absolute' + infoText.style.opacity = '0.5' + infoText.style.left = '100px' + infoText.style.bottom = '50px' + infoText.style.display = 'inline:block' + infoText.style.zIndex = '9999' + infoText.textContent = 'Use mouse wheel/touchpad to adapt size' + infoText.className = 'btn btn-secondary' + editor.appendChild(infoText) + } + }) + } +} diff --git a/templates/themes/24unix.net/_footer.html.twig b/templates/themes/24unix.net/_footer.html.twig new file mode 100644 index 0000000..a7208df --- /dev/null +++ b/templates/themes/24unix.net/_footer.html.twig @@ -0,0 +1,15 @@ +<footer class="footer"> + <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-bottom navbar-bottom"> + <div class="d-flex justify-content-xl-around"> + <div class="ms-5">powered by + <a href="#"> + <img class="mx-1" src="{{ asset('build/images/Spookie/spookie_64x64.png') }}" alt="Spookie"> + </a> + </div> + <div id="legal"> + <a href="{{ path('pages_display', { 'slug': 'imprint' }) }}">Imprint</a> + <a href="{{ path('pages_display', { 'slug': 'privacy' }) }}">Privacy Policy</a> + </div> + </div> + </nav> +</footer> \ No newline at end of file diff --git a/templates/themes/24unix.net/_header.html.twig b/templates/themes/24unix.net/_header.html.twig new file mode 100644 index 0000000..b99ea83 --- /dev/null +++ b/templates/themes/24unix.net/_header.html.twig @@ -0,0 +1,79 @@ +<nav + class="navbar navbar-expand-md navbar-dark sticky-top px-sm-5 border-0 {{ is_granted('ROLE_PREVIOUS_ADMIN') ? 'bg-light' : 'bg-dark' }}" +> + + <a class="navbar-brand border-0" href="{{ path('app_main') }}"> + <img src="{{ asset('build/images/24unix/24_logo_bg_64x64.png') }}" alt="24unix.net" id="site-logo"> + </a> + + <button class="navbar-toggler border-0" type="button" data-toggle="collapse" data-target="#CollapsingNavbar"> + ☰ + </button> + + <div class="collapse navbar-collapse" id="CollapsingNavbar"> + <ul class="navbar-nav ms-auto"> + <!-- + <li> + <form class="d-flex"> + <input class="form-control me-2 my-2" type="search" placeholder="Search" aria-label="Search"> + <button class="btn" type="submit">Search</button> + </form> + </li> + --> + {% if is_granted('ROLE_USER') %} + <li class="nav-item dropdown me-auto"> + <button type="button" id="navbar-dropdown" data-bs-target="#dropdown-menu" data-bs-toggle="dropdown" + class="btn btn-outline-dark dropdown-toggle button-login"> + {% if app.user.avatar %} + <img class="rounded-circle border border-primary" + width="50px" + src="{{ avatar_asset(app.user.avatar)|imagine_filter('squared_thumbnail_small') }}" + alt="profile image"/> + {% else %} + {{ app.user.username }} + {% endif %} + </button> + + <div class="dropdown-menu dropdown-menu-dark dropdown-menu-end" id="dropdown-menu" + aria-labelledby="navbar-dropdown"> + <a class="dropdown-item" href="{{ path('app_profile_edit', { 'username': app.user.username }) }}"> + <span class="fa fa-lg fa-fw fa-user" aria-hidden="true"></span> + Profile</a> + <a class="dropdown-item" href="#"> + <span class="fa fa-lg fa-fw fa-wrench" aria-hidden="true"></span> + Settings</a> + <div class="dropdown-divider"></div> + {% if is_granted('ROLE_ADMIN') %} + <a class="dropdown-item" href="{{ path('admin') }}"> + <span class="fa fa-lg fa-fw fa-cog" aria-hidden="true"></span> + Administration + </a> + <div class="dropdown-divider"></div> + {% endif %} + + {% if is_granted('ROLE_PREVIOUS_ADMIN') %} + <a class="dropdown-item" href="{{ path('app_main', { + '_switch_user': '_exit' + }) }}"> + <span class="fa fa-lg fa-fw fa-backward" aria-hidden="true"></span> + Back to Admin</a> + <div class="dropdown-divider"></div> + {% endif %} + + <a class="dropdown-item" href="{{ path('security_logout') }}"> + <span class="fa fa-lg fa-fw fa-sign-out" aria-hidden="true"></span> + Logout + </a> + </div> + </li> + {% else %} + <li class="nav-item"> + <a class="btn btn-primary button-login" href="{{ path('security_login') }}" role="button" + id="buttonLogin"> + <span class="fa fa-sign-in fa-lg fa-fw" aria-hidden="true"></span>Log In + </a> + </li> + {% endif %} + </ul> + </div> +</nav> diff --git a/templates/themes/24unix.net/base.html.twig b/templates/themes/24unix.net/base.html.twig new file mode 100644 index 0000000..9110af2 --- /dev/null +++ b/templates/themes/24unix.net/base.html.twig @@ -0,0 +1,117 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>{% block title %}Spookie{% endblock %}</title> + <link rel="icon" + href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text></svg>"> + + {% block stylesheets %} + {{ encore_entry_link_tags('app') }} + {% endblock %} + + {% block javascripts %} + {{ encore_entry_script_tags('app') }} + + <!-- Matomo --> + <script> + let _paq = window._paq = window._paq || [] + /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ + _paq.push(["trackPageView"]) + _paq.push(["enableLinkTracking"]); + (function () { + const u = "https://analytics.24unix.net/" + _paq.push(["setTrackerUrl", u + "matomo.php"]) + _paq.push(["setSiteId", "1"]) + const d = document, g = d.createElement("script"), s = d.getElementsByTagName("script")[0] + g.async = true + g.src = u + "matomo.js" + s.parentNode.insertBefore(g, s) + })() + </script> + <!-- End Matomo Code --> + {% endblock %} + +</head> +<body data-turbo="false"> + +{% include '@default/_header.html.twig' %} + +<!-- sidebar --> +<nav id="sidebar" class="m-3"> + <ul class="list-group ml1" id="main-menu"> + <li class="list-group-item list-group-item-action"> + <a href="{{ path('app_projects') }}" class="text-decoration-none"> + <span class="fa fa-lg fa-fw fa-file-code-o" aria-hidden="true" title="Projects"></span> + <span class="menuText"> Projects</span> + </a> + </li> + <li class="list-group-item list-group-item-action"> + <a href="//git.24unix.net" class="text-decoration-none" target="_blank"> + <span class="fa fa-lg fa-fw fa-gitea" aria-hidden="true" title="Gitea"></span> + <span class="menuText"> Gitea</span> + </a> + <span class="menuText"><span class="fa fa-external-link" aria-hidden="true"></span></span> + </li> + <li class="list-group-item list-group-item-action"> + <a href="//cloud.24unix.net" class="text-decoration-none" target="_blank"> + <span class="fa fa-lg fa-fw fa-nextcloud" aria-hidden="true" title="NextCloud"></span> + <span class="menuText"> NextCloud</span> + </a> + <span class="menuText"><span class="fa fa-external-link" aria-hidden="true"></span></span> + </li> + <li class="list-group-item list-group-item-action"> + <a href="#" id="toggleSidebar"> + <span id="toggleIcon" class="fa fa-lg fa-caret-square-o-left"></span> + </a> + </li> + <!-- <a href="//pastebin.24unix.net">pastebin.24unix.net</a>--> + </ul> +</nav> + +<div class="container-fluid" id="content"> + + + <div class="col m-3" id="main_content"> + + {# + <div data-turbo="false"> + {% for message in app.flashes('success') %} + <div id="react"></div> + <div + {{ stimulus_controller('toastify', { + flash: message + }) }} + > + </div> + dump(app) + {% endfor %} + </div> + #} + + {% for message in app.flashes('error') %} + <div class="alert alert-danger"> + {{ message }} + </div> + {% endfor %} + + {% block body %} + <div class="m-5"> + <h1 class="title-show">Quote of the Moment</h1> + <div class="quote-box p-3"> + <span class="fa fa-quote-left"></span><br> + {{ quote | raw | nl2br }} + </div> + </div> + {% endblock %} + </div> + +</div> + +{% include '@default/_footer.html.twig' %} + + + +</body> +</html> \ No newline at end of file diff --git a/templates/themes/24unix.net/pages/index.html.twig b/templates/themes/24unix.net/pages/index.html.twig new file mode 100644 index 0000000..7eb1db0 --- /dev/null +++ b/templates/themes/24unix.net/pages/index.html.twig @@ -0,0 +1,13 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}page_name{% endblock %} + +{% block body %} + {{ page.content | raw }} + <br> + Page created by: <a href="{{ path('app_profile', { 'username': page.owner.username }) }}">{{ page.owner.username }}</a> + {{ page.createdAt | ago }} + {% if page.modifiedAt %} + (last update: {{ page.modifiedAt | ago }}) + {% endif %} +{% endblock %} \ No newline at end of file diff --git a/templates/themes/24unix.net/projects/index.html.twig b/templates/themes/24unix.net/projects/index.html.twig new file mode 100644 index 0000000..003002d --- /dev/null +++ b/templates/themes/24unix.net/projects/index.html.twig @@ -0,0 +1,74 @@ +{# templates/projects/index.html.twig #} +{% extends '@default/base.html.twig' %} + +{% block title %} Projects {% endblock %} + +{% block body %} + <div class="container-fluid box"> + <div class="row"> + <h2>This is an overview of my current public (and open source) projects.</h2> + + <!-- projects List --> + <div class="col-sm-12"> + {% for project in projects %} + <div class="project-container bg-dark my-4"> + <div class="row"> + <div class="col-sm-3"> + <a href="{{ path('app_projects', { name: project.name }) }}"> + {% if project.teaserImage %} + <img + class="project-image" + src="/uploads/projects/{{ project.teaserImage }}" + alt="Teaser"> + {% else %} + <img + class="project-image" + src="{{ asset('build/images/24unix/24_logo_bg_96x96.png') }}" + alt="Teaser"> + {% endif %} + </a> + <br> + <div> + {% for developer in project.developer %} + <a class="align-left blog-details" + href="{{ path('app_profile', { 'username':developer.username }) }}"> + {% if developer.avatar is not null %} + <img class="rounded-circle mt-5 mb-4 ms-5" + src="{{ avatar_asset(developer.avatar)|imagine_filter('squared_thumbnail_small') }}" alt="profile image"/> + <br> + {% endif %} + <div class="ms-5 mb-4"> + <a href="{{ path('app_profile', { 'username':developer.username }) }}">{{ developer.username }}</a> + </div> + {% endfor %} + </div> + + </div> + <div class="col-sm-8 mt-2"> + <a href="{{ path('app_projects', { name: project.name }) }}"> + <div class="article-title d-inline-block pl-3 align-middle"> + <h2>{{ project.name }}</h2> + </div> + </a> + <br> + <div class="blog-teaser mb-2 pb-2 text-xl-start"> + {{ project.description }} + <br> + <br> + started: {{ project.createdAt | ago }} + </div> + </div> + </div> + + </div> + {% endfor %} + </div> + + {% if is_granted('ROLE_ADMIN') %} + <div class="text-xl-start"> + <a href="{{ path('app_main') }}"><span class="fa fa-plus-circle"></span></a> + </div> + {% endif %} + </div> + </div> +{% endblock %} \ No newline at end of file diff --git a/templates/themes/24unix.net/projects/show.html.twig b/templates/themes/24unix.net/projects/show.html.twig new file mode 100644 index 0000000..4c586f1 --- /dev/null +++ b/templates/themes/24unix.net/projects/show.html.twig @@ -0,0 +1,35 @@ +{# templates/blog/blog_show.html.twig #} +{% extends '@default/base.html.twig' %} + +{% block title %}Projects{% endblock %} + +{% block body %} + + <div class="row"> + <div class="col-sm-12"> + {% if is_granted('ROLE_ADMIN') %} + <div class="d-flex justify-content-end"> + <a href="{{ path('app_main', { id : project.id }) }}"><span class="fa fa-3x fa-fw fa-edit"></span></a> + <a href="{{ path('app_main', { id : project.id }) }}"><span class="fa fa-3x fa-fw fa-trash"></span></a> + </div> + {% endif %} + + <div class="show-article-container p-3 mt-4"> + <div class="show-article-title-container d-inline-block pl-3 align-middle"> + <h2>{{ project.name }}</h2> + </div> + <div> + Source: <a href="{{ project.url }}" target="_blank">{{ project.url }}</a> + <span class="fa fa-external-link" aria-hidden="true"></span> + </div> + <div class="row"> + <div class="col-sm-12"> + <div class="article-text"> + {{ readme | markdown_to_html }} + </div> + </div> + </div> + </div> + </div> + </div> +{% endblock %} \ No newline at end of file diff --git a/templates/themes/24unix.net/security/forgot_password.html.twig b/templates/themes/24unix.net/security/forgot_password.html.twig new file mode 100644 index 0000000..c397c08 --- /dev/null +++ b/templates/themes/24unix.net/security/forgot_password.html.twig @@ -0,0 +1,22 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}Reset your password{% endblock %} + +{% block body %} + {% for flash_error in app.flashes('reset_password_error') %} + <div class="alert alert-danger" role="alert">{{ flash_error }}</div> + {% endfor %} + <h1>Reset your password</h1> + + {{ form_start(requestForm) }} + {{ form_row(requestForm.account) }} + <div> + <small> + Enter your email address or your username and we will send you a + link to reset your password. + </small> + </div> + + <button class="btn btn-primary float-end">Send password reset email</button> + {{ form_end(requestForm) }} +{% endblock %} diff --git a/templates/themes/24unix.net/security/login.html.twig b/templates/themes/24unix.net/security/login.html.twig new file mode 100644 index 0000000..5522024 --- /dev/null +++ b/templates/themes/24unix.net/security/login.html.twig @@ -0,0 +1,60 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}Log In!{% endblock %} + +{% block body %} + <div class="container rounded"> + <div class="row"> + <div class="login-form bg-dark mt-4 p-4"> + <form method="post" class="row g-3"> + <h1 class="h3 mb-3 font-weight-normal">Please sign in</h1> + + {% if error %} + <div class="alert-dark alert-danger"> + {{ error.messageKey|trans(error.messageData, 'security') }} + </div> + {% endif %} + + + <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"> + + <div class="col-12"> + <label for="inputUsername">Username or eMail</label> + <input type="text" + name="username" + autocomplete="nickname" + id="inputUsername" + class="form-control" + value="{{ last_username }}" + required + autofocus + > + </div> + <div class="col-12"> + <label for="inputPassword">Password</label> + <input + type="password" + name="password" + autocomplete="current-password" + id="inputPassword" + class="form-control" + required + > + </div> + <div class="form-check mx-3"> + <label> + <input type="checkbox" name="_remember_me" class="form-check-input">Remember me + </label> + </div> + <div> + <a href="{{ path('security_forgot_password') }}">Forgot password?</a> + <button class="btn btn-primary float-end" type="submit"> + Sign in + </button> + </div> + <a href="{{ path('security_register') }}">Need an account? Register now.</a> + </form> + </div> + </div> + </div> +{% endblock %} diff --git a/templates/themes/24unix.net/security/mail/recovery.html.twig b/templates/themes/24unix.net/security/mail/recovery.html.twig new file mode 100644 index 0000000..a651258 --- /dev/null +++ b/templates/themes/24unix.net/security/mail/recovery.html.twig @@ -0,0 +1,9 @@ +<h1>Hi!</h1> + +<p>To reset your password, please visit the following link</p> + +<a href="{{ url('security_recovery_reset', {token: resetToken.token}) }}">Reset password</a> + +<p>This link will expire in {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }}.</p> + +<p>Cheers!</p> diff --git a/templates/themes/24unix.net/security/mail/registration.html.twig b/templates/themes/24unix.net/security/mail/registration.html.twig new file mode 100644 index 0000000..665506f --- /dev/null +++ b/templates/themes/24unix.net/security/mail/registration.html.twig @@ -0,0 +1,39 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html lang="en" style="margin:0;padding:0;"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> + <meta name="viewport" content="width=device-width, initial-scale=1"/> + <meta http-equiv="X-UA-Compatible" content="IE=edge"/> + <meta name="format-detection" content="telephone=no"/> + <title></title> + <style type="text/css"> + @media screen and (max-width: 599px) { + div { + max-width: 100% !important; + } + } + body { + background-color: #1e1f1e; + margin:25px; + padding:0; + } + </style> +</head> +<body> +<div style="border-collapse:collapse;border-spacing:0;"> + <h1>Hi {{ username }}, please confirm your email!</h1> + + <p> + Please confirm your email address by clicking the following link: <br><br> + <a href="{{ signedUrl|raw }}">Confirm my Email</a>. + <br> + This link will expire in {{ expiresAtMessageKey|trans(expiresAtMessageData, 'VerifyEmailBundle') }}. + </p> + + <p> + Kind regards, + 24unix.net + </p> +</div> +</body> +</html> diff --git a/templates/themes/24unix.net/security/recovery_mail_sent.html.twig b/templates/themes/24unix.net/security/recovery_mail_sent.html.twig new file mode 100644 index 0000000..8786623 --- /dev/null +++ b/templates/themes/24unix.net/security/recovery_mail_sent.html.twig @@ -0,0 +1,11 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}Password Reset Email Sent{% endblock %} + +{% block body %} + <p> + If an account matching your email exists, then an email was just sent that contains a link that you can use to reset your password. + This link will expire in {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }}. + </p> + <p>If you don't receive an email please check your spam folder or <a href="{{ path('security_forgot_password') }}">try again</a>.</p> +{% endblock %} diff --git a/templates/themes/24unix.net/security/register.html.twig b/templates/themes/24unix.net/security/register.html.twig new file mode 100644 index 0000000..6b3a3bc --- /dev/null +++ b/templates/themes/24unix.net/security/register.html.twig @@ -0,0 +1,60 @@ +{% extends '@default/base.html.twig' %} +{% form_theme registrationForm _self %} + +{% block title %}Register{% endblock %} + + +{% block form_row %} + {%- set widget_attr = {} -%} + {%- if help is not empty -%} + {%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%} + {%- endif -%} + + {{- form_label(form, null, { + label_attr: { class: 'sr-only' } + }) -}} + {{- form_errors(form) -}} + {{- form_widget(form, widget_attr) -}} + {{- form_help(form) -}} +{% endblock %} + + +{% block body %} + {% for flash_error in app.flashes('verify_email_error') %} + <div class="alert alert-danger" role="alert">{{ flash_error }}</div> + {% endfor %} + + <div class="container rounded"> + <div class="row"> + <div class="login-form bg-dark mt-4 p-4"> + <h1 class="h3 mb-3 font-weight-normal">Register</h1> + + {{ form_start(registrationForm, { + attr: { class: 'form-signin' } + }) }} + <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"> + {{ form_row(registrationForm.username, { + attr: { placeholder: 'User name' } + }) }} + {{ form_row(registrationForm.email, { + attr: { placeholder: 'eMail' } + }) }} + {{ form_row(registrationForm.password.first, { + attr: { placeholder: 'Password'} + }) }} + {{ form_row(registrationForm.password.second, { + attr: { placeholder: 'Confirm password'} + }) }} + + {{ form_row(registrationForm.agreeTerms) }} + + <button type="submit" class="btn btn-primary float-end">Register</button> + {{ form_end(registrationForm) }} + + </div> + </div> + </div> + +{% endblock %} + + diff --git a/templates/themes/24unix.net/security/registration_finished.html.twig b/templates/themes/24unix.net/security/registration_finished.html.twig new file mode 100644 index 0000000..5f12a74 --- /dev/null +++ b/templates/themes/24unix.net/security/registration_finished.html.twig @@ -0,0 +1,19 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}Registration finished{% endblock %} + +{% block body %} + + <div class="container rounded"> + <div class="row"> + <div class="login-form bg-dark mt-4 p-4"> + <h1 class="h3 mb-3 font-weight-normal">Registration finished</h1> + <p>You'll receive an email soon to confirm your identity.</p> + + </div> + </div> + </div> + +{% endblock %} + + diff --git a/templates/themes/24unix.net/security/resend_activation.html.twig b/templates/themes/24unix.net/security/resend_activation.html.twig new file mode 100644 index 0000000..c0e89c2 --- /dev/null +++ b/templates/themes/24unix.net/security/resend_activation.html.twig @@ -0,0 +1,20 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}Verify eMail{% endblock %} + +{% block body %} + <div class="container"> + <div class="row"> + <div class="login-form bg-dark mt-4 p-4"> + <h1 class="h3 mb-3 font-weight-normal">Verify your Email</h1> + <p> + A verification email was sent - please check it to enable your + account before logging in. + </p> + <form method="POST"> + <button type="submit" class="btn btn-primary">Re-send Email</button> + </form> + </div> + </div> + </div> +{% endblock %} diff --git a/templates/themes/24unix.net/security/reset_password.html.twig b/templates/themes/24unix.net/security/reset_password.html.twig new file mode 100644 index 0000000..ed95f9b --- /dev/null +++ b/templates/themes/24unix.net/security/reset_password.html.twig @@ -0,0 +1,12 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}Reset your password{% endblock %} + +{% block body %} + <h1>Reset your password</h1> + + {{ form_start(resetForm) }} + {{ form_row(resetForm.plainPassword) }} + <button class="btn btn-primary">Update password</button> + {{ form_end(resetForm) }} +{% endblock %} diff --git a/templates/themes/24unix.net/user/edit_profile.html.twig b/templates/themes/24unix.net/user/edit_profile.html.twig new file mode 100644 index 0000000..84d5f97 --- /dev/null +++ b/templates/themes/24unix.net/user/edit_profile.html.twig @@ -0,0 +1,62 @@ +{% extends '@default/base.html.twig' %} + +{% block title %} + Profile of {{ user.username }} +{% endblock %} + +{% block body %} + + <div class="container box rounded bg-dark mt-5 mb-5"> + {{ form_start(userForm) }} + <div class="row"> + + <div class="col-md-3 border-right"> + <div class="d-flex flex-column align-items-center text-center p-3 py-5"> + {# + {% if user.avatar is not null %} + <img class="rounded-circle mt-5 mb-4" + src="{{ avatar_asset(user.avatar)|imagine_filter('squared_thumbnail_small') }}" + alt="profile image"/> + {% endif %} + #} + + <div + class="dropzone" + id="avatarDropzone" + style="width:172px;" + {{ stimulus_controller('upload_avatar', { + avatarImage: avatar_asset(user.avatar)|imagine_filter('squared_thumbnail_small') , + userId: user.id + }) }} + > + </div> + <span class="font-weight-bold">{{ user.username }}</span> + <span class="text-white-50"><span class="fa fa-lg fa-envelope me-1"></span><a href="mailto:{{ user.email }}">{{ user.email }}</a></span> + </div> + </div> + <div class="col-md-8 border-right"> + <div class="p-3 py-5"> + <div class="d-flex justify-content-between align-items-center mb-3"> + <h4 class="text-right">User Profile</h4> + </div> + <div class="row mt-2"> + {{ form_row(userForm.username) }} + {{ form_row(userForm.firstName) }} + {{ form_row(userForm.lastName) }} + {{ form_row(userForm.email) }} + {{ form_row(userForm.newPassword.first) }} + {{ form_row(userForm.newPassword.second) }} + {{ form_rest(userForm) }} + </div> + <div class="mb-5 text-center float-end"> + <button class="btn btn-primary profile-button" type="submit">Save Profile</button> + </div> + </div> + </div> + </div> + {{ form_end(userForm) }} + + + </div> + +{% endblock %} diff --git a/templates/themes/24unix.net/user/list_users.html.twig b/templates/themes/24unix.net/user/list_users.html.twig new file mode 100644 index 0000000..7893a17 --- /dev/null +++ b/templates/themes/24unix.net/user/list_users.html.twig @@ -0,0 +1,49 @@ +{% extends '@default/base.html.twig' %} + +{% block title %} + Userlist +{% endblock %} + +{% block body %} + + + <div class="container box rounded bg-dark mt-5 mb-5"> + <div class="row"> + <table class="table table-striped"> + <thead> + <tr> + <th scope="col">Username</th> + <th scope="col">First</th> + <th scope="col">Last</th> + <th scope="col">eMail</th> + <th scope="col">Registered</th> + <th scope="col">Manage</th> + </tr> + </thead> + {% for user in users %} + <tr> + <td> + <a href="{{ path('app_main', { '_switch_user': user.username }) }}">{{ user.username }}</a> + </td> + <td> + {{ user.firstName }} + </td> + <td> + {{ user.lastName }} + </td> + <td> + {{ user.email }} + </td> + <td> + {{ user.createdAt|ago }} + </td> + <td> + <button type="button" class="btn btn-outline-primary btn-lg btn-circle ml-2"><i class="fa fa-edit"></i> </button> + </td> + + </tr> + {% endfor %} + </table> + </div> + </div> +{% endblock %} diff --git a/templates/themes/24unix.net/user/show_profile.html.twig b/templates/themes/24unix.net/user/show_profile.html.twig new file mode 100644 index 0000000..55b038c --- /dev/null +++ b/templates/themes/24unix.net/user/show_profile.html.twig @@ -0,0 +1,46 @@ +{% extends '@default/base.html.twig' %} + +{% block title %} + Profile of {{ user.username }} +{% endblock %} + +{% block body %} + + <div class="container box rounded bg-dark mt-5 mb-5"> + <div class="row"> + <div class="col-md-3 border-right"> + <div class="d-flex flex-column align-items-center text-center p-3 py-5"> + {% if user.avatar is not null %} + <img class="rounded-circle mt-5 mb-4" + src="{{ avatar_asset(user.avatar)|imagine_filter('squared_thumbnail_small') }}" + alt="profile image"/> + {% endif %} + <span class="font-weight-bold">{{ user.username }}</span> + {% if is_granted('ROLE_ADMIN') %} + <span class="font-weight-bold"> + <a href="{{ path('app_main', { '_switch_user': user.username }) }}">switch user</a> + </span> + {% endif %} + + <span class="text-white-50"><i class="fa fa-lg fa-envelope me-1"></i><a href="mailto:{{ user.email }}">{{ user.email }}</a></span> + </div> + </div> + <div class="col-md-5 border-right"> + <div class="p-3 py-5"> + <div class="d-flex justify-content-between align-items-center mb-3"> + <h4 class="text-right">User Profile</h4> + </div> + <div class="row mt-2"> + <label class="labels" for="first-name">First Name</label> + <input type="text" disabled id="first-name" class="form-control" value="{{ user.firstName }}"> + + <label class="labels" for="last-name">Last Name</label> + <input type="text" disabled id="last-name" class="form-control" value="{{ user.lastName }}"> + </div> + </div> + </div> + </div> + </div> + + +{% endblock %} From d9b86de4bb576fabbd0b11a0d5c22e8032a84bfe Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 16:39:18 +0100 Subject: [PATCH 03/17] symlinked default --- templates/themes/default | 1 + templates/themes/default/_header.html.twig | 68 ------------ templates/themes/default/base.html.twig | 105 ------------------ .../themes/default/pages/index.html.twig | 13 --- .../themes/default/projects/index.html.twig | 74 ------------ .../themes/default/projects/show.html.twig | 35 ------ .../security/forgot_password.html.twig | 22 ---- .../themes/default/security/login.html.twig | 46 -------- .../default/security/mail/recovery.html.twig | 9 -- .../security/mail/registration.html.twig | 39 ------- .../security/recovery_mail_sent.html.twig | 11 -- .../default/security/register.html.twig | 60 ---------- .../security/registration_finished.html.twig | 19 ---- .../security/resend_activation.html.twig | 20 ---- .../default/security/reset_password.html.twig | 12 -- .../default/user/edit_profile.html.twig | 55 --------- .../themes/default/user/list_users.html.twig | 49 -------- .../default/user/show_profile.html.twig | 63 ----------- 18 files changed, 1 insertion(+), 700 deletions(-) create mode 120000 templates/themes/default delete mode 100644 templates/themes/default/_header.html.twig delete mode 100644 templates/themes/default/base.html.twig delete mode 100644 templates/themes/default/pages/index.html.twig delete mode 100644 templates/themes/default/projects/index.html.twig delete mode 100644 templates/themes/default/projects/show.html.twig delete mode 100644 templates/themes/default/security/forgot_password.html.twig delete mode 100644 templates/themes/default/security/login.html.twig delete mode 100644 templates/themes/default/security/mail/recovery.html.twig delete mode 100644 templates/themes/default/security/mail/registration.html.twig delete mode 100644 templates/themes/default/security/recovery_mail_sent.html.twig delete mode 100644 templates/themes/default/security/register.html.twig delete mode 100644 templates/themes/default/security/registration_finished.html.twig delete mode 100644 templates/themes/default/security/resend_activation.html.twig delete mode 100644 templates/themes/default/security/reset_password.html.twig delete mode 100644 templates/themes/default/user/edit_profile.html.twig delete mode 100644 templates/themes/default/user/list_users.html.twig delete mode 100644 templates/themes/default/user/show_profile.html.twig diff --git a/templates/themes/default b/templates/themes/default new file mode 120000 index 0000000..be2ab77 --- /dev/null +++ b/templates/themes/default @@ -0,0 +1 @@ +24unix.net \ No newline at end of file diff --git a/templates/themes/default/_header.html.twig b/templates/themes/default/_header.html.twig deleted file mode 100644 index de4e893..0000000 --- a/templates/themes/default/_header.html.twig +++ /dev/null @@ -1,68 +0,0 @@ -<nav class="navbar navbar-expand-md navbar-dark bg-dark sticky-top px-sm-5 border-0"> - - <a class="navbar-brand border-0" href="{{ path('app_main') }}"> - <img src="{{ asset('build/images/24unix/24_logo_bg_64x64.png') }}" alt="24unix.net" id="site-logo"> - </a> - - <button class="navbar-toggler border-0" type="button" data-toggle="collapse" data-target="#CollapsingNavbar"> - ☰ - </button> - - <div class="collapse navbar-collapse" id="CollapsingNavbar"> - <ul class="navbar-nav ms-auto"> - <!-- - <li> - <form class="d-flex"> - <input class="form-control me-2 my-2" type="search" placeholder="Search" aria-label="Search"> - <button class="btn" type="submit">Search</button> - </form> - </li> - --> - {% if is_granted('ROLE_USER') %} - <li class="nav-item dropdown me-auto"> - <button type="button" id="navbar-dropdown" data-bs-target="#dropdown-menu" data-bs-toggle="dropdown" - class="btn btn-outline-dark dropdown-toggle button-login"> - {% if app.user.avatar %} - <img class="rounded-circle" - width="50px" - src="{{ avatar_asset(app.user.avatar)|imagine_filter('squared_thumbnail_small') }}" - alt="profile image"/> - {% else %} - {{ app.user.username }} - {% endif %} - </button> - - <div class="dropdown-menu dropdown-menu-dark dropdown-menu-end" id="dropdown-menu" - aria-labelledby="navbar-dropdown"> - <a class="dropdown-item" href="{{ path('app_profile_edit') }}"> - <span class="fa fa-lg fa-fw fa-user" aria-hidden="true"></span> - Profile</a> - <a class="dropdown-item" href="#"> - <span class="fa fa-lg fa-fw fa-wrench" aria-hidden="true"></span> - Settings</a> - <div class="dropdown-divider"></div> - {% if is_granted('ROLE_ADMIN') %} - <a class="dropdown-item" href="{{ path('admin') }}"> - <span class="fa fa-lg fa-fw fa-cog" aria-hidden="true"></span> - Administration - </a> - <div class="dropdown-divider"></div> - {% endif %} - - <a class="dropdown-item" href="{{ path('security_logout') }}"> - <span class="fa fa-lg fa-fw fa-sign-out" aria-hidden="true"></span> - Logout - </a> - </div> - </li> - {% else %} - <li class="nav-item"> - <a class="btn btn-primary button-login" href="{{ path('security_login') }}" role="button" - id="buttonLogin"> - <span class="fa fa-sign-in fa-lg fa-fw" aria-hidden="true"></span>Log In - </a> - </li> - {% endif %} - </ul> - </div> -</nav> diff --git a/templates/themes/default/base.html.twig b/templates/themes/default/base.html.twig deleted file mode 100644 index 2036b29..0000000 --- a/templates/themes/default/base.html.twig +++ /dev/null @@ -1,105 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>{% block title %}Spookie{% endblock %}</title> - <link rel="icon" - href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text></svg>"> - - {% block stylesheets %} - {{ encore_entry_link_tags('app') }} - {% endblock %} - - {% block javascripts %} - {{ encore_entry_script_tags('app') }} - - <!-- Matomo --> - <script> - let _paq = window._paq = window._paq || [] - /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ - _paq.push(["trackPageView"]) - _paq.push(["enableLinkTracking"]); - (function () { - const u = "https://analytics.24unix.net/" - _paq.push(["setTrackerUrl", u + "matomo.php"]) - _paq.push(["setSiteId", "1"]) - const d = document, g = d.createElement("script"), s = d.getElementsByTagName("script")[0] - g.async = true - g.src = u + "matomo.js" - s.parentNode.insertBefore(g, s) - })() - </script> - <!-- End Matomo Code --> - {% endblock %} -</head> -<body> - -{% include '@default/_header.html.twig' %} - -<!-- sidebar --> -<nav id="sidebar" class="m-3"> - <ul class="list-group ml1" id="main-menu"> - <li class="list-group-item list-group-item-action"> - <a href="{{ path('app_projects') }}" class="text-decoration-none"> - <span class="fa fa-lg fa-fw fa-file-code-o" aria-hidden="true" title="Projects"></span> - <span class="menuText"> Projects</span> - </a> - </li> - <li class="list-group-item list-group-item-action"> - <a href="//git.24unix.net" class="text-decoration-none" target="_blank"> - <span class="fa fa-lg fa-fw fa-gitea" aria-hidden="true" title="Gitea"></span> - <span class="menuText"> Gitea</span> - </a> - <span class="menuText"><span class="fa fa-external-link" aria-hidden="true"></span></span> - </li> - <li class="list-group-item list-group-item-action"> - <a href="//cloud.24unix.net" class="text-decoration-none" target="_blank"> - <span class="fa fa-lg fa-fw fa-nextcloud" aria-hidden="true" title="NextCloud"></span> - <span class="menuText"> NextCloud</span> - </a> - <span class="menuText"><span class="fa fa-external-link" aria-hidden="true"></span></span> - </li> - <li class="list-group-item list-group-item-action"> - <a href="#" id="toggleSidebar"> - <span id="toggleIcon" class="fa fa-lg fa-caret-square-o-left"></span> - </a> - </li> - <!-- <a href="//pastebin.24unix.net">pastebin.24unix.net</a>--> - </ul> -</nav> - -<div class="container-fluid" id="content"> - - - <div class="col m-3" id="main_content"> - - {% for message in app.flashes('success') %} - <div class="alert alert-success"> - {{ message }} - </div> - {% endfor %} - - {% for message in app.flashes('error') %} - <div class="alert alert-danger"> - {{ message }} - </div> - {% endfor %} - - {% block body %} - <div class="m-5"> - <h1 class="title-show">Quote of the Moment</h1> - <div class="quote-box p-3"> - <span class="fa fa-quote-left"></span><br> - {{ quote | raw | nl2br }} - </div> - </div> - {% endblock %} - </div> - -</div> - -{% include '@default/_footer.html.twig' %} - -</body> -</html> \ No newline at end of file diff --git a/templates/themes/default/pages/index.html.twig b/templates/themes/default/pages/index.html.twig deleted file mode 100644 index 7eb1db0..0000000 --- a/templates/themes/default/pages/index.html.twig +++ /dev/null @@ -1,13 +0,0 @@ -{% extends '@default/base.html.twig' %} - -{% block title %}page_name{% endblock %} - -{% block body %} - {{ page.content | raw }} - <br> - Page created by: <a href="{{ path('app_profile', { 'username': page.owner.username }) }}">{{ page.owner.username }}</a> - {{ page.createdAt | ago }} - {% if page.modifiedAt %} - (last update: {{ page.modifiedAt | ago }}) - {% endif %} -{% endblock %} \ No newline at end of file diff --git a/templates/themes/default/projects/index.html.twig b/templates/themes/default/projects/index.html.twig deleted file mode 100644 index 003002d..0000000 --- a/templates/themes/default/projects/index.html.twig +++ /dev/null @@ -1,74 +0,0 @@ -{# templates/projects/index.html.twig #} -{% extends '@default/base.html.twig' %} - -{% block title %} Projects {% endblock %} - -{% block body %} - <div class="container-fluid box"> - <div class="row"> - <h2>This is an overview of my current public (and open source) projects.</h2> - - <!-- projects List --> - <div class="col-sm-12"> - {% for project in projects %} - <div class="project-container bg-dark my-4"> - <div class="row"> - <div class="col-sm-3"> - <a href="{{ path('app_projects', { name: project.name }) }}"> - {% if project.teaserImage %} - <img - class="project-image" - src="/uploads/projects/{{ project.teaserImage }}" - alt="Teaser"> - {% else %} - <img - class="project-image" - src="{{ asset('build/images/24unix/24_logo_bg_96x96.png') }}" - alt="Teaser"> - {% endif %} - </a> - <br> - <div> - {% for developer in project.developer %} - <a class="align-left blog-details" - href="{{ path('app_profile', { 'username':developer.username }) }}"> - {% if developer.avatar is not null %} - <img class="rounded-circle mt-5 mb-4 ms-5" - src="{{ avatar_asset(developer.avatar)|imagine_filter('squared_thumbnail_small') }}" alt="profile image"/> - <br> - {% endif %} - <div class="ms-5 mb-4"> - <a href="{{ path('app_profile', { 'username':developer.username }) }}">{{ developer.username }}</a> - </div> - {% endfor %} - </div> - - </div> - <div class="col-sm-8 mt-2"> - <a href="{{ path('app_projects', { name: project.name }) }}"> - <div class="article-title d-inline-block pl-3 align-middle"> - <h2>{{ project.name }}</h2> - </div> - </a> - <br> - <div class="blog-teaser mb-2 pb-2 text-xl-start"> - {{ project.description }} - <br> - <br> - started: {{ project.createdAt | ago }} - </div> - </div> - </div> - - </div> - {% endfor %} - </div> - - {% if is_granted('ROLE_ADMIN') %} - <div class="text-xl-start"> - <a href="{{ path('app_main') }}"><span class="fa fa-plus-circle"></span></a> - </div> - {% endif %} - </div> - </div> -{% endblock %} \ No newline at end of file diff --git a/templates/themes/default/projects/show.html.twig b/templates/themes/default/projects/show.html.twig deleted file mode 100644 index 4c586f1..0000000 --- a/templates/themes/default/projects/show.html.twig +++ /dev/null @@ -1,35 +0,0 @@ -{# templates/blog/blog_show.html.twig #} -{% extends '@default/base.html.twig' %} - -{% block title %}Projects{% endblock %} - -{% block body %} - - <div class="row"> - <div class="col-sm-12"> - {% if is_granted('ROLE_ADMIN') %} - <div class="d-flex justify-content-end"> - <a href="{{ path('app_main', { id : project.id }) }}"><span class="fa fa-3x fa-fw fa-edit"></span></a> - <a href="{{ path('app_main', { id : project.id }) }}"><span class="fa fa-3x fa-fw fa-trash"></span></a> - </div> - {% endif %} - - <div class="show-article-container p-3 mt-4"> - <div class="show-article-title-container d-inline-block pl-3 align-middle"> - <h2>{{ project.name }}</h2> - </div> - <div> - Source: <a href="{{ project.url }}" target="_blank">{{ project.url }}</a> - <span class="fa fa-external-link" aria-hidden="true"></span> - </div> - <div class="row"> - <div class="col-sm-12"> - <div class="article-text"> - {{ readme | markdown_to_html }} - </div> - </div> - </div> - </div> - </div> - </div> -{% endblock %} \ No newline at end of file diff --git a/templates/themes/default/security/forgot_password.html.twig b/templates/themes/default/security/forgot_password.html.twig deleted file mode 100644 index c397c08..0000000 --- a/templates/themes/default/security/forgot_password.html.twig +++ /dev/null @@ -1,22 +0,0 @@ -{% extends '@default/base.html.twig' %} - -{% block title %}Reset your password{% endblock %} - -{% block body %} - {% for flash_error in app.flashes('reset_password_error') %} - <div class="alert alert-danger" role="alert">{{ flash_error }}</div> - {% endfor %} - <h1>Reset your password</h1> - - {{ form_start(requestForm) }} - {{ form_row(requestForm.account) }} - <div> - <small> - Enter your email address or your username and we will send you a - link to reset your password. - </small> - </div> - - <button class="btn btn-primary float-end">Send password reset email</button> - {{ form_end(requestForm) }} -{% endblock %} diff --git a/templates/themes/default/security/login.html.twig b/templates/themes/default/security/login.html.twig deleted file mode 100644 index 869a19c..0000000 --- a/templates/themes/default/security/login.html.twig +++ /dev/null @@ -1,46 +0,0 @@ -{% extends '@default/base.html.twig' %} - -{% block title %}Log In!{% endblock %} - -{% block body %} - <div class="container rounded"> - <div class="row"> - <div class="login-form bg-dark mt-4 p-4"> - <form method="post" class="row g-3"> - <h1 class="h3 mb-3 font-weight-normal">Please sign in</h1> - - {% if error %} - <div class="alert-dark alert-danger"> - {{ error.messageKey|trans(error.messageData, 'security') }} - </div> - {% endif %} - - - <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"> - - <div class="col-12"> - <label for="inputUsername">Username or eMail</label> - <input type="text" name="username" id="inputUsername" - class="form-control" {# value="{{ last_username }}" #} required autofocus> - </div> - <div class="col-12"> - <label for="inputPassword">Password</label> - <input type="password" name="password" id="inputPassword" class="form-control" required> - </div> - <div class="form-check mx-3"> - <label> - <input type="checkbox" name="_remember_me" class="form-check-input">Remember me - </label> - </div> - <div> - <a href="{{ path('security_forgot_password') }}">Forgot password?</a> - <button class="btn btn-primary float-end" type="submit"> - Sign in - </button> - </div> - <a href="{{ path('security_register') }}">Need an account? Register now.</a> - </form> - </div> - </div> - </div> -{% endblock %} diff --git a/templates/themes/default/security/mail/recovery.html.twig b/templates/themes/default/security/mail/recovery.html.twig deleted file mode 100644 index a651258..0000000 --- a/templates/themes/default/security/mail/recovery.html.twig +++ /dev/null @@ -1,9 +0,0 @@ -<h1>Hi!</h1> - -<p>To reset your password, please visit the following link</p> - -<a href="{{ url('security_recovery_reset', {token: resetToken.token}) }}">Reset password</a> - -<p>This link will expire in {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }}.</p> - -<p>Cheers!</p> diff --git a/templates/themes/default/security/mail/registration.html.twig b/templates/themes/default/security/mail/registration.html.twig deleted file mode 100644 index 665506f..0000000 --- a/templates/themes/default/security/mail/registration.html.twig +++ /dev/null @@ -1,39 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -<html lang="en" style="margin:0;padding:0;"> -<head> - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> - <meta name="viewport" content="width=device-width, initial-scale=1"/> - <meta http-equiv="X-UA-Compatible" content="IE=edge"/> - <meta name="format-detection" content="telephone=no"/> - <title></title> - <style type="text/css"> - @media screen and (max-width: 599px) { - div { - max-width: 100% !important; - } - } - body { - background-color: #1e1f1e; - margin:25px; - padding:0; - } - </style> -</head> -<body> -<div style="border-collapse:collapse;border-spacing:0;"> - <h1>Hi {{ username }}, please confirm your email!</h1> - - <p> - Please confirm your email address by clicking the following link: <br><br> - <a href="{{ signedUrl|raw }}">Confirm my Email</a>. - <br> - This link will expire in {{ expiresAtMessageKey|trans(expiresAtMessageData, 'VerifyEmailBundle') }}. - </p> - - <p> - Kind regards, - 24unix.net - </p> -</div> -</body> -</html> diff --git a/templates/themes/default/security/recovery_mail_sent.html.twig b/templates/themes/default/security/recovery_mail_sent.html.twig deleted file mode 100644 index 8786623..0000000 --- a/templates/themes/default/security/recovery_mail_sent.html.twig +++ /dev/null @@ -1,11 +0,0 @@ -{% extends '@default/base.html.twig' %} - -{% block title %}Password Reset Email Sent{% endblock %} - -{% block body %} - <p> - If an account matching your email exists, then an email was just sent that contains a link that you can use to reset your password. - This link will expire in {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }}. - </p> - <p>If you don't receive an email please check your spam folder or <a href="{{ path('security_forgot_password') }}">try again</a>.</p> -{% endblock %} diff --git a/templates/themes/default/security/register.html.twig b/templates/themes/default/security/register.html.twig deleted file mode 100644 index 6b3a3bc..0000000 --- a/templates/themes/default/security/register.html.twig +++ /dev/null @@ -1,60 +0,0 @@ -{% extends '@default/base.html.twig' %} -{% form_theme registrationForm _self %} - -{% block title %}Register{% endblock %} - - -{% block form_row %} - {%- set widget_attr = {} -%} - {%- if help is not empty -%} - {%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%} - {%- endif -%} - - {{- form_label(form, null, { - label_attr: { class: 'sr-only' } - }) -}} - {{- form_errors(form) -}} - {{- form_widget(form, widget_attr) -}} - {{- form_help(form) -}} -{% endblock %} - - -{% block body %} - {% for flash_error in app.flashes('verify_email_error') %} - <div class="alert alert-danger" role="alert">{{ flash_error }}</div> - {% endfor %} - - <div class="container rounded"> - <div class="row"> - <div class="login-form bg-dark mt-4 p-4"> - <h1 class="h3 mb-3 font-weight-normal">Register</h1> - - {{ form_start(registrationForm, { - attr: { class: 'form-signin' } - }) }} - <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"> - {{ form_row(registrationForm.username, { - attr: { placeholder: 'User name' } - }) }} - {{ form_row(registrationForm.email, { - attr: { placeholder: 'eMail' } - }) }} - {{ form_row(registrationForm.password.first, { - attr: { placeholder: 'Password'} - }) }} - {{ form_row(registrationForm.password.second, { - attr: { placeholder: 'Confirm password'} - }) }} - - {{ form_row(registrationForm.agreeTerms) }} - - <button type="submit" class="btn btn-primary float-end">Register</button> - {{ form_end(registrationForm) }} - - </div> - </div> - </div> - -{% endblock %} - - diff --git a/templates/themes/default/security/registration_finished.html.twig b/templates/themes/default/security/registration_finished.html.twig deleted file mode 100644 index 5f12a74..0000000 --- a/templates/themes/default/security/registration_finished.html.twig +++ /dev/null @@ -1,19 +0,0 @@ -{% extends '@default/base.html.twig' %} - -{% block title %}Registration finished{% endblock %} - -{% block body %} - - <div class="container rounded"> - <div class="row"> - <div class="login-form bg-dark mt-4 p-4"> - <h1 class="h3 mb-3 font-weight-normal">Registration finished</h1> - <p>You'll receive an email soon to confirm your identity.</p> - - </div> - </div> - </div> - -{% endblock %} - - diff --git a/templates/themes/default/security/resend_activation.html.twig b/templates/themes/default/security/resend_activation.html.twig deleted file mode 100644 index c0e89c2..0000000 --- a/templates/themes/default/security/resend_activation.html.twig +++ /dev/null @@ -1,20 +0,0 @@ -{% extends '@default/base.html.twig' %} - -{% block title %}Verify eMail{% endblock %} - -{% block body %} - <div class="container"> - <div class="row"> - <div class="login-form bg-dark mt-4 p-4"> - <h1 class="h3 mb-3 font-weight-normal">Verify your Email</h1> - <p> - A verification email was sent - please check it to enable your - account before logging in. - </p> - <form method="POST"> - <button type="submit" class="btn btn-primary">Re-send Email</button> - </form> - </div> - </div> - </div> -{% endblock %} diff --git a/templates/themes/default/security/reset_password.html.twig b/templates/themes/default/security/reset_password.html.twig deleted file mode 100644 index ed95f9b..0000000 --- a/templates/themes/default/security/reset_password.html.twig +++ /dev/null @@ -1,12 +0,0 @@ -{% extends '@default/base.html.twig' %} - -{% block title %}Reset your password{% endblock %} - -{% block body %} - <h1>Reset your password</h1> - - {{ form_start(resetForm) }} - {{ form_row(resetForm.plainPassword) }} - <button class="btn btn-primary">Update password</button> - {{ form_end(resetForm) }} -{% endblock %} diff --git a/templates/themes/default/user/edit_profile.html.twig b/templates/themes/default/user/edit_profile.html.twig deleted file mode 100644 index e1e28c1..0000000 --- a/templates/themes/default/user/edit_profile.html.twig +++ /dev/null @@ -1,55 +0,0 @@ -{% extends '@default/base.html.twig' %} - -{% block title %} - Profile of {{ user.username }} -{% endblock %} - -{% block body %} - - <div class="container box rounded bg-dark mt-5 mb-5"> - - <div class="row"> - <div class="col-md-3 border-right"> - <div class="d-flex flex-column align-items-center text-center p-3 py-5"> - {% if user.avatar is not null %} - <img class="rounded-circle mt-5 mb-4" - src="{{ avatar_asset(user.avatar)|imagine_filter('squared_thumbnail_small') }}" - alt="profile image"/> - {% endif %} - {# {{ form_row(userForm.avatarName, { 'label': false }) }} #} - <form - action="{{ path('user_upload_avatar', { id: user.id}) }}" - method="POST" - enctype="multipart/form-data" - class="dropzone" id="dropzoneForm"> - </form> - <div id="preview-content">{{ avatar_asset(user.avatar)|imagine_filter('squared_thumbnail_small') }}</div> - <span class="font-weight-bold">{{ user.username }}</span> - <span class="text-white-50"><span class="fa fa-lg fa-envelope me-1"></span>{{ user.email }}</span> - </div> - </div> - <div class="col-md-8 border-right"> - <div class="p-3 py-5"> - <div class="d-flex justify-content-between align-items-center mb-3"> - <h4 class="text-right">User Profile</h4> - </div> - <div class="row mt-2"> - {{ form_start(userForm) }} - {{ form_row(userForm.username) }} - {{ form_row(userForm.firstName) }} - {{ form_row(userForm.lastName) }} - {{ form_row(userForm.email) }} - {{ form_row(userForm.newPassword.first) }} - {{ form_row(userForm.newPassword.second) }} - {{ form_rest(userForm) }} - {{ form_end(userForm) }} - </div> - <div class="mb-5 text-center float-end"> - <button class="btn btn-primary profile-button" type="submit">Save Profile</button> - </div> - </div> - </div> - </div> - </div> - -{% endblock %} diff --git a/templates/themes/default/user/list_users.html.twig b/templates/themes/default/user/list_users.html.twig deleted file mode 100644 index 7893a17..0000000 --- a/templates/themes/default/user/list_users.html.twig +++ /dev/null @@ -1,49 +0,0 @@ -{% extends '@default/base.html.twig' %} - -{% block title %} - Userlist -{% endblock %} - -{% block body %} - - - <div class="container box rounded bg-dark mt-5 mb-5"> - <div class="row"> - <table class="table table-striped"> - <thead> - <tr> - <th scope="col">Username</th> - <th scope="col">First</th> - <th scope="col">Last</th> - <th scope="col">eMail</th> - <th scope="col">Registered</th> - <th scope="col">Manage</th> - </tr> - </thead> - {% for user in users %} - <tr> - <td> - <a href="{{ path('app_main', { '_switch_user': user.username }) }}">{{ user.username }}</a> - </td> - <td> - {{ user.firstName }} - </td> - <td> - {{ user.lastName }} - </td> - <td> - {{ user.email }} - </td> - <td> - {{ user.createdAt|ago }} - </td> - <td> - <button type="button" class="btn btn-outline-primary btn-lg btn-circle ml-2"><i class="fa fa-edit"></i> </button> - </td> - - </tr> - {% endfor %} - </table> - </div> - </div> -{% endblock %} diff --git a/templates/themes/default/user/show_profile.html.twig b/templates/themes/default/user/show_profile.html.twig deleted file mode 100644 index abf06e0..0000000 --- a/templates/themes/default/user/show_profile.html.twig +++ /dev/null @@ -1,63 +0,0 @@ -{% extends '@default/base.html.twig' %} - -{% block title %} - Profile of {{ user.username }} -{% endblock %} - -{% block body %} - - <div class="container box rounded bg-dark mt-5 mb-5"> - <div class="row"> - <div class="col-md-3 border-right"> - <div class="d-flex flex-column align-items-center text-center p-3 py-5"> - {% if user.avatar is not null %} - <img class="rounded-circle mt-5 mb-4" - src="{{ avatar_asset(user.avatar)|imagine_filter('squared_thumbnail_small') }}" alt="profile image"/> - {% endif %} - <span class="font-weight-bold">{{ user.username }}</span> - {% if is_granted('ROLE_ADMIN') %} - <span class="font-weight-bold"> - <a href="{{ path('app_main', { '_switch_user': app.user.username }) }}">switch user {{ user.username }}</a> - </span> - {% endif %} - - <span class="text-white-50"><i class="fa fa-lg fa-envelope me-1"></i>{{ user.email }}</span> - </div> - </div> - <div class="col-md-5 border-right"> - <div class="p-3 py-5"> - <div class="d-flex justify-content-between align-items-center mb-3"> - <h4 class="text-right">User Profile</h4> - </div> - <div class="row mt-2"> - <div class="col-md-6"> - <label class="labels" for="first-name">First Name</label> - <input type="text" disabled id="first-name" class="form-control" placeholder="First Name" - value="{{ user.firstName }}"> - </div> - - <div class="col-md-6"> - <label class="labels" for="last-name">Last Name</label> - <input type="text" disabled id="last-name" class="form-control" value="{{ user.lastName }}" - placeholder="Last Name"> - </div> - - <div class="col-md-6"> - <label class="labels" for="username">Username</label> - <input type="text" disabled class="form-control" id="username" placeholder="eMail address" - value="{{ user.email }}"> - </div> - </div> - - <!-- - <div class="mt-5 text-center"> - <button class="btn btn-primary profile-button" type="button">Save Profile</button> - </div> - --> - </div> - </div> - </div> - </div> - - -{% endblock %} From 3a322a707481d1df185e2d7d28d2a1bc8ca9a11a Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 16:43:20 +0100 Subject: [PATCH 04/17] symlinked --- templates/themes/24unix.net/pages/index.html.twig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/themes/24unix.net/pages/index.html.twig b/templates/themes/24unix.net/pages/index.html.twig index 7eb1db0..f0f6b6f 100644 --- a/templates/themes/24unix.net/pages/index.html.twig +++ b/templates/themes/24unix.net/pages/index.html.twig @@ -10,4 +10,5 @@ {% if page.modifiedAt %} (last update: {{ page.modifiedAt | ago }}) {% endif %} -{% endblock %} \ No newline at end of file +{% endblock %} + From 4deaf39e899c33c48b6229d1c747a0c3eaca5e38 Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 16:59:31 +0100 Subject: [PATCH 05/17] symlinked --- .../controllers/upload-avatar_controller.js | 51 ++++--------------- 1 file changed, 9 insertions(+), 42 deletions(-) diff --git a/assets/controllers/upload-avatar_controller.js b/assets/controllers/upload-avatar_controller.js index 96d9dd3..81206cb 100644 --- a/assets/controllers/upload-avatar_controller.js +++ b/assets/controllers/upload-avatar_controller.js @@ -9,21 +9,6 @@ export default class extends Controller { } connect() { - console.log('image', this.avatarImageValue) - console.log('id', this.userIdValue) - - /* - const formElement = document.getElementById('avatarDropzone') - const dzMessage = document.getElementsByClassName('dz-message') - formElement.style.backgroundImage = `url('${this.avatarImageValue}')` - formElement.style.backgroundRepeat = 'no-repeat' - formElement.style.backgroundPosition = 'center center' - formElement.style.backgroundSize = 'auto' - formElement.style.borderRadius = '25px' - console.log('formelement', formElement) -*/ - - console.log('init Dropzone') let avatarDropzone = new Dropzone('#avatarDropzone', { url: `/user/upload/avatar/${this.userIdValue}`, avatarUrl: this.avatarImageValue, @@ -37,32 +22,14 @@ export default class extends Controller { const callback = null // Optional callback when it's done const crossOrigin = null // Added to the `img` tag for crossOrigin handling const resizeThumbnail = false // Tells Dropzone whether it should resize the image first - avatarDropzone.displayExistingFile(mockFile, avatarDropzone.options.avatarUrl, callback, crossOrigin, resizeThumbnail); - avatarDropzone.files.push(mockFile); // line missing in official docs - - /* - console.log('url', avatarDropzone.options.foo) - this.hiddenFileInput.removeAttribute('multiple') - this.on('maxfilesexceeded', (file) => { - this.removeAllFiles() - this.addFile(file) - }) - this.on('error', (file, data) => { - console.log('error') - if (data.detail) { - this.emit('error', file, data.detail) - } - }) - console.log('beforemock') - const mockFile = { name: 'Name Image', size: 12345, type: 'image/jpeg' } - this.emit('addedfile', mockFile) - this.emit('success', mockFile) - console.log('avi', this.avatarImageValue) - this.emit('thumbnail', mockFile, avatarDropzone.options.avatarUrl) - console.log('aftermock') - this.emit('complete', mockFile); - this.files.push(mockFile); - */ + avatarDropzone.displayExistingFile( + mockFile, + avatarDropzone.options.avatarUrl, + callback, + crossOrigin, + resizeThumbnail + ) + avatarDropzone.files.push(mockFile) // line missing in official docs }, transformFile(file, done) { // Create the image editor overlay @@ -84,7 +51,7 @@ export default class extends Controller { editor.appendChild(image) // Create Cropper.js - const cropper = new Cropper(image, {aspectRatio: 1}) + const cropper = new Cropper(image, { aspectRatio: 1 }) // Create confirm button at the top left of the viewport const buttonCrop = document.createElement('button') From 42a4fc1d8a5a4ddaf8f09fbff7e877e9f54ecfc7 Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 17:02:20 +0100 Subject: [PATCH 06/17] dropzone styling --- assets/styles/app.scss | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/assets/styles/app.scss b/assets/styles/app.scss index fbf9f2f..1319010 100644 --- a/assets/styles/app.scss +++ b/assets/styles/app.scss @@ -27,9 +27,9 @@ $list-group-hover-bg: darken($list-group, 10%); $list-group-active-bg: $list-group; $list-group-action-active-bg: $list-group; -@import 'bootstrap/scss/bootstrap'; +@import '~bootstrap'; @import 'dropzone/dist/dropzone'; - +@import 'cropperjs'; @import './components/sidebar'; @@ -40,19 +40,35 @@ html, body { background: #0e0e10; } -// Dropzone -.dropzone .dz-preview.dz-image-preview { +// Dropzone +.dropzone .dz-preview { + background: transparent !important; + margin: 0 !important; +} + +.dropzone-container { + width: 160px; + height: 160px; +} + +.dropzone-preview-filename { + word-wrap: anywhere; + display: none; +} + +.dropzone-preview-image { + flex-basis: 0; + min-width: 150px; + max-width: 150px; + min-height: 150px; + max-height: 150px; +} + +.dz-image { background: transparent !important; } -.article-author-img { - width: 80px; - margin: 15px; -} - -/// - #main_content { overflow-y: auto; From 5247d71050765372b4e4096bb6a70a886fd9e184 Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 17:04:31 +0100 Subject: [PATCH 07/17] refactored dropzone stuff into controller --- assets/app.js | 55 +++++++++++---------------------------------------- 1 file changed, 11 insertions(+), 44 deletions(-) diff --git a/assets/app.js b/assets/app.js index 0bb46da..b98a7ee 100644 --- a/assets/app.js +++ b/assets/app.js @@ -11,57 +11,24 @@ import './styles/app.scss' import $ from 'jquery' import 'bootstrap' -// Dropzone stuff move to component -import {Dropzone} from 'dropzone' - -// TODO handle error (Chapter 26) -const formElement = $('#dropzoneForm') -if (formElement) { - const previewContent = $('#preview-content').html() - console.log(previewContent) - const dropzone = new Dropzone('#dropzoneForm', { - acceptedFiles: '.jpg, .jpeg, .png', - maxFiles: 1, - init: function () { - this.hiddenFileInput.removeAttribute('multiple') - this.on('maxfilesexceeded', (file) => { - this.removeAllFiles() - this.addFile(file) - }) - this.on('error', (file, data) => { - console.log('error'); - if (data.detail) { - this.emit('error', file, data.detail) - } - - }) - } - }) - console.log('filename', previewContent) - const mockFile = { name: previewContent } - console.log('file', mockFile) - dropzone.displayExistingFile(mockFile) -} - -// End Dropzone stuff move to component +// start the Stimulus application +import './bootstrap' //import './js/index' + // needed for legacy code //global.$ = $ if (window.matchMedia('(prefers-color-scheme)').media !== 'not all') { - console.log('🎉 Dark mode is supported') + console.log('🎉 Dark mode is supported') } $(document).ready(() => { - console.log('ready') - $('#toggleSidebar').on('click', () => { - const toggleIcon = $('#toggleIcon') - toggleIcon.toggleClass('fa fa-lg fa-fw fa-caret-square-o-left') - toggleIcon.toggleClass('fa fa-lg fa-fw fa-caret-square-o-right') - $('#sidebar').toggleClass('active') - }) + console.log('ready') + $('#toggleSidebar').on('click', () => { + const toggleIcon = $('#toggleIcon') + toggleIcon.toggleClass('fa fa-lg fa-fw fa-caret-square-o-left') + toggleIcon.toggleClass('fa fa-lg fa-fw fa-caret-square-o-right') + $('#sidebar').toggleClass('active') + }) }) - -// start the Stimulus application -//import './bootstrap' From 28d77f7ec5bb9a29e4a9b6008a658ad93b2abb44 Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 17:05:12 +0100 Subject: [PATCH 08/17] new controllers added by bundles --- assets/controllers.json | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/assets/controllers.json b/assets/controllers.json index a1c6e90..1620b19 100644 --- a/assets/controllers.json +++ b/assets/controllers.json @@ -1,4 +1,30 @@ { - "controllers": [], + "controllers": { + "@symfony/ux-cropperjs": { + "cropper": { + "enabled": true, + "fetch": "eager", + "autoimport": { + "cropperjs/dist/cropper.min.css": true, + "@symfony/ux-cropperjs/src/style.css": true + } + } + }, + "@symfony/ux-dropzone": { + "dropzone": { + "enabled": true, + "fetch": "eager", + "autoimport": { + "@symfony/ux-dropzone/src/style.css": true + } + } + }, + "@symfony/ux-turbo": { + "turbo-core": { + "enabled": true, + "fetch": "eager" + } + } + }, "entrypoints": [] } From d8aca181922f5eaf79a5471ada3e32aaef695b84 Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 17:07:27 +0100 Subject: [PATCH 09/17] changed size of small --- config/packages/liip_imagine.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/packages/liip_imagine.yaml b/config/packages/liip_imagine.yaml index 79bd742..1e7c42f 100644 --- a/config/packages/liip_imagine.yaml +++ b/config/packages/liip_imagine.yaml @@ -1,13 +1,15 @@ # Documentation on how to configure the bundle can be found at: https://symfony.com/doc/current/bundles/LiipImagineBundle/basic-usage.html liip_imagine: # valid drivers options include "gd" or "gmagick" or "imagick" - driver: "gd" + driver: "imagick" + twig: + mode: lazy filter_sets: squared_thumbnail_small: filters: thumbnail: - size: [100, 100] + size: [120, 120] mode: outbound allow_upscale: true squared_thumbnail_medium: From f1a8821ba743082b956a6c04e0c4e361fe8d3f9a Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 17:07:58 +0100 Subject: [PATCH 10/17] some bundles were added --- config/bundles.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/bundles.php b/config/bundles.php index 08dbdfd..56b2619 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -19,4 +19,9 @@ return [ SymfonyCasts\Bundle\VerifyEmail\SymfonyCastsVerifyEmailBundle::class => ['all' => true], SymfonyCasts\Bundle\ResetPassword\SymfonyCastsResetPasswordBundle::class => ['all' => true], Liip\ImagineBundle\LiipImagineBundle::class => ['all' => true], + Symfony\UX\Dropzone\DropzoneBundle::class => ['all' => true], + Symfony\UX\Turbo\TurboBundle::class => ['all' => true], + Flasher\Symfony\FlasherSymfonyBundle::class => ['all' => true], + Flasher\SweetAlert\Symfony\FlasherSweetAlertSymfonyBundle::class => ['all' => true], + Symfony\UX\Cropperjs\CropperjsBundle::class => ['all' => true], ]; From 481849b530c86367d8dfaace1a53123c17081a48 Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 17:08:44 +0100 Subject: [PATCH 11/17] refactored from render to renderForm --- src/Controller/SecurityController.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php index d9e0c0d..3ac3761 100644 --- a/src/Controller/SecurityController.php +++ b/src/Controller/SecurityController.php @@ -92,8 +92,8 @@ class SecurityController extends AbstractController return $this->render(view: '@default/security/registration_finished.html.twig'); } - return $this->render(view: '@default/security/register.html.twig', parameters: [ - 'registrationForm' => $form->createView(), + return $this->renderForm(view: '@default/security/register.html.twig', parameters: [ + 'registrationForm' => $form, ]); } @@ -142,8 +142,8 @@ class SecurityController extends AbstractController ); } - return $this->render(view: '@default/security/forgot_password.html.twig', parameters: [ - 'requestForm' => $form->createView(), + return $this->renderForm(view: '@default/security/forgot_password.html.twig', parameters: [ + 'requestForm' => $form, ]); } @@ -220,8 +220,8 @@ class SecurityController extends AbstractController return $this->redirectToRoute(route: 'app_main'); } - return $this->render(view: '@default/security/reset_password.html.twig', parameters: [ - 'resetForm' => $form->createView(), + return $this->renderForm(view: '@default/security/reset_password.html.twig', parameters: [ + 'resetForm' => $form, ]); } From f48529b743b65025c801919e147bb2f6e533277e Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 17:10:54 +0100 Subject: [PATCH 12/17] working version of edit profile --- src/Controller/UserController.php | 106 +++++++++++++++++------------- 1 file changed, 60 insertions(+), 46 deletions(-) diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index 9f20143..0edddab 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -6,6 +6,8 @@ use App\Entity\User; use App\Form\EditProfileFormType; use App\Repository\UserRepository; use Doctrine\ORM\EntityManagerInterface; +use Flasher\Prime\FlasherInterface; +use Flasher\SweetAlert\Prime\SweetAlertFactory; use Sunrise\Slugger\Slugger; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -24,50 +26,6 @@ use Symfony\Component\Validator\Validator\ValidatorInterface; */ class UserController extends BaseController { - - #[Route(path: '/profile/edit/{username}', name: 'app_profile_edit')] - public function editProfile(Request $request, UserRepository $userRepository, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager, string $username = ''): Response - { - if ($username !== '') { - if ($this->isGranted(attribute: 'ROLE_ADMIN')) { - $user = $userRepository->findOneBy([ - 'username' => $username, - ]); - } else { - throw new AccessDeniedException(message: 'Only admins are allowed to edit foreign profiles.'); - } - } else { - $user = $this->getUser(); - } - - $form = $this->createForm(type: EditProfileFormType::class, data: $user); - $form->handleRequest(request: $request); - - if ($form->isSubmitted() && $form->isValid()) { - $user = $form->getData(); - // if there's a new password, use it - - if ($form->get(name: 'newPassword')->getData()) - $user->setPassword( - password: $userPasswordHasher->hashPassword( - user: $user, - plainPassword: $form->get(name: 'newPassword')->getData() - ) - ); - - $entityManager->persist(entity: $user); - $entityManager->flush(); - - return $this->redirectToRoute(route: 'app_main'); - }; - - return $this->renderForm(view: '@default/user/edit_profile.html.twig', parameters: [ - 'user' => $user, - 'userForm' => $form - ]); - } - - #[Route(path: '/profile/{username}', name: 'app_profile')] public function showProfile(UserRepository $userRepository, string $username = ''): Response { @@ -85,6 +43,61 @@ class UserController extends BaseController ]); } + #[Route(path: '/profile/edit/{username}', name: 'app_profile_edit')] + public function editProfile(Request $request, + UserRepository $userRepository, + UserPasswordHasherInterface $userPasswordHasher, + EntityManagerInterface $entityManager, + string $username = ''): Response + { + $user = $this->getUser(); + + $editUser = $userRepository->findOneBy(['username' => $username]); + + if ($username !== $editUser->getUsername()) { + if (!$this->isGranted(attribute: 'ROLE_ADMIN')) { + $this->addFlash(type: 'error', message: 'Only admins are allowed to edit foreign profiles.'); + return $this->redirectToRoute(route: 'app_main'); + + } + } + + $form = $this->createForm(type: EditProfileFormType::class, data: $user); + $form->handleRequest(request: $request); + + if ($form->isSubmitted() && $form->isValid()) { + $user = $form->getData(); + // if there's a new password, use it + + if ($form->get(name: 'newPassword')->getData()) { + $user->setPassword( + password: $userPasswordHasher->hashPassword( + user: $user, + plainPassword: $form->get(name: 'newPassword')->getData() + ) + ); + } + + if ($user->getTmpAvatar()) { + $user->setAvatar($user->getTmpAvatar()); + $user->setTmpAvatar(''); + } + + $entityManager->persist(entity: $user); + $entityManager->flush(); + + $this->addFlash(type: 'success', message: 'Profile successfully updated.'); + + return $this->redirectToRoute(route: 'app_main'); + }; + + return $this->renderForm(view: '@default/user/edit_profile.html.twig', parameters: [ + 'user' => $editUser, + 'userForm' => $form + ]); + } + + #[Route(path: '/list_users/', name: 'app_list_user')] public function listUsers(UserRepository $userRepository): Response { @@ -96,7 +109,7 @@ class UserController extends BaseController } // TODO move to a helper class - function humanFilesize($bytes, $decimals = 2) + function humanFilesize($bytes, $decimals = 2): string { $sz = 'BKMGTP'; $factor = floor((strlen($bytes) - 1) / 3); @@ -132,7 +145,8 @@ class UserController extends BaseController $cleanFilename = $slugger->slugify($originalFilename); $newFilename = $cleanFilename . '-' . uniqid() . '.' . $uploadedAvatar->guessExtension(); $uploadedAvatar->move($destination, $newFilename); - $user->setAvatar($newFilename); + // Store the tmp name, use it on real form submit. + $user->setTmpAvatar($newFilename); $entityManager->persist(entity: $user); $entityManager->flush(); From 763e3f49185d4529311d690dd7d44fbfa49294fe Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 17:11:25 +0100 Subject: [PATCH 13/17] small cli tool to purge unused avatar uploads --- src/Command/CronRunCommand.php | 72 ++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/Command/CronRunCommand.php diff --git a/src/Command/CronRunCommand.php b/src/Command/CronRunCommand.php new file mode 100644 index 0000000..8704968 --- /dev/null +++ b/src/Command/CronRunCommand.php @@ -0,0 +1,72 @@ +<?php + +namespace App\Command; + +use App\Repository\UserRepository; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +#[AsCommand( + name: 'cron:run', + description: 'Cleanup stale avatars', +)] +class CronRunCommand extends Command +{ + public function __construct(private readonly UserRepository $userRepository) + { + parent::__construct(); + } + + protected function configure(): void + { + /* + $this + ->addArgument('arg1', InputArgument::OPTIONAL, 'Argument description') + ->addOption('option1', null, InputOption::VALUE_NONE, 'Option description') + ; + */ + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + $verbose = $input->getOption('verbose'); + + $staleCount = $this->deleteStaleAvatars(); + + if ($verbose) { + if ($staleCount > 0) { + $io->writeln("There were " . $staleCount . " stale avatars."); + } else { + $io->writeln("There were no stale avatars younger than 24 hours."); + } + } + + return Command::SUCCESS; + } + + private function deleteStaleAvatars(): int + { + $avatarDir = dirname(__DIR__, 2) . '/public/uploads/avatars'; + $keepTime = 86400; // 24 hours + $deletedFiles = 0; + + foreach (glob($avatarDir . '/*') as $entry) { + $filectime = filectime($entry); + if ($filectime && $filectime + $keepTime < time()) { + // check if it in use + if ($user = $this->userRepository->findOneBy(['avatar' => basename($entry)])) { + echo basename($entry) . " is in use by: " . $user->getUserIdentifier() . PHP_EOL; + } + unlink($entry); + $deletedFiles++; + } + + } + return $deletedFiles; + } +} From a64fa311a001f1619bce04461bbebac5456a18f0 Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 17:12:37 +0100 Subject: [PATCH 14/17] added result type to resendVerifyEmail --- src/Controller/SecurityController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php index 3ac3761..32ed070 100644 --- a/src/Controller/SecurityController.php +++ b/src/Controller/SecurityController.php @@ -330,7 +330,7 @@ class SecurityController extends AbstractController #[Route('/security/resend/verify_email', name: 'security_resend_verify_email')] - public function resendVerifyEmail(Request $request, UserRepository $userRepository) + public function resendVerifyEmail(Request $request, UserRepository $userRepository): Response { if ($request->isMethod('POST')) { From 995f47a8883415223299964e5eae3dd236780134 Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 17:13:03 +0100 Subject: [PATCH 15/17] added tmpAvatar --- src/Entity/User.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Entity/User.php b/src/Entity/User.php index 8540453..1b11469 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -64,6 +64,9 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface #[ORM\Column] private ?DateTimeImmutable $agreedTermsAt = null; + #[ORM\Column(length: 255, nullable: true)] + private ?string $tmpAvatar = null; + public function __construct() { $this->projects = new ArrayCollection(); @@ -315,4 +318,16 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface { // TODO: Implement eraseCredentials() method. } + + public function getTmpAvatar(): ?string + { + return $this->tmpAvatar; + } + + public function setTmpAvatar(?string $tmpAvatar): self + { + $this->tmpAvatar = $tmpAvatar; + + return $this; + } } From cd5f4e6590cb219c46c337d72b3bfa9de5894f3d Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 17:14:43 +0100 Subject: [PATCH 16/17] disabled UX-Dropzone --- src/Form/EditProfileFormType.php | 51 +++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/Form/EditProfileFormType.php b/src/Form/EditProfileFormType.php index a60f68b..5ba3b9c 100644 --- a/src/Form/EditProfileFormType.php +++ b/src/Form/EditProfileFormType.php @@ -5,34 +5,65 @@ namespace App\Form; use App\Entity\User; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\EmailType; -use Symfony\Component\Form\Extension\Core\Type\FileType; use Symfony\Component\Form\Extension\Core\Type\PasswordType; use Symfony\Component\Form\Extension\Core\Type\RepeatedType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Validator\Constraints\Image; use Symfony\Component\Validator\Constraints\Length; +use Symfony\UX\Cropperjs\Form\CropperType; +use Symfony\UX\Dropzone\Form\DropzoneType; class EditProfileFormType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options): void { $builder - ->add(child: 'username') - ->add(child: 'firstName') - ->add(child: 'lastName') - ->add(child: 'email', type: EmailType::class) + ->add(child: 'username', options: [ + 'attr' => [ + 'autocomplete' => 'nickname' + ] + ]) + ->add(child: 'firstName', options: [ + 'required' => false, + 'attr' => [ + 'autocomplete' => 'given-name' + ] + ]) + ->add(child: 'lastName', options: [ + 'required' => false, + 'attr' => [ + 'autocomplete' => 'family-name' + ] + + ]) + ->add(child: 'email', type: EmailType::class, options: [ + 'attr' => [ + 'autocomplete' => 'email' + ] + ]) + /* + ->add(child: 'avatarName', type: DropzoneType::class, options: [ + 'mapped' => false, + 'required' => false, + 'attr' => [ + 'data-controller' => 'upload-avatar', + ] + ]) + */ ->add(child: 'newPassword', type: RepeatedType::class, options: [ 'type' => PasswordType::class, 'mapped' => false, 'invalid_message' => 'The password fields must match.', - 'options' => ['attr' => ['class' => 'password-field', 'autocomplete' => 'off']], 'required' => false, 'first_options' => ['label' => 'Password'], 'second_options' => ['label' => 'Repeat Password (only needed if you want to update the password)'], - 'constraints' => [new Length(exactly: ['min' => 6])] - ]) - ; + 'constraints' => [new Length(exactly: ['min' => 6])], + 'options' => [ + 'attr' => [ + 'autocomplete' => 'new-password' + ] + ] + ]); } public function configureOptions(OptionsResolver $resolver): void From 27454709af167f8ff7649b3a635d8b65fc26db84 Mon Sep 17 00:00:00 2001 From: tracer <tracer@24unix.net> Date: Tue, 15 Nov 2022 17:17:47 +0100 Subject: [PATCH 17/17] before remerve from turbo to master --- assets/controllers/crop_avatar_controller.js | 34 - composer.json | 8 +- composer.lock | 930 ++++++++++++++++++- migrations/Version20221115104149.php | 31 + package.json | 10 +- symfony.lock | 15 + webpack.config.js | 4 + yarn.lock | 81 ++ 8 files changed, 1076 insertions(+), 37 deletions(-) delete mode 100644 assets/controllers/crop_avatar_controller.js create mode 100644 migrations/Version20221115104149.php diff --git a/assets/controllers/crop_avatar_controller.js b/assets/controllers/crop_avatar_controller.js deleted file mode 100644 index 2393657..0000000 --- a/assets/controllers/crop_avatar_controller.js +++ /dev/null @@ -1,34 +0,0 @@ -import { Controller } from '@hotwired/stimulus' -import Swal from 'sweetalert2' - -export default class extends Controller { - static values = { - cropImage: String - } - - connect() { - console.log('crop', this.cropImageValue) - window.CropAvatar = this - } - - open() { - console.log('open crop') - Swal.fire({ - title: 'Are you sure?', - text: "You won't be able to revert this!", - icon: 'warning', - showCancelButton: true, - confirmButtonColor: '#3085d6', - cancelButtonColor: '#d33', - confirmButtonText: 'Yes, delete it!', - }).then((result) => { - if (result.isConfirmed) { - Swal.fire( - 'Deleted!', - 'Your file has been deleted.', - 'success', - ) - } - }) - } -} diff --git a/composer.json b/composer.json index b632310..c380b50 100644 --- a/composer.json +++ b/composer.json @@ -16,6 +16,8 @@ "league/commonmark": "^2.3", "liip/imagine-bundle": "^2.9", "nelmio/cors-bundle": "^2.2", + "php-flasher/flasher-sweetalert-symfony": "^1.7", + "php-flasher/flasher-symfony": "^1.7", "phpdocumentor/reflection-docblock": "^5.3", "phpstan/phpdoc-parser": "^1.4", "rector/rector": "^0.12.21", @@ -48,6 +50,9 @@ "symfony/string": "6.1.*", "symfony/translation": "6.1.*", "symfony/twig-bundle": "6.1.*", + "symfony/ux-cropperjs": "^2.5", + "symfony/ux-dropzone": "^2.5", + "symfony/ux-turbo": "^2.5", "symfony/validator": "6.1.*", "symfony/web-link": "6.1.*", "symfony/webapp-meta": "^1.0", @@ -57,7 +62,8 @@ "symfonycasts/verify-email-bundle": "^1.12", "twig/extra-bundle": "^3.4", "twig/markdown-extra": "^3.4", - "twig/twig": "3.4.*" + "twig/twig": "3.4.*", + "ext-http": "*" }, "config": { "allow-plugins": { diff --git a/composer.lock b/composer.lock index ccaa754..e4ad933 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1c940d128112ec366d0f81bc6eccee45", + "content-hash": "e475387f74f1428bb35d9943950aa2f8", "packages": [ { "name": "dflydev/dot-access-data", @@ -1689,6 +1689,125 @@ ], "time": "2022-10-17T19:48:16+00:00" }, + { + "name": "guzzlehttp/psr7", + "version": "2.4.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "67c26b443f348a51926030c83481b85718457d3d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/67c26b443f348a51926030c83481b85718457d3d", + "reference": "67c26b443f348a51926030c83481b85718457d3d", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "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": "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" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.4.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2022-10-26T14:07:24+00:00" + }, { "name": "imagine/imagine", "version": "1.3.2", @@ -1751,6 +1870,90 @@ }, "time": "2022-04-01T11:58:30+00:00" }, + { + "name": "intervention/image", + "version": "2.7.2", + "source": { + "type": "git", + "url": "https://github.com/Intervention/image.git", + "reference": "04be355f8d6734c826045d02a1079ad658322dad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Intervention/image/zipball/04be355f8d6734c826045d02a1079ad658322dad", + "reference": "04be355f8d6734c826045d02a1079ad658322dad", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "guzzlehttp/psr7": "~1.1 || ^2.0", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.2", + "phpunit/phpunit": "^4.8 || ^5.7 || ^7.5.15" + }, + "suggest": { + "ext-gd": "to use GD library based image processing.", + "ext-imagick": "to use Imagick based image processing.", + "intervention/imagecache": "Caching extension for the Intervention Image library" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + }, + "laravel": { + "providers": [ + "Intervention\\Image\\ImageServiceProvider" + ], + "aliases": { + "Image": "Intervention\\Image\\Facades\\Image" + } + } + }, + "autoload": { + "psr-4": { + "Intervention\\Image\\": "src/Intervention/Image" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oliver Vogel", + "email": "oliver@intervention.io", + "homepage": "https://intervention.io/" + } + ], + "description": "Image handling and manipulation library with support for Laravel integration", + "homepage": "http://image.intervention.io/", + "keywords": [ + "gd", + "image", + "imagick", + "laravel", + "thumbnail", + "watermark" + ], + "support": { + "issues": "https://github.com/Intervention/image/issues", + "source": "https://github.com/Intervention/image/tree/2.7.2" + }, + "funding": [ + { + "url": "https://paypal.me/interventionio", + "type": "custom" + }, + { + "url": "https://github.com/Intervention", + "type": "github" + } + ], + "time": "2022-05-21T17:30:32+00:00" + }, { "name": "knplabs/knp-time-bundle", "version": "v1.20.0", @@ -2489,6 +2692,316 @@ }, "time": "2022-09-12T23:36:20+00:00" }, + { + "name": "php-flasher/flasher", + "version": "v1.7.0", + "source": { + "type": "git", + "url": "https://github.com/php-flasher/flasher.git", + "reference": "10071abc73d0311a99e1860e88d5895ac4d7535c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-flasher/flasher/zipball/10071abc73d0311a99e1860e88d5895ac4d7535c", + "reference": "10071abc73d0311a99e1860e88d5895ac4d7535c", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Flasher\\Prime\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Younes KHOUBZA", + "email": "younes.khoubza@gmail.com", + "homepage": "https://www.linkedin.com/in/younes-khoubza", + "role": "Developer" + } + ], + "description": "A powerful and flexible flash notification system for PHP", + "homepage": "https://php-flasher.io", + "keywords": [ + "Flasher", + "alerts", + "flash", + "laravel", + "lumen", + "messages", + "notifications", + "notify", + "noty", + "notyf", + "php", + "pnotify", + "sweet alert", + "symfony", + "toastr" + ], + "support": { + "source": "https://github.com/php-flasher/flasher/tree/v1.7.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/yoeunes", + "type": "custom" + }, + { + "url": "https://ko-fi.com/yoeunes", + "type": "ko_fi" + }, + { + "url": "https://opencollective.com/php-flasher", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/yoeunes", + "type": "patreon" + } + ], + "time": "2022-07-05T19:33:26+00:00" + }, + { + "name": "php-flasher/flasher-sweetalert", + "version": "v1.7.0", + "source": { + "type": "git", + "url": "https://github.com/php-flasher/flasher-sweetalert.git", + "reference": "abab36c6a70405ad9838238338a76853541baa34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-flasher/flasher-sweetalert/zipball/abab36c6a70405ad9838238338a76853541baa34", + "reference": "abab36c6a70405ad9838238338a76853541baa34", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "php-flasher/flasher": "^1.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Flasher\\SweetAlert\\Prime\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Younes KHOUBZA", + "email": "younes.khoubza@gmail.com", + "homepage": "https://www.linkedin.com/in/younes-khoubza", + "role": "Developer" + } + ], + "description": "PHP Flasher adapter for Sweet Alert 2", + "homepage": "https://php-flasher.io", + "keywords": [ + "alerts", + "laravel", + "lumen", + "messages", + "notifications", + "notify", + "php", + "pnotify", + "sweetalert", + "symfony" + ], + "support": { + "source": "https://github.com/php-flasher/flasher-sweetalert/tree/v1.7.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/yoeunes", + "type": "custom" + }, + { + "url": "https://ko-fi.com/yoeunes", + "type": "ko_fi" + }, + { + "url": "https://opencollective.com/php-flasher", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/yoeunes", + "type": "patreon" + } + ], + "time": "2022-07-05T19:36:36+00:00" + }, + { + "name": "php-flasher/flasher-sweetalert-symfony", + "version": "v1.7.0", + "source": { + "type": "git", + "url": "https://github.com/php-flasher/flasher-sweetalert-symfony.git", + "reference": "f8f10ad9760b30c8fc1fe4e9891b595a5cd8c51e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-flasher/flasher-sweetalert-symfony/zipball/f8f10ad9760b30c8fc1fe4e9891b595a5cd8c51e", + "reference": "f8f10ad9760b30c8fc1fe4e9891b595a5cd8c51e", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "php-flasher/flasher-sweetalert": "^1.7", + "php-flasher/flasher-symfony": "^1.7" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Flasher\\SweetAlert\\Symfony\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Younes KHOUBZA", + "email": "younes.khoubza@gmail.com", + "homepage": "https://www.linkedin.com/in/younes-khoubza", + "role": "Developer" + } + ], + "description": "PHP Flasher Symfony adapter for Sweet Alert 2", + "homepage": "https://php-flasher.io", + "keywords": [ + "alerts", + "bundle", + "flex", + "laravel", + "lumen", + "messages", + "notifications", + "notify", + "php", + "pnotify", + "sweetalert", + "symfony", + "toastr", + "yoeunes" + ], + "support": { + "source": "https://github.com/php-flasher/flasher-sweetalert-symfony/tree/v1.7.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/yoeunes", + "type": "custom" + }, + { + "url": "https://ko-fi.com/yoeunes", + "type": "ko_fi" + }, + { + "url": "https://opencollective.com/php-flasher", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/yoeunes", + "type": "patreon" + } + ], + "time": "2022-07-05T19:36:36+00:00" + }, + { + "name": "php-flasher/flasher-symfony", + "version": "v1.7.0", + "source": { + "type": "git", + "url": "https://github.com/php-flasher/flasher-symfony.git", + "reference": "1e003819402f415d07b8fedabfff527bd164822b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-flasher/flasher-symfony/zipball/1e003819402f415d07b8fedabfff527bd164822b", + "reference": "1e003819402f415d07b8fedabfff527bd164822b", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "php-flasher/flasher": "^1.7", + "symfony/config": "^2.0|^3.0|^4.0|^5.0|^6.0", + "symfony/console": "^2.0|^3.0|^4.0|^5.0|^6.0", + "symfony/dependency-injection": "^2.0|^3.0|^4.0|^5.0|^6.0", + "symfony/http-kernel": "^2.0|^3.0|^4.0|^5.0|^6.0", + "symfony/translation": "^2.0|^3.0|^4.0|^5.0|^6.0", + "symfony/twig-bundle": "^2.0|^3.0|^4.0|^5.0|^6.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Flasher\\Symfony\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Younes KHOUBZA", + "email": "younes.khoubza@gmail.com", + "homepage": "https://www.linkedin.com/in/younes-khoubza", + "role": "Developer" + } + ], + "description": "Symfony bundle integrating PHP Flasher into Symfony applications", + "homepage": "https://php-flasher.io", + "keywords": [ + "alerts", + "bundle", + "flex", + "laravel", + "lumen", + "messages", + "notifications", + "notify", + "php", + "pnotify", + "symfony", + "toastr", + "yoeunes" + ], + "support": { + "source": "https://github.com/php-flasher/flasher-symfony/tree/v1.7.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/yoeunes", + "type": "custom" + }, + { + "url": "https://ko-fi.com/yoeunes", + "type": "ko_fi" + }, + { + "url": "https://opencollective.com/php-flasher", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/yoeunes", + "type": "patreon" + } + ], + "time": "2022-07-05T19:36:36+00:00" + }, { "name": "phpdocumentor/reflection-common", "version": "2.2.0", @@ -2910,6 +3423,114 @@ }, "time": "2019-01-08T18:20:26+00:00" }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, { "name": "psr/link", "version": "2.0.1", @@ -3016,6 +3637,50 @@ }, "time": "2021-07-14T16:46:02+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "rector/rector", "version": "0.12.23", @@ -8175,6 +8840,269 @@ ], "time": "2022-09-09T09:34:27+00:00" }, + { + "name": "symfony/ux-cropperjs", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-cropperjs.git", + "reference": "123b30ff6b539625bcf50413b945a16de6bc9d6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-cropperjs/zipball/123b30ff6b539625bcf50413b945a16de6bc9d6e", + "reference": "123b30ff6b539625bcf50413b945a16de6bc9d6e", + "shasum": "" + }, + "require": { + "intervention/image": "^2.5", + "php": ">=7.2.5", + "symfony/config": "^4.4.17|^5.0|^6.0", + "symfony/dependency-injection": "^4.4.17|^5.0|^6.0", + "symfony/form": "^4.4.17|^5.0|^6.0", + "symfony/http-kernel": "^4.4.17|^5.0|^6.0", + "symfony/validator": "^4.4.17|^5.0|^6.0" + }, + "conflict": { + "symfony/flex": "<1.13" + }, + "require-dev": { + "symfony/framework-bundle": "^4.4.17|^5.0|^6.0", + "symfony/phpunit-bridge": "^5.2|^6.0", + "symfony/twig-bundle": "^4.4.17|^5.0|^6.0", + "symfony/var-dumper": "^4.4.17|^5.0|^6.0" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "name": "symfony/ux", + "url": "https://github.com/symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\Cropperjs\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Titouan Galopin", + "email": "galopintitouan@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Cropper.js integration for Symfony", + "homepage": "https://symfony.com", + "keywords": [ + "symfony-ux" + ], + "support": { + "source": "https://github.com/symfony/ux-cropperjs/tree/v2.5.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": "2022-11-01T17:19:11+00:00" + }, + { + "name": "symfony/ux-dropzone", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-dropzone.git", + "reference": "897dbc3a8e61510c3f9c2ee7fee5596eb9cbf1d6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-dropzone/zipball/897dbc3a8e61510c3f9c2ee7fee5596eb9cbf1d6", + "reference": "897dbc3a8e61510c3f9c2ee7fee5596eb9cbf1d6", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/config": "^4.4.17|^5.0|^6.0", + "symfony/dependency-injection": "^4.4.17|^5.0|^6.0", + "symfony/form": "^4.4.17|^5.0|^6.0", + "symfony/http-kernel": "^4.4.17|^5.0|^6.0" + }, + "require-dev": { + "symfony/framework-bundle": "^4.4.17|^5.0|^6.0", + "symfony/phpunit-bridge": "^5.2|^6.0", + "symfony/twig-bundle": "^4.4.17|^5.0|^6.0", + "symfony/var-dumper": "^4.4.17|^5.0|^6.0" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "name": "symfony/ux", + "url": "https://github.com/symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\Dropzone\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Titouan Galopin", + "email": "galopintitouan@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "File input dropzones for Symfony Forms", + "homepage": "https://symfony.com", + "keywords": [ + "symfony-ux" + ], + "support": { + "source": "https://github.com/symfony/ux-dropzone/tree/v2.5.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": "2022-09-08T14:28:44+00:00" + }, + { + "name": "symfony/ux-turbo", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-turbo.git", + "reference": "3476bf0030937824137ad0aa1c9797d7c6085882" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-turbo/zipball/3476bf0030937824137ad0aa1c9797d7c6085882", + "reference": "3476bf0030937824137ad0aa1c9797d7c6085882", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/webpack-encore-bundle": "^1.11" + }, + "conflict": { + "symfony/flex": "<1.13" + }, + "require-dev": { + "doctrine/annotations": "^1.12", + "doctrine/doctrine-bundle": "^2.2", + "doctrine/orm": "^2.8 | 3.0", + "phpstan/phpstan": "^0.12", + "symfony/debug-bundle": "^5.2|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/form": "^5.2|^6.0", + "symfony/framework-bundle": "^5.2|^6.0", + "symfony/mercure-bundle": "^0.3", + "symfony/messenger": "^5.2|^6.0", + "symfony/panther": "^1.0|^2.0", + "symfony/phpunit-bridge": "^5.2.1|^6.0", + "symfony/property-access": "^5.2|^6.0", + "symfony/security-core": "^5.2|^6.0", + "symfony/stopwatch": "^5.2|^6.0", + "symfony/twig-bundle": "^5.2|^6.0", + "symfony/web-profiler-bundle": "^5.2|^6.0" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "name": "symfony/ux", + "url": "https://github.com/symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\Turbo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Hotwire Turbo integration for Symfony", + "homepage": "https://symfony.com", + "keywords": [ + "hotwire", + "javascript", + "mercure", + "symfony-ux", + "turbo", + "turbo-stream" + ], + "support": { + "source": "https://github.com/symfony/ux-turbo/tree/v2.5.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": "2022-09-08T14:28:44+00:00" + }, { "name": "symfony/validator", "version": "v6.1.7", diff --git a/migrations/Version20221115104149.php b/migrations/Version20221115104149.php new file mode 100644 index 0000000..3ed9d62 --- /dev/null +++ b/migrations/Version20221115104149.php @@ -0,0 +1,31 @@ +<?php + +declare(strict_types=1); + +namespace DoctrineMigrations; + +use Doctrine\DBAL\Schema\Schema; +use Doctrine\Migrations\AbstractMigration; + +/** + * Auto-generated Migration: Please modify to your needs! + */ +final class Version20221115104149 extends AbstractMigration +{ + public function getDescription(): string + { + return ''; + } + + public function up(Schema $schema): void + { + // this up() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE user ADD tmp_avatar VARCHAR(255) DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE user DROP tmp_avatar'); + } +} diff --git a/package.json b/package.json index 74f8f8f..3a00bb9 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,17 @@ { "devDependencies": { + "@babel/preset-react": "^7.0.0", "@hotwired/stimulus": "^3.0.0", + "@hotwired/turbo": "^7.0.1", "@popperjs/core": "^2.11.6", "@symfony/stimulus-bridge": "^3.0.0", + "@symfony/ux-cropperjs": "file:vendor/symfony/ux-cropperjs/Resources/assets", + "@symfony/ux-dropzone": "file:vendor/symfony/ux-dropzone/Resources/assets", + "@symfony/ux-turbo": "file:vendor/symfony/ux-turbo/Resources/assets", "@symfony/webpack-encore": "^2.0.0", "autoprefixer": "^10.4.7", "core-js": "^3.0.0", + "cropperjs": "^1.5.9", "file-loader": "^6.0.0", "jquery": "^3.6.0", "less-loader": "^10.0.0", @@ -13,6 +19,7 @@ "regenerator-runtime": "^0.13.2", "sass": "^1.50.0", "sass-loader": "^12.0.0", + "sweetalert2": "^11.6.8", "ts-loader": "^9.0.0", "typescript": "^4.6.4", "webpack-manifest-plugin": "^5.0.0", @@ -44,6 +51,7 @@ "postcss-import": "^14.1.0", "postcss-loader": "^7.0.0", "quill": "^1.3.7", - "quill-html-edit-button": "^2.2.12" + "quill-html-edit-button": "^2.2.12", + "toastify-js": "^1.12.0" } } diff --git a/symfony.lock b/symfony.lock index 687a9a1..8fceaae 100644 --- a/symfony.lock +++ b/symfony.lock @@ -72,6 +72,12 @@ "config/packages/nelmio_cors.yaml" ] }, + "php-flasher/flasher-sweetalert-symfony": { + "version": "v1.7.0" + }, + "php-flasher/flasher-symfony": { + "version": "v1.7.0" + }, "sensio/framework-extra-bundle": { "version": "6.2", "recipe": { @@ -271,6 +277,15 @@ "templates/base.html.twig" ] }, + "symfony/ux-cropperjs": { + "version": "v2.5.0" + }, + "symfony/ux-dropzone": { + "version": "v2.5.0" + }, + "symfony/ux-turbo": { + "version": "v2.5.0" + }, "symfony/validator": { "version": "6.1", "recipe": { diff --git a/webpack.config.js b/webpack.config.js index 379811b..2555d3e 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -43,5 +43,9 @@ Encore } }) .autoProvidejQuery() + .enableStimulusBridge( + './assets/controllers.json' + ) + .enableReactPreset() module.exports = Encore.getWebpackConfig() diff --git a/yarn.lock b/yarn.lock index aca37f6..35d4f86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -461,6 +461,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-jsx@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" + integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -701,6 +708,39 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" +"@babel/plugin-transform-react-display-name@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz#8b1125f919ef36ebdfff061d664e266c666b9415" + integrity sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx-development@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5" + integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.18.6" + +"@babel/plugin-transform-react-jsx@^7.18.6": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz#b3cbb7c3a00b92ec8ae1027910e331ba5c500eb9" + integrity sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/plugin-syntax-jsx" "^7.18.6" + "@babel/types" "^7.19.0" + +"@babel/plugin-transform-react-pure-annotations@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz#561af267f19f3e5d59291f9950fd7b9663d0d844" + integrity sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-transform-regenerator@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz#585c66cb84d4b4bf72519a34cfce761b8676ca73" @@ -859,6 +899,18 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" +"@babel/preset-react@^7.0.0": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.18.6.tgz#979f76d6277048dc19094c217b507f3ad517dd2d" + integrity sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-transform-react-display-name" "^7.18.6" + "@babel/plugin-transform-react-jsx" "^7.18.6" + "@babel/plugin-transform-react-jsx-development" "^7.18.6" + "@babel/plugin-transform-react-pure-annotations" "^7.18.6" + "@babel/runtime@^7.8.4": version "7.20.1" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.1.tgz#1148bb33ab252b165a06698fde7576092a78b4a9" @@ -935,6 +987,11 @@ resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.1.1.tgz#652f08a8e1d5edcb407340e58818fcff463b5848" integrity sha512-e0JpzIaYLsRRXevRDVs0yevabiCvieIWWCwh7VqVXjXM5AOHdjb7AjaKIj34zYFmY1N6HIRRfk915WVMYlHnDA== +"@hotwired/turbo@^7.0.1": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@hotwired/turbo/-/turbo-7.2.4.tgz#0d35541be32cfae3b4f78c6ab9138f5b21f28a21" + integrity sha512-c3xlOroHp/cCZHDOuLp6uzQYEbvXBUVaal0puXoGJ9M8L/KHwZ3hQozD4dVeSN9msHWLxxtmPT1TlCN7gFhj4w== + "@humanwhocodes/config-array@^0.11.6": version "0.11.7" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.7.tgz#38aec044c6c828f6ed51d5d7ae3d9b9faf6dbb0f" @@ -1059,6 +1116,15 @@ loader-utils "^2.0.0" schema-utils "^3.0.0" +"@symfony/ux-cropperjs@file:vendor/symfony/ux-cropperjs/Resources/assets": + version "1.1.0" + +"@symfony/ux-dropzone@file:vendor/symfony/ux-dropzone/Resources/assets": + version "1.1.0" + +"@symfony/ux-turbo@file:vendor/symfony/ux-turbo/Resources/assets": + version "0.1.0" + "@symfony/webpack-encore@^2.0.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@symfony/webpack-encore/-/webpack-encore-2.1.0.tgz#353a1b8bc38022046cbbc3d627c4076aca2e28c3" @@ -2042,6 +2108,11 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" +cropperjs@^1.5.9: + version "1.5.12" + resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.5.12.tgz#d9c0db2bfb8c0d769d51739e8f916bbc44e10f50" + integrity sha512-re7UdjE5UnwdrovyhNzZ6gathI4Rs3KGCBSc8HCIjUo5hO42CtzyblmWLj6QWVw7huHyDMfpKxhiO2II77nhDw== + cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -5111,6 +5182,11 @@ svgo@^2.7.0: picocolors "^1.0.0" stable "^0.1.8" +sweetalert2@^11.6.8: + version "11.6.8" + resolved "https://registry.yarnpkg.com/sweetalert2/-/sweetalert2-11.6.8.tgz#5a515284367bc21b9f7830cbfbbfd09341576cca" + integrity sha512-0YHMaqF3DC67EI9uZzHpbU34rQV3acEFlnUCYmDSDNkeNOSFtSlF4DbWilfln+iUYv9s9aqbREXmKZRJqh5G5w== + sync-rpc@^1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/sync-rpc/-/sync-rpc-1.3.6.tgz#b2e8b2550a12ccbc71df8644810529deb68665a7" @@ -5173,6 +5249,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +toastify-js@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/toastify-js/-/toastify-js-1.12.0.tgz#cc1c4f5c7e7380e854e20bedceb51980ea29f64d" + integrity sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ== + toidentifier@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"