diff --git a/README.md b/README.md index 9aa72ae..6517833 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ LBCAlerte for YunoHost Logiciel pour être alerté de nouvelles annonces par mail, flux RSS et SMS sur Leboncoin et d'autres sites d'annonces. -**Version incluse:** 3.2 +**Version incluse:** 3.3 ## Limitations diff --git a/scripts/install b/scripts/install index 73dc086..721c919 100644 --- a/scripts/install +++ b/scripts/install @@ -27,8 +27,7 @@ sudo mkdir -p $src_path/var sudo cp -a ../sources/. $src_path # Set permissions to app files -sudo chown -R root: $src_path -sudo chown -R www-data: $src_path/var +sudo chown -R www-data: $src_path # Generate MySQL password and create database dbuser=$app diff --git a/scripts/upgrade b/scripts/upgrade new file mode 100644 index 0000000..c5b621d --- /dev/null +++ b/scripts/upgrade @@ -0,0 +1,45 @@ +#!/bin/bash + +# Exit on command errors and treat unset variables as an error +set -eu + +# See comments in install script +app=$YNH_APP_INSTANCE_NAME + +# Source YunoHost helpers +source /usr/share/yunohost/helpers + +# Retrieve app settings +domain=$(ynh_app_setting_get "$app" domain) +path=$(ynh_app_setting_get "$app" path) +admin=$(ynh_app_setting_get "$app" admin) +is_public=$(ynh_app_setting_get "$app" is_public) +language=$(ynh_app_setting_get "$app" language) + +# Remove trailing "/" for next commands +path=${path%/} + +# Copy source files +src_path=/var/www/$app +sudo mkdir -p $src_path +sudo cp -a ../sources/. $src_path + +# Set permissions to app files +# you may need to make some file and/or directory writeable by www-data (nginx user) +sudo chown -R www-data: $src_path + +# Modify Nginx configuration file and copy it to Nginx conf directory +nginx_conf=../conf/nginx.conf +sed -i "s@YNH_WWW_PATH@$path@g" $nginx_conf +sed -i "s@YNH_WWW_ALIAS@$src_path/@g" $nginx_conf + +sudo cp $nginx_conf /etc/nginx/conf.d/$domain.d/$app.conf + +# If app is public, add url to SSOWat conf as skipped_uris +if [[ $is_public -eq 1 ]]; then + # See install script + ynh_app_setting_set "$app" unprotected_uris "/" +fi + +# Reload nginx service +sudo service nginx reload diff --git a/sources/CHANGELOG.txt b/sources/CHANGELOG.txt index 434ecd1..7e85789 100644 --- a/sources/CHANGELOG.txt +++ b/sources/CHANGELOG.txt @@ -1,4 +1,22 @@ +## Version 3.3 + + * ajout: possibilité de sauvegarder les annonces Leboncoin. + * ajout: possiblité d'ajouter une note aux annonces sauvegardées. + * ajout: possiblité de pré-remplir les champs de création d'alerte et flux RSS. + * ajout: test de la disponibilité de mysqli et php-curl à l'installation. + * ajout: un début d'API est mis en place. + * ajout: notification vers Joaoapps / Join. + * ajout: notifications vers Slack. + * ajout: possibilité d'enregistrer une ou plusieurs adresses mails par défaut. + * amélioration: les erreurs sont mieux gérées. + * amélioration: la page des paramètres utilisateur est refondu. + * amélioration: optimisation de la gestion des systèmes d'alerte. + * correction: encodage des caractères en base de données invalide. + * correction: encodage des caractères du contenu Leboncoin invalide. + * correction: factorisation du code de la tâche cron. + * correction: la réinitialisation des alertes ne fonctionne pas sur une nouvelle installation. + ## Version 3.2 * correction: si CURLOPT_FOLLOWLOCATION désactivé, suivre manuellement les redirections. diff --git a/sources/api.php b/sources/api.php new file mode 100644 index 0000000..35d1a65 --- /dev/null +++ b/sources/api.php @@ -0,0 +1,60 @@ +get("storage", "type", "files"); +if ($storageType == "db") { + $userStorage = new \App\Storage\Db\User($dbConnection); +} else { + $userStorage = new \App\Storage\File\User(DOCUMENT_ROOT."/var/users.db"); +} + + +// Identification par clé API +$auth = new Auth\ApiKey($userStorage); +if (!$userAuthed = $auth->authenticate()) { + header("HTTP/1.0 401 Unauthorized"); + exit; +} + +// Si une action de modification de données est demandée, il faut que ce soit +// en POST. +if (in_array($action, array("create", "modify", "delete")) + && $_SERVER["REQUEST_METHOD"] != "POST") { + header("HTTP/1.0 400 Bad Request"); + exit; +} + +$init = DOCUMENT_ROOT."/app/".$module."/init.php"; +$script = DOCUMENT_ROOT."/app/api/".$module."/".$action.".php"; + +if (!is_file($script)) { + header("HTTP/1.0 400 Bad Request"); + exit; +} + +if (is_file($init)) { + require $init; +} +$data = require $script; + +if (empty($data)) { + $data = array(); +} +echo json_encode($data); diff --git a/sources/app/admin/scripts/storage.php b/sources/app/admin/scripts/storage.php index 7b25d09..9360a66 100644 --- a/sources/app/admin/scripts/storage.php +++ b/sources/app/admin/scripts/storage.php @@ -41,6 +41,8 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") { $_POST["options"]["password"], $_POST["options"]["dbname"]); if ($dbConnection->connect_error) { $errors["host"] = "Connexion impossible à la base de données."; + } else { + $dbConnection->set_charset("utf8"); } } } diff --git a/sources/app/admin/views/layout.phtml b/sources/app/admin/views/layout.phtml index 45e39cd..459fd9c 100644 --- a/sources/app/admin/views/layout.phtml +++ b/sources/app/admin/views/layout.phtml @@ -5,7 +5,8 @@ - + +
diff --git a/sources/app/annonce/init.php b/sources/app/annonce/init.php new file mode 100644 index 0000000..a5dd526 --- /dev/null +++ b/sources/app/annonce/init.php @@ -0,0 +1,9 @@ +get("storage", "type", "files"); +if ($storageType == "db") { + $storage = new \App\Storage\Db\Ad($dbConnection, $userAuthed); +} else { + $storage = new \App\Storage\File\Ad(DOCUMENT_ROOT."/var/configs/backup-ads-".$auth->getUsername().".csv"); +} + +$adPhoto = new App\Storage\AdPhoto($userAuthed); diff --git a/sources/app/annonce/scripts/backup.php b/sources/app/annonce/scripts/backup.php new file mode 100644 index 0000000..98e0b1c --- /dev/null +++ b/sources/app/annonce/scripts/backup.php @@ -0,0 +1,40 @@ +request($url); + +try { + $parser = \AdService\ParserFactory::factory($url); +} catch (\AdService\Exception $e) { + $logger->err($e->getMessage()); +} + +$ad = $parser->processAd( + $content, + parse_url($url, PHP_URL_SCHEME) +); + +$ad_stored = $storage->fetchById($ad->getId()); +if ($ad_stored) { + if ($_SERVER["REQUEST_METHOD"] != "POST") { + return; + } + + // Supprime les photos + $adPhoto->delete($ad); +} + + +if (!$ad_stored) { + $ad_stored = new \App\Ad\Ad(); +} + +$ad_stored->setFromArray($ad->toArray()); +$storage->save($ad_stored); + +$adPhoto->import($ad_stored); + +header("LOCATION: ./?mod=annonce&a=view&id=".$ad->getId()); exit; \ No newline at end of file diff --git a/sources/app/annonce/scripts/form-comment.php b/sources/app/annonce/scripts/form-comment.php new file mode 100644 index 0000000..c90e9fe --- /dev/null +++ b/sources/app/annonce/scripts/form-comment.php @@ -0,0 +1,27 @@ +fetchById($_GET["id"]); +if (!$ad) { + header("LOCATION: ./?mod=annonce"); exit; +} + +if ($_SERVER["REQUEST_METHOD"] == "POST") { + $comment = isset($_POST["comment"]) ? trim($_POST["comment"]) : ""; + $ad->setComment($comment); + $storage->save($ad); + + header("LOCATION: ./?mod=annonce&a=view&id=".$ad->getId()."&update=1"); + exit; +} + +try { + $ad_config = SiteConfigFactory::factory($ad->getLink()); +} catch (Exception $e) { + +} \ No newline at end of file diff --git a/sources/app/annonce/scripts/form-delete.php b/sources/app/annonce/scripts/form-delete.php new file mode 100644 index 0000000..c9676a0 --- /dev/null +++ b/sources/app/annonce/scripts/form-delete.php @@ -0,0 +1,17 @@ +fetchById($_GET["id"]); +if (!$ad) { + header("LOCATION: ./?mod=annonce"); exit; +} +if ($_SERVER["REQUEST_METHOD"] == "POST") { + if (isset($_POST["id"]) && $_POST["id"] == $_GET["id"]) { + $storage->delete($ad); + $adPhoto->delete($ad); + } + header("LOCATION: ./?mod=annonce"); exit; +} + +$referer = isset($_GET["r"]) ? $_GET["r"] : ""; \ No newline at end of file diff --git a/sources/app/annonce/scripts/form.php b/sources/app/annonce/scripts/form.php new file mode 100644 index 0000000..58e0aea --- /dev/null +++ b/sources/app/annonce/scripts/form.php @@ -0,0 +1,46 @@ +processAd( + $client->request($link), + parse_url($link, PHP_URL_SCHEME) + ); + if (!$ad) { + $errors["link"] = "Impossible de sauvegarder l'annonce (annonce hors ligne ou format des données invalides)."; + } + } + if (empty($errors) && !empty($ad)) { + $ad = $parser->processAd( + $client->request($link), + parse_url($link, PHP_URL_SCHEME) + ); + + $ad_stored = $storage->fetchById($ad->getId()); + if (!$ad_stored) { + $ad_stored = new \App\Ad\Ad(); + } + + $ad_stored->setFromArray($ad->toArray()); + $storage->save($ad_stored); + + $adPhoto->import($ad_stored); + + header("LOCATION: ./?mod=annonce"); + exit; + } +} \ No newline at end of file diff --git a/sources/app/annonce/scripts/index.php b/sources/app/annonce/scripts/index.php new file mode 100644 index 0000000..cffb677 --- /dev/null +++ b/sources/app/annonce/scripts/index.php @@ -0,0 +1,28 @@ +fetchAll($sort." ".$order); + + diff --git a/sources/app/annonce/scripts/view.php b/sources/app/annonce/scripts/view.php new file mode 100644 index 0000000..a858bf5 --- /dev/null +++ b/sources/app/annonce/scripts/view.php @@ -0,0 +1,18 @@ +fetchById($_GET["id"]); +if (!$ad) { + header("LOCATION: ./?mod=annonce"); exit; +} + +try { + $ad_config = SiteConfigFactory::factory($ad->getLink()); +} catch (Exception $e) { + +} \ No newline at end of file diff --git a/sources/app/annonce/views/backup.phtml b/sources/app/annonce/views/backup.phtml new file mode 100644 index 0000000..ee46816 --- /dev/null +++ b/sources/app/annonce/views/backup.phtml @@ -0,0 +1,20 @@ + diff --git a/sources/app/annonce/views/form-comment.phtml b/sources/app/annonce/views/form-comment.phtml new file mode 100644 index 0000000..3592cc5 --- /dev/null +++ b/sources/app/annonce/views/form-comment.phtml @@ -0,0 +1,17 @@ ++ + 1?"annonces sauvegardées":"annonce sauvegardée"; ?> | + + Sauvegarder une annonce +
+ ++ | + |
+
+ ![]() |
+
+
+ ![]() |
+
+
+ ![]() |
+
+
+ ![]() |
+
+
+ ![]() |
+
+
+ ![]() |
+
+
+ ![]() |
+
+
+ ![]() |
+ + |
---|---|---|---|---|---|---|---|---|---|---|
Aucune annonce sauvegardée | ||||||||||
+ |
+ getPhotos()) : ?>
+ |
+ getTitle()?htmlspecialchars($ad->getTitle()):"-"; ?> | +getAuthor()); ?> | +getDateCreated())); ?> | ++ | getCategory()); ?> | ++ getPrice()) : ?> + getCurrency()); ?> + + - + + | +getZipCode()); ?> | +getCity()); ?> | ++ |
+ < retour à la liste des annonces sauvegardées | + supprimer l'annonce +
+ +getDescription())); ?>
+
getComment())); ?>
++ + Ajouter une note + + Modifier la note + +
+