diff --git a/store/description.txt b/store/description.txt new file mode 100644 index 0000000..6e29fa9 --- /dev/null +++ b/store/description.txt @@ -0,0 +1,16 @@ +SimpleCloudNotifier is a app to display messages that you can send to your phone with a simple POST request to the right URL. + +After you start the app it generates a userID and a private key. +Now you can send your message to https://simplecloudnotifier.blackforestbytes.com/send.php and a notification will be pushed to your phone. +(see https://simplecloudnotifier.blackforestbytes.com/ for an example with curl) + + +Use it to + - send yourself automated messages from cron jobs + - notify youreself when long-running scripts finish + - send server error messages directly to your phone + - integrate with other online services + +The possibilities are endless* + +*Disclaimer: Developer does not actually guarantee endless possibilities \ No newline at end of file diff --git a/web/css/style.css b/web/css/style.css index a4c47fe..29752b2 100644 --- a/web/css/style.css +++ b/web/css/style.css @@ -13,7 +13,6 @@ body } - @keyframes blink-shadow { 0% { box-shadow: 0 0 32px #DDD; } 50% { box-shadow: none; } @@ -26,7 +25,7 @@ body animation:blink-shadow ease-in-out 4s infinite; width: 87%; min-width: 300px; - max-width: 800px; + max-width: 900px; position: relative; min-height: 445px; } @@ -55,6 +54,12 @@ body color: #FFF; text-shadow: #000 0 0 2px, #888 0 0 8px; } +@media (max-width: 600px) { + #mainpnl h1 { + font-size: calc(0.85rem * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio)); + margin-top: 40px; + } +} #mainpnl button { @@ -69,6 +74,7 @@ body position: fixed; bottom: 0; right: 0; + z-index: -999; } #copyinfo a:hover @@ -115,4 +121,75 @@ body height: 32px; background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjBweCIgeT0iMHB4IgogICAgIHdpZHRoPSI1MCIgaGVpZ2h0PSI1MCIKICAgICB2aWV3Qm94PSIwIDAgNDggNDgiCiAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDsiPjxnIGlkPSJzdXJmYWNlMSI+PHBhdGggc3R5bGU9IiBmaWxsOiM0REI2QUM7IiBkPSJNIDcuNzAzMTI1IDQuMDQyOTY5IEMgNy4yOTI5NjkgNC4xNDg0MzggNyA0LjUwNzgxMyA3IDUuMTIxMDk0IEMgNyA2LjkyMTg3NSA3IDIzLjkxNDA2MyA3IDIzLjkxNDA2MyBDIDcgMjMuOTE0MDYzIDcgNDIuMjgxMjUgNyA0My4wODk4NDQgQyA3IDQzLjUzNTE1NiA3LjE5NTMxMyA0My44MzU5MzggNy41IDQzLjk0NTMxMyBMIDI3LjY3OTY4OCAyMy44ODI4MTMgWiAiPjwvcGF0aD48cGF0aCBzdHlsZT0iIGZpbGw6I0RDRTc3NTsiIGQ9Ik0gMzMuMjM4MjgxIDE4LjM1OTM3NSBMIDI0LjkyOTY4OCAxMy41NjI1IEMgMjQuOTI5Njg4IDEzLjU2MjUgOS42ODM1OTQgNC43NjE3MTkgOC43ODkwNjMgNC4yNDIxODggQyA4LjQwMjM0NCA0LjAxOTUzMSA4LjAxOTUzMSAzLjk2MDkzOCA3LjcwMzEyNSA0LjA0Mjk2OSBMIDI3LjY4MzU5NCAyMy44ODI4MTMgWiAiPjwvcGF0aD48cGF0aCBzdHlsZT0iIGZpbGw6I0QzMkYyRjsiIGQ9Ik0gOC40MTc5NjkgNDMuODAwNzgxIEMgOC45NDkyMTkgNDMuNDkyMTg4IDIzLjY5OTIxOSAzNC45NzY1NjMgMzMuMjgxMjUgMjkuNDQ1MzEzIEwgMjcuNjc5Njg4IDIzLjg4MjgxMyBMIDcuNSA0My45NDUzMTMgQyA3Ljc0NjA5NCA0NC4wMzkwNjMgOC4wNjY0MDYgNDQuMDAzOTA2IDguNDE3OTY5IDQzLjgwMDc4MSBaICI+PC9wYXRoPjxwYXRoIHN0eWxlPSIgZmlsbDojRkJDMDJEOyIgZD0iTSA0MS4zOTg0MzggMjMuMDcwMzEzIEMgNDAuNjAxNTYzIDIyLjY0MDYyNSAzMy4yOTY4NzUgMTguMzk0NTMxIDMzLjI5Njg3NSAxOC4zOTQ1MzEgTCAzMy4yMzgyODEgMTguMzU5Mzc1IEwgMjcuNjc5Njg4IDIzLjg4MjgxMyBMIDMzLjI4MTI1IDI5LjQ0NTMxMyBDIDM3LjcxNDg0NCAyNi44ODY3MTkgNDEuMDQyOTY5IDI0Ljk2NDg0NCA0MS4zMzk4NDQgMjQuNzkyOTY5IEMgNDIuMjg1MTU2IDI0LjI0NjA5NCA0Mi4xOTUzMTMgMjMuNSA0MS4zOTg0MzggMjMuMDcwMzEzIFogIj48L3BhdGg+PC9nPjwvc3ZnPg==') 50% 50% no-repeat; background-size: 100%; +} + +#btnSend +{ + height: 42px; +} + +#btnSend .spinnerbox .spinner +{ + margin: 0; + padding: 0; + height: 16px; + width: 16px; +} + +#btnSend .spinnerbox +{ + margin: -8px; + display: flex; + justify-content: center; + align-items: center; + align-content: center; +} + +input[type='number'] { + -moz-appearance:textfield; +} + +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; +} + +.input-invalid, +.input-invalid:hover, +.input-invalid:active +{ + border-color: var(--input-invalid-color) !important; + box-shadow: none !important; +} + +.card.success { + --card-back-color: rgb(48, 135, 50); + --card-border-color: rgba(0, 0, 0, 0.3);; +} + +.fullcenterflex +{ + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + display: flex; + justify-content: center; + align-items: center; + align-content: center; +} + +a.card, +a.card:active, +a.card:visited, +a.card:hover +{ + color: #000; + text-decoration: none; +} + +a.card:hover +{ + box-shadow: 0 0 16px #AAA; } \ No newline at end of file diff --git a/web/css/toastify.min.css b/web/css/toastify.min.css new file mode 100644 index 0000000..765a518 --- /dev/null +++ b/web/css/toastify.min.css @@ -0,0 +1,15 @@ +/** + * Minified by jsDelivr using clean-css v4.2.0. + * Original file: /npm/toastify.js@1.3.0/src/toastify.css + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +/*! + * Toastify js 1.2.2 + * https://github.com/apvarun/toastify-js + * @license MIT licensed + * + * Copyright (C) 2018 Varun A P + */ +.toastify{padding:12px 20px;color:#fff;display:inline-block;box-shadow:0 3px 6px -1px rgba(0,0,0,.12),0 10px 36px -4px rgba(77,96,232,.3);background:-webkit-linear-gradient(315deg,#73a5ff,#5477f5);background:linear-gradient(135deg,#73a5ff,#5477f5);position:fixed;opacity:0;transition:all .4s cubic-bezier(.215,.61,.355,1);border-radius:2px;cursor:pointer;text-decoration:none;max-width:calc(50% - 20px)}.toastify.on{opacity:1}.toast-close{opacity:.4;padding:0 5px}.right{right:15px}.left{left:15px}.top{top:-150px}.bottom{bottom:-150px}.rounded{border-radius:25px}.avatar{width:1.5em;height:1.5em;margin:0 5px;border-radius:2px}@media only screen and (max-width:360px){.left,.right{margin-left:auto;margin-right:auto;left:0;right:0;max-width:fit-content}} +/*# sourceMappingURL=/sm/734ed69e2fe87a4469526acc0a10708fa8e0211c7d4359f9e034ceb89bb5d540.map */ \ No newline at end of file diff --git a/web/index.php b/web/index.php index 83db406..b89b26c 100644 --- a/web/index.php +++ b/web/index.php @@ -2,13 +2,14 @@ + + + - -
@@ -18,28 +19,27 @@
-
+
type="number">
-
+
type="text" maxlength="64">
-
+
type="text" maxlength="80">
-
+
-
- +
@@ -47,5 +47,7 @@ © blackforestbytes + + \ No newline at end of file diff --git a/web/index_api.php b/web/index_api.php index a67e3f4..f3e9c18 100644 --- a/web/index_api.php +++ b/web/index_api.php @@ -3,6 +3,8 @@ + + @@ -20,14 +22,14 @@
curl                                     \
     --data "user_id={userid}"            \
     --data "user_key={userkey}"          \
-    --data "message={message_title}"     \
+    --data "title={message_title}"       \
     --data "content={message_content}"   \
     https://simplecloudnotifier.blackforestbytes.com/send.php

The content parameter is optional, you can also send message with only a title

curl                                     \
     --data "user_id={userid}"            \
     --data "user_key={userkey}"          \
-    --data "message={message_title}"     \
+    --data "title={message_title}"       \
     https://simplecloudnotifier.blackforestbytes.com/send.php
diff --git a/web/index_sent.php b/web/index_sent.php new file mode 100644 index 0000000..7844f5f --- /dev/null +++ b/web/index_sent.php @@ -0,0 +1,53 @@ + + + + + + + + + + + + + +
+ +
+ + + + +
+

Message sent

+

Message succesfully sent
+ /100 remaining

+
+
+ + + + +
+

Failure

+

Unknown error

+
+
+ + + +
+ + + Send + +

Simple Cloud Notifier

+ +
+ +
+ © blackforestbytes +
+ + + \ No newline at end of file diff --git a/web/js/logic.js b/web/js/logic.js new file mode 100644 index 0000000..dc3c682 --- /dev/null +++ b/web/js/logic.js @@ -0,0 +1,84 @@ + +function send() +{ + let me = document.getElementById("btnSend"); + if (me.classList.contains("btn-disabled")) return; + + me.innerHTML = "
"; + + me.classList.add("btn-disabled"); + + let uid = document.getElementById("uid"); + let key = document.getElementById("ukey"); + let msg = document.getElementById("msg"); + let txt = document.getElementById("txt"); + + uid.classList.remove('input-invalid'); + key.classList.remove('input-invalid'); + msg.classList.remove('input-invalid'); + txt.classList.remove('input-invalid'); + + let data = new FormData(); + data.append('user_id', uid.value); + data.append('user_key', key.value); + data.append('title', msg.value); + data.append('content', txt.value); + + let xhr = new XMLHttpRequest(); + xhr.open('POST', '/send.php', true); + xhr.onreadystatechange = function () + { + if (xhr.readyState !== 4) return; + + console.log('Status: ' + xhr.status); + if (xhr.status === 200) + { + let resp = JSON.parse(xhr.responseText); + if (!resp.success) + { + if (resp.errhighlight === 101) uid.classList.add('input-invalid'); + if (resp.errhighlight === 102) key.classList.add('input-invalid'); + if (resp.errhighlight === 103) msg.classList.add('input-invalid'); + if (resp.errhighlight === 104) txt.classList.add('input-invalid'); + + Toastify({ + text: resp.message, + gravity: "top", + positionLeft: false, + backgroundColor: "#D32F2F", + }).showToast(); + } + else + { + window.location.href = + '/index_sent.php' + + '?ok=' + 1 + + '&message_count=' + resp.messagecount + + '"a=' + resp.quota + + '&preset_user_id=' + uid.value + + '&preset_user_key=' + key.value; + } + } + else + { + Toastify({ + text: 'Request failed: Statuscode=' + xhr.status, + gravity: "top", + positionLeft: false, + backgroundColor: "#D32F2F", + }).showToast(); + } + + me.classList.remove("btn-disabled"); + me.innerHTML = "Send"; + }; + xhr.send(data); +} + +window.addEventListener("load",function () +{ + let btnSend = document.getElementById("btnSend"); + + if (btnSend !== undefined) btnSend.onclick = function () { send(); return false; }; + +},false); \ No newline at end of file diff --git a/web/js/toastify.js b/web/js/toastify.js new file mode 100644 index 0000000..bbd01cd --- /dev/null +++ b/web/js/toastify.js @@ -0,0 +1,8 @@ +/** + * Minified by jsDelivr using UglifyJS v3.4.3. + * Original file: /npm/toastify-js@1.3.0/src/toastify.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +!function(t,o){"object"==typeof module&&module.exports?(require("./toastify.css"),module.exports=o()):t.Toastify=o()}(this,function(t){var i=function(t){return new i.lib.init(t)};function r(t,o){return!(!t||"string"!=typeof o)&&!!(t.className&&-1 false, 'errhighlight' => 101, 'message' => 'Missing parameter [[user_id]]'])); -if (!isset($INPUT['user_key'])) die(json_encode(['success' => false, 'errhighlight' => 102, 'message' => 'Missing parameter [[user_token]]'])); -if (!isset($INPUT['message_title'])) die(json_encode(['success' => false, 'errhighlight' => 103, 'message' => 'Missing parameter [[message_title]]'])); +if (!isset($INPUT['user_id'])) die(json_encode(['success' => false, 'errhighlight' => 101, 'message' => 'Missing parameter [[user_id]]'])); +if (!isset($INPUT['user_key'])) die(json_encode(['success' => false, 'errhighlight' => 102, 'message' => 'Missing parameter [[user_token]]'])); +if (!isset($INPUT['title'])) die(json_encode(['success' => false, 'errhighlight' => 103, 'message' => 'Missing parameter [[title]]'])); + +//------------------------------------------------------------------ $user_id = $INPUT['user_id']; $user_key = $INPUT['user_key']; -$message = $INPUT['message_title']; -$content = file_get_contents('php://input'); +$message = $INPUT['title']; +$content = $INPUT['content']; if ($content === null || $content === false) $content = ''; -//---------------------- +//------------------------------------------------------------------ + +if (strlen(trim($message)) == 0) die(json_encode(['success' => false, 'errhighlight' => 103, 'message' => 'No title specified'])); +if (strlen($message) > 120) die(json_encode(['success' => false, 'errhighlight' => 103, 'message' => 'Title too long (120 characters)'])); +if (strlen($content) > 10000) die(json_encode(['success' => false, 'errhighlight' => 104, 'message' => 'Content too long (10000 characters)'])); + +//------------------------------------------------------------------ $pdo = getDatabase(); @@ -31,6 +43,7 @@ if ($data['user_key'] !== $user_key) die(json_encode(['success' => false, 'errhi $fcm = $data['fcm_token']; +//------------------------------------------------------------------ $url = "https://fcm.googleapis.com/fcm/send"; $payload = json_encode(