Upload project.
This commit is contained in:
parent
36a582d89d
commit
00bf32859f
20
Aya-Backend/Aya-Backend.Tests/Aya-Backend.Tests.csproj
Normal file
20
Aya-Backend/Aya-Backend.Tests/Aya-Backend.Tests.csproj
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
<RootNamespace>Aya_Backend.Tests</RootNamespace>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="nunit" Version="3.12.0" />
|
||||||
|
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Aya-Backend\Aya-Backend.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -0,0 +1,36 @@
|
|||||||
|
using Aya_Backend.Controllers;
|
||||||
|
using Aya_Backend.Data;
|
||||||
|
using Aya_Backend.Data.Repositories.UserRepositories;
|
||||||
|
using Aya_Backend.Tests.Data;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class UserControllerTests
|
||||||
|
{
|
||||||
|
private readonly int validUserID = 2;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GetUser_CorrectUserReturned()
|
||||||
|
{
|
||||||
|
var expected = MockData.Users.FirstOrDefault(u => u.ID == validUserID);
|
||||||
|
var mockContext = new MockRepository(MockData.Users, null, null);
|
||||||
|
var controller = new UserController(mockContext);
|
||||||
|
|
||||||
|
var result = await controller.GetUser(validUserID);
|
||||||
|
|
||||||
|
Assert.IsNotNull(result);
|
||||||
|
var objectResult = result as OkObjectResult;
|
||||||
|
Assert.IsNotNull(objectResult);
|
||||||
|
var modelResult = objectResult.Value as User;
|
||||||
|
Assert.IsNotNull(modelResult);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected.ID, modelResult.ID);
|
||||||
|
Assert.AreEqual(expected.Username, modelResult.Username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class WorkbookControllerTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void Test1()
|
||||||
|
{
|
||||||
|
Assert.Pass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class WorkpageControllerTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void Test1()
|
||||||
|
{
|
||||||
|
Assert.Pass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
Aya-Backend/Aya-Backend.Tests/Data/MockData.cs
Normal file
17
Aya-Backend/Aya-Backend.Tests/Data/MockData.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using Aya_Backend.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Tests.Data
|
||||||
|
{
|
||||||
|
public static class MockData
|
||||||
|
{
|
||||||
|
public static List<User> Users = new List<User>
|
||||||
|
{
|
||||||
|
new User() { ID = 1, Username = "User 1" },
|
||||||
|
new User() { ID = 2, Username = "User 2" },
|
||||||
|
new User() { ID = 3, Username = "User 3" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
[assembly: System.Reflection.AssemblyCompanyAttribute("Aya-Backend.Tests")]
|
||||||
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
|
||||||
|
[assembly: System.Reflection.AssemblyProductAttribute("Aya-Backend.Tests")]
|
||||||
|
[assembly: System.Reflection.AssemblyTitleAttribute("Aya-Backend.Tests")]
|
||||||
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|
||||||
|
// Generated by the MSBuild WriteCodeFragment class.
|
||||||
|
|
31
Aya-Backend/Aya-Backend.sln
Normal file
31
Aya-Backend/Aya-Backend.sln
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.29728.190
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aya-Backend", "Aya-Backend\Aya-Backend.csproj", "{150093C3-BCCB-49E6-B39E-74E2BC7831E5}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aya-Backend.Tests", "Aya-Backend.Tests\Aya-Backend.Tests.csproj", "{ADE9EB7C-FBCE-4498-B9F2-8164115F0492}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{150093C3-BCCB-49E6-B39E-74E2BC7831E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{150093C3-BCCB-49E6-B39E-74E2BC7831E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{150093C3-BCCB-49E6-B39E-74E2BC7831E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{150093C3-BCCB-49E6-B39E-74E2BC7831E5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{ADE9EB7C-FBCE-4498-B9F2-8164115F0492}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{ADE9EB7C-FBCE-4498-B9F2-8164115F0492}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{ADE9EB7C-FBCE-4498-B9F2-8164115F0492}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{ADE9EB7C-FBCE-4498-B9F2-8164115F0492}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {288D4B34-3BEA-4CF7-8E3F-7F7AED944F18}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
34
Aya-Backend/Aya-Backend/Aya-Backend.csproj
Normal file
34
Aya-Backend/Aya-Backend/Aya-Backend.csproj
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
<RootNamespace>Aya_Backend</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="Data\Migrations\20200503195721_InitialCreate.cs" />
|
||||||
|
<Compile Remove="Data\Migrations\20200503195721_InitialCreate.Designer.cs" />
|
||||||
|
<Compile Remove="Data\Migrations\20200503223253_AddContentToWorkpage.cs" />
|
||||||
|
<Compile Remove="Data\Migrations\20200503223253_AddContentToWorkpage.Designer.cs" />
|
||||||
|
<Compile Remove="Data\Migrations\20200504225546_BetterWorkpageSeedData.cs" />
|
||||||
|
<Compile Remove="Data\Migrations\20200504225546_BetterWorkpageSeedData.Designer.cs" />
|
||||||
|
<Compile Remove="Data\Migrations\20200505163516_PrimaryKeysIdToInt.cs" />
|
||||||
|
<Compile Remove="Data\Migrations\20200505163516_PrimaryKeysIdToInt.Designer.cs" />
|
||||||
|
<Compile Remove="Data\Migrations\20200505223715_User-Store.cs" />
|
||||||
|
<Compile Remove="Data\Migrations\20200505223715_User-Store.Designer.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.3" />
|
||||||
|
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="3.1.3" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.3" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.3" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.3">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
</Project>
|
67
Aya-Backend/Aya-Backend/Controllers/UserController.cs
Normal file
67
Aya-Backend/Aya-Backend/Controllers/UserController.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Aya_Backend.Data;
|
||||||
|
using Aya_Backend.Data.Repositories.UserRepositories;
|
||||||
|
using Aya_Backend.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Controllers
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class UserController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IRepository _context;
|
||||||
|
private readonly IUserService _userService;
|
||||||
|
|
||||||
|
public UserController(IRepository context, IUserService userService)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns the user object of the user currently logged in (from token passed).
|
||||||
|
[Route("get")]
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetUser()
|
||||||
|
{
|
||||||
|
string userId = User.FindFirst(ClaimTypes.Name)?.Value;
|
||||||
|
var user = _context.GetUser(Int32.Parse(userId));
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
return NotFound();
|
||||||
|
return Ok(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns the user object if login credentials are valid (user object includes jwt token).
|
||||||
|
[AllowAnonymous]
|
||||||
|
[Route("login")]
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> Login([FromBody] LoginDTO login)
|
||||||
|
{
|
||||||
|
var user = _userService.Authenticate(login.Username, login.Password);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
return Ok(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Creates a new user object with the credentials passed and authenticates them.
|
||||||
|
[AllowAnonymous]
|
||||||
|
[Route("create")]
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> CreateAccount([FromBody] LoginDTO account)
|
||||||
|
{
|
||||||
|
var user = _context.AddUser(new User() { Username = account.Username, Password = account.Password });
|
||||||
|
|
||||||
|
return Ok(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
Aya-Backend/Aya-Backend/Controllers/WorkbookController.cs
Normal file
59
Aya-Backend/Aya-Backend/Controllers/WorkbookController.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Aya_Backend.Data.Repositories.UserRepositories;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Controllers
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class WorkbookController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IRepository _context;
|
||||||
|
|
||||||
|
public WorkbookController(IRepository context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Gets a workbook if the logged in user is owner of the workbook.
|
||||||
|
[Route("get")]
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetWorkbook(int id)
|
||||||
|
{
|
||||||
|
string userId = User.FindFirst(ClaimTypes.Name)?.Value;
|
||||||
|
|
||||||
|
var workbook = _context.GetWorkbook(id);
|
||||||
|
if (workbook.OwnerID != Int32.Parse(userId))
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
return Ok(workbook);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Adds a workbook to the user currently logged in.
|
||||||
|
[Route("add")]
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> AddWorkbook(string name)
|
||||||
|
{
|
||||||
|
string userId = User.FindFirst(ClaimTypes.Name)?.Value;
|
||||||
|
|
||||||
|
return Ok(_context.AddWorkbook(name, Int32.Parse(userId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Gets a list of all of the workbooks that belong to that user.
|
||||||
|
[Route("userworkbooks")]
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetUserWorkbooks()
|
||||||
|
{
|
||||||
|
Console.WriteLine("workbook");
|
||||||
|
string userId = User.FindFirst(ClaimTypes.Name)?.Value;
|
||||||
|
return Ok(_context.GetUserWorkbooks(Int32.Parse(userId)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
86
Aya-Backend/Aya-Backend/Controllers/WorkpageController.cs
Normal file
86
Aya-Backend/Aya-Backend/Controllers/WorkpageController.cs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Aya_Backend.Data;
|
||||||
|
using Aya_Backend.Data.Repositories.UserRepositories;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Controllers
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class WorkpageController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IRepository _context;
|
||||||
|
|
||||||
|
public WorkpageController(IRepository context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns a workpage, aslong as the user is owner.
|
||||||
|
[Route("get")]
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetWorkpage(int id)
|
||||||
|
{
|
||||||
|
string userId = User.FindFirst(ClaimTypes.Name)?.Value;
|
||||||
|
int workpageOwner = _context.GetWorkpageOwnerID(id);
|
||||||
|
|
||||||
|
if (workpageOwner != Int32.Parse(userId))
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
return Ok(_context.GetWorkpage(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns a list of the workpages from a workbook (given a workbook id).
|
||||||
|
//Only returns them if the workbook belongs to the user.
|
||||||
|
[Route("fromworkbook")]
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetFromWorkbook(int id)
|
||||||
|
{
|
||||||
|
string userId = User.FindFirst(ClaimTypes.Name)?.Value;
|
||||||
|
var workbook = _context.GetWorkbook(id);
|
||||||
|
|
||||||
|
if (workbook.OwnerID != Int32.Parse(userId))
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
return Ok(_context.GetWorkbookWorkpages(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Adds a workpage with the given name and workbookid, aslong as they are the owner of the workbook.
|
||||||
|
[Route("add")]
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> AddWorkpage(string name, int workbookid)
|
||||||
|
{
|
||||||
|
string userId = User.FindFirst(ClaimTypes.Name)?.Value;
|
||||||
|
var workbook = _context.GetWorkbook(workbookid);
|
||||||
|
|
||||||
|
if (workbook.OwnerID != Int32.Parse(userId))
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
var wp = new Workpage() { Name = name, WorkbookID = workbookid, Content = String.Empty };
|
||||||
|
_context.AddWorkpage(wp);
|
||||||
|
return Ok("true");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Updates the content of a workpage from the request body, as long as they are the owner of the workbook.
|
||||||
|
[Route("updateworkpagecontent")]
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> UpdateWorkpageContent(int id, [FromBody] string content)
|
||||||
|
{
|
||||||
|
string userId = User.FindFirst(ClaimTypes.Name)?.Value;
|
||||||
|
var workbook = _context.GetWorkbook(id);
|
||||||
|
|
||||||
|
if (workbook.OwnerID != Int32.Parse(userId))
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
_context.UpdateWorkbookContent(id, content);
|
||||||
|
return Ok("true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
61
Aya-Backend/Aya-Backend/Data/AyaContext.cs
Normal file
61
Aya-Backend/Aya-Backend/Data/AyaContext.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data.Repositories
|
||||||
|
{
|
||||||
|
public class AyaContext : DbContext
|
||||||
|
{
|
||||||
|
public DbSet<User> Users { get; set; }
|
||||||
|
public DbSet<Workbook> Workbooks { get; set; }
|
||||||
|
public DbSet<Workpage> Workpages { get; set; }
|
||||||
|
|
||||||
|
private IHostingEnvironment HostEnv { get; }
|
||||||
|
|
||||||
|
public AyaContext(DbContextOptions<AyaContext> options, IHostingEnvironment env) : base(options)
|
||||||
|
{
|
||||||
|
HostEnv = env;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
||||||
|
=> options.UseSqlite("Data Source=aya.db");
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
|
if (HostEnv != null && HostEnv.IsDevelopment())
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<User>()
|
||||||
|
.HasData(
|
||||||
|
new User() { ID = 1, Username = "User1", Password = "Password1_" },
|
||||||
|
new User() { ID = 2, Username = "User2", Password = "Password2_" },
|
||||||
|
new User() { ID = 3, Username = "User3", Password = "Password3_" }
|
||||||
|
);
|
||||||
|
|
||||||
|
modelBuilder.Entity<Workbook>()
|
||||||
|
.HasData(
|
||||||
|
new Workbook() { ID = 1, Name = "Workbook 1", OwnerID = 1 },
|
||||||
|
new Workbook() { ID = 2, Name = "Workbook 2", OwnerID = 1 },
|
||||||
|
new Workbook() { ID = 3, Name = "Workbook 3", OwnerID = 2 },
|
||||||
|
new Workbook() { ID = 4, Name = "Workbook 4", OwnerID = 2 },
|
||||||
|
new Workbook() { ID = 5, Name = "Workbook 5", OwnerID = 3 }
|
||||||
|
);
|
||||||
|
|
||||||
|
modelBuilder.Entity<Workpage>()
|
||||||
|
.HasData(
|
||||||
|
new Workpage() { ID = 1, Name = "Workpage 1", WorkbookID = 1, Content = "Content 1" },
|
||||||
|
new Workpage() { ID = 2, Name = "Workpage 2", WorkbookID = 1, Content = "Content 2" },
|
||||||
|
new Workpage() { ID = 3, Name = "Workpage 3", WorkbookID = 1, Content = "Content 3" },
|
||||||
|
new Workpage() { ID = 4, Name = "Workpage 4", WorkbookID = 1, Content = "Content 4" },
|
||||||
|
new Workpage() { ID = 5, Name = "Workpage 5", WorkbookID = 2, Content = "Content 5" },
|
||||||
|
new Workpage() { ID = 6, Name = "Workpage 6", WorkbookID = 2, Content = "Content 6" },
|
||||||
|
new Workpage() { ID = 7, Name = "Workpage 7", WorkbookID = 3, Content = "Content 7" }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
Aya-Backend/Aya-Backend/Data/LoginDTO.cs
Normal file
13
Aya-Backend/Aya-Backend/Data/LoginDTO.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data
|
||||||
|
{
|
||||||
|
public class LoginDTO
|
||||||
|
{
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
}
|
195
Aya-Backend/Aya-Backend/Data/Migrations/20200505164438_InitialFix.Designer.cs
generated
Normal file
195
Aya-Backend/Aya-Backend/Data/Migrations/20200505164438_InitialFix.Designer.cs
generated
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using Aya_Backend.Data.Repositories;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AyaContext))]
|
||||||
|
[Migration("20200505164438_InitialFix")]
|
||||||
|
partial class InitialFix
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.3");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 1,
|
||||||
|
Username = "User1"
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 2,
|
||||||
|
Username = "User2"
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 3,
|
||||||
|
Username = "User3"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.Workbook", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerID")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerID");
|
||||||
|
|
||||||
|
b.ToTable("Workbooks");
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 1,
|
||||||
|
Name = "Workbook 1",
|
||||||
|
OwnerID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 2,
|
||||||
|
Name = "Workbook 2",
|
||||||
|
OwnerID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 3,
|
||||||
|
Name = "Workbook 3",
|
||||||
|
OwnerID = 2
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 4,
|
||||||
|
Name = "Workbook 4",
|
||||||
|
OwnerID = 2
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 5,
|
||||||
|
Name = "Workbook 5",
|
||||||
|
OwnerID = 3
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.Workpage", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("WorkbookID")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("WorkbookID");
|
||||||
|
|
||||||
|
b.ToTable("Workpages");
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 1,
|
||||||
|
Content = "Content 1",
|
||||||
|
Name = "Workpage 1",
|
||||||
|
WorkbookID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 2,
|
||||||
|
Content = "Content 2",
|
||||||
|
Name = "Workpage 2",
|
||||||
|
WorkbookID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 3,
|
||||||
|
Content = "Content 3",
|
||||||
|
Name = "Workpage 3",
|
||||||
|
WorkbookID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 4,
|
||||||
|
Content = "Content 4",
|
||||||
|
Name = "Workpage 4",
|
||||||
|
WorkbookID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 5,
|
||||||
|
Content = "Content 5",
|
||||||
|
Name = "Workpage 5",
|
||||||
|
WorkbookID = 2
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 6,
|
||||||
|
Content = "Content 6",
|
||||||
|
Name = "Workpage 6",
|
||||||
|
WorkbookID = 2
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 7,
|
||||||
|
Content = "Content 7",
|
||||||
|
Name = "Workpage 7",
|
||||||
|
WorkbookID = 3
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.Workbook", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aya_Backend.Data.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.Workpage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aya_Backend.Data.Workbook", "Workbook")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("WorkbookID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,161 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data.Migrations
|
||||||
|
{
|
||||||
|
public partial class InitialFix : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Users",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
ID = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Username = table.Column<string>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Users", x => x.ID);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Workbooks",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
ID = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Name = table.Column<string>(nullable: true),
|
||||||
|
OwnerID = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Workbooks", x => x.ID);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Workbooks_Users_OwnerID",
|
||||||
|
column: x => x.OwnerID,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "ID",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Workpages",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
ID = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Name = table.Column<string>(nullable: true),
|
||||||
|
Content = table.Column<string>(nullable: true),
|
||||||
|
WorkbookID = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Workpages", x => x.ID);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Workpages_Workbooks_WorkbookID",
|
||||||
|
column: x => x.WorkbookID,
|
||||||
|
principalTable: "Workbooks",
|
||||||
|
principalColumn: "ID",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Users",
|
||||||
|
columns: new[] { "ID", "Username" },
|
||||||
|
values: new object[] { 1, "User1" });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Users",
|
||||||
|
columns: new[] { "ID", "Username" },
|
||||||
|
values: new object[] { 2, "User2" });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Users",
|
||||||
|
columns: new[] { "ID", "Username" },
|
||||||
|
values: new object[] { 3, "User3" });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Workbooks",
|
||||||
|
columns: new[] { "ID", "Name", "OwnerID" },
|
||||||
|
values: new object[] { 1, "Workbook 1", 1 });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Workbooks",
|
||||||
|
columns: new[] { "ID", "Name", "OwnerID" },
|
||||||
|
values: new object[] { 2, "Workbook 2", 1 });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Workbooks",
|
||||||
|
columns: new[] { "ID", "Name", "OwnerID" },
|
||||||
|
values: new object[] { 3, "Workbook 3", 2 });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Workbooks",
|
||||||
|
columns: new[] { "ID", "Name", "OwnerID" },
|
||||||
|
values: new object[] { 4, "Workbook 4", 2 });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Workbooks",
|
||||||
|
columns: new[] { "ID", "Name", "OwnerID" },
|
||||||
|
values: new object[] { 5, "Workbook 5", 3 });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Workpages",
|
||||||
|
columns: new[] { "ID", "Content", "Name", "WorkbookID" },
|
||||||
|
values: new object[] { 1, "Content 1", "Workpage 1", 1 });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Workpages",
|
||||||
|
columns: new[] { "ID", "Content", "Name", "WorkbookID" },
|
||||||
|
values: new object[] { 2, "Content 2", "Workpage 2", 1 });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Workpages",
|
||||||
|
columns: new[] { "ID", "Content", "Name", "WorkbookID" },
|
||||||
|
values: new object[] { 3, "Content 3", "Workpage 3", 1 });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Workpages",
|
||||||
|
columns: new[] { "ID", "Content", "Name", "WorkbookID" },
|
||||||
|
values: new object[] { 4, "Content 4", "Workpage 4", 1 });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Workpages",
|
||||||
|
columns: new[] { "ID", "Content", "Name", "WorkbookID" },
|
||||||
|
values: new object[] { 5, "Content 5", "Workpage 5", 2 });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Workpages",
|
||||||
|
columns: new[] { "ID", "Content", "Name", "WorkbookID" },
|
||||||
|
values: new object[] { 6, "Content 6", "Workpage 6", 2 });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Workpages",
|
||||||
|
columns: new[] { "ID", "Content", "Name", "WorkbookID" },
|
||||||
|
values: new object[] { 7, "Content 7", "Workpage 7", 3 });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Workbooks_OwnerID",
|
||||||
|
table: "Workbooks",
|
||||||
|
column: "OwnerID");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Workpages_WorkbookID",
|
||||||
|
table: "Workpages",
|
||||||
|
column: "WorkbookID");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Workpages");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Workbooks");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
204
Aya-Backend/Aya-Backend/Data/Migrations/20200505223849_User-Store.Designer.cs
generated
Normal file
204
Aya-Backend/Aya-Backend/Data/Migrations/20200505223849_User-Store.Designer.cs
generated
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using Aya_Backend.Data.Repositories;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AyaContext))]
|
||||||
|
[Migration("20200505223849_User-Store")]
|
||||||
|
partial class UserStore
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.3");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Token")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 1,
|
||||||
|
Password = "Password1_",
|
||||||
|
Username = "User1"
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 2,
|
||||||
|
Password = "Password2_",
|
||||||
|
Username = "User2"
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 3,
|
||||||
|
Password = "Password3_",
|
||||||
|
Username = "User3"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.Workbook", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerID")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerID");
|
||||||
|
|
||||||
|
b.ToTable("Workbooks");
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 1,
|
||||||
|
Name = "Workbook 1",
|
||||||
|
OwnerID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 2,
|
||||||
|
Name = "Workbook 2",
|
||||||
|
OwnerID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 3,
|
||||||
|
Name = "Workbook 3",
|
||||||
|
OwnerID = 2
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 4,
|
||||||
|
Name = "Workbook 4",
|
||||||
|
OwnerID = 2
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 5,
|
||||||
|
Name = "Workbook 5",
|
||||||
|
OwnerID = 3
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.Workpage", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("WorkbookID")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("WorkbookID");
|
||||||
|
|
||||||
|
b.ToTable("Workpages");
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 1,
|
||||||
|
Content = "Content 1",
|
||||||
|
Name = "Workpage 1",
|
||||||
|
WorkbookID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 2,
|
||||||
|
Content = "Content 2",
|
||||||
|
Name = "Workpage 2",
|
||||||
|
WorkbookID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 3,
|
||||||
|
Content = "Content 3",
|
||||||
|
Name = "Workpage 3",
|
||||||
|
WorkbookID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 4,
|
||||||
|
Content = "Content 4",
|
||||||
|
Name = "Workpage 4",
|
||||||
|
WorkbookID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 5,
|
||||||
|
Content = "Content 5",
|
||||||
|
Name = "Workpage 5",
|
||||||
|
WorkbookID = 2
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 6,
|
||||||
|
Content = "Content 6",
|
||||||
|
Name = "Workpage 6",
|
||||||
|
WorkbookID = 2
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 7,
|
||||||
|
Content = "Content 7",
|
||||||
|
Name = "Workpage 7",
|
||||||
|
WorkbookID = 3
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.Workbook", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aya_Backend.Data.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.Workpage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aya_Backend.Data.Workbook", "Workbook")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("WorkbookID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data.Migrations
|
||||||
|
{
|
||||||
|
public partial class UserStore : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Password",
|
||||||
|
table: "Users",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Token",
|
||||||
|
table: "Users",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "Users",
|
||||||
|
keyColumn: "ID",
|
||||||
|
keyValue: 1,
|
||||||
|
column: "Password",
|
||||||
|
value: "Password1_");
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "Users",
|
||||||
|
keyColumn: "ID",
|
||||||
|
keyValue: 2,
|
||||||
|
column: "Password",
|
||||||
|
value: "Password2_");
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "Users",
|
||||||
|
keyColumn: "ID",
|
||||||
|
keyValue: 3,
|
||||||
|
column: "Password",
|
||||||
|
value: "Password3_");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Password",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Token",
|
||||||
|
table: "Users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,202 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using Aya_Backend.Data.Repositories;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AyaContext))]
|
||||||
|
partial class AyaContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.3");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Token")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 1,
|
||||||
|
Password = "Password1_",
|
||||||
|
Username = "User1"
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 2,
|
||||||
|
Password = "Password2_",
|
||||||
|
Username = "User2"
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 3,
|
||||||
|
Password = "Password3_",
|
||||||
|
Username = "User3"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.Workbook", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerID")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerID");
|
||||||
|
|
||||||
|
b.ToTable("Workbooks");
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 1,
|
||||||
|
Name = "Workbook 1",
|
||||||
|
OwnerID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 2,
|
||||||
|
Name = "Workbook 2",
|
||||||
|
OwnerID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 3,
|
||||||
|
Name = "Workbook 3",
|
||||||
|
OwnerID = 2
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 4,
|
||||||
|
Name = "Workbook 4",
|
||||||
|
OwnerID = 2
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 5,
|
||||||
|
Name = "Workbook 5",
|
||||||
|
OwnerID = 3
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.Workpage", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("WorkbookID")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("WorkbookID");
|
||||||
|
|
||||||
|
b.ToTable("Workpages");
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 1,
|
||||||
|
Content = "Content 1",
|
||||||
|
Name = "Workpage 1",
|
||||||
|
WorkbookID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 2,
|
||||||
|
Content = "Content 2",
|
||||||
|
Name = "Workpage 2",
|
||||||
|
WorkbookID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 3,
|
||||||
|
Content = "Content 3",
|
||||||
|
Name = "Workpage 3",
|
||||||
|
WorkbookID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 4,
|
||||||
|
Content = "Content 4",
|
||||||
|
Name = "Workpage 4",
|
||||||
|
WorkbookID = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 5,
|
||||||
|
Content = "Content 5",
|
||||||
|
Name = "Workpage 5",
|
||||||
|
WorkbookID = 2
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 6,
|
||||||
|
Content = "Content 6",
|
||||||
|
Name = "Workpage 6",
|
||||||
|
WorkbookID = 2
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
ID = 7,
|
||||||
|
Content = "Content 7",
|
||||||
|
Name = "Workpage 7",
|
||||||
|
WorkbookID = 3
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.Workbook", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aya_Backend.Data.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Aya_Backend.Data.Workpage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Aya_Backend.Data.Workbook", "Workbook")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("WorkbookID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
Aya-Backend/Aya-Backend/Data/Repositories/IRepository.cs
Normal file
30
Aya-Backend/Aya-Backend/Data/Repositories/IRepository.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data.Repositories.UserRepositories
|
||||||
|
{
|
||||||
|
public interface IRepository
|
||||||
|
{
|
||||||
|
//Interface for getting values from a dataset (Database/Mocked data).
|
||||||
|
//User
|
||||||
|
public User GetUser(int id);
|
||||||
|
public User GetUserAuth(string username, string password);
|
||||||
|
public User AddUser(User user);
|
||||||
|
public void UpdateUser(User user);
|
||||||
|
|
||||||
|
//Workbook
|
||||||
|
public Workbook GetWorkbook(int id);
|
||||||
|
public Workbook AddWorkbook(string name, int ownerid);
|
||||||
|
public List<Workbook> GetUserWorkbooks(int id);
|
||||||
|
|
||||||
|
//Workpage
|
||||||
|
public Workpage GetWorkpage(int id);
|
||||||
|
public void AddWorkpage(Workpage wp);
|
||||||
|
public List<Workpage> GetWorkbookWorkpages(int id);
|
||||||
|
public void UpdateWorkbookContent(int id, string content);
|
||||||
|
|
||||||
|
public int GetWorkpageOwnerID(int id);
|
||||||
|
}
|
||||||
|
}
|
95
Aya-Backend/Aya-Backend/Data/Repositories/MockRepository.cs
Normal file
95
Aya-Backend/Aya-Backend/Data/Repositories/MockRepository.cs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data.Repositories.UserRepositories
|
||||||
|
{
|
||||||
|
|
||||||
|
//Mock repository to use for testing. Gets passed mock data in the form of lists upon construction.
|
||||||
|
public class MockRepository : IRepository
|
||||||
|
{
|
||||||
|
private List<User> MockUsers { get; }
|
||||||
|
private List<Workbook> MockWorkbooks { get; }
|
||||||
|
private List<Workpage> MockWorkpages { get; }
|
||||||
|
|
||||||
|
public MockRepository(List<User> users, List<Workbook> workbooks, List<Workpage> workpages)
|
||||||
|
{
|
||||||
|
MockUsers = users;
|
||||||
|
MockWorkbooks = workbooks;
|
||||||
|
MockWorkpages = workpages;
|
||||||
|
}
|
||||||
|
|
||||||
|
//User
|
||||||
|
public User GetUser(int id)
|
||||||
|
{
|
||||||
|
return MockUsers.FirstOrDefault(user => user.ID == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public User AddUser(User user)
|
||||||
|
{
|
||||||
|
MockUsers.Add(user);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Workbook
|
||||||
|
public Workbook GetWorkbook(int id)
|
||||||
|
{
|
||||||
|
return MockWorkbooks.FirstOrDefault(wb => wb.ID == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Workbook AddWorkbook(string name, int ownerid)
|
||||||
|
{
|
||||||
|
|
||||||
|
var workbook = new Workbook() { ID = 10, Name = name, OwnerID = ownerid };
|
||||||
|
MockWorkbooks.Add(workbook);
|
||||||
|
return workbook;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Workbook> GetUserWorkbooks(int id)
|
||||||
|
{
|
||||||
|
return MockWorkbooks.Where(wb => wb.OwnerID == id).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Workpage GetWorkpage(int id)
|
||||||
|
{
|
||||||
|
return MockWorkpages.FirstOrDefault(wp => wp.ID == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddWorkpage(Workpage wp)
|
||||||
|
{
|
||||||
|
MockWorkpages.Add(wp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Workpage> GetWorkbookWorkpages(int id)
|
||||||
|
{
|
||||||
|
return MockWorkpages.Where(wp => wp.WorkbookID == id).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateWorkbookContent(int id, string content)
|
||||||
|
{
|
||||||
|
var workpage = MockWorkpages.FirstOrDefault(wp => wp.ID == id);
|
||||||
|
workpage.Content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Workbook AddWorkbook(string name, string ownerid)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public User GetUserAuth(string username, string password)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateUser(User user)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetWorkpageOwnerID(int id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
Aya-Backend/Aya-Backend/Data/Repositories/Repository.cs
Normal file
94
Aya-Backend/Aya-Backend/Data/Repositories/Repository.cs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data.Repositories.UserRepositories
|
||||||
|
{
|
||||||
|
public class Repository : IRepository
|
||||||
|
{
|
||||||
|
private readonly AyaContext _context;
|
||||||
|
|
||||||
|
public Repository(AyaContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
//User
|
||||||
|
public User GetUser(int id)
|
||||||
|
{
|
||||||
|
return _context.Users.FirstOrDefault(u => u.ID == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public User GetUserAuth(string username, string password)
|
||||||
|
{
|
||||||
|
return _context.Users.FirstOrDefault(u => u.Username == username && u.Password == password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public User AddUser(User user)
|
||||||
|
{
|
||||||
|
var u = _context.Add(user);
|
||||||
|
_context.SaveChanges();
|
||||||
|
return u.Entity;
|
||||||
|
}
|
||||||
|
public void UpdateUser(User user)
|
||||||
|
{
|
||||||
|
_context.Update(user);
|
||||||
|
_context.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Workbook
|
||||||
|
public Workbook GetWorkbook(int id)
|
||||||
|
{
|
||||||
|
return _context.Workbooks.FirstOrDefault(u => u.ID == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Workbook AddWorkbook(string name, int ownerid)
|
||||||
|
{
|
||||||
|
var added = _context.Add(new Workbook { Name = name, OwnerID = ownerid });
|
||||||
|
_context.SaveChangesAsync();
|
||||||
|
return added.Entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Workbook> GetUserWorkbooks(int id)
|
||||||
|
{
|
||||||
|
return _context.Workbooks.Where(wb => wb.OwnerID == id).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Workpage
|
||||||
|
public Workpage GetWorkpage(int id)
|
||||||
|
{
|
||||||
|
return _context.Workpages.FirstOrDefault(wp => wp.ID == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddWorkpage(Workpage wp)
|
||||||
|
{
|
||||||
|
_context.Add(wp);
|
||||||
|
_context.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Workpage> GetWorkbookWorkpages(int id)
|
||||||
|
{
|
||||||
|
return _context.Workpages.Where(wp => wp.WorkbookID == id).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateWorkbookContent(int id, string content)
|
||||||
|
{
|
||||||
|
var original = _context.Workpages.FirstOrDefault(wp => wp.ID == id);
|
||||||
|
|
||||||
|
if (original == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
original.Content = content;
|
||||||
|
_context.Update(original);
|
||||||
|
_context.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetWorkpageOwnerID(int id)
|
||||||
|
{
|
||||||
|
var workbook = _context.Workpages.Include(wp => wp.Workbook).FirstOrDefault(wp => wp.ID == id);
|
||||||
|
return workbook.Workbook.OwnerID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
Aya-Backend/Aya-Backend/Data/TokenDTO.cs
Normal file
12
Aya-Backend/Aya-Backend/Data/TokenDTO.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data
|
||||||
|
{
|
||||||
|
public class TokenDTO
|
||||||
|
{
|
||||||
|
public string Token { get; set; }
|
||||||
|
}
|
||||||
|
}
|
17
Aya-Backend/Aya-Backend/Data/User.cs
Normal file
17
Aya-Backend/Aya-Backend/Data/User.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data
|
||||||
|
{
|
||||||
|
public class User
|
||||||
|
{
|
||||||
|
public int ID { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public string Password { get; set; }
|
||||||
|
public string Token { get; set; }
|
||||||
|
}
|
||||||
|
}
|
15
Aya-Backend/Aya-Backend/Data/Workbook.cs
Normal file
15
Aya-Backend/Aya-Backend/Data/Workbook.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data
|
||||||
|
{
|
||||||
|
public class Workbook
|
||||||
|
{
|
||||||
|
public int ID { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int OwnerID { get; set; }
|
||||||
|
public User Owner { get; set; }
|
||||||
|
}
|
||||||
|
}
|
16
Aya-Backend/Aya-Backend/Data/Workpage.cs
Normal file
16
Aya-Backend/Aya-Backend/Data/Workpage.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Data
|
||||||
|
{
|
||||||
|
public class Workpage
|
||||||
|
{
|
||||||
|
public int ID { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
public int WorkbookID { get; set; }
|
||||||
|
public Workbook Workbook { get; set; }
|
||||||
|
}
|
||||||
|
}
|
44
Aya-Backend/Aya-Backend/Program.cs
Normal file
44
Aya-Backend/Aya-Backend/Program.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Aya_Backend.Data.Repositories;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using IHostingEnvironment = Microsoft.AspNetCore.Hosting.IHostingEnvironment;
|
||||||
|
|
||||||
|
namespace Aya_Backend
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var host = CreateHostBuilder(args).Build();
|
||||||
|
|
||||||
|
using (var scope = host.Services.CreateScope())
|
||||||
|
{
|
||||||
|
var services = scope.ServiceProvider;
|
||||||
|
var env = services.GetRequiredService<IHostingEnvironment>();
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
var context = services.GetRequiredService<AyaContext>();
|
||||||
|
context.Database.EnsureDeleted();
|
||||||
|
context.Database.Migrate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
host.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||||
|
Host.CreateDefaultBuilder(args)
|
||||||
|
.ConfigureWebHostDefaults(webBuilder =>
|
||||||
|
{
|
||||||
|
webBuilder.UseStartup<Startup>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
30
Aya-Backend/Aya-Backend/Properties/launchSettings.json
Normal file
30
Aya-Backend/Aya-Backend/Properties/launchSettings.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:63581",
|
||||||
|
"sslPort": 44394
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Aya_Backend": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "",
|
||||||
|
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
Aya-Backend/Aya-Backend/Services/UserService.cs
Normal file
55
Aya-Backend/Aya-Backend/Services/UserService.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Aya_Backend.Data;
|
||||||
|
using Aya_Backend.Data.Repositories;
|
||||||
|
using Aya_Backend.Data.Repositories.UserRepositories;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Aya_Backend.Services
|
||||||
|
{
|
||||||
|
public interface IUserService
|
||||||
|
{
|
||||||
|
User Authenticate(string username, string password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UserService : IUserService
|
||||||
|
{
|
||||||
|
private readonly IRepository _context;
|
||||||
|
public UserService(IRepository repository)
|
||||||
|
{
|
||||||
|
_context = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User Authenticate(string username, string password)
|
||||||
|
{
|
||||||
|
var user = _context.GetUserAuth(username, password);
|
||||||
|
|
||||||
|
// return null if user not found
|
||||||
|
if (user == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// authentication successful so generate jwt token
|
||||||
|
var tokenHandler = new JwtSecurityTokenHandler();
|
||||||
|
var key = Encoding.ASCII.GetBytes("VmdjieSvw6co7huHZtyn");
|
||||||
|
var tokenDescriptor = new SecurityTokenDescriptor
|
||||||
|
{
|
||||||
|
Subject = new ClaimsIdentity(new Claim[]
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.Name, user.ID.ToString())
|
||||||
|
}),
|
||||||
|
Expires = DateTime.UtcNow.AddDays(7),
|
||||||
|
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
|
||||||
|
};
|
||||||
|
var token = tokenHandler.CreateToken(tokenDescriptor);
|
||||||
|
user.Token = tokenHandler.WriteToken(token);
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
89
Aya-Backend/Aya-Backend/Startup.cs
Normal file
89
Aya-Backend/Aya-Backend/Startup.cs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Aya_Backend.Data.Repositories;
|
||||||
|
using Aya_Backend.Data.Repositories.UserRepositories;
|
||||||
|
using Aya_Backend.Services;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.HttpsPolicy;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Aya_Backend
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public Startup(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
Configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddControllers();
|
||||||
|
|
||||||
|
services.AddDbContext<AyaContext>();
|
||||||
|
|
||||||
|
var key = Encoding.ASCII.GetBytes("VmdjieSvw6co7huHZtyn");
|
||||||
|
services.AddAuthentication(x =>
|
||||||
|
{
|
||||||
|
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
})
|
||||||
|
.AddJwtBearer(x =>
|
||||||
|
{
|
||||||
|
x.RequireHttpsMetadata = false;
|
||||||
|
x.SaveToken = true;
|
||||||
|
x.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(key),
|
||||||
|
ValidateIssuer = false,
|
||||||
|
ValidateAudience = false
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddScoped<IRepository, Repository>();
|
||||||
|
|
||||||
|
services.AddScoped<IUserService, UserService>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseCors(builder => builder
|
||||||
|
.AllowAnyOrigin()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader());
|
||||||
|
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
app.UseRouting();
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
|
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
app.UseEndpoints(endpoints =>
|
||||||
|
{
|
||||||
|
endpoints.MapControllers();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
Aya-Backend/Aya-Backend/appsettings.Development.json
Normal file
9
Aya-Backend/Aya-Backend/appsettings.Development.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
Aya-Backend/Aya-Backend/appsettings.json
Normal file
10
Aya-Backend/Aya-Backend/appsettings.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
BIN
Aya-Backend/Aya-Backend/aya.db
Normal file
BIN
Aya-Backend/Aya-Backend/aya.db
Normal file
Binary file not shown.
@ -0,0 +1,23 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
[assembly: System.Reflection.AssemblyCompanyAttribute("Aya-Backend")]
|
||||||
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
|
||||||
|
[assembly: System.Reflection.AssemblyProductAttribute("Aya-Backend")]
|
||||||
|
[assembly: System.Reflection.AssemblyTitleAttribute("Aya-Backend")]
|
||||||
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|
||||||
|
// Generated by the MSBuild WriteCodeFragment class.
|
||||||
|
|
20524
Aya-Backend/Aya-Backend/obj/Debug/netcoreapp3.1/project.razor.json
Normal file
20524
Aya-Backend/Aya-Backend/obj/Debug/netcoreapp3.1/project.razor.json
Normal file
File diff suppressed because it is too large
Load Diff
2
Aya-Backend/README.md
Normal file
2
Aya-Backend/README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Aya-Backend
|
||||||
|
The backend/API for Aya, written in C# ASP.NET.
|
41
Aya-Frontend/.gitignore
vendored
Normal file
41
Aya-Frontend/.gitignore
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
lib-cov
|
||||||
|
*.seed
|
||||||
|
*.log
|
||||||
|
*.csv
|
||||||
|
*.dat
|
||||||
|
*.out
|
||||||
|
*.pid
|
||||||
|
*.gz
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
pids
|
||||||
|
logs
|
||||||
|
results
|
||||||
|
tmp
|
||||||
|
|
||||||
|
# Build
|
||||||
|
public/css/main.css
|
||||||
|
|
||||||
|
# Coverage reports
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# API keys and secrets
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Dependency directory
|
||||||
|
node_modules
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# Editors
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
# OS metadata
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Ignore built ts files
|
||||||
|
dist/**/*
|
||||||
|
|
||||||
|
# ignore yarn.lock
|
||||||
|
yarn.lock
|
2
Aya-Frontend/README.md
Normal file
2
Aya-Frontend/README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Aya-Frontend
|
||||||
|
The main frontend to the Aya language learning webapp, using the VueJS framework.
|
3
Aya-Frontend/babel.config.js
Normal file
3
Aya-Frontend/babel.config.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: ["@vue/cli-plugin-babel/preset"]
|
||||||
|
};
|
15245
Aya-Frontend/package-lock.json
generated
Normal file
15245
Aya-Frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
88
Aya-Frontend/package.json
Normal file
88
Aya-Frontend/package.json
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
{
|
||||||
|
"name": "aya-frontend",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"test:unit": "vue-cli-service test:unit",
|
||||||
|
"lint": "vue-cli-service lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^1.2.28",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^5.13.0",
|
||||||
|
"@fortawesome/vue-fontawesome": "^0.1.9",
|
||||||
|
"@types/showdown": "^1.9.3",
|
||||||
|
"@types/simplemde": "^1.11.7",
|
||||||
|
"axios": "^0.19.2",
|
||||||
|
"bootstrap": "^4.4.1",
|
||||||
|
"bootstrap-vue": "^2.12.0",
|
||||||
|
"core-js": "^3.6.4",
|
||||||
|
"easymde": "^2.10.1",
|
||||||
|
"showdown": "^1.9.1",
|
||||||
|
"simplemde": "^1.11.2",
|
||||||
|
"vue": "^2.6.11",
|
||||||
|
"vue-class-component": "^7.2.3",
|
||||||
|
"vue-js-modal": "^2.0.0-rc.3",
|
||||||
|
"vue-property-decorator": "^8.4.1",
|
||||||
|
"vue-router": "^3.1.6",
|
||||||
|
"vue-simplemde": "^1.0.4",
|
||||||
|
"vuex": "^3.3.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jest": "^24.0.19",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^2.26.0",
|
||||||
|
"@typescript-eslint/parser": "^2.26.0",
|
||||||
|
"@vue/cli-plugin-babel": "~4.3.0",
|
||||||
|
"@vue/cli-plugin-eslint": "~4.3.0",
|
||||||
|
"@vue/cli-plugin-router": "~4.3.0",
|
||||||
|
"@vue/cli-plugin-typescript": "~4.3.0",
|
||||||
|
"@vue/cli-plugin-unit-jest": "~4.3.0",
|
||||||
|
"@vue/cli-service": "~4.3.0",
|
||||||
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
|
"@vue/eslint-config-typescript": "^5.0.2",
|
||||||
|
"@vue/test-utils": "1.0.0-beta.31",
|
||||||
|
"eslint": "^6.7.2",
|
||||||
|
"eslint-plugin-prettier": "^3.1.1",
|
||||||
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
"prettier": "^1.19.1",
|
||||||
|
"typescript": "~3.8.3",
|
||||||
|
"vue-template-compiler": "^2.6.11"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"eslint:recommended",
|
||||||
|
"@vue/typescript/recommended",
|
||||||
|
"@vue/prettier",
|
||||||
|
"@vue/prettier/@typescript-eslint"
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 2020
|
||||||
|
},
|
||||||
|
"rules": {},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"**/__tests__/*.{j,t}s?(x)",
|
||||||
|
"**/tests/unit/**/*.spec.{j,t}s?(x)"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"jest": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not dead"
|
||||||
|
],
|
||||||
|
"jest": {
|
||||||
|
"preset": "@vue/cli-plugin-unit-jest/presets/typescript-and-babel"
|
||||||
|
}
|
||||||
|
}
|
BIN
Aya-Frontend/public/favicon.ico
Normal file
BIN
Aya-Frontend/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 119 KiB |
17
Aya-Frontend/public/index.html
Normal file
17
Aya-Frontend/public/index.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
34
Aya-Frontend/src/App.vue
Normal file
34
Aya-Frontend/src/App.vue
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<div id="nav">
|
||||||
|
<HeaderPanel />
|
||||||
|
</div>
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// @ is an alias to /src
|
||||||
|
import HeaderPanel from "@/components/HeaderPanel.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Home",
|
||||||
|
components: {
|
||||||
|
HeaderPanel
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#app {
|
||||||
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
text-align: left;
|
||||||
|
color: #2c3e50;
|
||||||
|
}
|
||||||
|
html, body
|
||||||
|
{
|
||||||
|
height: 100%; overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
BIN
Aya-Frontend/src/assets/Aya_JP_With_Line.png
Normal file
BIN
Aya-Frontend/src/assets/Aya_JP_With_Line.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 786 KiB |
1
Aya-Frontend/src/assets/book-open-solid.svg
Normal file
1
Aya-Frontend/src/assets/book-open-solid.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="book-open" class="svg-inline--fa fa-book-open fa-w-18" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M542.22 32.05c-54.8 3.11-163.72 14.43-230.96 55.59-4.64 2.84-7.27 7.89-7.27 13.17v363.87c0 11.55 12.63 18.85 23.28 13.49 69.18-34.82 169.23-44.32 218.7-46.92 16.89-.89 30.02-14.43 30.02-30.66V62.75c.01-17.71-15.35-31.74-33.77-30.7zM264.73 87.64C197.5 46.48 88.58 35.17 33.78 32.05 15.36 31.01 0 45.04 0 62.75V400.6c0 16.24 13.13 29.78 30.02 30.66 49.49 2.6 149.59 12.11 218.77 46.95 10.62 5.35 23.21-1.94 23.21-13.46V100.63c0-5.29-2.62-10.14-7.27-12.99z"></path></svg>
|
After Width: | Height: | Size: 691 B |
1
Aya-Frontend/src/assets/book-solid.svg
Normal file
1
Aya-Frontend/src/assets/book-solid.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="book" class="svg-inline--fa fa-book fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M448 360V24c0-13.3-10.7-24-24-24H96C43 0 0 43 0 96v320c0 53 43 96 96 96h328c13.3 0 24-10.7 24-24v-16c0-7.5-3.5-14.3-8.9-18.7-4.2-15.4-4.2-59.3 0-74.7 5.4-4.3 8.9-11.1 8.9-18.6zM128 134c0-3.3 2.7-6 6-6h212c3.3 0 6 2.7 6 6v20c0 3.3-2.7 6-6 6H134c-3.3 0-6-2.7-6-6v-20zm0 64c0-3.3 2.7-6 6-6h212c3.3 0 6 2.7 6 6v20c0 3.3-2.7 6-6 6H134c-3.3 0-6-2.7-6-6v-20zm253.4 250H96c-17.7 0-32-14.3-32-32 0-17.6 14.4-32 32-32h285.4c-1.9 17.1-1.9 46.9 0 64z"></path></svg>
|
After Width: | Height: | Size: 666 B |
BIN
Aya-Frontend/src/assets/logo.png
Normal file
BIN
Aya-Frontend/src/assets/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
1
Aya-Frontend/src/assets/plus-square-solid.svg
Normal file
1
Aya-Frontend/src/assets/plus-square-solid.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="plus-square" class="svg-inline--fa fa-plus-square fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-32 252c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92H92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z"></path></svg>
|
After Width: | Height: | Size: 551 B |
97
Aya-Frontend/src/components/AccountDialog.vue
Normal file
97
Aya-Frontend/src/components/AccountDialog.vue
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
|
||||||
|
import Workpage from "../types/Workpage";
|
||||||
|
import API from '../data/API';
|
||||||
|
import UserAPI from "../data/UserAPI"
|
||||||
|
import User from '../types/User';
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class WorkpageExplorer extends Vue {
|
||||||
|
|
||||||
|
@Prop() api!: API;
|
||||||
|
|
||||||
|
//Watch for a login request, if a request is made (value is set to true), begin login procedure.
|
||||||
|
@Watch('$store.state.loginRequested')
|
||||||
|
onLoginRequest(newVal: any, oldVal: any)
|
||||||
|
{
|
||||||
|
if (newVal == true)
|
||||||
|
this.loginDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check whether a token exists in localstorage, if it does then login with that token.
|
||||||
|
created()
|
||||||
|
{
|
||||||
|
document.title = "Aya";
|
||||||
|
if (localStorage.token == null || localStorage.token == "")
|
||||||
|
this.loginDialog();
|
||||||
|
else
|
||||||
|
this.loginWithToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Show login dialog.
|
||||||
|
loginDialog()
|
||||||
|
{
|
||||||
|
this.$store.state.loginRequested = false;
|
||||||
|
this.$modal.show("dialog", {
|
||||||
|
title: "Please Login",
|
||||||
|
text: "Username: <input type=\"text\" id=\"username\"><br>" +
|
||||||
|
"Password: <input type=\"password\" id=\"password\">",
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
title: "Create",
|
||||||
|
default: false,
|
||||||
|
handler: () => { this.createAccount((document.getElementById("username") as HTMLInputElement).value, (document.getElementById("password") as HTMLInputElement).value); this.$modal.hide("dialog"); }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Login",
|
||||||
|
default: true,
|
||||||
|
handler: () => { this.login((document.getElementById("username") as HTMLInputElement).value, (document.getElementById("password") as HTMLInputElement).value); this.$modal.hide("dialog"); }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},{ clickToClose: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send request to API to login (returning user object with token).
|
||||||
|
async login(username: string, password: string)
|
||||||
|
{
|
||||||
|
if (this.api == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const uAPI = new UserAPI(this.api.axios, this.api.rootURL);
|
||||||
|
const response = await uAPI.login(username, password);
|
||||||
|
this.$store.state.currentUser = new User(response.data.id, response.data.username, response.data.token);
|
||||||
|
localStorage.token = response.data.token;
|
||||||
|
this.$store.state.authed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send request to API to create a new account (returns the new user with the token).
|
||||||
|
async createAccount(username: string, password: string)
|
||||||
|
{
|
||||||
|
if (this.api == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const uAPI = new UserAPI(this.api.axios, this.api.rootURL);
|
||||||
|
const response = await uAPI.create(username, password);
|
||||||
|
console.log(response);
|
||||||
|
this.$store.state.currentUser = new User(response.data.id, response.data.username, localStorage.token);
|
||||||
|
this.$store.state.authed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send request to API to login with a given token.
|
||||||
|
async loginWithToken()
|
||||||
|
{
|
||||||
|
if (this.api == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const uAPI = new UserAPI(this.api.axios, this.api.rootURL);
|
||||||
|
const response = await uAPI.getUser(localStorage.token);
|
||||||
|
this.$store.state.currentUser = new User(response.data.id, response.data.username, localStorage.token);
|
||||||
|
this.$store.state.authed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
92
Aya-Frontend/src/components/HeaderPanel.vue
Normal file
92
Aya-Frontend/src/components/HeaderPanel.vue
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<div class="topnav">
|
||||||
|
<img class="logo" src="../assets/Aya_JP_With_Line.png" width="84" height="49">
|
||||||
|
<a class="username" v-if="logString == 'Logout'" href="#">Logged in as: {{ $store.state.currentUser.Username }}</a>
|
||||||
|
<a class="Log-Link" href="#" @click="handleButton()"> {{ logString }} </a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
//Formatting in this script is odd for some reason, blame VSCode.
|
||||||
|
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
|
||||||
|
import Workpage from "../types/Workpage";
|
||||||
|
import API from '../data/API';
|
||||||
|
import UserAPI from "../data/UserAPI"
|
||||||
|
import User from '../types/User';
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class WorkpageExplorer extends Vue
|
||||||
|
{
|
||||||
|
@Prop() private logString = "Login";
|
||||||
|
|
||||||
|
//Check if authed has changed, and change the text based on whether authed or not.
|
||||||
|
@Watch('$store.state.authed')
|
||||||
|
onAuthChange(newVal: any, oldVal: any)
|
||||||
|
{
|
||||||
|
if (newVal == true)
|
||||||
|
this.logString = "Logout";
|
||||||
|
else
|
||||||
|
this.logString = "Login"
|
||||||
|
}
|
||||||
|
|
||||||
|
//Decides whether to request a login or logout, depending on the current state.
|
||||||
|
handleButton()
|
||||||
|
{
|
||||||
|
if (this.logString == "Login")
|
||||||
|
this.requestLogin();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.logout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sets the global loginRequested state to be true, saying that the login prompt should open.
|
||||||
|
requestLogin()
|
||||||
|
{
|
||||||
|
this.$store.state.loginRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Removes the token from the local storage and sets global authed to false. (Simple logout technique).
|
||||||
|
logout()
|
||||||
|
{
|
||||||
|
this.$store.state.authed = false;
|
||||||
|
localStorage.token = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.topnav {
|
||||||
|
background-color: #333;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.topnav a {
|
||||||
|
float: left;
|
||||||
|
color: #f2f2f2;
|
||||||
|
text-align: center;
|
||||||
|
padding: 14px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
.topnav a:hover {
|
||||||
|
background-color: #ddd;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
float: left;
|
||||||
|
color: #f2f2f2;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
.Log-Link
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
|
.username
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
right: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
138
Aya-Frontend/src/components/WorkbookSidebar.vue
Normal file
138
Aya-Frontend/src/components/WorkbookSidebar.vue
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ul class="workbookList">
|
||||||
|
<li v-for="workbook in workbookArray" :key="workbook.id">
|
||||||
|
<img @click="changeActiveWorkbook(workbook.id)" :src="getBookImage(workbook.id)" width="50" height="50">
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="addWorkbook">
|
||||||
|
<img @click="addWorkbookDialog()" src="../assets/plus-square-solid.svg" width="20" height="20"> Add Workbook
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<v-dialog />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
|
||||||
|
import Workbook from "../types/Workbook";
|
||||||
|
import API from '../data/API';
|
||||||
|
import WorkbookAPI from "../data/WorkbookAPI";
|
||||||
|
import { findByKey } from "../utils/collections";
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class WorkbookSidebar extends Vue {
|
||||||
|
|
||||||
|
//Local workbook variable, these are from the API.
|
||||||
|
@Prop() private workbookArray!: Workbook[];
|
||||||
|
|
||||||
|
@Prop() private api!: API;
|
||||||
|
|
||||||
|
//When dynamic images are done in this way, they must be required by the compiler.
|
||||||
|
@Prop() private readonly closedBookSolidImage = require('../assets/book-solid.svg');
|
||||||
|
@Prop() private readonly openBookSolidImage = require('../assets/book-open-solid.svg');
|
||||||
|
|
||||||
|
//When the user is authed, get all workbooks from that user from the api and assign them to the local variable.
|
||||||
|
//When the user is not authed, empty the array.
|
||||||
|
@Watch('$store.state.authed')
|
||||||
|
onAuthed(newVal: any, oldVal: any)
|
||||||
|
{
|
||||||
|
if (newVal == true)
|
||||||
|
this.getAllUserWorkbooksFromAPI();
|
||||||
|
else
|
||||||
|
this.emptyWorkbookArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Assign the response from the api to the local workbook variable.
|
||||||
|
private async getAllUserWorkbooksFromAPI()
|
||||||
|
{
|
||||||
|
if (this.api == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const wbAPI = new WorkbookAPI(this.api.axios, this.api.rootURL);
|
||||||
|
const response = await wbAPI.getAllUserWorkbooks(localStorage.token);
|
||||||
|
this.workbookArray = response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the book image (open/closed) for the specified ID.
|
||||||
|
//(If the current workbook is the workbook ID passed, the open book image will be used, otherwise the closed image will be used).
|
||||||
|
private getBookImage(id: string): any
|
||||||
|
{
|
||||||
|
if (this.$store.state.workbookActive == id)
|
||||||
|
return this.openBookSolidImage;
|
||||||
|
return this.closedBookSolidImage;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Change the store's active workbook to the ID passed.
|
||||||
|
private changeActiveWorkbook(id: string)
|
||||||
|
{
|
||||||
|
this.$store.commit("changeActiveWorkbook", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Show the dialog for adding a new workbook.
|
||||||
|
private addWorkbookDialog()
|
||||||
|
{
|
||||||
|
if (this.$store.state.authed == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.$modal.show("dialog", {
|
||||||
|
title: "Add Workbook",
|
||||||
|
text: "Please input the name of the new Workbook: <input id=\"new-workbook-name\" type=\"text\" style=\"width: 370px\">",
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
title: "Cancel",
|
||||||
|
hander: () => { this.$modal.hide("dialog") }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Create",
|
||||||
|
default: true,
|
||||||
|
handler: () => { this.addWorkbook((document.getElementById("new-workbook-name") as HTMLInputElement).value); this.$modal.hide("dialog"); }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//Adds a workbook by posting to the API. Then, retrieves all of the workbooks again to update the local version.
|
||||||
|
private async addWorkbook(name: string)
|
||||||
|
{
|
||||||
|
if (this.api == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const wbAPI = new WorkbookAPI(this.api.axios, this.api.rootURL);
|
||||||
|
const response = await wbAPI.addWorkbook(name, localStorage.token);
|
||||||
|
await this.getAllUserWorkbooksFromAPI();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Empties the local workbook array.
|
||||||
|
private emptyWorkbookArray()
|
||||||
|
{
|
||||||
|
this.workbookArray = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
body
|
||||||
|
{
|
||||||
|
background-color: darkslategray;
|
||||||
|
}
|
||||||
|
.addWorkbook
|
||||||
|
{
|
||||||
|
position : fixed;
|
||||||
|
bottom : 1vh;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.workbookList
|
||||||
|
{
|
||||||
|
position : fixed;
|
||||||
|
left: 0px;
|
||||||
|
overflow : auto;
|
||||||
|
height : 90vh;
|
||||||
|
list-style-type : none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.workbookList ul, .workbookList li
|
||||||
|
{
|
||||||
|
margin: 0; padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
109
Aya-Frontend/src/components/WorkpageEditor.vue
Normal file
109
Aya-Frontend/src/components/WorkpageEditor.vue
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<template>
|
||||||
|
<div class="editor">
|
||||||
|
<h1>{{ workpageTitle }}</h1>
|
||||||
|
<vue-simplemde ref="markdownEditor" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Prop, Vue, Watch, Ref } from "vue-property-decorator";
|
||||||
|
import VueSimplemde from 'vue-simplemde';
|
||||||
|
import API from "../data/API";
|
||||||
|
import WorkpageAPI from "../data/WorkpageAPI";
|
||||||
|
import AutoSave from "../utils/autosave";
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class WorkpageEditor extends Vue {
|
||||||
|
|
||||||
|
//Local variables for editor.
|
||||||
|
@Prop() private workpageTitle!: string;
|
||||||
|
@Prop() private workpageContent!: string;
|
||||||
|
|
||||||
|
@Prop() private api!: API;
|
||||||
|
|
||||||
|
@Prop() private autoSave!: any;
|
||||||
|
|
||||||
|
//Reference to the markdown editor.
|
||||||
|
@Ref("markdownEditor") readonly mde!: any;
|
||||||
|
|
||||||
|
//Watch for authed changing, if the user gets unauthed, then reset/empty all values.
|
||||||
|
@Watch('$store.state.authed')
|
||||||
|
onAuthChange(newVal: any, oldVal: any)
|
||||||
|
{
|
||||||
|
if (newVal == false)
|
||||||
|
{
|
||||||
|
this.workpageContent = "";
|
||||||
|
this.updateEditorText();
|
||||||
|
this.workpageTitle = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Watch for the active workpage changing, as this is when the text changes need to be applied.
|
||||||
|
@Watch('$store.state.workpageActive')
|
||||||
|
onWorkPageChange(newVal: any, oldVal: any)
|
||||||
|
{
|
||||||
|
this.getWorkpage(newVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create a loop for the autosave function. Creates the object on created (5 seconds per post).
|
||||||
|
created()
|
||||||
|
{
|
||||||
|
this.autoSave = new AutoSave(() => this.updateWorkpage(), 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Creates a hook for when a change is made (for example, text changes), create the timer. If another change is made within the 5 seconds, restart the timer.
|
||||||
|
//This means the save only starts after 5 seconds of inactivity after a change.
|
||||||
|
mounted()
|
||||||
|
{
|
||||||
|
const self = this.startAutosaveTimer;
|
||||||
|
this.mde.simplemde.codemirror.on("change", function(){
|
||||||
|
self();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//Gets a workpage from the api with the specified ID.
|
||||||
|
private async getWorkpage(id: string)
|
||||||
|
{
|
||||||
|
if (this.api == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const wpAPI = new WorkpageAPI(this.api.axios, this.api.rootURL);
|
||||||
|
const response = await wpAPI.getWorkpage(id, localStorage.token);
|
||||||
|
this.workpageTitle = response.data.name;
|
||||||
|
this.workpageContent = response.data.content;
|
||||||
|
this.updateEditorText();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Updates the Editor's text with the workpageContent variable.
|
||||||
|
private updateEditorText()
|
||||||
|
{
|
||||||
|
this.mde.simplemde.value(this.workpageContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Updates a workpage to the API based on the content in the editor and the active workpage.
|
||||||
|
private async updateWorkpage()
|
||||||
|
{
|
||||||
|
if (this.api == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const wpAPI = new WorkpageAPI(this.api.axios, this.api.rootURL);
|
||||||
|
const response = await wpAPI.updateWorkpage(this.$store.state.workpageActive, this.mde.simplemde.value(), localStorage.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Starts the autosave timer.
|
||||||
|
private startAutosaveTimer()
|
||||||
|
{
|
||||||
|
clearInterval(this.autoSave);
|
||||||
|
this.autoSave = setInterval(this.updateWorkpage, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import '~simplemde/dist/simplemde.min.css';
|
||||||
|
.editor
|
||||||
|
{
|
||||||
|
height: 90vh;
|
||||||
|
}
|
||||||
|
</style>
|
115
Aya-Frontend/src/components/WorkpageExplorer.vue
Normal file
115
Aya-Frontend/src/components/WorkpageExplorer.vue
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
<template>
|
||||||
|
<div class="workpageList">
|
||||||
|
<ul style="list-style-type : none;">
|
||||||
|
<li v-for="workpage in workpages" :key="workpage.id">
|
||||||
|
<a href="#" @click="changeSelectedWorkpage(workpage.id)">{{ workpage.name }}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="addWorkpage">
|
||||||
|
<img @click="addWorkpageDialog()" src="../assets/plus-square-solid.svg" width="20" height="20"> Add Workpage
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
|
||||||
|
import Workpage from "../types/Workpage";
|
||||||
|
import API from '../data/API';
|
||||||
|
import WorkpageAPI from "../data/WorkpageAPI"
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class WorkpageExplorer extends Vue {
|
||||||
|
|
||||||
|
//The local variable for the workpages displayed.
|
||||||
|
@Prop() private workpages!: Workpage[];
|
||||||
|
|
||||||
|
@Prop() private api!: API;
|
||||||
|
|
||||||
|
//Checks of the workbook changes. When the workbook changes, it gets all pages from that workbook.
|
||||||
|
@Watch('$store.state.workbookActive')
|
||||||
|
onWorkbookChange(newVal: any, oldVal: any)
|
||||||
|
{
|
||||||
|
this.getAllWorkpagesFromWorkbook(newVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Checks if the auth gets changed. If the user gets unauthed, all workpages should be removed from the view.
|
||||||
|
@Watch('$store.state.authed')
|
||||||
|
onAuthChange(newVal: any, oldVal: any)
|
||||||
|
{
|
||||||
|
if (newVal == false)
|
||||||
|
{
|
||||||
|
this.workpages = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Gets all of the workpages from the workbook id passed.
|
||||||
|
private async getAllWorkpagesFromWorkbook(id: string)
|
||||||
|
{
|
||||||
|
if (this.api == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const wpAPI = new WorkpageAPI(this.api.axios, this.api.rootURL);
|
||||||
|
const response = await wpAPI.getAllWorkpagesFromWorkbook(id, localStorage.token);
|
||||||
|
this.workpages = response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Commits the new selected workpage to the store.
|
||||||
|
private changeSelectedWorkpage(id: string)
|
||||||
|
{
|
||||||
|
this.$store.commit("changeActiveWorkpage", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Shows the dialog to add a workpage.
|
||||||
|
private addWorkpageDialog()
|
||||||
|
{
|
||||||
|
this.$modal.show("dialog", {
|
||||||
|
title: "Add Workpage",
|
||||||
|
text: "Please input the name of the new Workpage: <input id=\"new-workpage-name\" type=\"text\" style=\"width: 370px\">",
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
title: "Cancel",
|
||||||
|
hander: () => { this.$modal.hide("dialog") }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Create",
|
||||||
|
default: true,
|
||||||
|
handler: () => { this.addWorkpage((document.getElementById("new-workpage-name") as HTMLInputElement).value); this.$modal.hide("dialog"); }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//Adds a workpage to the API with the given name.
|
||||||
|
private async addWorkpage(name: string)
|
||||||
|
{
|
||||||
|
if (this.api == undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const activeWB = this.$store.state.workbookActive;
|
||||||
|
|
||||||
|
const wpAPI = new WorkpageAPI(this.api.axios, this.api.rootURL);
|
||||||
|
const response = await wpAPI.addWorkpage(name, activeWB, localStorage.token);
|
||||||
|
await this.getAllWorkpagesFromWorkbook(activeWB);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.workpageList
|
||||||
|
{
|
||||||
|
text-align: left;
|
||||||
|
white-space : nowrap;
|
||||||
|
overflow: auto;
|
||||||
|
list-style-type : none;
|
||||||
|
}
|
||||||
|
.addWorkpage
|
||||||
|
{
|
||||||
|
position : fixed;
|
||||||
|
bottom : 1vh;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.workpageList ul, .workpageList li
|
||||||
|
{
|
||||||
|
margin: 0; padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
47
Aya-Frontend/src/data/API.ts
Normal file
47
Aya-Frontend/src/data/API.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
export default class API
|
||||||
|
{
|
||||||
|
readonly rootURL: string;
|
||||||
|
readonly axios: any;
|
||||||
|
|
||||||
|
constructor(ax: any, root: string)
|
||||||
|
{
|
||||||
|
this.axios = ax;
|
||||||
|
this.rootURL = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
async post(path: string, bodyContent: string)
|
||||||
|
{
|
||||||
|
const res = await this.axios.post(this.rootURL + path, bodyContent, { headers: { "Content-Type": "application/json" }});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
async postAuthed(path: string, token: string)
|
||||||
|
{
|
||||||
|
const res = await this.axios.post(this.rootURL + path, "", { headers: { "Authorization": "Bearer " + token }});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
async postAuthedWithBody(path: string, content: string, token: string)
|
||||||
|
{
|
||||||
|
const res = await this.axios.post(this.rootURL + path, content, { headers: { "Authorization": "Bearer " + token, "Content-Type": "application/json" }, });
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
async postWithHeaders(path: string, bodyContent: string, options: any)
|
||||||
|
{
|
||||||
|
const res = await this.axios.post(this.rootURL + path, bodyContent, options);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
async get(path: string)
|
||||||
|
{
|
||||||
|
const res = await this.axios.get(this.rootURL + path);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAuthed(path: string, token: string)
|
||||||
|
{
|
||||||
|
const res = await this.axios.get(this.rootURL + path, { headers: { "Authorization": "Bearer " + token }});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
26
Aya-Frontend/src/data/UserAPI.ts
Normal file
26
Aya-Frontend/src/data/UserAPI.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import API from "./API";
|
||||||
|
|
||||||
|
export default class UserAPI extends API
|
||||||
|
{
|
||||||
|
private readonly apiPath = "api/user/";
|
||||||
|
|
||||||
|
constructor(ax: any, root: string)
|
||||||
|
{
|
||||||
|
super(ax, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
async login(username: string, password: string)
|
||||||
|
{
|
||||||
|
return await super.post(this.apiPath + "login", JSON.stringify({ Username: username, Password: password }));
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUser(token: string)
|
||||||
|
{
|
||||||
|
return await super.getAuthed(this.apiPath + "get", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(username: string, password: string)
|
||||||
|
{
|
||||||
|
return await super.post(this.apiPath + "create", JSON.stringify({ Username: username, Password: password }));
|
||||||
|
}
|
||||||
|
}
|
22
Aya-Frontend/src/data/WorkbookAPI.ts
Normal file
22
Aya-Frontend/src/data/WorkbookAPI.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import API from './API';
|
||||||
|
|
||||||
|
export default class WorkbookAPI extends API
|
||||||
|
{
|
||||||
|
private readonly apiPath = "api/workbook/";
|
||||||
|
|
||||||
|
constructor(ax: any, root: string)
|
||||||
|
{
|
||||||
|
super(ax, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllUserWorkbooks(token: string)
|
||||||
|
{
|
||||||
|
return await super.getAuthed(this.apiPath + "userworkbooks", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
async addWorkbook(name: string, token: string)
|
||||||
|
{
|
||||||
|
console.log(name + " " + token);
|
||||||
|
return await super.postAuthed(this.apiPath + "add?name=" + name, token);
|
||||||
|
}
|
||||||
|
}
|
31
Aya-Frontend/src/data/WorkpageAPI.ts
Normal file
31
Aya-Frontend/src/data/WorkpageAPI.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import API from './API';
|
||||||
|
|
||||||
|
export default class WorkpageAPI extends API
|
||||||
|
{
|
||||||
|
private readonly apiPath = "api/workpage/";
|
||||||
|
|
||||||
|
constructor(ax: any, root: string)
|
||||||
|
{
|
||||||
|
super(ax, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllWorkpagesFromWorkbook(id: string, token: string)
|
||||||
|
{
|
||||||
|
return await super.getAuthed(this.apiPath + "fromworkbook?id=" + id, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getWorkpage(id: string, token: string)
|
||||||
|
{
|
||||||
|
return await super.getAuthed(this.apiPath + "get?id=" + id, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
async addWorkpage(name: string, workbookid: number, token)
|
||||||
|
{
|
||||||
|
return await super.postAuthed(this.apiPath + "add?name=" + name + "&workbookid=" + workbookid, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateWorkpage(id: string, content: string, token: string)
|
||||||
|
{
|
||||||
|
return await super.postAuthedWithBody(this.apiPath + "updateworkpagecontent?id=" + id, '"' + content + '"', token);
|
||||||
|
}
|
||||||
|
}
|
30
Aya-Frontend/src/main.ts
Normal file
30
Aya-Frontend/src/main.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import Vue from "vue";
|
||||||
|
import App from "./App.vue";
|
||||||
|
import router from "./router";
|
||||||
|
import store from "./store/store";
|
||||||
|
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue';
|
||||||
|
import 'bootstrap/dist/css/bootstrap.css';
|
||||||
|
import 'bootstrap-vue/dist/bootstrap-vue.css';
|
||||||
|
import { library } from '@fortawesome/fontawesome-svg-core';
|
||||||
|
import { faUserSecret } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||||
|
import VueSimplemde from 'vue-simplemde';
|
||||||
|
import 'simplemde/dist/simplemde.min.css';
|
||||||
|
import VModal from 'vue-js-modal';
|
||||||
|
|
||||||
|
library.add(faUserSecret);
|
||||||
|
|
||||||
|
Vue.use(BootstrapVue);
|
||||||
|
Vue.use(IconsPlugin);
|
||||||
|
Vue.use(VModal, { dialog: true });
|
||||||
|
Vue.component('font-awesome-icon', FontAwesomeIcon);
|
||||||
|
|
||||||
|
Vue.component('vue-simplemde', VueSimplemde)
|
||||||
|
|
||||||
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
store,
|
||||||
|
router,
|
||||||
|
render: h => h(App)
|
||||||
|
}).$mount("#app");
|
20
Aya-Frontend/src/router/index.ts
Normal file
20
Aya-Frontend/src/router/index.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import Vue from "vue";
|
||||||
|
import VueRouter, { RouteConfig } from "vue-router";
|
||||||
|
import Home from "../views/Home.vue";
|
||||||
|
|
||||||
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
|
const routes: Array<RouteConfig> = [
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
name: "Home",
|
||||||
|
component: Home
|
||||||
|
}];
|
||||||
|
|
||||||
|
const router = new VueRouter({
|
||||||
|
mode: "history",
|
||||||
|
base: process.env.BASE_URL,
|
||||||
|
routes
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
13
Aya-Frontend/src/shims-tsx.d.ts
vendored
Normal file
13
Aya-Frontend/src/shims-tsx.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import Vue, { VNode } from "vue";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace JSX {
|
||||||
|
// tslint:disable no-empty-interface
|
||||||
|
interface Element extends VNode {}
|
||||||
|
// tslint:disable no-empty-interface
|
||||||
|
interface ElementClass extends Vue {}
|
||||||
|
interface IntrinsicElements {
|
||||||
|
[elem: string]: any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
Aya-Frontend/src/shims-vue.d.ts
vendored
Normal file
4
Aya-Frontend/src/shims-vue.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
declare module "*.vue" {
|
||||||
|
import Vue from "vue";
|
||||||
|
export default Vue;
|
||||||
|
}
|
27
Aya-Frontend/src/store/store.ts
Normal file
27
Aya-Frontend/src/store/store.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
import User from '@/types/User';
|
||||||
|
|
||||||
|
Vue.use(Vuex)
|
||||||
|
|
||||||
|
export default new Vuex.Store({
|
||||||
|
state: {
|
||||||
|
workbookActive: 0,
|
||||||
|
workpageActive: 0,
|
||||||
|
authed: false,
|
||||||
|
loginRequested: false,
|
||||||
|
currentUser: User
|
||||||
|
},
|
||||||
|
getters: {},
|
||||||
|
mutations: {
|
||||||
|
changeActiveWorkbook(state, payload)
|
||||||
|
{
|
||||||
|
state.workbookActive = payload;
|
||||||
|
},
|
||||||
|
changeActiveWorkpage(state, payload)
|
||||||
|
{
|
||||||
|
state.workpageActive = payload;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {}
|
||||||
|
});
|
13
Aya-Frontend/src/types/User.ts
Normal file
13
Aya-Frontend/src/types/User.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export default class User
|
||||||
|
{
|
||||||
|
ID!: string;
|
||||||
|
Username!: string;
|
||||||
|
Token!: string;
|
||||||
|
|
||||||
|
constructor(id: string, username: string, token: string)
|
||||||
|
{
|
||||||
|
this.ID = id;
|
||||||
|
this.Username = username;
|
||||||
|
this.Token = token;
|
||||||
|
}
|
||||||
|
}
|
9
Aya-Frontend/src/types/Workbook.ts
Normal file
9
Aya-Frontend/src/types/Workbook.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import User from "../types/User";
|
||||||
|
import Workpage from "../types/Workpage";
|
||||||
|
|
||||||
|
export default class Workbook
|
||||||
|
{
|
||||||
|
id!: string;
|
||||||
|
name!: string;
|
||||||
|
ownerID!: string;
|
||||||
|
}
|
14
Aya-Frontend/src/types/Workpage.ts
Normal file
14
Aya-Frontend/src/types/Workpage.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import showdown from "showdown";
|
||||||
|
|
||||||
|
export default class Workpage
|
||||||
|
{
|
||||||
|
WorkpageID!: string;
|
||||||
|
WorkpageName!: string;
|
||||||
|
WorkpageContent!: string;
|
||||||
|
|
||||||
|
GetWorkpageContentMarkdown(): string
|
||||||
|
{
|
||||||
|
const converter = new showdown.Converter;
|
||||||
|
return converter.makeHtml(this.WorkpageContent);
|
||||||
|
}
|
||||||
|
}
|
22
Aya-Frontend/src/utils/autosave.ts
Normal file
22
Aya-Frontend/src/utils/autosave.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
export default class AutoSave
|
||||||
|
{
|
||||||
|
private currentTimeout!: any;
|
||||||
|
private delayTime!: number;
|
||||||
|
private func!: Function;
|
||||||
|
|
||||||
|
constructor(f: Function, time: number)
|
||||||
|
{
|
||||||
|
this.func = f;
|
||||||
|
this.delayTime = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public start(): void
|
||||||
|
{
|
||||||
|
this.currentTimeout = setTimeout(this.func, this.delayTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public stop(): void
|
||||||
|
{
|
||||||
|
clearTimeout(this.currentTimeout);
|
||||||
|
}
|
||||||
|
}
|
8
Aya-Frontend/src/utils/collections.ts
Normal file
8
Aya-Frontend/src/utils/collections.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
//Searches through the array and finds the value with the key, else returns null.
|
||||||
|
export function findByKey(arr: Array<any>, value: any, key = "id"): any
|
||||||
|
{
|
||||||
|
for (const val of arr)
|
||||||
|
if (val[key] == value)
|
||||||
|
return val;
|
||||||
|
return null;
|
||||||
|
}
|
70
Aya-Frontend/src/views/Home.vue
Normal file
70
Aya-Frontend/src/views/Home.vue
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm WorkbookSidebar">
|
||||||
|
<WorkbookSidebar :api="api" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm WorkpageExplorer">
|
||||||
|
<WorkpageExplorer :api="api" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm WorkpageEditor">
|
||||||
|
<WorkpageEditor :api="api" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<AccountDialog :api="api" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// @ is an alias to /src
|
||||||
|
import WorkbookSidebar from "@/components/WorkbookSidebar.vue";
|
||||||
|
import WorkpageExplorer from "@/components/WorkpageExplorer.vue";
|
||||||
|
import WorkpageEditor from "@/components/WorkpageEditor.vue";
|
||||||
|
import AccountDialog from "@/components/AccountDialog.vue";
|
||||||
|
import API from "@/data/API";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Home",
|
||||||
|
components: {
|
||||||
|
WorkbookSidebar,
|
||||||
|
WorkpageExplorer,
|
||||||
|
WorkpageEditor,
|
||||||
|
AccountDialog
|
||||||
|
},
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
api: new API(require("axios"), "https://localhost:5001/")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.WorkbookSidebar
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
width: 150px;
|
||||||
|
height: 90vh;
|
||||||
|
resize : horizontal;
|
||||||
|
background-color: lightslategray;
|
||||||
|
}
|
||||||
|
.WorkpageExplorer
|
||||||
|
{
|
||||||
|
text-align: left;
|
||||||
|
position: absolute;
|
||||||
|
left: 125px;
|
||||||
|
width: 300px;
|
||||||
|
height: 90vh;
|
||||||
|
resize : horizontal;
|
||||||
|
background-color: rgb(183, 188, 200);
|
||||||
|
}
|
||||||
|
.WorkpageEditor
|
||||||
|
{
|
||||||
|
text-align: left;
|
||||||
|
position: absolute;
|
||||||
|
height: 90vh;
|
||||||
|
left: 425px;
|
||||||
|
background-color: rgb(231, 231, 231);
|
||||||
|
}
|
||||||
|
</style>
|
12
Aya-Frontend/tests/unit/example.spec.ts
Normal file
12
Aya-Frontend/tests/unit/example.spec.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { shallowMount } from "@vue/test-utils";
|
||||||
|
import HelloWorld from "@/components/HelloWorld.vue";
|
||||||
|
|
||||||
|
describe("HelloWorld.vue", () => {
|
||||||
|
it("renders props.msg when passed", () => {
|
||||||
|
const msg = "new message";
|
||||||
|
const wrapper = shallowMount(HelloWorld, {
|
||||||
|
propsData: { msg }
|
||||||
|
});
|
||||||
|
expect(wrapper.text()).toMatch(msg);
|
||||||
|
});
|
||||||
|
});
|
40
Aya-Frontend/tsconfig.json
Normal file
40
Aya-Frontend/tsconfig.json
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "esnext",
|
||||||
|
"module": "esnext",
|
||||||
|
"strict": false,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"importHelpers": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"types": [
|
||||||
|
"webpack-env",
|
||||||
|
"jest"
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"lib": [
|
||||||
|
"esnext",
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"scripthost"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
"src/**/*.vue",
|
||||||
|
"tests/**/*.ts",
|
||||||
|
"tests/**/*.tsx"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user