diff options
author | Ian C <ianc@noddybox.co.uk> | 2024-03-22 12:28:07 +0000 |
---|---|---|
committer | Ian C <ianc@noddybox.co.uk> | 2024-03-22 12:28:07 +0000 |
commit | 3f05ee34d209fcb994cba50955cd2e301315d9bd (patch) | |
tree | 5cd375c2e8ecc444786286af4d1afcbcaf95227e | |
parent | d71f080ad276653399c92810c9122bf537e551fe (diff) |
Initial working version.
-rw-r--r-- | Download.cs | 17 | ||||
-rw-r--r-- | Pages/Index.cshtml | 79 | ||||
-rw-r--r-- | Pages/Index.cshtml.cs | 114 | ||||
-rw-r--r-- | Pages/Privacy.cshtml | 8 | ||||
-rw-r--r-- | Pages/Privacy.cshtml.cs | 19 | ||||
-rw-r--r-- | Pages/Report.cshtml | 43 | ||||
-rw-r--r-- | Pages/Report.cshtml.cs | 111 | ||||
-rw-r--r-- | Pages/Shared/_Layout.cshtml | 13 |
8 files changed, 320 insertions, 84 deletions
diff --git a/Download.cs b/Download.cs new file mode 100644 index 0000000..6e043cb --- /dev/null +++ b/Download.cs @@ -0,0 +1,17 @@ +namespace download_admin; + +public class Download +{ + public string Key {get; private set;} + public string IpAddress {get; private set;} + public string UserAgent {get; private set;} + public DateTime Time {get; private set;} + + public Download(string key, string ip_address, string user_agent, DateTime time) + { + Key = key; + IpAddress = ip_address; + UserAgent = user_agent; + Time = time; + } +} diff --git a/Pages/Index.cshtml b/Pages/Index.cshtml index 9c1f3c2..469011c 100644 --- a/Pages/Index.cshtml +++ b/Pages/Index.cshtml @@ -1,48 +1,37 @@ @page @model download_admin.Pages.IndexModel @using download_admin.Pages -<!DOCTYPE html> -<html> - <head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Download Repsoitory Editor</title> - </head> - <body> - <a href="report">Download Report</a><br> - @if (Model.HasError) - { - <p style="color:red"><b>@Model.ErrorText</b></p> - } - <table> - <tr> - <td style="width:25%;"><b>Key</b></td> - <td style="width:20%;"><b>Mime type</b></td> - <td style="width:20%;"><b>File name</b></td> - <td style="width:15%;"><b>File data</b></td> - <td style="width:20%;"><b>Commands</b></td> - </tr> - @foreach(FileObject obj in Model.Rows) - { - <tr> - <form enctype="multipart/form-data" method="post"> - <td><input type=text name="Key" maxlength=64 value="@obj.Key"></td> - <td><input type=text name="MimeType" maxlength=64 value="@obj.MimeType"></td> - <td><input type=text name="Filename" maxlength=64 value="@obj.FileName"></td> - <td><input type=file name="Data"></td> - <td><input type="submit" name="update" value="Update"><input type="submit" name="delete" value="Delete"></td> - </form> - </tr> - } - <tr> - <form enctype="multipart/form-data" method="post"> - <td><input type=text name="Key" maxlength=64 value=""></td> - <td><input type=text name="MimeType" maxlength=64 value=""></td> - <td><input type=text name="Filename" maxlength=64 value=""></td> - <td><input type=file name="Data"></td> - <td><input type="submit" name="add" value="Add"></td> - </form> - </tr> - </table> - </body> -</html> +@if (Model.HasError) +{ + <p style="color:red"><b>@Model.ErrorText</b></p> +} +<table> + <tr> + <td style="width:25%;"><b>Key</b></td> + <td style="width:20%;"><b>Mime type</b></td> + <td style="width:20%;"><b>File name</b></td> + <td style="width:15%;"><b>File data</b></td> + <td style="width:20%;"><b>Commands</b></td> + </tr> + @foreach(FileObject obj in Model.Rows) + { + <tr> + <form enctype="multipart/form-data" method="post"> + <td><input type=text name="key" maxlength=64 value="@obj.Key"></td> + <td><input type=text name="mime_type" maxlength=64 value="@obj.MimeType"></td> + <td><input type=text name="file_name" maxlength=64 value="@obj.FileName"></td> + <td><input type=file name="file"></td> + <td><input type="submit" name="update" value="Update"><input type="submit" name="delete" value="Delete"><input readonly style="display: none" type=text name="original_key" maxlength=64 value="@obj.Key"></td> + </form> + </tr> + } + <tr> + <form enctype="multipart/form-data" method="post"> + <td><input type=text name="key" maxlength=64 value=""></td> + <td><input type=text name="mime_type" maxlength=64 value=""></td> + <td><input type=text name="file_name" maxlength=64 value=""></td> + <td><input type=file name="file"></td> + <td><input type="submit" name="add" value="Add"></td> + </form> + </tr> +</table>
\ No newline at end of file diff --git a/Pages/Index.cshtml.cs b/Pages/Index.cshtml.cs index 6e9a5ed..90c18db 100644 --- a/Pages/Index.cshtml.cs +++ b/Pages/Index.cshtml.cs @@ -17,11 +17,14 @@ public class IndexModel : PageModel public void OnGet() { + ViewData["Title"] = "Download Repsoitory Editor"; LoadData(); } public void OnPost() { + ViewData["Title"] = "Download Repsoitory Editor"; + if (!String.IsNullOrEmpty(Request.Form["add"])) { DoAdd(); @@ -47,17 +50,122 @@ public class IndexModel : PageModel private void DoAdd() { - SetError("DoAdd"); + try + { + string? key = Request.Form["key"]; + string? mime_type = Request.Form["mime_type"]; + string? file_name = Request.Form["file_name"]; + IFormFile? file = Request.Form.Files.Count > 0 ? Request.Form.Files[0] : null; + + if (String.IsNullOrWhiteSpace(key) || + String.IsNullOrWhiteSpace(mime_type) || + String.IsNullOrEmpty(file_name) || + file == null) + { + SetError("Need key, mime type, file name and file"); + return; + } + + using var file_stream = file.OpenReadStream(); + byte[] file_data = new byte[file.Length]; + file_stream.Read(file_data, 0, (int)file.Length); + + using var conn = new NpgsqlConnection(Config.Settings["ConnectionStrings:download"]); + + conn.Open(); + + using var cmd = new NpgsqlCommand("INSERT INTO file_object (key, mime_type, file_name, data) VALUES (@key, @mime_type, @file_name, @data)", conn); + + cmd.Parameters.AddWithValue("key", NpgsqlTypes.NpgsqlDbType.Varchar, key); + cmd.Parameters.AddWithValue("mime_type", NpgsqlTypes.NpgsqlDbType.Varchar, mime_type); + cmd.Parameters.AddWithValue("file_name", NpgsqlTypes.NpgsqlDbType.Varchar, file_name); + cmd.Parameters.AddWithValue("data", NpgsqlTypes.NpgsqlDbType.Bytea, file_data); + + cmd.ExecuteNonQuery(); + } + catch(Exception e) + { + SetError(e.Message); + } } private void DoDelete() { - SetError("DoDelete"); + try + { + string? key = Request.Form["original_key"]; + + using var conn = new NpgsqlConnection(Config.Settings["ConnectionStrings:download"]); + + conn.Open(); + + using var delete_download = new NpgsqlCommand("DELETE FROM download WHERE key = @original_key", conn); + + delete_download.Parameters.AddWithValue("original_key", NpgsqlTypes.NpgsqlDbType.Varchar, key); + delete_download.ExecuteNonQuery(); + + using var delete_file = new NpgsqlCommand("DELETE FROM file_object WHERE key = @original_key", conn); + + delete_file.Parameters.AddWithValue("original_key", NpgsqlTypes.NpgsqlDbType.Varchar, key); + delete_file.ExecuteNonQuery(); + } + catch(Exception e) + { + SetError(e.Message); + } } private void DoUpdate() { - SetError("DoUpdate"); + try + { + string? original_key = Request.Form["original_key"]; + string? key = Request.Form["key"]; + string? mime_type = Request.Form["mime_type"]; + string? file_name = Request.Form["file_name"]; + IFormFile? file = Request.Form.Files.Count > 0 ? Request.Form.Files[0] : null; + + if (file != null) + { + using var file_stream = file.OpenReadStream(); + byte[] file_data = new byte[file.Length]; + file_stream.Read(file_data, 0, (int)file.Length); + + using var conn = new NpgsqlConnection(Config.Settings["ConnectionStrings:download"]); + + conn.Open(); + + using var cmd = new NpgsqlCommand("UPDATE file_object set key=@key, mime_type=@mime_type, file_name=@file_name, data=@data WHERE key=@original_key", conn); + + cmd.Parameters.AddWithValue("original_key", NpgsqlTypes.NpgsqlDbType.Varchar, original_key); + cmd.Parameters.AddWithValue("key", NpgsqlTypes.NpgsqlDbType.Varchar, key); + cmd.Parameters.AddWithValue("mime_type", NpgsqlTypes.NpgsqlDbType.Varchar, mime_type); + cmd.Parameters.AddWithValue("file_name", NpgsqlTypes.NpgsqlDbType.Varchar, file_name); + cmd.Parameters.AddWithValue("data", NpgsqlTypes.NpgsqlDbType.Bytea, file_data); + + cmd.ExecuteNonQuery(); + } + else + { + using var conn = new NpgsqlConnection(Config.Settings["ConnectionStrings:download"]); + + conn.Open(); + + using var cmd = new NpgsqlCommand("UPDATE file_object set key=@key, mime_type=@mime_type, file_name=@file_name WHERE key=@original_key", conn); + + cmd.Parameters.AddWithValue("original_key", NpgsqlTypes.NpgsqlDbType.Varchar, original_key); + cmd.Parameters.AddWithValue("key", NpgsqlTypes.NpgsqlDbType.Varchar, key); + cmd.Parameters.AddWithValue("mime_type", NpgsqlTypes.NpgsqlDbType.Varchar, mime_type); + cmd.Parameters.AddWithValue("file_name", NpgsqlTypes.NpgsqlDbType.Varchar, file_name); + + cmd.ExecuteNonQuery(); + } + + } + catch(Exception e) + { + SetError(e.Message); + } } private void LoadData() diff --git a/Pages/Privacy.cshtml b/Pages/Privacy.cshtml deleted file mode 100644 index 46ba966..0000000 --- a/Pages/Privacy.cshtml +++ /dev/null @@ -1,8 +0,0 @@ -@page -@model PrivacyModel -@{ - ViewData["Title"] = "Privacy Policy"; -} -<h1>@ViewData["Title"]</h1> - -<p>Use this page to detail your site's privacy policy.</p> diff --git a/Pages/Privacy.cshtml.cs b/Pages/Privacy.cshtml.cs deleted file mode 100644 index 9afceae..0000000 --- a/Pages/Privacy.cshtml.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; - -namespace download_admin.Pages; - -public class PrivacyModel : PageModel -{ - private readonly ILogger<PrivacyModel> _logger; - - public PrivacyModel(ILogger<PrivacyModel> logger) - { - _logger = logger; - } - - public void OnGet() - { - } -} - diff --git a/Pages/Report.cshtml b/Pages/Report.cshtml new file mode 100644 index 0000000..b928ef5 --- /dev/null +++ b/Pages/Report.cshtml @@ -0,0 +1,43 @@ +@page +@model download_admin.Pages.ReportModel + +@if (Model.HasError) +{ + <p style="color:red"><b>@Model.ErrorText</b></p> +} +<h1>Count for each key</h1> + +<table> + <tr> + <td style="width:50%;"><b>Key</b></td> + <td style="width:50%;"><b>Downloads</b></td> + </tr> + + @foreach (string t in Model.Keys) + { + <tr> + <td>@t</td> + <td>@Model.GetCount(t)</td> + </tr> + } +</table> + +<h1>Download Details</h1> + +<table> + <tr> + <td style="width:25%;"><b>Time</b></td> + <td style="width:25%;"><b>Key</b></td> + <td style="width:25%;"><b>IP Address</b></td> + <td style="width:25%;"><b>User Agent</b></td> + </tr> + @foreach(Download obj in Model.Rows) + { + <tr> + <td>@obj.Time</td> + <td>@obj.Key</td> + <td>@obj.IpAddress</td> + <td>@obj.UserAgent</td> + </tr> + } +</table>
\ No newline at end of file diff --git a/Pages/Report.cshtml.cs b/Pages/Report.cshtml.cs new file mode 100644 index 0000000..37e2c11 --- /dev/null +++ b/Pages/Report.cshtml.cs @@ -0,0 +1,111 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Npgsql; +using System.Collections.Generic; +using download_admin; + +namespace download_admin.Pages; + +public class ReportModel : PageModel +{ + public void OnGet() + { + ViewData["Title"] = "Download Repsoitory Report"; + + try + { + Rows = new List<Download>(); + + using var conn = new NpgsqlConnection(Config.Settings["ConnectionStrings:download"]); + + conn.Open(); + + using var cmd = new NpgsqlCommand("SELECT key, ip_address, user_agent, time FROM download ORDER BY time", conn); + using var reader = cmd.ExecuteReader(); + + while(reader.Read()) + { + string key = (string)reader["key"]; + string ip_address = (string)reader["ip_address"]; + string user_agent = (string)reader["user_agent"]; + DateTime time = (DateTime)reader["time"]; + + Rows.Add(new Download(key, ip_address, user_agent, time)); + } + } + catch(Exception e) + { + SetError(e.Message); + } + } + + private void SetError(string error_text) + { + HasError = true; + ErrorText = error_text; + } + + public List<string> Keys + { + get + { + var keys = new List<String>(); + + try + { + using var conn = new NpgsqlConnection(Config.Settings["ConnectionStrings:download"]); + + conn.Open(); + + using var cmd = new NpgsqlCommand("SELECT key FROM file_object ORDER BY key", conn); + using var reader = cmd.ExecuteReader(); + + while(reader.Read()) + { + string key = (string)reader["key"]; + keys.Add(key); + } + } + catch(Exception e) + { + SetError(e.Message); + } + + return keys; + } + + } + + public long GetCount(string key) + { + try + { + using var conn = new NpgsqlConnection(Config.Settings["ConnectionStrings:download"]); + + conn.Open(); + + using var cmd = new NpgsqlCommand("SELECT count(*) FROM download where key = @key", conn); + cmd.Parameters.AddWithValue("key", NpgsqlTypes.NpgsqlDbType.Varchar, key); + + object? scalar = cmd.ExecuteScalar(); + + if (scalar != null) + { + return (long)scalar; + } + } + catch(Exception e) + { + SetError(e.Message); + } + + return 0; + } + + public List<Download>? Rows {get;private set;} + + public bool HasError {get; private set;} + + public string? ErrorText {get; private set;} + +} diff --git a/Pages/Shared/_Layout.cshtml b/Pages/Shared/_Layout.cshtml index 86c0cc1..cc18cc7 100644 --- a/Pages/Shared/_Layout.cshtml +++ b/Pages/Shared/_Layout.cshtml @@ -3,7 +3,7 @@ <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <title>@ViewData["Title"] - download_admin</title> + <title>@ViewData["Title"]</title> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" /> <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" /> <link rel="stylesheet" href="~/download_admin.styles.css" asp-append-version="true" /> @@ -20,10 +20,10 @@ <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between"> <ul class="navbar-nav flex-grow-1"> <li class="nav-item"> - <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a> + <a class="nav-link text-dark" asp-area="" asp-page="/Index">Download Repository Editor</a> </li> <li class="nav-item"> - <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a> + <a class="nav-link text-dark" asp-area="" asp-page="/Report">Download Repository Report</a> </li> </ul> </div> @@ -38,14 +38,9 @@ <footer class="border-top footer text-muted"> <div class="container"> - © 2024 - download_admin - <a asp-area="" asp-page="/Privacy">Privacy</a> + © 2024 - <a href="http://deathstation9000.org.uk">download_admin</a> </div> </footer> - <script src="~/lib/jquery/dist/jquery.min.js"></script> - <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script> - <script src="~/js/site.js" asp-append-version="true"></script> - - @await RenderSectionAsync("Scripts", required: false) </body> </html>
\ No newline at end of file |