diff --git a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/SCNApp.java b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/SCNApp.java index 21b2284..a7726fe 100644 --- a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/SCNApp.java +++ b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/SCNApp.java @@ -102,29 +102,29 @@ public class SCNApp extends Application implements LifecycleObserver /* ==TODO== - - Pro mode - - no ads - - more quota - - restore pro mode - - send pro state to server +[X] - Pro mode +[X] - no ads +[X] - more quota +[X] - restore pro mode +[X] - send pro state to server - - prevent duplicate-send - - send custom msg-id in API - - prevent second ack on same msg-id +[X] - prevent duplicate-send +[X] - send custom msg-id in API +[X] - prevent second ack on same msg-id - - more in-depth API doc on website (?) +[X] - more in-depth API doc on website (?) - - perhaps response codes in api (?) +[X] - perhaps response codes in api (?) - - test notification channels +[ ] - test notification channels - - publish (+ HN post ?) +[ ] - publish (+ HN post ?) - - Use for mscom server errrors - - Use for bfb server errors - - Use for transmission state - - Message on connnection lost (seperate process - resend until succ) - - Message on connnection regained - - Message on seed-count changed +[ ] - Use for mscom server errrors +[ ] - Use for bfb server errors +[ ] - Use for transmission state +[ ] - Message on connnection lost (seperate process - resend until succ) +[ ] - Message on connnection regained +[ ] - Message on seed-count changed */ \ No newline at end of file diff --git a/web/model.php b/web/model.php index 3af5cbe..61930ed 100644 --- a/web/model.php +++ b/web/model.php @@ -196,4 +196,22 @@ function api_return($http_code, $message) http_response_code($http_code); echo $message; die(); +} + +/** + * @param String $str + * @param String[] $path + */ +function try_json($str, $path) +{ + try + { + $o = json_decode($str); + foreach ($path as $p) $o = $o[$p]; + return $o; + } + catch (Exception $e) + { + return null; + } } \ No newline at end of file diff --git a/web/schema.sql b/web/schema.sql index 0dbc3bf..ec0fd5e 100644 --- a/web/schema.sql +++ b/web/schema.sql @@ -1,17 +1,34 @@ CREATE TABLE `users` ( - `user_id` INT(11) NOT NULL AUTO_INCREMENT, - `user_key` VARCHAR(64) NOT NULL, - `fcm_token` VARCHAR(256) NULL DEFAULT NULL, - `messages_sent` INT(11) NOT NULL DEFAULT '0', - `timestamp_created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - `timestamp_accessed` DATETIME NULL DEFAULT NULL, + `user_id` INT(11) NOT NULL AUTO_INCREMENT, + `user_key` VARCHAR(64) NOT NULL, + `fcm_token` VARCHAR(256) NULL DEFAULT NULL, + `messages_sent` INT(11) NOT NULL DEFAULT '0', + `timestamp_created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `timestamp_accessed` DATETIME NULL DEFAULT NULL, - `quota_today` INT(11) NOT NULL DEFAULT '0', - `quota_day` DATE NULL DEFAULT NULL, + `quota_today` INT(11) NOT NULL DEFAULT '0', + `quota_day` DATE NULL DEFAULT NULL, - `is_pro` BIT NOT NULL DEFAULT 0, - `pro_token` VARCHAR(256) NULL DEFAULT NULL, + `is_pro` BIT NOT NULL DEFAULT 0, + `pro_token` VARCHAR(256) NULL DEFAULT NULL, PRIMARY KEY (`user_id`) ); + +CREATE TABLE `messages` +( + `scn_message_id` INT(11) NOT NULL AUTO_INCREMENT, + `sender_user_id` INT(11) NOT NULL, + + `timestamp` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + + `title` VARCHAR(256) NOT NULL, + `content` VARCHAR(12288) NULL, + `priority` INT(11) NOT NULL, + + `fcn_message_id` VARCHAR(256) NOT NULL, + `usr_message_id` VARCHAR(256) NULL, + + PRIMARY KEY (`scn_message_id`) +) \ No newline at end of file diff --git a/web/send.php b/web/send.php index be0fe83..8f256fe 100644 --- a/web/send.php +++ b/web/send.php @@ -23,6 +23,7 @@ try $message = $INPUT['title']; $content = isset($INPUT['content']) ? $INPUT['content'] : ''; $priority = isset($INPUT['priority']) ? $INPUT['priority'] : '1'; + $usrmsgid = isset($INPUT['msg_id']) ? $INPUT['msg_id'] : null; //------------------------------------------------------------------ @@ -53,6 +54,29 @@ try if ($data['quota_day'] === null || $data['quota_day'] !== date("Y-m-d")) $new_quota=1; if ($new_quota > Statics::quota_max($data['is_pro'])) api_return(403, json_encode(['success' => false, 'error' => 2101, 'errhighlight' => -1, 'message' => 'Daily quota reached ('.Statics::quota_max($data['is_pro']).')'])); +//------------------------------------------------------------------ + + if ($usrmsgid != null) + { + $stmt = $pdo->prepare('SELECT scn_message_id FROM messages WHERE sender_user_id=:uid AND usr_message_id IS NOT NULL AND usr_message_id=:umid LIMIT 1'); + $stmt->execute(['uid' => $user_id, 'umid' => $usrmsgid]); + + if (count($stmt->fetchAll(PDO::FETCH_ASSOC))>0) + { + api_return(200, json_encode( + [ + 'success' => true, + 'message' => 'Message already sent', + 'suppress_send' => true, + 'response' => '', + 'messagecount' => $data['messages_sent']+1, + 'quota' => $data['quota_today'], + 'is_pro' => $data['is_pro'], + 'quota_max' => Statics::quota_max($data['is_pro']), + ])); + } + } + //------------------------------------------------------------------ $url = "https://fcm.googleapis.com/fcm/send"; @@ -68,10 +92,11 @@ try //], 'data' => [ - 'title' => $message, - 'body' => $content, - 'priority' => $priority, - 'timestamp' => time(), + 'title' => $message, + 'body' => $content, + 'priority' => $priority, + 'timestamp' => time(), + 'usr_msg_id' => $usrmsgid, ] ]); $header= @@ -83,6 +108,12 @@ try try { $httpresult = sendPOST($url, $payload, $header); + + if (try_json($httpresult, ['success']) != 1) + { + reportError("FCM communication failed (success_1 <> true)\n\n".$httpresult); + api_return(403, json_encode(['success' => false, 'error' => 9902, 'errhighlight' => -1, 'message' => 'Communication with firebase service failed.'])); + } } catch (Exception $e) { @@ -93,15 +124,27 @@ try $stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), messages_sent=messages_sent+1, quota_today=:q, quota_day=NOW() WHERE user_id = :uid'); $stmt->execute(['uid' => $user_id, 'q' => $new_quota]); + $stmt = $pdo->prepare('INSERT INTO messages (sender_user_id, title, content, priority, fcn_message_id, usr_message_id) VALUES (:suid, :t, :c, :p, :fmid, :umid)'); + $stmt->execute( + [ + 'suid' => $user_id, + 't' => $message, + 'c' => $content, + 'p' => $priority, + 'fmid' => try_json($httpresult, ['results', 'message_id']), + 'umid' => $usrmsgid, + ]); + api_return(200, json_encode( [ - 'success' => true, - 'message' => 'Message sent', - 'response' => $httpresult, - 'messagecount' => $data['messages_sent']+1, - 'quota' => $new_quota, - 'is_pro' => $data['is_pro'], - 'quota_max' => Statics::quota_max($data['is_pro']), + 'success' => true, + 'message' => 'Message sent', + 'suppress_send' => false, + 'response' => $httpresult, + 'messagecount' => $data['messages_sent']+1, + 'quota' => $new_quota, + 'is_pro' => $data['is_pro'], + 'quota_max' => Statics::quota_max($data['is_pro']), ])); } catch (Exception $mex)