Skip to content

Commit c169956

Browse files
authored
Agent camera masks and ui themes (#110)
* websocket listener * ws configurable * show agent status from websocket on frontend * fix for linux decimals * snackbar support * agent status on page updates in real time * correct field saving * add autofocus commands, more agent events * added image mask saving to agent * some fixes * get it saving on the handler properly * finish enable/disable logic, fix config sending * more tweaks and fixes * add pagination on mask page * add some error handling on image load * proper resolution * correct coordinates * standalone components * theming, login, etc * angular 17 * fancy glows, multi theme * some css fixes * reorg * send the image too * only send when configured to * not for all * schedule agent scrape * fix tests * open to plate directly from web push alert * open url from chrome * no dev mode * open on windows * linting * tests work * get fe tests running on gha * working directory * test separate * backend tests * more test work * no lower bound
1 parent 6081aad commit c169956

260 files changed

Lines changed: 15501 additions & 6792 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/docker-publish.yml

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,59 @@ jobs:
1414
runs-on: ubuntu-latest
1515
steps:
1616
- uses: actions/checkout@v2
17-
- name: Run tests
17+
- name: Run build
18+
run: docker build . --file ./OpenAlprWebhookProcessor/Dockerfile
19+
20+
back-end-tests:
21+
runs-on: ubuntu-latest
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v2
25+
26+
- name: Setup .NET
27+
uses: actions/setup-dotnet@v1
28+
with:
29+
dotnet-version: 7.x
30+
31+
- name: Restore Dependencies
32+
run: dotnet restore
33+
34+
- name: Build
35+
run: dotnet build --configuration Release --no-restore
36+
37+
- name: Test
38+
run: dotnet test --configuration Release --no-build --collect:"XPlat Code Coverage" --results-directory ./coverage
39+
40+
- name: Code Coverage Report
41+
uses: irongut/CodeCoverageSummary@v1.3.0
42+
with:
43+
filename: coverage/**/coverage.cobertura.xml
44+
badge: true
45+
fail_below_min: true
46+
format: markdown
47+
hide_branch_rate: false
48+
hide_complexity: true
49+
indicators: true
50+
output: both
51+
thresholds: '0 80'
52+
53+
- name: Add Coverage PR Comment
54+
uses: marocchino/sticky-pull-request-comment@v2
55+
if: github.event_name == 'pull_request'
56+
with:
57+
recreate: true
58+
path: code-coverage-results.md
59+
60+
front-end-tests:
61+
runs-on: ubuntu-latest
62+
steps:
63+
- uses: actions/checkout@v2
64+
- name: Run frontend tests
65+
working-directory: ./OpenAlprWebhookProcessor/angularapp
1866
run: |
19-
if [ -f docker-compose.test.yml ]; then
20-
docker-compose --file docker-compose.test.yml build
21-
docker-compose --file docker-compose.test.yml run sut
22-
else
23-
docker build . --file ./OpenAlprWebhookProcessor/Dockerfile
24-
fi
67+
npm ci
68+
npm run test:prod
69+
npm run lint
2570
2671
windows-build-push:
2772
needs: build

OpenAlprWebhookProcessor.sln

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 16
4-
VisualStudioVersion = 16.0.30804.86
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.7.34031.279
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{350E0804-C372-49AB-B670-75E037878FAF}"
77
ProjectSection(SolutionItems) = preProject
@@ -10,6 +10,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1010
EndProject
1111
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenAlprWebhookProcessor", "OpenAlprWebhookProcessor\OpenAlprWebhookProcessor.csproj", "{7C3E9804-0A13-4060-B5FD-91A613647146}"
1212
EndProject
13+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{DD123D3E-8A09-4104-AF20-D5FBFAA6F52E}"
14+
EndProject
1315
Global
1416
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1517
Debug|Any CPU = Debug|Any CPU
@@ -20,6 +22,10 @@ Global
2022
{7C3E9804-0A13-4060-B5FD-91A613647146}.Debug|Any CPU.Build.0 = Debug|Any CPU
2123
{7C3E9804-0A13-4060-B5FD-91A613647146}.Release|Any CPU.ActiveCfg = Release|Any CPU
2224
{7C3E9804-0A13-4060-B5FD-91A613647146}.Release|Any CPU.Build.0 = Release|Any CPU
25+
{DD123D3E-8A09-4104-AF20-D5FBFAA6F52E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26+
{DD123D3E-8A09-4104-AF20-D5FBFAA6F52E}.Debug|Any CPU.Build.0 = Debug|Any CPU
27+
{DD123D3E-8A09-4104-AF20-D5FBFAA6F52E}.Release|Any CPU.ActiveCfg = Release|Any CPU
28+
{DD123D3E-8A09-4104-AF20-D5FBFAA6F52E}.Release|Any CPU.Build.0 = Release|Any CPU
2329
EndGlobalSection
2430
GlobalSection(SolutionProperties) = preSolution
2531
HideSolutionNode = FALSE
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
2+
[*.{cs,vb}]
3+
#### Naming styles ####
4+
5+
# Naming rules
6+
7+
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
8+
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
9+
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
10+
11+
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
12+
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
13+
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
14+
15+
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
16+
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
17+
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
18+
19+
# Symbol specifications
20+
21+
dotnet_naming_symbols.interface.applicable_kinds = interface
22+
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
23+
dotnet_naming_symbols.interface.required_modifiers =
24+
25+
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
26+
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
27+
dotnet_naming_symbols.types.required_modifiers =
28+
29+
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
30+
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
31+
dotnet_naming_symbols.non_field_members.required_modifiers =
32+
33+
# Naming styles
34+
35+
dotnet_naming_style.begins_with_i.required_prefix = I
36+
dotnet_naming_style.begins_with_i.required_suffix =
37+
dotnet_naming_style.begins_with_i.word_separator =
38+
dotnet_naming_style.begins_with_i.capitalization = pascal_case
39+
40+
dotnet_naming_style.pascal_case.required_prefix =
41+
dotnet_naming_style.pascal_case.required_suffix =
42+
dotnet_naming_style.pascal_case.word_separator =
43+
dotnet_naming_style.pascal_case.capitalization = pascal_case
44+
45+
dotnet_naming_style.pascal_case.required_prefix =
46+
dotnet_naming_style.pascal_case.required_suffix =
47+
dotnet_naming_style.pascal_case.word_separator =
48+
dotnet_naming_style.pascal_case.capitalization = pascal_case
49+
dotnet_style_operator_placement_when_wrapping = beginning_of_line
50+
tab_width = 4
51+
indent_size = 4
52+
end_of_line = crlf
53+
dotnet_style_coalesce_expression = true:suggestion
54+
dotnet_style_null_propagation = true:suggestion
55+
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
56+
dotnet_style_prefer_auto_properties = true:silent
57+
dotnet_style_object_initializer = true:suggestion
58+
dotnet_style_collection_initializer = true:suggestion
59+
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
60+
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
61+
dotnet_style_prefer_conditional_expression_over_return = true:silent
62+
dotnet_style_explicit_tuple_names = true:suggestion
63+
dotnet_style_prefer_inferred_tuple_names = true:suggestion
64+
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
65+
dotnet_style_prefer_compound_assignment = true:suggestion
66+
dotnet_style_prefer_simplified_interpolation = true:suggestion
67+
dotnet_style_namespace_match_folder = true:suggestion
68+
dotnet_code_quality_unused_parameters = all:suggestion
69+
70+
[*.cs]
71+
csharp_indent_labels = one_less_than_current
72+
csharp_using_directive_placement = outside_namespace:silent
73+
csharp_prefer_simple_using_statement = true:suggestion
74+
csharp_prefer_braces = true:silent
75+
csharp_style_namespace_declarations = block_scoped:silent
76+
csharp_style_prefer_method_group_conversion = true:silent
77+
csharp_style_prefer_top_level_statements = true:silent
78+
csharp_style_prefer_primary_constructors = true:suggestion
79+
csharp_style_expression_bodied_methods = false:silent
80+
csharp_style_expression_bodied_constructors = false:silent
81+
csharp_style_expression_bodied_operators = false:silent
82+
csharp_style_expression_bodied_properties = true:silent
83+
csharp_style_expression_bodied_indexers = true:silent
84+
csharp_style_expression_bodied_accessors = true:silent
85+
csharp_style_expression_bodied_lambdas = true:silent
86+
csharp_style_expression_bodied_local_functions = false:silent
87+
csharp_style_throw_expression = true:suggestion
88+
csharp_style_unused_value_assignment_preference = discard_variable:suggestion

OpenAlprWebhookProcessor/Alerts/Alert.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Threading.Tasks;
52

63
namespace OpenAlprWebhookProcessor.Alerts
74
{
85
public class Alert
96
{
107
public Guid Id { get; set; }
118

9+
public bool IsUrgent { get; set; }
10+
1211
public string PlateNumber { get; set; }
1312

1413
public bool StrictMatch { get; set; }

OpenAlprWebhookProcessor/Alerts/AlertService.cs

Lines changed: 8 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using Microsoft.AspNetCore.SignalR;
2-
using Microsoft.EntityFrameworkCore;
32
using Microsoft.Extensions.DependencyInjection;
43
using Microsoft.Extensions.Hosting;
54
using Microsoft.Extensions.Logging;
@@ -19,22 +18,18 @@ public class AlertService : IHostedService
1918

2019
private readonly CancellationTokenSource _cancellationTokenSource;
2120

22-
private readonly IServiceProvider _serviceProvider;
23-
2421
private readonly ILogger _logger;
2522

2623
private readonly IHubContext<ProcessorHub.ProcessorHub, ProcessorHub.IProcessorHub> _processorHub;
2724

2825
private readonly IEnumerable<IAlertClient> _alertClients;
2926

3027
public AlertService(
31-
IServiceProvider serviceProvider,
3228
ILogger<AlertService> logger,
3329
IHubContext<ProcessorHub.ProcessorHub, ProcessorHub.IProcessorHub> processorHub,
3430
IEnumerable<IAlertClient> alertClients)
3531
{
3632
_logger = logger;
37-
_serviceProvider = serviceProvider;
3833
_cancellationTokenSource = new CancellationTokenSource();
3934
_alertsToProcess = new BlockingCollection<AlertUpdateRequest>();
4035
_processorHub = processorHub;
@@ -67,48 +62,18 @@ private async Task ProcessAlertsAsync()
6762
{
6863
foreach (var job in _alertsToProcess.GetConsumingEnumerable(_cancellationTokenSource.Token))
6964
{
70-
using (var scope = _serviceProvider.CreateScope())
71-
{
72-
var processorContext = scope.ServiceProvider.GetRequiredService<ProcessorContext>();
73-
74-
var plateGroups = processorContext.PlateGroups.AsQueryable();
65+
_logger.LogInformation("alerting for: {plateNumber}", job.PlateNumber);
66+
await _processorHub.Clients.All.LicensePlateAlerted(job.PlateNumber);
7567

76-
if (job.IsStrictMatch)
77-
{
78-
plateGroups = plateGroups.Where(x => x.Id == job.LicensePlateId || x.PossibleNumbers.Any(x => x.Number == job.LicensePlateId.ToString()));
79-
}
80-
else
68+
foreach (var alertClient in _alertClients)
69+
{
70+
try
8171
{
82-
plateGroups = plateGroups.Where(x => x.Id == job.LicensePlateId);
72+
await alertClient.SendAlertAsync(job, _cancellationTokenSource.Token);
8373
}
84-
85-
var result = await plateGroups
86-
.Include(x => x.PlateImage)
87-
.FirstOrDefaultAsync(_cancellationTokenSource.Token);
88-
89-
if (result != null)
74+
catch (Exception ex)
9075
{
91-
_logger.LogInformation("alerting for: {alertId}", result.Id);
92-
await _processorHub.Clients.All.LicensePlateAlerted(result.Id.ToString());
93-
94-
foreach (var alertClient in _alertClients)
95-
{
96-
try
97-
{
98-
await alertClient.SendAlertAsync(new Alert()
99-
{
100-
Description = job.Description,
101-
Id = result.Id,
102-
PlateNumber = result.BestNumber,
103-
},
104-
result.PlateImage.Jpeg,
105-
_cancellationTokenSource.Token);
106-
}
107-
catch (Exception ex)
108-
{
109-
_logger.LogError(ex, $"failed to send alert to {nameof(alertClient)}");
110-
}
111-
}
76+
_logger.LogError(ex, $"failed to send alert to {nameof(alertClient)}");
11277
}
11378
}
11479
}

OpenAlprWebhookProcessor/Alerts/AlertUpdateRequest.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@ namespace OpenAlprWebhookProcessor.Alerts
44
{
55
public class AlertUpdateRequest
66
{
7-
public Guid CameraId { get; set; }
8-
97
public string Description { get; set; }
108

11-
public Guid LicensePlateId { get; set; }
9+
public bool IsUrgent { get; set; }
10+
11+
public Guid PlateId { get; set; }
12+
13+
public string PlateNumber { get; set; }
14+
15+
public byte[] PlateJpeg { get; set; }
16+
17+
public string PlateJpegUrl { get; set; }
1218

13-
public bool IsStrictMatch { get; set; }
19+
public DateTimeOffset ReceivedOn { get; set; }
1420
}
1521
}

OpenAlprWebhookProcessor/Alerts/IAlertClient.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ namespace OpenAlprWebhookProcessor.Alerts
66
{
77
public interface IAlertClient
88
{
9+
Task<bool> ShouldSendAllPlatesAsync(CancellationToken cancellationToken);
10+
911
Task SendAlertAsync(
10-
Alert alert,
11-
byte[] plateJpeg,
12+
AlertUpdateRequest alert,
1213
CancellationToken cancellationToken);
1314

1415
Task VerifyCredentialsAsync(

OpenAlprWebhookProcessor/Alerts/Pushover/GetPushoverClientRequestHandler.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public async Task<PushoverRequest> HandleAsync(CancellationToken cancellationTok
2828
ApiToken = client.ApiToken,
2929
IsEnabled = client.IsEnabled,
3030
SendPlatePreviewEnabled = client.SendPlatePreview,
31+
SendEveryPlateEnabled = client.SendEveryPlateEnabled,
3132
UserKey = client.UserKey,
3233
};
3334
}

0 commit comments

Comments
 (0)