Commit 18706a45 authored by Dominik Hebeler's avatar Dominik Hebeler
Browse files

Merge branch '1142-include-key-for-paypal-donations' into 'development'

Resolve "Include Key for PayPal Donations"

Closes #1142

See merge request !1896
parents dfa2d931 58013409
......@@ -59,7 +59,7 @@ RUN sed -i 's/pid = \/run\/php\/php7.4-fpm.pid/;pid = \/run\/php\/php7.4-fpm.pid
sed -i 's/error_log = \/var\/log\/php7.4-fpm.log/error_log = \/dev\/stderr/g' /etc/php/7.4/fpm/php-fpm.conf && \
sed -i 's/;daemonize = yes/daemonize = no/g' /etc/php/7.4/fpm/php-fpm.conf && \
sed -i 's/listen = \/run\/php\/php7.4-fpm.sock/listen = 9000/g' /etc/php/7.4/fpm/pool.d/www.conf && \
sed -i 's/;request_terminate_timeout = 0/request_terminate_timeout = 30/g' /etc/php/7.4/fpm/pool.d/www.conf && \
sed -i 's/;request_terminate_timeout = 0/request_terminate_timeout = 0/g' /etc/php/7.4/fpm/pool.d/www.conf && \
sed -i 's/;request_terminate_timeout_track_finished = no/request_terminate_timeout_track_finished = yes/g' /etc/php/7.4/fpm/pool.d/www.conf && \
sed -i 's/;decorate_workers_output = no/decorate_workers_output = no/g' /etc/php/7.4/fpm/pool.d/www.conf && \
sed -i 's/;catch_workers_output = yes/catch_workers_output = yes/g' /etc/php/7.4/fpm/pool.d/www.conf && \
......@@ -99,6 +99,7 @@ USER 0:0
RUN apt purge -y php7.4-xdebug
RUN sed -i 's/expose_php = On/expose_php = Off/g' /etc/php/7.4/fpm/php.ini && \
sed -i 's/;opcache.enable=1/opcache.enable=1/g' /etc/php/7.4/fpm/php.ini && \
sed -i 's/request_terminate_timeout = 0/request_terminate_timeout = 30/g' /etc/php/7.4/fpm/pool.d/www.conf && \
sed -i 's/;opcache.memory_consumption=128/opcache.memory_consumption=128/g' /etc/php/7.4/fpm/php.ini && \
sed -i 's/;opcache.interned_strings_buffer=8/opcache.interned_strings_buffer=8/g' /etc/php/7.4/fpm/php.ini && \
sed -i 's/;opcache.max_accelerated_files=10000/opcache.max_accelerated_files=10000/g' /etc/php/7.4/fpm/php.ini && \
......
......@@ -75,13 +75,13 @@ class MailController extends Controller
"attachments" => []
];
if($request->has("attachments") && is_array($request->file("attachments"))){
foreach($request->file("attachments") as $attachment){
if ($request->has("attachments") && is_array($request->file("attachments"))) {
foreach ($request->file("attachments") as $attachment) {
$postdata["attachments"][] = [
$attachment->getClientOriginalName() => "data:" . $attachment->getMimeType() . ";base64," . base64_encode(file_get_contents($attachment->getRealPath()))
];
}
}
}
if (LaravelLocalization::getCurrentLocale() === "de") {
$postdata["deptId"] = 1;
......@@ -117,12 +117,12 @@ class MailController extends Controller
// Fetch the result
$answer = Redis::blpop($resulthash, 20);
// Fehlerfall
if(empty($answer) || (is_array($answer) && sizeof($answer) === 2 && $answer[1] === "no-result")){
if (empty($answer) || (is_array($answer) && sizeof($answer) === 2 && $answer[1] === "no-result")) {
$messageType = "error";
$returnMessage = trans('kontakt.error.2', ["email" => config("mail.mailers.smtp.username")]);
}else{
} else {
$returnMessage = trans('kontakt.success.1', ["email" => $replyTo]);
$messageType = "success";
}
......@@ -132,7 +132,6 @@ class MailController extends Controller
->with('title', 'Kontakt')
->with('js', ['lib.js'])
->with($messageType, $returnMessage);
}
public function donation(Request $request)
......@@ -151,10 +150,10 @@ class MailController extends Controller
$lastname = "";
$company = "";
$private = $request->input('person', '') === 'private' ? true : false;
if($request->input('person', '') === 'private') {
if ($request->input('person', '') === 'private') {
$firstname = $request->input('firstname');
$lastname = $request->input('lastname');
} elseif($request->input('person', '') === 'company') {
} elseif ($request->input('person', '') === 'company') {
$company = $request->input('companyname');
}
......@@ -170,7 +169,7 @@ class MailController extends Controller
'frequency' => $request->input('frequency', ''),
'nachricht' => $request->input('Nachricht', ''),
];
$iban = $request->input('iban', '');
$bic = $request->input('bic', '');
$email = $request->input('email', '');
......@@ -213,7 +212,7 @@ class MailController extends Controller
if ($validator->fails()) {
$messageToUser = trans('spende.error.robot');
$messageType = "error";
} elseif(($private && (empty($firstname) || empty($lastname))) || (!$private && empty($company))){
} elseif (($private && (empty($firstname) || empty($lastname))) || (!$private && empty($company))) {
$messageToUser = trans('spende.error.name');
$messageType = "error";
} elseif (!$iban->Verify()) {
......@@ -232,10 +231,6 @@ class MailController extends Controller
# The value has to have a maximum of 2 decimal digits
$betrag = round($betrag, 2, PHP_ROUND_HALF_DOWN);
# Generating personalised key for donor
$key = app('App\Models\Key')->generateKey($betrag, null, null, 'Für ' . $betrag . '€ aufgeladen am '. date("d.m.Y"));
try {
$postdata = [
"entity" => "Contribution",
......@@ -248,21 +243,19 @@ class MailController extends Controller
"amount" => $betrag,
"frequency" => $frequency,
"email" => $email,
"mgkey" => $key,
"message" => $nachricht
];
if($request->input('person') === 'private') {
if ($request->input('person') === 'private') {
$postdata['first_name'] = $firstname;
$postdata['last_name'] = $lastname;
} elseif($request->input('person') === 'company') {
} elseif ($request->input('person') === 'company') {
$postdata['business_name'] = $company;
}
$postdata = http_build_query($postdata);
$resulthash = md5(json_encode($postdata));
$mission = [
"resulthash" => $resulthash,
"url" => config("metager.metager.civicrm.url"),
......@@ -284,15 +277,22 @@ class MailController extends Controller
];
$mission = json_encode($mission);
Redis::rpush(\App\MetaGer::FETCHQUEUE_KEY, $mission);
// Fetch the result
$answer = Redis::blpop($resulthash, 20);
$key = "";
// Fehlerfall
if(empty($answer) || (is_array($answer) && sizeof($answer) === 2 && $answer[1] === "no-result")){
if (empty($answer) || (is_array($answer) && sizeof($answer) === 2 && $answer[1] === "no-result")) {
$messageType = "error";
$messageToUser = "Beim Senden Ihrer Spendenbenachrichtigung ist ein Fehler auf unserer Seite aufgetreten. Bitte schicken Sie eine E-Mail an: dominik@suma-ev.de, damit wir uns darum kümmern können.";
}else{
}
$answer = json_decode($answer[1], true);
if ($answer["is_error"] !== 0 || $answer["count"] !== 1) {
$messageType = "error";
$messageToUser = "Beim Senden Ihrer Spendenbenachrichtigung ist ein Fehler auf unserer Seite aufgetreten. Bitte schicken Sie eine E-Mail an: dominik@suma-ev.de, damit wir uns darum kümmern können.";
} else {
$key = $answer["values"][0]["MGKey.MGKey"];
$messageToUser = "Herzlichen Dank!! Wir haben Ihre Spendenbenachrichtigung erhalten.";
$messageType = "success";
}
......@@ -316,6 +316,158 @@ class MailController extends Controller
}
}
public function donationPayPalCallback(Request $request)
{
$url = "https://www.sandbox.paypal.com/cgi-bin/webscr";
# PayPal Transaction ID
$tx = $request->input("tx", "");
$postdata = [
"cmd" => "_notify-synch",
"tx" => $tx,
"at" => config("metager.metager.paypal.pdt_token"),
"submit" => "PDT",
];
$postdata = http_build_query($postdata);
$resulthash = md5($tx);
$mission = [
"resulthash" => $resulthash,
"url" => $url,
"useragent" => "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:81.0) Gecko/20100101 Firefox/81.0",
"username" => null,
"password" => null,
"headers" => [
"Content-Type" => "application/x-www-form-urlencoded",
],
"cacheDuration" => 0,
"name" => "Ticket",
"curlopts" => [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postdata,
CURLOPT_LOW_SPEED_TIME => 20,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 20
]
];
$mission = json_encode($mission);
Redis::rpush(\App\MetaGer::FETCHQUEUE_KEY, $mission);
// Fetch the result
// Verify at PayPal that the transaction was indeed SUCCESSFULL
$answer = Redis::blpop($resulthash, 20);
if (sizeof($answer) !== 2) {
return ''; # TODO Redirect on failure
} else {
$answer = $answer[1];
$answer = explode("\n", $answer);
}
if ($answer[0] !== "SUCCESS") {
return ''; #TODO Redirect on failure
}
# Transaction was successfull. Let's parse the details
array_splice($answer, 0, 1);
$answertmp = $answer;
$answer = [];
foreach ($answertmp as $index => $element) {
if (preg_match("/^([^=]+)=(.*)$/", $element, $matches) === 1) {
$key = $matches[1];
$value = urldecode($matches[2]);
$answer[$key] = $value;
}
}
$data = [
"person" => "private",
"firstname" => !empty($answer["first_name"]) ? $answer["first_name"] : "",
"lastname" => !empty($answer["last_name"]) ? $answer["last_name"] : "",
"company" => "",
"iban" => "",
"bic" => "",
"email" => !empty($answer["payer_email"]) ? $answer["payer_email"] : "",
"betrag" => !empty($answer["mc_gross"]) && !empty($answer["mc_fee"]) ? floatval($answer["mc_gross"]) - floatval($answer["mc_fee"]) : 0,
"nachricht" => !empty($answer["memo"]) ? $answer["memo"] : "",
];
// Generate a key
$postdata = [
"entity" => "Contribution",
"action" => "mgcreate",
"api_key" => config("metager.metager.civicrm.apikey"),
"key" => config("metager.metager.civicrm.sitekey"),
"json" => 1,
"amount" => $data["betrag"],
"frequency" => "once",
"email" => $data["email"],
"message" => $data["nachricht"],
'first_name' => $data["firstname"],
'last_name' => $data["lastname"],
'transaction_id' => $answer["txn_id"]
];
$postdata = http_build_query($postdata);
$resulthash = md5(json_encode($postdata));
$mission = [
"resulthash" => $resulthash,
"url" => config("metager.metager.civicrm.url"),
"useragent" => "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:81.0) Gecko/20100101 Firefox/81.0",
"username" => null,
"password" => null,
"headers" => [
"Content-Type" => "application/x-www-form-urlencoded",
],
"cacheDuration" => 0,
"name" => "Ticket",
"curlopts" => [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postdata,
CURLOPT_LOW_SPEED_TIME => 20,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 20
]
];
$mission = json_encode($mission);
Redis::rpush(\App\MetaGer::FETCHQUEUE_KEY, $mission);
// Fetch the result
$answer = Redis::blpop($resulthash, 20);
$key = "";
$messageToUser = "";
$messageType = ""; # [success|error]
// Fehlerfall
if (empty($answer) || (is_array($answer) && sizeof($answer) === 2 && $answer[1] === "no-result")) {
$messageType = "error";
$messageToUser = "Beim Senden Ihrer Spendenbenachrichtigung ist ein Fehler auf unserer Seite aufgetreten. Bitte schicken Sie eine E-Mail an: dominik@suma-ev.de, damit wir uns darum kümmern können.";
}
$answer = json_decode($answer[1], true);
if ($answer["is_error"] !== 0 || $answer["count"] !== 1) {
$messageType = "error";
$messageToUser = "Beim Senden Ihrer Spendenbenachrichtigung ist ein Fehler auf unserer Seite aufgetreten. Bitte schicken Sie eine E-Mail an: dominik@suma-ev.de, damit wir uns darum kümmern können.";
} else {
$key = $answer["values"][0]["MGKey.MGKey"];
$messageToUser = "Herzlichen Dank!! Wir haben Ihre Spende erhalten.";
$messageType = "success";
}
if ($messageType === "error") {
return view('spende.spende')
->with('title', 'Kontakt')
->with($messageType, $messageToUser);
} else {
$data['key'] = $key;
$data = base64_encode(serialize($data));
return redirect(LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), route("danke", ['data' => $data])));
}
}
#Ueberprueft ob ein bereits vorhandener Eintrag bearbeitet worden ist
public static function isEdited($k, $v, $filename)
{
......
......@@ -66,7 +66,7 @@ class MetaGerSearch extends Controller
$metager->startSearch($timings);
# Versuchen die Ergebnisse der Quicktips zu laden
if($quicktips !== null) {
if ($quicktips !== null) {
$quicktipResults = $quicktips->loadResults();
if (!empty($timings)) {
$timings["Loaded Quicktip Results"] = microtime(true) - $time;
......@@ -95,13 +95,13 @@ class MetaGerSearch extends Controller
$metager->prepareResults($timings);
$admitad = [];
$adgoal = [];
if(!$metager->isApiAuthorized() && !$metager->isDummy()){
if (!$metager->isApiAuthorized() && !$metager->isDummy()) {
$newAdmitad = new \App\Models\Admitad($metager);
if(!empty($newAdmitad->hash)){
if (!empty($newAdmitad->hash)) {
$admitad[] = $newAdmitad;
}
$newAdgoal = new \App\Models\Adgoal($metager);
if(!empty($newAdgoal->hash)){
if (!empty($newAdgoal->hash)) {
$adgoal[] = $newAdgoal;
}
}
......@@ -109,6 +109,11 @@ class MetaGerSearch extends Controller
$metager->parseAffiliates($admitad);
$metager->parseAffiliates($adgoal);
// Add Advertisement for Donations
if (!$metager->isApiAuthorized() && !$metager->isDummy()) {
$metager->addDonationAdvertisement();
}
$finished = true;
foreach ($metager->getEngines() as $engine) {
if ($engine->loaded) {
......@@ -153,7 +158,7 @@ class MetaGerSearch extends Controller
// This might speed up page view time for users with slow network
$responseArray = str_split($resultpage->render(), 1024);
foreach ($responseArray as $responsePart) {
echo($responsePart);
echo ($responsePart);
flush();
}
$requestTime = microtime(true) - $time;
......@@ -223,13 +228,13 @@ class MetaGerSearch extends Controller
$metager->rankAll();
$metager->prepareResults();
if(!$metager->isApiAuthorized() && !$metager->isDummy()){
if (!$metager->isApiAuthorized() && !$metager->isDummy()) {
$newAdmitad = new \App\Models\Admitad($metager);
if(!empty($newAdmitad->hash)){
if (!empty($newAdmitad->hash)) {
$admitad[] = $newAdmitad;
}
$newAdgoal = new \App\Models\Adgoal($metager);
if(!empty($newAdgoal->hash)){
if (!empty($newAdgoal->hash)) {
$adgoal[] = $newAdgoal;
}
}
......
......@@ -310,6 +310,7 @@ class MetaGer
}
$newResults[] = $ad;
}
$this->ads = $newResults;
if (!empty($timings)) {
$timings["prepareResults"]["validated ads"] = microtime(true) - $timings["starttime"];
......@@ -446,6 +447,45 @@ class MetaGer
return $finished;
}
/**
* Modifies the already filled array of advertisements and
* includes an advertisement for our donation page.
*
* It will do so everytime when there are other advertisments to mix it in
* and only in a percentage of cases when there are no other advertisements.
*
* The Position at which our advertisement is placed is random within the other
* advertisements. In some cases it will be the first ad and in other cases in some
* other place.
*/
public function addDonationAdvertisement()
{
/**
* If there are no other advertisements we will only display our advertisements
* every so often. ~33% in this case
*/
if (sizeof($this->ads) === 0 && rand(1, 100) > 33) {
return;
}
$donationAd = new \App\Models\Result(
"MetaGer",
__("metaGer.ads.own.title"),
LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), route("spende")),
LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), route("spende")),
__("metaGer.ads.own.description"),
"MetaGer",
"https://metager.de",
1
);
$adCount = sizeof($this->ads);
// Put Donation Advertisement to random position
$position = random_int(0, $adCount);
array_splice($this->ads, $position, 0, [$donationAd]);
}
public function humanVerification(&$results)
{
# Let's check if we need to implement a redirect for human verification
......
......@@ -55,6 +55,9 @@ return [
"user" => env("WEBDRIVER_USER", ""),
"key" => env("WEBDRIVER_KEY", ""),
],
"paypal" => [
'pdt_token' => env("PAYPAL_PDT_TOKEN", ""),
],
"maps" => [
"version" => env("maps_version"),
],
......
......@@ -139,4 +139,7 @@ return [
"filter.max" => "Maximum Sleep (in s)",
"settings" => "Einstellungen",
"ads.own.title" => "Jetzt MetaGer unterstützen",
"ads.own.description" => "Mit Ihrer Spende unterstützen Sie den Erhalt und die Weiterentwicklung der unabhängigen Suchmaschine metager.de und die Arbeit des gemeinnützigen Trägervereins SUMA-EV.",
];
......@@ -139,4 +139,7 @@ return [
"filter.max" => "Maximum sleep (in s)",
"settings" => "Settings",
"ads.own.title" => "Support MetaGer",
"ads.own.description" => "With your donation you support the maintenance and further development of the independent search engine metager.de and the work of the non-profit association SUMA-EV.",
];
<?php
return [
"results.failed" => "Lo sentimos. No encontrado resultados adecuados.",
"settings.noneSelected" => "¡Guarda! No habéis seleccionado un motor de busqueda.",
"engines.noParser" => "Falta: Preguntar :engine. Por favor notificáis MetaGer: <a href=\"/es/kontakt\">Formulario encriptado</a>",
"formdata.noSearch" => "¡Guarda! No insertado palabras para buscar.",
"formdata.hostBlacklist" => "No recibís resultados del host \":host\"",
"formdata.domainBlacklist" => "No recibís resultados del dominio: \":domain\"",
"formdata.stopwords" => "Resultados sin \":stopwords\"",
"formdata.phrase" => "Resultados \":phrase\"",
"sitesearch.failed" => "Habéis querido una búsqueda en \":site\". Los motores de busqueda seleccioados no tienen resultados. Podéis hacer el sitesearch en el foco \"Web\": <a href=\":searchLink\">hier</a> ",
"sitesearch.success" => "Habéis querido una búsqueda \"sitesearch\". Recibís resultados solo de <a href=\"http://:site\" target=\"_blank\" rel=\"noopener\">\":site\"</a> ."
];
\ No newline at end of file
"results.failed" => "Lo sentimos. No encontrado resultados adecuados.",
"settings.noneSelected" => "¡Guarda! No habéis seleccionado un motor de busqueda.",
"engines.noParser" => "Falta: Preguntar :engine. Por favor notificáis MetaGer: <a href=\"/es/kontakt\">Formulario encriptado</a>",
"formdata.noSearch" => "¡Guarda! No insertado palabras para buscar.",
"formdata.hostBlacklist" => "No recibís resultados del host \":host\"",
"formdata.domainBlacklist" => "No recibís resultados del dominio: \":domain\"",
"formdata.stopwords" => "Resultados sin \":stopwords\"",
"formdata.phrase" => "Resultados \":phrase\"",
"sitesearch.failed" => "Habéis querido una búsqueda en \":site\". Los motores de busqueda seleccioados no tienen resultados. Podéis hacer el sitesearch en el foco \"Web\": <a href=\":searchLink\">hier</a> ",
"sitesearch.success" => "Habéis querido una búsqueda \"sitesearch\". Recibís resultados solo de <a href=\"http://:site\" target=\"_blank\" rel=\"noopener\">\":site\"</a> .",
"ads.own.title" => "Apoya a MetaGer",
"ads.own.description" => "Con su donación, apoya el mantenimiento y desarrollo del motor de búsqueda independiente metager.de y el trabajo de la asociación patrocinadora sin fines de lucro SUMA-EV.",
];
......@@ -78,6 +78,7 @@
.quicktip-headline {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.quicktip-title,
......@@ -232,6 +233,10 @@
}
}
.mg-icon {
filter: @invert-state
}
.mg-icon-rot180 {
transition: transform 0.5s;
}
......
@import "./variables.less";
// Default Background Color
......@@ -14,19 +13,21 @@
@card-background-color: @color-strong-grey;
// Default Borde Color
@border-color: #727272;
// Inverts color of svgs. Our Svgs are all black which means 0% invert for light and 100% for dark.
@invert-state: invert(100%);
// Story coloring
@story-privacy-background: @color-strong-grey;
@story-privacy-color: @color-almost-white;
@story-ngo-background:#200000;
@story-ngo-color:#ffaaaa;
@story-diversity-background:#000020;
@story-diversity-color:#aaaaff;
@story-eco-background:#002000;
@story-eco-color:#aaffaa;
@story-ngo-background: #200000;
@story-ngo-color: #ffaaaa;
@story-diversity-background: #000020;
@story-diversity-color: #aaaaff;
@story-eco-background: #002000;
@story-eco-color: #aaffaa;
@story-plugin-background: @color-almost-black;
@story-font-color: @color-almost-white;
@icon-color:0.9;
@icon-color: 0.9;
@searchbar-background-color: @color-almost-black;
......@@ -34,4 +35,4 @@
@input-text: @color-almost-white;
@blacklist-entries-odd: @color-almost-black;
@blacklist-entries-even:rgb(30, 15, 0);
\ No newline at end of file
@blacklist-entries-even: rgb(30, 15, 0);
\ No newline at end of file
......@@ -12,6 +12,7 @@
@background-color: @color-white;
@background-color-mobile: #FAFAFA;
@sidebar-list-hover-color: @color-almost-white;
@invert-state: invert(0%); // Inverts color of svgs. Our Svgs are all black which means 0% invert for light and 100% for dark.
// Default Font
@metager-font: "Liberation Sans",
"Helvetica Neue",
......
......@@ -31,10 +31,12 @@
<input type="text" name="email" id="email" value="{{ $data['email'] }}" readonly>
</div>
@endif
@if(!empty($data['iban']))
<div class="data-element">
<label for="iban" style="margin-right: 16px;">{{ trans('spende.iban') }}</label>
<input type="text" name="iban" id="iban" value="{{ $data['iban'] }}" readonly>
</div>
@endif
@if(!empty($data["bic"]))
<div class="data-element">
<label for="bic" style="margin-right: 16px;">{{ trans('spende.bic') }}</label>
......@@ -45,10 +47,12 @@
<label for="betrag" style="margin-right: 16px;">{{ trans('spende.betrag') }}</label>
<input type="text" name="betrag" id="betrag" value="{{ $data['betrag'] }} €" readonly>
</div>
@if(!empty($data['frequency']))
<div class="data-element">
<label for="frequency" style="margin-right: 16px;">{{ trans('spende.frequency') }}</label>
<input type="text" name="frequency" id="frequency" value="{{ trans('spende.frequency.' . $data['frequency']) }}" readonly>
</div>
@endif
<div class="data-element">
<label for="nachricht" style="margin-right: 16px;">{{ trans('spende.danke.message') }}</label>
<textarea name="nachricht" id="nachricht" readonly>{{ $data['nachricht'] }}</textarea>
......
......@@ -165,4 +165,4 @@
</div>
</div>
</div>
@endsection
@endsection
\ No newline at end of file
......@@ -80,20 +80,28 @@ Route::get('tor', function () {
->with('title', 'tor hidden service - MetaGer')
->with('navbarFocus', 'dienste');
});
Route::get('spende', function () {
return view('spende.spende')
->with('title', trans('titles.spende'))
->with('js', [mix('/js/donation.js')])
->with('navbarFocus', 'foerdern');
})->name("spende");
Route::get('spende/danke/{data}', function ($data) {
return view('spende.danke')
->with('title', trans('titles.spende'))
->with('navbarFocus', 'foerdern')
->with('css', [mix('/css/spende/danke.css')])
->with('data', unserialize(base64_decode($data)));
})->name("danke");