Skip to content

Commit 494d4bf

Browse files
committed
More work
1 parent 1c4337a commit 494d4bf

25 files changed

+1888
-116
lines changed

OVDB_database/Migrations/20260125203254_AddTrainlogSettingsToUser.Designer.cs

Lines changed: 1282 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using Microsoft.EntityFrameworkCore.Migrations;
2+
3+
#nullable disable
4+
5+
namespace OVDB_database.Migrations
6+
{
7+
/// <inheritdoc />
8+
public partial class AddTrainlogSettingsToUser : Migration
9+
{
10+
/// <inheritdoc />
11+
protected override void Up(MigrationBuilder migrationBuilder)
12+
{
13+
migrationBuilder.AddColumn<string>(
14+
name: "TrainlogMaterialKey",
15+
table: "Users",
16+
type: "varchar(100)",
17+
maxLength: 100,
18+
nullable: true)
19+
.Annotation("MySql:CharSet", "utf8mb4");
20+
21+
migrationBuilder.AddColumn<string>(
22+
name: "TrainlogRegistrationKey",
23+
table: "Users",
24+
type: "varchar(100)",
25+
maxLength: 100,
26+
nullable: true)
27+
.Annotation("MySql:CharSet", "utf8mb4");
28+
29+
migrationBuilder.AddColumn<string>(
30+
name: "TrainlogSeatKey",
31+
table: "Users",
32+
type: "varchar(100)",
33+
maxLength: 100,
34+
nullable: true)
35+
.Annotation("MySql:CharSet", "utf8mb4");
36+
}
37+
38+
/// <inheritdoc />
39+
protected override void Down(MigrationBuilder migrationBuilder)
40+
{
41+
migrationBuilder.DropColumn(
42+
name: "TrainlogMaterialKey",
43+
table: "Users");
44+
45+
migrationBuilder.DropColumn(
46+
name: "TrainlogRegistrationKey",
47+
table: "Users");
48+
49+
migrationBuilder.DropColumn(
50+
name: "TrainlogSeatKey",
51+
table: "Users");
52+
}
53+
}
54+
}

OVDB_database/Migrations/OVDBDatabaseContextModelSnapshot.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,18 @@ protected override void BuildModel(ModelBuilder modelBuilder)
783783
b.Property<long?>("TelegramUserId")
784784
.HasColumnType("bigint");
785785

786+
b.Property<string>("TrainlogMaterialKey")
787+
.HasMaxLength(100)
788+
.HasColumnType("varchar(100)");
789+
790+
b.Property<string>("TrainlogRegistrationKey")
791+
.HasMaxLength(100)
792+
.HasColumnType("varchar(100)");
793+
794+
b.Property<string>("TrainlogSeatKey")
795+
.HasMaxLength(100)
796+
.HasColumnType("varchar(100)");
797+
786798
b.Property<string>("TrawellingAccessToken")
787799
.HasColumnType("longtext");
788800

OVDB_database/Models/User.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ public class User
4141
public DateTime? TrawellingTokenExpiresAt { get; set; }
4242
public string TrawellingUsername { get; set; }
4343

44+
// Trainlog Export Mapping
45+
[MaxLength(100)]
46+
public string TrainlogMaterialKey { get; set; }
47+
[MaxLength(100)]
48+
public string TrainlogRegistrationKey { get; set; }
49+
[MaxLength(100)]
50+
public string TrainlogSeatKey { get; set; }
51+
4452
/// <summary>
4553
/// Collection of active refresh tokens for this user (supports multiple sessions)
4654
/// </summary>

OV_DB/Controllers/ExportController.cs

Lines changed: 24 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Microsoft.AspNetCore.Mvc;
1+
using Microsoft.AspNetCore.Mvc;
22
using Microsoft.EntityFrameworkCore;
33
using OV_DB.Helpers;
44
using OV_DB.Models;
@@ -14,6 +14,7 @@
1414
using CsvHelper.Configuration.Attributes;
1515
using System.Globalization;
1616
using NetTopologySuite.Geometries;
17+
using System.Security.Claims;
1718

1819
namespace OV_DB.Controllers
1920
{
@@ -31,12 +32,15 @@ public ExportController(OVDBDatabaseContext dbContext)
3132
[HttpPost("Trainlog")]
3233
public async Task<IActionResult> ExportToTrainlog([FromBody] ExportRequest request)
3334
{
34-
var adminClaim = (User.Claims.SingleOrDefault(c => c.Type == "admin").Value ?? "false");
35+
var adminClaim = (User.Claims.SingleOrDefault(c => c.Type == "admin")?.Value ?? "false");
3536
if (string.Equals(adminClaim, "false", StringComparison.OrdinalIgnoreCase))
3637
{
3738
return Forbid();
3839
}
3940

41+
var userIdClaim = int.Parse(User.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value ?? "-1");
42+
var user = await _dbContext.Users.FindAsync(userIdClaim);
43+
4044
if ((request.RouteInstanceIds == null || !request.RouteInstanceIds.Any()) &&
4145
(request.RouteIds == null || !request.RouteIds.Any()))
4246
{
@@ -48,8 +52,6 @@ public async Task<IActionResult> ExportToTrainlog([FromBody] ExportRequest reque
4852
.ThenInclude(r => r.RouteType)
4953
.Include(ri => ri.Route)
5054
.ThenInclude(r => r.Regions)
51-
.ThenInclude(rg => rg.ParentRegion)
52-
.ThenInclude(pr => pr.ParentRegion)
5355
.Include(ri => ri.RouteInstanceProperties);
5456

5557
if (request.RouteIds != null && request.RouteIds.Any())
@@ -140,7 +142,7 @@ public async Task<IActionResult> ExportToTrainlog([FromBody] ExportRequest reque
140142
}
141143
else
142144
{
143-
end = start.AddHours(1); // Default duration?
145+
end = start; // Default duration?
144146
}
145147

146148
// 3. Flags/Stations
@@ -296,9 +298,18 @@ public async Task<IActionResult> ExportToTrainlog([FromBody] ExportRequest reque
296298
}
297299

298300
// Tags
299-
string materialType = properties.ContainsKey("Voertuig type") ? properties["Voertuig type"] :
300-
(properties.ContainsKey("train_type") ? properties["train_type"] : "");
301-
string reg = properties.ContainsKey("Voertuig nummer") ? properties["Voertuig nummer"] : "";
301+
string materialKey = !string.IsNullOrEmpty(user?.TrainlogMaterialKey) ? user.TrainlogMaterialKey : "Voertuig type";
302+
string regKey = !string.IsNullOrEmpty(user?.TrainlogRegistrationKey) ? user.TrainlogRegistrationKey : "Voertuig nummer";
303+
string seatKey = !string.IsNullOrEmpty(user?.TrainlogSeatKey) ? user.TrainlogSeatKey : "Stoel";
304+
305+
string materialType = properties.ContainsKey(materialKey) ? properties[materialKey] : "";
306+
if (string.IsNullOrEmpty(materialType) && string.IsNullOrEmpty(user?.TrainlogMaterialKey) && properties.ContainsKey("train_type"))
307+
{
308+
materialType = properties["train_type"];
309+
}
310+
311+
string reg = properties.ContainsKey(regKey) ? properties[regKey] : "";
312+
string seat = properties.ContainsKey(seatKey) ? properties[seatKey] : "";
302313
string note = "";
303314

304315
// Create Row Object
@@ -308,15 +319,15 @@ public async Task<IActionResult> ExportToTrainlog([FromBody] ExportRequest reque
308319
Username = "ovdb_export",
309320
OriginStation = origin,
310321
DestinationStation = destination,
311-
StartDatetime = start.ToString("yyyy-MM-dd HH:mm:ss"),
312-
EndDatetime = end.ToString("yyyy-MM-dd HH:mm:ss"),
322+
StartDatetime = start==end? start.ToString("yyyy-MM-dd"): start.ToString("yyyy-MM-dd HH:mm:ss"),
323+
EndDatetime = start == end ? start.ToString("yyyy-MM-dd") : end.ToString("yyyy-MM-dd HH:mm:ss"),
313324
EstimatedTripDuration = duration.ToString("F0"),
314325
ManualTripDuration = "",
315326
TripLength = lengthMeters.ToString("F0"),
316327
Operator = route.OperatingCompany ?? "",
317328
Countries = countriesJson,
318-
UtcStartDatetime = start.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss"),
319-
UtcEndDatetime = end.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss"),
329+
UtcStartDatetime = start == end ? start.ToString("yyyy-MM-dd"):start.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss"),
330+
UtcEndDatetime = start == end ? start.ToString("yyyy-MM-dd"):end.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss"),
320331
LineName = route.LineNumber ?? "",
321332
Created = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
322333
LastModified = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
@@ -329,7 +340,6 @@ public async Task<IActionResult> ExportToTrainlog([FromBody] ExportRequest reque
329340
Price = "",
330341
Currency = "",
331342
PurchasingDate = "",
332-
Visibility = "public",
333343
Path = encodedPath
334344
});
335345
}
@@ -347,7 +357,7 @@ private string GetFlagFromRegions(Point point, IEnumerable<Region> regions)
347357
{
348358
// Find region containing point with a flag
349359
var match = regions.FirstOrDefault(r => !string.IsNullOrEmpty(r.FlagEmoji) && r.Geometry != null && r.Geometry.Contains(point));
350-
return match?.FlagEmoji ?? "";
360+
return match?.FlagEmoji ?? "🇺🇳";
351361
}
352362

353363
private string AppendFlag(string flag, string name)
@@ -359,68 +369,5 @@ private string AppendFlag(string flag, string name)
359369
return name;
360370
}
361371

362-
public class TrainlogExportRow
363-
{
364-
[Name("uid")]
365-
public string Uid { get; set; }
366-
[Name("username")]
367-
public string Username { get; set; }
368-
[Name("origin_station")]
369-
public string OriginStation { get; set; }
370-
[Name("destination_station")]
371-
public string DestinationStation { get; set; }
372-
[Name("start_datetime")]
373-
public string StartDatetime { get; set; }
374-
[Name("end_datetime")]
375-
public string EndDatetime { get; set; }
376-
[Name("estimated_trip_duration")]
377-
public string EstimatedTripDuration { get; set; }
378-
[Name("manual_trip_duration")]
379-
public string ManualTripDuration { get; set; }
380-
[Name("trip_length")]
381-
public string TripLength { get; set; }
382-
[Name("operator")]
383-
public string Operator { get; set; }
384-
[Name("countries")]
385-
public string Countries { get; set; }
386-
[Name("utc_start_datetime")]
387-
public string UtcStartDatetime { get; set; }
388-
[Name("utc_end_datetime")]
389-
public string UtcEndDatetime { get; set; }
390-
[Name("line_name")]
391-
public string LineName { get; set; }
392-
[Name("created")]
393-
public string Created { get; set; }
394-
[Name("last_modified")]
395-
public string LastModified { get; set; }
396-
[Name("type")]
397-
public string Type { get; set; }
398-
[Name("material_type")]
399-
public string MaterialType { get; set; }
400-
[Name("seat")]
401-
public string Seat { get; set; }
402-
[Name("reg")]
403-
public string Reg { get; set; }
404-
[Name("waypoints")]
405-
public string Waypoints { get; set; }
406-
[Name("notes")]
407-
public string Notes { get; set; }
408-
[Name("price")]
409-
public string Price { get; set; }
410-
[Name("currency")]
411-
public string Currency { get; set; }
412-
[Name("purchasing_date")]
413-
public string PurchasingDate { get; set; }
414-
[Name("visibility")]
415-
public string Visibility { get; set; }
416-
[Name("path")]
417-
public string Path { get; set; }
418-
}
419-
420-
public class ExportRequest
421-
{
422-
public List<int> RouteInstanceIds { get; set; }
423-
public List<int> RouteIds { get; set; }
424-
}
425372
}
426373
}

OV_DB/Controllers/RoutesController.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,70 @@ public async Task<ActionResult<RouteListDTO>> GetRoutes([FromQuery] int? start,
122122

123123
}
124124

125+
[HttpGet("instances/list")]
126+
public async Task<ActionResult<RouteInstanceListResponseDTO>> GetRouteInstances([FromQuery] int? start, [FromQuery] int? count, [FromQuery] string sortColumn, [FromQuery] bool? descending, [FromQuery] string filter, CancellationToken cancellationToken)
127+
{
128+
var userIdClaim = int.Parse(User.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value ?? "-1");
129+
if (userIdClaim < 0)
130+
{
131+
return Forbid();
132+
}
133+
var originalQuery = _context.RouteInstances
134+
.Include(r => r.Route)
135+
.ThenInclude(r => r.RouteType)
136+
.Where(r => r.Route.RouteMaps.Any(rm => rm.Map.UserId == userIdClaim));
137+
138+
if (!string.IsNullOrWhiteSpace(filter))
139+
{
140+
originalQuery = originalQuery.Where(r => EF.Functions.Like(r.Route.Name, "%" + filter + "%") || EF.Functions.Like(r.Route.Description, "%" + filter + "%") || EF.Functions.Like(r.Route.From, "%" + filter + "%") || EF.Functions.Like(r.Route.To, "%" + filter + "%"));
141+
}
142+
143+
var query = originalQuery.ProjectTo<RouteInstanceListDTO>(_mapper.ConfigurationProvider);
144+
145+
if (!string.IsNullOrWhiteSpace(sortColumn))
146+
{
147+
if (sortColumn == "name")
148+
{
149+
if (descending.GetValueOrDefault(false))
150+
query = query.OrderByDescending(r => r.RouteName);
151+
else
152+
query = query.OrderBy(r => r.RouteName);
153+
}
154+
if (sortColumn == "date")
155+
{
156+
if (descending.GetValueOrDefault(false))
157+
query = query.OrderByDescending(r => r.Date).ThenByDescending(r => r.StartTime);
158+
else
159+
query = query.OrderBy(r => r.Date).ThenBy(r => r.StartTime);
160+
}
161+
if (sortColumn == "type")
162+
{
163+
if (descending.GetValueOrDefault(false))
164+
query = query.OrderByDescending(r => r.RouteType);
165+
else
166+
query = query.OrderBy(r => r.RouteType);
167+
}
168+
}
169+
else
170+
{
171+
query = query.OrderByDescending(r => r.Date).ThenByDescending(r => r.StartTime);
172+
}
173+
174+
var total = await query.CountAsync(cancellationToken);
175+
if (start.HasValue)
176+
query = query.Skip(start.Value);
177+
if (count.HasValue)
178+
query = query.Take(count.Value);
179+
180+
var list = await query.ToListAsync(cancellationToken);
181+
182+
return new RouteInstanceListResponseDTO
183+
{
184+
Count = total,
185+
Instances = list
186+
};
187+
}
188+
125189

126190
[HttpGet("missingInfo")]
127191
public async Task<ActionResult<IEnumerable<RouteDTO>>> GetRoutesWithMissingInfo()

OV_DB/Controllers/UserController.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ public async Task<ActionResult<UserProfileDTO>> GetProfileAsync()
4949
Email = user.Email,
5050
PreferredLanguage = user.PreferredLanguage?.ToLanguageCode(),
5151
TelegramUserId = user.TelegramUserId,
52-
HasTraewelling = !string.IsNullOrWhiteSpace(user.TrawellingAccessToken)
52+
HasTraewelling = !string.IsNullOrWhiteSpace(user.TrawellingAccessToken),
53+
TrainlogMaterialKey = user.TrainlogMaterialKey,
54+
TrainlogRegistrationKey = user.TrainlogRegistrationKey,
55+
TrainlogSeatKey = user.TrainlogSeatKey
5356
});
5457
}
5558

@@ -80,6 +83,9 @@ public async Task<ActionResult> UpdateProfileAsync([FromBody] UpdateProfileDTO u
8083
? LanguageHelper.FromLanguageCode(updateProfile.PreferredLanguage)
8184
: null;
8285
user.TelegramUserId = updateProfile.TelegramUserId;
86+
user.TrainlogMaterialKey = updateProfile.TrainlogMaterialKey;
87+
user.TrainlogRegistrationKey = updateProfile.TrainlogRegistrationKey;
88+
user.TrainlogSeatKey = updateProfile.TrainlogSeatKey;
8389

8490
DatabaseContext.Update(user);
8591
await DatabaseContext.SaveChangesAsync();

OV_DB/Mappings/MappingProfile.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ public MappingProfile()
3737

3838
CreateMap<RouteInstance, RouteInstanceDTO>()
3939
.ForMember(dest => dest.AverageSpeedKmh, ops => ops.MapFrom(ri => ri.GetAverageSpeedKmh()));
40+
41+
CreateMap<RouteInstance, RouteInstanceListDTO>()
42+
.IncludeBase<RouteInstance, RouteInstanceDTO>()
43+
.ForMember(dest => dest.RouteName, ops => ops.MapFrom(ri => ri.Route.Name))
44+
.ForMember(dest => dest.RouteDescription, ops => ops.MapFrom(ri => ri.Route.Description))
45+
.ForMember(dest => dest.RouteType, ops => ops.MapFrom(ri => ri.Route.RouteType.Name))
46+
.ForMember(dest => dest.RouteTypeColour, ops => ops.MapFrom(ri => ri.Route.RouteType.Colour))
47+
.ForMember(dest => dest.From, ops => ops.MapFrom(ri => ri.Route.From))
48+
.ForMember(dest => dest.To, ops => ops.MapFrom(ri => ri.Route.To))
49+
.ForMember(dest => dest.Distance, ops => ops.MapFrom(ri => ri.Route.OverrideDistance ?? ri.Route.CalculatedDistance))
50+
.ForMember(dest => dest.RouteOverrideColour, ops => ops.MapFrom(ri => ri.Route.OverrideColour));
51+
4052

4153
CreateMap<RouteInstanceProperty, RouteInstancePropertyDTO>();
4254

OV_DB/Models/RouteInstanceDTO.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public class RouteInstanceDTO
1919

2020
public class RouteInstancePropertyDTO
2121
{
22-
public int? RouteInstancePropertyId { get; set; }
22+
public long? RouteInstancePropertyId { get; set; }
2323
public string Key { get; set; }
2424
public string Value { get; set; }
2525
public bool? Bool { get; set; }

0 commit comments

Comments
 (0)