Compare commits

...

2 commits

12 changed files with 186 additions and 47 deletions

View file

@ -9,7 +9,7 @@ using Snootalogue.Data;
namespace snootalogue.Migrations namespace snootalogue.Migrations
{ {
[DbContext(typeof(SnootalogueContext))] [DbContext(typeof(SnootalogueContext))]
[Migration("20200915115113_InitialCreate")] [Migration("20200917125618_InitialCreate")]
partial class InitialCreate partial class InitialCreate
{ {
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -25,7 +25,7 @@ namespace snootalogue.Migrations
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<string>("Authors") b.Property<string>("Authors")
.HasColumnType("TEXT"); .HasColumnType("jsonb");
b.Property<string>("Category") b.Property<string>("Category")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
@ -39,6 +39,9 @@ namespace snootalogue.Migrations
b.Property<string>("Hash") b.Property<string>("Hash")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<string>("Notes")
.HasColumnType("TEXT");
b.Property<bool>("Read") b.Property<bool>("Read")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
@ -46,7 +49,7 @@ namespace snootalogue.Migrations
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<string>("Tags") b.Property<string>("Tags")
.HasColumnType("TEXT"); .HasColumnType("jsonb");
b.Property<string>("Title") b.Property<string>("Title")
.HasColumnType("TEXT"); .HasColumnType("TEXT");

View file

@ -17,11 +17,12 @@ namespace snootalogue.Migrations
Hash = table.Column<string>(nullable: true), Hash = table.Column<string>(nullable: true),
Size = table.Column<long>(nullable: false), Size = table.Column<long>(nullable: false),
Title = table.Column<string>(nullable: true), 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), Category = table.Column<string>(nullable: true),
DateAdded = table.Column<DateTime>(nullable: false), DateAdded = table.Column<DateTime>(nullable: false),
Tags = table.Column<string>(nullable: true), Tags = table.Column<string>(type: "jsonb", nullable: true),
Read = table.Column<bool>(nullable: false) Read = table.Column<bool>(nullable: false),
Notes = table.Column<string>(nullable: true)
}, },
constraints: table => constraints: table =>
{ {

View file

@ -23,7 +23,7 @@ namespace snootalogue.Migrations
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<string>("Authors") b.Property<string>("Authors")
.HasColumnType("TEXT"); .HasColumnType("jsonb");
b.Property<string>("Category") b.Property<string>("Category")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
@ -37,6 +37,9 @@ namespace snootalogue.Migrations
b.Property<string>("Hash") b.Property<string>("Hash")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<string>("Notes")
.HasColumnType("TEXT");
b.Property<bool>("Read") b.Property<bool>("Read")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
@ -44,7 +47,7 @@ namespace snootalogue.Migrations
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<string>("Tags") b.Property<string>("Tags")
.HasColumnType("TEXT"); .HasColumnType("jsonb");
b.Property<string>("Title") b.Property<string>("Title")
.HasColumnType("TEXT"); .HasColumnType("TEXT");

View file

@ -15,10 +15,11 @@ namespace Snootalogue.Models {
[UIHint("CommaSeparatedList")] [UIHint("CommaSeparatedList")]
public List<string> Authors { get; set; } public List<string> Authors { get; set; }
public string Category { get; set; } public string Category { get; set; }
[Display(Name = "Release Date")] [Display(Name = "Date added")]
public DateTime DateAdded { get; set; } public DateTime DateAdded { get; set; }
[UIHint("CommaSeparatedList")] [UIHint("CommaSeparatedList")]
public List<string> Tags { get; set; } public List<string> Tags { get; set; }
public Boolean Read { get; set; } public Boolean Read { get; set; }
public string Notes { get; set; }
} }
} }

View 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" *@

View 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");
}
}
}

View file

@ -28,7 +28,7 @@
<div class="vertical-buttons"> <div class="vertical-buttons">
<a href="/Content/@item.Filename" class="button simple">View</a> <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 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> <a href="#" class="button simple">Delete</a>
</div> </div>
</div> </div>

View file

@ -10,7 +10,7 @@
<body> <body>
<nav> <nav>
<div id="nav-links">Snootalogue</div> <div id="nav-links"><a href="/">Snootalogue</a></div>
<div id="nav-controls"> <div id="nav-controls">
<input id="nav-search" type="search" placeholder="Search..."> <input id="nav-search" type="search" placeholder="Search...">
<a class="button inverted" href="#">Help</a> <a class="button inverted" href="#">Help</a>

View file

@ -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
View 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
```

View 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; }
}
}

View file

@ -22,7 +22,8 @@ a {
text-decoration: none; text-decoration: none;
} }
a.button { .button {
font-size: 1em;
color: #a66; color: #a66;
background: transparent; background: transparent;
border: thin #a66 solid; border: thin #a66 solid;
@ -31,19 +32,19 @@ a.button {
text-align: center; text-align: center;
transition: 0.2s all; transition: 0.2s all;
} }
a.button:hover { .button:hover {
background: #a66; background: #a66;
color: white; color: white;
} }
a.button.block { .button.block {
display: inline-block; display: inline-block;
margin: 5px auto; margin: 5px auto;
} }
a.button.inverted { .button.inverted {
color: white; color: white;
border-color: white; border-color: white;
} }
a.button.inverted:hover { .button.inverted:hover {
background: white; background: white;
color: #a00; color: #a00;
} }
@ -52,15 +53,15 @@ a.button.inverted:hover {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.vertical-buttons a.button { .vertical-buttons .button {
flex: 1; flex: 1;
border-bottom: none; border-bottom: none;
border-radius: 0; border-radius: 0;
} }
.vertical-buttons a.button:first-child { .vertical-buttons .button:first-child {
border-radius: 5px 5px 0 0; border-radius: 5px 5px 0 0;
} }
.vertical-buttons a.button:last-child { .vertical-buttons .button:last-child {
border-bottom: thin #a66 solid; border-bottom: thin #a66 solid;
border-radius: 0 0 5px 5px; border-radius: 0 0 5px 5px;
} }
@ -75,6 +76,9 @@ nav {
#nav-links { #nav-links {
font-size: 1.4em; font-size: 1.4em;
} }
#nav-links a {
color: white;
}
#nav-links, #nav-search { #nav-links, #nav-search {
margin: auto 0; margin: auto 0;
} }
@ -156,7 +160,7 @@ main {
} }
@media only screen and (max-width: 800px) { @media only screen and (max-width: 800px) {
a.button { .button {
padding: 3px 5px; padding: 3px 5px;
} }
} }