Skip to content

Commit

Permalink
Init
Browse files Browse the repository at this point in the history
First commit
  • Loading branch information
ludojmj authored Nov 10, 2021
0 parents commit 7882bf2
Show file tree
Hide file tree
Showing 77 changed files with 7,463 additions and 0 deletions.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2021 Ludovic, Jean, Michel Jarno

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
184 changes: 184 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# All-In-One CRUD

```bash
git clone https://github.com/ludojmj/svelte-netcore-identity.git
```

The aim of this project is to gather, in a single place, useful front and back ends development tools:

- A Database with SQLite;
- A Web API server with .NET Core 5.x;
- A Svelte JS client App;
- A link to an external service for identity management, authorization, and API security.

## Quick start (Development)

Server

```bash
cd <myfolder>/Server
dotnet run
```

Client

```bash
cd <myfolder>/client
npm install
npm run dev
```

---

## Inspiration

- SQLite database powered by: <https://www.sqlite.org>
- Server based on API mechanisms of: <https://reqres.in/api/whatever>
- Svelte template client borrowed from: <https://github.com/sveltejs/template.git>
- Identity service powered by: <https://demo.identityserver.io>
- Identity client borrowed from: <https://github.com/dopry/svelte-oidc>
- CSS borrowed from: <https://getbootstrap.com>
- SVG borrowed from: <https://creativecommons.org>

---

## Manufacturing process steps

### >>>>> SQLite database

#### Overwrite database if needed

```bash
cd <myfolder>
sqlite3 Server/App_Data/stuff.db < Server/App_Data/create_tables.sql
```

### >>>>> .NET Core 5.x Web API server

#### Create the server project

```bash
cd <myfolder>
dotnet new gitignore
dotnet new webapi -n Server
dotnet new xunit -n Server.UnitTest
```

#### Generate the model from the database for the Web API server

```bash
dotnet tool install --global dotnet-ef
cd <myfolder>/Server
dotnet ef dbcontext scaffold "Data Source=App_Data/stuff.db" Microsoft.EntityFrameworkCore.Sqlite \
--output-dir DbModels --context-dir DbModels --context StuffDbContext --force
```

#### Run the tests

```bash
cd <myfolder>/Server.UnitTest
dotnet restore
dotnet build
dotnet test
dotnet test /p:CollectCoverage=true
```

#### Run the Web API server

```bash
cd <myfolder>/Server
export ASPNETCORE_ENVIRONMENT=Development
dotnet run
```

### >>>>> Svelte client App

#### Create the client project

```bash
cd <myfolder>
git clone https://github.com/sveltejs/template.git
mv template myApp
```

#### Run the client App

```bash
cd <myfolder>/client
npm install
npm run dev
```

#### Possibly run a standalone version of the client App (mocking) except identity server

At the second line of the file:

> ```<myfolder>/client/src/api/stuff.js```
Swap isProd to !isProd:

> const rootApi = !isProd ? "https://localhost:5001/api/stuff" : "http://localhost:3000/mock/stuff";
---

## Troubleshooting

### _An error occured. Please try again later._

**When?**

- Creating a record in the SQLite database _stuff.db_ running Linux on Azure;
- The "real" error (not displayed in Production) is: _SQLite Error 5: 'database is locked'_;
- There is a restricted write access to the file on Linux web app when running on Azure.

**How to solve:**

- ==> Either use a real database or deploy the web app on Azure choosing Windows OS.

### _SQLite Error 1: 'no such table: t_stuff'_

**When?**

- Running the Svelte client App (```npm run dev```);
- Connecting to: <http://localhost:3000/>.

**How to solve:**

- ==> Create the database _stuff.db_ (```sqlite3 Server/App_Data/stuff.db < Server/App_Data/create_tables.sql```).

### _Network Error_

**When?**

- Running the Svelte client App (```npm run dev```);
- Connecting to: <http://localhost:3000/>.

**How to solve:**

- ==> Start the .NET Core server (```dotnet run```) before the Svelte client App (```npm run dev```).

### _Your connection is not private_ (NET::ERR_CERT_AUTHORITY_INVALID)

**When?**

- Running the .NET Core server (dotnet run);
- Connecting to: <http://localhost:5000/swagger>;
- Or connecting to its redirection: <https://localhost:5001/swagger>.

**How to solve:**

- ==> Click "Advanced settings" button;
- ==> Click on the link to continue to the assumed unsafe localhost site;
- ==> Accept self-signed localhost certificate.

### _You do not have permission to view this directory or page._

**When?**

- Browsing the web site on a Azure Windows instance.

**How to solve:**

- ==> Add the web.config file since you've got IIS running;
- ==> On Linux, the web.config file is useless
(Update your http headers according to the suitable Web Server configuration file).
168 changes: 168 additions & 0 deletions Server.UnitTest/Controllers/StuffControllerTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Moq;
using Xunit;
using Server.Controllers;
using Server.Models;
using Server.Repository.Interfaces;

namespace Server.UnitTest.Controllers
{
public class StuffControllerTest
{
private static readonly UserModel CurrentUserModelTest = new UserModel()
{
Id = "11",
Name = "GivenName FamilyName",
GivenName = "GivenName",
FamilyName = "FamilyName",
Email = "Email"
};

private static readonly DatumModel TestDatum = new DatumModel
{
Id = "1",
Label = "Label",
Description = "Description",
OtherInfo = "OtherInfo",
User = CurrentUserModelTest
};

private static readonly StuffModel TestStuff = new StuffModel
{
DatumList = new Collection<DatumModel>
{
TestDatum
}
};

// ***** ***** ***** LIST
[Fact]
public async Task StuffController_GetStuffList_ShouldReturn_Ok()
{
// Arrange
var mockStuffRepo = Mock.Of<IStuffRepo>(x => x.GetListAsync(1) == Task.FromResult(TestStuff));
var controller = new StuffController(mockStuffRepo);
int existingPage = 1;

// Act
IActionResult actionResult = await controller.GetList(existingPage, null);

// Assert
var okResult = Assert.IsType<OkObjectResult>(actionResult);
var contentResult = Assert.IsType<StuffModel>(okResult.Value);
var expected = TestDatum.Id;
var actual = contentResult.DatumList.ToArray()[0].Id;
Assert.Equal(expected, actual);
}

// ***** ***** ***** SEARCH
[Fact]
public async Task StuffController_SearchStuffList_ShouldReturn_Ok()
{
// Arrange
var mockStuffRepo = Mock.Of<IStuffRepo>(x => x.SearchListAsync("foo") == Task.FromResult(TestStuff));
var controller = new StuffController(mockStuffRepo);

// Act
IActionResult actionResult = await controller.GetList(0, "foo");

// Assert
var okResult = Assert.IsType<OkObjectResult>(actionResult);
var contentResult = Assert.IsType<StuffModel>(okResult.Value);
var expected = TestDatum.Id;
var actual = contentResult.DatumList.ToArray()[0].Id;
Assert.Equal(expected, actual);
}

// ***** ***** ***** CREATE
[Fact]
public async Task StuffController_Create_ShouldReturnCreated()
{
// Arrange
var mockStuffRepo = Mock.Of<IStuffRepo>(x => x.CreateAsync(TestDatum) == Task.FromResult(TestDatum));
var controller = new StuffController(mockStuffRepo);

// Act
IActionResult actionResult = await controller.Create(TestDatum);

// Assert
var okResult = Assert.IsType<CreatedAtActionResult>(actionResult);
var contentResult = Assert.IsType<DatumModel>(okResult.Value);
Assert.Equal(TestDatum.Id, contentResult.Id);
}

// ***** ***** ***** READ SINGLE
[Fact]
public async Task StuffController_Read_ShouldReturn_Ok()
{
// Arrange
var mockStuffRepo = Mock.Of<IStuffRepo>(x => x.ReadAsync("1") == Task.FromResult(TestDatum));
var controller = new StuffController(mockStuffRepo);

// Act
IActionResult actionResult = await controller.Read("1");

// Assert
var okResult = Assert.IsType<OkObjectResult>(actionResult);
var contentResult = Assert.IsType<DatumModel>(okResult.Value);
var expected = TestDatum.Id;
var actual = contentResult.Id;
Assert.Equal(expected, actual);
}

[Fact]
public async Task StuffController_Read_ShouldReturn_Null()
{
// Arrange
var mockUserRepo = Mock.Of<IStuffRepo>();
var controller = new StuffController(mockUserRepo);

// Act
IActionResult actionResult = await controller.Read("1");

// Assert
var okResult = Assert.IsType<OkObjectResult>(actionResult);
var contentResult = okResult.Value;
StuffModel expected = null;
var actual = contentResult;
Assert.Equal(expected, actual);
}

// ***** ***** ***** UPDATE
[Fact]
public async Task StuffController_UpdateStuff_ShouldReturn_Ok()
{
// Arrange
var mockStuffRepo = Mock.Of<IStuffRepo>(x => x.UpdateAsync("1", TestDatum) == Task.FromResult(TestDatum));
var controller = new StuffController(mockStuffRepo);
string existingId = "1";

// Act
IActionResult actionResult = await controller.Update(existingId, TestDatum);

// Assert
var okResult = Assert.IsType<OkObjectResult>(actionResult);
var contentResult = Assert.IsType<DatumModel>(okResult.Value);
Assert.Equal(TestDatum.Id, contentResult.Id);
}

// ***** ***** ***** DELETE
[Fact]
public async Task StuffController_DeleteStuff_ShouldReturnNoContent()
{
// Arrange
var mockStuffRepo = Mock.Of<IStuffRepo>();
var controller = new StuffController(mockStuffRepo);
string badId = "2";

// Act
IActionResult actionResult = await controller.Delete(badId);

// Assert
Assert.IsType<NoContentResult>(actionResult);
}
}
}
Loading

0 comments on commit 7882bf2

Please sign in to comment.