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