created JSON API, TODO: refactor
This commit is contained in:
parent
33dedf0368
commit
75ed103d17
9 changed files with 198 additions and 54 deletions
|
@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|||
- refactored code into multiple php files.
|
||||
- Requires PHP version >=7.2
|
||||
- make all addresses lowercase #30
|
||||
- fixed error when downloading email
|
||||
|
||||
### Added
|
||||
- better horizontal spacing for header (from @Spegeli) and style
|
||||
|
@ -24,6 +25,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|||
- Blacklist some usernames, configurable #27
|
||||
- copyToClipboard button #30
|
||||
- mail counter in title
|
||||
- rest api option
|
||||
|
||||
## [0.1.4] - 2017-04-15
|
||||
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
<?php
|
||||
|
||||
require_once './imap_client.php';
|
||||
require_once './view.php';
|
||||
|
||||
abstract class Page {
|
||||
|
||||
abstract class Controller {
|
||||
|
||||
/**
|
||||
* @var ViewHandler
|
||||
*/
|
||||
protected $viewHandler;
|
||||
|
||||
public function setViewHandler(ViewHandler $outputHandler) {
|
||||
$this->viewHandler = $outputHandler;
|
||||
}
|
||||
|
||||
function invoke(ImapClient $imapClient) {
|
||||
}
|
||||
|
@ -23,22 +34,12 @@ abstract class Page {
|
|||
$name = $word . $nr;
|
||||
|
||||
$domain = $domains[array_rand($domains)];
|
||||
header("location: ?$name@$domain");
|
||||
}
|
||||
|
||||
/**
|
||||
* print error and stop program.
|
||||
* @param $status integer http status
|
||||
* @param $text string error text
|
||||
*/
|
||||
function error($status, $text) {
|
||||
@http_response_code($status);
|
||||
die("{\"error\": \"$text\"}");
|
||||
$this->viewHandler->newAddress("$name@$domain");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class RedirectToAddressPage extends Page {
|
||||
class RedirectToAddressController extends Controller {
|
||||
private $username;
|
||||
private $domain;
|
||||
private $config_blocked_usernames;
|
||||
|
@ -51,11 +52,11 @@ class RedirectToAddressPage extends Page {
|
|||
|
||||
function invoke(ImapClient $imapClient) {
|
||||
$user = User::parseUsernameAndDomain($this->username, $this->domain, $this->config_blocked_usernames);
|
||||
header("location: ?" . $user->username . "@" . $user->domain);
|
||||
$this->viewHandler->newAddress($user->username . "@" . $user->domain);
|
||||
}
|
||||
}
|
||||
|
||||
class DownloadEmailPage extends Page {
|
||||
class DownloadEmailController extends Controller {
|
||||
|
||||
private $email_id;
|
||||
private $address;
|
||||
|
@ -75,21 +76,18 @@ class DownloadEmailPage extends Page {
|
|||
$this->if_invalid_redirect_to_random($user, $this->config_domains);
|
||||
|
||||
$download_email_id = filter_var($this->email_id, FILTER_SANITIZE_NUMBER_INT);
|
||||
if ($imapClient->load_one_email($download_email_id, $user) !== null) {
|
||||
header("Content-Type: message/rfc822; charset=utf-8");
|
||||
header("Content-Disposition: attachment; filename=\"" . $user->address . "-" . $download_email_id . ".eml\"");
|
||||
|
||||
$headers = imap_fetchheader($this->mailbox->getImapStream(), $download_email_id, FT_UID);
|
||||
$body = imap_body($this->mailbox->getImapStream(), $download_email_id, FT_UID);
|
||||
print $headers . "\n" . $body;
|
||||
$full_email = $imapClient->load_one_email_fully($download_email_id, $user);
|
||||
if ($full_email !== null) {
|
||||
$filename = $user->address . "-" . $download_email_id . ".eml";
|
||||
$this->viewHandler->downloadEmailAsRfc822($full_email, $filename);
|
||||
} else {
|
||||
$this->error(404, 'download error: invalid username/mailid combination');
|
||||
$this->viewHandler->error(404, 'download error: invalid username/mailid combination');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DeleteEmailPage extends Page {
|
||||
class DeleteEmailController extends Controller {
|
||||
private $email_id;
|
||||
private $address;
|
||||
private $config_domains;
|
||||
|
@ -108,14 +106,14 @@ class DeleteEmailPage extends Page {
|
|||
|
||||
$delete_email_id = filter_var($this->email_id, FILTER_SANITIZE_NUMBER_INT);
|
||||
if ($imapClient->delete_email($delete_email_id, $user)) {
|
||||
header("location: ?" . $user->address);
|
||||
$this->viewHandler->done($this->address);
|
||||
} else {
|
||||
$this->error(404, 'delete error: invalid username/mailid combination');
|
||||
$this->viewHandler->error(404, 'delete error: invalid username/mailid combination');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RedirectToRandomAddressPage extends Page {
|
||||
class RedirectToRandomAddressController extends Controller {
|
||||
private $config_domains;
|
||||
|
||||
public function __construct($config_domains) {
|
||||
|
@ -128,7 +126,7 @@ class RedirectToRandomAddressPage extends Page {
|
|||
|
||||
}
|
||||
|
||||
class DisplayEmailsPage extends Page {
|
||||
class DisplayEmailsController extends Controller {
|
||||
private $address;
|
||||
private $config;
|
||||
|
||||
|
@ -142,16 +140,14 @@ class DisplayEmailsPage extends Page {
|
|||
// print emails with html template
|
||||
$user = User::parseDomain($this->address, $this->config['blocked_usernames']);
|
||||
$this->if_invalid_redirect_to_random($user, $this->config['domains']);
|
||||
|
||||
// Set variables for frontend template:
|
||||
$emails = $imapClient->get_emails($user);
|
||||
$config = $this->config;
|
||||
require "frontend.template.php";
|
||||
|
||||
$this->viewHandler->displayEmails($emails, $this->config, $user);
|
||||
}
|
||||
}
|
||||
|
||||
class InvalidRequestPage extends Page {
|
||||
class InvalidRequestController extends Controller {
|
||||
function invoke(ImapClient $imapClient) {
|
||||
$this->error(400, "Bad Request");
|
||||
$this->viewHandler->error(400, "Bad Request");
|
||||
}
|
||||
}
|
|
@ -184,7 +184,7 @@ $purifier = new HTMLPurifier($purifier_config);
|
|||
|
||||
<a class="btn btn-sm btn-outline-danger"
|
||||
role="button"
|
||||
href="?action=delete_email&delete_email_id=<?php echo $safe_email_id; ?>&address=<?php echo $user->address ?>">Delete
|
||||
href="?action=delete_email&email_id=<?php echo $safe_email_id; ?>&address=<?php echo $user->address ?>">Delete
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -54,13 +54,25 @@ class ImapClient {
|
|||
}
|
||||
|
||||
|
||||
public function load_one_email_fully($download_email_id, $user) {
|
||||
if ($this->load_one_email($download_email_id, $user) !== null) {
|
||||
$headers = imap_fetchheader($this->mailbox->getImapStream(), $download_email_id, FT_UID);
|
||||
$body = imap_body($this->mailbox->getImapStream(), $download_email_id, FT_UID);
|
||||
return $headers . "\n" . $body;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Load emails using the $mail_ids, the mails have to match the $address in TO or CC.
|
||||
* @param $mail_ids array of integer ids
|
||||
* @param $user User
|
||||
* @return array of emails
|
||||
*/
|
||||
private function _load_emails(array $mail_ids, User $user) {
|
||||
private
|
||||
function _load_emails(array $mail_ids, User $user) {
|
||||
$emails = array();
|
||||
foreach ($mail_ids as $id) {
|
||||
$mail = $this->mailbox->getMail($id);
|
||||
|
@ -75,7 +87,8 @@ class ImapClient {
|
|||
/**
|
||||
* deletes messages older than X days.
|
||||
*/
|
||||
public function delete_old_messages(string $delete_messages_older_than) {
|
||||
public
|
||||
function delete_old_messages(string $delete_messages_older_than) {
|
||||
$ids = $this->mailbox->searchMailbox('BEFORE ' . date('d-M-Y', strtotime($delete_messages_older_than)));
|
||||
foreach ($ids as $id) {
|
||||
$this->mailbox->deleteMail($id);
|
||||
|
|
|
@ -7,13 +7,14 @@ require_once './backend-libs/autoload.php';
|
|||
|
||||
require_once './user.php';
|
||||
require_once './imap_client.php';
|
||||
require_once './pages.php';
|
||||
require_once './controller.php';
|
||||
require_once './router.php';
|
||||
|
||||
$imapClient = new ImapClient($config['imap']['url'], $config['imap']['username'], $config['imap']['password']);
|
||||
|
||||
$router = new Router($_SERVER['REQUEST_METHOD'], $_GET['action'] ?? NULL, $_GET, $_POST, $_SERVER['QUERY_STRING'], $config);
|
||||
$page = $router->route();
|
||||
$page->setViewHandler(new ServerRenderViewHandler());
|
||||
$page->invoke($imapClient);
|
||||
|
||||
// delete after each request
|
||||
|
|
23
src/rest.php
Normal file
23
src/rest.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
# set the new path of config.php (must be in a safe location outside the `public_html`)
|
||||
require_once '../../config.php';
|
||||
|
||||
# load php dependencies:
|
||||
require_once './backend-libs/autoload.php';
|
||||
|
||||
require_once './user.php';
|
||||
require_once './imap_client.php';
|
||||
require_once './controller.php';
|
||||
require_once './router.rest.php';
|
||||
|
||||
$imapClient = new ImapClient($config['imap']['url'], $config['imap']['username'], $config['imap']['password']);
|
||||
|
||||
$router = new RestRouter($_SERVER['REQUEST_METHOD'], $_GET['action'] ?? NULL, $_GET, $_POST, $_SERVER['QUERY_STRING'], $config);
|
||||
$page = $router->route();
|
||||
$page->setViewHandler(new JsonViewHandler());
|
||||
$page->invoke($imapClient);
|
||||
|
||||
// delete after each request
|
||||
$imapClient->delete_old_messages($config['delete_messages_older_than']);
|
||||
|
||||
?>
|
|
@ -1,15 +1,15 @@
|
|||
<?php
|
||||
|
||||
require_once './pages.php';
|
||||
require_once './controller.php';
|
||||
|
||||
class Router {
|
||||
|
||||
private $method;
|
||||
private $action;
|
||||
private $get_vars;
|
||||
private $post_vars;
|
||||
private $query_string;
|
||||
private $config;
|
||||
protected $method;
|
||||
protected $action;
|
||||
protected $get_vars;
|
||||
protected $post_vars;
|
||||
protected $query_string;
|
||||
protected $config;
|
||||
|
||||
public function __construct(string $method, string $action = NULL, array $get_vars, array $post_vars, string $query_string, array $config) {
|
||||
$this->method = $method;
|
||||
|
@ -21,30 +21,30 @@ class Router {
|
|||
}
|
||||
|
||||
|
||||
function route(): Page {
|
||||
function route(): Controller {
|
||||
if ($this->action === "redirect"
|
||||
&& isset($this->post_vars['username'])
|
||||
&& isset($this->post_vars['domain'])) {
|
||||
return new RedirectToAddressPage($this->post_vars['username'], $this->post_vars['domain'], $this->config['blocked_usernames']);
|
||||
return new RedirectToAddressController($this->post_vars['username'], $this->post_vars['domain'], $this->config['blocked_usernames']);
|
||||
|
||||
} elseif ($this->action === "download_email"
|
||||
&& isset($this->get_vars['download_email_id'])
|
||||
&& isset($this->get_vars['email_id'])
|
||||
&& isset($this->get_vars['address'])) {
|
||||
return new DownloadEmailPage($this->get_vars['download_email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']);
|
||||
return new DownloadEmailController($this->get_vars['email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']);
|
||||
|
||||
} elseif ($this->action === "delete_email"
|
||||
&& isset($this->get_vars['delete_email_id'])
|
||||
&& isset($this->get_vars['email_id'])
|
||||
&& isset($this->get_vars['address'])) {
|
||||
return new DeleteEmailPage($this->get_vars['delete_email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']);
|
||||
return new DeleteEmailController($this->get_vars['email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']);
|
||||
|
||||
} elseif ($this->action === 'random') {
|
||||
return new RedirectToRandomAddressPage($this->config['domains']);
|
||||
return new RedirectToRandomAddressController($this->config['domains']);
|
||||
|
||||
} elseif (!empty($this->query_string)) {
|
||||
return new DisplayEmailsPage($this->query_string, $this->config);
|
||||
return new DisplayEmailsController($this->query_string, $this->config);
|
||||
|
||||
} else {
|
||||
return new RedirectToRandomAddressPage($this->config['domains']);
|
||||
return new RedirectToRandomAddressController($this->config['domains']);
|
||||
}
|
||||
}
|
||||
}
|
30
src/router.rest.php
Normal file
30
src/router.rest.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
require_once './controller.php';
|
||||
require_once './router.php';
|
||||
|
||||
|
||||
class RestRouter extends Router {
|
||||
|
||||
function route(): Controller {
|
||||
if ($this->action === "download_email"
|
||||
&& isset($this->get_vars['email_id'])
|
||||
&& isset($this->get_vars['address'])) {
|
||||
return new DownloadEmailController($this->get_vars['email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']);
|
||||
|
||||
} elseif ($this->action === "delete_email"
|
||||
&& isset($this->get_vars['email_id'])
|
||||
&& isset($this->get_vars['address'])) {
|
||||
return new DeleteEmailController($this->get_vars['email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']);
|
||||
|
||||
} elseif ($this->action === 'get_random_username') {
|
||||
return new RedirectToRandomAddressController($this->config['domains']);
|
||||
|
||||
} elseif ($this->action === 'get_emails' && isset($this->get_vars['address'])) {
|
||||
return new DisplayEmailsController($this->get_vars['address'], $this->config);
|
||||
|
||||
} else {
|
||||
return new InvalidRequestController();
|
||||
}
|
||||
}
|
||||
}
|
79
src/view.php
Normal file
79
src/view.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
interface ViewHandler {
|
||||
function done($address);
|
||||
|
||||
/**
|
||||
* print error and stop program.
|
||||
* @param $status integer http status
|
||||
* @param $text string error text
|
||||
*/
|
||||
function error($status, $text);
|
||||
|
||||
function displayEmails($emails, $config, $user);
|
||||
|
||||
function newAddress($string);
|
||||
|
||||
function downloadEmailAsRfc822($full_email, $filename);
|
||||
}
|
||||
|
||||
class JsonViewHandler implements ViewHandler {
|
||||
|
||||
private function json($obj) {
|
||||
header('Content-type: application/json');
|
||||
|
||||
// Never cache requests:
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
print json_encode($obj);
|
||||
die();
|
||||
}
|
||||
|
||||
function done($address) {
|
||||
$this->json(array('status' => "success"));
|
||||
}
|
||||
|
||||
function error($status, $msg) {
|
||||
@http_response_code($status);
|
||||
$this->json(array('status' => "failure", 'error' => $msg));
|
||||
}
|
||||
|
||||
function displayEmails($emails, $config, $user) {
|
||||
$this->json(array('status' => "success", 'emails' => $emails));
|
||||
}
|
||||
|
||||
function newAddress($address) {
|
||||
$this->json(array('status' => "failure", 'address' => $address));
|
||||
}
|
||||
|
||||
function downloadEmailAsRfc822($full_email, $filename) {
|
||||
$this->json(array('status' => "success", 'body' => $full_email));
|
||||
}
|
||||
}
|
||||
|
||||
class ServerRenderViewHandler implements ViewHandler {
|
||||
function done($address) {
|
||||
header("location: ?" . $address);
|
||||
}
|
||||
|
||||
function error($status, $msg) {
|
||||
@http_response_code($status);
|
||||
die("{'result': 'error', 'error': '$msg'}");
|
||||
}
|
||||
|
||||
function displayEmails($emails, $config, $user) {
|
||||
// Set variables for frontend template: $emails, $config
|
||||
require "frontend.template.php";
|
||||
}
|
||||
|
||||
function newAddress($address) {
|
||||
header("location: ?$address");
|
||||
}
|
||||
|
||||
function downloadEmailAsRfc822($full_email, $filename) {
|
||||
header("Content-Type: message/rfc822; charset=utf-8");
|
||||
header("Content-Disposition: attachment; filename=\"$filename\"");
|
||||
print $full_email;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue