diff --git a/data/createdatabase.sql b/data/createdatabase.sql index 41b5a17..1f84364 100644 --- a/data/createdatabase.sql +++ b/data/createdatabase.sql @@ -2,114 +2,114 @@ USE [master] GO /****** Object: Database [sql101.firstname.lastname] Script Date: 1/21/2019 9:11:50 PM ******/ -CREATE DATABASE [sql101.firstname.lastname] +CREATE DATABASE [sql101.castello.govender] CONTAINMENT = NONE ON PRIMARY -( NAME = N'sql101.firstname.lastname', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\sql101.firstname.lastname.mdf' , SIZE = 8192KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB ) +( NAME = N'sql101.castello.govender', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\sql101.castello.govender.mdf' , SIZE = 8192KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB ) LOG ON -( NAME = N'sql101.firstname.lastname_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\sql101.firstname.lastname_log.ldf' , SIZE = 8192KB , MAXSIZE = 2048GB , FILEGROWTH = 65536KB ) +( NAME = N'sql101.castello.govender_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\sql101.castello.govender_log.ldf' , SIZE = 8192KB , MAXSIZE = 2048GB , FILEGROWTH = 65536KB ) GO -ALTER DATABASE [sql101.firstname.lastname] SET COMPATIBILITY_LEVEL = 130 +ALTER DATABASE [sql101.castello.govender] SET COMPATIBILITY_LEVEL = 130 GO IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled')) begin -EXEC [sql101.firstname.lastname].[dbo].[sp_fulltext_database] @action = 'enable' +EXEC [sql101.castello.govender].[dbo].[sp_fulltext_database] @action = 'enable' end GO -ALTER DATABASE [sql101.firstname.lastname] SET ANSI_NULL_DEFAULT OFF +ALTER DATABASE [sql101.castello.govender] SET ANSI_NULL_DEFAULT OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET ANSI_NULLS OFF +ALTER DATABASE [sql101.castello.govender] SET ANSI_NULLS OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET ANSI_PADDING OFF +ALTER DATABASE [sql101.castello.govender] SET ANSI_PADDING OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET ANSI_WARNINGS OFF +ALTER DATABASE [sql101.castello.govender] SET ANSI_WARNINGS OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET ARITHABORT OFF +ALTER DATABASE [sql101.castello.govender] SET ARITHABORT OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET AUTO_CLOSE OFF +ALTER DATABASE [sql101.castello.govender] SET AUTO_CLOSE OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET AUTO_SHRINK OFF +ALTER DATABASE [sql101.castello.govender] SET AUTO_SHRINK OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET AUTO_UPDATE_STATISTICS ON +ALTER DATABASE [sql101.castello.govender] SET AUTO_UPDATE_STATISTICS ON GO -ALTER DATABASE [sql101.firstname.lastname] SET CURSOR_CLOSE_ON_COMMIT OFF +ALTER DATABASE [sql101.castello.govender] SET CURSOR_CLOSE_ON_COMMIT OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET CURSOR_DEFAULT GLOBAL +ALTER DATABASE [sql101.castello.govender] SET CURSOR_DEFAULT GLOBAL GO -ALTER DATABASE [sql101.firstname.lastname] SET CONCAT_NULL_YIELDS_NULL OFF +ALTER DATABASE [sql101.castello.govender] SET CONCAT_NULL_YIELDS_NULL OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET NUMERIC_ROUNDABORT OFF +ALTER DATABASE [sql101.castello.govender] SET NUMERIC_ROUNDABORT OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET QUOTED_IDENTIFIER OFF +ALTER DATABASE [sql101.castello.govender] SET QUOTED_IDENTIFIER OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET RECURSIVE_TRIGGERS OFF +ALTER DATABASE [sql101.castello.govender] SET RECURSIVE_TRIGGERS OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET DISABLE_BROKER +ALTER DATABASE [sql101.castello.govender] SET DISABLE_BROKER GO -ALTER DATABASE [sql101.firstname.lastname] SET AUTO_UPDATE_STATISTICS_ASYNC OFF +ALTER DATABASE [sql101.castello.govender] SET AUTO_UPDATE_STATISTICS_ASYNC OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET DATE_CORRELATION_OPTIMIZATION OFF +ALTER DATABASE [sql101.castello.govender] SET DATE_CORRELATION_OPTIMIZATION OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET TRUSTWORTHY OFF +ALTER DATABASE [sql101.castello.govender] SET TRUSTWORTHY OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET ALLOW_SNAPSHOT_ISOLATION OFF +ALTER DATABASE [sql101.castello.govender] SET ALLOW_SNAPSHOT_ISOLATION OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET PARAMETERIZATION SIMPLE +ALTER DATABASE [sql101.castello.govender] SET PARAMETERIZATION SIMPLE GO -ALTER DATABASE [sql101.firstname.lastname] SET READ_COMMITTED_SNAPSHOT OFF +ALTER DATABASE [sql101.castello.govender] SET READ_COMMITTED_SNAPSHOT OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET HONOR_BROKER_PRIORITY OFF +ALTER DATABASE [sql101.castello.govender] SET HONOR_BROKER_PRIORITY OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET RECOVERY FULL +ALTER DATABASE [sql101.castello.govender] SET RECOVERY FULL GO -ALTER DATABASE [sql101.firstname.lastname] SET MULTI_USER +ALTER DATABASE [sql101.castello.govender] SET MULTI_USER GO -ALTER DATABASE [sql101.firstname.lastname] SET PAGE_VERIFY CHECKSUM +ALTER DATABASE [sql101.castello.govender] SET PAGE_VERIFY CHECKSUM GO -ALTER DATABASE [sql101.firstname.lastname] SET DB_CHAINING OFF +ALTER DATABASE [sql101.castello.govender] SET DB_CHAINING OFF GO -ALTER DATABASE [sql101.firstname.lastname] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF ) +ALTER DATABASE [sql101.castello.govender] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF ) GO -ALTER DATABASE [sql101.firstname.lastname] SET TARGET_RECOVERY_TIME = 60 SECONDS +ALTER DATABASE [sql101.castello.govender] SET TARGET_RECOVERY_TIME = 60 SECONDS GO -ALTER DATABASE [sql101.firstname.lastname] SET DELAYED_DURABILITY = DISABLED +ALTER DATABASE [sql101.castello.govender] SET DELAYED_DURABILITY = DISABLED GO -ALTER DATABASE [sql101.firstname.lastname] SET QUERY_STORE = OFF +ALTER DATABASE [sql101.castello.govender] SET QUERY_STORE = OFF GO -USE [sql101.firstname.lastname] +USE [sql101.castello.govender] GO ALTER DATABASE SCOPED CONFIGURATION SET LEGACY_CARDINALITY_ESTIMATION = OFF; @@ -124,7 +124,7 @@ GO ALTER DATABASE SCOPED CONFIGURATION SET QUERY_OPTIMIZER_HOTFIXES = OFF; GO -ALTER DATABASE [sql101.firstname.lastname] SET READ_WRITE +ALTER DATABASE [sql101.castello.govender] SET READ_WRITE GO diff --git a/data/createuser.sql b/data/createuser.sql index bcf3038..0e2d860 100644 --- a/data/createuser.sql +++ b/data/createuser.sql @@ -1,18 +1,18 @@ USE [master] GO -CREATE LOGIN [firstnamelastname] WITH PASSWORD=N'rabbit123!@#' MUST_CHANGE, DEFAULT_DATABASE=[sql101.firstname.lastname], CHECK_EXPIRATION=ON, CHECK_POLICY=ON +CREATE LOGIN [castellogovender] WITH PASSWORD=N'rabbit123!@#' MUST_CHANGE, DEFAULT_DATABASE=[sql101.castello.govender], CHECK_EXPIRATION=ON, CHECK_POLICY=ON GO -use [sql101.firstname.lastname] +use [sql101.castello.govender] GO use [master] GO -USE [sql101.firstname.lastname] +USE [sql101.castello.govender] GO -CREATE USER [firstnamelastname] FOR LOGIN [firstnamelastname] +CREATE USER [castellogovender] FOR LOGIN [castellogovender] GO -USE [sql101.firstname.lastname] +USE [sql101.castello.govender] GO -ALTER ROLE [db_owner] ADD MEMBER [firstnamelastname] +ALTER ROLE [db_owner] ADD MEMBER [castellogovender] GO diff --git a/src/MyTimesheet/MyTimesheet/CacheSecrets.config b/src/MyTimesheet/MyTimesheet/CacheSecrets.config new file mode 100644 index 0000000..dcc3694 --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/CacheSecrets.config @@ -0,0 +1,21 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/MyTimesheet/MyTimesheet/Controllers/EmployeesController.cs b/src/MyTimesheet/MyTimesheet/Controllers/EmployeesController.cs new file mode 100644 index 0000000..d0a299e --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Controllers/EmployeesController.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using MyTimesheet.Models; + +namespace MyTimesheet.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class EmployeesController : ControllerBase + { + private readonly TimesheetContext _context; + readonly IConfiguration _config; + public EmployeesController(TimesheetContext context, IConfiguration config) + { + _context = context; + _config = config; + } + + // GET: api/Employees + [HttpGet] + public async Task>> GetEmployee() + { + return await _context.Employee.ToListAsync(); + } + + // GET: api/Employees/5 + [HttpGet("{id}")] + public async Task> GetEmployee(int id) + { + var employee = await _context.Employee.FindAsync(id); + + if (employee == null) + { + return NotFound(); + } + + return employee; + } + + // PUT: api/Employees/5 + [HttpPut("{id}")] + public async Task PutEmployee(int id, Employee employee) + { + if (id != employee.Id) + { + return BadRequest(); + } + + _context.Entry(employee).State = EntityState.Modified; + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!EmployeeExists(id)) + { + return NotFound(); + } + else + { + throw; + } + } + + return NoContent(); + } + + // POST: api/Employees + [HttpPost] + public async Task> PostEmployee(Employee employee) + { + _context.Employee.Add(employee); + await _context.SaveChangesAsync(); + + return CreatedAtAction("GetEmployee", new { id = employee.Id }, employee); + } + + // DELETE: api/Employees/5 + [HttpDelete("{id}")] + public async Task> DeleteEmployee(int id) + { + var employee = await _context.Employee.FindAsync(id); + if (employee == null) + { + return NotFound(); + } + + _context.Employee.Remove(employee); + await _context.SaveChangesAsync(); + + return employee; + } + + private bool EmployeeExists(int id) + { + return _context.Employee.Any(e => e.Id == id); + } + } +} diff --git a/src/MyTimesheet/MyTimesheet/Controllers/TimesheetController.cs b/src/MyTimesheet/MyTimesheet/Controllers/TimesheetController.cs index b2f5a7c..d55b53d 100644 --- a/src/MyTimesheet/MyTimesheet/Controllers/TimesheetController.cs +++ b/src/MyTimesheet/MyTimesheet/Controllers/TimesheetController.cs @@ -1,6 +1,9 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; using MyTimesheet.Models; +using Newtonsoft.Json; +using StackExchange.Redis; using System; using System.Collections.Generic; using System.Linq; @@ -13,9 +16,11 @@ namespace MyTimesheet.Controllers public class TimesheetController : ControllerBase { private readonly TimesheetContext _db; - public TimesheetController(TimesheetContext context) + readonly IConfiguration _config; + public TimesheetController(TimesheetContext context, IConfiguration config) { _db = context; + _config = config; } // GET api/values @@ -34,19 +39,50 @@ public async Task> Get(int id) // POST api/values [HttpPost] - public async Task Post([FromBody] TimesheetEntry value) + public async Task Post([FromBody] TimesheetEntry value) { await _db.Entries.AddAsync(value); await _db.SaveChangesAsync(); + + var cacheConnection = _config.GetValue("CacheConnection").ToString(); + var lazyConnection = new Lazy(() => + { + return ConnectionMultiplexer.Connect(cacheConnection); + }); + + IDatabase cache = lazyConnection.Value.GetDatabase(); + var serializeddata = JsonConvert.SerializeObject(value); + await cache.StringSetAsync($"{value.EmployeeId}",serializeddata); + + var cacheItem = await cache.StringGetAsync($"{value.EmployeeId}"); + + lazyConnection.Value.Dispose(); + + return cacheItem; } // PUT api/values/5 [HttpPut("{id}")] - public async Task Put(int id, [FromBody] TimesheetEntry value) + public async Task Put(int id, [FromBody] TimesheetEntry value) { var entry = await _db.Entries.FindAsync(id); entry = value; await _db.SaveChangesAsync(); + + var lazyConnection = new Lazy(() => + { + + return ConnectionMultiplexer.Connect(_config.GetValue("CacheConnection")); + }); + + IDatabase cache = lazyConnection.Value.GetDatabase(); + + var cacheItem = await cache.StringGetAsync($"{id}"); + var serializeddata = JsonConvert.SerializeObject(value); + await cache.StringSetAsync($"{value.Id}", serializeddata); + lazyConnection.Value.Dispose(); + + return JsonConvert.SerializeObject(value); } // DELETE api/values/5 diff --git a/src/MyTimesheet/MyTimesheet/Migrations/20190122085507_InitialCreate.Designer.cs b/src/MyTimesheet/MyTimesheet/Migrations/20190122085507_InitialCreate.Designer.cs new file mode 100644 index 0000000..7527162 --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Migrations/20190122085507_InitialCreate.Designer.cs @@ -0,0 +1,57 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MyTimesheet.Models; + +namespace MyTimesheet.Migrations +{ + [DbContext(typeof(TimesheetContext))] + [Migration("20190122085507_InitialCreate")] + partial class InitialCreate + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.1-servicing-10028") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("MyTimesheet.Models.TimesheetEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Billable"); + + b.Property("Client"); + + b.Property("Date"); + + b.Property("Description"); + + b.Property("Duration"); + + b.Property("Name"); + + b.Property("Project"); + + b.Property("Surname"); + + b.Property("TimeEnd"); + + b.Property("TimeStart"); + + b.HasKey("Id"); + + b.ToTable("Entries"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/MyTimesheet/MyTimesheet/Migrations/20190122085507_InitialCreate.cs b/src/MyTimesheet/MyTimesheet/Migrations/20190122085507_InitialCreate.cs new file mode 100644 index 0000000..f49fcb6 --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Migrations/20190122085507_InitialCreate.cs @@ -0,0 +1,40 @@ +using System; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace MyTimesheet.Migrations +{ + public partial class InitialCreate : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Entries", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), + Name = table.Column(nullable: true), + Surname = table.Column(nullable: true), + Client = table.Column(nullable: true), + Project = table.Column(nullable: true), + Date = table.Column(nullable: false), + TimeStart = table.Column(nullable: false), + TimeEnd = table.Column(nullable: false), + Duration = table.Column(nullable: false), + Description = table.Column(nullable: true), + Billable = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Entries", x => x.Id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Entries"); + } + } +} diff --git a/src/MyTimesheet/MyTimesheet/Migrations/20190126163356_ChangedNameSurnameToEmployeeId.Designer.cs b/src/MyTimesheet/MyTimesheet/Migrations/20190126163356_ChangedNameSurnameToEmployeeId.Designer.cs new file mode 100644 index 0000000..653274f --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Migrations/20190126163356_ChangedNameSurnameToEmployeeId.Designer.cs @@ -0,0 +1,55 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MyTimesheet.Models; + +namespace MyTimesheet.Migrations +{ + [DbContext(typeof(TimesheetContext))] + [Migration("20190126163356_ChangedNameSurnameToEmployeeId")] + partial class ChangedNameSurnameToEmployeeId + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.1-servicing-10028") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("MyTimesheet.Models.TimesheetEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Billable"); + + b.Property("Client"); + + b.Property("Date"); + + b.Property("Description"); + + b.Property("Duration"); + + b.Property("EmployeeId"); + + b.Property("Project"); + + b.Property("TimeEnd"); + + b.Property("TimeStart"); + + b.HasKey("Id"); + + b.ToTable("Entries"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/MyTimesheet/MyTimesheet/Migrations/20190126163356_ChangedNameSurnameToEmployeeId.cs b/src/MyTimesheet/MyTimesheet/Migrations/20190126163356_ChangedNameSurnameToEmployeeId.cs new file mode 100644 index 0000000..fcb4a8a --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Migrations/20190126163356_ChangedNameSurnameToEmployeeId.cs @@ -0,0 +1,32 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace MyTimesheet.Migrations +{ + public partial class ChangedNameSurnameToEmployeeId : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Name", + table: "Entries"); + + migrationBuilder.RenameColumn( + name: "Surname", + table: "Entries", + newName: "EmployeeId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "EmployeeId", + table: "Entries", + newName: "Surname"); + + migrationBuilder.AddColumn( + name: "Name", + table: "Entries", + nullable: true); + } + } +} diff --git a/src/MyTimesheet/MyTimesheet/Migrations/20190126170818_AttemptNewTable.Designer.cs b/src/MyTimesheet/MyTimesheet/Migrations/20190126170818_AttemptNewTable.Designer.cs new file mode 100644 index 0000000..0a40c53 --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Migrations/20190126170818_AttemptNewTable.Designer.cs @@ -0,0 +1,80 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MyTimesheet.Models; + +namespace MyTimesheet.Migrations +{ + [DbContext(typeof(TimesheetContext))] + [Migration("20190126170818_AttemptNewTable")] + partial class AttemptNewTable + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.1-servicing-10028") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("MyTimesheet.Models.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Name"); + + b.Property("Surname"); + + b.HasKey("Id"); + + b.ToTable("Employee"); + }); + + modelBuilder.Entity("MyTimesheet.Models.TimesheetEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Billable"); + + b.Property("Client"); + + b.Property("Date"); + + b.Property("Description"); + + b.Property("Duration"); + + b.Property("EmployeeId"); + + b.Property("Project"); + + b.Property("TimeEnd"); + + b.Property("TimeStart"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.ToTable("Entries"); + }); + + modelBuilder.Entity("MyTimesheet.Models.TimesheetEntry", b => + { + b.HasOne("MyTimesheet.Models.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/MyTimesheet/MyTimesheet/Migrations/20190126170818_AttemptNewTable.cs b/src/MyTimesheet/MyTimesheet/Migrations/20190126170818_AttemptNewTable.cs new file mode 100644 index 0000000..c22430a --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Migrations/20190126170818_AttemptNewTable.cs @@ -0,0 +1,65 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace MyTimesheet.Migrations +{ + public partial class AttemptNewTable : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "EmployeeId", + table: "Entries", + nullable: false, + oldClrType: typeof(string), + oldNullable: true); + + migrationBuilder.CreateTable( + name: "Employee", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), + Name = table.Column(nullable: false), + Surname = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Employee", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_Entries_EmployeeId", + table: "Entries", + column: "EmployeeId"); + + migrationBuilder.AddForeignKey( + name: "FK_Entries_Employee_EmployeeId", + table: "Entries", + column: "EmployeeId", + principalTable: "Employee", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Entries_Employee_EmployeeId", + table: "Entries"); + + migrationBuilder.DropTable( + name: "Employee"); + + migrationBuilder.DropIndex( + name: "IX_Entries_EmployeeId", + table: "Entries"); + + migrationBuilder.AlterColumn( + name: "EmployeeId", + table: "Entries", + nullable: true, + oldClrType: typeof(int)); + } + } +} diff --git a/src/MyTimesheet/MyTimesheet/Migrations/20190126171629_AttemptNewTableEmployee.Designer.cs b/src/MyTimesheet/MyTimesheet/Migrations/20190126171629_AttemptNewTableEmployee.Designer.cs new file mode 100644 index 0000000..989925d --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Migrations/20190126171629_AttemptNewTableEmployee.Designer.cs @@ -0,0 +1,80 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MyTimesheet.Models; + +namespace MyTimesheet.Migrations +{ + [DbContext(typeof(TimesheetContext))] + [Migration("20190126171629_AttemptNewTableEmployee")] + partial class AttemptNewTableEmployee + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.1-servicing-10028") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("MyTimesheet.Models.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Name"); + + b.Property("Surname"); + + b.HasKey("Id"); + + b.ToTable("Employee"); + }); + + modelBuilder.Entity("MyTimesheet.Models.TimesheetEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Billable"); + + b.Property("Client"); + + b.Property("Date"); + + b.Property("Description"); + + b.Property("Duration"); + + b.Property("EmployeeId"); + + b.Property("Project"); + + b.Property("TimeEnd"); + + b.Property("TimeStart"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.ToTable("Entries"); + }); + + modelBuilder.Entity("MyTimesheet.Models.TimesheetEntry", b => + { + b.HasOne("MyTimesheet.Models.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/MyTimesheet/MyTimesheet/Migrations/20190126171629_AttemptNewTableEmployee.cs b/src/MyTimesheet/MyTimesheet/Migrations/20190126171629_AttemptNewTableEmployee.cs new file mode 100644 index 0000000..3ebb7c2 --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Migrations/20190126171629_AttemptNewTableEmployee.cs @@ -0,0 +1,17 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace MyTimesheet.Migrations +{ + public partial class AttemptNewTableEmployee : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/src/MyTimesheet/MyTimesheet/Migrations/20190126175405_AttemptNewTableEmployeeWithControllers.Designer.cs b/src/MyTimesheet/MyTimesheet/Migrations/20190126175405_AttemptNewTableEmployeeWithControllers.Designer.cs new file mode 100644 index 0000000..ba46296 --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Migrations/20190126175405_AttemptNewTableEmployeeWithControllers.Designer.cs @@ -0,0 +1,80 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MyTimesheet.Models; + +namespace MyTimesheet.Migrations +{ + [DbContext(typeof(TimesheetContext))] + [Migration("20190126175405_AttemptNewTableEmployeeWithControllers")] + partial class AttemptNewTableEmployeeWithControllers + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.1-servicing-10028") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("MyTimesheet.Models.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Name"); + + b.Property("Surname"); + + b.HasKey("Id"); + + b.ToTable("Employee"); + }); + + modelBuilder.Entity("MyTimesheet.Models.TimesheetEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Billable"); + + b.Property("Client"); + + b.Property("Date"); + + b.Property("Description"); + + b.Property("Duration"); + + b.Property("EmployeeId"); + + b.Property("Project"); + + b.Property("TimeEnd"); + + b.Property("TimeStart"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.ToTable("Entries"); + }); + + modelBuilder.Entity("MyTimesheet.Models.TimesheetEntry", b => + { + b.HasOne("MyTimesheet.Models.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/MyTimesheet/MyTimesheet/Migrations/20190126175405_AttemptNewTableEmployeeWithControllers.cs b/src/MyTimesheet/MyTimesheet/Migrations/20190126175405_AttemptNewTableEmployeeWithControllers.cs new file mode 100644 index 0000000..0ede870 --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Migrations/20190126175405_AttemptNewTableEmployeeWithControllers.cs @@ -0,0 +1,17 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace MyTimesheet.Migrations +{ + public partial class AttemptNewTableEmployeeWithControllers : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/src/MyTimesheet/MyTimesheet/Migrations/TimesheetContextModelSnapshot.cs b/src/MyTimesheet/MyTimesheet/Migrations/TimesheetContextModelSnapshot.cs new file mode 100644 index 0000000..5217e7d --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Migrations/TimesheetContextModelSnapshot.cs @@ -0,0 +1,78 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MyTimesheet.Models; + +namespace MyTimesheet.Migrations +{ + [DbContext(typeof(TimesheetContext))] + partial class TimesheetContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.1-servicing-10028") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("MyTimesheet.Models.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Name"); + + b.Property("Surname"); + + b.HasKey("Id"); + + b.ToTable("Employee"); + }); + + modelBuilder.Entity("MyTimesheet.Models.TimesheetEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Billable"); + + b.Property("Client"); + + b.Property("Date"); + + b.Property("Description"); + + b.Property("Duration"); + + b.Property("EmployeeId"); + + b.Property("Project"); + + b.Property("TimeEnd"); + + b.Property("TimeStart"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.ToTable("Entries"); + }); + + modelBuilder.Entity("MyTimesheet.Models.TimesheetEntry", b => + { + b.HasOne("MyTimesheet.Models.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/MyTimesheet/MyTimesheet/Models/Employee.cs b/src/MyTimesheet/MyTimesheet/Models/Employee.cs new file mode 100644 index 0000000..751c95b --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Models/Employee.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace MyTimesheet.Models +{ + public class Employee + { + + public int Id { get; set; } + public int Name { get; set; } + public int Surname { get; set; } + } +} diff --git a/src/MyTimesheet/MyTimesheet/Models/TimesheetContext.cs b/src/MyTimesheet/MyTimesheet/Models/TimesheetContext.cs index 5bf7e22..053ecb6 100644 --- a/src/MyTimesheet/MyTimesheet/Models/TimesheetContext.cs +++ b/src/MyTimesheet/MyTimesheet/Models/TimesheetContext.cs @@ -13,6 +13,7 @@ public TimesheetContext(DbContextOptions options) { } public DbSet Entries { get; set; } + public DbSet Employee { get; set; } } } diff --git a/src/MyTimesheet/MyTimesheet/Models/TimesheetEntry.cs b/src/MyTimesheet/MyTimesheet/Models/TimesheetEntry.cs index 8c65667..712bdc1 100644 --- a/src/MyTimesheet/MyTimesheet/Models/TimesheetEntry.cs +++ b/src/MyTimesheet/MyTimesheet/Models/TimesheetEntry.cs @@ -15,8 +15,8 @@ public class TimesheetEntry */ public int Id { get; set; } - public string Name { get; set; } - public string Surname { get; set; } + public int EmployeeId { get; set; } + public Employee Employee { get; set; } public string Client { get; set; } public string Project { get; set; } public DateTime Date { get; set; } diff --git a/src/MyTimesheet/MyTimesheet/MyTimesheet.csproj b/src/MyTimesheet/MyTimesheet/MyTimesheet.csproj index 54dfccf..a636127 100644 --- a/src/MyTimesheet/MyTimesheet/MyTimesheet.csproj +++ b/src/MyTimesheet/MyTimesheet/MyTimesheet.csproj @@ -9,6 +9,7 @@ + diff --git a/src/MyTimesheet/MyTimesheet/Startup.cs b/src/MyTimesheet/MyTimesheet/Startup.cs index e81072d..c94d92a 100644 --- a/src/MyTimesheet/MyTimesheet/Startup.cs +++ b/src/MyTimesheet/MyTimesheet/Startup.cs @@ -35,9 +35,11 @@ public void ConfigureServices(IServiceCollection services) c.SwaggerDoc("v1", new Info { Title = "My Timesheet API", Version = "v1" }); }); - var connection = @"Server=sql101labs1793591179000.westeurope.cloudapp.azure.com;Database=sql101.#NAME.SURNAME;User Id=myUsername;Password=myPassword;"; + var connection = @"Server=sql101labs1793591179000.westeurope.cloudapp.azure.com;Database=sql101.castello.govender;User Id=castellogovender;Password=P@ssword01;"; services.AddDbContext (options => options.UseSqlServer(connection)); + services.AddSingleton(Configuration); + } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/src/MyTimesheet/MyTimesheet/Views/Employees/Create.cshtml b/src/MyTimesheet/MyTimesheet/Views/Employees/Create.cshtml new file mode 100644 index 0000000..2c0cc1b --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Views/Employees/Create.cshtml @@ -0,0 +1,38 @@ +@model MyTimesheet.Models.Employee + +@{ + ViewData["Title"] = "Create"; +} + +

Create

+ +

Employee

+
+
+
+
+
+
+ + + +
+
+ + + +
+
+ +
+
+
+
+ + + +@section Scripts { + @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} +} diff --git a/src/MyTimesheet/MyTimesheet/Views/Employees/Delete.cshtml b/src/MyTimesheet/MyTimesheet/Views/Employees/Delete.cshtml new file mode 100644 index 0000000..dc2cc05 --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Views/Employees/Delete.cshtml @@ -0,0 +1,33 @@ +@model MyTimesheet.Models.Employee + +@{ + ViewData["Title"] = "Delete"; +} + +

Delete

+ +

Are you sure you want to delete this?

+
+

Employee

+
+
+
+ @Html.DisplayNameFor(model => model.Name) +
+
+ @Html.DisplayFor(model => model.Name) +
+
+ @Html.DisplayNameFor(model => model.Surname) +
+
+ @Html.DisplayFor(model => model.Surname) +
+
+ +
+ + | + Back to List +
+
diff --git a/src/MyTimesheet/MyTimesheet/Views/Employees/Details.cshtml b/src/MyTimesheet/MyTimesheet/Views/Employees/Details.cshtml new file mode 100644 index 0000000..8c527dd --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Views/Employees/Details.cshtml @@ -0,0 +1,30 @@ +@model MyTimesheet.Models.Employee + +@{ + ViewData["Title"] = "Details"; +} + +

Details

+ +
+

Employee

+
+
+
+ @Html.DisplayNameFor(model => model.Name) +
+
+ @Html.DisplayFor(model => model.Name) +
+
+ @Html.DisplayNameFor(model => model.Surname) +
+
+ @Html.DisplayFor(model => model.Surname) +
+
+
+ diff --git a/src/MyTimesheet/MyTimesheet/Views/Employees/Edit.cshtml b/src/MyTimesheet/MyTimesheet/Views/Employees/Edit.cshtml new file mode 100644 index 0000000..520d9a8 --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Views/Employees/Edit.cshtml @@ -0,0 +1,39 @@ +@model MyTimesheet.Models.Employee + +@{ + ViewData["Title"] = "Edit"; +} + +

Edit

+ +

Employee

+
+
+
+
+
+ +
+ + + +
+
+ + + +
+
+ +
+
+
+
+ + + +@section Scripts { + @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} +} diff --git a/src/MyTimesheet/MyTimesheet/Views/Employees/Index.cshtml b/src/MyTimesheet/MyTimesheet/Views/Employees/Index.cshtml new file mode 100644 index 0000000..9b54ca4 --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Views/Employees/Index.cshtml @@ -0,0 +1,41 @@ +@model IEnumerable + +@{ + ViewData["Title"] = "Index"; +} + +

Index

+ +

+ Create New +

+ + + + + + + + + +@foreach (var item in Model) { + + + + + +} + +
+ @Html.DisplayNameFor(model => model.Name) + + @Html.DisplayNameFor(model => model.Surname) +
+ @Html.DisplayFor(modelItem => item.Name) + + @Html.DisplayFor(modelItem => item.Surname) + + Edit | + Details | + Delete +
diff --git a/src/MyTimesheet/MyTimesheet/Views/Shared/_ValidationScriptsPartial.cshtml b/src/MyTimesheet/MyTimesheet/Views/Shared/_ValidationScriptsPartial.cshtml new file mode 100644 index 0000000..ed86611 --- /dev/null +++ b/src/MyTimesheet/MyTimesheet/Views/Shared/_ValidationScriptsPartial.cshtml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/src/MyTimesheet/MyTimesheet/appsettings.json b/src/MyTimesheet/MyTimesheet/appsettings.json index def9159..0b2237b 100644 --- a/src/MyTimesheet/MyTimesheet/appsettings.json +++ b/src/MyTimesheet/MyTimesheet/appsettings.json @@ -4,5 +4,6 @@ "Default": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "CacheConnection" :"101.redis.cache.windows.net.redis.cache.windows.net,abortConnect=false,ssl=true,password=85BYRVqUHV6aW7Jz8zIIxRnaYMgbBd2kwo4bpDiz4vw=" }