web kinda finished

This commit is contained in:
Mike Schwörer 2018-09-22 19:40:50 +02:00
parent fcdb5217ee
commit 543f359acd
Signed by: Mikescher
GPG Key ID: D3C7172E0A70F8CF
9 changed files with 288 additions and 18 deletions

16
store/description.txt Normal file
View File

@ -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*
<i>*Disclaimer: Developer does not actually guarantee endless possibilities</i>

View File

@ -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;
}

15
web/css/toastify.min.css vendored Normal file
View File

@ -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 */

View File

@ -2,13 +2,14 @@
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="/css/toastify.min.css"/>
<link rel="stylesheet" href="/css/mini-default.min.css">
<!--<link rel="stylesheet" href="/css/mini-nord.min.css">-->
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
<link rel="stylesheet" href="/css/style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form id="mainpnl">
<a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
@ -18,28 +19,27 @@
<div class="row responsive-label">
<div class="col-sm-12 col-md-3"><label for="uid" class="doc">UserID</label></div>
<div class="col-sm-12 col-md"><input placeholder="UserID" id="uid" class="doc" type="text"></div>
<div class="col-sm-12 col-md"><input placeholder="UserID" id="uid" class="doc" <?php echo (isset($_GET['preset_user_id']) ? (' value="'.$_GET['preset_user_id'].'" '):(''));?> type="number"></div>
</div>
<div class="row responsive-label">
<div class="col-sm-12 col-md-3"><label for="ukey" class="doc">Authentification Key</label></div>
<div class="col-sm-12 col-md"><input placeholder="Key" id="ukey" class="doc" type="text"></div>
<div class="col-sm-12 col-md"><input placeholder="Key" id="ukey" class="doc" <?php echo (isset($_GET['preset_user_key']) ? (' value="'.$_GET['preset_user_key'].'" '):(''));?> type="text" maxlength="64"></div>
</div>
<div class="row responsive-label">
<div class="col-sm-12 col-md-3"><label for="msg" class="doc">Message Title</label></div>
<div class="col-sm-12 col-md"><input placeholder="Message" id="msg" class="doc" type="text"></div>
<div class="col-sm-12 col-md"><input placeholder="Message" id="msg" class="doc" <?php echo (isset($_GET['preset_title']) ? (' value="'.$_GET['preset_title'].'" '):(''));?> type="text" maxlength="80"></div>
</div>
<div class="row responsive-label">
<div class="col-sm-12 col-md-3"><label for="txt" class="doc">Message Content</label></div>
<div class="col-sm-12 col-md"><textarea id="txt" class="doc" rows="5"></textarea></div>
<div class="col-sm-12 col-md"><textarea id="txt" class="doc" <?php echo (isset($_GET['preset_content']) ? (' value="'.$_GET['preset_content'].'" '):(''));?> rows="5"></textarea></div>
</div>
<div class="row">
<div class="col-sm-12 col-md-3"></div>
<div class="col-sm-12 col-md"><button type="submit" class="primary bordered">Send</button></div>
<div class="col-sm-12 col-md"><button type="submit" class="primary bordered" id="btnSend">Send</button></div>
</div>
</form>
@ -47,5 +47,7 @@
<a href="https://www.blackforestbytes.com">&#169; blackforestbytes</a>
</div>
<script src="/js/logic.js" type="text/javascript" ></script>
<script src="/js/toastify.js"></script>
</body>
</html>

View File

@ -3,6 +3,8 @@
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="/css/mini-default.min.css">
<!--<link rel="stylesheet" href="/css/mini-nord.min.css">-->
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
<link rel="stylesheet" href="/css/style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
@ -20,14 +22,14 @@
<pre>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</pre>
<p>The <code>content</code> parameter is optional, you can also send message with only a title</p>
<pre>curl \
--data "user_id={userid}" \
--data "user_key={userkey}" \
--data "message={message_title}" \
--data "title={message_title}" \
https://simplecloudnotifier.blackforestbytes.com/send.php</pre>
</form>

53
web/index_sent.php Normal file
View File

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="/css/mini-default.min.css">
<!--<link rel="stylesheet" href="/css/mini-nord.min.css">-->
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
<link rel="stylesheet" href="/css/style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form id="mainpnl">
<div class="fullcenterflex">
<?php if (isset($_GET['ok']) && $_GET['ok'] === "1" ): ?>
<a class="card success" href="/index.php?preset_user_id=<?php echo isset($_GET['preset_user_id'])?$_GET['preset_user_id']:'ERR';?>&preset_user_key=<?php echo isset($_GET['preset_user_key'])?$_GET['preset_user_key']:'ERR';?>">
<div class="section">
<h3 class="doc">Message sent</h3>
<p class="doc">Message succesfully sent<br>
<?php echo isset($_GET['quota'])?$_GET['quota']:'ERR';?>/100 remaining</p>
</div>
</a>
<?php else: ?>
<a class="card error" href="/index.php">
<div class="section">
<h3 class="doc">Failure</h3>
<p class="doc">Unknown error</p>
</div>
</a>
<?php endif; ?>
</div>
<a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
<a href="/index.php" class="button bordered" id="tr_link">Send</a>
<h1>Simple Cloud Notifier</h1>
</form>
<div id="copyinfo">
<a href="https://www.blackforestbytes.com">&#169; blackforestbytes</a>
</div>
</body>
</html>

84
web/js/logic.js Normal file
View File

@ -0,0 +1,84 @@
function send()
{
let me = document.getElementById("btnSend");
if (me.classList.contains("btn-disabled")) return;
me.innerHTML = "<div class=\"spinnerbox\"><div class=\"spinner primary\"></div></div>";
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 +
'&quota=' + 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);

8
web/js/toastify.js Normal file
View File

@ -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<t.className.trim().split(/\s+/gi).indexOf(o))}return i.lib=i.prototype={toastify:"1.2.2",constructor:i,init:function(t){return t||(t={}),this.options={},this.options.text=t.text||"Hi there!",this.options.duration=t.duration||3e3,this.options.selector=t.selector,this.options.callback=t.callback||function(){},this.options.destination=t.destination,this.options.newWindow=t.newWindow||!1,this.options.close=t.close||!1,this.options.gravity="bottom"==t.gravity?"bottom":"top",this.options.positionLeft=t.positionLeft||!1,this.options.backgroundColor=t.backgroundColor,this.options.avatar=t.avatar||"",this.options.className=t.className||"",this},buildToast:function(){if(!this.options)throw"Toastify is not initialized";var t=document.createElement("div");if(t.className="toastify on "+this.options.className,!0===this.options.positionLeft?t.className+=" left":t.className+=" right",t.className+=" "+this.options.gravity,this.options.backgroundColor&&(t.style.background=this.options.backgroundColor),t.innerHTML=this.options.text,""!==this.options.avatar){var o=document.createElement("img");o.src=this.options.avatar,o.className="avatar",!0===this.options.positionLeft?t.appendChild(o):t.insertAdjacentElement("beforeend",o)}if(!0===this.options.close){var i=document.createElement("span");i.innerHTML="&#10006;",i.className="toast-close",i.addEventListener("click",function(t){t.stopPropagation(),this.removeElement(t.target.parentElement),window.clearTimeout(t.target.parentElement.timeOutValue)}.bind(this));var n=0<window.innerWidth?window.innerWidth:screen.width;!0===this.options.positionLeft&&360<n?t.insertAdjacentElement("afterbegin",i):t.appendChild(i)}return void 0!==this.options.destination&&t.addEventListener("click",function(t){t.stopPropagation(),!0===this.options.newWindow?window.open(this.options.destination,"_blank"):window.location=this.options.destination}.bind(this)),t},showToast:function(){var t,o=this.buildToast();if(!(t=void 0===this.options.selector?document.body:document.getElementById(this.options.selector)))throw"Root element is not defined";return t.insertBefore(o,t.firstChild),i.reposition(),o.timeOutValue=window.setTimeout(function(){this.removeElement(o)}.bind(this),this.options.duration),this},removeElement:function(t){t.className=t.className.replace(" on",""),window.setTimeout(function(){t.parentNode.removeChild(t),this.options.callback.call(t),i.reposition()}.bind(this),400)}},i.reposition=function(){for(var t,o={top:15,bottom:15},i={top:15,bottom:15},n={top:15,bottom:15},e=document.getElementsByClassName("toastify"),s=0;s<e.length;s++){t=!0===r(e[s],"top")?"top":"bottom";var a=e[s].offsetHeight;(0<window.innerWidth?window.innerWidth:screen.width)<=360?(e[s].style[t]=n[t]+"px",n[t]+=a+15):!0===r(e[s],"left")?(e[s].style[t]=o[t]+"px",o[t]+=a+15):(e[s].style[t]=i[t]+"px",i[t]+=a+15)}return this},i.lib.init.prototype=i.lib,i});
//# sourceMappingURL=/sm/3f68e387be4f7a323a891120e4e01e3bee54a927113a386cf5e598b3cd442fcc.map

View File

@ -2,19 +2,31 @@
include_once 'model.php';
//------------------------------------------------------------------
sleep(1);
//------------------------------------------------------------------
$INPUT = array_merge($_GET, $_POST);
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['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(