Merge branch 'main' of https://git.innov.energy/Innovenergy/git_trunk
This commit is contained in:
commit
dcab3ab4d1
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Flurl.Http" Version="3.2.4" />
|
<PackageReference Include="Flurl.Http" Version="3.2.4" />
|
||||||
|
<PackageReference Include="Hellang.Middleware.ProblemDetails" Version="6.5.1" />
|
||||||
<PackageReference Include="MailKit" Version="3.6.0" />
|
<PackageReference Include="MailKit" Version="3.6.0" />
|
||||||
<PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.3" />
|
<PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.3" />
|
||||||
<PackageReference Include="Microsoft.AspNet.Identity.Owin" Version="2.2.3" />
|
<PackageReference Include="Microsoft.AspNet.Identity.Owin" Version="2.2.3" />
|
||||||
|
|
|
@ -17,14 +17,19 @@ public class Controller : ControllerBase
|
||||||
public ActionResult<Session> Login(String username, String password)
|
public ActionResult<Session> Login(String username, String password)
|
||||||
{
|
{
|
||||||
var user = Db.GetUserByName(username);
|
var user = Db.GetUserByName(username);
|
||||||
|
|
||||||
if (user is null)
|
if (user is null)
|
||||||
return Unauthorized();
|
{
|
||||||
|
throw new Exceptions(400,"Null User Exception", "Must provide a user to log in as.", Request.Path.Value!);
|
||||||
|
}
|
||||||
|
|
||||||
if (!(user.Password is null && user.MustResetPassword))
|
if (!(user.Password is null && user.MustResetPassword))
|
||||||
{
|
{
|
||||||
if (!user.VerifyPassword(password))
|
if (!user.VerifyPassword(password))
|
||||||
return Unauthorized();
|
{
|
||||||
|
//return Unauthorized("No Password set");
|
||||||
|
throw new Exceptions(401,"Wrong Password Exception", "Please try again.", Request.Path.Value!);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var session = new Session(user.HidePassword().HideParentIfUserHasNoAccessToParent(user));
|
var session = new Session(user.HidePassword().HideParentIfUserHasNoAccessToParent(user));
|
||||||
|
@ -33,7 +38,7 @@ public class Controller : ControllerBase
|
||||||
|
|
||||||
return Db.Create(session)
|
return Db.Create(session)
|
||||||
? session
|
? session
|
||||||
: Unauthorized();
|
: throw new Exceptions(401,"Session Creation Exception", "Not allowed to log in.", Request.Path.Value!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -427,8 +432,6 @@ public class Controller : ControllerBase
|
||||||
: Unauthorized();
|
: Unauthorized();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -186,7 +186,8 @@ public static class SessionMethods
|
||||||
|
|
||||||
return sessionUser is not null
|
return sessionUser is not null
|
||||||
&& sessionUser
|
&& sessionUser
|
||||||
.Do(() => sessionUser.Password = sessionUser.SaltAndHashPassword(newPassword))
|
.Do(() => sessionUser.Password = sessionUser.SaltAndHashPassword(newPassword))
|
||||||
|
.Do(() => sessionUser.MustResetPassword = false)
|
||||||
.Apply(Db.Update);
|
.Apply(Db.Update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace InnovEnergy.App.Backend;
|
||||||
|
|
||||||
|
public class Exceptions : Exception
|
||||||
|
{
|
||||||
|
public String Type { get; set; }
|
||||||
|
public String Detail { get; set; }
|
||||||
|
public String Instance { get; set; }
|
||||||
|
public Int32? Status { get; set; }
|
||||||
|
public Exceptions(Int32? status, String type, String detail, String instance)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
Detail = detail;
|
||||||
|
Instance = instance;
|
||||||
|
Status = status;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
|
using Hellang.Middleware.ProblemDetails;
|
||||||
using InnovEnergy.App.Backend.Database;
|
using InnovEnergy.App.Backend.Database;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend;
|
namespace InnovEnergy.App.Backend;
|
||||||
|
@ -16,6 +18,21 @@ public static class Program
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
|
builder.Services.AddProblemDetails(setup =>
|
||||||
|
{
|
||||||
|
//This includes the stacktrace in Development Env
|
||||||
|
setup.IncludeExceptionDetails = (ctx, env) => builder.Environment.IsDevelopment() || builder.Environment.IsStaging();
|
||||||
|
|
||||||
|
//This handles our Exceptions
|
||||||
|
setup.Map<Exceptions>(exception => new ProblemDetails()
|
||||||
|
{
|
||||||
|
Detail = exception.Detail,
|
||||||
|
Status = exception.Status,
|
||||||
|
Type = exception.Type,
|
||||||
|
Instance = exception.Instance
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
builder.Services.AddSwaggerGen(c =>
|
builder.Services.AddSwaggerGen(c =>
|
||||||
{
|
{
|
||||||
c.SwaggerDoc("v1", OpenApiInfo);
|
c.SwaggerDoc("v1", OpenApiInfo);
|
||||||
|
@ -30,10 +47,11 @@ public static class Program
|
||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
app.UseSwaggerUI();
|
app.UseSwaggerUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseCors(p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()) ;
|
app.UseCors(p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()) ;
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
app.UseProblemDetails();
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -38,7 +38,7 @@ public readonly struct BatteryConnection
|
||||||
var ttys = await fs.GetFiles("/dev", FileType.CharacterDevice);
|
var ttys = await fs.GetFiles("/dev", FileType.CharacterDevice);
|
||||||
|
|
||||||
var candidateTtys = ttys
|
var candidateTtys = ttys
|
||||||
.Where(f => f.StartsWith("ttyUSB"))
|
.Where(f => f.Contains("ttyUSB"))
|
||||||
.Select(t => t.Split("/").LastOrDefault())
|
.Select(t => t.Split("/").LastOrDefault())
|
||||||
.NotNull()
|
.NotNull()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
|
@ -23,15 +23,16 @@ public class BmsTunnel : IDisposable
|
||||||
private const Byte TunnelCode = 0x41;
|
private const Byte TunnelCode = 0x41;
|
||||||
private const String CrcError = "?? CRC FAILED";
|
private const String CrcError = "?? CRC FAILED";
|
||||||
|
|
||||||
public BmsTunnel(String tty, Byte node)
|
public BmsTunnel(String tty, Byte node, SshHost? host)
|
||||||
{
|
{
|
||||||
Tty = tty;
|
Tty = tty;
|
||||||
Node = node;
|
Node = node;
|
||||||
|
|
||||||
StopSerialStarter();
|
StopSerialStarter(host);
|
||||||
|
|
||||||
SerialPort = new SerialPort(Tty, BaudRate, Parity, DataBits, StopBits);
|
SerialPort = new SerialPort(Tty, BaudRate, Parity, DataBits, StopBits);
|
||||||
SerialPort.ReadTimeout = 100;
|
SerialPort.ReadTimeout = 100;
|
||||||
|
|
||||||
SerialPort.Open();
|
SerialPort.Open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,10 +165,11 @@ public class BmsTunnel : IDisposable
|
||||||
.Concat(NewLine);
|
.Concat(NewLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StopSerialStarter()
|
private void StopSerialStarter(SshHost? host)
|
||||||
{
|
{
|
||||||
CliPrograms.StopTty
|
CliPrograms.StopTty
|
||||||
.WithArguments(Tty)
|
.WithArguments(Tty)
|
||||||
|
.OnHost(host)
|
||||||
.ExecuteBufferedAsync()
|
.ExecuteBufferedAsync()
|
||||||
.Task
|
.Task
|
||||||
.Wait(3000);
|
.Wait(3000);
|
||||||
|
|
|
@ -13,16 +13,19 @@ public static class Program
|
||||||
|
|
||||||
public static async Task<Int32> Main(String[] args)
|
public static async Task<Int32> Main(String[] args)
|
||||||
{
|
{
|
||||||
var connection = await ConnectToBms(args.FirstOrDefault());
|
var hostName = args.FirstOrDefault();
|
||||||
|
|
||||||
|
BatteryConnection? connection = hostName is not null ? await ConnectToBms(hostName, new SshHost(hostName)): new BatteryConnection();
|
||||||
|
|
||||||
if (connection is null)
|
if (connection is null)
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
|
// connection.Tty;
|
||||||
Console.WriteLine("\nstarting BMS tunnel\n");
|
Console.WriteLine("\nstarting BMS tunnel\n");
|
||||||
|
|
||||||
// var path = $"/dev/{tty}";
|
var path = $"/dev/{connection.Value.Tty}";
|
||||||
// if (host != null)
|
// if (hostName != null)
|
||||||
// path = $"root@{host}" + path;
|
// path = $"root@{hostName}:" + path;
|
||||||
//
|
//
|
||||||
// var node = connection.Nodes.Any()
|
// var node = connection.Nodes.Any()
|
||||||
// ? connection.Nodes.First()
|
// ? connection.Nodes.First()
|
||||||
|
@ -30,13 +33,13 @@ public static class Program
|
||||||
//
|
//
|
||||||
|
|
||||||
// TODO: Fixme
|
// TODO: Fixme
|
||||||
var path = "";
|
// var path = "";
|
||||||
Byte node = 2;
|
Byte node = 2;
|
||||||
var nodes = new Byte[] { 1, 2, 3 };
|
var nodes = new Byte[] { 1, 2, 3 };
|
||||||
|
|
||||||
// TODO: Fixme
|
// TODO: Fixme
|
||||||
|
|
||||||
using var tunnel = new BmsTunnel(path, node);
|
using var tunnel = new BmsTunnel(path, node, hostName is not null ? new SshHost(hostName): null);
|
||||||
|
|
||||||
ExplainNode();
|
ExplainNode();
|
||||||
ExplainNodes();
|
ExplainNodes();
|
||||||
|
@ -117,12 +120,8 @@ public static class Program
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<BatteryConnection?> ConnectToBms(String? hostName)
|
private static async Task<BatteryConnection?> ConnectToBms(String? hostName, SshHost host)
|
||||||
{
|
{
|
||||||
if (hostName is null)
|
|
||||||
return new BatteryConnection();
|
|
||||||
|
|
||||||
var host = new SshHost(hostName);
|
|
||||||
|
|
||||||
if (await host.Ping())
|
if (await host.Ping())
|
||||||
return await BatteryConnection.Connect(host);
|
return await BatteryConnection.Connect(host);
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class FileSystem
|
||||||
public async Task<IReadOnlyList<String>> GetFiles(String path, FileType fileType, Int32 maxDepth = 1)
|
public async Task<IReadOnlyList<String>> GetFiles(String path, FileType fileType, Int32 maxDepth = 1)
|
||||||
{
|
{
|
||||||
var result = await Find
|
var result = await Find
|
||||||
.WithArguments($"find {path} -maxdepth {maxDepth} -type {(Char)fileType}")
|
.WithArguments($"{path} -maxdepth {maxDepth} -type {(Char)fileType}")
|
||||||
.OnHost(Host)
|
.OnHost(Host)
|
||||||
.ExecuteBufferedAsync();
|
.ExecuteBufferedAsync();
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ const resolution = TimeSpan.fromSeconds(2);
|
||||||
|
|
||||||
const cache = new DataCache(x => (Promise.resolve({foo: 0})), resolution)
|
const cache = new DataCache(x => (Promise.resolve({foo: 0})), resolution)
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
const sampleTimes = [1, 2, 3, 4, 5, 6].select(e => UnixTime.fromTicks(e)).toArray();
|
const sampleTimes = [1, 2, 3, 4, 5, 6].select(e => UnixTime.fromTicks(e)).toArray();
|
||||||
|
|
||||||
const series = cache.getSeries(sampleTimes)
|
const series = cache.getSeries(sampleTimes)
|
||||||
|
|
|
@ -114,7 +114,8 @@ export default class DataCache<T extends Record<string, number>>
|
||||||
const pn = p + n
|
const pn = p + n
|
||||||
|
|
||||||
let interpolated: Partial<Record<string, number>> = {}
|
let interpolated: Partial<Record<string, number>> = {}
|
||||||
|
|
||||||
|
//What about string nodes? like Alarms
|
||||||
for (const k of Object.keys(dataBefore))
|
for (const k of Object.keys(dataBefore))
|
||||||
{
|
{
|
||||||
interpolated[k] = (dataBefore[k] * n + dataAfter[k] * p) / pn
|
interpolated[k] = (dataBefore[k] * n + dataAfter[k] * p) / pn
|
||||||
|
|
|
@ -59,7 +59,7 @@ const AvailableUserDialog = () => {
|
||||||
scroll="paper"
|
scroll="paper"
|
||||||
>
|
>
|
||||||
<DialogTitle id="available-user-dialog-title">
|
<DialogTitle id="available-user-dialog-title">
|
||||||
Create new folder
|
Grant access
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent id="available-user-dialog-content">
|
<DialogContent id="available-user-dialog-content">
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
|
|
|
@ -27,7 +27,7 @@ const AddUser = () => {
|
||||||
sx={{ my: 1 }}
|
sx={{ my: 1 }}
|
||||||
onClick={() => setOpen(true)}
|
onClick={() => setOpen(true)}
|
||||||
>
|
>
|
||||||
<FormattedMessage id="addUser" defaultMessage="Add user" />
|
<FormattedMessage id="addUser" defaultMessage="Create user" />
|
||||||
</InnovenergyButton>
|
</InnovenergyButton>
|
||||||
<Dialog
|
<Dialog
|
||||||
onClose={() => setOpen(false)}
|
onClose={() => setOpen(false)}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Selector } from 'testcafe';
|
import { Selector } from 'testcafe';
|
||||||
|
import { login, logout } from "./helper.js";
|
||||||
|
|
||||||
fixture('Login testing')
|
fixture('Login testing')
|
||||||
.page('http://localhost:3000/'); //Todo write me in a config file
|
.page('http://localhost:3000/'); //Todo write me in a config file
|
||||||
|
@ -8,33 +9,31 @@ fixture('Login testing')
|
||||||
test('Lulu login', async t => {
|
test('Lulu login', async t => {
|
||||||
// await t
|
// await t
|
||||||
// .debug();
|
// .debug();
|
||||||
await t
|
login('lulu', '1233'); //Todo write me in a config file
|
||||||
.login('lulu', '1233') //Todo write me in a config file
|
await t.expect(Selector('#demo-simple-select').visible).ok();
|
||||||
.expect(Selector('#demo-simple-select').visible).ok();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test('Wrong PW', async t => {
|
test('Wrong PW', async t => {
|
||||||
await t
|
login('lulu', '12334'); //Todo write me in a config file
|
||||||
.login('lulu', '12334') //Todo write me in a config file
|
await t.expect(Selector('#demo-simple-select').visible).notOk(); //Todo check for feedback
|
||||||
.expect(Selector('#demo-simple-select').visible).notOk(); //Todo check for feedback
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Invalid Username', async t => {
|
test('Invalid Username', async t => {
|
||||||
|
login('Not Agent Smith', '12334')
|
||||||
await t
|
await t
|
||||||
.login('Not Agent Smith', '12334') //Todo write me in a config file
|
|
||||||
.expect(Selector('#demo-simple-select').visible).notOk(); //Todo check for feedback
|
.expect(Selector('#demo-simple-select').visible).notOk(); //Todo check for feedback
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Logout', async t => {
|
test('Logout', async t => {
|
||||||
|
login('lulu', '1233');
|
||||||
|
logout();
|
||||||
await t
|
await t
|
||||||
.login('lulu', '1233') //Todo write me in a config file
|
|
||||||
.logout()
|
|
||||||
.expect(Selector('#username-textfield').visible).Ok();
|
.expect(Selector('#username-textfield').visible).Ok();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Installation List Loads', async t => {
|
test('Installation List Loads', async t => {
|
||||||
|
login('lulu', '1233');
|
||||||
await t
|
await t
|
||||||
.login('lulu', '1233') //Todo write me in a config file
|
|
||||||
.expect(Selector('').visible).Ok();
|
.expect(Selector('').visible).Ok();
|
||||||
});
|
});
|
Loading…
Reference in New Issue