From 4db5d463d789dc73d12dab929b4eb997c1af8b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99dzior?= Date: Tue, 3 Dec 2019 22:15:56 -0800 Subject: [PATCH 01/13] add new function to host endpoint which calculates score --- ExpressEntryCalculator.Api/.gitignore | 264 ++++++++++++++++++ ExpressEntryCalculator.Api/Calculate.cs | 198 +++++++++++++ .../ExpressEntryCalculator.Api.csproj | 21 ++ .../Models/ApplicantDataViewModel.cs | 57 ++++ .../Models/PointsSummaryViewModel.cs | 24 ++ ExpressEntryCalculator.Api/host.json | 2 + .../ExpressEntryCalculator.Core.csproj | 2 +- ExpressEntryCalculator.sln | 6 + 8 files changed, 573 insertions(+), 1 deletion(-) create mode 100644 ExpressEntryCalculator.Api/.gitignore create mode 100644 ExpressEntryCalculator.Api/Calculate.cs create mode 100644 ExpressEntryCalculator.Api/ExpressEntryCalculator.Api.csproj create mode 100644 ExpressEntryCalculator.Api/Models/ApplicantDataViewModel.cs create mode 100644 ExpressEntryCalculator.Api/Models/PointsSummaryViewModel.cs create mode 100644 ExpressEntryCalculator.Api/host.json diff --git a/ExpressEntryCalculator.Api/.gitignore b/ExpressEntryCalculator.Api/.gitignore new file mode 100644 index 0000000..ff5b00c --- /dev/null +++ b/ExpressEntryCalculator.Api/.gitignore @@ -0,0 +1,264 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.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 + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# 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 +# TODO: 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 +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable 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 + +# 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 +node_modules/ +orleans.codegen.cs + +# 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 + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# 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/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/ExpressEntryCalculator.Api/Calculate.cs b/ExpressEntryCalculator.Api/Calculate.cs new file mode 100644 index 0000000..dad8950 --- /dev/null +++ b/ExpressEntryCalculator.Api/Calculate.cs @@ -0,0 +1,198 @@ + +using System.IO; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs; +using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.AspNetCore.Http; +using Microsoft.Azure.WebJobs.Host; +using Newtonsoft.Json; +using ExpressEntryCalculator.Core; +using ExpressEntryCalculator.Api.Models; + +namespace ExpressEntryCalculator.Api +{ + public static class Calculate + { + [FunctionName("calculate")] + public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)]HttpRequest req, TraceWriter log) + { + log.Info("C# HTTP trigger function processed a request."); + + string requestBody = new StreamReader(req.Body).ReadToEnd(); + + var model = JsonConvert.DeserializeObject(requestBody); + + //if (!ModelState.IsValid) + //{ + // return View("Index", model); + //} + + //// save model to temp data + //// by clicking browser's back button user expects to see form populated with data + //// so user can quickly change one/more form params and calculate again + //// need to serialize model because TempData can't serialize complex objects + //TempData[APPLICANT_DATA_MODEL_KEY] = JsonConvert.SerializeObject(model); + + int age = AgeHelper.CountAge(model.BirthDate.Value); + int pointForAge; + if (model.SpouseExist == false) + { + pointForAge = AgePointsCalculator.CountPointsForAge(age); + } + else + { + pointForAge = AgePointsCalculator.CountPointsForAgeWithSpouse(age); + } + + + int pointForEducation; + + if (model.SpouseExist == false) + { + pointForEducation = EducationPointsCalculator.CountPointsForEducation(model.EducationLevel); + } + else + { + pointForEducation = EducationPointsCalculator.CountPointsForEducationWithSpouse(model.EducationLevel); + } + + LanguagePoints primaryAplicantFirstLangPoints; + + if (model.TypeOfFirstExam.HasValue) + { + var firstExamType = LanguagePoints.IdentifyingTheTypeOfExam(model.TypeOfFirstExam.Value); + primaryAplicantFirstLangPoints = new LanguagePoints(firstExamType, model.SpeakingPoints, model.WritingPoints, model.ReadingPoints, model.ListeningPoints); + } + else + { + primaryAplicantFirstLangPoints = new LanguagePoints(); + } + + int pointsForSpeaking; + int pointsForWriting; + int pointsForReading; + int pointsForListening; + int pointsForLanguage; + if (model.SpouseExist == false) + { + pointsForSpeaking = LanguagePointsCalculator.LanguagePointsCalculatorWithoutSpouse(primaryAplicantFirstLangPoints.CLBSpeakingPoints); + pointsForWriting = LanguagePointsCalculator.LanguagePointsCalculatorWithoutSpouse(primaryAplicantFirstLangPoints.CLBWritingPoints); + pointsForReading = LanguagePointsCalculator.LanguagePointsCalculatorWithoutSpouse(primaryAplicantFirstLangPoints.CLBReadingPoints); + pointsForListening = LanguagePointsCalculator.LanguagePointsCalculatorWithoutSpouse(primaryAplicantFirstLangPoints.CLBListeningPoints); + } + else + { + pointsForSpeaking = LanguagePointsCalculator.LanguagePointsCalculatorWithSpouse(primaryAplicantFirstLangPoints.CLBSpeakingPoints); + pointsForWriting = LanguagePointsCalculator.LanguagePointsCalculatorWithSpouse(primaryAplicantFirstLangPoints.CLBWritingPoints); + pointsForReading = LanguagePointsCalculator.LanguagePointsCalculatorWithSpouse(primaryAplicantFirstLangPoints.CLBReadingPoints); + pointsForListening = LanguagePointsCalculator.LanguagePointsCalculatorWithSpouse(primaryAplicantFirstLangPoints.CLBListeningPoints); + } + pointsForLanguage = pointsForSpeaking + pointsForWriting + pointsForReading + pointsForListening; + + var secondExamType = LanguagePoints.IdentifyingTheTypeOfExam(model.TypeOfSecondExam); + LanguagePoints primaryAplicantSecondLangPoints = new LanguagePoints(secondExamType, model.SpeakingPointsSecondLanguage, model.WritingPointsSecondLanguage, model.ReadingPointsSecondLanguage, model.ListeningPointsSecondLanguage); + + int pointsForSecondLangSpeaking; + int pointsForSecondLangWriting; ; + int pointsForSecondLangReading; + int pointsForSecondLangListening; + int pointsForSecondLanguage; + + pointsForSecondLangSpeaking = SecondLanguagePointsCalculator.SecondLangPointsCalculator(primaryAplicantSecondLangPoints.CLBSpeakingPoints); + pointsForSecondLangWriting = SecondLanguagePointsCalculator.SecondLangPointsCalculator(primaryAplicantSecondLangPoints.CLBWritingPoints); + pointsForSecondLangReading = SecondLanguagePointsCalculator.SecondLangPointsCalculator(primaryAplicantSecondLangPoints.CLBReadingPoints); + pointsForSecondLangListening = SecondLanguagePointsCalculator.SecondLangPointsCalculator(primaryAplicantSecondLangPoints.CLBListeningPoints); + + pointsForSecondLanguage = pointsForSecondLangSpeaking + pointsForSecondLangWriting + pointsForSecondLangReading + pointsForSecondLangListening; + + int pointsForExperience; + if (model.SpouseExist == false) + { + pointsForExperience = ExperiencePointsCalculator.CountPointsForExperienceWithoutSpouse(model.CanadianExperience); + } + else + { + pointsForExperience = ExperiencePointsCalculator.CountPointsForExperienceWithSpouse(model.CanadianExperience); + } + + int sectionA = pointForAge + pointForEducation + pointsForLanguage + pointsForSecondLanguage + pointsForExperience; + + int pointsForSpouseEducation = 0; + int pointsForSpouseSpeaking = 0; + int pointsForSpouseWriting = 0; + int pointsForSpouseReading = 0; + int pointsForSpouseListening = 0; + int pointsForSpouseLanguage = 0; + int pointsForSpouseExperience = 0; + + if (model.SpouseExist) + { + pointsForSpouseEducation = EducationPointsCalculator.CountPointsForSpouseEducation(model.SpouseEducationLevel); + + LanguagePoints spouseFirstLangPoints; + + if (model.TypeOfSpouseExam.HasValue) + { + var spouseExamType = LanguagePoints.IdentifyingTheTypeOfExam(model.TypeOfSpouseExam.Value); + spouseFirstLangPoints = new LanguagePoints(spouseExamType, model.SpouseSpeakingPoints, model.SpouseWritingPoints, model.SpouseReadingPoints, model.SpouseListeningPoints); + } + else + { + spouseFirstLangPoints = new LanguagePoints(); + } + + pointsForSpouseSpeaking = LanguagePointsCalculator.CalculatorOfSpouseLanguagePoints(spouseFirstLangPoints.CLBSpeakingPoints); + pointsForSpouseWriting = LanguagePointsCalculator.CalculatorOfSpouseLanguagePoints(spouseFirstLangPoints.CLBWritingPoints); + pointsForSpouseReading = LanguagePointsCalculator.CalculatorOfSpouseLanguagePoints(spouseFirstLangPoints.CLBReadingPoints); + pointsForSpouseListening = LanguagePointsCalculator.CalculatorOfSpouseLanguagePoints(spouseFirstLangPoints.CLBListeningPoints); + + pointsForSpouseLanguage = pointsForSpouseSpeaking + pointsForSpouseWriting + pointsForSpouseReading + pointsForSpouseListening; + pointsForSpouseExperience = ExperiencePointsCalculator.CountPointsForSpouseExperience(model.SpouseCanadianExperience); + } + + int sectionB = pointsForSpouseEducation + pointsForSpouseLanguage + pointsForSpouseExperience; + + int sectionC; + sectionC = SkillTransferabilityFactorsCalculator.CalculateSkillTransferabilityFactorsPoints(primaryAplicantFirstLangPoints, model.EducationLevel, model.CanadianExperience, model.ExperienceOutsideCanada); + + int sectionD; + + int canadianFamilyMemberPoints = AdditionalPointsCalculator.GiveAdditionalPoints(model.CanadianFamilyMember); + int canadianEducationPoints = AdditionalPointsCalculator.CanadianEducationPoints(model.CanadianEducation); + int canadianArrangedEmploymentPoints = AdditionalPointsCalculator.CalculatePointsForArrangementEmployment(model.CanadianArrangedEmployment); + int canadianProvincialOrTerritorialNominationPoints = AdditionalPointsCalculator.GiveAdditionalPointsForProvincialOrTerritorialNomination(model.CanadianProvincialOrTerritorialNomination); + int additionalLanguagePoints = 0; + if (primaryAplicantFirstLangPoints.LanguageExamType == LanguagePoints.LanguageExamTypes.TEF + || primaryAplicantFirstLangPoints.LanguageExamType == LanguagePoints.LanguageExamTypes.TCF) + { + additionalLanguagePoints = AdditionalPointsCalculator.GiveAdditionalPointsForLanguages(primaryAplicantFirstLangPoints, primaryAplicantSecondLangPoints); + } + sectionD = canadianFamilyMemberPoints + canadianEducationPoints + canadianArrangedEmploymentPoints + canadianProvincialOrTerritorialNominationPoints + additionalLanguagePoints; + + int totalPointsForExpressEntry; + totalPointsForExpressEntry = sectionA + sectionB + sectionC + sectionD; + + PointsSummaryViewModel points = new PointsSummaryViewModel(); + points.PointsForAge = pointForAge; + points.PointsForEducation = pointForEducation; + points.PointsForFirstLanguage = pointsForLanguage; + points.PointsForSecondLanguage = pointsForSecondLanguage; + points.PointsForCanadianExperience = pointsForExperience; + points.PointsInSectionA = sectionA; + points.PointsForSpouseEducation = pointsForSpouseEducation; + points.PointsForSpouseLanguageExam = pointsForSpouseLanguage; + points.PointsForSpouseCanadianExperience = pointsForSpouseExperience; + points.PointsInSectionB = sectionB; + points.PointsInSectionC = sectionC; + points.PointsInSectionD = sectionD; + points.TotalPointsForExpressEntry = totalPointsForExpressEntry; + //points.LastExpressEntryStats = _expressEntryStats; // TODO:DK + + return (ActionResult)new OkObjectResult(points); + + //return name != null + // ? (ActionResult)new OkObjectResult($"Hello, {name}") + // : new BadRequestObjectResult("Please pass a name on the query string or in the request body"); + } + } +} diff --git a/ExpressEntryCalculator.Api/ExpressEntryCalculator.Api.csproj b/ExpressEntryCalculator.Api/ExpressEntryCalculator.Api.csproj new file mode 100644 index 0000000..9544ac1 --- /dev/null +++ b/ExpressEntryCalculator.Api/ExpressEntryCalculator.Api.csproj @@ -0,0 +1,21 @@ + + + netstandard2.0 + v2 + + + + + + + + + + PreserveNewest + + + PreserveNewest + Never + + + \ No newline at end of file diff --git a/ExpressEntryCalculator.Api/Models/ApplicantDataViewModel.cs b/ExpressEntryCalculator.Api/Models/ApplicantDataViewModel.cs new file mode 100644 index 0000000..79442a3 --- /dev/null +++ b/ExpressEntryCalculator.Api/Models/ApplicantDataViewModel.cs @@ -0,0 +1,57 @@ +using Newtonsoft.Json; +using System; +using System.ComponentModel.DataAnnotations; + +namespace ExpressEntryCalculator.Api.Models +{ + public class ApplicantDataViewModel + { + [Required] + [DataType(DataType.Date)] // TODO:DK might not be needed + public DateTime? BirthDate { get; set; } + public bool SpouseExist { get; set; } + + [Required] + public ushort EducationLevel { get; set; } + + public int? TypeOfFirstExam { get; set; } + + public double SpeakingPoints { get; set; } + public double WritingPoints { get; set; } + public double ReadingPoints { get; set; } + public double ListeningPoints { get; set; } + + public bool SecondLanguage { get; set; } + public int TypeOfSecondExam { get; set; } + + public double SpeakingPointsSecondLanguage { get; set; } + public double WritingPointsSecondLanguage { get; set; } + public double ReadingPointsSecondLanguage { get; set; } + public double ListeningPointsSecondLanguage { get; set; } + + public int CanadianExperience { get; set; } + + [Required] + public ushort SpouseEducationLevel { get; set; } + + public int? TypeOfSpouseExam { get; set; } + public double SpouseSpeakingPoints { get; set; } + public double SpouseWritingPoints { get; set; } + public double SpouseReadingPoints { get; set; } + public double SpouseListeningPoints { get; set; } + + public int SpouseCanadianExperience { get; set; } + + public int ExperienceOutsideCanada { get; set; } + + public bool CanadianFamilyMember { get; set; } + public int CanadianEducation { get; set; } + public int CanadianArrangedEmployment { get; set; } + public bool CanadianProvincialOrTerritorialNomination { get; set; } + + public ApplicantDataViewModel() + { + CanadianEducation = -1; + } + } +} diff --git a/ExpressEntryCalculator.Api/Models/PointsSummaryViewModel.cs b/ExpressEntryCalculator.Api/Models/PointsSummaryViewModel.cs new file mode 100644 index 0000000..160218b --- /dev/null +++ b/ExpressEntryCalculator.Api/Models/PointsSummaryViewModel.cs @@ -0,0 +1,24 @@ +namespace ExpressEntryCalculator.Api.Models +{ + public class PointsSummaryViewModel + { + public int PointsForAge { get; set; } + public int PointsForEducation { get; set; } + public int PointsForFirstLanguage { get; set; } + public int PointsForSecondLanguage { get; set; } + public int PointsForCanadianExperience { get; set; } + public int PointsInSectionA { get; set; } + + public int PointsForSpouseEducation { get; set; } + public int PointsForSpouseLanguageExam { get; set; } + public int PointsForSpouseCanadianExperience { get; set; } + public int PointsInSectionB { get; set; } + + public int PointsInSectionC { get; set; } + + public int PointsInSectionD { get; set; } + + public int TotalPointsForExpressEntry { get; set; } + //public ExpressEntryStats LastExpressEntryStats { get; set; } // TODO:DK + } +} diff --git a/ExpressEntryCalculator.Api/host.json b/ExpressEntryCalculator.Api/host.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/ExpressEntryCalculator.Api/host.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/ExpressEntryCalculator.Core/ExpressEntryCalculator.Core.csproj b/ExpressEntryCalculator.Core/ExpressEntryCalculator.Core.csproj index da80576..d0512a7 100644 --- a/ExpressEntryCalculator.Core/ExpressEntryCalculator.Core.csproj +++ b/ExpressEntryCalculator.Core/ExpressEntryCalculator.Core.csproj @@ -1,7 +1,7 @@  - netcoreapp2.2 + netstandard2.0 Library diff --git a/ExpressEntryCalculator.sln b/ExpressEntryCalculator.sln index ca7a73a..44fd254 100644 --- a/ExpressEntryCalculator.sln +++ b/ExpressEntryCalculator.sln @@ -18,6 +18,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{0FE855C4 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExpressEntryCalculator.AcceptanceTests", "ExpressEntryCalculator.AcceptanceTests\ExpressEntryCalculator.AcceptanceTests.csproj", "{28AC818A-3379-4DDD-84BC-A01E8952CCDA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExpressEntryCalculator.Api", "ExpressEntryCalculator.Api\ExpressEntryCalculator.Api.csproj", "{FFD41CF0-22AF-4165-A3B2-471400B055E7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -40,6 +42,10 @@ Global {28AC818A-3379-4DDD-84BC-A01E8952CCDA}.Debug|Any CPU.Build.0 = Debug|Any CPU {28AC818A-3379-4DDD-84BC-A01E8952CCDA}.Release|Any CPU.ActiveCfg = Release|Any CPU {28AC818A-3379-4DDD-84BC-A01E8952CCDA}.Release|Any CPU.Build.0 = Release|Any CPU + {FFD41CF0-22AF-4165-A3B2-471400B055E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FFD41CF0-22AF-4165-A3B2-471400B055E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FFD41CF0-22AF-4165-A3B2-471400B055E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FFD41CF0-22AF-4165-A3B2-471400B055E7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From c4d889b86b4e983d74e308f0d90c6876fe2716ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99dzior?= Date: Tue, 3 Dec 2019 23:26:27 -0800 Subject: [PATCH 02/13] add static index file rendered for development --- ExpressEntryCalculator.Web/wwwroot/index.html | 801 ++++++++++++++++++ 1 file changed, 801 insertions(+) create mode 100644 ExpressEntryCalculator.Web/wwwroot/index.html diff --git a/ExpressEntryCalculator.Web/wwwroot/index.html b/ExpressEntryCalculator.Web/wwwroot/index.html new file mode 100644 index 0000000..9442dfb --- /dev/null +++ b/ExpressEntryCalculator.Web/wwwroot/index.html @@ -0,0 +1,801 @@ + + + + + + + Express Entry Calculator, Canada Immigration + + + + + + + + + + + + + + +
+
+

Express Entry Calculator

+

+ This tool will help you calculate points for Comprehensive Ranking System (CRS). + Based on your score you are ranked in Canadian immigration system called Express Entry. +

+
+
+ +
+ +
+
+ + +
+
+ +
+
+

Express Entry Calculator

+
+
+ +
+ + +
+
+ +
+
+ + (Choose one of the eight options) + + Warning: + If you earned degree, diploma or certificate outside Canada, you will need to get an Educational Credential Assessments + (ECA) for your degree, diploma or certificate from designated organizations (ECA report must not be more than five years old.). + Read more + +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+ +
+
+ + + Warning: + You must take an approved language test to be eligible for Express Entry! + + + Read more about approved language test: + IELTS, + CELPIP, + TEF, + TCF. + + + Your test results must be less than two years old. Read more + + +
+
+ +
+
+ + + + + + + +
+
+ + + Warning: + To be eligible for Express Entry, your work experience (your occupation) must be classified in the National Occupational Classification + (NOC). + + + Your work experience must also be paid work and classified as Skill Type 0, or Skill Levels A or B. + Read more + + + Your work experience is calculated after having completed the full year worked. If you have worked less than a year, choose "none or less than a year". There is no rounding up. + 1 year full time (1,560 hours total) means + 30 hours/week for 12 months (full-time work which could be performed for more then one employer) or + 15 hours/week for 24 months (part-time work) + Read more + +
+
+ +
+
+ + +
+
+ + + Warning: + To be eligible for Express Entry, your work experience (your occupation) must be classified in the National Occupational Classification + (NOC). + + + Your work experience must also be paid work and classified as Skill Type 0, or Skill Levels A or B. + Read more + + + Your work experience is calculated after having completed the full year worked. If you have worked less than a year, choose "none or less than a year". There is no rounding up. + 1 year full time (1,560 hours total) means + 30 hours/week for 12 months (full-time work which could be performed for more then one employer) or + 15 hours/week for 24 months (part-time work) + Read more + +
+
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ + +
+
+ + + Your valid job offer must be classified in the National Occupational Classification (NOC) as Skill Type 0, or Skill Level A or B + and not be from an embassy, high commission or consulate in Canada. It must be also full-time, paid work. + Check + other requirements that the job offer must meet to be valid. + + + Your valid job offer must be supported by a Labour Market Impact Assessment (LMIA). + Check + the exclusions for this requirement. + +
+
+ +
+
+ + +
+ +
+ +
+
+ + +
+
+ + Warning: If your spouse or common - law partner is citizen or permanent resident of Canada can not be included in your application under Express Entry. +
+
+ +
+
+ + +
+ +
+
+
+ +
+ +
+
+
+ Disclaimer! The information contained in this website is provided for general information purposes only. + Before relying on information contained in this website, users should carefully evaluate its accuracy, completeness, availability, + reliability and relevance to their particular purpose. Nothing contained in this website is to be used as professional advice and this + website is not a substitute for the advice of a lawyer, especially qualified Canadian immigration lawyer. Any reliance you place on + such information is therefore strictly at your own risk. The creator of the Express Entry Calculator is not responsible for, and + expressly disclaims all liability for any loss or damage incurred by use of or reliance on the Express Entry Calculator or the information + contained within this website and cannot guarantee and assumes no legal liability or responsibility for the accuracy or completeness of + the information and up-to-date. Through this website you are able to link to other websites which are not under the control of creator + of the Express Entry Calculator. The Creator of the Express Entry Calculator is not responsible for the accuracy or content of information + contained in these sites and have no control over the nature, content and availability of those sites. +
+
+
+ +
+
+

FAQ

+
+
+ +
+
+ Express Entry is a Canadian immigration system to manage how people with skilled work experience apply to immigrate to Canada. + Express Entry is using to manage applications for permanent residence for these programs: + + Provinces and territories can also recruit candidates from the Express Entry pool through the Provincial Nominee Program (PNP) + to meet local labour market needs. + Ministerial Instructions set out the rules for the Express Entry application management system. +
+
+
+ +
+ +
+
+ Provincial Nominee Program is a program by means of which most provinces and territories in Canada can nominate immigrants. + These immigrants must have the skills, education and work experience to contribute to the economy of that province or territory, + and must want to live there. Each province and territory has its own “streams” (immigration programs that target certain groups) + and criteria for their PNP. For example, in a program stream, provinces and territories may target students, business people, + skilled workers or semi-skilled workers. + The province of Quebec does not have a PNP. See their immigration website to learn more about their programs. +
+
+
+
+ +
+
+ The Comprehensive Ranking System is the points-based system using to assess and score your profile and rank you in the Express Entry pool. +
    +
  • + The CRS gives you a score from the information in your profile, including your: +
      +
    • skills
    • +
    • education
    • +
    • language ability
    • +
    • work experience
    • +
    • other factors
    • +
    +
  • +
  • + The CRS also gives you points for: +
      +
    • Canadian degrees, diplomas or certificates
    • +
    • a valid job offer
    • +
    • a nomination from a province or territory
    • +
    • other factors
    • +
    +
  • +
+ The Government regularly send invitations to apply to the highest-ranking candidates in the pool. If you are invited, you can apply to immigrate as a permanent resident. +
+
+
+
+ +
+
+
    +
  1. Check your number of points for Express Entry using Express Entry Calculator.
  2. +
  3. + Create your Express Entry profile. + An Express Entry profile is a form where you give Canadian Government information about your: +
      +
    • skills
    • +
    • education
    • +
    • language ability
    • +
    • work experience
    • +
    • other details
    • +
    + Once you start an Express Entry profile, you have 60 days to complete it. + The information in your profile will help Canadian Government see if you are eligible for an immigration program managed by Express Entry. + If you meet the criteria, Canadian Government will accept you into its pool of candidates. + Getting into the pool doesn't mean that Canadian Government will invite you to apply for permanent residence. + To be chosen from the pool you need to have one of the highest-ranking scores when Canadian Government send out invitations. + If you are invited, you can apply for permanent residence. + When you apply for permanent residence, you will also need to meet eligibility and admissibility requirements under Canada's immigration law. +
  4. + +
  5. + Get to the group of the highest-ranking candidates in the pool to apply for permanent residence and receive an invitation from the Canadian Government.
    + Canadian Government send + invitations to apply to the candidates with the highest scores in the pool. If Government invite you to apply, + you will have 60 (before 90) days to submit an online + application for permanent residence. + Canadian Government will process most complete applications that have all the supporting documents in six months or less. + You can stay in the pool for up to 12 months as long as you meet the criteria for one of the federal programs. + You should update your profile anytime as your case changes. + If Canadian Government don’t invite you to apply for permanent residence within 12 months of submitting an Express Entry profile, you can submit a new profile. + If you still meet the criteria, you will re-enter the pool. +
  6. +
+
+
+
+
+ +
+
+ There is no fixed minimum number of points, which is enough to guarantee an invitation to apply for permanent residence. + However, you can check the CRS score of the lowest-ranked candidate invited to applying for permanent residence at previous rounds of invitations. + +
+
+
+
+ +
+
+ Express Entry Calculator is a program to calculate points for Express Entry based on Comprehensive Ranking System (CRS) Criteria. + Thus, this calculator can estimate your CSR score before creating an Express Entry profile. +
+
+
+
+
+
+ +
+
+
+
+

© @DateTime.Now.Year - Express Entry Calculator v.2.3.3

+
+
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + From 420dd4972934e5782c09c8d470a9bf0c578239f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99dzior?= Date: Wed, 4 Dec 2019 20:28:45 -0800 Subject: [PATCH 03/13] add stats function; add calls to calculate and stats functions; --- ExpressEntryCalculator.Api/GetLastStats.cs | 31 ++++ .../Models/ExpressEntryStats.cs | 11 ++ .../ExpressEntryCalculator.Web.csproj | 3 +- ExpressEntryCalculator.Web/wwwroot/index.html | 134 +++++++++++++++++- 4 files changed, 174 insertions(+), 5 deletions(-) create mode 100644 ExpressEntryCalculator.Api/GetLastStats.cs create mode 100644 ExpressEntryCalculator.Api/Models/ExpressEntryStats.cs diff --git a/ExpressEntryCalculator.Api/GetLastStats.cs b/ExpressEntryCalculator.Api/GetLastStats.cs new file mode 100644 index 0000000..95bfc56 --- /dev/null +++ b/ExpressEntryCalculator.Api/GetLastStats.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs; +using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using ExpressEntryCalculator.Api.Models; + +namespace ExpressEntryCalculator.Api +{ + public static class GetLastStats + { + [FunctionName("stats")] + public static async Task Run( + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, + ILogger log) + { + log.LogInformation("C# HTTP trigger function processed a request."); + + var lastStats = new ExpressEntryStats + { + InvitationsIssued = 3600, + LowestScore = 471, + RoundDate = new DateTime(2019, 11, 27) + }; + + return new OkObjectResult(lastStats); + } + } +} diff --git a/ExpressEntryCalculator.Api/Models/ExpressEntryStats.cs b/ExpressEntryCalculator.Api/Models/ExpressEntryStats.cs new file mode 100644 index 0000000..f04a66c --- /dev/null +++ b/ExpressEntryCalculator.Api/Models/ExpressEntryStats.cs @@ -0,0 +1,11 @@ +using System; + +namespace ExpressEntryCalculator.Api.Models +{ + public class ExpressEntryStats + { + public DateTime RoundDate { get; set; } + public int LowestScore { get; set; } + public int InvitationsIssued { get; set; } + } +} diff --git a/ExpressEntryCalculator.Web/ExpressEntryCalculator.Web.csproj b/ExpressEntryCalculator.Web/ExpressEntryCalculator.Web.csproj index 6ab7e07..5feecd6 100644 --- a/ExpressEntryCalculator.Web/ExpressEntryCalculator.Web.csproj +++ b/ExpressEntryCalculator.Web/ExpressEntryCalculator.Web.csproj @@ -11,10 +11,11 @@ - + + diff --git a/ExpressEntryCalculator.Web/wwwroot/index.html b/ExpressEntryCalculator.Web/wwwroot/index.html index 9442dfb..4f1421b 100644 --- a/ExpressEntryCalculator.Web/wwwroot/index.html +++ b/ExpressEntryCalculator.Web/wwwroot/index.html @@ -72,8 +72,8 @@

Express Entry Calculator

@@ -82,7 +82,7 @@

Express Entry Calculator

Express Entry Calculator

-
+
@@ -558,13 +558,72 @@

Express Entry Calculator

- + +
+
+
+ +
+ + + + + +
@@ -772,6 +831,7 @@

+ + From 058842cd8328f1caca3139dec980994a6e24e833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99dzior?= Date: Wed, 4 Dec 2019 20:47:38 -0800 Subject: [PATCH 04/13] fix input checkbox issues --- ExpressEntryCalculator.Web/wwwroot/index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ExpressEntryCalculator.Web/wwwroot/index.html b/ExpressEntryCalculator.Web/wwwroot/index.html index 4f1421b..e03c1b5 100644 --- a/ExpressEntryCalculator.Web/wwwroot/index.html +++ b/ExpressEntryCalculator.Web/wwwroot/index.html @@ -210,7 +210,7 @@

Express Entry Calculator

- +

@@ -350,7 +350,7 @@

Express Entry Calculator

- +
@@ -395,7 +395,7 @@

Express Entry Calculator

- +
@@ -408,7 +408,7 @@

Express Entry Calculator

Warning: If your spouse or common - law partner is citizen or permanent resident of Canada can not be included in your application under Express Entry.
- +
From ceb0d4009b837c4539a22d5267e421cbc89ffba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99dzior?= Date: Wed, 4 Dec 2019 20:55:02 -0800 Subject: [PATCH 05/13] fix front-end validation; clean up some todos --- ExpressEntryCalculator.Api/Calculate.cs | 14 ++------------ .../Models/ApplicantDataViewModel.cs | 1 - .../Models/PointsSummaryViewModel.cs | 1 - ExpressEntryCalculator.Web/wwwroot/index.html | 2 +- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/ExpressEntryCalculator.Api/Calculate.cs b/ExpressEntryCalculator.Api/Calculate.cs index dad8950..ad114e6 100644 --- a/ExpressEntryCalculator.Api/Calculate.cs +++ b/ExpressEntryCalculator.Api/Calculate.cs @@ -22,17 +22,12 @@ public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "post var model = JsonConvert.DeserializeObject(requestBody); + // TODO:DK validation to return 400? //if (!ModelState.IsValid) //{ // return View("Index", model); //} - //// save model to temp data - //// by clicking browser's back button user expects to see form populated with data - //// so user can quickly change one/more form params and calculate again - //// need to serialize model because TempData can't serialize complex objects - //TempData[APPLICANT_DATA_MODEL_KEY] = JsonConvert.SerializeObject(model); - int age = AgeHelper.CountAge(model.BirthDate.Value); int pointForAge; if (model.SpouseExist == false) @@ -186,13 +181,8 @@ public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "post points.PointsInSectionC = sectionC; points.PointsInSectionD = sectionD; points.TotalPointsForExpressEntry = totalPointsForExpressEntry; - //points.LastExpressEntryStats = _expressEntryStats; // TODO:DK - - return (ActionResult)new OkObjectResult(points); - //return name != null - // ? (ActionResult)new OkObjectResult($"Hello, {name}") - // : new BadRequestObjectResult("Please pass a name on the query string or in the request body"); + return new OkObjectResult(points); } } } diff --git a/ExpressEntryCalculator.Api/Models/ApplicantDataViewModel.cs b/ExpressEntryCalculator.Api/Models/ApplicantDataViewModel.cs index 79442a3..3eeb12f 100644 --- a/ExpressEntryCalculator.Api/Models/ApplicantDataViewModel.cs +++ b/ExpressEntryCalculator.Api/Models/ApplicantDataViewModel.cs @@ -7,7 +7,6 @@ namespace ExpressEntryCalculator.Api.Models public class ApplicantDataViewModel { [Required] - [DataType(DataType.Date)] // TODO:DK might not be needed public DateTime? BirthDate { get; set; } public bool SpouseExist { get; set; } diff --git a/ExpressEntryCalculator.Api/Models/PointsSummaryViewModel.cs b/ExpressEntryCalculator.Api/Models/PointsSummaryViewModel.cs index 160218b..24e90cb 100644 --- a/ExpressEntryCalculator.Api/Models/PointsSummaryViewModel.cs +++ b/ExpressEntryCalculator.Api/Models/PointsSummaryViewModel.cs @@ -19,6 +19,5 @@ public class PointsSummaryViewModel public int PointsInSectionD { get; set; } public int TotalPointsForExpressEntry { get; set; } - //public ExpressEntryStats LastExpressEntryStats { get; set; } // TODO:DK } } diff --git a/ExpressEntryCalculator.Web/wwwroot/index.html b/ExpressEntryCalculator.Web/wwwroot/index.html index e03c1b5..aa90583 100644 --- a/ExpressEntryCalculator.Web/wwwroot/index.html +++ b/ExpressEntryCalculator.Web/wwwroot/index.html @@ -558,7 +558,7 @@

Express Entry Calculator

- +
From 3ea2e6d76cee821afb9e37872491f987f0b3e03b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99dzior?= Date: Wed, 4 Dec 2019 21:17:57 -0800 Subject: [PATCH 06/13] validation improvements, removing time from last round date --- ExpressEntryCalculator.Web/wwwroot/index.html | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ExpressEntryCalculator.Web/wwwroot/index.html b/ExpressEntryCalculator.Web/wwwroot/index.html index aa90583..721d844 100644 --- a/ExpressEntryCalculator.Web/wwwroot/index.html +++ b/ExpressEntryCalculator.Web/wwwroot/index.html @@ -558,7 +558,7 @@

Express Entry Calculator

- +
@@ -874,15 +874,20 @@

$('#lowestScore').text(lastStats.lowestScore); $('#sadLowestScore').text(lastStats.lowestScore); $('#goodLowestScore').text(lastStats.lowestScore); - $('#roundDate').text(lastStats.roundDate); + $('#roundDate').text(lastStats.roundDate.slice(0, 10)); }); } function calculate() { var $form = $("#frmCalculation"); + var validator = $form.validate(); + if (!validator.form()) { + return; + } + var data = getFormData($form); - return axios.post(`${apiBaseUrl}/calculate`, data) + axios.post(`${apiBaseUrl}/calculate`, data) .then(resp => { var pointsSummary = resp.data; From 74f9d6150cb4225fa75250a7c263d537c6c27e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99dzior?= Date: Wed, 4 Dec 2019 21:23:45 -0800 Subject: [PATCH 07/13] add margin for points summary --- ExpressEntryCalculator.Web/wwwroot/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ExpressEntryCalculator.Web/wwwroot/index.html b/ExpressEntryCalculator.Web/wwwroot/index.html index 721d844..72f75e6 100644 --- a/ExpressEntryCalculator.Web/wwwroot/index.html +++ b/ExpressEntryCalculator.Web/wwwroot/index.html @@ -565,7 +565,7 @@

Express Entry Calculator

-