diff --git a/TODO b/TODO index 165f72a..fca0bc2 100644 --- a/TODO +++ b/TODO @@ -2,6 +2,15 @@ ============= * Document code Very important, since now it is far more complex + +* Clean code. Some ideas: +** Substitute bot calls with API functions (i.e. sendMessage, forwardMessage...). + Functions are already written (not yet tested!) in shared.php +** Create a class for inline keyboard management +** Use info(), warning() and error() instead of botlog() +** Always insert "or error(... $sql->error())" when making SQL queries. + +* Capabilities to send Image/Videos/Document (at the moment are blocked) * Facebook page integration Make the bot publish info not only in mailing list and Telegram channel, diff --git a/config.php b/config.php index dbe6633..b8f5c97 100644 --- a/config.php +++ b/config.php @@ -16,6 +16,13 @@ const DEBUG = true; /* Log file name */ const LOGFILE = 'botlog.log'; + /* MySQL informations */ + const MYSQL_USER = ''; + const MYSQL_PASSWORD = ''; + const MYSQL_DB = ''; + const MYSQL_TABLE = ''; + /* Memcached local server port */ + const MEMCACHED_PORT = '11211'; $EMOJI_THUMBSUP = mb_convert_encoding('👍', 'UTF-8', 'HTML-ENTITIES'); $EMOJI_THUMBSDOWN = mb_convert_encoding('👎', 'UTF-8', 'HTML-ENTITIES'); @@ -33,23 +40,20 @@ const STATE_MSG_ANSWER = 'msg_answer'; // Saved variables in memcached - const MC_STATUS = 'status'; - const MC_FORWARD_MSG = 'msg_forward'; - const MC_DATE_MSG = 'msg_date'; - const MC_INLINE_ID = 'inline_id'; + const MC_STATUS = 'status'; + const MC_FORWARD_MSG = 'msg_forward'; + const MC_DATE_MSG = 'msg_date'; + const MC_INLINE_ID = 'inline_id'; + const MC_FW_EDIT = 'fw_edit'; // should not be necessary anymore + const MC_LIST_NUMBER = 'list_number'; + const MC_DELETE_SCHEDULED_ID = 'delete_sch_id'; // buttons costants const MSG_YES = 'y'; const MSG_NO = 'n'; const MSG_SCHEDULE = 'sch'; const MSG_ABORT = 'abort'; - - const MYSQL_USER = ''; - const MYSQL_PASSWORD = ''; - const MYSQL_DB = ''; - const MYSQL_TABLE = ''; - - const MEMCACHED_PORT = '11211'; + const MSG_DELETE = 'delete'; $WELCOME_MESSAGE = "$EMOJI_BOT GOLEMbot $EMOJI_MSG Se scrivi un messaggio ti chiedo se inoltrarlo al canale diff --git a/main.php b/main.php index 714bba2..2a4bd12 100644 --- a/main.php +++ b/main.php @@ -1,8 +1,8 @@ addServer('localhost', MEMCACHED_PORT) or error("Something is wrong connecting to memcached daemon"); // Accept only messages from a private chat -if (isset($row->message->chat->type) and $row->message->chat->type != "private") { - if (DEBUG) warning("Message from ".$row->message->chat->type); +if(!isset($row->message->text)) { + if (DEBUG) warning("Message from a not acceptable source"); die(); } // HANDLE A CALLBACK @@ -59,6 +59,12 @@ elseif (isset ($row->callback_query)) { } // HANDLE A COMMON MESSAGE (text/commands/keyboard) else { + // throw away photos, documents and stickers (fixit) + if(isset($row->message->sticker) or isset($row->message->document)) { + // sto username si potrebbe quasi quasi estrapolare e mettere in una variabile decente + error("Qualcheduno (".$row->message->from->username.") ha mandato una cosa non supportata"); + } + // Load variables $chatID = $row->message->chat->id; @@ -70,7 +76,11 @@ else { } // Finally, check actual state and do things -$status = $mc->get($chatID.MC_STATUS) or $mc->set($chatID.MC_STATUS, STATE_IDLE) or die(); // set status or force it to STATE_IDLE +$status = $mc->get($chatID.MC_STATUS); + if (!$status) { + $mc->set($chatID.MC_STATUS, STATE_IDLE) or die(); // set status or force it to STATE_IDLE + $status = STATE_IDLE; + } if (DEBUG) info("Starting from status $status"); // ricordati di schiantare quando ricevi un messaggio invece di una callback @@ -79,12 +89,114 @@ switch ($status) { case STATE_IDLE: // In this state are not accepted callback requests if (isset($callback_data)) { - if (DEBUG) warning("Callback request is not accepted in status $status"); - die(); + switch ($callback_data){ + case MSG_DELETE: + $sql = new mysqli('localhost', MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB); + $IDdelete = $mc->get($chatID.MC_DELETE_SCHEDULED_ID); + $sql->query("DELETE FROM ".MYSQL_TABLE." WHERE ID=$IDdelete") + or error("Can't make the query, SQL error ".$sql->error); + $sql->close(); + + $url = API_URL.API_TOKEN."/editMessageText?chat_id=".($chatID). + "&message_id=".$inlineID . + "&text=Rimosso correttamente"; + file_get_contents($url); + die(); + break; + case '>': + $sql = new mysqli('localhost', MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB); + $numbers = $sql->query("SELECT COUNT(*) FROM ".MYSQL_TABLE); + $numbers = $numbers->fetch_array()[0]; + info("Number of pages: $numbers"); + $offset = $mc->get($chatID.MC_LIST_NUMBER); + // gestire meglio qui + $offset++; + break; + case '<': + $sql = new mysqli('localhost', MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB); + $numbers = $sql->query("SELECT COUNT(*) FROM ".MYSQL_TABLE); + $numbers = $numbers->fetch_array()[0]; + info("Number of pages: $numbers"); + $offset = $mc->get($chatID.MC_LIST_NUMBER); + // gestire meglio qui + $offset--; + break; + default: + if (DEBUG) warning("Callback request is not accepted in status $status"); + die(); + } + + $query = $sql->query("SELECT DATE_FORMAT(DateTime,'%d/%m/%Y ore %H') as DateTime,Text,Author,ID FROM ".MYSQL_TABLE." + ORDER BY DateTime ASC LIMIT 1 OFFSET $offset") or error("Can't make the query, SQL error ".$sql->error); + + //while($row = $query->fetch_assoc()) { + $row = $query->fetch_assoc(); + $mc->set($chatID.MC_DELETE_SCHEDULED_ID, $row['ID']) + or $mc->replace($chatID.MC_DELETE_SCHEDULED_ID, $row['ID']); + //~ $query = API_URL . API_TOKEN . '/forwardMessage?' . + //~ 'chat_id=' . urlencode($chatID) . + //~ '&from_chat_id=' . urlencode($row['ChatID']) . + //~ '&message_id=' . urlencode($row['MessageID']); + //~ $answer = file_get_contents($query); + //~ $answer = json_decode($answer); + $sql->close(); + + $container = array( + array( + array( + "text" => $row['DateTime'], + "callback_data" => "null" + ))); + + $container[] = array( + $offset > 0? + array( + "text" => "<", + "callback_data" => "<" + ) + : + array( + "text" => " ", + "callback_data" => "null" + ), + array( + "text" => "$EMOJI_THUMBSDOWN Canc", + "callback_data" => MSG_DELETE + ), + $offset < $numbers-1 ? + array( + "text" => ">", + "callback_data" => ">" + ) + : + array( + "text" => " ", + "callback_data" => "null" + ) + ); + + $resp = array( + "inline_keyboard" => $container); + $reply = json_encode($resp); + + $text="$row[Text]\n_$row[Author]_"; // NOME CANALE ".API_CHANNEL_ID."?"; + + $query = API_URL.API_TOKEN."/editMessageText?chat_id=".($chatID). + "&message_id=".$inlineID. + "&text=".urlencode($text). + "&parse_mode=".urlencode("Markdown"). + "&reply_markup=".$reply; + $answer = file_get_contents($query); + $answer = json_decode($answer); + + $mc->set($chatID.MC_LIST_NUMBER, $offset) + or $mc->replace($chatID.MC_LIST_NUMBER, $offset); + + die(); } - + // qui ci metterei un else // Search for a command - if (($command = getCommand($row->message)) != -1) { + if (($command = getCommand($row->message)) != null) { info("Command received: $command[command] with options $command[options]"); switch ($command['command']) { @@ -99,29 +211,116 @@ switch ($status) { file_get_contents($query); break; + case '/edit': + //~ $text = "Invio effettuato correttamente"; + //~ $url = API_URL.API_TOKEN."/deleteMessage?chat_id=".($chatID). + //~ "&message_id=2551"; + //~ file_get_contents($url); + break; + case '/list': - $dateID = date('Y-n-j G:*'); + //~ $dateID = date('Y-n-j G:*'); + + //~ $sql = new mysqli('localhost', MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB); + //~ $query = $sql->query("SELECT DateTime,ChatID,MessageID FROM ".MYSQL_TABLE." WHERE DateTime>='$dateID' + //~ ORDER BY DateTime ASC LIMIT 10") or error("Can't make the query, SQL error ".$sql->error); + + //~ $text = "Prossimi 10 messaggi programmati"; + //~ $i = 1; + //~ while($row = $query->fetch_assoc()) { + //~ $text .= "\n".$i." - ". $row['DateTime']; + //~ $i++; + //~ } + //~ $text .= "\nFunzione in miglioramento"; + //~ $query = API_URL . API_TOKEN . '/sendMessage?' . + //~ 'chat_id=' . urlencode($chatID) . + //~ '&text=' . urlencode($text); + //~ $sql->close(); + //~ file_get_contents($query); + + //~ break; + + // yusdgfdsjf + + //~ $dateID = date('Y-n-j G:*'); $sql = new mysqli('localhost', MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB); - $query = $sql->query("SELECT DateTime FROM ".MYSQL_TABLE." WHERE DateTime>='$dateID' - ORDER BY DateTime ASC LIMIT 10") or error("Can't make the query, SQL error ".$sql->error); - - $text = "Prossimi 10 messaggi programmati"; - $i = 1; - while ($row = $query->fetch_assoc()) { - $text .= "\n".$i." - ". $row['DateTime']; - $i++; + $numbers = $sql->query("SELECT COUNT(*) FROM ".MYSQL_TABLE); + $numbers = $numbers->fetch_array()[0]; + if ($numbers == 0) { + $query = API_URL.API_TOKEN."/sendmessage?chat_id=".($chatID). + "&text=Nessun messaggio programmato"; + $answer = file_get_contents($query); + die(); } + + $query = $sql->query("SELECT DATE_FORMAT(DateTime,'%d/%m/%Y ore %H') as DateTime,Text,Author,ID FROM ".MYSQL_TABLE." + ORDER BY DateTime ASC LIMIT 1") or error("Can't make the query, SQL error ".$sql->error); + + //while($row = $query->fetch_assoc()) { + $row = $query->fetch_assoc(); + $mc->set($chatID.MC_DELETE_SCHEDULED_ID, $row['ID']) + or $mc->replace($chatID.MC_DELETE_SCHEDULED_ID, $row['ID']);; + //~ $query = API_URL . API_TOKEN . '/forwardMessage?' . + //~ 'chat_id=' . urlencode($chatID) . + //~ '&from_chat_id=' . urlencode($row['ChatID']) . + //~ '&message_id=' . urlencode($row['MessageID']); + //~ $answer = file_get_contents($query); + //~ $answer = json_decode($answer); $sql->close(); - $query = API_URL.API_TOKEN."/sendmessage?chat_id=".($chatID). - "&text=".urlencode($text). - "&reply_markup=".$reply; - $answer = file_get_contents($query); + //$mc->set($chatID.MC_FW_EDIT, $answer->result->message_id) + // or $mc->replace($chatID.MC_FW_EDIT, $answer->result->message_id); + $container = array( + array( + array( + "text" => $row['DateTime'], + "callback_data" => "null" + ))); + + $container[] = array( + array( + "text" => " ", + "callback_data" => "null" + ), + array( + "text" => "$EMOJI_THUMBSDOWN Canc", + "callback_data" => MSG_DELETE + ), + $numbers > 1 ? + array( + "text" => ">", + "callback_data" => ">" + ) + : + array( + "text" => " ", + "callback_data" => "null" + ) + ); + + $resp = array( + "inline_keyboard" => $container); + $reply = json_encode($resp); + + $text="$row[Text]\n_$row[Author]_"; // NOME CANALE ".API_CHANNEL_ID."?"; + + $query = API_URL.API_TOKEN."/sendmessage?chat_id=".($chatID). + "&text=".urlencode($text). + "&parse_mode=".urlencode("Markdown"). + "&reply_markup=".$reply; + $answer = file_get_contents($query); + $answer = json_decode($answer); + + $mc->set($chatID.MC_INLINE_ID, $answer->result->message_id) + or $mc->replace($chatID.MC_INLINE_ID, $answer->result->message_id); + + $mc->set($chatID.MC_LIST_NUMBER, 0) + or $mc->replace($chatID.MC_LIST_NUMBER, 0); break; default: - if (DEBUG) warning("$command[command] is not a valid command"); + warning("$command[command] is not a valid command"); } } else { // not a command (pure text) @@ -181,11 +380,17 @@ switch ($status) { $msg = $mc->get($chatID.MC_FORWARD_MSG) or error("Can't forward message\n"); - $query = API_URL . API_TOKEN . '/forwardMessage?' . - 'chat_id=' . urlencode(API_CHANNEL_ID) . - '&from_chat_id=' . urlencode($msg->message->chat->id) . - '&message_id=' . urlencode($msg->message->message_id); - file_get_contents($query); + //~ $query = API_URL . API_TOKEN . '/forwardMessage?' . + //~ 'chat_id=' . urlencode(API_CHANNEL_ID) . + //~ '&from_chat_id=' . urlencode($msg->message->chat->id) . + //~ '&message_id=' . urlencode($msg->message->message_id); + //~ file_get_contents($query); + $query = API_URL . API_TOKEN . '/sendmessage?' . + 'chat_id=' . urlencode(API_CHANNEL_ID) . + '&text='.urlencode($msg->message->text."\n_".$msg->message->chat->username."_"). + "&parse_mode=".urlencode("Markdown"); //bah, un isset un ce lo vedrei male + $result = file_get_contents($query); + if(DEBUG) botlog("[LOG] $result\n"); // Remove kbd $text = "Invio effettuato correttamente"; @@ -386,7 +591,7 @@ switch ($status) { $msg = $mc->get($chatID.MC_FORWARD_MSG); // add to database (mysql) - + $sql = new mysqli('localhost', MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB); // Build up mysql query $value = "("; $value .= $msg->message->message_id; @@ -397,12 +602,17 @@ switch ($status) { $value .= $currentTab['month'].'-'; $value .= $currentTab['day'].' '; $value .= $callback_data.":00:00'"; + $value .= ","; + $value .= "'".$sql->escape_string($msg->message->text)."'"; + $value .= ","; + $value .= "'".$sql->escape_string($msg->message->from->username)."'"; // andrebbe fatto un isset, vabbĂ© $value .= ");"; info("Saving post in ".MYSQL_TABLE.", scheduled date: ".$value); - $sql = new mysqli('localhost', MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB); - $query = $sql->query("INSERT INTO ".MYSQL_TABLE." (MessageID,ChatID,DateTime) VALUE ".$value); + + $query = $sql->query("INSERT INTO ".MYSQL_TABLE." (MessageID,ChatID,DateTime,Text,Author) VALUE ".$value) + or error("Can't make the query, SQL error ".$sql->error); $sql->close(); $text = "Programmazione avvenuta con successo"; diff --git a/schedule.php b/schedule.php index 0d1a187..ce45f8c 100644 --- a/schedule.php +++ b/schedule.php @@ -1,23 +1,33 @@ query("SELECT MessageID,ChatID FROM ".MYSQL_TABLE." WHERE DateTime='".$dateID."'"); +$query = $sql->query("SELECT DateTime,Text,Author FROM ".MYSQL_TABLE. + "WHERE DateTime='".$dateID."'") + or error("Can't make the query, SQL error ".$sql->error); + +// Post all messages (only text) while ($row = $query->fetch_assoc()) { info("Publishing message $row[MessageID]"); - $bot_query = API_URL . API_TOKEN . '/forwardMessage?' . + $bot_query = API_URL . API_TOKEN . '/sendMessage?' . 'chat_id=' . urlencode(API_CHANNEL_ID) . - '&from_chat_id=' . urlencode($row['ChatID']) . - '&message_id=' . urlencode($row['MessageID']); + '&text=' . urlencode($row['Text']."\n_".$row['Author']."_"). + "&parse_mode=".urlencode("Markdown"); file_get_contents($bot_query); } -// clean events <= today +// Remove just posted messages (and any eventual previous one) $sql->query("DELETE FROM ".MYSQL_TABLE." WHERE DateTime<='".$dateID."'"); $sql->close(); ?> diff --git a/shared.php b/shared.php index 5d69db4..37402cf 100644 --- a/shared.php +++ b/shared.php @@ -25,26 +25,98 @@ if (DEBUG) botlog("[II] $message\n"); } - // Interpreta un comando inviato al bot - mettere null o simili invece di -1 +// Interpreta un comando inviato al bot - mettere null o simili invece di -1 function getCommand($messaggio, $NoOffset = true) { if (!isset($messaggio->entities)) - return -1; + return null; foreach ($messaggio->entities as $entity) { if ($entity->type == "bot_command") { if ($NoOffset == true and $entity->offset != 0) - return -1; + return null; //~ if (DEBUG) botlog("[II] Comando: ".$entity->offset. " ".$messaggio->text); //return substr($messaggio->text, $entity->offset, $entity->length); $ret['command'] = substr($messaggio->text, $entity->offset, $entity->length); $ret['options'] = substr($messaggio->text, $entity->length+$entity->offset+1); - if (DEBUG) botlog("[II] Comando: ".$ret['command']."\n"); + info("Command: $ret[command]"); return $ret; } } - return -1; + return null; } - // fabbrica una tabellina che in futuro sarĂ  la pagina di calendario specificata da $mese e $anno + /**** Telegram query functions ****/ + + // return a message object, null if is error + function sendMessage($chat_id, $text, $parse_mode = null, + $disable_web_preview = false, + $disable_notification = false, + $reply_to_message_id = null, + $reply_markup = null) { + $query = API_URL.API_TOKEN."/sendMessage?chat_id=".$chat_id. + "&text=".urlencode($text); + + if ($parse_mode != null) $query .= "&parse_mode=$parse_mode"; + if ($reply_markup != null) $query .= "&reply_markup=$reply_markup"; + if ($disable_web_preview != false) $query .= "&disable_web_preview=$disable_web_preview"; + if ($disable_notification != false) $query .= "&disable_notification=$disable_notification"; + if ($reply_to_message_id != null) $query .= "&reply_to_message_id=$reply_to_message_id"; + if ($reply_markup != null) $query .= "&reply_markup=$reply_markup"; + + $answer = file_get_contents($query); + if ($answer === false) warning("Something is wrong in sendMessage - chat_id: $chat_id - text: $text"); + return $answer; + } + + // + function forwardMessage($chat_id, $from_chat_id, + $message_id, + $disable_notification = false) { + + $query = API_URL . API_TOKEN . "/forwardMessage?" . + "chat_id=".urlencode($chat_id) . + "&from_chat_id=" . urlencode($from_chat_id) . + "&message_id=" . urlencode($message_id); + + if ($disable_notification != null) $query .= "&disable_notification=$disable_notification"; + + $answer = file_get_contents($query); + if ($answer === false) warning("Something is wrong in forwardMessage - chat_id: $chat_id - message_id: $message_id"); + return $answer; + } + + // omitted "inline parameters", for inline bot funtions (not used here) + function editMessageText($chat_id, $message_id, $text, + $parse_mode = null, + $disable_web_page_preview = false, + $reply_markup = null) { + + $query = API_URL . API_TOKEN . "/forwardMessage?" . + "chat_id=".urlencode($chat_id) . + "&message_id=" . urlencode($message_id). + "&text=" . urlencode($text); + + if ($disable_web_page_preview != null) $query .= "&disable_web_page_preview=$disable_web_page_preview"; + if ($reply_markup != null) $query .= "&reply_markup=$reply_markup"; + + $answer = file_get_contents($query); + if ($answer === false) warning("Something is wrong in editMessageText - chat_id: $chat_id - message_id: $message_id"); + return $answer; + } + + // + function deleteMessage($chat_id, $message_id) { + + $query = API_URL . API_TOKEN . "/deleteMessage?" . + "chat_id=".urlencode($chat_id) . + "&message_id=" . urlencode($message_id); + + $answer = file_get_contents($query); + if ($answer === false) warning("Something is wrong in deleteMessage - chat_id: $chat_id - message_id: $message_id"); + return $answer; + } + + + // Makes the calendar inline keyboard function getCalendarTab ($month, $year) { $container = array(); $riga = array(); @@ -66,8 +138,8 @@ $daysInMonth = cal_days_in_month (CAL_GREGORIAN , $month , $year); $date = $year."-".$month; - $currentMonth = date('nY') == $month.$year; //magari anche l'anno? - $startingDay = $currentMonth ? date('j') : 1; + $isCurrentMonth = date('nY') == $month.$year; + $startingDay = $isCurrentMonth ? date('j') : 1; if (DEBUG) botlog("[II] First day: ".$date.'-'.$startingDay."\n"); $firstDay = date("N", strtotime($date.'-'.$startingDay)); @@ -121,7 +193,7 @@ $container[] = array( - $currentMonth ? + $isCurrentMonth ? array( "text" => " ", "callback_data" => "null"