Implement Zammad contact form
All checks were successful
continuous-integration/drone/pr Build is passing
All checks were successful
continuous-integration/drone/pr Build is passing
Closes #190
This commit is contained in:
parent
8aa0599432
commit
d8884ba9ea
@ -1087,40 +1087,16 @@ hr.-even {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.contact_form--required {
|
||||
color: var(--dark-red)
|
||||
}
|
||||
|
||||
.contact_form__textarea,
|
||||
.contact_form__text_input,
|
||||
.contact_form__captcha {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.contact_form__message {
|
||||
height: 12em;
|
||||
}
|
||||
|
||||
.contact_form__subject,
|
||||
.contact_form__message,
|
||||
.contact_form__name,
|
||||
.contact_form__email,
|
||||
.contact_form__captcha {
|
||||
.zammad-form-control {
|
||||
font-family: 'Lato', sans-serif;
|
||||
line-height: 1.3rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.contact_form__submit_button {
|
||||
.zammad-form .btn {
|
||||
font-size: 1rem;
|
||||
padding: 0 0.25rem;
|
||||
}
|
||||
|
||||
/* Hide captcha field as part of spam protection. We got no real captcha. */
|
||||
.contact_form__captcha {
|
||||
display: none;
|
||||
}
|
||||
/* main - Ende */
|
||||
|
||||
/* footer - Start */
|
||||
|
@ -1,95 +0,0 @@
|
||||
const contactFormAjaxUrl = '/php/contact_form.php';
|
||||
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
const contact_form = document.getElementsByClassName('content__contact_form')[0];
|
||||
if (contact_form) {
|
||||
contact_form.addEventListener('submit', wtf_submitContactForm, false);
|
||||
wtf_startContactFormSession();
|
||||
}
|
||||
});
|
||||
|
||||
function wtf_startContactFormSession() {
|
||||
let formData = new FormData();
|
||||
formData.append('action', 'start_session');
|
||||
fetch(contactFormAjaxUrl, {
|
||||
method: 'POST',
|
||||
mode: 'same-origin',
|
||||
body: formData,
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Response was not OK');
|
||||
}
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then(json => {
|
||||
console.log(json);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Could not start the session:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function wtf_submitContactForm(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const subject = document.getElementsByClassName('contact_form__subject')[0];
|
||||
const message = document.getElementsByClassName('contact_form__message')[0];
|
||||
const name = document.getElementsByClassName('contact_form__name')[0];
|
||||
const email = document.getElementsByClassName('contact_form__email')[0];
|
||||
const captcha = document.getElementsByClassName('contact_form__captcha')[0];
|
||||
|
||||
let formData = new FormData();
|
||||
formData.append('action', 'handle_form');
|
||||
formData.append('subject', subject.value);
|
||||
formData.append('message', message.value);
|
||||
formData.append('name', name.value);
|
||||
formData.append('email', email.value);
|
||||
|
||||
// If some bot entered some value, return.
|
||||
if (typeof captcha.value == 'undefined') {
|
||||
formData.append('captcha', 'Nudelsuppe');
|
||||
} else {
|
||||
console.log('bot detected');
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(contactFormAjaxUrl, {
|
||||
method: 'POST',
|
||||
mode: 'same-origin',
|
||||
body: formData,
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(json => {
|
||||
const feedback = document.getElementsByClassName('contact_form__feedback')[0];
|
||||
console.log(json);
|
||||
if (json.errors) {
|
||||
feedback.classList.remove('--success');
|
||||
feedback.classList.add('--error');
|
||||
// Über errors iterieren und diese ausgeben (evtl. nur ersten Fehler ausgeben?)
|
||||
let error_message = '';
|
||||
json.errors.forEach(function(error){
|
||||
/**
|
||||
* Nur Zeilenumbrüche wenn mehrer Fehlermeldungen existieren,
|
||||
* aber bei der letzten nicht.
|
||||
*/
|
||||
if (json.errors.length > 1) {
|
||||
if (error == json.errors[json.errors.length - 1]) {
|
||||
error_message = error_message + error;
|
||||
} else {
|
||||
error_message = error_message + error + '<br>';
|
||||
}
|
||||
} else {
|
||||
error_message = error_message + error;
|
||||
}
|
||||
})
|
||||
feedback.innerHTML = error_message;
|
||||
} else if (json.status == 'ok') {
|
||||
feedback.classList.remove('--error');
|
||||
feedback.classList.add('--success');
|
||||
feedback.textContent = "Ihre Nachricht wurde erfolgreich ans Office geschickt.";
|
||||
}
|
||||
})
|
||||
.catch(error => console.log(error));
|
||||
}
|
2
assets/js/jquery-3.7.1.min.js
vendored
Normal file
2
assets/js/jquery-3.7.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,139 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
function sanitize_text(string $name, string $type) {
|
||||
$filters = array(
|
||||
'text' => FILTER_SANITIZE_SPECIAL_CHARS,
|
||||
'email' => FILTER_SANITIZE_EMAIL,
|
||||
);
|
||||
$text = filter_var(trim($_POST[$name]), $filters[$type]);
|
||||
$text = stripslashes($text);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
function prepare_message_body(string $message, string $name) {
|
||||
// Replace HTML-Entities with actual carriage returns and line feeds
|
||||
$message = str_replace(" ", "\r", $message);
|
||||
$message = str_replace(" ", "\n", $message);
|
||||
|
||||
// Ensure line breaks via carriage return + line feed
|
||||
$message = str_replace("\r\n", "\n", $message);
|
||||
$message = str_replace("\n", "\r\n", $message);
|
||||
|
||||
$message = "Nachricht von: $name\r\n\r\n" . $message;
|
||||
$message = base64_encode($message);
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sending email
|
||||
*
|
||||
* mail(): Braucht auf dem Server einen korrekt konfigurierten Mailserver
|
||||
* phpmailer: Bibliothek, der per Composer installiert wird. Tut ganz gut mit SMTP.
|
||||
*/
|
||||
function send_message_to_office(string $subject, string $message, string $name, string $email) {
|
||||
$returnPath = filter_var(getenv('WTF_RETURN_PATH'), FILTER_VALIDATE_EMAIL);
|
||||
$to = filter_var(getenv('WTF_CONTACT_TO'), FILTER_VALIDATE_EMAIL);
|
||||
|
||||
if (!$returnPath || !$to) {
|
||||
error_log('Address for "To" or "Return-Path" is invalid');
|
||||
return false;
|
||||
}
|
||||
|
||||
return mail(
|
||||
$to,
|
||||
"=?UTF-8?B?" . base64_encode($subject) . "?=",
|
||||
prepare_message_body($message, $name),
|
||||
array(
|
||||
"From" => getenv('WTF_CONTACT_FROM'),
|
||||
"Reply-To" => $email,
|
||||
"Content-Type" => "text/plain; charset=utf-8",
|
||||
"Content-Transfer-Encoding" => "base64",
|
||||
),
|
||||
"-f $returnPath"
|
||||
);
|
||||
}
|
||||
|
||||
function send_response(array $response_data) {
|
||||
$json = json_encode($response_data);
|
||||
if ($json === false) {
|
||||
// Avoid echo of empty string (which is invalid JSON), and
|
||||
// JSONify the error message instead:
|
||||
$json = json_encode(["jsonError" => json_last_error_msg()]);
|
||||
if ($json === false) {
|
||||
// This should not happen, but …
|
||||
$json = '{"jsonError":"unknown"}';
|
||||
}
|
||||
// Set HTTP response status code to: 500 - Internal Server Error
|
||||
http_response_code(500);
|
||||
}
|
||||
header('Content-type: application/json');
|
||||
echo $json;
|
||||
}
|
||||
|
||||
function prepare_response() {
|
||||
$response = array();
|
||||
|
||||
if (empty($_POST['message'])) {
|
||||
$response['errors'][] = 'Sie haben keine Nachricht eingegeben.';
|
||||
}
|
||||
if (empty($_POST['email'])) {
|
||||
$response['errors'][] = 'Sie haben keine E-Mail-Adresse eingegeben.';
|
||||
}
|
||||
if (empty($_POST['name'])) {
|
||||
$response['errors'][] = 'Sie haben keinen Namen eingegeben.';
|
||||
}
|
||||
if (empty($_POST['subject'])) {
|
||||
$response['errors'][] = 'Sie haben keinen Betreff eingegeben.';
|
||||
}
|
||||
/**
|
||||
* Idee zur Bot-Erkennung:
|
||||
* 1. Ein Bot hat das Pseudocaptcha entweder leer abgeschickt, oder sich selbst etwas ausgedacht.
|
||||
* 2. Ein Bot schickt die Daten in unter 5s ab.
|
||||
* 3. Ein Mensch braucht nicht länger als 60min.
|
||||
*/
|
||||
if (
|
||||
$_POST['captcha'] != 'Nudelsuppe' or
|
||||
time() - $_SESSION['start_time'] < 5 or
|
||||
time() - $_SESSION['start_time'] > 3600
|
||||
) {
|
||||
$response['errors'][] = 'Wir glauben Sie sind ein Bot.';
|
||||
}
|
||||
if (!array_key_exists('errors', $response)) {
|
||||
$subject = sanitize_text('subject', 'text');
|
||||
$message = sanitize_text('message', 'text');
|
||||
$name = sanitize_text('name', 'text');
|
||||
$email = sanitize_text('email', 'email');
|
||||
|
||||
if (!send_message_to_office($subject, $message, $name, $email)) {
|
||||
$response['errors'][] = 'Ihre Nachricht konnte nicht übermittelt werden.';
|
||||
} else {
|
||||
$response['status'] = 'ok';
|
||||
}
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$response = array();
|
||||
|
||||
if (empty($_POST['action'])){
|
||||
$response['errors'][] = 'Kann eigentlich nicht passieren :/';
|
||||
} else {
|
||||
if ($_POST['action'] == 'start_session') {
|
||||
$_SESSION['start_time'] = time();
|
||||
// $response['session_start_time'] = $_SESSION['start_time'];
|
||||
// $response['session_id_before'] = session_id();
|
||||
} elseif ($_POST['action'] == 'handle_form') {
|
||||
$response = prepare_response();
|
||||
session_destroy();
|
||||
} else {
|
||||
$response['errors'][] = 'Kann eigentlich auch nicht passieren :/';
|
||||
}
|
||||
}
|
||||
send_response($response);
|
||||
} else {
|
||||
http_response_code(404);
|
||||
}
|
@ -135,17 +135,10 @@ kompetenzen_heading: Expertise
|
||||
---
|
||||
contact_form_button: Send message
|
||||
---
|
||||
contact_form_email: Email address
|
||||
---
|
||||
contact_form_heading: Contact
|
||||
---
|
||||
contact_form_info:
|
||||
|
||||
Your email address will not be published.<br>
|
||||
<span aria-hidden="true">Required fields are marked <span class="contact_form--required" aria-hidden="true">*</span>
|
||||
---
|
||||
contact_form_message: Message
|
||||
Your email address will not be published.
|
||||
---
|
||||
contact_form_subheading: Contact form
|
||||
---
|
||||
contact_form_subject: Subject
|
||||
|
@ -138,19 +138,10 @@ kompetenzen_heading: Kompetenzen
|
||||
---
|
||||
contact_form_button: Anfrage abschicken
|
||||
---
|
||||
contact_form_email: E-Mail-Adresse
|
||||
---
|
||||
contact_form_heading: Kontakt
|
||||
---
|
||||
contact_form_info:
|
||||
|
||||
Deine E-Mail-Adresse wird nicht veröffentlicht.<br>
|
||||
<span aria-hidden="true">Erforderliche Felder sind gekennzeichnet <span class="contact_form--required" aria-hidden="true">*</span>
|
||||
---
|
||||
contact_form_message: Nachricht
|
||||
---
|
||||
contact_form_name: Name
|
||||
Deine E-Mail-Adresse wird nicht veröffentlicht.
|
||||
---
|
||||
contact_form_subheading: Kontaktformular
|
||||
---
|
||||
contact_form_subject: Betreff
|
||||
|
@ -89,35 +89,10 @@
|
||||
<div class="content__box">
|
||||
<div class="content__inner_box -width_constraint content__contact_form_wrapper">
|
||||
<h2 id="contact">{{ this.contact_form_subheading }}</h2>
|
||||
<form id="contact_form" class="content__contact_form">
|
||||
<p class="contact_form__note">
|
||||
{{ this.contact_form_info }}
|
||||
</p>
|
||||
<p class="contact_form__text_input">
|
||||
<label for="name">{{ this.contact_form_subject }} <span class="contact_form--required" aria-hidden="true">*</span></label>
|
||||
<input id="name" class="contact_form__subject" name="subject" type="text" value="" size="30" maxlength="245" required />
|
||||
</p>
|
||||
<p class="contact_form__textarea">
|
||||
<label for="message">{{ this.contact_form_message }} <span class="contact_form--required" aria-hidden="true">*</span></label>
|
||||
<textarea id="message" class="contact_form__message" aria-label="message" aria-hidden="true" cols="65" rows="7" name="message" required></textarea>
|
||||
</p>
|
||||
<p class="contact_form__text_input">
|
||||
<label for="name">{{ this.contact_form_name }} <span class="contact_form--required" aria-hidden="true">*</span></label>
|
||||
<input id="name" class="contact_form__name" name="name" type="text" value="" size="30" maxlength="245" required />
|
||||
</p>
|
||||
<p class="contact_form__text_input">
|
||||
<label for="email">{{ this.contact_form_email }} <span class="contact_form--required" aria-hidden="true">*</span></label>
|
||||
<input id="email" class="contact_form__email" name="email" type="email" value="" size="30" maxlength="100" aria-describedby="email-address" required />
|
||||
</p>
|
||||
<p class="contact_form__captcha">
|
||||
<label for="captcha">Captcha <span class="contact_form--required" aria-hidden="true">*</span></label>
|
||||
<input id="captcha" class="contact_form__captcha" name="captcha" type="captcha" value="…" size="30" maxlength="100" required placeholder="Wie viele Ecken hat ein Pentagramm?"/>
|
||||
</p>
|
||||
<p class="contact_form__submit">
|
||||
<input name="submit" type="submit" id="submit" class="contact_form__submit_button" value="{{ this.contact_form_button }}" />
|
||||
<p class="contact_form__feedback"></p>
|
||||
</p>
|
||||
</form>
|
||||
<p class="contact_form__note">
|
||||
{{ this.contact_form_info }}
|
||||
</p>
|
||||
<div id="zammad-feedback-form"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -132,7 +132,29 @@ __ ____________________
|
||||
{%- if '/js/nav_toggle.js'|asseturl is defined -%}
|
||||
<script type="text/javascript" src="{{ '/js/nav_toggle.js'|asseturl }}"></script>
|
||||
{%- endif %}
|
||||
{% if '/js/contact_form.js'|asseturl is defined and this.title == 'Services' -%}
|
||||
<script type="text/javascript" src="{{ '/js/contact_form.js'|asseturl }}"></script>
|
||||
{%- if '/js/jquery-3.7.1.min.js'|asseturl is defined -%}
|
||||
<script type="text/javascript" src="{{ '/js/jquery-3.7.1.min.js'|asseturl }}"></script>
|
||||
{%- endif %}
|
||||
<script id="zammad_form_script" src="https://tickets.wtf-eg.de/assets/form/form.js"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
$('#zammad-feedback-form').ZammadForm({
|
||||
messageSubmit: '{{ this.contact_form_button }}',
|
||||
messageThankYou: 'Vielen Dank für Deine Anfrage. Wir melden uns umgehend.',
|
||||
noCSS: false,
|
||||
messageTitle: 'Kontaktformular',
|
||||
translations: {
|
||||
'de': {
|
||||
'Attachments': 'Anhänge',
|
||||
'Email': 'E-Mail',
|
||||
'Message': 'Nachricht',
|
||||
'Name': 'Name',
|
||||
'Your Email': 'Deine E-Mail',
|
||||
'Your Message…': 'Deine Nachricht',
|
||||
'Your Name': 'Dein Name',
|
||||
},
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
Loading…
Reference in New Issue
Block a user