Initial
This commit is contained in:
commit
1f4b4dbab9
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
config.inc.php
|
239
aliasmanager.php
Normal file
239
aliasmanager.php
Normal file
@ -0,0 +1,239 @@
|
||||
<?php
|
||||
|
||||
class aliasmanager extends rcube_plugin {
|
||||
|
||||
private $rcmail;
|
||||
|
||||
private $postfixadmin_db;
|
||||
|
||||
/**
|
||||
* Initializes the plugin.
|
||||
*/
|
||||
public function init() {
|
||||
$this->rcmail = rcube::get_instance();
|
||||
$this->load_config();
|
||||
|
||||
if ($dsn = $this->rcmail->config->get('postfixadmin_db_dsn')) {
|
||||
$this->postfixadmin_db = rcube_db::factory($dsn, '', false);
|
||||
} else {
|
||||
throw new \Exception('cannot connect ot postfix db');
|
||||
}
|
||||
|
||||
if ($this->rcmail->task == "settings") {
|
||||
$this->add_hook("settings_actions", [$this, "hookSettingsActions"]);
|
||||
$this->register_action('plugin.aliasmanager', [$this, "onShowSettingsPage"]);
|
||||
|
||||
switch ($this->rcmail->action) {
|
||||
case 'plugin.aliasmanager-get-alias-list':
|
||||
$this->onGetAliasList();
|
||||
break;
|
||||
case 'plugin.aliasmanager-add-alias':
|
||||
$this->onAddAlias();
|
||||
break;
|
||||
case 'plugin.aliasmanager-toggle-alias':
|
||||
$this->onToggleAlias();
|
||||
break;
|
||||
case 'plugin.aliasmanager-delete-alias':
|
||||
$this->onDeleteAlias();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function hookSettingsActions($arg): array {
|
||||
// add the menu item to the settings sidebar
|
||||
$arg['actions'][] = [
|
||||
'action' => 'plugin.aliasmanager',
|
||||
'class' => 'aliasmanager',
|
||||
'label' => 'plugin_aliasmanager',
|
||||
'title' => 'plugin_aliasmanager',
|
||||
];
|
||||
|
||||
return $arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders and returns the settings.html view.
|
||||
* @return mixed
|
||||
*/
|
||||
public function settingsPageHandler() {
|
||||
$this->include_script('assets/scripts/app.js');
|
||||
$this->include_stylesheet('assets/styles/app.css');
|
||||
|
||||
$this->rcmail->output->add_label("plugin_aliasmanager");
|
||||
|
||||
return $this->view("elastic", "aliasmanager.settings", []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and outputs the settings page.
|
||||
*/
|
||||
public function onShowSettingsPage() {
|
||||
$this->register_handler('plugin.body', [$this, 'settingsPageHandler']);
|
||||
$this->rcmail->output->set_pagetitle($this->gettext('aliasmanager'));
|
||||
$this->rcmail->output->send('plugin');
|
||||
}
|
||||
|
||||
public function onGetAliasList() {
|
||||
$alias_list = [];
|
||||
$result = $this->postfixadmin_db->query('SELECT address as email, goto as users, active FROM alias WHERE address != goto AND goto = ? AND domain = ?', $this->rcmail->user->get_username(), $this->rcmail->config->get('alias_email_domain'));
|
||||
foreach ($result as $row) {
|
||||
$alias_list[] = [
|
||||
'email' => $row['email'],
|
||||
'active' => $row['active'],
|
||||
];
|
||||
}
|
||||
|
||||
$this->sendResponse(true, [
|
||||
'data' => [
|
||||
'alias_list' => $alias_list,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function onAddAlias() {
|
||||
$email = $_POST['email'] ?? null;
|
||||
if (empty($email)) {
|
||||
$this->sendResponse(false, [
|
||||
'msg' => 'Email not set',
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$email_alias_domain = $this->rcmail->config->get('alias_email_domain');
|
||||
|
||||
$email = $email.'-'.$this->generateRandomEmailAliasHash($this->rcmail->config->get('alias_email_hash_len', 7)).'@'.$email_alias_domain;
|
||||
|
||||
$error = $this->postfixadmin_db->query('INSERT INTO alias (address, goto, domain, created, modified, active) VALUES (?, ?, ?, NOW(), NOW(), 1)', [$email, $this->rcmail->user->get_username(), $email_alias_domain]);
|
||||
if (!$error) {
|
||||
$this->sendResponse(false, [
|
||||
'msg' => 'failed to add alias', // $this->postfixadmin_db->is_error()
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sendResponse(true, []);
|
||||
}
|
||||
|
||||
public function onToggleAlias() {
|
||||
$state = $_POST['state'] == 'true' ? 1 : 0;
|
||||
$email = $_POST['email'];
|
||||
|
||||
if (empty($email)) {
|
||||
$this->sendResponse(false, [
|
||||
'msg' => 'Email not set',
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$email_alias_domain = $this->rcmail->config->get('alias_email_domain');
|
||||
|
||||
$error = $this->postfixadmin_db->query('UPDATE alias SET active = ? WHERE address = ? AND goto = ? AND domain = ?', [$state, $email, $this->rcmail->user->get_username(), $email_alias_domain]);
|
||||
if (!$error) {
|
||||
$this->sendResponse(false, [
|
||||
'msg' => 'failed to toggle alias', // $this->postfixadmin_db->is_error()
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sendResponse(true, []);
|
||||
}
|
||||
|
||||
public function onDeleteAlias() {
|
||||
$email = $_POST['email'];
|
||||
if (empty($email)) {
|
||||
$this->sendResponse(false, [
|
||||
'msg' => 'Email not set',
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$email_alias_domain = $this->rcmail->config->get('alias_email_domain');
|
||||
|
||||
$error = $this->postfixadmin_db->query('DELETE FROM alias WHERE address = ? AND goto = ? AND domain = ?', [$email, $this->rcmail->user->get_username(), $email_alias_domain]);
|
||||
if (!$error) {
|
||||
$this->sendResponse(false, [
|
||||
'msg' => 'failed to toggle alias', // $this->postfixadmin_db->is_error()
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sendResponse(true, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends ajax response in json format.
|
||||
*
|
||||
* IMPORTANT: When sending an error with an error message, use this format:
|
||||
* sendResponse(true, array('success' => false, 'errorMessage' => $message, 'other data'...)
|
||||
* This is because the standard way of setting $success and $errorMessage won't work properly with non-English
|
||||
* character sets (when the error is sent using http/1.0 500)
|
||||
*
|
||||
* @param bool $success
|
||||
* @param array $data
|
||||
*/
|
||||
private function sendResponse($success, $data = [], $errorMessage = false) {
|
||||
if ($this->unitTest) {
|
||||
return ["success" => $success, "data" => $data, "errorMessage" => $data['errorMessage']];
|
||||
}
|
||||
|
||||
if (ob_get_contents()) {
|
||||
@ob_end_clean();
|
||||
}
|
||||
|
||||
if (!is_array($data)) {
|
||||
$data = [];
|
||||
}
|
||||
|
||||
if (!isset($data['success'])) {
|
||||
$data['success'] = (bool)$success;
|
||||
}
|
||||
|
||||
if ($success) {
|
||||
exit(json_encode($data));
|
||||
}
|
||||
|
||||
if (empty($errorMessage)) {
|
||||
$errorMessage = empty($data['errorMessage']) ? "Server error" : $data['errorMessage'];
|
||||
}
|
||||
|
||||
exit(@header("HTTP/1.0 500 ".$errorMessage));
|
||||
}
|
||||
|
||||
private function view($skin, $view, $data = false) {
|
||||
if (empty($data) || !is_array($data)) {
|
||||
$data = [];
|
||||
}
|
||||
|
||||
$parts = explode(".", $view);
|
||||
$plugin = $parts[0];
|
||||
|
||||
unset($parts[0]);
|
||||
$html = file_get_contents(__DIR__."/../$plugin/skins/$skin/templates/".implode(".", $parts).".html");
|
||||
|
||||
while (($i = strrpos($html, "[+")) !== false && ($j = strrpos($html, "+]")) !== false) {
|
||||
$html = substr_replace($html, xrc()->gettext(substr($html, $i + 2, $j - $i - 2)), $i, $j - $i + 2);
|
||||
}
|
||||
|
||||
// replace our custom tags that can contain html tags
|
||||
foreach ($data as $key => $val) {
|
||||
if (is_string($val)) {
|
||||
$html = str_replace("[~".$key."~]", $val, $html);
|
||||
} else if (is_array($val)) {
|
||||
$html = str_replace("[~".$key."~]", @json_encode($val), $html);
|
||||
}
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function generateRandomEmailAliasHash($length = 10) {
|
||||
$characters = '0123456789abcdefghijklmnopqrstuvwxyz';
|
||||
$charactersLength = strlen($characters);
|
||||
$randomString = '';
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$randomString .= $characters[rand(0, $charactersLength - 1)];
|
||||
}
|
||||
return $randomString;
|
||||
}
|
||||
}
|
96
assets/scripts/app.js
Normal file
96
assets/scripts/app.js
Normal file
@ -0,0 +1,96 @@
|
||||
$(function() {
|
||||
function updateAliasesList() {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/?_task=settings&_action=plugin.aliasmanager-get-alias-list',
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
$('[name=alias_new_name]').val('');
|
||||
|
||||
// Clear table
|
||||
$('.alias-list').html('');
|
||||
|
||||
// Make template
|
||||
let template = $('template#alias-list-row').html();
|
||||
|
||||
for (let i = 0; i < response.data.alias_list.length; i++) {
|
||||
const row = response.data.alias_list[i];
|
||||
|
||||
let tpl = template.replaceAll('{i}', i);
|
||||
tpl = tpl.replaceAll('{email}', row.email);
|
||||
tpl = tpl.replaceAll('{active}', row.active == 1);
|
||||
tpl = tpl.replaceAll('{checked}', row.active == 1 ? 'checked' : '');
|
||||
$('.alias-list').append(tpl);
|
||||
}
|
||||
}
|
||||
},
|
||||
dataType: 'json'
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '.btn-aliasmanager-add-alias', function() {
|
||||
const email = $('[name=alias_new_name]').val();
|
||||
if (!/[a-z0-9]/.test(email)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/?_task=settings&_action=plugin.aliasmanager-add-alias',
|
||||
data: {
|
||||
email: email,
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
$('[name=alias_new_name]').val('');
|
||||
|
||||
updateAliasesList();
|
||||
}
|
||||
},
|
||||
dataType: 'json'
|
||||
});
|
||||
})
|
||||
|
||||
$(document).on('change', '.btn-aliasmanager-toggle-alias', function() {
|
||||
const email = $(this).attr('data-email');
|
||||
const isOn = $(this).is(':checked');
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/?_task=settings&_action=plugin.aliasmanager-toggle-alias',
|
||||
data: {
|
||||
state: isOn,
|
||||
email: email,
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
updateAliasesList();
|
||||
}
|
||||
},
|
||||
dataType: 'json'
|
||||
});
|
||||
})
|
||||
|
||||
$(document).on('click', '.btn-aliasmanager-delete-alias', function() {
|
||||
const email = $(this).attr('data-email');
|
||||
|
||||
if (confirm('You really want to delete ' + email + '?')) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/?_task=settings&_action=plugin.aliasmanager-delete-alias',
|
||||
data: {
|
||||
email: email,
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
updateAliasesList();
|
||||
}
|
||||
},
|
||||
dataType: 'json'
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
// Init
|
||||
updateAliasesList()
|
||||
});
|
3
assets/styles/app.css
Normal file
3
assets/styles/app.css
Normal file
@ -0,0 +1,3 @@
|
||||
.scroller {
|
||||
overflow-y: scroll;
|
||||
}
|
16
composer.json
Normal file
16
composer.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "stuzer05/aliasmanager",
|
||||
"type": "roundcube-plugin",
|
||||
"description": "Provides postfix alias manager.",
|
||||
"license": "MIT",
|
||||
"version": "0.0.1",
|
||||
"homepage": "https://stuzer.link",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Illya Marchenko",
|
||||
"email": "dev@stuzer.link"
|
||||
}
|
||||
],
|
||||
"repositories": [],
|
||||
"require": {}
|
||||
}
|
7
config.inc.php.dist
Normal file
7
config.inc.php.dist
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
$config['alias_email_domain'] = 'social.mail.example.com';
|
||||
|
||||
$config['alias_email_hash_len'] = 7;
|
||||
|
||||
$config['postfixadmin_db_dsn'] = 'mysql://user:pass@host/db';
|
5
localization/en_US.inc
Normal file
5
localization/en_US.inc
Normal file
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
$labels = [];
|
||||
|
||||
$labels['plugin_aliasmanager'] = 'Alias manager';
|
50
skins/elastic/templates/settings.html
Normal file
50
skins/elastic/templates/settings.html
Normal file
@ -0,0 +1,50 @@
|
||||
<div id='aliasmanager-settings' class="scroller">
|
||||
<div class="boxcontent formcontent">
|
||||
<form id="password-form" name="password-form" method="post" action="./?_task=settings&_action=plugin.password-save">
|
||||
<table class="propform">
|
||||
<tbody>
|
||||
<tr class="form-group row">
|
||||
<td class="title col-sm-2">
|
||||
<label for="alias-new-name" class="col-form-label">New alias for</label>
|
||||
</td>
|
||||
<td class="col-sm-2">
|
||||
<input id="alias-new-name" size="60" required name="alias_new_name" class="form-control" placeholder="Service name.." type="text">
|
||||
</td>
|
||||
<td class="col-sm-1">
|
||||
<button class="button submit btn btn-primary btn-aliasmanager-add-alias" type="button">Add</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="form-group row">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Alias</th>
|
||||
<th>Enabled</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="alias-list"></tbody>
|
||||
</table>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template id="alias-list-row">
|
||||
<tr class="form-group">
|
||||
<td>
|
||||
<span>{email}</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" id="toggle-active-{i}" value="{active}" {checked} data-email="{email}" class="form-check-input custom-control-input btn-aliasmanager-toggle-alias">
|
||||
<label for="toggle-active-{i}" class="custom-control-label" title=""></label>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<button class="button btn-sm btn-danger btn-aliasmanager-delete-alias" data-email="{email}" type="button">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
Loading…
x
Reference in New Issue
Block a user