Add nodemailer configuration and console.log statement
Update formAJAX function to log data from the server Add getUserByEmail and checkEmail functions Update profile.ejs to require login Update addSensorData function to emit new sensor data Update api.css with styling changes Update token route to generate and send token email Update authChecker middleware to allow user and token routes
This commit is contained in:
@ -6,6 +6,10 @@
|
||||
!-->
|
||||
|
||||
<%- include('top') %>
|
||||
<script type="text/javascript">
|
||||
// Require login to see this page.
|
||||
app.auth.forceLogin()
|
||||
</script>
|
||||
<link rel="stylesheet" href="css/api.css" media="all">
|
||||
|
||||
<body class="one-content-column-version">
|
||||
@ -312,81 +316,6 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="overflow-hidden content-section" id="content-errors">
|
||||
<h2>Errors</h2>
|
||||
<p>
|
||||
The Westeros API uses the following error codes:
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Error Code</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>X000</td>
|
||||
<td>
|
||||
Some parameters are missing. This error appears when you don't pass every mandatory
|
||||
parameters.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>403</td>
|
||||
<td>
|
||||
Unknown or unvalid <code class="higlighted">secret_key</code>. This error appears if
|
||||
you use an unknow API key or if your API key expired.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>500</td>
|
||||
<td>
|
||||
Unvalid <code class="higlighted">secret_key</code> No API key was supplied. Invalid
|
||||
request.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X003</td>
|
||||
<td>
|
||||
Unknown or unvalid user <code class="higlighted">token</code>. This error appears if
|
||||
you use an unknow user <code class="higlighted">token</code> or if the user <code
|
||||
class="higlighted">token</code> expired.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="overflow-hidden content-section" id="content-get-api">
|
||||
<div class="api-keys-header">
|
||||
<h2>API Keys</h2>
|
||||
<button class="generate-key-button">Generate Key</button>
|
||||
<p>
|
||||
You can generate API Keys here:
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Public Key</th>
|
||||
<th>Private Key</th>
|
||||
<th>Key Type</th>
|
||||
<th>Created</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>API Key</td>
|
||||
<td>GR234-We34</td>
|
||||
<td>greR-234-fEG</td>
|
||||
<td>Type</td>
|
||||
<td>2024-01-22</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-hidden content-section" id="content-get-sensor">
|
||||
<h2>Get all sensor</h2>
|
||||
<p>
|
||||
@ -483,7 +412,7 @@
|
||||
<td>Authorization</td>
|
||||
<td>JSON</td>
|
||||
<td>Your API key.</td>
|
||||
<td>(Required) Example: curl https://api.teeseng.uk/api/v0/sensor/new
|
||||
<td>(Required) Example: curl https://api.teeseng.uk/api/v0/sensor/new
|
||||
-H "Authorization: {provide your
|
||||
API key here}"</td>
|
||||
</td>
|
||||
@ -620,7 +549,8 @@
|
||||
<td>Description</td>
|
||||
<td>JSON</td>
|
||||
<td>Description of Sensor</td>
|
||||
<td>(Optional) Description of Sensor Example: curl https://api.teeseng.uk/api/v0/sensor/update
|
||||
<td>(Optional) Description of Sensor Example: curl
|
||||
https://api.teeseng.uk/api/v0/sensor/update
|
||||
-H "Authorization: provide
|
||||
your API key here" -d '{"description":"test"}'</td>
|
||||
</td>
|
||||
@ -629,7 +559,8 @@
|
||||
<td>Location</td>
|
||||
<td>JSON</td>
|
||||
<td>Location of Sensor</td>
|
||||
<td>(Optional) Location of Sensor Example: curl https://api.teeseng.uk/api/v0/sensor/update
|
||||
<td>(Optional) Location of Sensor Example: curl
|
||||
https://api.teeseng.uk/api/v0/sensor/update
|
||||
-H "Authorization: provide
|
||||
your API key here" -d '{"location": "11"}'</td>
|
||||
</td>
|
||||
@ -679,10 +610,77 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="api-keys-header iot-card" id="content-get-api">
|
||||
<h2>API Keys</h2>
|
||||
<p>
|
||||
You can generate API Keys here:
|
||||
</p>
|
||||
<form action="token/new" onsubmit="formAJAX(this)" class="api-form">
|
||||
<div class="card-header shadow actionMessage" style="display:none;"></div>
|
||||
<input type="email" name="email" id="email" placeholder="Email address"
|
||||
pattern="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*">
|
||||
<div style="margin-top: 10px;"></div>
|
||||
<button class="generate-key-button">Generate Key</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overflow-hidden content-section" id="content-errors">
|
||||
<h2>Errors</h2>
|
||||
<p>
|
||||
The EcoSaver API uses the following error codes:
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Error Code</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>X000</td>
|
||||
<td>
|
||||
Some parameters are missing. This error appears when you don't pass every
|
||||
mandatory
|
||||
parameters.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>403</td>
|
||||
<td>
|
||||
Unknown or unvalid <code class="higlighted">secret_key</code>. This error
|
||||
appears if
|
||||
you use an unknow API key or if your API key expired.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>500</td>
|
||||
<td>
|
||||
Unvalid <code class="higlighted">secret_key</code> No API key was supplied.
|
||||
Invalid
|
||||
request.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X003</td>
|
||||
<td>
|
||||
Unknown or unvalid user <code class="higlighted">token</code>. This error
|
||||
appears if
|
||||
you use an unknow user <code class="higlighted">token</code> or if the user
|
||||
<code class="higlighted">token</code> expired.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<script src="js/api.js"></script>
|
||||
</html>
|
||||
|
||||
</html>
|
@ -42,7 +42,8 @@
|
||||
</p>
|
||||
<p>
|
||||
<abbr title="Email">E</abbr>:
|
||||
<a href="mailto:name@example.com">leongdingxuan@gmail.com
|
||||
<a href="mailto:name@example.com">ecosaverx@gmail.com
|
||||
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
@ -55,17 +56,18 @@
|
||||
<!-- Contact Form -->
|
||||
<!-- In order to set the email address and subject line for the contact form go to the bin/contact_me.php file. -->
|
||||
<div class="row">
|
||||
<div class="form contact iot-card">
|
||||
<div class="col-lg-8 mb-4 contact-left">
|
||||
<h3>Send us a Message</h3>
|
||||
<form id="form">
|
||||
<input type="hidden" name="access_key" value="">
|
||||
<form action="auth/contact" onsubmit="formAJAX(this)">
|
||||
<div class="card-header shadow actionMessage" style="display:none"></div>
|
||||
<div class="mb-3">
|
||||
<label for="name">Full Name</label>
|
||||
<input type="text" name="name" id="name" required>
|
||||
<input type="text" name="name" id="name" required pattern="^[a-zA-Z]{3,}( {1,2}[a-zA-Z]{3,}){0,}$">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email">Email address</label>
|
||||
<input type="email" name="email" id="email" required>
|
||||
<input type="email" name="email" id="email" required pattern="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="message">Message</label>
|
||||
@ -75,6 +77,8 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
@ -1,18 +1,59 @@
|
||||
<%- include('top') %>
|
||||
<script>
|
||||
<script type="text/javascript">
|
||||
function extractNumbers(str) {
|
||||
if (typeof str === 'number') return str;
|
||||
return str.match(/\d+/)[0];
|
||||
}
|
||||
|
||||
function calculateAverage(numbers) {
|
||||
if (numbers.length === 0) return 0
|
||||
const sum = numbers.reduce((acc, num) => acc + num, 0);
|
||||
return sum / numbers.length;
|
||||
}
|
||||
const values = {
|
||||
psi: [],
|
||||
humidity: [],
|
||||
temperature: [],
|
||||
windspeed: [],
|
||||
};
|
||||
|
||||
function parseRowToTemplace(row) {
|
||||
values.psi.unshift(extractNumbers(row.measurement.psi))
|
||||
values.humidity.unshift(extractNumbers(row.measurement.humidity))
|
||||
values.temperature.unshift(extractNumbers(row.measurement.temperature))
|
||||
values.windspeed.unshift(extractNumbers(row.measurement.windspeed))
|
||||
|
||||
return {
|
||||
average: {
|
||||
psi: parseInt(calculateAverage(values.psi)),
|
||||
humidity: parseInt(calculateAverage(values.humidity)),
|
||||
temperature: parseInt(calculateAverage(values.temperature)),
|
||||
windspeed: parseInt(calculateAverage(values.windspeed)),
|
||||
},
|
||||
latest: {
|
||||
psi: values.psi[0],
|
||||
humidity: values.humidity[0],
|
||||
temperature: values.temperature[0],
|
||||
windspeed: values.windspeed[0],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(async function () {
|
||||
|
||||
app.api.get('latest-sensor-data/data', function (error, data) {
|
||||
//console.log(data[0]);
|
||||
$.scope.LatestSensorData.push(data[0]);
|
||||
for (let row of data) {
|
||||
//console.log(row);
|
||||
$.scope.LatestSensorData.update(parseRowToTemplace(row));
|
||||
}
|
||||
});
|
||||
|
||||
//call socket.io to get live data
|
||||
app.socket.on("sensorData:new", function (data) {
|
||||
$.scope.LatestSensorData.update(parseRowToTemplace(data));
|
||||
});
|
||||
});
|
||||
//call socket.io to get live data
|
||||
app.socket.on("sensorData:new", function (data) {
|
||||
|
||||
console.log(data[0]);
|
||||
$.scope.LatestSensorData.update(data[0]);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@ -69,7 +110,8 @@
|
||||
<div class="card">
|
||||
<h4 class="card-header">Air Quality Index</h4>
|
||||
<div class="card-body text-center">
|
||||
<p class="card-text display-4">{{ measurement.psi }} PSI</p>
|
||||
<p class="card-text display-4"> Average: {{average.psi}} PSI</p>
|
||||
<p class="card-text display-4"> Latest: {{latest.psi}} PSI</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a href="/learnmore" class="btn btn-primary">Learn More</a>
|
||||
@ -80,7 +122,8 @@
|
||||
<div class="card">
|
||||
<h4 class="card-header">Humidity</h4>
|
||||
<div class="card-body text-center">
|
||||
<p class="card-text display-4">{{ measurement.humidity }} %</p>
|
||||
<p class="card-text display-4"> Average: {{average.humidity}} %</p>
|
||||
<p class="card-text display-4"> Latest: {{latest.humidity}} %</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a href="/learnmore" class="btn btn-primary">Learn More</a>
|
||||
@ -91,7 +134,8 @@
|
||||
<div class="card">
|
||||
<h4 class="card-header">Temperature</h4>
|
||||
<div class="card-body text-center">
|
||||
<p class="card-text display-4">{{ measurement.temperature }}°</p>
|
||||
<p class="card-text display-4"> Average: {{average.temperature}}°</p>
|
||||
<p class="card-text display-4"> Latest: {{latest.temperature}}°</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a href="/learnmore" class="btn btn-primary">Learn More</a>
|
||||
@ -102,7 +146,8 @@
|
||||
<div class="card">
|
||||
<h4 class="card-header">Wind Speed</h4>
|
||||
<div class="card-body text-center">
|
||||
<p class="card-text display-4">{{ measurement.windspeed }} Km/h </p>
|
||||
<p class="card-text display-4"> Average: {{average.windspeed}} Km/h</p>
|
||||
<p class="card-text display-4"> Latest: {{latest.windspeed}} Km/h</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a href="/learnmore" class="btn btn-primary">Learn More</a>
|
||||
|
@ -27,7 +27,7 @@
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.1/mustache.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.1/mustache.js"></script>
|
||||
<!-- socket.io scriot -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.2.0/socket.io.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.2.0/socket.io.min.js"></script>
|
||||
|
||||
<!-- jquery app.js -->
|
||||
<script src="js/app.js"></script>
|
||||
@ -44,19 +44,22 @@
|
||||
$(document).ready(function () {
|
||||
//check if user is logged in
|
||||
app.auth.isLoggedIn(function (error, data) {
|
||||
if (data) {
|
||||
$('#cl-logout-button').show('fast');
|
||||
$('#cl-profile-button').show('fast');
|
||||
$('#cl-login-button').hide('fast');
|
||||
if (!error) {
|
||||
$("#cl-logout-button").show("fast");
|
||||
$("#cl-api-button").show("fast");
|
||||
$("#cl-profile-button").show("fast");
|
||||
$("#cl-login-button").hide("fast");
|
||||
|
||||
} else {
|
||||
$('#cl-login-button').show('fast');
|
||||
|
||||
}
|
||||
$('body').show('fast')
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</script>
|
||||
|
||||
|
||||
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-light top-nav fixed-top">
|
||||
@ -79,11 +82,12 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/contact">Contact</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/api">API Doc</a>
|
||||
</li>
|
||||
<!-- profile button -->
|
||||
<div class="form-inline mt-2 mt-md-0">
|
||||
<a id="cl-api-button" class="btn btn-outline-info btn-sm my-2 my-sm-0" href="/api"
|
||||
style="display: none">
|
||||
<i class="fas fa-sign-out"></i> API
|
||||
</a>
|
||||
<a id="cl-profile-button" class="btn btn-outline-info my-2 my-sm-0" href="/profile"
|
||||
style="display: none;">
|
||||
<i class="fas fa-sign-out"></i>
|
||||
@ -103,5 +107,4 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
</nav>
|
@ -1,4 +1,8 @@
|
||||
<%- include('top') %>
|
||||
<script type="text/javascript">
|
||||
// Require login to see this page.
|
||||
app.auth.forceLogin()
|
||||
</script>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
@ -6,9 +10,9 @@
|
||||
<div class="profile">
|
||||
<!-- <li jq-repeat="getUsername" class="nav-item"> -->
|
||||
<div class="edit_information" jq-repeat="getUserDetails">
|
||||
<div class="card-header shadow actionMessage" style="display:none"></div>
|
||||
<form id="profileForm" action="user/update" method="put" onsubmit="formAJAX(this)"
|
||||
evalAJAX="app.auth.profileRedirect();">
|
||||
<div class="card-header shadow actionMessage" style="display:none"></div>
|
||||
<h3 class="text-center">Edit Personal Information</h3>
|
||||
<br>
|
||||
<div class="row">
|
||||
|
Reference in New Issue
Block a user