diff options
| -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 | 
