feat: add PayPal donation

This commit is contained in:
2025-09-28 20:39:47 +04:00
parent 1365953b97
commit 5bbc6f1c66
9 changed files with 737 additions and 0 deletions
+1
View File
@@ -6,6 +6,7 @@ sitemap.xml
robots.txt
site.webmanifest
mentions-legales.php
dons.php
# Fichiers de l'IDE/éditeur
.vscode/
+68
View File
@@ -23,6 +23,9 @@ kaubuntu.re est une interface web responsive qui permet de consulter et recherch
- 🌐 Mode hors ligne avec cache intelligent
- 📡 Détection automatique d'état de connexion
- 📊 Analytics intégré avec Plausible (respectueux de la vie privée)
- 📰 *Intégration WordPress* : Affichage des articles depuis un site WordPress via REST API
- 💝 *Système de dons* : Interface PayPal Me configurable pour collecter des dons
- ⏰ *Système de countdown* : Page de lancement configurable avec compte à rebours multi-fuseaux
== 🛠️ Technologies utilisées
@@ -154,6 +157,71 @@ cp mentions-legales.php.sample mentions-legales.php
Ces fichiers sont listés dans le `.gitignore` afin que vos modifications ne soient pas suivies par Git, ce qui vous permet de personnaliser votre instance sans affecter le code source principal.
== 💝 Système de dons
kaubuntu.re intègre un système de dons configurable qui permet de collecter des contributions via PayPal Me.
=== ✨ Fonctionnalités
- 💳 *PayPal Me intégré* : Redirection sécurisée vers votre compte PayPal
- 🎯 *Montants prédéfinis* : Boutons rapides avec montants suggérés
- ✍️ *Montant personnalisé* : Champ libre pour des dons de montant libre
- 🔒 *Sécurisé* : Validation stricte des URLs et protection XSS
- 📱 *Responsive* : Interface optimisée mobile et desktop
- 🎨 *Intégré* : Design cohérent avec la charte graphique du site
- ♿ *Accessible* : Conforme aux standards d'accessibilité
=== ⚙️ Configuration
Pour activer le système de dons, ajoutez dans votre `config.local.php` :
[source,php]
----
// Activer le système de dons
define('DONATIONS_ENABLED', true);
// URL PayPal Me (sans le montant)
define('PAYPAL_ME_URL', 'https://www.paypal.com/paypalme/votre-compte');
// Montants suggérés (optionnel)
define('DONATION_AMOUNTS', [5, 10, 20, 50, 100]);
// Devise (optionnel, EUR par défaut)
define('DONATION_CURRENCY', 'EUR');
----
=== 📄 Personnalisation
. Copiez le fichier sample pour créer votre page de dons :
+
[source,bash]
----
cp dons.sample.php dons.php
----
. Personnalisez le contenu en remplaçant les placeholders :
* `[VOTRE ORGANISATION]` par le nom de votre organisation
* `[VOTRE CAUSE]` par votre cause/mission
* `[OBJECTIF X]` par vos objectifs spécifiques
=== 🎯 Interface utilisateur
Une fois activé, le système de dons ajoute :
- 💝 *Icône cœur rouge* dans le header (sans cadre)
- 📋 *Lien "Soutenir"* dans la sidebar
- 📄 *Page dédiée* accessible via `/dons.php`
=== 🔒 Sécurité
Le système intègre plusieurs protections :
- ✅ *Validation URL PayPal* : Seules les URLs PayPal Me valides sont acceptées
- ✅ *Protection XSS* : Échappement de toutes les sorties utilisateur
- ✅ *Validation montants* : Contrôle des montants min/max
- ✅ *Headers sécurisés* : CSP et autres headers de sécurité
- ✅ *Ouverture sécurisée* : Liens avec `noopener noreferrer`
== 🛡️ Configuration de sécurité Apache
Le fichier `conf/.htaccess.sample` fourni inclut des règles de sécurité importantes pour protéger votre installation :
+331
View File
@@ -0,0 +1,331 @@
/* Styles pour la page de dons */
/* Ajustements pour la page de dons */
.main-content .container {
max-width: none;
padding: 0;
}
/* Hero section */
.donation-hero {
background: linear-gradient(135deg, var(--primary-red), #cc0000);
color: white;
padding: 60px 0;
text-align: center;
margin-bottom: 40px;
}
.donation-hero-content h1 {
font-size: 2.5rem;
margin-bottom: 16px;
font-weight: bold;
}
.donation-hero-content h1 i {
color: #ffdddd;
margin-right: 12px;
}
.hero-subtitle {
font-size: 1.2rem;
opacity: 0.9;
max-width: 600px;
margin: 0 auto;
}
/* Section principale */
.donation-main {
margin-bottom: 60px;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
padding: 0 20px;
}
.donation-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 40px;
align-items: start;
}
/* Message de don */
.donation-message h2 {
color: var(--primary-red);
margin-bottom: 20px;
font-size: 1.8rem;
}
.donation-message p {
margin-bottom: 16px;
line-height: 1.6;
color: var(--text-color);
}
.donation-message ul {
list-style: none;
padding: 0;
margin: 20px 0;
}
.donation-message li {
padding: 8px 0;
display: flex;
align-items: center;
color: var(--text-color);
}
.donation-message li i {
color: var(--primary-red);
margin-right: 12px;
width: 20px;
text-align: center;
}
/* Interface de don */
.donation-interface {
background: var(--card-bg);
border-radius: 12px;
padding: 30px;
box-shadow: var(--card-shadow);
border: 1px solid var(--border-color);
}
.donation-interface h3 {
color: var(--primary-red);
margin-bottom: 24px;
font-size: 1.5rem;
text-align: center;
}
/* Boutons de montants */
.donation-amounts {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
margin-bottom: 30px;
}
.donation-btn {
background: white;
border: 2px solid var(--border-color);
border-radius: 8px;
padding: 16px 20px;
font-size: 1.2rem;
font-weight: bold;
color: var(--text-color);
cursor: pointer;
transition: all 0.3s ease;
text-align: center;
}
.donation-btn:hover {
border-color: var(--primary-red);
background: #fff5f5;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(255, 0, 0, 0.15);
}
.donation-btn.active {
background: var(--primary-red);
color: white;
border-color: var(--primary-red);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(255, 0, 0, 0.3);
}
/* Montant personnalisé */
.custom-amount {
margin-bottom: 24px;
}
.custom-amount label {
display: block;
margin-bottom: 12px;
font-weight: 600;
color: var(--text-color);
}
.custom-amount-input {
display: flex;
align-items: center;
gap: 8px;
}
.custom-amount-input input {
flex: 1;
padding: 12px 16px;
border: 2px solid var(--border-color);
border-radius: 8px;
font-size: 1.1rem;
transition: border-color 0.3s ease;
}
.custom-amount-input input:focus {
outline: none;
border-color: var(--primary-red);
box-shadow: 0 0 0 3px rgba(255, 0, 0, 0.1);
}
.custom-amount-input .currency {
font-weight: bold;
color: var(--text-secondary);
font-size: 1.1rem;
}
.btn-custom-donate {
background: var(--primary-red);
color: white;
border: none;
border-radius: 8px;
padding: 12px 24px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
font-size: 1rem;
}
.btn-custom-donate:hover {
background: #cc0000;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(255, 0, 0, 0.3);
}
/* Sécurité */
.donation-security {
text-align: center;
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
border: 1px solid #e9ecef;
}
.donation-security p {
margin: 0;
color: var(--text-secondary);
font-size: 0.9rem;
}
.donation-security i {
color: #28a745;
margin-right: 8px;
}
/* Section d'informations */
.donation-info {
margin-top: 60px;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
padding: 0 20px;
}
.info-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 30px;
}
.info-card {
text-align: center;
padding: 30px 20px;
background: var(--card-bg);
border-radius: 12px;
border: 1px solid var(--border-color);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.info-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
.info-card i {
font-size: 2.5rem;
color: var(--primary-red);
margin-bottom: 16px;
}
.info-card h4 {
color: var(--text-color);
margin-bottom: 12px;
font-size: 1.3rem;
}
.info-card p {
color: var(--text-secondary);
line-height: 1.5;
margin: 0;
}
/* Responsive Design */
@media (max-width: 1024px) {
.donation-content {
grid-template-columns: 1fr;
gap: 30px;
}
.info-grid {
grid-template-columns: 1fr;
gap: 20px;
}
}
@media (max-width: 768px) {
.donation-hero {
padding: 40px 0;
}
.donation-hero-content h1 {
font-size: 2rem;
}
.hero-subtitle {
font-size: 1.1rem;
}
.donation-interface {
padding: 20px;
}
.donation-amounts {
grid-template-columns: 1fr;
}
.custom-amount-input {
flex-direction: column;
align-items: stretch;
}
.custom-amount-input .currency {
order: -1;
text-align: center;
margin-bottom: 8px;
}
}
@media (max-width: 480px) {
.donation-hero-content h1 {
font-size: 1.6rem;
}
.donation-btn {
padding: 14px 16px;
font-size: 1.1rem;
}
}
/* Dark theme adjustments */
[data-theme="dark"] .donation-security {
background: var(--card-bg);
border-color: var(--border-color);
}
[data-theme="dark"] .donation-btn {
background: var(--card-bg);
border-color: var(--border-color);
}
[data-theme="dark"] .donation-btn:hover {
background: rgba(255, 0, 0, 0.1);
}
+59
View File
@@ -487,6 +487,65 @@ img {
color: var(--primary-red) !important;
}
/* Bouton de don dans le header */
.donation-link {
background: transparent !important;
color: var(--primary-red) !important;
position: relative;
overflow: hidden;
border: none !important;
box-shadow: none !important;
}
.donation-link:hover {
background: rgba(255, 0, 0, 0.1) !important;
transform: scale(1.2);
}
.donation-link i {
color: var(--primary-red) !important;
}
/* Animation pulse pour attirer l'attention */
.donation-link::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(255, 255, 255, 0.3);
border-radius: 50%;
transform: translate(-50%, -50%);
animation: pulse-heart 2s infinite;
}
@keyframes pulse-heart {
0% {
width: 0;
height: 0;
opacity: 1;
}
100% {
width: 40px;
height: 40px;
opacity: 0;
}
}
/* Lien de don dans la sidebar */
.donation-nav-link i {
color: var(--primary-red) !important;
}
.donation-nav-link:hover i {
color: #cc0000 !important;
}
.donation-nav-link.active i {
color: var(--primary-red) !important;
}
[data-theme="dark"] img {
opacity: 0.9;
}
+235
View File
@@ -0,0 +1,235 @@
<?php
/**
* Page de dons - Template d'exemple
*
* Pour personnaliser cette page :
* 1. Copiez ce fichier vers dons.php
* 2. Activez les dons dans config.local.php :
* define('DONATIONS_ENABLED', true);
* define('PAYPAL_ME_URL', 'https://www.paypal.com/paypalme/votre-compte');
* 3. Personnalisez le contenu selon vos besoins
*/
require_once 'includes/config.php';
require_once 'includes/security.php';
// Vérifier si les dons sont activés
if (!defined('DONATIONS_ENABLED') || !DONATIONS_ENABLED || empty(PAYPAL_ME_URL)) {
http_response_code(404);
include '404.php';
exit;
}
// Définir les headers de sécurité
setSecurityHeaders();
// Validation et nettoyage de l'URL PayPal
$paypalUrl = filter_var(PAYPAL_ME_URL, FILTER_VALIDATE_URL);
if (!$paypalUrl || !str_contains($paypalUrl, 'paypal.com/paypalme/')) {
http_response_code(500);
error_log('Configuration PayPal invalide: ' . PAYPAL_ME_URL);
include '500.php';
exit;
}
// Configuration des montants et devise
$donationAmounts = defined('DONATION_AMOUNTS') ? DONATION_AMOUNTS : [5, 10, 20, 50];
$currency = defined('DONATION_CURRENCY') ? DONATION_CURRENCY : 'EUR';
$currencySymbol = $currency === 'EUR' ? '€' : '$';
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- PERSONNALISEZ: Titre et description de votre page de dons -->
<title>Soutenir [VOTRE ORGANISATION] - Dons</title>
<meta name="description" content="Soutenez [VOTRE ORGANISATION] par un don. Chaque contribution compte pour [VOTRE CAUSE].">
<!-- Styles -->
<link rel="stylesheet" href="css/styles.css?v=<?php echo filemtime('css/styles.css'); ?>">
<link rel="stylesheet" href="css/donations.css?v=<?php echo filemtime('css/donations.css'); ?>">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css" crossorigin="anonymous">
<!-- Favicons -->
<link rel="apple-touch-icon" sizes="180x180" href="img/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png">
<link rel="manifest" href="manifest.json">
<!-- Schema.org pour les dons - PERSONNALISEZ -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "[VOTRE ORGANISATION]",
"description": "[DESCRIPTION DE VOTRE ORGANISATION]",
"url": "<?php echo htmlspecialchars($_SERVER['HTTP_HOST']); ?>",
"potentialAction": {
"@type": "DonateAction",
"target": {
"@type": "EntryPoint",
"urlTemplate": "<?php echo htmlspecialchars($paypalUrl); ?>"
}
}
}
</script>
</head>
<body>
<?php include 'includes/header.php'; ?>
<!-- Sidebar gauche -->
<div class="sidebar-container">
<?php include 'includes/sidebar.php'; ?>
</div>
<main class="main-content">
<div class="container">
<!-- En-tête de la page - PERSONNALISEZ -->
<section class="donation-hero">
<div class="donation-hero-content">
<h1><i class="fas fa-heart"></i> Soutenir [VOTRE ORGANISATION]</h1>
<p class="hero-subtitle">Votre soutien est essentiel pour [VOTRE CAUSE]</p>
</div>
</section>
<!-- Section principale de don -->
<section class="donation-main">
<div class="donation-content">
<div class="donation-message">
<!-- PERSONNALISEZ: Votre message de don -->
<h2>Pourquoi nous soutenir ?</h2>
<p>[VOTRE ORGANISATION] est [DESCRIPTION].
Vos dons nous permettent de :</p>
<ul>
<!-- PERSONNALISEZ: Vos objectifs -->
<li><i class="fas fa-bullhorn"></i> [OBJECTIF 1]</li>
<li><i class="fas fa-users"></i> [OBJECTIF 2]</li>
<li><i class="fas fa-laptop"></i> [OBJECTIF 3]</li>
<li><i class="fas fa-book"></i> [OBJECTIF 4]</li>
</ul>
<p><strong>Chaque don, même petit, fait la différence !</strong></p>
</div>
<!-- Interface de don -->
<div class="donation-interface">
<h3>Choisissez votre montant</h3>
<div class="donation-amounts">
<?php foreach ($donationAmounts as $amount): ?>
<button class="donation-btn"
data-amount="<?php echo $amount; ?>"
onclick="redirectToPayPal(<?php echo $amount; ?>)">
<?php echo $amount . $currencySymbol; ?>
</button>
<?php endforeach; ?>
</div>
<div class="custom-amount">
<label for="custom-amount-input">Ou entrez un montant personnalisé :</label>
<div class="custom-amount-input">
<input type="number"
id="custom-amount-input"
min="1"
max="10000"
step="1"
placeholder="Montant">
<span class="currency"><?php echo htmlspecialchars($currencySymbol); ?></span>
<button onclick="redirectToPayPalCustom()" class="btn-custom-donate">
Donner
</button>
</div>
</div>
<div class="donation-security">
<p><i class="fas fa-shield-alt"></i>
Paiement sécurisé via PayPal. Aucune donnée bancaire n'est stockée sur ce site.</p>
</div>
</div>
</div>
</section>
<!-- Informations supplémentaires - PERSONNALISEZ -->
<section class="donation-info">
<div class="info-grid">
<div class="info-card">
<i class="fas fa-server"></i>
<h4>Hébergement & Infrastructure</h4>
<p>Maintenir nos serveurs, notre plateforme et nos outils numériques, représente des coûts mensuels importants.</p>
</div>
<div class="info-card">
<i class="fas fa-tools"></i>
<h4>Maintenance & Développement</h4>
<p>Assurer la sécurité, les mises à jour et l'évolution de nos outils technologiques demande un investissement constant.</p>
</div>
<div class="info-card">
<i class="fas fa-shield-alt"></i>
<h4>Indépendance Numérique</h4>
<p>Vos dons nous permettent de rester indépendants des plateformes commerciales et de préserver notre souveraineté numérique.</p>
</div>
</div>
</section>
</div>
</main>
<?php include 'includes/footer.php'; ?>
<!-- Script de redirection PayPal -->
<script>
const PAYPAL_BASE_URL = <?php echo json_encode($paypalUrl, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT); ?>;
const CURRENCY = <?php echo json_encode($currency, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT); ?>;
function redirectToPayPal(amount) {
if (amount && amount > 0) {
// Construction de l'URL PayPal Me avec montant
const url = `${PAYPAL_BASE_URL}/${amount}${CURRENCY}`;
window.open(url, '_blank', 'noopener,noreferrer');
}
}
function redirectToPayPalCustom() {
const input = document.getElementById('custom-amount-input');
const amount = parseFloat(input.value);
if (!amount || amount <= 0) {
alert('Veuillez entrer un montant valide.');
input.focus();
return;
}
if (amount > 10000) {
alert('Le montant maximum est de 10000' + <?php echo json_encode($currencySymbol); ?> + '.');
return;
}
redirectToPayPal(amount);
}
// Permettre la validation par Entrée
document.getElementById('custom-amount-input').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
redirectToPayPalCustom();
}
});
// Highlight des boutons de montant
document.querySelectorAll('.donation-btn').forEach(btn => {
btn.addEventListener('click', function() {
// Retirer la classe active de tous les boutons
document.querySelectorAll('.donation-btn').forEach(b => b.classList.remove('active'));
// Ajouter la classe active au bouton cliqué
this.classList.add('active');
// Vider le champ personnalisé
document.getElementById('custom-amount-input').value = '';
});
});
// Réinitialiser la sélection si on tape dans le champ personnalisé
document.getElementById('custom-amount-input').addEventListener('input', function() {
document.querySelectorAll('.donation-btn').forEach(b => b.classList.remove('active'));
});
</script>
</body>
</html>
+16
View File
@@ -146,4 +146,20 @@ if (!defined('WORDPRESS_POSTS_COUNT')) define('WORDPRESS_POSTS_COUNT', 6);
// Activation des articles WordPress par défaut
if (!defined('WORDPRESS_ENABLED')) define('WORDPRESS_ENABLED', false);
// =========================================
// Système de dons par défaut
// =========================================
// Activation du système de dons par défaut
if (!defined('DONATIONS_ENABLED')) define('DONATIONS_ENABLED', false);
// URL PayPal Me par défaut (sans le montant)
if (!defined('PAYPAL_ME_URL')) define('PAYPAL_ME_URL', '');
// Montants de dons suggérés par défaut
if (!defined('DONATION_AMOUNTS')) define('DONATION_AMOUNTS', [5, 10, 20, 50]);
// Devise par défaut
if (!defined('DONATION_CURRENCY')) define('DONATION_CURRENCY', 'EUR');
?>
+16
View File
@@ -265,6 +265,22 @@ define('COUNTDOWN_TIMEZONES', [
// Activer/désactiver l'affichage des articles WordPress
// define('WORDPRESS_ENABLED', true);
// =========================================
// Système de dons
// =========================================
// Activer/désactiver le système de dons
// define('DONATIONS_ENABLED', true);
// URL PayPal Me (exemple: https://www.paypal.com/paypalme/kubuntu)
// define('PAYPAL_ME_URL', 'https://www.paypal.com/paypalme/votre-compte');
// Montants de dons suggérés (en euros par défaut)
// define('DONATION_AMOUNTS', [5, 10, 20, 50, 100]);
// Devise pour les dons
// define('DONATION_CURRENCY', 'EUR');
// =========================================
// Texte de présentation du mouvement
// =========================================
+5
View File
@@ -40,6 +40,11 @@
</nav>
<div class="action-icons">
<?php if (defined('DONATIONS_ENABLED') && DONATIONS_ENABLED && !empty(PAYPAL_ME_URL)): ?>
<a href="dons.php" class="icon-button donation-link" aria-label="Soutenir KA UBUNTU" title="Faire un don">
<i class="fas fa-heart" aria-hidden="true"></i>
</a>
<?php endif; ?>
<button id="theme-toggle" class="icon-button" aria-label="Basculer entre mode clair et sombre" title="Changer le thème">
<i class="fas fa-sun" aria-hidden="true"></i>
</button>
+6
View File
@@ -21,6 +21,12 @@
<i class="fas fa-broadcast-tower" aria-hidden="true"></i> <span>Direct</span>
</a>
<?php if (defined('DONATIONS_ENABLED') && DONATIONS_ENABLED && !empty(PAYPAL_ME_URL)): ?>
<a href="dons.php" class="nav-item donation-nav-link <?php echo ($currentPage === 'dons.php') ? 'active' : ''; ?>" data-title="Soutenir" aria-current="<?php echo ($currentPage === 'dons.php') ? 'page' : 'false'; ?>">
<i class="fas fa-heart" aria-hidden="true"></i> <span>Soutenir</span>
</a>
<?php endif; ?>
<div class="nav-divider"></div>
<?php