summaryrefslogtreecommitdiffstats
path: root/api/WhatApi/Endpoints
diff options
context:
space:
mode:
Diffstat (limited to 'api/WhatApi/Endpoints')
-rw-r--r--api/WhatApi/Endpoints/BaseEndpoint.cs12
-rw-r--r--api/WhatApi/Endpoints/DownloadContentEndpoint.cs19
-rw-r--r--api/WhatApi/Endpoints/GetPlacesEndpoint.cs57
-rw-r--r--api/WhatApi/Endpoints/UploadContentEndpoint.cs49
4 files changed, 137 insertions, 0 deletions
diff --git a/api/WhatApi/Endpoints/BaseEndpoint.cs b/api/WhatApi/Endpoints/BaseEndpoint.cs
new file mode 100644
index 0000000..4d8f9ad
--- /dev/null
+++ b/api/WhatApi/Endpoints/BaseEndpoint.cs
@@ -0,0 +1,12 @@
+using System.Net;
+using Microsoft.AspNetCore.Mvc;
+
+namespace WhatApi.Endpoints;
+
+[ApiController]
+public class BaseEndpoint : ControllerBase
+{
+ protected IPAddress GetIp() => Request.Headers.TryGetValue("X-Forwarded-For", out var ip)
+ ? IPAddress.Parse(ip.ToString())
+ : HttpContext.Connection.RemoteIpAddress!;
+} \ No newline at end of file
diff --git a/api/WhatApi/Endpoints/DownloadContentEndpoint.cs b/api/WhatApi/Endpoints/DownloadContentEndpoint.cs
new file mode 100644
index 0000000..dbe6bff
--- /dev/null
+++ b/api/WhatApi/Endpoints/DownloadContentEndpoint.cs
@@ -0,0 +1,19 @@
+using Microsoft.AspNetCore.Mvc;
+
+namespace WhatApi.Endpoints;
+
+public class DownloadContentEndpoint : BaseEndpoint
+{
+ [HttpGet("~/{id:guid}")]
+ public async Task<ActionResult> HandleAsync(Guid id, CancellationToken ct = default) {
+ try {
+ var path = Path.Combine(Directory.GetCurrentDirectory(), "files", id.ToString());
+ await using var file = new FileStream(path, FileMode.Open);
+ if (!file.CanRead) return NotFound();
+ return File(file, "application/octet-stream", id.ToString());
+ } catch (Exception e) {
+ if (e is not FileNotFoundException) Console.WriteLine(e);
+ return NotFound();
+ }
+ }
+} \ No newline at end of file
diff --git a/api/WhatApi/Endpoints/GetPlacesEndpoint.cs b/api/WhatApi/Endpoints/GetPlacesEndpoint.cs
new file mode 100644
index 0000000..5630229
--- /dev/null
+++ b/api/WhatApi/Endpoints/GetPlacesEndpoint.cs
@@ -0,0 +1,57 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using NetTopologySuite;
+using NetTopologySuite.Features;
+using NetTopologySuite.Geometries;
+using WhatApi.Tables;
+
+namespace WhatApi.Endpoints;
+
+public class GetPlacesEndpoint(Database db) : BaseEndpoint
+{
+ [HttpGet("~/places")]
+ public async Task<ActionResult> HandleAsync(string w, string s, string e, string n, CancellationToken ct = default) {
+ var north = double.Parse(n);
+ var east = double.Parse(e);
+ var south = double.Parse(s);
+ var west = double.Parse(w);
+
+ IQueryable<Place> resultingQuery;
+
+ if (west > east) {
+ resultingQuery = db.Places
+ .FromSqlInterpolated($"""
+ SELECT * FROM "Place"
+ WHERE ST_Intersects(
+ "Location",
+ ST_MakeEnvelope({west}, {south}, 180, {north}, {Constants.Wgs84SpatialReferenceId}) || ST_MakeEnvelope(-180, {south}, {east}, {north}, {Constants.Wgs84SpatialReferenceId})
+ )
+ """);
+ } else {
+ resultingQuery = db.Places
+ .FromSqlInterpolated($"""
+ SELECT * FROM "Place"
+ WHERE ST_Intersects(
+ "Location",
+ ST_MakeEnvelope({west}, {south}, {east}, {north}, {Constants.Wgs84SpatialReferenceId})
+ )
+ """);
+ }
+
+ var gf = NtsGeometryServices.Instance.CreateGeometryFactory(srid: Constants.Wgs84SpatialReferenceId);
+ var fc = new FeatureCollection();
+
+ await foreach (var p in resultingQuery.AsAsyncEnumerable().WithCancellation(ct)) {
+ var point = gf.CreatePoint(new Coordinate(p.Location.X, p.Location.Y));
+ fc.Add(new Feature(point, new AttributesTable {
+ {
+ "id", p.Id
+ }, {
+ "cid", p.ContentId
+ }
+ }));
+ }
+
+ return Ok(fc);
+ }
+} \ No newline at end of file
diff --git a/api/WhatApi/Endpoints/UploadContentEndpoint.cs b/api/WhatApi/Endpoints/UploadContentEndpoint.cs
new file mode 100644
index 0000000..82fb71b
--- /dev/null
+++ b/api/WhatApi/Endpoints/UploadContentEndpoint.cs
@@ -0,0 +1,49 @@
+using Microsoft.AspNetCore.Http.Extensions;
+using Microsoft.AspNetCore.Mvc;
+using NetTopologySuite;
+using NetTopologySuite.Geometries;
+
+namespace WhatApi.Endpoints;
+
+public class UploadContentEndpoint(Database db) : BaseEndpoint
+{
+ public record UploadContent(IFormFile File, string LatLong);
+
+ [HttpPost("~/upload")]
+ public async Task<ActionResult> HandleAsync([FromForm] UploadContent request, CancellationToken ct = default) {
+ if (string.IsNullOrWhiteSpace(Request.GetMultipartBoundary())) {
+ return StatusCode(415, "Unsupported Media Type");
+ }
+
+ var blobId = Guid.NewGuid();
+ var contentId = Guid.NewGuid();
+
+ var latitude = request.LatLong.Split(',')[0];
+ var longitude = request.LatLong.Split(',')[1];
+
+ var gf = NtsGeometryServices.Instance.CreateGeometryFactory(srid: Constants.Wgs84SpatialReferenceId);
+ var point = gf.CreatePoint(new Coordinate(double.Parse(longitude), double.Parse(latitude)));
+
+ var place = new Tables.Place() {
+ ContentId = contentId,
+ Location = point
+ };
+
+ var content = new Tables.Content() {
+ Id = contentId,
+ Mime = request.File.ContentType,
+ Created = DateTime.UtcNow,
+ BlobId = blobId,
+ Ip = GetIp()
+ };
+
+ var path = Path.Combine(Directory.GetCurrentDirectory(), "files", blobId.ToString());
+
+ await using var writer = new FileStream(path, FileMode.CreateNew);
+ await request.File.CopyToAsync(writer, ct);
+ await db.Content.AddAsync(content, ct);
+ await db.Places.AddAsync(place, ct);
+ await db.SaveChangesAsync(ct);
+ return Ok(contentId);
+ }
+} \ No newline at end of file