commit 0e0a5e341724dbe6d15050964bb0bb7bfeeae4c3 Author: Fergal Moran Date: Wed Feb 6 00:18:07 2019 +0000 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d9cd622 --- /dev/null +++ b/.gitignore @@ -0,0 +1,280 @@ +## 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 +*.suo +*.user +*.userosscache +*.sln.docstates +*.vcxproj.filters + +# 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 + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_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 + +# 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 +# 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 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/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/ + +.vscode/ +.idea/ +appsettings.Development.json +appsettings.Production.json diff --git a/Controllers/CalendarController.cs b/Controllers/CalendarController.cs new file mode 100644 index 0000000..d75ac3e --- /dev/null +++ b/Controllers/CalendarController.cs @@ -0,0 +1,26 @@ +using System; +using System.Threading.Tasks; +using retns.api.Data; +using retns.api.Data.Models; +using retns.api.Services.Extensions; +using Microsoft.AspNetCore.Mvc; + +namespace retns.homework.api.Controllers { + [Route("api/[controller]")] + [ApiController] + public class CalendarController : ControllerBase { + private readonly HomeworkService _service; + + public CalendarController(HomeworkService service) { + this._service = service; + } + + [HttpGet] + public async Task> Get() { + var key = DateTime.Now.GetThisMonday() + .ToString("ddMMyy"); + var week = await _service.Get(key); + return Ok(week); + } + } +} diff --git a/Controllers/DocUploadController.cs b/Controllers/DocUploadController.cs new file mode 100644 index 0000000..8e07f08 --- /dev/null +++ b/Controllers/DocUploadController.cs @@ -0,0 +1,35 @@ +using System.Threading.Tasks; +using retns.api.Services; +using retns.api.Services.Extensions; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +namespace retns.homework.api.Controllers { + [Route("api/[controller]")] + [ApiController] + + public class DocUploadController : ControllerBase { + private readonly ILogger _logger; + private readonly HomeworkFileParser _parser; + + public DocUploadController(ILogger logger, HomeworkFileParser parser) { + this._logger = logger; + this._parser = parser; + } + // POST api/values + [HttpPost] + [Consumes("application/x-www-form-urlencoded")] + public async Task Post([FromForm] string url, [FromForm] string filename) { + _logger.LogDebug($"New event received\n\tFile url: {url}\n\tFile name: {filename}"); + if (!filename.EndsWith("doc") && !filename.EndsWith("docx")) { + filename = $"{filename.TrimEnd('.')}.doc"; + } + if (!string.IsNullOrEmpty(url)) { + if (await _parser.ProcessFromUrl(url, filename)) { + return Ok(); + } + } + return BadRequest(); + } + } +} diff --git a/Controllers/GetHomeworkController.cs b/Controllers/GetHomeworkController.cs new file mode 100644 index 0000000..90c7a3e --- /dev/null +++ b/Controllers/GetHomeworkController.cs @@ -0,0 +1,52 @@ +using System; +using System.IO; +using System.Net.Http; +using System.Threading.Tasks; +using retns.api.Data.Settings; +using retns.api.Services.Extensions; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using HtmlAgilityPack; +using System.Linq; + +namespace retns.homework.api.Controllers { + [Route("api/[controller]")] + [ApiController] + public class GetHomeworkController : ControllerBase { + private readonly StorageSettings _storageSettings; + private readonly HttpClient _httpClient; + + public GetHomeworkController(IOptions storageSettings, + IHttpClientFactory httpClientFactory) { + this._storageSettings = storageSettings.Value; + this._httpClient = httpClientFactory.CreateClient("AzureClient"); + } + [HttpGet] + public async Task GetCurrentWeek() { + var fileName = + DateTime.Now.GetThisMonday(DayOfWeek.Monday) + .ToString("ddMMyy") + + ".html"; + + using (var wc = new System.Net.WebClient()) { + var result = await _httpClient.GetAsync($"html/{fileName}"); + if (result.IsSuccessStatusCode) { + Stream stream = await result.Content.ReadAsStreamAsync(); + + HtmlDocument doc = new HtmlDocument(); + doc.Load(stream); + var html = doc.DocumentNode.SelectSingleNode("//body"); + html.Descendants("div") + .Where(n => n.Attributes["title"] != null && n.Attributes["title"].Value == "header") + .FirstOrDefault().RemoveAll(); + + foreach (var node in html.SelectNodes("//table")) { + node.Attributes.Append("class", "table table-striped"); + } + return Ok(html.InnerHtml); + } + } + return NotFound(); + } + } +} diff --git a/Data/HomeworkService.cs b/Data/HomeworkService.cs new file mode 100644 index 0000000..4e462fc --- /dev/null +++ b/Data/HomeworkService.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using retns.api.Data.Models; +using Microsoft.Extensions.Configuration; +using MongoDB.Driver; +using System.Threading.Tasks; + +namespace retns.api.Data { + public class HomeworkService { + private readonly IMongoCollection _homeworkWeeks; + + public HomeworkService(IConfiguration config) { + var client = new MongoClient(config.GetConnectionString("HomeworkDb")); + var database = client.GetDatabase("retns"); + _homeworkWeeks = database.GetCollection("Homework"); + } + + public async Task> Get() { + return (await _homeworkWeeks.FindAsync(homework => true)).ToList(); + } + + public async Task Get(string id) { + return (await _homeworkWeeks.FindAsync(homework => homework.Id == id)).FirstOrDefault(); + } + + public async Task Create(HomeworkWeek homework) { + await _homeworkWeeks.InsertOneAsync(homework); + return homework; + } + + public async Task Update(string id, HomeworkWeek homeworkIn) { + await _homeworkWeeks.ReplaceOneAsync(homework => homework.Id == id, homeworkIn); + } + + public async Task Remove(HomeworkWeek homeworkIn) { + await _homeworkWeeks.DeleteOneAsync(homework => homework.Id == homeworkIn.Id); + } + + public async Task Remove(string id) { + await _homeworkWeeks.DeleteOneAsync(homework => homework.Id == id); + } + } +} \ No newline at end of file diff --git a/Data/Models/HomeworkWeek.cs b/Data/Models/HomeworkWeek.cs new file mode 100644 index 0000000..1653167 --- /dev/null +++ b/Data/Models/HomeworkWeek.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Options; + +namespace retns.api.Data.Models { + public class HomeworkWeek { + public HomeworkWeek(string id) { + this.Id = id; + this.Days = new Dictionary>(); + } + [BsonId] + [BsonRepresentation(BsonType.String)] + public string Id { get; set; } + + [BsonElement("WeekCommencing")] + public DateTime WeekCommencing { get; set; } + + [BsonElement("WeekCNotesommencing")] + public string Notes { get; set; } + + [BsonElement("Subjects")] + public List Subjects; + + [BsonElement("Days")] + [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] + public Dictionary> Days { get; set; } + } +} diff --git a/Data/Settings/StorageSettings.cs b/Data/Settings/StorageSettings.cs new file mode 100644 index 0000000..0f7c8bf --- /dev/null +++ b/Data/Settings/StorageSettings.cs @@ -0,0 +1,6 @@ +namespace retns.api.Data.Settings { + public class StorageSettings { + public string ConnectionString { get; set; } + public string CdnUrl { get; set; } + } +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a17b765 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM microsoft/dotnet:sdk AS build-env +WORKDIR /app +EXPOSE 5000 + +# copy csproj and restore as distinct layers +COPY *.csproj ./ +RUN dotnet restore + +COPY . ./ +RUN dotnet publish -c Release -o out + +# spin up the runtime +FROM microsoft/dotnet:aspnetcore-runtime +WORKDIR /app +COPY --from=build-env /app/out . +ENTRYPOINT ["dotnet", "retns.homework.api.dll"] \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..31e9ed7 --- /dev/null +++ b/Program.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace retns.homework.api { + public class Program { + public static void Main(string[] args) { + CreateWebHostBuilder(args).Build().Run(); + } + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup() + .ConfigureKestrel(options => { + options.Listen(IPAddress.Any, 5000); + }); + } +} diff --git a/Services/AzureHelper.cs b/Services/AzureHelper.cs new file mode 100644 index 0000000..f611597 --- /dev/null +++ b/Services/AzureHelper.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using retns.api.Data.Settings; +using Microsoft.Extensions.Options; +using Microsoft.WindowsAzure.Storage; +using Microsoft.WindowsAzure.Storage.Blob; + +namespace retns.api.Services { + public class AzureHelper { + private readonly CloudBlobClient _blobClient; + + public AzureHelper(IOptions settings) { + var storageAccount = CloudStorageAccount.Parse(settings.Value.ConnectionString); + _blobClient = storageAccount.CreateCloudBlobClient(); + } + + public async Task FileExists(string containerName, string fileName) { + var result = await _blobClient.GetContainerReference(containerName) + .GetBlockBlobReference(fileName) + .ExistsAsync(); + + return result; + } + public async Task UploadFile( + string sourceFile, string containerName, + string destinationFile, string contentType) { + var container = _blobClient.GetContainerReference(containerName); + await container.CreateIfNotExistsAsync(); + + var blockBlob = container.GetBlockBlobReference(destinationFile); + blockBlob.Properties.ContentType = contentType; + + var blockSize = 256 * 1024; + blockBlob.StreamWriteSizeInBytes = blockSize; + var bytesToUpload = (new FileInfo(sourceFile)).Length; + var fileSize = bytesToUpload; + + if (bytesToUpload < blockSize) { + await blockBlob.UploadFromFileAsync(sourceFile); + } else { + var blockIds = new List(); + var index = 1; + long startPosition = 0; + long bytesUploaded = 0; + do { + var bytesToRead = Math.Min(blockSize, bytesToUpload); + var blobContents = new byte[bytesToRead]; + using (var fs = new FileStream(sourceFile, FileMode.Open)) { + fs.Position = startPosition; + fs.Read(blobContents, 0, (int)bytesToRead); + } + + var mre = new ManualResetEvent(false); + var blockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(index.ToString("d6"))); + Console.WriteLine("Now uploading block # " + index.ToString("d6")); + blockIds.Add(blockId); + await blockBlob.PutBlockAsync(blockId, new MemoryStream(blobContents), null); + bytesUploaded += bytesToRead; + bytesToUpload -= bytesToRead; + startPosition += bytesToRead; + index++; + var percentComplete = (double)bytesUploaded / (double)fileSize; + Console.WriteLine("Percent complete = " + percentComplete.ToString("P")); + + mre.Set(); + mre.WaitOne(); + } while (bytesToUpload > 0); + + Console.WriteLine("Now committing block list"); + await blockBlob.PutBlockListAsync(blockIds); + blockBlob.Properties.ContentType = "audio/mpeg"; + await blockBlob.SetPropertiesAsync(); + + Console.WriteLine("Blob uploaded completely."); + } + return $"{containerName}/{destinationFile}"; + } + } +} \ No newline at end of file diff --git a/Services/DocHelpers.cs b/Services/DocHelpers.cs new file mode 100644 index 0000000..01fd43b --- /dev/null +++ b/Services/DocHelpers.cs @@ -0,0 +1,50 @@ +using System; +using System.Diagnostics; +using System.Threading.Tasks; + +namespace retns.api.Services { + public class DocHelpers { + public static Task ConvertToDocx(string fileName) { + return Task.Run(() => { + var outputFile = $"{fileName}.docx"; + var processArgs = $"-d document --format=docx --output {outputFile} {fileName}"; + var process = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = "unoconv", + Arguments = processArgs, + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true, + } + }; + process.Start(); + string result = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + return outputFile; + }); + } + public static Task ConvertToHtml(string fileName, string outputFile) { + return Task.Run(() => { + //unoconv -d document --format=docx --output /tmp/test-case-2.doc.docx /tmp/test-case-2.doc + var processArgs = $"-d document --format=html --output {outputFile} {fileName}"; + var process = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = "unoconv", + Arguments = processArgs, + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true, + } + }; + process.Start(); + var result = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + return outputFile; + }); + } + } +} \ No newline at end of file diff --git a/Services/Extensions/DateTimeExtensions.cs b/Services/Extensions/DateTimeExtensions.cs new file mode 100644 index 0000000..2953671 --- /dev/null +++ b/Services/Extensions/DateTimeExtensions.cs @@ -0,0 +1,15 @@ +using System; + +namespace retns.api.Services.Extensions { + public static class DateTimeExtensions { + public static DateTime GetNextWeekday(this DateTime dt, DayOfWeek day) { + int daysToAdd = ((int)day - (int)dt.DayOfWeek + 7) % 7; + // TODO: Remove the -7 adddays!!!! + return dt.AddDays(-7).AddDays(daysToAdd); + } + public static DateTime GetThisMonday(this DateTime dt, DayOfWeek day = DayOfWeek.Monday) { + int diff = (7 + (dt.DayOfWeek - day)) % 7; + return dt.AddDays(-1 * diff).Date; + } + } +} \ No newline at end of file diff --git a/Services/Extensions/ExtensionHolder.cs b/Services/Extensions/ExtensionHolder.cs new file mode 100644 index 0000000..2d2588f --- /dev/null +++ b/Services/Extensions/ExtensionHolder.cs @@ -0,0 +1,7 @@ +using System; + +namespace retns.api.Services.Extensions { + public static class ExtensionHolder { + + } +} \ No newline at end of file diff --git a/Services/HomeworkFileParser.cs b/Services/HomeworkFileParser.cs new file mode 100644 index 0000000..e2eec5e --- /dev/null +++ b/Services/HomeworkFileParser.cs @@ -0,0 +1,158 @@ +using System; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Wordprocessing; +using retns.api.Data.Models; +using System.Linq; +using System.Collections.Generic; +using retns.api.Data; +using System.IO; +using System.Globalization; +using retns.api.Services.Extensions; +using Microsoft.Extensions.Logging; + +namespace retns.api.Services { + public class HomeworkFileParser { + private readonly AzureHelper _fileUploader; + private readonly HomeworkService _service; + private readonly ILogger _logger; + + public HomeworkFileParser(AzureHelper fileUploader, HomeworkService service, ILogger logger) { + this._logger = logger; + this._fileUploader = fileUploader; + this._service = service; + } + public async Task ProcessFromUrl(string url, string sourceFilename) { + + var extension = new FileInfo(sourceFilename).Extension; + using (var wc = new System.Net.WebClient()) { + + string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + $".{extension}"; + await wc.DownloadFileTaskAsync(new Uri(url), fileName); + if (System.IO.File.Exists(fileName)) { + + if (extension.Equals(".doc")) { + fileName = await DocHelpers.ConvertToDocx(fileName); + } + + if (System.IO.File.Exists(fileName)) { + var id = DateTime.Now.GetNextWeekday(DayOfWeek.Monday).ToString("ddMMyy"); + await _createHtmlFile(id, fileName); + var week = await _processFile(id, fileName); + if (week != null) { + Console.WriteLine("Sending to cosmos"); + await _service.Create(week); + return true; + } + } + } + } + return false; + } + private async Task _downloadFile(string url) { + using (var client = new HttpClient()) { + using (var result = await client.GetAsync(url)) { + if (result.IsSuccessStatusCode) { + return await result.Content.ReadAsByteArrayAsync(); + } + } + } + return null; + } + private static DateTime _parseOrdinalDateTime(string dt) { + string[] expectedFormats = new[] + { + "d'st' MMMM yyyy", + "d'nd' MMMM yyyy", + "d'rd' MMMM yyyy", + "d'th' MMMM yyyy" + }; + + try { + return DateTime.ParseExact(dt, expectedFormats, null, DateTimeStyles.None); + } catch (Exception e) { + throw new InvalidOperationException("Not a valid DateTime string", e); + } + } + private void _processTable(Table node, ref HomeworkWeek week) { + //parse the subjects + week.Subjects = node.Descendants() + .First() + .Skip(2) + .Select(r => r.InnerText) + .ToList(); + short dayIndex = 0; + foreach (var dow in Enum.GetValues(typeof(DayOfWeek)) + .OfType() + .ToList() + .Skip(1).Take(4)) { + + var entries = node.Descendants() + .Skip(dayIndex + 1) + .First() + .Skip(2) + .Select(r => r.InnerText) + .ToArray(); + var days = new Dictionary(); + short entryIndex = 0; + foreach (var entry in entries) { + try { + var subject = week.Subjects[entryIndex++]; + days.Add(subject, entry); + } catch (Exception ex) { + Console.Error.WriteLine(ex.Message); + } + } + week.Days.Add(dow, days); + dayIndex++; + } + } + private Task _processFile(string id, string fileName) { + return Task.Run(() => { + var fi = new FileInfo(fileName); + + var sb = new StringBuilder(); + using (var doc = WordprocessingDocument.Open(fileName, false)) { + var week = new HomeworkWeek(id); + week.WeekCommencing = DateTimeExtensions.GetNextWeekday(DateTime.Now, DayOfWeek.Monday); + var notes = new StringBuilder(); + + var paragraphs = doc.MainDocumentPart.Document.Body.Elements().OfType(); + foreach (var paragraph in paragraphs) { + try { + //check if we got the date + var date = _parseOrdinalDateTime(paragraph.InnerText); + week.WeekCommencing = date; + continue; + } catch (Exception /*ex*/) { + // _logger.LogError(ex.Message); + } + notes.Append(paragraph.InnerText); + notes.Append(Environment.NewLine); + notes.Append(Environment.NewLine); + } + + week.Notes = notes.ToString(); + var table = doc.MainDocumentPart.Document.Body.Elements().OfType().FirstOrDefault(); + if (table == null) return null; + + _processTable(table, ref week); + return week; + } + }); + } + + private async Task _createHtmlFile(string id, string fileName) { + var outputFile = id + ".html"; + var tempFile = Path.Combine(Path.GetTempPath(), outputFile); + var htmlFile = await DocHelpers.ConvertToHtml(fileName, tempFile); + if (File.Exists(htmlFile)) { + await _fileUploader.UploadFile(htmlFile, "html", outputFile, "text/html"); + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/Startup.cs b/Startup.cs new file mode 100644 index 0000000..5b0eb9c --- /dev/null +++ b/Startup.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using retns.api.Data; +using retns.api.Data.Models; +using retns.api.Data.Settings; +using retns.api.Services; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace retns.homework.api { + public class Startup { + public Startup(IConfiguration configuration) { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) { + services.Configure(Configuration.GetSection("StorageSettings")); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + var storageSettings = Configuration.GetSection(nameof(StorageSettings)).Get(); + services.AddHttpClient("AzureClient", client => { + client.BaseAddress = new Uri(storageSettings.CdnUrl); + }); + services.AddCors(options => { + options.AddPolicy( + "AllowAllOrigins", + builder => builder.AllowAnyOrigin() + .AllowAnyHeader()); + + }); + + services.AddMvc(options => { + options.OutputFormatters.OfType().Single().SupportedMediaTypes.Add("text/html"); + }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env) { + if (env.IsDevelopment()) { + app.UseDeveloperExceptionPage(); + } else { + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseHttpsRedirection(); + app.UseCors(builder => { + builder.AllowAnyOrigin().AllowAnyHeader(); + }); + + app.UseMvc(); + } + } +} diff --git a/appsettings.json b/appsettings.json new file mode 100644 index 0000000..7376aad --- /dev/null +++ b/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/retns.homework.api.csproj b/retns.homework.api.csproj new file mode 100644 index 0000000..c7c849a --- /dev/null +++ b/retns.homework.api.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp2.2 + InProcess + + + + + + + + + + + + +