Compare commits
42 commits
Author | SHA1 | Date | |
---|---|---|---|
d70029951f | |||
|
80ef8caf20 | ||
d2612882c8 | |||
cc5e0b6b27 | |||
|
a6e4b205f7 | ||
4e5b69450e | |||
|
a543fd2a4a | ||
e70157067c | |||
2d31f7cd76 | |||
1c172ec454 | |||
90d6fd0770 | |||
5eeb662d6f | |||
220d6a1f83 | |||
92c07b02cb | |||
48bf4f26c4 | |||
c7b400cec3 | |||
f86319f23c | |||
7b9542f0bd | |||
3d0ffa3311 | |||
42564e085c | |||
304c0d4ba6 | |||
f87b3a0115 | |||
e327966ef0 | |||
0c5f93bc36 | |||
54fa878115 | |||
34e5132c3d | |||
61b861b510 | |||
a034a6118a | |||
3135c26345 | |||
af12833642 | |||
1f140475b9 | |||
d4a7bd4228 | |||
f0c2bfae3a | |||
66e5631c16 | |||
ee36881c49 | |||
e4972d1b32 | |||
1296ca7cfb | |||
6b1406fde9 | |||
775dcfa681 | |||
b47e2c1b14 | |||
93eef67209 | |||
865f8ec94f |
27 changed files with 4341 additions and 4625 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -243,3 +243,6 @@ temp/
|
||||||
# .pnp.*
|
# .pnp.*
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/node,phpunit,symfony,composer,yarn
|
# End of https://www.toptal.com/developers/gitignore/api/node,phpunit,symfony,composer,yarn
|
||||||
|
|
||||||
|
# Snyk
|
||||||
|
.dccache
|
45
Jenkinsfile
vendored
45
Jenkinsfile
vendored
|
@ -2,36 +2,39 @@ node {
|
||||||
def app
|
def app
|
||||||
|
|
||||||
stage('Clone repository') {
|
stage('Clone repository') {
|
||||||
/* Let's make sure we have the repository cloned to our workspace */
|
// Let's make sure we have the repository cloned to our workspace
|
||||||
|
|
||||||
checkout scm
|
checkout scm
|
||||||
}
|
}
|
||||||
|
|
||||||
stage('Build image') {
|
stage('Install dependencies') {
|
||||||
/* This builds the actual image; synonymous to
|
// Install dependencies for build later
|
||||||
* docker build on the command line */
|
sh 'composer update'
|
||||||
|
sh 'yarn install'
|
||||||
app = docker.build("thisfro/plantex")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stage('Test image') {
|
stage('Composer Vulnr test') {
|
||||||
/* Ideally, we would run a test framework against our image.
|
snykSecurity(
|
||||||
* For this example, we're using a Volkswagen-type approach ;-) */
|
snykInstallation: 'snyk-local',
|
||||||
|
targetFile: 'composer.lock',
|
||||||
app.inside {
|
)
|
||||||
// php 'bin/phpunit'
|
|
||||||
sh 'echo "success"'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stage('Push image') {
|
stage('npm vulnr test') {
|
||||||
docker.withRegistry('https://hub.thisfro.ch') {
|
snykSecurity(
|
||||||
app.push("$BUILD_NUMBER")
|
snykInstallation: 'snyk-local',
|
||||||
app.push('latest')
|
targetFile: 'package.json',
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
stage('Deploy staging') {
|
stage('Deploy staging') {
|
||||||
sh 'cd /opt/containers/pflaenz.li && docker-compose pull && docker-compose up -d'
|
// Deploy to staging host
|
||||||
|
sh 'vendor/bin/dep deploy lq5xi.ftp.infomaniak.com --no-interaction'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
stage('Test staging') {
|
||||||
|
// Run phpunit tests on staging host
|
||||||
|
bin/phpunit COMMAND
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
10
README.md
10
README.md
|
@ -1,11 +1,14 @@
|
||||||
# plant-exchange
|
# Pflänz.li
|
||||||
|
|
||||||
## Idea
|
## Idea
|
||||||
A platform where people can exchange plants. They can post what they have and search for others with [filters](#filters).
|
A platform where people can trade their plants. You can post what you have and search for others with [filters](#filters). The aim is to make it easier to trade plants and collect as few data as possible. Only the email/username and a postal code is required.
|
||||||
|
|
||||||
## Tech stack
|
## Tech stack
|
||||||
- [Symfony](https://symfony.com/)
|
- [Symfony](https://symfony.com/)
|
||||||
- [MariaDB](https://www.mariadb.org)
|
- [MariaDB](https://www.mariadb.org)
|
||||||
|
- [Deployer](https://deployer.org)
|
||||||
|
|
||||||
|
Can easily be depoyed to a LAMP server
|
||||||
|
|
||||||
## Admin dashboard
|
## Admin dashboard
|
||||||
Find it under `/admin`
|
Find it under `/admin`
|
||||||
|
@ -14,8 +17,11 @@ Find it under `/admin`
|
||||||
|
|
||||||
### Implemented
|
### Implemented
|
||||||
- Distance between postal codes
|
- Distance between postal codes
|
||||||
|
- Search within title
|
||||||
|
|
||||||
### Ideas
|
### Ideas
|
||||||
|
It would be nice to have categories somehow, but it would be hard to make it comprehensive.
|
||||||
|
|
||||||
:warning: This list is work in progress!
|
:warning: This list is work in progress!
|
||||||
|
|
||||||
Searching with filters such as:
|
Searching with filters such as:
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
// any CSS you import will output into a single css file (app.css in this case)
|
// any CSS you import will output into a single css file (app.css in this case)
|
||||||
import './styles/app.scss';
|
import './styles/app.scss';
|
||||||
|
|
||||||
const $ = require('jquery');
|
|
||||||
// start the Stimulus application
|
// start the Stimulus application
|
||||||
require('bootstrap');
|
require('bootstrap');
|
||||||
|
|
||||||
|
@ -18,27 +17,32 @@ import '@fortawesome/fontawesome-free/js/solid'
|
||||||
import '@fortawesome/fontawesome-free/js/regular'
|
import '@fortawesome/fontawesome-free/js/regular'
|
||||||
import '@fortawesome/fontawesome-free/js/brands'
|
import '@fortawesome/fontawesome-free/js/brands'
|
||||||
|
|
||||||
// Friendly captcha
|
|
||||||
import { WidgetInstance } from 'friendly-challenge';
|
|
||||||
|
|
||||||
function doneCallback(solution) {
|
|
||||||
$('#registration_form_captcha_solution').val(solution);
|
|
||||||
}
|
|
||||||
|
|
||||||
const element = document.querySelector('#captcha');
|
|
||||||
const options = {
|
|
||||||
doneCallback: doneCallback,
|
|
||||||
sitekey: 'FCMVL79DP1G5K1K0',
|
|
||||||
}
|
|
||||||
const widget = new WidgetInstance(element, options);
|
|
||||||
widget.start()
|
|
||||||
|
|
||||||
// Dsiplay Filename when uploading
|
|
||||||
document.querySelector('.custom-file-input').addEventListener('change', function (e) {
|
|
||||||
var fileName = document.getElementById('offer_form_photo').files[0].name;
|
|
||||||
var nextSibling = e.target.nextElementSibling
|
|
||||||
nextSibling.innerText = fileName
|
|
||||||
})
|
|
||||||
|
|
||||||
// Cookie-consent
|
// Cookie-consent
|
||||||
import 'cookie-notice/dist/cookie.notice.min.js'
|
import 'cookie-notice/dist/cookie.notice.min';
|
||||||
|
|
||||||
|
new cookieNoticeJS({
|
||||||
|
// Position for the cookie-notifier (default=bottom)
|
||||||
|
'cookieNoticePosition': 'bottom',
|
||||||
|
|
||||||
|
// The message will be shown again in X days
|
||||||
|
'expiresIn': 365,
|
||||||
|
|
||||||
|
// Specify a custom font family and size in pixels
|
||||||
|
'fontFamily': 'inherit',
|
||||||
|
'fontSize': '.9rem',
|
||||||
|
|
||||||
|
// Dismiss button background color
|
||||||
|
'buttonBgColor': '#343a40',
|
||||||
|
|
||||||
|
// Dismiss button text color
|
||||||
|
'buttonTextColor': '#fff',
|
||||||
|
|
||||||
|
// Notice background color
|
||||||
|
'noticeBgColor': '#000',
|
||||||
|
|
||||||
|
// Notice text color
|
||||||
|
'noticeTextColor': '#fff',
|
||||||
|
|
||||||
|
// Print debug output to the console (default=false)
|
||||||
|
'debug': false
|
||||||
|
});
|
15
assets/captcha.js
Normal file
15
assets/captcha.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Friendly captcha
|
||||||
|
import { WidgetInstance } from 'friendly-challenge';
|
||||||
|
const $ = require('jquery');
|
||||||
|
|
||||||
|
function doneCallback(solution) {
|
||||||
|
$('#registration_form_captcha_solution').val(solution);
|
||||||
|
}
|
||||||
|
|
||||||
|
const element = document.querySelector('#captcha');
|
||||||
|
const options = {
|
||||||
|
doneCallback: doneCallback,
|
||||||
|
sitekey: 'FCMVL79DP1G5K1K0',
|
||||||
|
}
|
||||||
|
const widget = new WidgetInstance(element, options);
|
||||||
|
widget.start()
|
5
assets/fileUpload.js
Normal file
5
assets/fileUpload.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const $ = require('jquery');
|
||||||
|
|
||||||
|
$( ".custom-file-input" ).change(function() {
|
||||||
|
$(".custom-file-label").html(($(".custom-file-input").prop("files")[0]["name"]));
|
||||||
|
});
|
|
@ -8,6 +8,7 @@
|
||||||
"ext-ctype": "*",
|
"ext-ctype": "*",
|
||||||
"ext-iconv": "*",
|
"ext-iconv": "*",
|
||||||
"composer/package-versions-deprecated": "1.11.99.1",
|
"composer/package-versions-deprecated": "1.11.99.1",
|
||||||
|
"deployer/deployer": "^7.0",
|
||||||
"doctrine/doctrine-bundle": "^2.3",
|
"doctrine/doctrine-bundle": "^2.3",
|
||||||
"doctrine/doctrine-migrations-bundle": "^3.1",
|
"doctrine/doctrine-migrations-bundle": "^3.1",
|
||||||
"doctrine/orm": "^2.8",
|
"doctrine/orm": "^2.8",
|
||||||
|
@ -17,26 +18,26 @@
|
||||||
"presta/sitemap-bundle": "^3.2",
|
"presta/sitemap-bundle": "^3.2",
|
||||||
"samayo/bulletproof": "4.0.1",
|
"samayo/bulletproof": "4.0.1",
|
||||||
"sensio/framework-extra-bundle": "^6.1",
|
"sensio/framework-extra-bundle": "^6.1",
|
||||||
"symfony/asset": "5.4.*",
|
"symfony/asset": "^5.4.20",
|
||||||
"symfony/console": "5.4.*",
|
"symfony/console": "^5.4.20",
|
||||||
"symfony/dotenv": "5.4.*",
|
"symfony/dotenv": "^5.4.20",
|
||||||
"symfony/filesystem": "5.4.*",
|
"symfony/filesystem": "^5.4.20",
|
||||||
"symfony/flex": "^1.3.1",
|
"symfony/flex": "^1.3.1",
|
||||||
"symfony/form": "5.4.*",
|
"symfony/form": "^5.4.20",
|
||||||
"symfony/framework-bundle": "5.4.*",
|
"symfony/framework-bundle": "^5.4.20",
|
||||||
"symfony/mailer": "5.4.*",
|
"symfony/mailer": "^5.4.20",
|
||||||
"symfony/monolog-bundle": "^3.7",
|
"symfony/monolog-bundle": "^3.7",
|
||||||
"symfony/proxy-manager-bridge": "5.4.*",
|
"symfony/proxy-manager-bridge": "^5.4.20",
|
||||||
"symfony/security-bundle": "5.4.*",
|
"symfony/security-bundle": "^5.4.20",
|
||||||
"symfony/twig-bundle": "5.4.*",
|
"symfony/twig-bundle": "^5.4.20",
|
||||||
"symfony/validator": "5.4.*",
|
"symfony/validator": "^5.4.20",
|
||||||
"symfony/webpack-encore-bundle": "^1.11",
|
"symfony/webpack-encore-bundle": "^1.11",
|
||||||
"symfony/yaml": "5.4.*",
|
"symfony/yaml": "^5.4.20",
|
||||||
"symfonycasts/reset-password-bundle": "^1.7",
|
"symfonycasts/reset-password-bundle": "^1.7",
|
||||||
"symfonycasts/verify-email-bundle": "^1.4",
|
"symfonycasts/verify-email-bundle": "^1.4",
|
||||||
"twig/extra-bundle": "^2.12|^3.0",
|
"twig/extra-bundle": "^2.12|^3.0",
|
||||||
"twig/intl-extra": "^3.3",
|
"twig/intl-extra": "^3.3",
|
||||||
"twig/twig": "^2.12|^3.0"
|
"twig/twig": "^3.4.3"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"optimize-autoloader": true,
|
"optimize-autoloader": true,
|
||||||
|
@ -82,11 +83,10 @@
|
||||||
"extra": {
|
"extra": {
|
||||||
"symfony": {
|
"symfony": {
|
||||||
"allow-contrib": false,
|
"allow-contrib": false,
|
||||||
"require": "5.4.*"
|
"require": "^5.4.20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"deployer/dist": "^6.8",
|
|
||||||
"symfony/browser-kit": "^5.4",
|
"symfony/browser-kit": "^5.4",
|
||||||
"symfony/css-selector": "^5.4",
|
"symfony/css-selector": "^5.4",
|
||||||
"symfony/debug-bundle": "^5.4",
|
"symfony/debug-bundle": "^5.4",
|
||||||
|
|
1896
composer.lock
generated
1896
composer.lock
generated
File diff suppressed because it is too large
Load diff
24
deploy.php
24
deploy.php
|
@ -1,10 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Deployer;
|
namespace Deployer;
|
||||||
|
|
||||||
require 'recipe/symfony4.php';
|
require 'recipe/symfony.php';
|
||||||
|
|
||||||
// Project name
|
// Project name
|
||||||
set('application', 'beta.pflaenz.li');
|
set('application', 'pflaenz.li');
|
||||||
|
|
||||||
// Project repository
|
// Project repository
|
||||||
set('repository', 'ssh://git@git.thisfro.ch:222/thisfro/pflaenz.li.git');
|
set('repository', 'ssh://git@git.thisfro.ch:222/thisfro/pflaenz.li.git');
|
||||||
|
@ -13,11 +13,11 @@ set('repository', 'ssh://git@git.thisfro.ch:222/thisfro/pflaenz.li.git');
|
||||||
set('git_tty', true);
|
set('git_tty', true);
|
||||||
|
|
||||||
set('bin/php', function() {
|
set('bin/php', function() {
|
||||||
return '/opt/php8.0/bin/php';
|
return '/opt/php8.2/bin/php';
|
||||||
});
|
});
|
||||||
|
|
||||||
set('bin/composer', function() {
|
set('bin/composer', function() {
|
||||||
return '/opt/php8.0/bin/composer2';
|
return '/opt/php8.2/bin/composer2';
|
||||||
});
|
});
|
||||||
|
|
||||||
// Shared files/dirs between deploys
|
// Shared files/dirs between deploys
|
||||||
|
@ -28,14 +28,14 @@ add('shared_dirs', ['public/uploads']);
|
||||||
add('writable_dirs', []);
|
add('writable_dirs', []);
|
||||||
|
|
||||||
// Set composer options
|
// Set composer options
|
||||||
set('composer_options', '{{composer_action}} --verbose --prefer-dist --no-progress --no-interaction --optimize-autoloader --no-scripts --no-dev');
|
set('composer_options', '--verbose --prefer-dist --no-progress --no-interaction --optimize-autoloader --no-scripts');
|
||||||
|
|
||||||
// Hosts
|
// Hosts
|
||||||
host('beta.xn--pflnz-ira.li')
|
host('lq5xi.ftp.infomaniak.com')
|
||||||
->user('lq5xi_thisfro')
|
->set('remote_user', 'lq5xi_thisfro')
|
||||||
->set('deploy_path', '~/sites/{{application}}')
|
->set('deploy_path', '~/sites/{{stage}}.{{application}}')
|
||||||
->set('http_user', 'uid153060')
|
->set('http_user', 'uid153060')
|
||||||
->stage('beta');
|
->set('stage', 'beta');
|
||||||
|
|
||||||
// Tasks
|
// Tasks
|
||||||
|
|
||||||
|
@ -45,9 +45,9 @@ task('upload:build', function() {
|
||||||
|
|
||||||
// Build yarn locally
|
// Build yarn locally
|
||||||
task('deploy:build:assets', function (): void {
|
task('deploy:build:assets', function (): void {
|
||||||
run('yarn install');
|
runLocally('yarn install');
|
||||||
run('yarn encore production');
|
runLocally('yarn encore production');
|
||||||
})->local()->desc('Install front-end assets');
|
})->desc('Install front-end assets');
|
||||||
|
|
||||||
before('deploy:symlink', 'deploy:build:assets');
|
before('deploy:symlink', 'deploy:build:assets');
|
||||||
|
|
||||||
|
|
6703
package-lock.json
generated
6703
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -19,11 +19,12 @@
|
||||||
"dev-server": "encore dev-server",
|
"dev-server": "encore dev-server",
|
||||||
"dev": "encore dev",
|
"dev": "encore dev",
|
||||||
"watch": "encore dev --watch",
|
"watch": "encore dev --watch",
|
||||||
"build": "encore production --progress"
|
"build": "encore production --progress",
|
||||||
|
"test": "snyk test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@snyk/protect": "^1.834.0",
|
||||||
"cookie-notice": "^1.3.6",
|
"cookie-notice": "^1.3.6",
|
||||||
"friendly-challenge": "^0.8.5",
|
"friendly-challenge": "^0.8.5"
|
||||||
"snyk": "^1.806.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 6 KiB |
|
@ -18,5 +18,7 @@ if ($_SERVER['APP_DEBUG']) {
|
||||||
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
|
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
|
||||||
$request = Request::createFromGlobals();
|
$request = Request::createFromGlobals();
|
||||||
$response = $kernel->handle($request);
|
$response = $kernel->handle($request);
|
||||||
|
$response->headers->set('X-Frame-Options', 'DENY');
|
||||||
|
$response->headers->set('X-Content-Type-Options', 'nosniff');
|
||||||
$response->send();
|
$response->send();
|
||||||
$kernel->terminate($request, $response);
|
$kernel->terminate($request, $response);
|
|
@ -33,15 +33,21 @@ class OfferController extends AbstractController
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/offers', name: 'offers', options: ["sitemap" => true])]
|
#[Route('/offers', name: 'offers', options: ["sitemap" => true])]
|
||||||
public function showAll(Environment $twig, Request $request, OfferRepository $offerRepository, PlzToCoordinate $plzconverter, DistanceCalculator $distanceCalculator): Response
|
public function showAll(Request $request, OfferRepository $offerRepository, PlzToCoordinate $plzconverter, DistanceCalculator $distanceCalculator): Response
|
||||||
{
|
{
|
||||||
$form = $this->createForm(OfferFilterFormType::class);
|
$form = $this->createForm(OfferFilterFormType::class);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
$allOffers = $offerRepository->findAll();
|
|
||||||
$filteredOffers = [];
|
$filteredOffers = [];
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid() && $form->get('search')->getData() != null) {
|
||||||
|
$allOffers = $offerRepository->findBySearchLiteral($form->get('search')->getData());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$allOffers = $offerRepository->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid() && $form->get('distance')->getData() != null && $form->get('zipCode')->getData() != null) {
|
||||||
$filterDistance = $form->get('distance')->getData();
|
$filterDistance = $form->get('distance')->getData();
|
||||||
$filterPlz = $form->get('zipCode')->getData();
|
$filterPlz = $form->get('zipCode')->getData();
|
||||||
$filterCoordinate = $plzconverter->convertPlzToCoordinate($filterPlz);
|
$filterCoordinate = $plzconverter->convertPlzToCoordinate($filterPlz);
|
||||||
|
@ -144,7 +150,7 @@ class OfferController extends AbstractController
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/offer/edit/{urlId}', name: 'edit_offer')]
|
#[Route('/offer/edit/{urlId}', name: 'edit_offer')]
|
||||||
public function editOffer(Offer $offer, OfferRepository $offerRepository, Request $request, string $photoDir, OfferPhotoHelper $offerPhotoHelper): Response
|
public function editOffer(Offer $offer, Request $request, string $photoDir, OfferPhotoHelper $offerPhotoHelper): Response
|
||||||
{
|
{
|
||||||
$form = $this->createForm(OfferFormType::class, $offer);
|
$form = $this->createForm(OfferFormType::class, $offer);
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
|
@ -164,6 +170,10 @@ class OfferController extends AbstractController
|
||||||
|
|
||||||
$this->entityManager->persist($offer);
|
$this->entityManager->persist($offer);
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$this->addFlash("success", "Successfully updated the offer!");
|
||||||
|
|
||||||
|
return $this->redirectToRoute('show_offer', ['urlId' => $offer->getUrlId()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('offer/edit.html.twig', [
|
return $this->render('offer/edit.html.twig', [
|
||||||
|
@ -209,4 +219,14 @@ class OfferController extends AbstractController
|
||||||
'offers' => $offerRepository->findByUser($user),
|
'offers' => $offerRepository->findByUser($user),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route('/offers/search', name: 'search', options: ["sitemap" => false])]
|
||||||
|
public function search(OfferRepository $offerRepository): Response
|
||||||
|
{
|
||||||
|
$offers = $offerRepository->findBySearchLiteral('');
|
||||||
|
|
||||||
|
return $this->render('offer/search.html.twig', [
|
||||||
|
'offers' => $offers,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ class ResetPasswordController extends AbstractController
|
||||||
* Validates and process the reset URL that the user clicked in their email.
|
* Validates and process the reset URL that the user clicked in their email.
|
||||||
*/
|
*/
|
||||||
#[Route('/reset/{token}', name: 'app_reset_password')]
|
#[Route('/reset/{token}', name: 'app_reset_password')]
|
||||||
public function reset(Request $request, UserPasswordHasherInterface $passwordHasher, string $token = null): Response
|
public function reset(Request $request, UserPasswordHasherInterface $passwordEncoder, string $token = null): Response
|
||||||
{
|
{
|
||||||
if ($token) {
|
if ($token) {
|
||||||
// We store the token in session and remove it from the URL, to avoid the URL being
|
// We store the token in session and remove it from the URL, to avoid the URL being
|
||||||
|
@ -106,12 +106,13 @@ class ResetPasswordController extends AbstractController
|
||||||
$this->resetPasswordHelper->removeResetRequest($token);
|
$this->resetPasswordHelper->removeResetRequest($token);
|
||||||
|
|
||||||
// Encode the plain password, and set it.
|
// Encode the plain password, and set it.
|
||||||
$encodedPassword = $passwordHasher->encodePassword(
|
$user->setPassword(
|
||||||
$user,
|
$passwordEncoder->hashPassword(
|
||||||
$form->get('plainPassword')->getData()
|
$user,
|
||||||
|
$form->get('plainPassword')->getData()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
$user->setPassword($encodedPassword);
|
|
||||||
$this->getDoctrine()->getManager()->flush();
|
$this->getDoctrine()->getManager()->flush();
|
||||||
|
|
||||||
// The session is cleaned up after the password has been changed.
|
// The session is cleaned up after the password has been changed.
|
||||||
|
|
|
@ -14,11 +14,17 @@ class OfferFilterFormType extends AbstractType
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
{
|
{
|
||||||
$builder
|
$builder
|
||||||
->add('zipCode', TextType::class, [
|
->add('search', TextType::class, [
|
||||||
'label' => 'ZIP',
|
'label' => '<i class="fas fa-search mr-1"></i>Search',
|
||||||
|
'label_html' => true,
|
||||||
|
])
|
||||||
|
->add('zipCode', NumberType::class, [
|
||||||
|
'label' => '<i class="fas fa-map-marker-alt mr-2"></i>ZIP',
|
||||||
|
'label_html' => true,
|
||||||
])
|
])
|
||||||
->add('distance', NumberType::class, [
|
->add('distance', NumberType::class, [
|
||||||
'label' => 'Distance',
|
'label' => '<i class="fas fa-map-signs mr-1"></i>Distance',
|
||||||
|
'label_html' => true,
|
||||||
])
|
])
|
||||||
->add('Apply', SubmitType::class)
|
->add('Apply', SubmitType::class)
|
||||||
;
|
;
|
||||||
|
|
|
@ -46,6 +46,8 @@ class RegistrationFormType extends AbstractType
|
||||||
])
|
])
|
||||||
->add('agreeTerms', CheckboxType::class, [
|
->add('agreeTerms', CheckboxType::class, [
|
||||||
'mapped' => false,
|
'mapped' => false,
|
||||||
|
'label' => 'Agree to <a href="/imprint" target="_blank">Terms</a>',
|
||||||
|
'label_html' => true,
|
||||||
'constraints' => [
|
'constraints' => [
|
||||||
new IsTrue([
|
new IsTrue([
|
||||||
'message' => 'You need to agree to our terms.',
|
'message' => 'You need to agree to our terms.',
|
||||||
|
|
|
@ -44,6 +44,19 @@ class OfferRepository extends ServiceEntityRepository
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findBySearchLiteral(string $literal)
|
||||||
|
{
|
||||||
|
$qb = $this->createQueryBuilder('o');
|
||||||
|
$qb->andWhere($qb->expr()->like('o.title', ':lit'))
|
||||||
|
->setParameter('lit', '%' . $literal . '%')
|
||||||
|
->orderBy('o.id', 'ASC')
|
||||||
|
;
|
||||||
|
|
||||||
|
$qb = $qb->getQuery()->getResult();
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public function findOneBySomeField($value): ?Offer
|
public function findOneBySomeField($value): ?Offer
|
||||||
{
|
{
|
||||||
|
|
|
@ -348,15 +348,9 @@
|
||||||
"symfony/polyfill-mbstring": {
|
"symfony/polyfill-mbstring": {
|
||||||
"version": "v1.22.1"
|
"version": "v1.22.1"
|
||||||
},
|
},
|
||||||
"symfony/polyfill-php73": {
|
|
||||||
"version": "v1.22.1"
|
|
||||||
},
|
|
||||||
"symfony/polyfill-php80": {
|
"symfony/polyfill-php80": {
|
||||||
"version": "v1.22.1"
|
"version": "v1.22.1"
|
||||||
},
|
},
|
||||||
"symfony/polyfill-php81": {
|
|
||||||
"version": "v1.23.0"
|
|
||||||
},
|
|
||||||
"symfony/polyfill-uuid": {
|
"symfony/polyfill-uuid": {
|
||||||
"version": "v1.22.1"
|
"version": "v1.22.1"
|
||||||
},
|
},
|
||||||
|
@ -404,9 +398,6 @@
|
||||||
"symfony/security-csrf": {
|
"symfony/security-csrf": {
|
||||||
"version": "v5.2.4"
|
"version": "v5.2.4"
|
||||||
},
|
},
|
||||||
"symfony/security-guard": {
|
|
||||||
"version": "v5.2.4"
|
|
||||||
},
|
|
||||||
"symfony/security-http": {
|
"symfony/security-http": {
|
||||||
"version": "v5.2.6"
|
"version": "v5.2.6"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
{% extends 'base.html.twig' %}
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
{% block title %}New Offer{% endblock %}
|
{% block title %}New Offer{% endblock %}
|
||||||
|
|
||||||
|
{% block javascripts %}
|
||||||
|
{{ encore_entry_script_tags('fileUpload') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{% for message in app.flashes('error') %}
|
{% for message in app.flashes('error') %}
|
||||||
|
|
|
@ -41,10 +41,10 @@
|
||||||
</p>
|
</p>
|
||||||
<p class="pr-3">
|
<p class="pr-3">
|
||||||
<i class="fas fa-map-marker-alt"></i> {{ offer.zipCode }}
|
<i class="fas fa-map-marker-alt"></i> {{ offer.zipCode }}
|
||||||
{% if distance > 0 %}
|
|
||||||
(ca. {{ distance }} km)
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
</p>
|
||||||
|
{% if distance > 0 %}
|
||||||
|
<p class="pr-3"><i class="fas fa-map-signs mr-1"></i>ca. {{ distance }} km</p>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<h3>Description</h3>
|
<h3>Description</h3>
|
||||||
<p>{{ offer.description }}</p>
|
<p>{{ offer.description }}</p>
|
||||||
|
|
|
@ -10,38 +10,38 @@
|
||||||
<meta name="robots" content="index,follow" />
|
<meta name="robots" content="index,follow" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<meta name="publisher" content="pflänz.li" />
|
<meta name="publisher" content="pflänz.li" />
|
||||||
<meta name="keywords" content="trade, share, plants", "sustainability" />
|
<meta name="keywords" content="trade, share, plants, sustainability, pflanzentausch, pflanzen" />
|
||||||
|
|
||||||
{% block stylesheets %}
|
{% block stylesheets %}
|
||||||
{{ encore_entry_link_tags('app') }}
|
{{ encore_entry_link_tags('app') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block javascripts %}
|
{% block javascripts %}{% endblock %}
|
||||||
{{ encore_entry_script_tags('app') }}
|
|
||||||
|
|
||||||
<!-- Matomo -->
|
{{ encore_entry_script_tags('app') }}
|
||||||
<script>
|
|
||||||
var _paq = window._paq = window._paq || [];
|
<!-- Matomo -->
|
||||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
<script>
|
||||||
_paq.push(['trackPageView']);
|
var _paq = window._paq = window._paq || [];
|
||||||
_paq.push(['enableLinkTracking']);
|
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||||
(function () {
|
_paq.push(['trackPageView']);
|
||||||
var u = "//analytics.thisfro.ch/";
|
_paq.push(['enableLinkTracking']);
|
||||||
_paq.push([
|
(function () {
|
||||||
'setTrackerUrl',
|
var u = "https://analytics.thisfro.ch/";
|
||||||
u + 'matomo.php'
|
_paq.push([
|
||||||
]);
|
'setTrackerUrl',
|
||||||
_paq.push(['setSiteId', '2']);
|
u + 'matomo.php'
|
||||||
var d = document,
|
]);
|
||||||
g = d.createElement('script'),
|
_paq.push(['setSiteId', '2']);
|
||||||
s = d.getElementsByTagName('script')[0];
|
var d = document,
|
||||||
g.async = true;
|
g = d.createElement('script'),
|
||||||
g.src = u + 'matomo.js';
|
s = d.getElementsByTagName('script')[0];
|
||||||
s.parentNode.insertBefore(g, s);
|
g.async = true;
|
||||||
})();
|
g.src = u + 'matomo.js';
|
||||||
</script>
|
s.parentNode.insertBefore(g, s);
|
||||||
<!-- End Matomo Code -->
|
})();
|
||||||
{% endblock %}
|
</script>
|
||||||
|
<!-- End Matomo Code -->
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
</head>
|
</head>
|
||||||
|
@ -110,11 +110,11 @@ s.parentNode.insertBefore(g, s);
|
||||||
</a>
|
</a>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg pt-4">
|
<div class="col-lg pt-4 pl-5">
|
||||||
<section>
|
<section>
|
||||||
<h2 class="h5">Links</h2>
|
<h2 class="h5">Links</h2>
|
||||||
<ul class="link-list">
|
<ul class="link-list">
|
||||||
<li><a href="https://blog.pflänz.li">Blog</a></li>
|
<li><a href="https://blog.pflaenz.li">Blog</a></li>
|
||||||
<li><a href="{{ path('imprint') }}">Imprint</a></li>
|
<li><a href="{{ path('imprint') }}">Imprint</a></li>
|
||||||
<li><a href="{{ path('faq') }}">FAQ</a></li>
|
<li><a href="{{ path('faq') }}">FAQ</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<div class="btn btn-primary"><i class="fas fa-filter mr-3"></i>Filter<i class="fas fa-chevron-down ml-3 dropdown-collapse"></i></div>
|
<div class="btn btn-primary"><i class="fas fa-filter mr-3"></i>Filter<i class="fas fa-chevron-down ml-3 dropdown-collapse"></i></div>
|
||||||
</a>
|
</a>
|
||||||
<div class="collapse" id="collapseExample">
|
<div class="collapse" id="collapseExample">
|
||||||
{{ form(filter_form) }}
|
{{ form(filter_form, {attr: {novalidate: 'novalidate'}}) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block meta %}
|
{% block meta %}
|
||||||
<meta name="description" content="Register for pflänz.li"
|
<meta name="description" content="Register for pflänz.li" />
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block javascripts %}
|
||||||
|
{{ encore_entry_script_tags('captcha') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
<h1>Reset your password</h1>
|
<h1>Reset your password</h1>
|
||||||
|
|
||||||
{{ form_start(resetForm) }}
|
{{ form_start(resetForm) }}
|
||||||
{{ form_row(resetForm.plainPassword) }}
|
{{form_widget(resetForm)}}
|
||||||
<button class="btn btn-primary">Reset password</button>
|
|
||||||
{{ form_end(resetForm) }}
|
{{ form_end(resetForm) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -21,6 +21,8 @@ Encore
|
||||||
* and one CSS file (e.g. app.css) if your JavaScript imports CSS.
|
* and one CSS file (e.g. app.css) if your JavaScript imports CSS.
|
||||||
*/
|
*/
|
||||||
.addEntry('app', './assets/app.js')
|
.addEntry('app', './assets/app.js')
|
||||||
|
.addEntry('captcha', './assets/captcha.js')
|
||||||
|
.addEntry('fileUpload', './assets/fileUpload.js')
|
||||||
|
|
||||||
// enables the Symfony UX Stimulus bridge (used in assets/bootstrap.js)
|
// enables the Symfony UX Stimulus bridge (used in assets/bootstrap.js)
|
||||||
.enableStimulusBridge('./assets/controllers.json')
|
.enableStimulusBridge('./assets/controllers.json')
|
||||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -936,6 +936,11 @@
|
||||||
error-stack-parser "^2.0.0"
|
error-stack-parser "^2.0.0"
|
||||||
string-width "^4.2.3"
|
string-width "^4.2.3"
|
||||||
|
|
||||||
|
"@snyk/protect@^1.834.0":
|
||||||
|
version "1.834.0"
|
||||||
|
resolved "https://registry.npmjs.org/@snyk/protect/-/protect-1.834.0.tgz"
|
||||||
|
integrity sha512-I/zzykVqRI4ZeIGwhwnQ/li01W0fJC6uMGdM6oGWOIOex3L6BBz2LTZeHr4PMoZDNha2TM10hgcYf9JvGvjNKQ==
|
||||||
|
|
||||||
"@stimulus/core@^2.0.0":
|
"@stimulus/core@^2.0.0":
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmjs.org/@stimulus/core/-/core-2.0.0.tgz"
|
resolved "https://registry.npmjs.org/@stimulus/core/-/core-2.0.0.tgz"
|
||||||
|
@ -1593,9 +1598,9 @@ caniuse-api@^3.0.0:
|
||||||
lodash.uniq "^4.5.0"
|
lodash.uniq "^4.5.0"
|
||||||
|
|
||||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001286:
|
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001286:
|
||||||
version "1.0.30001287"
|
version "1.0.30001388"
|
||||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001287.tgz"
|
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001388.tgz"
|
||||||
integrity sha512-4udbs9bc0hfNrcje++AxBuc6PfLNHwh3PO9kbwnfCQWyqtlzg3py0YgFu8jyRTTo85VAz4U+VLxSlID09vNtWA==
|
integrity sha512-znVbq4OUjqgLxMxoNX2ZeeLR0d7lcDiE5uJ4eUiWdml1J1EkxbnQq6opT9jb9SMfJxB0XA16/ziHwni4u1I3GQ==
|
||||||
|
|
||||||
chalk@^2.0.0, chalk@^2.3.2, chalk@^2.4.2:
|
chalk@^2.0.0, chalk@^2.3.2, chalk@^2.4.2:
|
||||||
version "2.4.2"
|
version "2.4.2"
|
||||||
|
@ -4197,11 +4202,6 @@ slash@^3.0.0:
|
||||||
resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
|
resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
|
||||||
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||||
|
|
||||||
snyk@^1.806.0:
|
|
||||||
version "1.806.0"
|
|
||||||
resolved "https://registry.npmjs.org/snyk/-/snyk-1.806.0.tgz"
|
|
||||||
integrity sha512-X0Aso0+zA9YXrrIgW1G3GXRqsvW4j7gXS9QyxFUwPp9qp5dAX1sjNUuLrK/z0CpuIpT7MVOBrYHF/RkMJ2C+FA==
|
|
||||||
|
|
||||||
sockjs@^0.3.21:
|
sockjs@^0.3.21:
|
||||||
version "0.3.24"
|
version "0.3.24"
|
||||||
resolved "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz"
|
resolved "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz"
|
||||||
|
|
Reference in a new issue