Compare commits
2 commits
49a13a412f
...
f571265130
Author | SHA1 | Date | |
---|---|---|---|
f571265130 | |||
19a2c0e631 |
12 changed files with 186 additions and 47 deletions
|
@ -9,7 +9,7 @@ using Snootalogue.Data;
|
|||
namespace snootalogue.Migrations
|
||||
{
|
||||
[DbContext(typeof(SnootalogueContext))]
|
||||
[Migration("20200915115113_InitialCreate")]
|
||||
[Migration("20200917125618_InitialCreate")]
|
||||
partial class InitialCreate
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
|
@ -25,7 +25,7 @@ namespace snootalogue.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Authors")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("jsonb");
|
||||
|
||||
b.Property<string>("Category")
|
||||
.HasColumnType("TEXT");
|
||||
|
@ -39,6 +39,9 @@ namespace snootalogue.Migrations
|
|||
b.Property<string>("Hash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("Read")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
|
@ -46,7 +49,7 @@ namespace snootalogue.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Tags")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("jsonb");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("TEXT");
|
|
@ -17,11 +17,12 @@ namespace snootalogue.Migrations
|
|||
Hash = table.Column<string>(nullable: true),
|
||||
Size = table.Column<long>(nullable: false),
|
||||
Title = table.Column<string>(nullable: true),
|
||||
Authors = table.Column<string>(nullable: true),
|
||||
Authors = table.Column<string>(type: "jsonb", nullable: true),
|
||||
Category = table.Column<string>(nullable: true),
|
||||
DateAdded = table.Column<DateTime>(nullable: false),
|
||||
Tags = table.Column<string>(nullable: true),
|
||||
Read = table.Column<bool>(nullable: false)
|
||||
Tags = table.Column<string>(type: "jsonb", nullable: true),
|
||||
Read = table.Column<bool>(nullable: false),
|
||||
Notes = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
|
@ -23,7 +23,7 @@ namespace snootalogue.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Authors")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("jsonb");
|
||||
|
||||
b.Property<string>("Category")
|
||||
.HasColumnType("TEXT");
|
||||
|
@ -37,6 +37,9 @@ namespace snootalogue.Migrations
|
|||
b.Property<string>("Hash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("Read")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
|
@ -44,7 +47,7 @@ namespace snootalogue.Migrations
|
|||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Tags")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("jsonb");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("TEXT");
|
||||
|
|
|
@ -15,10 +15,11 @@ namespace Snootalogue.Models {
|
|||
[UIHint("CommaSeparatedList")]
|
||||
public List<string> Authors { get; set; }
|
||||
public string Category { get; set; }
|
||||
[Display(Name = "Release Date")]
|
||||
[Display(Name = "Date added")]
|
||||
public DateTime DateAdded { get; set; }
|
||||
[UIHint("CommaSeparatedList")]
|
||||
public List<string> Tags { get; set; }
|
||||
public Boolean Read { get; set; }
|
||||
public string Notes { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
42
Pages/Documents/Edit.cshtml
Normal file
42
Pages/Documents/Edit.cshtml
Normal file
|
@ -0,0 +1,42 @@
|
|||
@page "{id:int}"
|
||||
@model Snootalogue.Pages.Documents.EditModel
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Edit";
|
||||
}
|
||||
|
||||
<form method="POST">
|
||||
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
||||
<input type="hidden" asp-for="ed.ID" />
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="ed.Title" class="control-label"></label>
|
||||
<input asp-for="ed.Title" class="form-control"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="ed.Category" class="control-label"></label>
|
||||
<input asp-for="ed.Category" class="form-control"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="ed.Notes" class="control-label"></label>
|
||||
@* <input asp-for="EditDocument.Notes" class="form-control"/> *@
|
||||
@Html.TextAreaFor(model => model.ed.Notes)
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="ed.Read" class="control-label"></label>
|
||||
<input asp-for="ed.Read" class="form-control"/>
|
||||
</div>
|
||||
|
||||
<div class="centred">
|
||||
<input type="submit" class="button block" value="Edit"/>
|
||||
<br>
|
||||
<a href="/" class="button block">Cancel</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
@* value="@Model.EditDocument.Title" *@
|
69
Pages/Documents/Edit.cshtml.cs
Normal file
69
Pages/Documents/Edit.cshtml.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Snootalogue.Data;
|
||||
using Snootalogue.Models;
|
||||
using Snootalogue.ViewModels;
|
||||
|
||||
namespace Snootalogue.Pages.Documents {
|
||||
public class EditModel : PageModel {
|
||||
private readonly SnootalogueContext _context;
|
||||
[BindProperty]
|
||||
public EditDocument ed { get; set; }
|
||||
|
||||
public EditModel(SnootalogueContext context) {
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnGetAsync(int? id) {
|
||||
if (id == null) {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var Document = await _context.Document.FirstOrDefaultAsync(d => d.ID == id);
|
||||
|
||||
if (Document == null) {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
ed = new EditDocument {
|
||||
ID = Document.ID,
|
||||
Title = Document.Title,
|
||||
Authors = Document.Authors,
|
||||
Category = Document.Category,
|
||||
Tags = Document.Tags,
|
||||
Read = Document.Read
|
||||
};
|
||||
|
||||
return Page();
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostAsync() {
|
||||
if (!ModelState.IsValid) {
|
||||
return Page();
|
||||
}
|
||||
|
||||
Document d = _context.Document.First(d => d.ID == ed.ID);
|
||||
d.Title = ed.Title;
|
||||
d.Category = ed.Category;
|
||||
d.Notes = ed.Notes;
|
||||
d.Read = ed.Read;
|
||||
|
||||
_context.Attach(d).State = EntityState.Modified;
|
||||
|
||||
try {
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e) {
|
||||
// TODO: handle it like https://github.com/dotnet/AspNetCore.Docs/blob/master/aspnetcore/tutorials/razor-pages/razor-pages-start/sample/RazorPagesMovie30/Pages/Movies/Edit.cshtml.cs#L56
|
||||
throw e;
|
||||
}
|
||||
|
||||
return RedirectToPage("/Index");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@
|
|||
<div class="vertical-buttons">
|
||||
<a href="/Content/@item.Filename" class="button simple">View</a>
|
||||
<a asp-page="./Documents/Details" asp-route-id="@item.ID" class="button simple">Details</a>
|
||||
<a href="#" class="button simple">Edit</a>
|
||||
<a asp-page="./Documents/Edit" asp-route-id="@item.ID" class="button simple">Edit</a>
|
||||
<a href="#" class="button simple">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<body>
|
||||
<nav>
|
||||
<div id="nav-links">Snootalogue</div>
|
||||
<div id="nav-links"><a href="/">Snootalogue</a></div>
|
||||
<div id="nav-controls">
|
||||
<input id="nav-search" type="search" placeholder="Search...">
|
||||
<a class="button inverted" href="#">Help</a>
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:37553",
|
||||
"sslPort": 44374
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"snootalogue": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
README.md
Normal file
21
README.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
Snootalogue
|
||||
===
|
||||
|
||||
A webapp for categorising, sharing and searching documents. Not at all ready for production in its current state.
|
||||
|
||||
## Dependencies
|
||||
You need the *ASP.NET Core Runtime* to run Snootalogue - the *.NET Core Runtime* on its own is not enough. The [.NET 3.1 download page](https://dotnet.microsoft.com/download/dotnet-core/3.1) provides links to the installers you'll need. Note that **no binaries are currently provided**, so you'll need to build Snootalogue yourself (see the Developing section below).
|
||||
|
||||
## Developing
|
||||
[Visual Studio Code](https://code.visualstudio.com/) provides great C# integration. Ensure you've installed the [.NET Core SDK](https://dotnet.microsoft.com/download) (not just the runtime) and the [Visual Studio Code C# Extension](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp), and you'll be good to go.
|
||||
|
||||
### Testing
|
||||
Snootalogue runs on port **5000**, so make sure you don't have anything currently using that port.
|
||||
|
||||
```bash
|
||||
git clone https://git.bune.city/lynnesbian/Snootalogue
|
||||
cd Snootalogue
|
||||
if ! which dotnet-ef; then dotnet tool install --global dotnet-ef; fi
|
||||
dotnet ef database update
|
||||
dotnet run
|
||||
```
|
22
ViewModels/EditDocument.cs
Normal file
22
ViewModels/EditDocument.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
// a version of the Document model designed for user editing
|
||||
|
||||
namespace Snootalogue.ViewModels {
|
||||
public class EditDocument {
|
||||
[Required]
|
||||
public int ID { get; set; }
|
||||
[Required]
|
||||
public string Title { get; set; }
|
||||
[UIHint("CommaSeparatedList")]
|
||||
public List<string> Authors { get; set; }
|
||||
public string Category { get; set; }
|
||||
[UIHint("CommaSeparatedList")]
|
||||
public List<string> Tags { get; set; }
|
||||
public Boolean Read { get; set; }
|
||||
public string Notes { get; set; }
|
||||
}
|
||||
}
|
|
@ -22,7 +22,8 @@ a {
|
|||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.button {
|
||||
.button {
|
||||
font-size: 1em;
|
||||
color: #a66;
|
||||
background: transparent;
|
||||
border: thin #a66 solid;
|
||||
|
@ -31,19 +32,19 @@ a.button {
|
|||
text-align: center;
|
||||
transition: 0.2s all;
|
||||
}
|
||||
a.button:hover {
|
||||
.button:hover {
|
||||
background: #a66;
|
||||
color: white;
|
||||
}
|
||||
a.button.block {
|
||||
.button.block {
|
||||
display: inline-block;
|
||||
margin: 5px auto;
|
||||
}
|
||||
a.button.inverted {
|
||||
.button.inverted {
|
||||
color: white;
|
||||
border-color: white;
|
||||
}
|
||||
a.button.inverted:hover {
|
||||
.button.inverted:hover {
|
||||
background: white;
|
||||
color: #a00;
|
||||
}
|
||||
|
@ -52,15 +53,15 @@ a.button.inverted:hover {
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.vertical-buttons a.button {
|
||||
.vertical-buttons .button {
|
||||
flex: 1;
|
||||
border-bottom: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
.vertical-buttons a.button:first-child {
|
||||
.vertical-buttons .button:first-child {
|
||||
border-radius: 5px 5px 0 0;
|
||||
}
|
||||
.vertical-buttons a.button:last-child {
|
||||
.vertical-buttons .button:last-child {
|
||||
border-bottom: thin #a66 solid;
|
||||
border-radius: 0 0 5px 5px;
|
||||
}
|
||||
|
@ -75,6 +76,9 @@ nav {
|
|||
#nav-links {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
#nav-links a {
|
||||
color: white;
|
||||
}
|
||||
#nav-links, #nav-search {
|
||||
margin: auto 0;
|
||||
}
|
||||
|
@ -156,7 +160,7 @@ main {
|
|||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
a.button {
|
||||
.button {
|
||||
padding: 3px 5px;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue