Merge branch 'master' of github.com:newroco/mail2deck

# Conflicts:
#	config.php
pull/25/head
Lucian Pricop 2022-05-11 13:51:26 +03:00
commit 5c60208eb0
10 zmienionych plików z 423 dodań i 152 usunięć

3
.gitignore vendored 100644
Wyświetl plik

@ -0,0 +1,3 @@
config.php
vendor/
.idea/

Wyświetl plik

@ -1,26 +1,32 @@
# mail2deck # mail2deck
Provides an "email in" solution for the Nextcloud Deck app Provides an "email in" solution for the Nextcloud Deck app
## A. For users # 🚀 A. For users
Follow the above steps to add a new card from email. Follow the above steps to add a new card from email.
* Deck Bot is the user who will create the cards and it will be set up by your nextcloud admin. * Deck Bot is the user who will create the cards and it will be set up by your nextcloud admin.
* In this tutorial email address for Deck Bot will be: <code>bot@ncserver.com</code> * In this tutorial email address for Deck Bot will be: <code>bot@ncserver.com</code>
### 1) Assign Deck Bot to the board. ## 1) Assign Deck Bot to the board.
### 2) Mail subject & content Deck Bot must be assigned and must have edit permission inside the board.
## 2) Mail subject & content
Let's assume you want to add a card with title "Update website logo" on board "Website" and stack "To do". Let's assume you want to add a card with title "Update website logo" on board "Website" and stack "To do".
You can do this in two ways. You can do this in two ways.
#### 2.1: Set stack and board in the email subject ### 2.1: Set stack and board in the email subject
Here's how the email subject should look like: Here's how the email subject should look like:
<code>Update website logo b-'Website' s-'To do'</code> <code>Update website logo b-'website' s-'to do'</code>
*You can use single or double quotes.* * *You can use single or double quotes.*
#### 2.2: Set the board in the email address * *Case-insensitive for board and stack respectively.*
At the end of the email address prefix (before @) add "+Website"
Example: <code>bot+Website@ncserver.com</code> ### 2.2: Set the board in the email address
At the end of the email address prefix (before @) add "+website"
Example: <code>bot+website@ncserver.com</code>
* *If board has multiple words e.g. <code>"some project"</code>, you'll have to send the email to <code>bot+some+project@ncserver.com</code>*
In this case, if you don't specify the stack in the email subject, the card will be added in the first stack (if it exists). In this case, if you don't specify the stack in the email subject, the card will be added in the first stack (if it exists).
@ -28,37 +34,40 @@ Note:
* Email content will be card description * Email content will be card description
* You can add attachments in the email and those will be integrated in the created card * You can add attachments in the email and those will be integrated in the created card
## B. For NextCloud admins to setup # ⚙️ B. For NextCloud admins to setup
### Requirements ## Requirements
This app requires php-curl, php-mbstring ,php-imap and some sort of imap server (e.g. Postfix with Courier). This app requires php-curl, php-mbstring ,php-imap and some sort of imap server (e.g. Postfix with Courier).
### NC new user ## NC new user
Create a new user from User Management on your NC server, which will have to function as a bot. We chose to call him *deckbot*, but you can call it however you want.<br> Create a new user from User Management on your NC server, which will have to function as a bot. We chose to call him *deckbot*, but you can call it however you want.<br>
__Note__: that you have to assign *deckbot* on each board you want to add new cards from email. __Note__: that you have to assign *deckbot* on each board you want to add new cards from email.
### Configure Email ## Configure Email
#### Option 1 - Set up Postfix for incoming email ### Option 1 - Set up Postfix for incoming email
You can setup Posfix mail server folowing the instructions on [Posfix setup](https://docs.gitlab.com/ee/administration/reply_by_email_postfix_setup.html), and after that add "+" delimiter (which separe the user from the board in the email address) using the command:<br> You can setup Posfix mail server folowing the instructions on [Posfix setup](https://docs.gitlab.com/ee/administration/reply_by_email_postfix_setup.html), and after that add "+" delimiter (which separe the user from the board in the email address) using the command:<br>
``` ```
sudo postconf -e "recipient_delimiter = +" sudo postconf -e "recipient_delimiter = +"
``` ```
#### Option 2 - Use an existing email server ### Option 2 - Use an existing email server
This could be any hosted email service. The only requirement is that you can connect to it via the IMAP protocol. This could be any hosted email service. The only requirement is that you can connect to it via the IMAP protocol.
*Please note this option may not be as flexible as a self-hosted server. For example your email service may not support the "+"delimiter for directing messages to a specific board.* *Please note this option may not be as flexible as a self-hosted server. For example your email service may not support the "+"delimiter for directing messages to a specific board.*
### Download and install ## Download and install
If using a self-hosted Postfix server, clone this repository into the home directory of the *incoming* user. If not self-hosting, you may need to create a new user on your system and adjust the commands in future steps to match that username.<br> If using a self-hosted Postfix server, clone this repository into the home directory of the *incoming* user. If not self-hosting, you may need to create a new user on your system and adjust the commands in future steps to match that username.<br>
``` ```
cd /home/incoming/ su - incoming
git clone https://github.com/putt1ck/mail2deck.git mail2deck git clone https://github.com/newroco/mail2deck.git mail2deck
``` ```
Edit the config file as you need: Create config.php file and edit it for your needs:
``` ```
sudo nano /home/incoming/mail2deck/config.php cd /home/incoming/mail2deck
cp config.example.php config.php
sudo vim config.php
``` ```
*You can refer to https://www.php.net/manual/en/function.imap-open.php for setting the value of MAIL_SERVER_FLAGS* *You can refer to https://www.php.net/manual/en/function.imap-open.php for setting the value of MAIL_SERVER_FLAGS*
### Add a cronjob which will run mail2deck. ## Add a cronjob which will run mail2deck.
``` ```
sudo crontab -u incoming -e sudo crontab -u incoming -e
``` ```
Add the following line in the opened file: Add the following line in the opened file:
<code>*/5 * * * * /usr/bin/php /home/incoming/mail2deck/index.php >/dev/null 2>&1</code> <code>*/5 * * * * /usr/bin/php /home/incoming/mail2deck/index.php >/dev/null 2>&1</code>
### Finish
## Finish
Now __mail2deck__ will add new cards every five minutes if new emails are received. Now __mail2deck__ will add new cards every five minutes if new emails are received.

5
composer.json 100644
Wyświetl plik

@ -0,0 +1,5 @@
{
"require": {
"league/html-to-markdown": "^5.1"
}
}

108
composer.lock wygenerowano 100644
Wyświetl plik

@ -0,0 +1,108 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "55d22588d74c4cd2af8b00fa004ab06f",
"packages": [
{
"name": "league/html-to-markdown",
"version": "5.1.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/html-to-markdown.git",
"reference": "e0fc8cf07bdabbcd3765341ecb50c34c271d64e1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/e0fc8cf07bdabbcd3765341ecb50c34c271d64e1",
"reference": "e0fc8cf07bdabbcd3765341ecb50c34c271d64e1",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-xml": "*",
"php": "^7.2.5 || ^8.0"
},
"require-dev": {
"mikehaertl/php-shellcommand": "^1.1.0",
"phpstan/phpstan": "^0.12.99",
"phpunit/phpunit": "^8.5 || ^9.2",
"scrutinizer/ocular": "^1.6",
"unleashedtech/php-coding-standard": "^2.7",
"vimeo/psalm": "^4.22"
},
"bin": [
"bin/html-to-markdown"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"autoload": {
"psr-4": {
"League\\HTMLToMarkdown\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "https://www.colinodell.com",
"role": "Lead Developer"
},
{
"name": "Nick Cernis",
"email": "nick@cern.is",
"homepage": "http://modernnerd.net",
"role": "Original Author"
}
],
"description": "An HTML-to-markdown conversion helper for PHP",
"homepage": "https://github.com/thephpleague/html-to-markdown",
"keywords": [
"html",
"markdown"
],
"support": {
"issues": "https://github.com/thephpleague/html-to-markdown/issues",
"source": "https://github.com/thephpleague/html-to-markdown/tree/5.1.0"
},
"funding": [
{
"url": "https://www.colinodell.com/sponsor",
"type": "custom"
},
{
"url": "https://www.paypal.me/colinpodell/10.00",
"type": "custom"
},
{
"url": "https://github.com/colinodell",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/league/html-to-markdown",
"type": "tidelift"
}
],
"time": "2022-03-02T17:24:08+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.1.0"
}

13
config.example.php 100644
Wyświetl plik

@ -0,0 +1,13 @@
<?php
define("NC_SERVER", "localhost"); // https://server.domain (without "https://" attachments will not be created)
define("NC_USER", "deckbot");
define("NC_PASSWORD", "****");
define("MAIL_SERVER", "localhost"); // server.domain
define("MAIL_SERVER_FLAGS", "/novalidate-cert"); // flags needed to connect to server. Refer to https://www.php.net/manual/en/function.imap-open.php for a list of valid flags.
define("MAIL_SERVER_PORT", "143");
define("MAIL_USER", "incoming");
define("MAIL_PASSWORD", "****");
define("DECODE_SPECIAL_CHARACTERS", true); //requires mbstring, if false special characters (like öäüß) won't be displayed correctly
define("ASSIGN_SENDER", true); // if true, sender will be assigned to card if has NC account
define("MAIL_NOTIFICATION", true); // if true, send notifications when a new card was created or an error occured
?>

102
index.php
Wyświetl plik

@ -1,26 +1,25 @@
<?php <?php
error_reporting(E_ERROR | E_PARSE); error_reporting(E_ERROR | E_PARSE);
require __DIR__ . '/vendor/autoload.php';
require_once("config.php"); require_once("config.php");
require_once('lib/DeckClass.php'); require_once('lib/DeckClass.php');
require_once('lib/MailClass.php');
require_once('lib/ConvertToMD.php');
$inbox = imap_open("{" . MAIL_SERVER . "/imap" . MAIL_SERVER_FLAGS . "}INBOX", MAIL_USER, MAIL_PASSWORD) $inbox = new MailClass();
or die("can't connect:" . imap_last_error()); $emails = $inbox->getNewMessages();
$emails = imap_search($inbox, 'UNSEEN');
if ($emails) if ($emails)
for ($j = 0; $j <= count($emails) && $j <= 4; $j++) { for ($j = 0; $j < count($emails) && $j < 5; $j++) {
$structure = imap_fetchstructure($inbox, $emails[$j]); $structure = $inbox->fetchMessageStructure($emails[$j]);
$base64encode = false;
if($structure->encoding == 3) {
$base64encode = true; // BASE64
}
$attachments = array(); $attachments = array();
$attNames = array();
if (isset($structure->parts) && count($structure->parts)) { if (isset($structure->parts) && count($structure->parts)) {
for ($i = 0; $i < count($structure->parts); $i++) { for ($i = 0; $i < count($structure->parts); $i++) {
$attachments[$i] = array(
'is_attachment' => false,
'filename' => '',
'name' => '',
'attachment' => ''
);
if ($structure->parts[$i]->ifdparameters) { if ($structure->parts[$i]->ifdparameters) {
foreach ($structure->parts[$i]->dparameters as $object) { foreach ($structure->parts[$i]->dparameters as $object) {
if (strtolower($object->attribute) == 'filename') { if (strtolower($object->attribute) == 'filename') {
@ -40,7 +39,7 @@ if ($emails)
} }
if ($attachments[$i]['is_attachment']) { if ($attachments[$i]['is_attachment']) {
$attachments[$i]['attachment'] = imap_fetchbody($inbox, $emails[$j], $i+1); $attachments[$i]['attachment'] = $inbox->fetchMessageBody($emails[$j], $i+1);
if ($structure->parts[$i]->encoding == 3) { // 3 = BASE64 if ($structure->parts[$i]->encoding == 3) { // 3 = BASE64
$attachments[$i]['attachment'] = base64_decode($attachments[$i]['attachment']); $attachments[$i]['attachment'] = base64_decode($attachments[$i]['attachment']);
} }
@ -50,51 +49,66 @@ if ($emails)
} }
} }
} }
for ($i = 1; $i < count($attachments); $i++) { for ($i = 1; $i <= count($attachments); $i++) {
if(! file_exists(getcwd() . '/attachments')) {
mkdir(getcwd() . '/attachments');
}
if ($attachments[$i]['is_attachment'] == 1) { if ($attachments[$i]['is_attachment'] == 1) {
$filename = $attachments[$i]['name']; $filename = $attachments[$i]['name'];
if (empty($filename)) $filename = $attachments[$i]['filename']; if (empty($filename)) $filename = $attachments[$i]['filename'];
$fp = fopen("./attachments/" . $filename, "w+"); $fp = fopen(getcwd() . '/attachments/' . $filename, "w+");
fwrite($fp, $attachments[$i]['attachment']); fwrite($fp, $attachments[$i]['attachment']);
fclose($fp); fclose($fp);
array_push($attNames, $attachments[$i]['filename']);
} }
} }
$hasAttachment = false; $overview = $inbox->headerInfo($emails[$j]);
for ($i = 0; $i < count($attachments); $i++) { $board = null;
if ($attachments[$i]['is_attachment'] != '') { if(isset($overview->{'X-Original-To'}) && strstr($overview->{'X-Original-To'}, '+')) {
$hasAttachment = true; $board = strstr(substr($overview->{'X-Original-To'}, strpos($overview->{'X-Original-To'}, '+') + 1), '@', true);
}
}
$overview = imap_headerinfo($inbox, $emails[$j]);
$toAddress = strrev($overview->toaddress);
if(preg_match('/@([^+]+)/', $toAddress, $m)) {
global $boardName;
$boardName = strrev($m[1]);
}
if ($hasAttachment) {
$message = imap_fetchbody($inbox, $emails[$j], 1.1);
} else { } else {
$message = imap_fetchbody($inbox, $emails[$j], 1); if(strstr($overview->to[0]->mailbox, '+')) {
$board = substr($overview->to[0]->mailbox, strpos($overview->to[0]->mailbox, '+') + 1);
}
};
if(strstr($board, '+')) $board = str_replace('+', ' ', $board);
$data = new stdClass();
$data->title = DECODE_SPECIAL_CHARACTERS ? mb_decode_mimeheader($overview->subject) : $overview->subject;
$data->type = "plain";
$data->order = -time();
if(count($attachments)) {
$data->attachments = $attNames;
$description = DECODE_SPECIAL_CHARACTERS ? quoted_printable_decode($inbox->fetchMessageBody($emails[$j], 1.1)) : $inbox->fetchMessageBody($emails[$j], 1.1);
} else {
$description = DECODE_SPECIAL_CHARACTERS ? quoted_printable_decode($inbox->fetchMessageBody($emails[$j], 1)) : $inbox->fetchMessageBody($emails[$j], 1);
} }
$mailData = new stdClass(); if($base64encode) {
$mailData->mailSubject = DECODE_SPECIAL_CHARACTERS ? mb_decode_mimeheader($overview->subject) : $overview->subject; $description = base64_decode($description);
$mailData->mailMessage = DECODE_SPECIAL_CHARACTERS ? quoted_printable_decode($message) : $message; }
$mailData->from = $overview->from[0]->mailbox . '@' . $overview->from[0]->host; if($description != strip_tags($description)) {
$description = (new ConvertToMD($description))->execute();
}
$data->description = $description;
$mailSender = new stdClass();
$mailSender->userId = $overview->reply_to[0]->mailbox;
$newcard = new DeckClass(); $newcard = new DeckClass();
$newcard->getParameters(); $response = $newcard->addCard($data, $mailSender, $board);
$newcard->addCard($data); $mailSender->userId .= "@{$overview->reply_to[0]->host}";
if ($hasAttachment) { if(MAIL_NOTIFICATION) {
for ($i = 1; $i <= count($attachments); $i++) { if($response) {
$mailData->fileAttached[$i] = $attachments[$i]['name']; $inbox->reply($mailSender->userId, $response);
} else {
$inbox->reply($mailSender->userId);
} }
$newcard->addAttachment($data); }
if(!$response) {
foreach($attNames as $attachment) unlink(getcwd() . "/attachments/" . $attachment);
} }
} }
imap_close($inbox);
?> ?>

Wyświetl plik

@ -0,0 +1,22 @@
<?php
use League\HTMLToMarkdown\HtmlConverter;
class ConvertToMD {
protected $html;
public function __construct($html) {
$this->converter = new HtmlConverter([
'strip_tags' => true,
'remove_nodes' => 'title'
]);
$this->html = $html;
}
public function execute()
{
return $this->converter->convert($this->html);
}
}
?>

Wyświetl plik

@ -1,117 +1,137 @@
<?php <?php
class DeckClass { class DeckClass {
protected function apiCall($request, $endpoint, $data){ private $responseCode;
$curl = curl_init();
$headers = [ private function apiCall($request, $endpoint, $data = null, $attachment = false){
"OCS-APIRequest: true" $curl = curl_init();
]; if($data && !$attachment) {
$endpoint .= '?' . http_build_query($data);
// set CURLOPTs commmon to all HTTP methods }
$options = [ curl_setopt_array($curl, array(
CURLOPT_USERPWD => NC_USER . ":" . NC_PASSWORD,
CURLOPT_URL => $endpoint, CURLOPT_URL => $endpoint,
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSLVERSION => "all", CURLOPT_ENCODING => '',
]; CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => $request,
CURLOPT_HTTPHEADER => array(
'Authorization: Basic ' . base64_encode(NC_USER . ':' . NC_PASSWORD),
'OCS-APIRequest: true',
),
));
// set HTTP request specific headers and options/data if($request === 'POST') curl_setopt($curl, CURLOPT_POSTFIELDS, (array) $data);
if ($request == '') {// an empty request value is used for attachments
// add data without JSON encoding or JSON Content-Type header
$options[CURLOPT_POST] = true;
$options[CURLOPT_POSTFIELDS] = $data;
} elseif ($request == "POST") {
array_push($headers, "Content-Type: application/json");
$options[CURLOPT_POST] = true;
$options[CURLOPT_POSTFIELDS] = json_encode($data);
} elseif ($request == "GET") {
array_push($headers, "Content-Type: application/json");
}
// add headers to options
$options[CURLOPT_HTTPHEADER] = $headers;
curl_setopt_array($curl, $options);
$response = curl_exec($curl); $response = curl_exec($curl);
$err = curl_error($curl); $err = curl_error($curl);
$this->responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl); curl_close($curl);
if($err) echo "cURL Error #:" . $err;
if ($err) {
echo "cURL Error #:" . $err;
}
return json_decode($response); return json_decode($response);
} }
public function getParameters() {// get the board and the stack public function getParameters($params, $boardFromMail = null) {// get the board and the stack
global $mailData; if(!$boardFromMail) // if board is not set within the email address, look for board into email subject
global $boardId; if(preg_match('/b-"([^"]+)"/', $params, $m) || preg_match("/b-'([^']+)'/", $params, $m)) {
$boardFromMail = $m[1];
if(preg_match('/b-"([^"]+)"/', $mailData->mailSubject, $m) || preg_match("/b-'([^']+)'/", $mailData->mailSubject, $m)) { $params = str_replace($m[0], '', $params);
$boardFromMail = $m[1]; }
$mailData->mailSubject = str_replace($m[0], '', $mailData->mailSubject); if(preg_match('/s-"([^"]+)"/', $params, $m) || preg_match("/s-'([^']+)'/", $params, $m)) {
}
if(preg_match('/s-"([^"]+)"/', $mailData->mailSubject, $m) || preg_match("/s-'([^']+)'/", $mailData->mailSubject, $m)) {
$stackFromMail = $m[1]; $stackFromMail = $m[1];
$mailData->mailSubject = str_replace($m[0], '', $mailData->mailSubject); $params = str_replace($m[0], '', $params);
} }
global $boardName; $boards = $this->apiCall("GET", NC_SERVER . "/index.php/apps/deck/api/v1.0/boards");
$boards = $this->apiCall("GET", NC_SERVER . "/index.php/apps/deck/api/v1.0/boards", ''); $boardId = $boardName = null;
foreach($boards as $board) { foreach($boards as $board) {
if($board->title == $boardFromMail || $board->title == $boardName) { if(strtolower($board->title) == strtolower($boardFromMail)) {
if(!$this->checkBotPermissions($board)) {
return false;
}
$boardId = $board->id; $boardId = $board->id;
$boardName = $board->title;
break;
}
}
if($boardId) {
$stacks = $this->apiCall("GET", NC_SERVER . "/index.php/apps/deck/api/v1.0/boards/$boardId/stacks");
foreach($stacks as $key => $stack)
if(strtolower($stack->title) == strtolower($stackFromMail)) {
$stackId = $stack->id;
break;
}
if($key == array_key_last($stacks) && !isset($stackId)) $stackId = $stacks[0]->id;
} else {
return false;
}
$boardStack = new stdClass();
$boardStack->board = $boardId;
$boardStack->stack = $stackId;
$boardStack->newTitle = $params;
$boardStack->boardTitle = $boardName;
return $boardStack;
}
public function addCard($data, $user, $board = null) {
$params = $this->getParameters($data->title, $board);
if($params) {
$data->title = $params->newTitle;
$card = $this->apiCall("POST", NC_SERVER . "/index.php/apps/deck/api/v1.0/boards/{$params->board}/stacks/{$params->stack}/cards", $data);
$card->board = $params->board;
$card->stack = $params->stack;
if($this->responseCode == 200) {
if(ASSIGN_SENDER) $this->assignUser($card, $user);
if($data->attachments) $this->addAttachments($card, $data->attachments);
$card->boardTitle = $params->boardTitle;
} else { } else {
echo "Board not found\n"; return false;
}
}
$stacks = $this->apiCall("GET", NC_SERVER . "/index.php/apps/deck/api/v1.0/boards/$boardId/stacks", '');
foreach($stacks as $stack) {
if($stack->title == $stackFromMail) {
global $stackId;
$stackId = $stack->id;
} else if (!is_numeric($stackId)) {
global $stackId;
$stackId = $stacks[0]->id;
} }
return $card;
} }
return false;
} }
public function addCard($data) { private function addAttachments($card, $attachments) {
global $mailData; $fullPath = getcwd() . "/attachments/"; //get full path to attachments directory
global $stackId; for ($i = 0; $i < count($attachments); $i++) {
$file = $fullPath . $attachments[$i];
$data = new stdClass();
$data->stackId = $stackId;
$data->title = $mailData->mailSubject;
$data->description =
"$mailData->mailMessage
***
### $mailData->from
";
$data->type = "plain";
$data->order = "-" . time(); // put the card to the top
//create card
$response = $this->apiCall("POST", NC_SERVER . "/index.php/apps/deck/api/v1.0/boards/1/stacks/1/cards", $data);
global $cardId;
$cardId = $response->id;
}
public function addAttachment($data) {
global $mailData;
global $cardId;
$fullPath = getcwd() . "/attachments/"; //get full path to attachments dirctory
for ($i = 1; $i < count($mailData->fileAttached); $i++) {
$data = array( $data = array(
'file' => new CURLFile($fullPath . $mailData->fileAttached[$i]) 'file' => new CURLFile($file)
); );
$this->apiCall("", NC_SERVER . "/index.php/apps/deck/api/v1.0/boards/1/stacks/1/cards/$cardId/attachments?type=deck_file", $data); $this->apiCall("POST", NC_SERVER . "/index.php/apps/deck/api/v1.0/boards/{$card->board}/stacks/{$card->stack}/cards/{$card->id}/attachments?type=file", $data, true);
unlink($file);
} }
} }
public function assignUser($card, $mailUser)
{
$board = $this->apiCall("GET", NC_SERVER . "/index.php/apps/deck/api/v1.0/boards/{$card->board}");
$boardUsers = array_map(function ($user) { return $user->uid; }, $board->users);
foreach($boardUsers as $user) {
if($user === $mailUser->userId) {
$this->apiCall("PUT", NC_SERVER . "/index.php/apps/deck/api/v1.0/boards/{$card->board}/stacks/{$card->stack}/cards/{$card->id}/assignUser", $mailUser);
break;
}
}
}
private function checkBotPermissions($board) {
foreach($board->acl as $acl)
if($acl->participant->uid == NC_USER && $acl->permissionEdit)
return true;
return false;
}
} }
?> ?>

77
lib/MailClass.php 100644
Wyświetl plik

@ -0,0 +1,77 @@
<?php
class MailClass {
private $inbox;
public function __construct()
{
$this->inbox = imap_open("{" . MAIL_SERVER . ":" . MAIL_SERVER_PORT . MAIL_SERVER_FLAGS . "}INBOX", MAIL_USER, MAIL_PASSWORD)
or die("can't connect:" . imap_last_error());
}
public function __destruct()
{
imap_close($this->inbox);
}
public function getNewMessages() {
return imap_search($this->inbox, 'UNSEEN');
}
public function fetchMessageStructure($email) {
return imap_fetchstructure($this->inbox, $email);
}
public function fetchMessageBody($email, $section) {
return imap_fetchbody($this->inbox, $email, $section);
}
public function headerInfo($email) {
$headerInfo = imap_headerinfo($this->inbox, $email);
$additionalHeaderInfo = imap_fetchheader($this->inbox, $email);
$infos = explode("\n", $additionalHeaderInfo);
foreach($infos as $info) {
$data = explode(":", $info);
if( count($data) == 2 && !isset($head[$data[0]])) {
if(trim($data[0]) === 'X-Original-To') {
$headerInfo->{'X-Original-To'} = trim($data[1]);
break;
}
}
}
return $headerInfo;
}
public function reply($sender, $response = null) {
$server = NC_SERVER;
if(strstr($server, "https://")) {
$server = str_replace('https://', '', $server);
} else if(strstr($server, "http://")) {
$server = str_replace('http://', '', $server);
}
$headers = array(
'From' => 'no-reply@' . $server,
'MIME-Version' => '1.0',
'Content-Type' => 'text/html'
);
if($response) {
$body = "<h1>You created a new issue on board {$response->boardTitle}.</h1><p>Check out this <a href=\"" . NC_SERVER . "/index.php/apps/deck/#/board/{$response->board}/card/{$response->id}" . "\">link</a> to see your newly created card.</p>";
$subject = 'An issue has been reported!';
} else {
$body = "<h1>There was a problem creating your new card.</h1><p>Make sure you set up the board correctly.</p>";
$subject = "Your issue has not been reported!";
}
$message = "<html>";
$message .= "<head><title>Mail2Deck response</title></head>";
$message .= "<body>$body</body>";
$message .= "</html>";
mail($sender, $subject, $message, $headers);
}
}