Compare commits
No commits in common. "d289f28e936929aefe49ac34c1764bb8dc1bdbf8" and "837f10037dd67c7ed568728781609c606139da0a" have entirely different histories.
d289f28e93
...
837f10037d
backend
deploy.shfrontend
favicon.ico
fonts
img
index.htmllogin
mockdata
pages
home
login
profile
register
profile
scripts
services
shared
styles
iot
@ -1,74 +0,0 @@
|
|||||||
using Api.DBAccess;
|
|
||||||
using Api.Models;
|
|
||||||
using RabbitMQ.Client;
|
|
||||||
using RabbitMQ.Client.Events;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
namespace Api.AMQPReciever
|
|
||||||
{
|
|
||||||
public class AMQPReciever
|
|
||||||
{
|
|
||||||
private readonly IConfiguration _configuration;
|
|
||||||
private readonly DbAccess _dbAccess;
|
|
||||||
|
|
||||||
public AMQPReciever(IConfiguration configuration, DbAccess dbAccess)
|
|
||||||
{
|
|
||||||
_dbAccess = dbAccess;
|
|
||||||
_configuration = configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Handle_Received_Application_Message()
|
|
||||||
{
|
|
||||||
var factory = new ConnectionFactory();
|
|
||||||
var queue = "temperature-logs";
|
|
||||||
|
|
||||||
factory.UserName = _configuration["AMQP:username"];
|
|
||||||
factory.Password = _configuration["AMQP:password"];
|
|
||||||
factory.HostName = _configuration["AMQP:host"];
|
|
||||||
factory.Port = Convert.ToInt32(_configuration["AMQP:port"]);
|
|
||||||
|
|
||||||
using var conn = await factory.CreateConnectionAsync();
|
|
||||||
Console.WriteLine("AMQPClien connected");
|
|
||||||
using var channel = await conn.CreateChannelAsync();
|
|
||||||
|
|
||||||
await channel.QueueDeclareAsync(queue: queue, durable: false, exclusive: false, autoDelete: false);
|
|
||||||
Console.WriteLine($"{queue} connected");
|
|
||||||
|
|
||||||
var consumer = new AsyncEventingBasicConsumer(channel);
|
|
||||||
consumer.ReceivedAsync += (model, ea) =>
|
|
||||||
{
|
|
||||||
Console.WriteLine("Received application message.");
|
|
||||||
var body = ea.Body.ToArray();
|
|
||||||
var message = Encoding.UTF8.GetString(body);
|
|
||||||
|
|
||||||
var messageReceive = JsonSerializer.Deserialize<MQTTMessageReceive>(message);
|
|
||||||
|
|
||||||
if (messageReceive == null || messageReceive.temperature == 0 || messageReceive.device_id == null || messageReceive.timestamp == 0)
|
|
||||||
{
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
TemperatureLogs newLog = new TemperatureLogs();
|
|
||||||
string refernceId = messageReceive.device_id;
|
|
||||||
var device = _dbAccess.ReadDevice(refernceId);
|
|
||||||
|
|
||||||
if (device == null) { return Task.CompletedTask; }
|
|
||||||
|
|
||||||
newLog.Temperature = messageReceive.temperature;
|
|
||||||
newLog.Date = DateTimeOffset.FromUnixTimeSeconds(messageReceive.timestamp).DateTime;
|
|
||||||
newLog.TempHigh = device.TempHigh;
|
|
||||||
newLog.TempLow = device.TempLow;
|
|
||||||
|
|
||||||
_dbAccess.CreateLog(newLog, refernceId);
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
};
|
|
||||||
|
|
||||||
await channel.BasicConsumeAsync(queue, true, consumer);
|
|
||||||
|
|
||||||
Console.WriteLine("Press enter to exit.");
|
|
||||||
Console.ReadLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,7 +23,6 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
|
||||||
<PackageReference Include="MQTTnet" Version="5.0.1.1416" />
|
<PackageReference Include="MQTTnet" Version="5.0.1.1416" />
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="7.1.2" />
|
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -5,8 +5,6 @@ VisualStudioVersion = 17.9.34607.119
|
|||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Api", "Api.csproj", "{9CCF78E1-969C-420F-BE31-F8AFCE0C6827}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Api", "Api.csproj", "{9CCF78E1-969C-420F-BE31-F8AFCE0C6827}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "..\test\test.csproj", "{5ACD3275-AE0C-458C-AACD-12FE1E165621}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -17,10 +15,6 @@ Global
|
|||||||
{9CCF78E1-969C-420F-BE31-F8AFCE0C6827}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{9CCF78E1-969C-420F-BE31-F8AFCE0C6827}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{9CCF78E1-969C-420F-BE31-F8AFCE0C6827}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{9CCF78E1-969C-420F-BE31-F8AFCE0C6827}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{9CCF78E1-969C-420F-BE31-F8AFCE0C6827}.Release|Any CPU.Build.0 = Release|Any CPU
|
{9CCF78E1-969C-420F-BE31-F8AFCE0C6827}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{5ACD3275-AE0C-458C-AACD-12FE1E165621}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{5ACD3275-AE0C-458C-AACD-12FE1E165621}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{5ACD3275-AE0C-458C-AACD-12FE1E165621}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{5ACD3275-AE0C-458C-AACD-12FE1E165621}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -28,21 +28,21 @@ namespace Api.Controllers
|
|||||||
return await _deviceLogic.GetDevices(userId);
|
return await _deviceLogic.GetDevices(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize]
|
//[Authorize]
|
||||||
[HttpPost("adddevice/{userId}")]
|
[HttpPost("adddevice/{userId}")]
|
||||||
public async Task<IActionResult> AddDevice([FromBody] Device device, int userId)
|
public async Task<IActionResult> AddDevice([FromBody] Device device, int userId)
|
||||||
{
|
{
|
||||||
return await _deviceLogic.AddDevice(device, userId);
|
return await _deviceLogic.AddDevice(device, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize]
|
//[Authorize]
|
||||||
[HttpGet("logs/{deviceId}")]
|
[HttpGet("logs/{deviceId}")]
|
||||||
public async Task<IActionResult> GetLogs(int deviceId)
|
public async Task<IActionResult> GetLogs(int deviceId)
|
||||||
{
|
{
|
||||||
return await _deviceLogic.GetLogs(deviceId);
|
return await _deviceLogic.GetLogs(deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize]
|
//[Authorize]
|
||||||
[HttpPut("Edit/{deviceId}")]
|
[HttpPut("Edit/{deviceId}")]
|
||||||
public async Task<IActionResult> EditDevice([FromBody] Device device, int deviceId)
|
public async Task<IActionResult> EditDevice([FromBody] Device device, int deviceId)
|
||||||
{
|
{
|
||||||
|
@ -33,14 +33,14 @@ namespace Api.Controllers
|
|||||||
return await _userLogic.RegisterUser(user);
|
return await _userLogic.RegisterUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize]
|
//[Authorize]
|
||||||
[HttpPut("Edit/{userId}")]
|
[HttpPut("Edit/{userId}")]
|
||||||
public async Task<IActionResult> EditUser([FromBody] User user, int userId)
|
public async Task<IActionResult> EditUser([FromBody] User user, int userId)
|
||||||
{
|
{
|
||||||
return await _userLogic.EditProfile(user, userId);
|
return await _userLogic.EditProfile(user, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize]
|
//[Authorize]
|
||||||
[HttpDelete("Delete/{userId}")]
|
[HttpDelete("Delete/{userId}")]
|
||||||
public async Task<IActionResult> DeleteUser(int userId)
|
public async Task<IActionResult> DeleteUser(int userId)
|
||||||
{
|
{
|
||||||
|
@ -36,11 +36,8 @@ namespace Api.DBAccess
|
|||||||
}
|
}
|
||||||
|
|
||||||
_context.Users.Add(user);
|
_context.Users.Add(user);
|
||||||
bool saved = await _context.SaveChangesAsync() == 1;
|
|
||||||
|
return new OkObjectResult(await _context.SaveChangesAsync());
|
||||||
if (saved) { return new OkObjectResult(true); }
|
|
||||||
|
|
||||||
return new ConflictObjectResult(new { message = "Could not save to databse" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<User> Login(Login login)
|
public async Task<User> Login(Login login)
|
||||||
@ -111,7 +108,7 @@ namespace Api.DBAccess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_context.Users.Remove(user);
|
_context.Users.Remove(user);
|
||||||
bool saved = await _context.SaveChangesAsync() >= 0;
|
bool saved = await _context.SaveChangesAsync() == 1;
|
||||||
|
|
||||||
if (saved) { return new OkObjectResult(saved); }
|
if (saved) { return new OkObjectResult(saved); }
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ namespace Api.MQTTReciever
|
|||||||
using (mqttClient = mqttFactory.CreateMqttClient())
|
using (mqttClient = mqttFactory.CreateMqttClient())
|
||||||
{
|
{
|
||||||
var mqttClientOptions = new MqttClientOptionsBuilder()
|
var mqttClientOptions = new MqttClientOptionsBuilder()
|
||||||
.WithTcpServer($"{_configuration["MQTT:host"]}", Convert.ToInt32(_configuration["MQTT:port"]))
|
.WithTcpServer($"{_configuration["MQTT:host"]}", 1883)
|
||||||
.WithCredentials($"{_configuration["MQTT:username"]}", $"{_configuration["MQTT:password"]}")
|
.WithCredentials($"{_configuration["MQTT:username"]}", $"{_configuration["MQTT:password"]}")
|
||||||
.WithCleanSession()
|
.WithCleanSession()
|
||||||
.Build();
|
.Build();
|
||||||
@ -43,7 +43,7 @@ namespace Api.MQTTReciever
|
|||||||
|
|
||||||
var mqttMessageReceive = JsonSerializer.Deserialize<MQTTMessageReceive>(sensorData);
|
var mqttMessageReceive = JsonSerializer.Deserialize<MQTTMessageReceive>(sensorData);
|
||||||
|
|
||||||
if (mqttMessageReceive == null || mqttMessageReceive.temperature == 0 || mqttMessageReceive.device_id == null || mqttMessageReceive.timestamp == 0)
|
if (mqttMessageReceive == null || mqttMessageReceive.temperature == 0 || mqttMessageReceive.device_id == null || mqttMessageReceive.timestamp == null)
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,15 @@
|
|||||||
using Api;
|
using Api;
|
||||||
using Api.AMQPReciever;
|
|
||||||
using Api.DBAccess;
|
using Api.DBAccess;
|
||||||
using Api.MQTTReciever;
|
using Api.MQTTReciever;
|
||||||
using Microsoft.AspNetCore;
|
using Microsoft.AspNetCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
var app = CreateWebHostBuilder(args).Build();
|
var app = CreateWebHostBuilder(args).Build();
|
||||||
|
|
||||||
|
|
||||||
RunMigrations(app);
|
RunMigrations(app);
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
@ -24,9 +20,6 @@ class Program
|
|||||||
var configuration = services.GetRequiredService<IConfiguration>();
|
var configuration = services.GetRequiredService<IConfiguration>();
|
||||||
var dbAccess = services.GetRequiredService<DbAccess>();
|
var dbAccess = services.GetRequiredService<DbAccess>();
|
||||||
|
|
||||||
//AMQPReciever amqp = new AMQPReciever(configuration, dbAccess);
|
|
||||||
//amqp.Handle_Received_Application_Message().Wait();
|
|
||||||
|
|
||||||
MQTTReciever mqtt = new MQTTReciever(configuration, dbAccess);
|
MQTTReciever mqtt = new MQTTReciever(configuration, dbAccess);
|
||||||
mqtt.Handle_Received_Application_Message().Wait();
|
mqtt.Handle_Received_Application_Message().Wait();
|
||||||
}
|
}
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="7.1.2" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
|
||||||
VisualStudioVersion = 17.9.34607.119
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp1", "ConsoleApp1.csproj", "{0BC93CF2-F92D-4DD6-83BE-A985CBB74960}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{0BC93CF2-F92D-4DD6-83BE-A985CBB74960}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{0BC93CF2-F92D-4DD6-83BE-A985CBB74960}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{0BC93CF2-F92D-4DD6-83BE-A985CBB74960}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{0BC93CF2-F92D-4DD6-83BE-A985CBB74960}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {55EE0E94-4585-4E79-AC67-4B0E809E99AB}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
@ -1,52 +0,0 @@
|
|||||||
using RabbitMQ.Client;
|
|
||||||
using RabbitMQ.Client.Events;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
|
|
||||||
var factory = new ConnectionFactory();
|
|
||||||
var queue = "test";
|
|
||||||
|
|
||||||
|
|
||||||
factory.UserName = "h5";
|
|
||||||
factory.Password = "Merc1234";
|
|
||||||
factory.HostName = "10.135.51.116";
|
|
||||||
factory.Port = 5672;
|
|
||||||
|
|
||||||
using var conn = await factory.CreateConnectionAsync();
|
|
||||||
Console.WriteLine("AMQPClien connected");
|
|
||||||
using var channel = await conn.CreateChannelAsync();
|
|
||||||
|
|
||||||
await channel.QueueDeclareAsync(queue: queue, durable: false, exclusive: false, autoDelete: false);
|
|
||||||
Console.WriteLine($"{queue} connected");
|
|
||||||
|
|
||||||
var consumer = new AsyncEventingBasicConsumer(channel);
|
|
||||||
consumer.ReceivedAsync += (model, ea) =>
|
|
||||||
{
|
|
||||||
Console.WriteLine("Received application message.");
|
|
||||||
var body = ea.Body.ToArray();
|
|
||||||
var message = Encoding.UTF8.GetString(body);
|
|
||||||
Console.WriteLine(message);
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
};
|
|
||||||
|
|
||||||
await channel.BasicConsumeAsync(queue, true, consumer);
|
|
||||||
|
|
||||||
|
|
||||||
const string message = "Hello World!";
|
|
||||||
var body = Encoding.UTF8.GetBytes(message);
|
|
||||||
await channel.BasicPublishAsync(exchange: string.Empty, routingKey: queue, body: body);
|
|
||||||
Console.WriteLine(" Press enter to continue.");
|
|
||||||
Console.ReadLine();
|
|
||||||
await channel.BasicPublishAsync(exchange: string.Empty, routingKey: queue, body: body);
|
|
||||||
Console.WriteLine(" Press enter to continue.");
|
|
||||||
Console.ReadLine();
|
|
||||||
await channel.BasicPublishAsync(exchange: string.Empty, routingKey: queue, body: body);
|
|
||||||
Console.WriteLine(" Press enter to continue.");
|
|
||||||
Console.ReadLine();
|
|
||||||
await channel.BasicPublishAsync(exchange: string.Empty, routingKey: queue, body: body);
|
|
||||||
Console.WriteLine(" Press enter to continue.");
|
|
||||||
Console.ReadLine();
|
|
||||||
await channel.BasicPublishAsync(exchange: string.Empty, routingKey: queue, body: body);
|
|
||||||
Console.WriteLine(" Press enter to exit.");
|
|
||||||
Console.ReadLine();
|
|
@ -1,36 +0,0 @@
|
|||||||
using MQTTnet;
|
|
||||||
|
|
||||||
var mqttFactory = new MqttClientFactory();
|
|
||||||
IMqttClient mqttClient;
|
|
||||||
|
|
||||||
using (mqttClient = mqttFactory.CreateMqttClient())
|
|
||||||
{
|
|
||||||
var mqttClientOptions = new MqttClientOptionsBuilder()
|
|
||||||
.WithTcpServer($"10.135.51.116", 1883)
|
|
||||||
.WithCredentials($"h5", $"Merc1234")
|
|
||||||
.WithCleanSession()
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
// Setup message handling before connecting so that queued messages
|
|
||||||
// are also handled properly. When there is no event handler attached all
|
|
||||||
// received messages get lost.
|
|
||||||
mqttClient.ApplicationMessageReceivedAsync += e =>
|
|
||||||
{
|
|
||||||
Console.WriteLine("Received application message.");
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);
|
|
||||||
Console.WriteLine("mqttClient");
|
|
||||||
|
|
||||||
//var mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder().WithTopicTemplate(topic).Build();
|
|
||||||
|
|
||||||
await mqttClient.SubscribeAsync("temperature");
|
|
||||||
|
|
||||||
Console.WriteLine("MQTT client subscribed to topic.");
|
|
||||||
|
|
||||||
Console.WriteLine("Press enter to exit.");
|
|
||||||
Console.ReadLine();
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="MQTTnet" Version="5.0.1.1416" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/usr/bin
|
||||||
|
|
||||||
BASEPATH=/home/developers/temperature-alarm
|
BASEPATH=/home/developers/temperature-alarm
|
||||||
|
|
||||||
@ -12,9 +12,6 @@ chown www-data:www-data -R /var/www/html
|
|||||||
|
|
||||||
# Update backend
|
# Update backend
|
||||||
docker stop api
|
docker stop api
|
||||||
docker rm api
|
|
||||||
docker image rm api:latest
|
|
||||||
|
|
||||||
docker build --tag api $BASEPATH/backend/Api
|
docker build --tag api $BASEPATH/backend/Api
|
||||||
docker run -d -p 5000:5000 --volume /home/developers/volume:/app/db --name api --rm api
|
docker run -d -p 8080:80 -p 8081:443 -p 5000:5000 --name api --rm api
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: 128px | Height: 128px | Size: 66 KiB |
Binary file not shown.
Binary file not shown.
Before ![]() (image error) Size: 266 KiB |
Binary file not shown.
Before ![]() (image error) Size: 27 KiB |
Binary file not shown.
Before ![]() (image error) Size: 9.5 KiB |
@ -1,28 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<title>Temperature Alarm</title>
|
|
||||||
<link rel="stylesheet" href="/styles/frontpage.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<main>
|
|
||||||
<div id="title">
|
|
||||||
<h1>
|
|
||||||
<img id="logo" src="/img/logo.webp" alt="Logo">
|
|
||||||
Temperature Alarm
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div id="buttons-wrapper">
|
|
||||||
<a href="/login">
|
|
||||||
<button class="secondary">Login</button>
|
|
||||||
</a>
|
|
||||||
<a href="/register">
|
|
||||||
<button class="primary">Sign up</button>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<title>Login - Temperature alarm</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link rel="stylesheet" href="/styles/auth.css">
|
|
||||||
<script defer type="module" src="/scripts/login.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<form id="loginForm">
|
|
||||||
<div class="form-container">
|
|
||||||
<h1>Login</h1>
|
|
||||||
|
|
||||||
<label for="emailorusn"><b>Email or Username</b></label>
|
|
||||||
<input type="text" placeholder="Enter email or username" id="emailorusn" required>
|
|
||||||
|
|
||||||
<label for="psw"><b>Password</b></label>
|
|
||||||
<input type="password" placeholder="Enter password" id="psw" required>
|
|
||||||
|
|
||||||
<button type="submit">Login</button>
|
|
||||||
<div class="details">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" name="remember"> Remember me
|
|
||||||
</label>
|
|
||||||
<span>
|
|
||||||
Dont have an account? <a href="/register">Register</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="form-error"></div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
|||||||
export const profileData = {
|
|
||||||
id: 1,
|
|
||||||
username: "LilleBRG",
|
|
||||||
email: "lillebrg@gmail.com",
|
|
||||||
pfp: "/img/user-32.png"
|
|
||||||
}
|
|
@ -74,6 +74,40 @@ tr:nth-child(even) {
|
|||||||
width: 20px;
|
width: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chartContainer{
|
/* The Modal (background) */
|
||||||
margin: 20px;
|
.modal {
|
||||||
|
display: none; /* Hidden by default */
|
||||||
|
position: fixed; /* Stay in place */
|
||||||
|
z-index: 1; /* Sit on top */
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%; /* Full width */
|
||||||
|
height: 100%; /* Full height */
|
||||||
|
background-color: rgb(0, 0, 0); /* Fallback color */
|
||||||
|
background-color: rgba(0, 0, 0, 0.6); /* Black w/ opacity */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modal Content/Box */
|
||||||
|
.modal-content {
|
||||||
|
border-radius: 20px;
|
||||||
|
background-color: #fefefe;
|
||||||
|
margin: 15% auto; /* 15% from the top and centered */
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #888;
|
||||||
|
width: 80%; /* Could be more or less, depending on screen size */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The Close Button */
|
||||||
|
.close {
|
||||||
|
color: #aaa;
|
||||||
|
float: right;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close:hover,
|
||||||
|
.close:focus {
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
@ -5,22 +5,22 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Temperature-Alarm-Web</title>
|
<title>Temperature-Alarm-Web</title>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
|
||||||
<link rel="stylesheet" href="/styles/home.css" />
|
|
||||||
<script type="module" src="/scripts/home.js"></script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<div class="topnav">
|
<div class="topnav">
|
||||||
<a class="active" href="/home/index.html">Home</a>
|
<a class="active" href="#home">Home</a>
|
||||||
<div style="display: flex; justify-content: flex-end;">
|
<a href="#news" id="myBtn">View Chart</a>
|
||||||
<a class="" href="/home/index.html">Devices</a>
|
</div>
|
||||||
<a class="" href="/profile/index.html">Profile</a>
|
|
||||||
|
<div id="chartModal" class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<span class="close">×</span>
|
||||||
|
<canvas id="myChart" style="width: 80%; width: 80%"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="chartContainer">
|
|
||||||
<canvas id="myChart" style="width: 49%; height: 49%;"></canvas>
|
|
||||||
</div>
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
@ -33,4 +33,6 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
<link rel="stylesheet" href="home.css" />
|
||||||
|
<script type="module" src="home.js"></script>
|
||||||
</html>
|
</html>
|
@ -1,4 +1,4 @@
|
|||||||
import { mockTemperatureLogs } from "../mockdata/temperature-logs.mockdata.js"; // Import data
|
import { mockTemperatureLogs } from "../../mockdata/temperature-logs.mockdata.js"; // Import data
|
||||||
|
|
||||||
const xValues = mockTemperatureLogs.map((log) =>
|
const xValues = mockTemperatureLogs.map((log) =>
|
||||||
new Date(log.date).toLocaleString()
|
new Date(log.date).toLocaleString()
|
41
frontend/pages/login/login.css
Normal file
41
frontend/pages/login/login.css
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
body {font-family: Arial, Helvetica, sans-serif;}
|
||||||
|
|
||||||
|
.container{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Full-width input fields */
|
||||||
|
input[type=text], input[type=password], input[type=email] {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 20px;
|
||||||
|
margin: 8px 0;
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set a style for all buttons */
|
||||||
|
button {
|
||||||
|
background-color: #04AA6D;
|
||||||
|
color: white;
|
||||||
|
padding: 14px 20px;
|
||||||
|
margin: 8px 0;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
width: 800px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.registerText{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
36
frontend/pages/login/login.html
Normal file
36
frontend/pages/login/login.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<form id="loginForm">
|
||||||
|
<div class="form-container">
|
||||||
|
<h1>Login</h1>
|
||||||
|
|
||||||
|
<label for="emailorusn"><b>Email or Username</b></label>
|
||||||
|
<input type="text" placeholder="Enter email or username" id="emailorusn" required>
|
||||||
|
|
||||||
|
<label for="psw"><b>Password</b></label>
|
||||||
|
<input type="password" placeholder="Enter password" id="psw" required>
|
||||||
|
|
||||||
|
<button type="submit">Login</button>
|
||||||
|
<div class="registerText">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="remember"> Remember me
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Dont have an account? <a href="../register/register.html">Register</a>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<link rel="stylesheet" href="login.css">
|
||||||
|
<script type="module" src="login.js"></script>
|
||||||
|
|
||||||
|
</html>
|
13
frontend/pages/login/login.js
Normal file
13
frontend/pages/login/login.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { login } from "../../services/users.service.js";
|
||||||
|
|
||||||
|
document.getElementById("loginForm").addEventListener("submit", function(event) {
|
||||||
|
event.preventDefault(); // Prevents default form submission
|
||||||
|
|
||||||
|
// Get form values
|
||||||
|
const emailOrUsername = document.getElementById("emailorusn").value;
|
||||||
|
const password = document.getElementById("psw").value;
|
||||||
|
|
||||||
|
|
||||||
|
// Call function with form values
|
||||||
|
login(emailOrUsername, password);
|
||||||
|
});
|
0
frontend/pages/profile/profile.html
Normal file
0
frontend/pages/profile/profile.html
Normal file
0
frontend/pages/profile/profile.js
Normal file
0
frontend/pages/profile/profile.js
Normal file
41
frontend/pages/register/register.css
Normal file
41
frontend/pages/register/register.css
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
body {font-family: Arial, Helvetica, sans-serif;}
|
||||||
|
|
||||||
|
.container{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Full-width input fields */
|
||||||
|
input[type=text], input[type=password], input[type=email] {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 20px;
|
||||||
|
margin: 8px 0;
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set a style for all buttons */
|
||||||
|
button {
|
||||||
|
background-color: #04AA6D;
|
||||||
|
color: white;
|
||||||
|
padding: 14px 20px;
|
||||||
|
margin: 8px 0;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
width: 800px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loginText{
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
@ -1,13 +1,11 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html>
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
<head>
|
||||||
<title>Register - Temperature Alarm</title>
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
</head>
|
||||||
<link rel="stylesheet" href="/styles/auth.css">
|
<body>
|
||||||
<script defer type="module" src="/scripts/register.js"></script>
|
<div class="container">
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<form id="registerForm">
|
<form id="registerForm">
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<h1>Create Account</h1>
|
<h1>Create Account</h1>
|
||||||
@ -25,17 +23,17 @@
|
|||||||
<input type="password" placeholder="Enter password again" id="rpsw" required>
|
<input type="password" placeholder="Enter password again" id="rpsw" required>
|
||||||
|
|
||||||
<button type="submit">Register</button>
|
<button type="submit">Register</button>
|
||||||
<div class="details">
|
<div class="loginText">
|
||||||
<div></div>
|
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
Already have an account? <a href="/login">Login</a>
|
Already have an account? <a href="../login/login.html">Login</a>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="form-error"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</div>
|
||||||
</html>
|
</body>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="register.css">
|
||||||
|
<script type="module" src="register.js"></script>
|
||||||
|
|
||||||
|
</html>
|
14
frontend/pages/register/register.js
Normal file
14
frontend/pages/register/register.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { create } from "../../services/users.service.js";
|
||||||
|
|
||||||
|
document.getElementById("registerForm").addEventListener("submit", function(event) {
|
||||||
|
event.preventDefault(); // Prevents default form submission
|
||||||
|
|
||||||
|
// Get form values
|
||||||
|
const email = document.getElementById("email").value;
|
||||||
|
const username = document.getElementById("uname").value;
|
||||||
|
const password = document.getElementById("psw").value;
|
||||||
|
const repeatPassword = document.getElementById("rpsw").value;
|
||||||
|
|
||||||
|
// Call function with form values
|
||||||
|
create(email, username, password, repeatPassword);
|
||||||
|
});
|
@ -1,65 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<title>Register - Temperature Alarm</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link rel="stylesheet" href="/styles/auth.css">
|
|
||||||
<link rel="stylesheet" href="/styles/profile.css">
|
|
||||||
<script defer type="module" src="/scripts/profile.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="container">
|
|
||||||
<div id="profileCard"></div>
|
|
||||||
<div class="btnContainer">
|
|
||||||
<button class="btn" id="openEditModal">Edit</button>
|
|
||||||
<button class="btn" id="openPasswordModal">Change Password</button>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="editModal" class="modal">
|
|
||||||
<div class="modal-content">
|
|
||||||
<span class="close">×</span>
|
|
||||||
<h2>Edit Username or Email</h2>
|
|
||||||
<form id="editForm">
|
|
||||||
<div class="form-container">
|
|
||||||
<label for="email"><b>Email</b></label>
|
|
||||||
<input type="email" placeholder="Enter email "id="email" required>
|
|
||||||
|
|
||||||
<label for="uname"><b>Username</b></label>
|
|
||||||
<input type="text" placeholder="Enter username" id="uname" required>
|
|
||||||
|
|
||||||
<button type="submit">Save Changes</button>
|
|
||||||
|
|
||||||
<div class="error-text" id="form-error-edit"></div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="PasswordModal" class="modal">
|
|
||||||
<div class="modal-content">
|
|
||||||
<span class="close">×</span>
|
|
||||||
<h2>Change Password</h2>
|
|
||||||
<form id="PasswordForm">
|
|
||||||
<div class="form-container">
|
|
||||||
<label for="psw"><b>Old Password</b></label>
|
|
||||||
<input type="password" placeholder="Enter your current password" id="oldpsw" required>
|
|
||||||
|
|
||||||
<label for="psw"><b>New Password</b></label>
|
|
||||||
<input type="password" placeholder="Enter the new password" id="psw" required>
|
|
||||||
|
|
||||||
<label for="rpsw"><b>Repeat New Password</b></label>
|
|
||||||
<input type="password" placeholder="Enter the new password again" id="rpsw" required>
|
|
||||||
|
|
||||||
<button type="submit">Change Password</button>
|
|
||||||
|
|
||||||
<div class="error-text" id="form-error-password"></div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
import { login } from "./services/users.service.js";
|
|
||||||
|
|
||||||
document.getElementById("loginForm").addEventListener("submit", function(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
document.getElementById("form-error").style.display = "none";
|
|
||||||
|
|
||||||
const emailOrUsername = document.getElementById("emailorusn").value;
|
|
||||||
const password = document.getElementById("psw").value;
|
|
||||||
|
|
||||||
login(emailOrUsername, password)
|
|
||||||
.then(response => {
|
|
||||||
if (response.error) {
|
|
||||||
document.getElementById("form-error").innerText = response.error;
|
|
||||||
document.getElementById("form-error").style.display = "block";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
location.href = "/home";
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,91 +0,0 @@
|
|||||||
import { profileData } from "../mockdata/profile.mockdata.js";
|
|
||||||
|
|
||||||
var table = document.getElementById(`profileCard`);
|
|
||||||
table.innerHTML += `
|
|
||||||
<div class="pfp">
|
|
||||||
<img style="width:200px; height:200px" src="${profileData.pfp}">
|
|
||||||
</div>
|
|
||||||
<div class="userData">
|
|
||||||
<h2>${profileData.username}</h2>
|
|
||||||
<h2>${profileData.email}</h2>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
var pswModal = document.getElementById("PasswordModal");
|
|
||||||
var editModal = document.getElementById("editModal");
|
|
||||||
var editBtn = document.getElementById("openEditModal");
|
|
||||||
var passwordBtn = document.getElementById("openPasswordModal");
|
|
||||||
|
|
||||||
// Open modals
|
|
||||||
editBtn.onclick = () => (editModal.style.display = "block");
|
|
||||||
passwordBtn.onclick = () => (pswModal.style.display = "block");
|
|
||||||
|
|
||||||
// Close modals when clicking on any close button
|
|
||||||
document.querySelectorAll(".close").forEach(closeBtn => {
|
|
||||||
closeBtn.onclick = () => {
|
|
||||||
pswModal.style.display = "none";
|
|
||||||
editModal.style.display = "none";
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Close modals when clicking outside
|
|
||||||
window.onclick = (event) => {
|
|
||||||
if (event.target == pswModal || event.target == editModal) {
|
|
||||||
pswModal.style.display = "none";
|
|
||||||
editModal.style.display = "none";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
document.getElementById("editForm").addEventListener("submit", function(event) {
|
|
||||||
event.preventDefault(); // Prevents default form submission
|
|
||||||
|
|
||||||
document.getElementById("form-error-edit").style.display = "none";
|
|
||||||
|
|
||||||
// Get form values
|
|
||||||
const email = document.getElementById("email").value;
|
|
||||||
const username = document.getElementById("uname").value;
|
|
||||||
|
|
||||||
// Call function with form values
|
|
||||||
update(email, username)
|
|
||||||
.then(response => {
|
|
||||||
if (response?.error) {
|
|
||||||
document.getElementById("form-error").innerText = response.error;
|
|
||||||
document.getElementById("form-error").style.display = "block";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
location.href = "/login";
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById("PasswordForm").addEventListener("submit", function(event) {
|
|
||||||
event.preventDefault(); // Prevents default form submission
|
|
||||||
|
|
||||||
document.getElementById("form-error-password").style.display = "none";
|
|
||||||
|
|
||||||
// Get form values
|
|
||||||
const oldPassword = document.getElementById("oldpsw").value;
|
|
||||||
const newPassword = document.getElementById("psw").value;
|
|
||||||
const repeatPassword = document.getElementById("rpsw").value;
|
|
||||||
|
|
||||||
if (newPassword !== repeatPassword) {
|
|
||||||
let errorDiv = document.getElementById("form-error-password");
|
|
||||||
errorDiv.style.display = "block";
|
|
||||||
errorDiv.innerText = "Passwords do not match!";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call function with form values
|
|
||||||
update(email, username)
|
|
||||||
.then(response => {
|
|
||||||
if (response?.error) {
|
|
||||||
document.getElementById("form-error").innerText = response.error;
|
|
||||||
document.getElementById("form-error").style.display = "block";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
location.href = "/login";
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,26 +0,0 @@
|
|||||||
import { create } from "./services/users.service.js";
|
|
||||||
|
|
||||||
document.getElementById("registerForm").addEventListener("submit", function(event) {
|
|
||||||
event.preventDefault(); // Prevents default form submission
|
|
||||||
|
|
||||||
document.getElementById("form-error").style.display = "none";
|
|
||||||
|
|
||||||
// Get form values
|
|
||||||
const email = document.getElementById("email").value;
|
|
||||||
const username = document.getElementById("uname").value;
|
|
||||||
const password = document.getElementById("psw").value;
|
|
||||||
const repeatPassword = document.getElementById("rpsw").value;
|
|
||||||
|
|
||||||
// Call function with form values
|
|
||||||
create(email, username, password, repeatPassword)
|
|
||||||
.then(response => {
|
|
||||||
if (response?.error) {
|
|
||||||
document.getElementById("form-error").innerText = response.error;
|
|
||||||
document.getElementById("form-error").style.display = "block";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
location.href = "/login";
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,54 +0,0 @@
|
|||||||
import { address } from "../../shared/constants.js";
|
|
||||||
import { handleResponse } from "../../shared/utils.js";
|
|
||||||
|
|
||||||
export function login(usernameOrEmail, password) {
|
|
||||||
return fetch(`${address}/user/login`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
EmailOrUsrn: usernameOrEmail,
|
|
||||||
Password: password,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.then(handleResponse)
|
|
||||||
.catch(err => { error: err.message });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function create(email, username, password, repeatPassword){
|
|
||||||
return fetch(`${address}/user/create`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
body: JSON.stringify({email: email, username: username, password: password, repeatPassword: repeatPassword})
|
|
||||||
})
|
|
||||||
.then(handleResponse)
|
|
||||||
.catch(err => { error: err.message });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function update(email, username){
|
|
||||||
return fetch(`${address}/user/update`, {
|
|
||||||
method: "PATCH",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
body: JSON.stringify({email: email, username: username})
|
|
||||||
})
|
|
||||||
.then(handleResponse)
|
|
||||||
.catch(err => { error: err.message });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updatePassword(oldPassword, newPassword){
|
|
||||||
return fetch(`${address}/user/update-password`, {
|
|
||||||
method: "PATCH",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
body: JSON.stringify({oldPassword: oldPassword, newPassword: newPassword})
|
|
||||||
})
|
|
||||||
.then(handleResponse)
|
|
||||||
.catch(err => { error: err.message });
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
import { address } from "../../shared/constants";
|
const address = "http://10.135.51.116/temperature-alarm-webapi/devices"
|
||||||
|
|
||||||
export function getDevicesOnUserId(id) {
|
function getDevicesOnUserId(id) {
|
||||||
fetch(`${address}/get-on-user-id`, {
|
fetch(`${address}/get-on-user-id`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
@ -13,7 +13,7 @@ export function getDevicesOnUserId(id) {
|
|||||||
.catch(error => console.error("Error:", error));
|
.catch(error => console.error("Error:", error));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function update(ids) {
|
function update(ids) {
|
||||||
fetch(`${address}/get-on-user-id`, {
|
fetch(`${address}/get-on-user-id`, {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
headers: {
|
headers: {
|
||||||
@ -24,17 +24,4 @@ export function update(ids) {
|
|||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => console.log("Success:", data))
|
.then(data => console.log("Success:", data))
|
||||||
.catch(error => console.error("Error:", error));
|
.catch(error => console.error("Error:", error));
|
||||||
}
|
|
||||||
|
|
||||||
export function getLogsOnDeviceIds(id) {
|
|
||||||
fetch(`${address}/get-on-device-ids`, {
|
|
||||||
method: "GET",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ ids: id })
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => console.log("Success:", data))
|
|
||||||
.catch(error => console.error("Error:", error));
|
|
||||||
}
|
}
|
14
frontend/services/temperature-logs.service.js
Normal file
14
frontend/services/temperature-logs.service.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const address = "http://10.135.51.116/temperature-alarm-webapi/temperature-logs"
|
||||||
|
|
||||||
|
function getOnDeviceIds(ids) {
|
||||||
|
fetch(`${address}/get-on-device-ids`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ ids: ids })
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => console.log("Success:", data))
|
||||||
|
.catch(error => console.error("Error:", error));
|
||||||
|
}
|
43
frontend/services/users.service.js
Normal file
43
frontend/services/users.service.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
const address = "http://10.135.51.116/temperature-alarm-webapi/users"
|
||||||
|
|
||||||
|
export function login(usernameOrEmail, password) {
|
||||||
|
console.log(usernameOrEmail);
|
||||||
|
console.log(password);
|
||||||
|
|
||||||
|
fetch(`${address}/login`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify({usernameOrEmail: usernameOrEmail, password: password})
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => console.log("Success:", data))
|
||||||
|
.catch(error => console.error("Error:", error));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function create(email, username, password, repeatPassword){
|
||||||
|
fetch(`${address}/create`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify({email: email, username: username, password: password, repeatPassword: repeatPassword})
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => console.log("Success:", data))
|
||||||
|
.catch(error => console.error("Error:", error));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function update(email, username, password){
|
||||||
|
fetch(`${address}/update`, {
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify({email: email, username: username, password: password})
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => console.log("Success:", data))
|
||||||
|
.catch(error => console.error("Error:", error));
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
export const address = "hhttps://temperature.mercantec.tech/api"
|
|
@ -1,12 +0,0 @@
|
|||||||
export async function handleResponse(response) {
|
|
||||||
const json = await response.json();
|
|
||||||
|
|
||||||
if (response.ok || json.error) return json;
|
|
||||||
|
|
||||||
if (json.errors) {
|
|
||||||
return { error: Object.values(response.errors)[0][0] };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { error: "Request failed with HTTP code " + response.status };
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
|||||||
body {
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Full-width input fields */
|
|
||||||
input[type=text], input[type=password], input[type=email] {
|
|
||||||
width: 100%;
|
|
||||||
padding: 12px 20px;
|
|
||||||
margin: 8px 0;
|
|
||||||
display: inline-block;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set a style for all buttons */
|
|
||||||
button {
|
|
||||||
background-color: #04AA6D;
|
|
||||||
color: white;
|
|
||||||
padding: 14px 20px;
|
|
||||||
margin: 8px 0;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-container {
|
|
||||||
width: 800px;
|
|
||||||
padding: 16px;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.details {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#form-error {
|
|
||||||
display: none;
|
|
||||||
background-color: #FFCDD2;
|
|
||||||
color: #C62828;
|
|
||||||
border: 1px solid #C62828;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 1rem 2rem;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
button{
|
|
||||||
border-radius: 20px;
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
.error {
|
|
||||||
background-color: #EF9A9A;
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
@font-face {
|
|
||||||
font-family: "Poetsen One";
|
|
||||||
src: url("/fonts/PoetsenOne-Regular.ttf");
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
background-image: url("/img/background.jpg");
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center;
|
|
||||||
background-size: cover;
|
|
||||||
background-color: rgba(255, 255, 255, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#logo {
|
|
||||||
height: 1em;
|
|
||||||
position: relative;
|
|
||||||
top: 5px;
|
|
||||||
filter: drop-shadow(3px 3px 6px rgba(0, 0, 0, 0.4));
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 4rem;
|
|
||||||
text-shadow: 3px 3px 6px rgba(0, 0, 0, 0.4);
|
|
||||||
font-family: "Poetsen One";
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
#title {
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
#buttons-wrapper {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 2rem;
|
|
||||||
margin-top: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 1rem 2rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition-duration: 100ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
button:active {
|
|
||||||
filter: brightness(0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
button.secondary {
|
|
||||||
background-color: white;
|
|
||||||
border: 1px solid #04aa6d;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.primary {
|
|
||||||
background-color: #04aa6d;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
|||||||
#profileCard{
|
|
||||||
margin-top: 50px;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.userData{
|
|
||||||
margin-top: 10px;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2{
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btnContainer{
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn{
|
|
||||||
margin-inline: 5px;
|
|
||||||
width: 170px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal {
|
|
||||||
display: none; /* Hidden by default */
|
|
||||||
position: fixed; /* Stay in place */
|
|
||||||
z-index: 1; /* Sit on top */
|
|
||||||
padding-top: 100px; /* Location of the box */
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100%; /* Full width */
|
|
||||||
height: 100%; /* Full height */
|
|
||||||
overflow: auto; /* Enable scroll if needed */
|
|
||||||
background-color: rgb(0,0,0); /* Fallback color */
|
|
||||||
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
background-color: #fefefe;
|
|
||||||
margin: auto;
|
|
||||||
padding: 20px;
|
|
||||||
border: 1px solid #888;
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The Close Button */
|
|
||||||
.close {
|
|
||||||
color: #aaaaaa;
|
|
||||||
float: right;
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close:hover,
|
|
||||||
.close:focus {
|
|
||||||
color: #000;
|
|
||||||
text-decoration: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-container{
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
|||||||
all: main.c mqtt.c temperature.c device_id.c
|
all: main.c mqtt.c temperature.c
|
||||||
$(CC) -lmosquitto -lpthread -li2c main.c mqtt.c temperature.c device_id.c
|
$(CC) -lmosquitto -lpthread -li2c main.c mqtt.c temperature.c
|
||||||
|
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "device_id.h"
|
|
||||||
|
|
||||||
#define DEVICE_ID_SIZE 5
|
|
||||||
|
|
||||||
char *get_device_id(void)
|
|
||||||
{
|
|
||||||
FILE *file = fopen("device_id.txt", "r");
|
|
||||||
|
|
||||||
if (!file) {
|
|
||||||
char *device_id = generate_device_id();
|
|
||||||
|
|
||||||
file = fopen("device_id.txt", "w");
|
|
||||||
fprintf(file, "%s", device_id);
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
return device_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *device_id = malloc(DEVICE_ID_SIZE + 1);
|
|
||||||
fgets(device_id, DEVICE_ID_SIZE + 1, file);
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
return device_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *generate_device_id(void)
|
|
||||||
{
|
|
||||||
char *device_id = malloc(DEVICE_ID_SIZE + 1);
|
|
||||||
|
|
||||||
for (int i = 0; i < DEVICE_ID_SIZE; i++) {
|
|
||||||
device_id[i] = 'A' + (random() % 26);
|
|
||||||
}
|
|
||||||
|
|
||||||
device_id[DEVICE_ID_SIZE] = '\0';
|
|
||||||
|
|
||||||
return device_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy_device_id(char *device_id)
|
|
||||||
{
|
|
||||||
free(device_id);
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
|||||||
char *get_device_id(void);
|
|
||||||
|
|
||||||
char *generate_device_id(void);
|
|
||||||
|
|
||||||
void destroy_device_id(char *device_id);
|
|
||||||
|
|
23
iot/main.c
23
iot/main.c
@ -4,36 +4,23 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include "mqtt.h"
|
#include "mqtt.h"
|
||||||
#include "temperature.h"
|
#include "temperature.h"
|
||||||
#include "device_id.h"
|
|
||||||
|
|
||||||
void *watch_temperature(void *arg)
|
void *watch_temperature(void *arg)
|
||||||
{
|
{
|
||||||
char *device_id = get_device_id();
|
|
||||||
|
|
||||||
printf("Device ID: %s\n", device_id);
|
|
||||||
|
|
||||||
temperature_handle_t temp_handle = init_temperature();
|
temperature_handle_t temp_handle = init_temperature();
|
||||||
|
|
||||||
get_temperature(temp_handle);
|
get_temperature(temp_handle);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
double temperature = get_temperature(temp_handle);
|
double temperature = get_temperature(temp_handle);
|
||||||
size_t timestamp = time(NULL);
|
|
||||||
|
|
||||||
char *format = "{"
|
char *str = malloc(snprintf(NULL, 0, "%lf", temperature) + 1);
|
||||||
"\"temperature\": %lf,"
|
sprintf(str, "%lf", temperature);
|
||||||
"\"device_id\": \"%s\","
|
|
||||||
"\"timestamp\": %zu"
|
|
||||||
"}";
|
|
||||||
|
|
||||||
char *str = malloc(snprintf(NULL, 0, format, temperature, device_id, timestamp) + 1);
|
mqtt_send_message("/temperature", str);
|
||||||
sprintf(str, format, temperature, device_id, timestamp);
|
|
||||||
|
|
||||||
mqtt_send_message("temperature", str);
|
|
||||||
|
|
||||||
free(str);
|
free(str);
|
||||||
|
|
||||||
@ -42,8 +29,6 @@ void *watch_temperature(void *arg)
|
|||||||
sleep(60);
|
sleep(60);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_device_id(device_id);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,8 +40,6 @@ void mqtt_on_connect(void)
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
srand(time(NULL));
|
|
||||||
|
|
||||||
init_mqtt();
|
init_mqtt();
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
Loading…
Reference in New Issue
Block a user