diff --git a/.vs/TraninngLab/v16/.suo b/.vs/TraninngLab/v16/.suo new file mode 100644 index 0000000..f61747c Binary files /dev/null and b/.vs/TraninngLab/v16/.suo differ diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 0000000..1aa02a1 --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,8 @@ +{ + "ExpandedNodes": [ + "\\Backend", + "\\Backend\\WebApi\\WebApi", + "\\Backend\\WebApi\\WebApi\\AuthServices" + ], + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000..69a325e Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/Backend/AwsSnapShot.sql b/Backend/AwsSnapShot.sql new file mode 100644 index 0000000..0e20a72 --- /dev/null +++ b/Backend/AwsSnapShot.sql @@ -0,0 +1,402 @@ +CREATE DATABASE IF NOT EXISTS `TestingLab` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */; +USE `TestingLab`; +-- MySQL dump 10.13 Distrib 8.0.25, for macos11 (x86_64) +-- +-- Host: traininglab.cwnie53k7o0m.ap-south-1.rds.amazonaws.com Database: TestingLab +-- ------------------------------------------------------ +-- Server version 8.0.25 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!50503 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN; +SET @@SESSION.SQL_LOG_BIN= 0; + +-- +-- GTID state at the beginning of the backup +-- + +SET @@GLOBAL.GTID_PURGED=/*!80000 '+'*/ ''; + +-- +-- Table structure for table `CourseDetails` +-- + +DROP TABLE IF EXISTS `CourseDetails`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `CourseDetails` ( + `CourseID` int NOT NULL AUTO_INCREMENT, + `Name` varchar(45) NOT NULL, + PRIMARY KEY (`CourseID`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `CourseDetails` +-- + +LOCK TABLES `CourseDetails` WRITE; +/*!40000 ALTER TABLE `CourseDetails` DISABLE KEYS */; +INSERT INTO `CourseDetails` VALUES (1,'C# for BackEnd'),(2,'ReactJS for FrontEnd'); +/*!40000 ALTER TABLE `CourseDetails` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `EventActiveUser` +-- + +DROP TABLE IF EXISTS `EventActiveUser`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `EventActiveUser` ( + `userName` varchar(32) NOT NULL, + `EventID` varchar(32) NOT NULL, + `Panelist` tinyint NOT NULL DEFAULT '0', + `Active` tinyint NOT NULL DEFAULT '0', + PRIMARY KEY (`userName`,`EventID`), + KEY `EventID` (`EventID`), + CONSTRAINT `EventID` FOREIGN KEY (`EventID`) REFERENCES `EventList` (`EventID`) ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT `userName2` FOREIGN KEY (`userName`) REFERENCES `UserAuthentication` (`userName`) ON DELETE RESTRICT ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `EventActiveUser` +-- + +LOCK TABLES `EventActiveUser` WRITE; +/*!40000 ALTER TABLE `EventActiveUser` DISABLE KEYS */; +/*!40000 ALTER TABLE `EventActiveUser` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `EventList` +-- + +DROP TABLE IF EXISTS `EventList`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `EventList` ( + `EventID` varchar(32) NOT NULL, + `Name` varchar(45) NOT NULL, + `StartTime` datetime NOT NULL, + `Active` tinyint NOT NULL DEFAULT '0', + `EventURL` varchar(258) NOT NULL, + `EndTime` datetime NOT NULL, + PRIMARY KEY (`EventID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `EventList` +-- + +LOCK TABLES `EventList` WRITE; +/*!40000 ALTER TABLE `EventList` DISABLE KEYS */; +INSERT INTO `EventList` VALUES ('TESTEVENT1','Testing Event with Bollywood','2021-06-20 17:15:00',1,'https://www.youtube.com/watch?v=A_VYgPvMp0E','2021-07-20 17:15:00'); +/*!40000 ALTER TABLE `EventList` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `InviteList` +-- + +DROP TABLE IF EXISTS `InviteList`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `InviteList` ( + `email` varchar(32) NOT NULL, + PRIMARY KEY (`email`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `InviteList` +-- + +LOCK TABLES `InviteList` WRITE; +/*!40000 ALTER TABLE `InviteList` DISABLE KEYS */; +INSERT INTO `InviteList` VALUES ('abh1abii101@gmail.com'),('abhi@gmail.com'),('admin@abiistudio.com'); +/*!40000 ALTER TABLE `InviteList` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `LevelSlab` +-- + +DROP TABLE IF EXISTS `LevelSlab`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `LevelSlab` ( + `LevelNo` int NOT NULL AUTO_INCREMENT, + `LevelName` varchar(45) NOT NULL, + `MinimumScore` float NOT NULL, + PRIMARY KEY (`LevelNo`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `LevelSlab` +-- + +LOCK TABLES `LevelSlab` WRITE; +/*!40000 ALTER TABLE `LevelSlab` DISABLE KEYS */; +INSERT INTO `LevelSlab` VALUES (1,'Amateur',0),(2,'Novice',30),(3,'Intermediate',60),(4,'Expert',120),(5,'AntiSocial',260); +/*!40000 ALTER TABLE `LevelSlab` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `SubCourseDetails` +-- + +DROP TABLE IF EXISTS `SubCourseDetails`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `SubCourseDetails` ( + `SubCourseID` int NOT NULL AUTO_INCREMENT, + `Name` varchar(45) NOT NULL, + `SubCourseURL` varchar(258) NOT NULL, + `CourseID` int NOT NULL, + `Title` varchar(45) DEFAULT 'Title', + `Desc` varchar(258) DEFAULT 'Desc', + PRIMARY KEY (`SubCourseID`), + KEY `CourseID2_idx` (`CourseID`), + CONSTRAINT `CourseID2` FOREIGN KEY (`CourseID`) REFERENCES `CourseDetails` (`CourseID`) ON DELETE RESTRICT ON UPDATE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `SubCourseDetails` +-- + +LOCK TABLES `SubCourseDetails` WRITE; +/*!40000 ALTER TABLE `SubCourseDetails` DISABLE KEYS */; +INSERT INTO `SubCourseDetails` VALUES (1,'An Introduction to C# learning cycle.','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/C%23_for_BackEnd/01.An_Introduction_To_The_C%23_Learning_Cycle.mp4',1,'Title','Desc'),(2,'How To Install Visual Studio-2019','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/C%23_for_BackEnd/02.How_To_Install_Visual_Studio-2019.mp4',1,'How To Install Visual Studio-2019','Desc'),(3,' Intro to Visual Studio 2019, What\'s New?','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/C%23_for_BackEnd/03.Intro_to_Visual_Studio_2019-What\'s_New%2C_What\'s_Better%2C_and_Why_You_Should_Upgrade.mp4',1,' Intro to Visual Studio 2019, What\'s New?','Desc'),(4,'Top 10 Hidden Gems in Visual Studio','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/C%23_for_BackEnd/04.Top_10_Hidden_Gems_in_Visual_Studio-Speed_Up_Development_Without_Increasing_Your_Costs.mp4',1,' Top 10 Hidden Gems in Visual Studio ','Desc'),(5,'Visual Studio Editor Tips','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/C%23_for_BackEnd/05.15_Visual_Studio_Editor_Tips_including_Intellicode_and_EditorConfig.mp4',1,'Visual Studio Editor Tips','Desc'),(6,'Getting help online as a Developer','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/C%23_for_BackEnd/06.How_to_Get_Help_Online_as_a_Software_Developer.mp4',1,'Getting help online as a Developer ','Desc'),(7,'Debugging and Breakpoints','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/C%23_for_BackEnd/07.C%23_Debugging__Breakpoints.mp4',1,'Debugging and Breakpoints ','Desc'),(8,'Handling Exceptions','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/C%23_for_BackEnd/08.Handling_Exceptions_in_C%23_-_When_to_catch_them%2C_where_to_catch_them%2C_and_how_to_catch_them.mp4',1,'Handling Exceptions ','Desc'),(9,'Finding and Fixing Problems','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/C%23_for_BackEnd/09.Debugging_in_C%23_-_Finding_and_Fixing_Problems_in_Your_Application.mp4',1,'Finding and Fixing Problems ','Desc'),(10,'Refactoring in C#','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/C%23_for_BackEnd/10.Refactoring_in_C%23_-_Improving_an_Existing_Application.mp4',1,'Refactoring in C# ','Desc'),(11,'Introduction','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/ReactJS_for_FrontEnd/01.ReactJS_Tutorial_-_1_-_Introduction.mp4',2,'Introduction ','Desc'),(12,'Hello World','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/ReactJS_for_FrontEnd/02.ReactJS_Tutorial_-_2_-_Hello_World.mp4',2,'Hello World ','Desc'),(13,'Folder Structure','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/ReactJS_for_FrontEnd/03.ReactJS_Tutorial_-_3_-_Folder_Structure.mp4',2,'Folder Structure ','Desc'),(14,'Components','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/ReactJS_for_FrontEnd/04.ReactJS_Tutorial_-_4_-_Components.mp4',2,'Components ','Desc'),(15,'Functional Components','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/ReactJS_for_FrontEnd/05.ReactJS_Tutorial_-_5_-_Functional_Components.mp4',2,'Functional Components ','Desc'),(16,'Class Components','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/ReactJS_for_FrontEnd/06.ReactJS_Tutorial_-_6_-_Class_Components.mp4',2,'Class Components ','Desc'),(17,'Hooks Update','https://prespectify-traininglab.s3.ap-south-1.amazonaws.com/ReactJS_for_FrontEnd/07.ReactJS_Tutorial_-_7_-_Hooks_Update.mp4',2,'Hooks Update ','Desc'); +/*!40000 ALTER TABLE `SubCourseDetails` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `TestDetails` +-- + +DROP TABLE IF EXISTS `TestDetails`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `TestDetails` ( + `TestID` int NOT NULL AUTO_INCREMENT, + `TestName` varchar(45) NOT NULL, + `CourseID` int NOT NULL, + `TestURL` varchar(258) NOT NULL, + PRIMARY KEY (`TestID`), + KEY `CourseID_idx` (`CourseID`), + CONSTRAINT `CourseID` FOREIGN KEY (`CourseID`) REFERENCES `CourseDetails` (`CourseID`) ON DELETE RESTRICT ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `TestDetails` +-- + +LOCK TABLES `TestDetails` WRITE; +/*!40000 ALTER TABLE `TestDetails` DISABLE KEYS */; +/*!40000 ALTER TABLE `TestDetails` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `UserActivityLog` +-- + +DROP TABLE IF EXISTS `UserActivityLog`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `UserActivityLog` ( + `userName` varchar(32) NOT NULL, + `LogInTime` datetime NOT NULL, + `LogOutTime` datetime DEFAULT NULL, + `LogID` int NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`LogID`), + KEY `userName` (`userName`), + CONSTRAINT `userName` FOREIGN KEY (`userName`) REFERENCES `UserAuthentication` (`userName`) ON DELETE RESTRICT ON UPDATE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `UserActivityLog` +-- + +LOCK TABLES `UserActivityLog` WRITE; +/*!40000 ALTER TABLE `UserActivityLog` DISABLE KEYS */; +INSERT INTO `UserActivityLog` VALUES ('abh1abii','2021-06-13 17:30:45','2021-06-13 17:32:45',1),('admin','2021-06-13 17:27:45','2021-06-13 17:30:45',2); +/*!40000 ALTER TABLE `UserActivityLog` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `UserAuthentication` +-- + +DROP TABLE IF EXISTS `UserAuthentication`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `UserAuthentication` ( + `userName` varchar(32) NOT NULL, + `Admin` tinyint NOT NULL DEFAULT '0', + `password` varchar(258) NOT NULL, + `email` varchar(32) NOT NULL, + PRIMARY KEY (`userName`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `UserAuthentication` +-- + +LOCK TABLES `UserAuthentication` WRITE; +/*!40000 ALTER TABLE `UserAuthentication` DISABLE KEYS */; +INSERT INTO `UserAuthentication` VALUES ('abh1abii',0,'ff53ac5fa36921dfea21f422b056461e59be6ce1214acb1fa63c9ace84bf1e98','abh1abii101@gmail.com'),('admin',1,'8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918','admin@abiistudio.com'); +/*!40000 ALTER TABLE `UserAuthentication` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `UserLevel` +-- + +DROP TABLE IF EXISTS `UserLevel`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `UserLevel` ( + `userName` varchar(32) NOT NULL, + `TestScore` float NOT NULL DEFAULT '0', + PRIMARY KEY (`userName`), + CONSTRAINT `userName4` FOREIGN KEY (`userName`) REFERENCES `UserAuthentication` (`userName`) ON DELETE RESTRICT ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `UserLevel` +-- + +LOCK TABLES `UserLevel` WRITE; +/*!40000 ALTER TABLE `UserLevel` DISABLE KEYS */; +INSERT INTO `UserLevel` VALUES ('abh1abii',0),('admin',0); +/*!40000 ALTER TABLE `UserLevel` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `UserProgress` +-- + +DROP TABLE IF EXISTS `UserProgress`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `UserProgress` ( + `userName` varchar(32) NOT NULL, + `Score` float NOT NULL DEFAULT '0', + `courseID` int NOT NULL, + `expirationdate` datetime NOT NULL, + PRIMARY KEY (`CourseID`,`userName`), + KEY `userName3_idx` (`userName`), + CONSTRAINT `courseID3` FOREIGN KEY (`courseID`) REFERENCES `coursedetails` (`CourseID`) ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT `userName3` FOREIGN KEY (`userName`) REFERENCES `UserAuthentication` (`userName`) ON DELETE RESTRICT ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `UserProgress` +-- + +LOCK TABLES `UserProgress` WRITE; +/*!40000 ALTER TABLE `UserProgress` DISABLE KEYS */; +/*!40000 ALTER TABLE `UserProgress` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `blacklisttokens` +-- + +DROP TABLE IF EXISTS `blacklisttokens`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `blacklisttokens` ( + `token` varchar(258) NOT NULL, + `entrytime` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `blacklisttokens` +-- + +LOCK TABLES `blacklisttokens` WRITE; +/*!40000 ALTER TABLE `blacklisttokens` DISABLE KEYS */; +/*!40000 ALTER TABLE `blacklisttokens` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `refreshtokens` +-- + +DROP TABLE IF EXISTS `refreshtokens`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `refreshtokens` ( + `username` varchar(20) NOT NULL, + `refreshtoken` varchar(258) NOT NULL, + `expirationdate` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `refreshtokens` +-- + +LOCK TABLES `refreshtokens` WRITE; +/*!40000 ALTER TABLE `refreshtokens` DISABLE KEYS */; +/*!40000 ALTER TABLE `refreshtokens` ENABLE KEYS */; +UNLOCK TABLES; +SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + + + + + +DROP TABLE IF EXISTS `testquestions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `testquestions` ( + `TestID` int NOT NULL, + `QuestionID` int NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + + +DROP TABLE IF EXISTS `quesans`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `quesans` ( + `QuestionID` int NOT NULL, + `Question` varchar(400) NOT NULL, + `Option1` varchar(100) NOT NULL, + `Option2` varchar(100) NOT NULL, + `Option3` varchar(100) NOT NULL, + `Option4` varchar(100) NOT NULL, + `Answer` int NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +-- Dump completed on 2021-06-30 12:34:39 diff --git a/Backend/WebApi/.gitignore b/Backend/WebApi/.gitignore new file mode 100644 index 0000000..8afdcb6 --- /dev/null +++ b/Backend/WebApi/.gitignore @@ -0,0 +1,454 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# JetBrains Rider +.idea/ +*.sln.iml + +## +## Visual Studio Code +## +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json diff --git a/Backend/WebApi/WebApi.sln b/Backend/WebApi/WebApi.sln new file mode 100644 index 0000000..32a820e --- /dev/null +++ b/Backend/WebApi/WebApi.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31321.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi", "WebApi\WebApi.csproj", "{EB2ED597-43F0-4D99-87BC-930AAB47DC7A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EB2ED597-43F0-4D99-87BC-930AAB47DC7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EB2ED597-43F0-4D99-87BC-930AAB47DC7A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EB2ED597-43F0-4D99-87BC-930AAB47DC7A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EB2ED597-43F0-4D99-87BC-930AAB47DC7A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {34110C2F-5C52-4EED-B75B-FCFD2130DB59} + EndGlobalSection +EndGlobal diff --git a/Backend/WebApi/WebApi/AuthServices/CheckIfSessionActive.cs b/Backend/WebApi/WebApi/AuthServices/CheckIfSessionActive.cs new file mode 100644 index 0000000..79bd997 --- /dev/null +++ b/Backend/WebApi/WebApi/AuthServices/CheckIfSessionActive.cs @@ -0,0 +1,94 @@ +using MySql.Data.MySqlClient; +using System; +using System.Diagnostics; + +namespace WebApi.AuthServices +{ + public class CheckIfSessionActive + { + private static Lazy Initializer = new Lazy(() => new CheckIfSessionActive()); + public static CheckIfSessionActive Instance => Initializer.Value; + private CheckIfSessionActive() + { + } + public bool IfInvalid(string username) + { + using (MySqlConnection conn = new MySqlConnection(DBCreds.connectionString)) + { + try + { + conn.Open(); + MySqlCommand cmd = new MySqlCommand("select * from refreshtokens where username = '" + username + + "' and DATE_ADD(expirationdate,interval 6 day) < now();", conn);//CONFIGURE THE EXPIRATION + MySqlDataReader reader = cmd.ExecuteReader(); + if (reader.Read() == true) + { + UpdateUserActivity(conn,username); + return true; + } + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + finally + { + conn.Close(); + } + return false; + } + } + + private void UpdateUserActivity(MySqlConnection conn,string username) + { + try + { + conn.Open(); + DeleteRefreshToken(conn,username); + MySqlCommand cmd = new MySqlCommand("update UserActivityLog set LogOutTime='" + DateTime.Now.ToString("yyyy-MM-dd H:mm:ss") + + "' where LogID = '" + GetUserID(conn,username) + "';", conn); + MySqlDataReader reader = cmd.ExecuteReader(); + reader.Read(); + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + } + + private int GetUserID(MySqlConnection conn,string username) + { + try + { + conn.Open(); + MySqlCommand cmd = new MySqlCommand("select max(LogID) from UserActivityLog where UserName = '" + username + "';", conn); + MySqlDataReader reader = cmd.ExecuteReader(); + reader.Read(); + int ID = reader.GetInt32(0); + reader.Close(); + return ID; + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + return 0; + } + + private void DeleteRefreshToken(MySqlConnection conn,string username) + { + try + { + conn.Open(); + string query = "delete from refreshokens where username ='" + username + "';"; + MySqlCommand cmd = new MySqlCommand(query, conn); + MySqlDataReader reader = cmd.ExecuteReader(); + reader.Close(); + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + } + } +} diff --git a/Backend/WebApi/WebApi/AuthServices/JwtAuthenticationManager.cs b/Backend/WebApi/WebApi/AuthServices/JwtAuthenticationManager.cs new file mode 100644 index 0000000..be2bd65 --- /dev/null +++ b/Backend/WebApi/WebApi/AuthServices/JwtAuthenticationManager.cs @@ -0,0 +1,46 @@ +using Microsoft.IdentityModel.Tokens; +using System; +using System.Security.Claims; +using System.IdentityModel.Tokens.Jwt; +using System.Text; + +namespace WebApi.AuthServices +{ + public class JwtAuthenticationManager + { + private readonly string key; + public JwtAuthenticationManager(string key) + { + this.key = key; + } + public string GenerateTokenIfValid(string username, string password, bool refresh) + { + if (!LoginServices.Instance.MatchLoginCreds(username, password, refresh)) + { + return null; + } + return GenerateJWTToken(username, password); + } + public string GenerateJWTToken(string username, string password) + { + var tokenHandler = new JwtSecurityTokenHandler(); + var tokenKey = Encoding.ASCII.GetBytes(key); + var tokenDescriptor = new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity(new Claim[] + { + new Claim(ClaimTypes.Name,username), + new Claim("USERSECRET", password) + }), + Expires = DateTime.Now.AddHours(2),//CONFIGURE TO MINUTES OR HOURS JWT TOKEN EXPIRY + SigningCredentials = + new SigningCredentials( + new SymmetricSecurityKey(tokenKey), + SecurityAlgorithms.HmacSha256Signature) + + }; + var token = tokenHandler.CreateToken(tokenDescriptor); + return tokenHandler.WriteToken(token); + } + } +} diff --git a/Backend/WebApi/WebApi/AuthServices/LoginServices.cs b/Backend/WebApi/WebApi/AuthServices/LoginServices.cs new file mode 100644 index 0000000..c388f1f --- /dev/null +++ b/Backend/WebApi/WebApi/AuthServices/LoginServices.cs @@ -0,0 +1,128 @@ +using MySql.Data.MySqlClient; +using System; +using System.Diagnostics; +using System.Web.Helpers; + +namespace WebApi.AuthServices +{ + public class LoginServices + { + private static Lazy Initializer = new Lazy(() => new LoginServices()); + public static LoginServices Instance => Initializer.Value; + public int GetLogIdOfUSer(string username) + { + using (MySqlConnection conn = new MySqlConnection(DBCreds.connectionString)) + { + try + { + conn.Open(); + MySqlCommand cmd = new MySqlCommand("select LogID from UserActivityLog where userName = ?username and LogOutTime is null;", conn); + cmd.Parameters.Add(new MySqlParameter("username", username)); + MySqlDataReader reader = cmd.ExecuteReader(); + int ID = 0; + if(reader.Read()) + reader.GetInt32(0); + reader.Close(); + return ID; + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + finally + { + conn.Close(); + } + } + return 0; + } + public bool MatchLoginCreds(string username, string password,bool refresh) + { + using (MySqlConnection conn = new MySqlConnection(DBCreds.connectionString)) + { + try + { + conn.Open(); + MySqlCommand cmd = new MySqlCommand("select * from UserAuthentication", conn); + MySqlDataReader reader = cmd.ExecuteReader(); + while (reader.Read()) + { + if (reader["userName"].ToString() == username && Crypto.SHA256(password) == reader["password"].ToString()) + { + reader.Close(); + if(!refresh) + AddInUserActivityLog(conn,username); + return true; + } + } + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + finally + { + conn.Close(); + } + return false; + } + } + private void AddInUserActivityLog(MySqlConnection conn,string username) + { + try + { + string query = "insert into UserActivityLog(userName,LogInTime) values('" + + username + "','" + + DateTime.Now.ToString("yyyy-MM-dd H:mm:ss") + "');"; + MySqlCommand cmd = new MySqlCommand(query, conn); + MySqlDataReader reader = cmd.ExecuteReader(); + reader.Close(); + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + } + public void RemovePrevious(string username) + { + using (MySqlConnection conn = new MySqlConnection(DBCreds.connectionString)) + { + try + { + conn.Open(); + MySqlCommand cmd = new MySqlCommand("update UserActivityLog set LogOutTime='" + + DateTime.Now.ToString("yyyy-MM-dd H:mm:ss") + + "' where LogID = '" + GetUserID(conn, username) + "';", conn); + MySqlDataReader reader = cmd.ExecuteReader(); + while (reader.Read()) { } + reader.Close(); + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + finally + { + conn.Close(); + } + } + } + private int GetUserID(MySqlConnection conn, string username) + { + try + { + MySqlCommand cmd = new MySqlCommand("select max(LogId) from UserActivityLog where userName = '" + username + "';", conn); + MySqlDataReader reader = cmd.ExecuteReader(); + reader.Read(); + int ID = reader.GetInt32(0); + reader.Close(); + return ID; + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + return 0; + } + } +} diff --git a/Backend/WebApi/WebApi/AuthServices/LogoutServices.cs b/Backend/WebApi/WebApi/AuthServices/LogoutServices.cs new file mode 100644 index 0000000..e4f438f --- /dev/null +++ b/Backend/WebApi/WebApi/AuthServices/LogoutServices.cs @@ -0,0 +1,71 @@ +using MySql.Data.MySqlClient; +using System; +using System.Diagnostics; + +namespace WebApi.AuthServices +{ + public class LogoutServices + { + private static Lazy Initializer = new Lazy(() => new LogoutServices()); + public static LogoutServices Instance => Initializer.Value; + private LogoutServices() + { + } + public void Logout(string username,string token) + { + using (MySqlConnection conn = new MySqlConnection(DBCreds.connectionString)) + { + try + { + conn.Open(); + DeleteRefreshToken(conn,username); + MySqlCommand cmd = new MySqlCommand("update UserActivityLog set LogOutTime='"+ + DateTime.Now.ToString("yyyy-MM-dd H:mm:ss")+ + "' where LogID = '"+ GetUserID(conn,username)+"';", conn); + MySqlDataReader reader = cmd.ExecuteReader(); + while (reader.Read()) { } + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + finally + { + conn.Close(); + } + } + } + + private void DeleteRefreshToken(MySqlConnection conn,string username) + { + try + { + string query = "delete from RefreshTokens where username ='" + username + "';"; + MySqlCommand cmd = new MySqlCommand(query, conn); + MySqlDataReader reader = cmd.ExecuteReader(); + reader.Close(); + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + } + private int GetUserID(MySqlConnection conn, string username) + { + try + { + MySqlCommand cmd = new MySqlCommand("select max(LogId) from UserActivityLog where userName = '" + username + "';", conn); + MySqlDataReader reader = cmd.ExecuteReader(); + reader.Read(); + int ID = reader.GetInt32(0); + reader.Close(); + return ID; + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + return 0; + } + } +} diff --git a/Backend/WebApi/WebApi/AuthServices/Models/RefreshTokenModel.cs b/Backend/WebApi/WebApi/AuthServices/Models/RefreshTokenModel.cs new file mode 100644 index 0000000..15dbf6e --- /dev/null +++ b/Backend/WebApi/WebApi/AuthServices/Models/RefreshTokenModel.cs @@ -0,0 +1,9 @@ +namespace WebApi.AuthServices.Models +{ + public class RefreshTokenModel + { + public string Username { get; set; } + public string RefreshToken { get; set; } + public System.DateTime ExpirationTime { get; set; } + } +} diff --git a/Backend/WebApi/WebApi/AuthServices/Models/RegisterModel.cs b/Backend/WebApi/WebApi/AuthServices/Models/RegisterModel.cs new file mode 100644 index 0000000..ee3a469 --- /dev/null +++ b/Backend/WebApi/WebApi/AuthServices/Models/RegisterModel.cs @@ -0,0 +1,10 @@ +namespace WebApi.AuthServices.Models +{ + public class RegisterModel + { + public UserPayload UserPayload { get; set; } + + public string Email { get; set; } + + } +} diff --git a/Backend/WebApi/WebApi/AuthServices/Models/UserPayload.cs b/Backend/WebApi/WebApi/AuthServices/Models/UserPayload.cs new file mode 100644 index 0000000..834b0f6 --- /dev/null +++ b/Backend/WebApi/WebApi/AuthServices/Models/UserPayload.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace WebApi.AuthServices.Models +{ + public class UserPayload + { + public string Username { get; set; } + public string Payload { get; set; } + } +} diff --git a/Backend/WebApi/WebApi/AuthServices/RefreshToken/FromJWTToken.cs b/Backend/WebApi/WebApi/AuthServices/RefreshToken/FromJWTToken.cs new file mode 100644 index 0000000..f3bd644 --- /dev/null +++ b/Backend/WebApi/WebApi/AuthServices/RefreshToken/FromJWTToken.cs @@ -0,0 +1,42 @@ +using Microsoft.IdentityModel.Tokens; +using System; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; + +namespace WebApi.RefreshToken +{ + public class FromJWTToken + { + private static Lazy Initializer = new Lazy(() => new FromJWTToken()); + public static FromJWTToken Instance => Initializer.Value; + private FromJWTToken() + { + } + internal ClaimsPrincipal ValidateAndGetClaims(string token) + { + var tokenValidationParameters = new TokenValidationParameters + { + ValidateAudience = false, + ValidateIssuer = false, + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("dasdaswr0q9ur3 0ru208nncrm23c0ru23c0em23r902m3cr23cr32")), + ValidateLifetime = false + }; + try + { + var tokenHandler = new JwtSecurityTokenHandler(); + SecurityToken securityToken; + var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out securityToken); + var jwtSecurityToken = securityToken as JwtSecurityToken; + if (jwtSecurityToken == null || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase)) + return null; + return principal; + } + catch (Exception) + { + throw new Exception(message: "Invalid Token"); + } + } + } +} diff --git a/Backend/WebApi/WebApi/AuthServices/RefreshToken/GenerateRefreshToken.cs b/Backend/WebApi/WebApi/AuthServices/RefreshToken/GenerateRefreshToken.cs new file mode 100644 index 0000000..d516d96 --- /dev/null +++ b/Backend/WebApi/WebApi/AuthServices/RefreshToken/GenerateRefreshToken.cs @@ -0,0 +1,77 @@ +using MySql.Data.MySqlClient; +using System; +using System.Security.Cryptography; +using WebApi.AuthServices.Models; + +namespace WebApi.RefreshToken +{ + public class GenerateRefreshToken + { + private static Lazy Initializer = new Lazy(() => new GenerateRefreshToken()); + public static GenerateRefreshToken Instance => Initializer.Value; + private GenerateRefreshToken() + { + } + public GenerateRefreshToken(string username) + { + RefreshTokenModel refreshTokenEntry = new RefreshTokenModel() + { + Username = username, + RefreshToken = GetRandomRefreshToken(), + ExpirationTime = DateTime.Now // creation time of the token + }; + StoreRefreshToken(refreshTokenEntry); + } + + private void StoreRefreshToken(RefreshTokenModel refreshTokenEntry) + { + using (MySqlConnection conn = new MySqlConnection(DBCreds.connectionString)) + { + try + { + conn.Open(); + DeleteOldRefreshToken(conn,refreshTokenEntry.Username); + string query = "INSERT INTO refreshtokens VALUES('" + + refreshTokenEntry.Username + "', '" + + refreshTokenEntry.RefreshToken + "', '"+ + refreshTokenEntry.ExpirationTime.ToString("yyyy-MM-dd H:mm:ss") + "');"; + MySqlCommand cmd = new MySqlCommand(query, conn); + MySqlDataReader reader = cmd.ExecuteReader(); + reader.Close(); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + } + finally + { + conn.Close(); + } + } + } + + private void DeleteOldRefreshToken(MySqlConnection conn,string username) + { + try + { + string query = "delete from refreshtokens where username ='" + username + "';"; + MySqlCommand cmd = new MySqlCommand(query, conn); + MySqlDataReader reader = cmd.ExecuteReader(); + reader.Close(); + } + catch (Exception) + { + } + } + + private string GetRandomRefreshToken() + { + var randomNumber = new byte[32]; + using (var rng = RandomNumberGenerator.Create()) + { + rng.GetBytes(randomNumber); + return Convert.ToBase64String(randomNumber); + } + } + } +} diff --git a/Backend/WebApi/WebApi/AuthServices/RefreshToken/RefreshJWTToken.cs b/Backend/WebApi/WebApi/AuthServices/RefreshToken/RefreshJWTToken.cs new file mode 100644 index 0000000..d8f671e --- /dev/null +++ b/Backend/WebApi/WebApi/AuthServices/RefreshToken/RefreshJWTToken.cs @@ -0,0 +1,80 @@ +using Microsoft.AspNetCore.Mvc; +using MySql.Data.MySqlClient; +using System; +using System.Linq; +using WebApi.AuthServices; +using WebApi.AuthServices.Models; + +namespace WebApi.RefreshToken +{ + public class RefreshJWTToken : Controller + { + private readonly JwtAuthenticationManager jwtAuthenticationManager; + public RefreshJWTToken(JwtAuthenticationManager jwtAuthenticationManager) + { + this.jwtAuthenticationManager = jwtAuthenticationManager; + } + + public IActionResult RefreshTokenIfValid(string token) + { + try + { + var Principle = FromJWTToken.Instance.ValidateAndGetClaims(token);//check validity of the JWT token and retrieve claims + + if (Principle != null) + { + var username = Principle.Identity.Name; + var password = Principle.Claims.FirstOrDefault(x => + x.Type.ToString().Equals( + "USERSECRET", StringComparison.InvariantCultureIgnoreCase)) + .Value; + Tuple Refreshtoken = RefreshTokenInDB.Instance.Check(username); + if (Refreshtoken is null) + throw new Exception(message: "No Refresh Token for The User"); + DateTime expiryDate = ConvertToSTDDateTime(Refreshtoken.Item2); + string newToken = ""; + + TimeSpan ts = DateTime.Now - expiryDate; + if (ts.TotalDays <= 6) + { + newToken = jwtAuthenticationManager.GenerateTokenIfValid(username, password,true); + new GenerateRefreshToken(username); + } + else + { + LogoutServices.Instance.Logout(username, token); + return Unauthorized( new { Status = "error", + Username = username, + JwtToken = "" }); + } + return Ok(new { Status = "Success", + Username = username, + JwtToken = token }); + + } + else + { + return Unauthorized(new { Status = "Error", + JwtToken = ""}); + } + } + catch (Exception) + { + return Unauthorized(new { Status = "Error", + JwtToken = "" }); + } + } + + private DateTime ConvertToSTDDateTime(string value) + { + try + { + return Convert.ToDateTime(value); + } + catch (FormatException) + { + throw new Exception(message: "error at ConvertToSTDDateTime(string value)"); + } + } + } +} diff --git a/Backend/WebApi/WebApi/AuthServices/RefreshToken/RefreshTokenInDB.cs b/Backend/WebApi/WebApi/AuthServices/RefreshToken/RefreshTokenInDB.cs new file mode 100644 index 0000000..038b37b --- /dev/null +++ b/Backend/WebApi/WebApi/AuthServices/RefreshToken/RefreshTokenInDB.cs @@ -0,0 +1,38 @@ +using MySql.Data.MySqlClient; +using System; +using System.Diagnostics; + +namespace WebApi.RefreshToken +{ + public class RefreshTokenInDB + { + public static RefreshTokenInDB Instance = new RefreshTokenInDB(); + internal Tuple Check(string username) + { + using (MySqlConnection conn = new MySqlConnection(DBCreds.connectionString)) + { + try + { + conn.Open(); + MySqlCommand cmd = new MySqlCommand("select * from refreshtokens;", conn); + MySqlDataReader reader = cmd.ExecuteReader(); + while (reader.Read()) + { + if (reader["username"].ToString() == username) + return new Tuple(reader["refreshtoken"].ToString(), reader["expirationdate"].ToString()); + } + return null; + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + finally + { + conn.Close(); + } + return null; + } + } + } +} diff --git a/Backend/WebApi/WebApi/AuthServices/RegisterServices.cs b/Backend/WebApi/WebApi/AuthServices/RegisterServices.cs new file mode 100644 index 0000000..c5f4582 --- /dev/null +++ b/Backend/WebApi/WebApi/AuthServices/RegisterServices.cs @@ -0,0 +1,95 @@ +using MySql.Data.MySqlClient; +using System; +using System.Diagnostics; +using System.Web.Helpers; +using WebApi.AuthServices.Models; + +namespace WebApi.AuthServices +{ + public class RegisterServices + { + private static Lazy Initializer = new Lazy(() => new RegisterServices()); + public static RegisterServices Instance => Initializer.Value; + public bool RegisterRecordsIfValid(RegisterModel registerModel) + { + using (MySqlConnection conn = new MySqlConnection(DBCreds.connectionString)) + { + try + { + conn.Open(); + MySqlCommand cmd = new MySqlCommand("select * from InviteList;", conn); + MySqlDataReader reader = cmd.ExecuteReader(); + while (reader.Read()) + { + if (reader["email"].ToString() == registerModel.Email) + { + reader.Close(); + DeleteInvitation(conn, registerModel.Email); + StoreUserEntries(conn, registerModel); + InitializeUserLevel(conn, registerModel.UserPayload.Username); + return false; + } + } + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + finally + { + conn.Close(); + } + } + return true ; + } + + private void InitializeUserLevel(MySqlConnection conn, string userName) + { + try + { + string query = "insert into UserLevel(userName) values('" + + userName + "');"; + MySqlCommand cmd = new MySqlCommand(query, conn); + MySqlDataReader reader = cmd.ExecuteReader(); + reader.Close(); + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + } + + private void DeleteInvitation(MySqlConnection conn,string email) + { + try + { + string query = "delete from testinglab.InviteList where email ='" + email + "';"; + MySqlCommand cmd = new MySqlCommand(query, conn); + MySqlDataReader reader = cmd.ExecuteReader(); + reader.Close(); + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + } + + private void StoreUserEntries(MySqlConnection conn,RegisterModel registerModel) + { + try + { + string query = "insert into UserAuthentication(username,password,email) values('" + + registerModel.UserPayload.Username + "','" + + Crypto.SHA256(registerModel.UserPayload.Payload) + "','" + + registerModel.Email + "');"; + MySqlCommand cmd = new MySqlCommand(query, conn); + MySqlDataReader reader = cmd.ExecuteReader(); + reader.Close(); + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + } + } +} diff --git a/Backend/WebApi/WebApi/Controllers/ApiController.cs b/Backend/WebApi/WebApi/Controllers/ApiController.cs new file mode 100644 index 0000000..2190ecf --- /dev/null +++ b/Backend/WebApi/WebApi/Controllers/ApiController.cs @@ -0,0 +1,105 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using WebApi.AuthServices; +using WebApi.AuthServices.Models; +using WebApi.RefreshToken; + +namespace WebApi.Controllers +{ + [Produces("application/json")] + [Route("[controller]")] + [ApiController] + [EnableCors("ReactPolicy")] + public class ApiController : ControllerBase + { + private readonly JwtAuthenticationManager jwtAuthenticationManager; + public ApiController(JwtAuthenticationManager jwtAuthenticationManager) + { + this.jwtAuthenticationManager = jwtAuthenticationManager; + } + + [Authorize] + [HttpGet] + [Route("auth")] + public IActionResult GetAuth() + { + return Ok(new { Status = "Success"}); + //bydefault [Authorize] will give 401 status on unauthorized use of jwt token + } + + + [AllowAnonymous] + [HttpPost("login")] + public IActionResult Login([FromBody] UserPayload credentials) + { + string message = ""; + if (CheckIfSessionActive.Instance.IfInvalid(credentials.Username)) + message = "Session was Expired. Logging in Again !\n" ; + if (LoginServices.Instance.GetLogIdOfUSer(credentials.Username) == 0) + { + var token = jwtAuthenticationManager + .GenerateTokenIfValid(credentials.Username, credentials.Payload, false); + if (token == null) + return Unauthorized(new { Status = "Error", + Message = "Wrong credentials" }); + new GenerateRefreshToken(credentials.Username); + return Ok(new { Status = message+" Success", + Username = credentials.Username, + JwtToken = token }); + } + else//temporary fix for front end routing issue + { + LoginServices.Instance.RemovePrevious(credentials.Username); + var token = jwtAuthenticationManager + .GenerateTokenIfValid(credentials.Username, credentials.Payload, false); + if (token == null) + return Unauthorized(new + { + Status = "Error", + Message = "Wrong credentials" + }); + new GenerateRefreshToken(credentials.Username); + return Ok(new + { + Status = message + "already loggedin Success", + Username = credentials.Username, + JwtToken = token + }); + + } + } + + + [AllowAnonymous] + [HttpPost("logout")] + public IActionResult Logout([FromBody] UserPayload credentials) + { + LogoutServices.Instance.Logout(credentials.Username, credentials.Payload); + return Ok(new { Status = "Success", + Message = "Successfully Logged Out"}); + } + + + [AllowAnonymous] + [HttpPost("register")] + public IActionResult Register([FromBody] RegisterModel registerModel) + { + if (!RegisterServices.Instance.RegisterRecordsIfValid(registerModel)) + return Ok(new { Status = "Success", + Message = "User created successfully!" }); + return Unauthorized(new { Status = "Error", + Message = "FAILED why? user already exist or not invited..!!" }); + } + + + [AllowAnonymous] + [HttpPost("refresh/{token}")] + public IActionResult Refresh( string token) + { + return new RefreshJWTToken(jwtAuthenticationManager).RefreshTokenIfValid(token); + } + } +} diff --git a/Backend/WebApi/WebApi/Controllers/QueryCoursesController.cs b/Backend/WebApi/WebApi/Controllers/QueryCoursesController.cs new file mode 100644 index 0000000..94dc097 --- /dev/null +++ b/Backend/WebApi/WebApi/Controllers/QueryCoursesController.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using WebApi.Controllers; +using WebApi.CourseServices; +/* + * Changes mentioned in the last code review were related to naming convention of routes. + * These changes are not implemented as it has already been implemented in the front end. + * We as a team will sit together and clean up the code. A sit together with front end + * and backend was not possible before the code review. + */ + +namespace WebApi.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class QueryCoursesController : ControllerBase + { + public List GetCourse() + { + + + return RetrieveCourse.getInstance().getAllCourses(); + + } + [HttpGet] + [Route("SubCourses")] + public List GetSubCourse([FromQuery] int SubCourseID) + { + return RetrieveSubCourse.getInstance().GetSubCoursesFromCourseID(SubCourseID); + } + } +} \ No newline at end of file diff --git a/Backend/WebApi/WebApi/Controllers/QueryEventActiveUserController.cs b/Backend/WebApi/WebApi/Controllers/QueryEventActiveUserController.cs new file mode 100644 index 0000000..ca1d88f --- /dev/null +++ b/Backend/WebApi/WebApi/Controllers/QueryEventActiveUserController.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using WebApi.EventServices; + +namespace WebApi.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class QueryEventActiveUserController : ControllerBase + { + public List GetAllEventActiveUsers() + { + + + return EventActiveUserRetrieval.getInstance().getAllEventActiveUsers(); + + } + [HttpGet] + [Route("EventActiveUserByID")] + public EventActiveUser GetEventByID([FromQuery] string EventID) + { + return EventActiveUserRetrieval.getInstance().GetEventFromID(EventID); + } + [Route("LogUserToEvent")] + public void LogUserToEvent([FromBody] EventActiveUser User) + { + EventActiveUserRetrieval.getInstance().Add(User); + + } + [Route("LogUserOffEvent")] + public void LogUserOffEvent([FromBody] String User, String eventID) + { + EventActiveUserRetrieval.getInstance().Remove(User,eventID); + + } + } +} \ No newline at end of file diff --git a/Backend/WebApi/WebApi/Controllers/QueryEventsController.cs b/Backend/WebApi/WebApi/Controllers/QueryEventsController.cs new file mode 100644 index 0000000..4d0e4f7 --- /dev/null +++ b/Backend/WebApi/WebApi/Controllers/QueryEventsController.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using WebApi.EventServices; +using WebApi.CourseServices; + +namespace WebApi.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class QueryEventsController : ControllerBase + { + public List GetEvents() + { + + + return RetrieveEvents.getInstance().getAllEvents(); + + } + [HttpGet] + [Route("EventByID")] + public Event GetEventByID([FromQuery] string EventID) + { + return RetrieveEvents.getInstance().GetEventFromID(EventID); + } + } +} \ No newline at end of file diff --git a/Backend/WebApi/WebApi/Controllers/TestController.cs b/Backend/WebApi/WebApi/Controllers/TestController.cs new file mode 100644 index 0000000..1fc6c6d --- /dev/null +++ b/Backend/WebApi/WebApi/Controllers/TestController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using WebApi.TestServices; +using WebApi.TestServices.Model; + +namespace WebApi.Controllers +{ + [Produces("application/json")] + [Route("api/[controller]")] + [ApiController] + public class TestController : Controller + { + public string Get() + { + return "huhuh"; + } + [HttpGet("{id:int}")] + public string GetQnA(int id) + { + return JsonConvert.SerializeObject( QnA.Instance.GetRandomTen(id)); + } + [HttpPost("{courseid:int}/{levelid:int}/update")] + public void SetScore(int courseid,int levelid, [FromBody] ScoreModel score) + { + ScoreCalc.Instance.UpdateScore(courseid,levelid,score); + } + [HttpGet("courseid/{id:int}")] + public string GetLevelInfo(int id) + { + return JsonConvert.SerializeObject(LevelDetails.Instance.GetLevelInfo(id)); + } + } +} diff --git a/Backend/WebApi/WebApi/Controllers/UserProfileController.cs b/Backend/WebApi/WebApi/Controllers/UserProfileController.cs new file mode 100644 index 0000000..0ddb971 --- /dev/null +++ b/Backend/WebApi/WebApi/Controllers/UserProfileController.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using WebApi.UserServices; + +namespace WebApi.Controllers +{ + [Produces("application/json")] + [Route("api/[controller]")] + [ApiController] + [EnableCors("ReactPolicy")] + public class UserProfileController : Controller + { + [HttpGet("{username}")] + public string UserDetailsRequest(string username) + { + return JsonConvert.SerializeObject(UserDetails.Instance.GetDetails(username)); + } + } +} diff --git a/Backend/WebApi/WebApi/CourseServices/Course.cs b/Backend/WebApi/WebApi/CourseServices/Course.cs new file mode 100644 index 0000000..c9d3fdf --- /dev/null +++ b/Backend/WebApi/WebApi/CourseServices/Course.cs @@ -0,0 +1,22 @@ +using System; +namespace WebApi.CourseServices +{ + public class Course + { + int courseID; + public int CourseID + { + get { return courseID; } + set { courseID = value; } + } + string name; + public string Name + { + get { return name; } + set { name = value; } + } + + + + } +} diff --git a/Backend/WebApi/WebApi/CourseServices/RetrieveCourse.cs b/Backend/WebApi/WebApi/CourseServices/RetrieveCourse.cs new file mode 100644 index 0000000..f7aaed1 --- /dev/null +++ b/Backend/WebApi/WebApi/CourseServices/RetrieveCourse.cs @@ -0,0 +1,142 @@ +using System; +using System.Data; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Configuration; +using System.Text; +using System.Threading.Tasks; +using MySql.Data.MySqlClient; +using System.Diagnostics; + +namespace WebApi.CourseServices +{ + public class RetrieveCourse + { + + List CourseList; + + static RetrieveCourse retrieveCourseObject = null; + + private RetrieveCourse() + { + CourseList = new List(); + + + MySqlConnection con = new MySqlConnection(DBCreds.connectionString); + try { + + con.Open(); + string query = "SELECT * from CourseDetails;"; + using (MySqlCommand cmd = new MySqlCommand(query,con)) + { + using (MySqlDataReader rdr = cmd.ExecuteReader()) + { + if (rdr.HasRows) + { + while (rdr.Read()) + { + Course currentCourse = new Course(); + currentCourse.Name = rdr.GetString(1); + currentCourse.CourseID = rdr.GetInt32(0); + CourseList.Add(currentCourse); + } + } + } + } + con.Close(); + } + catch ( Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + public static RetrieveCourse getInstance() + { + + retrieveCourseObject = new RetrieveCourse(); + return retrieveCourseObject; + + } + + public void Add(Course course) + { + CourseList.Add(course); + + + MySqlConnection con = new MySqlConnection(DBCreds.connectionString); + try + { + + + con.Open(); + string query = "Insert INTO CourseDetails(Name) VALUES(\"" + course.Name +"\");"; + MySqlCommand command = new MySqlCommand(query, con); + + MySqlDataReader reader = command.ExecuteReader(); + + + + con.Close(); + } + catch (Exception e) + { + Debug.WriteLine(e.ToString()); + } + } + public int Remove(int CourseID) + { + for (int i = 0; i < CourseList.Count; i++) + { + Course courseAtIndex = CourseList.ElementAt(i); + if (courseAtIndex.CourseID.Equals(CourseID)) + { + CourseList.RemoveAt(i); + + + + + MySqlConnection con = new MySqlConnection(DBCreds.connectionString); + try + { + con.Open(); + string query = "DELETE FROM CourseDetails WHERE CourseID=" + courseAtIndex.CourseID + ";"; + MySqlCommand command = new MySqlCommand(query,con); + + MySqlDataReader reader = command.ExecuteReader(); + con.Close(); + return 1; + } + catch(Exception e) + { + Debug.WriteLine(e.ToString()); + } + } + + } + return 0; + } + public List getAllCourses() + { + + return CourseList; + } + public Course GetCourseFromID(int CourseID) + { + for (int i = 0; i < CourseList.Count; i++) + { + Course CourseAtIndex = CourseList.ElementAt(i); + if (CourseAtIndex.CourseID.Equals(CourseID)) + { + return CourseAtIndex; + } + } + return null; + } + + + } +} + + diff --git a/Backend/WebApi/WebApi/CourseServices/RetrieveSubCourse.cs b/Backend/WebApi/WebApi/CourseServices/RetrieveSubCourse.cs new file mode 100644 index 0000000..e4fc379 --- /dev/null +++ b/Backend/WebApi/WebApi/CourseServices/RetrieveSubCourse.cs @@ -0,0 +1,76 @@ +using System; +using System.Data; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Configuration; +using System.Text; +using System.Threading.Tasks; +using MySql.Data.MySqlClient; +using System.Diagnostics; + +namespace WebApi.CourseServices +{ + public class RetrieveSubCourse + { + + + List SubCourseList; + static RetrieveSubCourse retriveSubCourseObject = null; + + public static RetrieveSubCourse getInstance() + { + + retriveSubCourseObject = new RetrieveSubCourse(); + return retriveSubCourseObject; + + } + + + public List GetSubCoursesFromCourseID(int CourseID) + { + SubCourseList = new List(); + + + MySqlConnection con = new MySqlConnection(DBCreds.connectionString); + try + { + + con.Open(); + string query = "SELECT * from SubCourseDetails WHERE CourseID=" + CourseID + ";"; + using (MySqlCommand cmd = new MySqlCommand(query, con)) + { + using (MySqlDataReader rdr = cmd.ExecuteReader()) + { + if (rdr.HasRows) + { + while (rdr.Read()) + { + SubCourse currentSubCourse = new SubCourse(); + currentSubCourse.Name = rdr.GetString(1); + currentSubCourse.SubCourseID = rdr.GetInt32(0); + currentSubCourse.Url = rdr.GetString(2); + currentSubCourse.CourseID = rdr.GetInt32(3); + currentSubCourse.Title = rdr.GetString(4); + currentSubCourse.Desc = rdr.GetString(5); + SubCourseList.Add(currentSubCourse); + } + } + + } + } + con.Close(); + + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + + } + return SubCourseList; + } + + } +} + + diff --git a/Backend/WebApi/WebApi/CourseServices/SubCourse.cs b/Backend/WebApi/WebApi/CourseServices/SubCourse.cs new file mode 100644 index 0000000..b86b322 --- /dev/null +++ b/Backend/WebApi/WebApi/CourseServices/SubCourse.cs @@ -0,0 +1,46 @@ +using System; +namespace WebApi.CourseServices +{ + public class SubCourse + { + int courseID; + public int CourseID + { + get { return courseID; } + set { courseID = value; } + } + string name; + public string Name + { + get { return name; } + set { name = value; } + } + string url; + public String Url + { + get { return url; } + set { url = value; } + } + int subCourseID; + public int SubCourseID + { + get { return subCourseID; } + set { subCourseID = value; } + } + String title; + public string Title + { + get + { return title; } + set + { title = value; } + } + String desc; + public String Desc + { + get { return desc; } + set { desc = value; } + } + + } +} diff --git a/Backend/WebApi/WebApi/DBCreds.cs b/Backend/WebApi/WebApi/DBCreds.cs new file mode 100644 index 0000000..9604de4 --- /dev/null +++ b/Backend/WebApi/WebApi/DBCreds.cs @@ -0,0 +1,13 @@ +namespace WebApi +{ + public class DBCreds + { + internal static readonly string connectionString = "server = localhost; " + + "userid = root; " + + "password = Abhi@1214; " + + "database = testinglab"; + //internal static readonly string ConnectionString ="server = localhost; userid = root; password = Abh1Ank1; database = TrainingLab"; + //internal static readonly string ConnectionString ="server = localhost; userid = root; password = frontend; database = testinglab"; + //internal static readonly string ConnectionString = "server = traininglab.cwnie53k7o0m.ap-south-1.rds.amazonaws.com; userid = root; password = Prespectify; database = TestingLab"; + } +} diff --git a/Backend/WebApi/WebApi/EventServices/Event.cs b/Backend/WebApi/WebApi/EventServices/Event.cs new file mode 100644 index 0000000..5075907 --- /dev/null +++ b/Backend/WebApi/WebApi/EventServices/Event.cs @@ -0,0 +1,50 @@ +using System; +namespace WebApi.EventServices +{ + public class Event + { + String eventID; + public String EventID + { + get { return eventID; } + set { eventID = value; } + } + String name; + public String Name + { + get { return name; } + set { name = value; } + } + DateTime startTime; + public DateTime StartTime + { + get { return startTime; } + set { startTime = value; } + } + DateTime endTime; + public DateTime EndTime + { + get { return endTime; } + set { endTime = value; } + } + String url; + public String Url + { + get { return url; } + set { url = value; } + } + Boolean active; + public Boolean Active + { + get { return active; } + set { active = value; } + } + public Event() + { + startTime = new DateTime(); + endTime = new DateTime(); + active = false; + + } + } +} diff --git a/Backend/WebApi/WebApi/EventServices/EventActiveUser.cs b/Backend/WebApi/WebApi/EventServices/EventActiveUser.cs new file mode 100644 index 0000000..d166e1e --- /dev/null +++ b/Backend/WebApi/WebApi/EventServices/EventActiveUser.cs @@ -0,0 +1,32 @@ +using System; +namespace WebApi.EventServices +{ + public class EventActiveUser + { + String userName; + public String UserName + { + get { return userName; } + set { userName = value; } + } + String eventID; + public String EventID + { + get { return eventID; } + set { EventID = value; } + } + Boolean panelist; + public Boolean Panelist + { + get { return panelist; } + set { panelist = value; } + + } + Boolean active; + public Boolean Active + { + get { return active; } + set { active = value; } + } + } +} diff --git a/Backend/WebApi/WebApi/EventServices/EventActiveUserRetrieval.cs b/Backend/WebApi/WebApi/EventServices/EventActiveUserRetrieval.cs new file mode 100644 index 0000000..30d0bd4 --- /dev/null +++ b/Backend/WebApi/WebApi/EventServices/EventActiveUserRetrieval.cs @@ -0,0 +1,156 @@ +using System; +using System.Data; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Configuration; +using System.Text; +using System.Threading.Tasks; +using MySql.Data.MySqlClient; +using System.Diagnostics; + +namespace WebApi.EventServices +{ + public class EventActiveUserRetrieval + + { + List EventActiveUserList; + + static EventActiveUserRetrieval EventActiveUserRetrievalObject = null; + + + + + private EventActiveUserRetrieval() + { + EventActiveUserList = new List(); + + + MySqlConnection con = new MySqlConnection(DBCreds.connectionString); + try + { + + con.Open(); + string query = "SELECT * from EventActiveUser where Active=1;"; + using (MySqlCommand cmd = new MySqlCommand(query, con)) + { + using (MySqlDataReader rdr = cmd.ExecuteReader()) + { + if (rdr.HasRows) + { + while (rdr.Read()) + { + EventActiveUser currentObj = new EventActiveUser(); + currentObj.UserName = rdr.GetString(0); + currentObj.EventID = rdr.GetString(1); + currentObj.Panelist = rdr.GetBoolean(2); + currentObj.Active = rdr.GetBoolean(3); + EventActiveUserList.Add(currentObj); + } + } + } + } + con.Close(); + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + public static EventActiveUserRetrieval getInstance() + { + + EventActiveUserRetrievalObject = new EventActiveUserRetrieval(); + return EventActiveUserRetrievalObject; + + } + + + public void Add(EventActiveUser eventActiveUserObj) + { + EventActiveUserList.Add(eventActiveUserObj); + + + MySqlConnection con = new MySqlConnection(DBCreds.connectionString); + try + { + + int activeParameter = eventActiveUserObj.Active ? 1 : 0; + int panelistParameter = eventActiveUserObj.Panelist ? 1 : 0; + + con.Open(); + string query = "Insert INTO EventActiveUser VALUES(\"" + eventActiveUserObj.UserName + "\",\"" + eventActiveUserObj.EventID + "\"," + panelistParameter + "," + activeParameter + ");"; + + MySqlCommand command = new MySqlCommand(query, con); + + MySqlDataReader reader = command.ExecuteReader(); + + + + con.Close(); + } + catch (Exception e) + { + Debug.WriteLine(e.ToString()); + } + } + public int Remove(String userName, String eventID ) + { + for (int i = 0; i < EventActiveUserList.Count; i++) + { + EventActiveUser UserAtIndex = EventActiveUserList.ElementAt(i); + if ((UserAtIndex.UserName.Equals(userName)) && (UserAtIndex.EventID.Equals(eventID))) + { + EventActiveUserList.RemoveAt(i); + + + + + MySqlConnection con = new MySqlConnection(DBCreds.connectionString); + try + { + con.Open(); + string query = "DELETE FROM EventActiveUser WHERE userName=\"" + UserAtIndex.UserName + "\" AND EventID=\""+UserAtIndex.EventID+"\" ;"; + MySqlCommand command = new MySqlCommand(query, con); + + MySqlDataReader reader = command.ExecuteReader(); + con.Close(); + return 1; + } + catch (Exception e) + { + Debug.WriteLine(e.ToString()); + } + } + + } + return 0; + } + + + public List getAllEventActiveUsers() + { + + return EventActiveUserList; + } + + + public EventActiveUser GetEventFromID(String EventID) + { + for (int i = 0; i < EventActiveUserList.Count; i++) + { + EventActiveUser EventAtIndex = EventActiveUserList.ElementAt(i); + if (EventAtIndex.EventID.Equals(EventID)) + { + return EventAtIndex; + } + } + return null; + } + + + } +} + + diff --git a/Backend/WebApi/WebApi/EventServices/RetrieveEvents.cs b/Backend/WebApi/WebApi/EventServices/RetrieveEvents.cs new file mode 100644 index 0000000..dbf0c9e --- /dev/null +++ b/Backend/WebApi/WebApi/EventServices/RetrieveEvents.cs @@ -0,0 +1,123 @@ +using System; +using System.Data; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Configuration; +using System.Text; +using System.Threading.Tasks; +using MySql.Data.MySqlClient; +using System.Diagnostics; + +namespace WebApi.EventServices +{ + public class RetrieveEvents + + { + List activeEventList; + + static RetrieveEvents retrieveEventsObject = null; + + + + + private RetrieveEvents() + { + activeEventList = new List(); + + + MySqlConnection con = new MySqlConnection(DBCreds.connectionString); + try + { + DateTime currentTime = new DateTime(); + currentTime = DateTime.Now; + + con.Open(); + string query = "SELECT * from EventList where ((Active=1) && (\'" + currentTime.ToString("yyyy-MM-dd HH:mm:ss") + "\' BETWEEN StartTime AND EndTime)); "; + using (MySqlCommand cmd = new MySqlCommand(query, con)) + { + using (MySqlDataReader rdr = cmd.ExecuteReader()) + { + if (rdr.HasRows) + { + while (rdr.Read()) + { + Event currentEvent = new Event(); + currentEvent.Name = rdr.GetString(1); + currentEvent.EventID = rdr.GetString(0); + currentEvent.StartTime = rdr.GetDateTime(2); + currentEvent.Active = rdr.GetBoolean(3); + currentEvent.Url = rdr.GetString(4); + currentEvent.EndTime = rdr.GetDateTime(5); + activeEventList.Add(currentEvent); + } + } + } + } + con.Close(); + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + public static RetrieveEvents getInstance() + { + + retrieveEventsObject = new RetrieveEvents(); + return retrieveEventsObject; + + } + + + public void Add(Event eventObj) + { + activeEventList.Add(eventObj); + + + MySqlConnection con = new MySqlConnection(DBCreds.connectionString); + try + { + + int activeParameter = eventObj.Active ? 1 : 0; + con.Open(); + string query = "Insert INTO EventList VALUES(\"" + eventObj.EventID + "\",\"" + eventObj.Name + "\",\'" + eventObj.StartTime.ToString("yyyy-MM-dd HH:mm:ss") + "\'," + activeParameter + ",\"" + eventObj.Url + "\",\'" + eventObj.EndTime.ToString("yyyy-MM-dd HH:mm:ss") + "\');"; + + MySqlCommand command = new MySqlCommand(query, con); + + MySqlDataReader reader = command.ExecuteReader(); + + + + con.Close(); + } + catch (Exception e) + { + Debug.WriteLine(e.ToString()); + } + } + + + + public List getAllEvents() + { + + return activeEventList; + } + public Event GetEventFromID(String EventID) + { + for (int i = 0; i < activeEventList.Count; i++) + { + Event EventAtIndex = activeEventList.ElementAt(i); + if (EventAtIndex.EventID.Equals(EventID)) + { + return EventAtIndex; + } + } + return null; + } + + + } +} diff --git a/Backend/WebApi/WebApi/Program.cs b/Backend/WebApi/WebApi/Program.cs new file mode 100644 index 0000000..e94957b --- /dev/null +++ b/Backend/WebApi/WebApi/Program.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace WebApi +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} diff --git a/Backend/WebApi/WebApi/Properties/launchSettings.json b/Backend/WebApi/WebApi/Properties/launchSettings.json new file mode 100644 index 0000000..13826d7 --- /dev/null +++ b/Backend/WebApi/WebApi/Properties/launchSettings.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:58524", + "sslPort": 44388 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "api", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "WebApi": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "api" , + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Backend/WebApi/WebApi/Startup.cs b/Backend/WebApi/WebApi/Startup.cs new file mode 100644 index 0000000..e4cfbde --- /dev/null +++ b/Backend/WebApi/WebApi/Startup.cs @@ -0,0 +1,80 @@ +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.IdentityModel.Tokens; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System.Text; +using WebApi.AuthServices; + +namespace WebApi +{ + public class Startup + { + private readonly string key = "dasdaswr0q9ur3 0ru208nncrm23c0ru23c0em23r902m3cr23cr32"; + 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.AddCors(); + services.AddControllers(); + services.AddCors(options => + { + options.AddPolicy("AllowAllOrigins", + builder => builder.AllowAnyOrigin()); + }); + + 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(Encoding.ASCII.GetBytes(key)), + ValidateIssuer = false, + ValidateAudience = false, + ClockSkew = System.TimeSpan.Zero, + ValidateLifetime = true + }; + }); + services.AddSingleton(new JwtAuthenticationManager(key)); + services.AddCors(o => o.AddPolicy("ReactPolicy", builder => + { + builder.AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader(); + })); + } + + // 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.UseHttpsRedirection(); + app.UseRouting(); + app.UseCors("ReactPolicy"); + app.UseAuthentication(); + app.UseAuthorization(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + } +} diff --git a/Backend/WebApi/WebApi/TestServices/LevelDetails.cs b/Backend/WebApi/WebApi/TestServices/LevelDetails.cs new file mode 100644 index 0000000..f50f439 --- /dev/null +++ b/Backend/WebApi/WebApi/TestServices/LevelDetails.cs @@ -0,0 +1,55 @@ +using MySql.Data.MySqlClient; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using WebApi.TestServices.Model; +using WebApi.UserServices.Models; + +namespace WebApi.TestServices +{ + public class LevelDetails + { + private static Lazy Initializer = new Lazy(() => new LevelDetails()); + public static LevelDetails Instance => Initializer.Value; + internal List GetLevelInfo(int courseid) + { + int first = 1; + List LevelDetails = new List(); + using (MySqlConnection conn = new MySqlConnection(DBCreds.connectionString)) + { + bool nextinline = false; + try + { + string query = "select testlevelid, testlevelname, hastaken from testdetails where courseid = '"+courseid+"' order by testlevelid"; + conn.Open(); + MySqlCommand cmd = new MySqlCommand(query, conn); + MySqlDataReader reader = cmd.ExecuteReader(); + while (reader.Read()) + { + if (!Convert.ToBoolean(reader["hastaken"]) && first == 1) + { + first = 0; + nextinline = true; + } + else + { + nextinline = false; + } + LevelDetails.Add(new TestlevelModels + { + LevelID = Convert.ToInt32(reader["testlevelid"]), + LevelName = reader["testlevelname"].ToString(), + HasTaken = Convert.ToBoolean(reader["hastaken"]), + NextInLine = nextinline + }) ; + } + reader.Close(); + } + catch (Exception) + { } + } + return LevelDetails; + } + } +} diff --git a/Backend/WebApi/WebApi/TestServices/Model/Option.cs b/Backend/WebApi/WebApi/TestServices/Model/Option.cs new file mode 100644 index 0000000..b530548 --- /dev/null +++ b/Backend/WebApi/WebApi/TestServices/Model/Option.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace WebApi.TestServices.Model +{ + public class Option + { + public string Answer { get; set; } + public bool IsCorrect { get; set; } + } +} diff --git a/Backend/WebApi/WebApi/TestServices/Model/QnAModel.cs b/Backend/WebApi/WebApi/TestServices/Model/QnAModel.cs new file mode 100644 index 0000000..8b2a95f --- /dev/null +++ b/Backend/WebApi/WebApi/TestServices/Model/QnAModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using WebApi.TestServices.Model; + +namespace WebApi.TestServices.Models +{ + public class QnAModel + { + public int QuesID { get; set; } + public string Question { get; set; } + public List