diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3729ff0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/.gitignore b/.gitignore index e071329..154e127 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,477 @@ -.idea -.vscode -.vs -.DS_Store -*.sln.DotSettings.user +## 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/main/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/ \ No newline at end of file +[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 +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 +*.tlog +*.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 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# 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/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# 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 + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml + +## +## 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 diff --git a/.idea/.idea.TodoistSync/.idea/.gitignore b/.idea/.idea.TodoistSync/.idea/.gitignore new file mode 100644 index 0000000..f0d50f0 --- /dev/null +++ b/.idea/.idea.TodoistSync/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/.idea.TodoistSync.iml +/projectSettingsUpdater.xml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.TodoistSync/.idea/encodings.xml b/.idea/.idea.TodoistSync/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.TodoistSync/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.TodoistSync/.idea/indexLayout.xml b/.idea/.idea.TodoistSync/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.TodoistSync/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.TodoistSync/.idea/vcs.xml b/.idea/.idea.TodoistSync/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/.idea.TodoistSync/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TodoistSync.sln b/TodoistSync.sln index 4618b16..1b97147 100644 --- a/TodoistSync.sln +++ b/TodoistSync.sln @@ -1,6 +1,16 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TodoistSync", "TodoistSync\TodoistSync.csproj", "{CAC9D405-2208-4E7C-B518-612A2B99B8A7}" +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34221.43 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TodoistSync", "TodoistSync\TodoistSync.csproj", "{5EC12E74-C583-42B9-AEDF-E6DD20D11DA8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A56EF0DE-ACBA-45A1-A2D8-DDADDF9FAA23}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitignore = .gitignore + README.md = README.md + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -8,9 +18,15 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CAC9D405-2208-4E7C-B518-612A2B99B8A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CAC9D405-2208-4E7C-B518-612A2B99B8A7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CAC9D405-2208-4E7C-B518-612A2B99B8A7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CAC9D405-2208-4E7C-B518-612A2B99B8A7}.Release|Any CPU.Build.0 = Release|Any CPU + {5EC12E74-C583-42B9-AEDF-E6DD20D11DA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5EC12E74-C583-42B9-AEDF-E6DD20D11DA8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5EC12E74-C583-42B9-AEDF-E6DD20D11DA8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5EC12E74-C583-42B9-AEDF-E6DD20D11DA8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3105CC69-4986-4F47-8AB0-38DA58F5BFD8} EndGlobalSection EndGlobal diff --git a/TodoistSync/Controllers/ClickupController.cs b/TodoistSync/Controllers/ClickupController.cs deleted file mode 100644 index 9664ea0..0000000 --- a/TodoistSync/Controllers/ClickupController.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using TodoistSync.Repositories; -using Clickup = TodoistSync.Models.Clickup; -using TodoistSync.Services; - -namespace TodoistSync.Controllers -{ - [Route("[controller]")] - [ApiController] - public class ClickupController : ControllerBase - { - private readonly ClickupService _clickupService; - - public ClickupController(ClickupService clickupService) - { - _clickupService = clickupService; - } - - [HttpPost("webhook")] - public async Task Webhook(Clickup.WebhookEvent webhookEvent) - { - if (webhookEvent.Event == Clickup.WebhookEventType.TaskDeleted) - { - await _clickupService.DeleteTodoistTaskIfExists(webhookEvent.TaskId); - return Ok(); - } - - await _clickupService.CreateOrUpdateTodoistTask(webhookEvent.TaskId); - - return Ok(); - } - } -} diff --git a/TodoistSync/Controllers/TodoistController.cs b/TodoistSync/Controllers/TodoistController.cs deleted file mode 100644 index 36793e3..0000000 --- a/TodoistSync/Controllers/TodoistController.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json; -using TodoistSync.Repositories; -using TodoistSync.Services; -using Todoist = TodoistSync.Models.Todoist; - -namespace TodoistSync.Controllers -{ - [Route("[controller]")] - [ApiController] - public class TodoistController : ControllerBase - { - private readonly ClickupService _clickupService; - private readonly TodoistService _todoistService; - - public TodoistController( - ClickupService clickupService, - TodoistService todoistService) - { - _clickupService = clickupService; - _todoistService = todoistService; - } - - [HttpPost("webhook")] - public async Task Webhook(Todoist.WebhookEvent webhookEvent) - { - if (!webhookEvent.EventData.Labels.Contains(_todoistService.ClickupLabelId)) - { - return Ok(); - } - - var clickupTaskId = _clickupService.GetClickupIdFromTodoistContent(webhookEvent.EventData.Content); - - if (clickupTaskId == null) - { - return Ok(); - } - - switch (webhookEvent.EventName) - { - case "item:completed": - await _clickupService.CompleteTask(clickupTaskId); - break; - case "item:updated": - await _clickupService.UpdateClickupTask(clickupTaskId, webhookEvent.EventData.Due?.Date); - break; - } - - return Ok(); - } - } -} diff --git a/TodoistSync/Controllers/WeatherForecastController.cs b/TodoistSync/Controllers/WeatherForecastController.cs new file mode 100644 index 0000000..0ecf3df --- /dev/null +++ b/TodoistSync/Controllers/WeatherForecastController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; + +namespace TodoistSync.Controllers +{ + [ApiController] + [Route("[controller]")] + public class WeatherForecastController : ControllerBase + { + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + [HttpGet(Name = "GetWeatherForecast")] + public IEnumerable Get() + { + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } + } +} \ No newline at end of file diff --git a/TodoistSync/Dockerfile b/TodoistSync/Dockerfile new file mode 100644 index 0000000..28026c5 --- /dev/null +++ b/TodoistSync/Dockerfile @@ -0,0 +1,22 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base +WORKDIR /app +EXPOSE 80 +EXPOSE 443 + +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +WORKDIR /src +COPY ["TodoistSync/TodoistSync.csproj", "TodoistSync/"] +RUN dotnet restore "TodoistSync/TodoistSync.csproj" +COPY . . +WORKDIR "/src/TodoistSync" +RUN dotnet build "TodoistSync.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "TodoistSync.csproj" -c Release -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "TodoistSync.dll"] \ No newline at end of file diff --git a/TodoistSync/LambdaEntryPoint.cs b/TodoistSync/LambdaEntryPoint.cs deleted file mode 100644 index e46e07f..0000000 --- a/TodoistSync/LambdaEntryPoint.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; - -namespace TodoistSync -{ - /// - /// This class extends from APIGatewayProxyFunction which contains the method FunctionHandlerAsync which is the - /// actual Lambda function entry point. The Lambda handler field should be set to - /// - /// TodoistSync::TodoistSync.LambdaEntryPoint::FunctionHandlerAsync - /// - public class LambdaEntryPoint : - - // The base class must be set to match the AWS service invoking the Lambda function. If not Amazon.Lambda.AspNetCoreServer - // will fail to convert the incoming request correctly into a valid ASP.NET Core request. - // - // API Gateway REST API -> Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction - // API Gateway HTTP API payload version 1.0 -> Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction - // API Gateway HTTP API payload version 2.0 -> Amazon.Lambda.AspNetCoreServer.APIGatewayHttpApiV2ProxyFunction - // Application Load Balancer -> Amazon.Lambda.AspNetCoreServer.ApplicationLoadBalancerFunction - // - // Note: When using the AWS::Serverless::Function resource with an event type of "HttpApi" then payload version 2.0 - // will be the default and you must make Amazon.Lambda.AspNetCoreServer.APIGatewayHttpApiV2ProxyFunction the base class. - Amazon.Lambda.AspNetCoreServer.APIGatewayHttpApiV2ProxyFunction - { - /// - /// The builder has configuration, logging and Amazon API Gateway already configured. The startup class - /// needs to be configured in this method using the UseStartup<>() method. - /// - /// - protected override void Init(IWebHostBuilder builder) - { - builder - .UseStartup() - .UseSentry(); - } - - /// - /// Use this override to customize the services registered with the IHostBuilder. - /// - /// It is recommended not to call ConfigureWebHostDefaults to configure the IWebHostBuilder inside this method. - /// Instead customize the IWebHostBuilder in the Init(IWebHostBuilder) overload. - /// - /// - protected override void Init(IHostBuilder builder) - { - } - } -} diff --git a/TodoistSync/LocalEntryPoint.cs b/TodoistSync/LocalEntryPoint.cs deleted file mode 100644 index c01af57..0000000 --- a/TodoistSync/LocalEntryPoint.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; - -namespace TodoistSync -{ - /// - /// The Main function can be used to run the ASP.NET Core application locally using the Kestrel webserver. - /// - public class LocalEntryPoint - { - 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/TodoistSync/Middleware/SentryEventsFlusherMiddleware.cs b/TodoistSync/Middleware/SentryEventsFlusherMiddleware.cs deleted file mode 100644 index 5eee4fa..0000000 --- a/TodoistSync/Middleware/SentryEventsFlusherMiddleware.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Sentry; - -namespace TodoistSync.Middleware -{ - public class SentryEventsFlusherMiddleware - { - private readonly RequestDelegate _next; - - public SentryEventsFlusherMiddleware(RequestDelegate next) - { - _next = next; - } - - public async Task InvokeAsync(HttpContext context, ISentryClient sentryClient) - { - context.Response.OnCompleted(async () => - { - await sentryClient.FlushAsync(timeout: TimeSpan.FromSeconds(10)); - }); - - await _next(context); - } - } -} diff --git a/TodoistSync/Models/Clickup/Attachment.cs b/TodoistSync/Models/Clickup/Attachment.cs deleted file mode 100644 index cb7e20c..0000000 --- a/TodoistSync/Models/Clickup/Attachment.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using Newtonsoft.Json; - -namespace TodoistSync.Models.Clickup -{ - public class Attachment - { - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("date")] - public string Date { get; set; } - - [JsonProperty("title")] - public string Title { get; set; } - - [JsonProperty("type")] - public long Type { get; set; } - - [JsonProperty("source")] - public long Source { get; set; } - - [JsonProperty("version")] - public long Version { get; set; } - - [JsonProperty("extension")] - public string Extension { get; set; } - - [JsonProperty("thumbnail_small")] - public Uri ThumbnailSmall { get; set; } - - [JsonProperty("thumbnail_large")] - public Uri ThumbnailLarge { get; set; } - - [JsonProperty("is_folder")] - public bool? IsFolder { get; set; } - - [JsonProperty("mimetype")] - public string Mimetype { get; set; } - - [JsonProperty("hidden")] - public bool Hidden { get; set; } - - [JsonProperty("parentid")] - public string ParentId { get; set; } - - [JsonProperty("size")] - public long Size { get; set; } - - [JsonProperty("total_comments")] - public long TotalComments { get; set; } - - [JsonProperty("resolved_comments")] - public long ResolvedComments { get; set; } - - [JsonProperty("user")] - public User User { get; set; } - - [JsonProperty("deleted")] - public bool Deleted { get; set; } - - [JsonProperty("url")] - public Uri Url { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/Checklist.cs b/TodoistSync/Models/Clickup/Checklist.cs deleted file mode 100644 index 0a39209..0000000 --- a/TodoistSync/Models/Clickup/Checklist.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace TodoistSync.Models.Clickup -{ - public class Checklist - { - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("task_id")] - public string TaskId { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("date_created")] - public string DateCreated { get; set; } - - [JsonProperty("orderindex")] - public long Orderindex { get; set; } - - [JsonProperty("creator")] - public long Creator { get; set; } - - [JsonProperty("resolved")] - public long Resolved { get; set; } - - [JsonProperty("unresolved")] - public long Unresolved { get; set; } - - [JsonProperty("items")] - public List Items { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/ChecklistItem.cs b/TodoistSync/Models/Clickup/ChecklistItem.cs deleted file mode 100644 index 78d4d00..0000000 --- a/TodoistSync/Models/Clickup/ChecklistItem.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace TodoistSync.Models.Clickup -{ - public class ChecklistItem - { - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("orderindex")] - public long Orderindex { get; set; } - - [JsonProperty("assignee")] - public User Assignee { get; set; } - - [JsonProperty("resolved")] - public bool Resolved { get; set; } - - [JsonProperty("parent")] - public string Parent { get; set; } - - [JsonProperty("date_created")] - public string DateCreated { get; set; } - - [JsonProperty("children")] - public List Children { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/Dependency.cs b/TodoistSync/Models/Clickup/Dependency.cs deleted file mode 100644 index 4fc11d1..0000000 --- a/TodoistSync/Models/Clickup/Dependency.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; - -namespace TodoistSync.Models.Clickup -{ - public class Dependency - { - [JsonProperty("task_id")] - public string TaskId { get; set; } - - [JsonProperty("depends_on")] - public string DependsOn { get; set; } - - [JsonProperty("type")] - public int Type { get; set; } - - [JsonProperty("date_created")] - public string DateCreated { get; set; } - - [JsonProperty("user_id")] - public string UserId { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/Folder.cs b/TodoistSync/Models/Clickup/Folder.cs deleted file mode 100644 index ec3df3d..0000000 --- a/TodoistSync/Models/Clickup/Folder.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Newtonsoft.Json; - -namespace TodoistSync.Models.Clickup -{ - public class Folder - { - [JsonProperty("id")] - public long Id { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("access")] - public bool Access { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/Project.cs b/TodoistSync/Models/Clickup/Project.cs deleted file mode 100644 index bda0527..0000000 --- a/TodoistSync/Models/Clickup/Project.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Newtonsoft.Json; - -namespace TodoistSync.Models.Clickup -{ - public class Project - { - [JsonProperty("id")] - public long Id { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("access")] - public bool Access { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/Space.cs b/TodoistSync/Models/Clickup/Space.cs deleted file mode 100644 index 7ca138c..0000000 --- a/TodoistSync/Models/Clickup/Space.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace TodoistSync.Models.Clickup -{ - public class Space - { - [JsonProperty("id")] - public long Id { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/Tag.cs b/TodoistSync/Models/Clickup/Tag.cs deleted file mode 100644 index 9ee9d1a..0000000 --- a/TodoistSync/Models/Clickup/Tag.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; - -namespace TodoistSync.Models.Clickup -{ - public class Tag - { - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("tag_fg")] - public string TagFg { get; set; } - - [JsonProperty("tag_bg")] - public string TagBg { get; set; } - - [JsonProperty("creator")] - public User Creator { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/Task.cs b/TodoistSync/Models/Clickup/Task.cs deleted file mode 100644 index fa610b9..0000000 --- a/TodoistSync/Models/Clickup/Task.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using System.Collections.Generic; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using TodoistSync.Utilities; - -namespace TodoistSync.Models.Clickup -{ - public class Task - { - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("text_content")] - public string TextContent { get; set; } - - [JsonProperty("description")] - public string Description { get; set; } - - [JsonProperty("status")] - public TaskStatus Status { get; set; } - - [JsonProperty("orderindex")] - public string Orderindex { get; set; } - - [JsonProperty("date_created")] - [JsonConverter(typeof(EpochDateTimeOffsetConverter))] - public DateTimeOffset? DateCreated { get; set; } - - [JsonProperty("date_updated")] - [JsonConverter(typeof(EpochDateTimeOffsetConverter))] - public DateTimeOffset? DateUpdated { get; set; } - - [JsonProperty("date_closed")] - [JsonConverter(typeof(EpochDateTimeOffsetConverter))] - public DateTimeOffset? DateClosed { get; set; } - - [JsonProperty("archived")] - public bool Archived { get; set; } - - [JsonProperty("creator")] - public User Creator { get; set; } - - [JsonProperty("assignees")] - public List Assignees { get; set; } - - [JsonProperty("watchers")] - public List Watchers { get; set; } - - [JsonProperty("checklists")] - public List Checklists { get; set; } - - [JsonProperty("tags")] - public List Tags { get; set; } - - [JsonProperty("parent")] - public string Parent { get; set; } - - [JsonProperty("priority")] - public TaskPriority Priority { get; set; } - - [JsonProperty("due_date")] - [JsonConverter(typeof(EpochDateTimeOffsetConverter))] - public DateTimeOffset? DueDate { get; set; } - - [JsonProperty("start_date")] - public string StartDate { get; set; } - - [JsonProperty("time_estimate")] - public string TimeEstimate { get; set; } - - [JsonProperty("time_spent")] - public long TimeSpent { get; set; } - - [JsonProperty("custom_fields")] - public List CustomFields { get; set; } - - [JsonProperty("dependencies")] - public List Dependencies { get; set; } - - [JsonProperty("linked_tasks")] - public List LinkedTasks { get; set; } - - [JsonProperty("team_id")] - public long TeamId { get; set; } - - [JsonProperty("url")] - public Uri Url { get; set; } - - [JsonProperty("permission_level")] - public string PermissionLevel { get; set; } - - [JsonProperty("list")] - public TaskList List { get; set; } - - [JsonProperty("project")] - public Project Project { get; set; } - - [JsonProperty("folder")] - public Folder Folder { get; set; } - - [JsonProperty("space")] - public Space Space { get; set; } - - [JsonProperty("attachments")] - public List Attachments { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/TaskList.cs b/TodoistSync/Models/Clickup/TaskList.cs deleted file mode 100644 index d992cfd..0000000 --- a/TodoistSync/Models/Clickup/TaskList.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Newtonsoft.Json; - -namespace TodoistSync.Models.Clickup -{ - public class TaskList - { - [JsonProperty("id")] - public long Id { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("access")] - public bool Access { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/TaskPriority.cs b/TodoistSync/Models/Clickup/TaskPriority.cs deleted file mode 100644 index 9059ff0..0000000 --- a/TodoistSync/Models/Clickup/TaskPriority.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; - -namespace TodoistSync.Models.Clickup -{ - public class TaskPriority - { - [JsonProperty("id")] - public long Id { get; set; } - - [JsonProperty("priority")] - public string Priority { get; set; } - - [JsonProperty("color")] - public string Color { get; set; } - - [JsonProperty("orderindex")] - public long Orderindex { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/TaskStatus.cs b/TodoistSync/Models/Clickup/TaskStatus.cs deleted file mode 100644 index 83502b2..0000000 --- a/TodoistSync/Models/Clickup/TaskStatus.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; - -namespace TodoistSync.Models.Clickup -{ - public class TaskStatus - { - [JsonProperty("status")] - public string Status { get; set; } - - [JsonProperty("color")] - public string Color { get; set; } - - [JsonProperty("orderindex")] - public long Orderindex { get; set; } - - [JsonProperty("type")] - public string Type { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/User.cs b/TodoistSync/Models/Clickup/User.cs deleted file mode 100644 index 5908d99..0000000 --- a/TodoistSync/Models/Clickup/User.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using Newtonsoft.Json; - -namespace TodoistSync.Models.Clickup -{ - public class User - { - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("username")] - public string Username { get; set; } - - [JsonProperty("color")] - public string Color { get; set; } - - [JsonProperty("initials")] - public string Initials { get; set; } - - [JsonProperty("email")] - public string Email { get; set; } - - [JsonProperty("profilePicture")] - public Uri ProfilePicture { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/WebhookEvent.cs b/TodoistSync/Models/Clickup/WebhookEvent.cs deleted file mode 100644 index d571856..0000000 --- a/TodoistSync/Models/Clickup/WebhookEvent.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Newtonsoft.Json; - -namespace TodoistSync.Models.Clickup -{ - public class WebhookEvent - { - [JsonProperty("event")] - public WebhookEventType Event { get; set; } - - [JsonProperty("task_id")] - public string TaskId { get; set; } - - [JsonProperty("webhook_id")] - public string WebhookId { get; set; } - } -} diff --git a/TodoistSync/Models/Clickup/WebhookEventType.cs b/TodoistSync/Models/Clickup/WebhookEventType.cs deleted file mode 100644 index 9d56892..0000000 --- a/TodoistSync/Models/Clickup/WebhookEventType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace TodoistSync.Models.Clickup -{ - public enum WebhookEventType - { - TaskUpdated, - TaskCreated, - TaskDeleted - } -} diff --git a/TodoistSync/Models/Todoist/EventData.cs b/TodoistSync/Models/Todoist/EventData.cs deleted file mode 100644 index 33924dd..0000000 --- a/TodoistSync/Models/Todoist/EventData.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace TodoistSync.Models.Todoist -{ - public class EventData - { - [JsonProperty("is_deleted")] - public long? IsDeleted { get; set; } - - [JsonProperty("assigned_by_uid")] - public string AssignedByUid { get; set; } - - [JsonProperty("labels")] - public List Labels { get; set; } - - [JsonProperty("sync_id")] - public long? SyncId { get; set; } - - [JsonProperty("section_id")] - public long? SectionId { get; set; } - - [JsonProperty("in_history")] - public long? InHistory { get; set; } - - [JsonProperty("child_order")] - public long? ChildOrder { get; set; } - - [JsonProperty("date_added")] - public DateTimeOffset? DateAdded { get; set; } - - [JsonProperty("checked")] - public long? Checked { get; set; } - - [JsonProperty("id")] - public long? Id { get; set; } - - [JsonProperty("content")] - public string Content { get; set; } - - [JsonProperty("date_completed")] - public DateTimeOffset? DateCompleted { get; set; } - - [JsonProperty("added_by_uid")] - public long? AddedByUid { get; set; } - - [JsonProperty("user_id")] - public long? UserId { get; set; } - - [JsonProperty("url")] - public Uri Url { get; set; } - - [JsonProperty("due")] - public TaskDue Due { get; set; } - - [JsonProperty("priority")] - public long? Priority { get; set; } - - [JsonProperty("parent_id")] - public string ParentId { get; set; } - - [JsonProperty("responsible_uid")] - public string ResponsibleUid { get; set; } - - [JsonProperty("project_id")] - public long? ProjectId { get; set; } - - [JsonProperty("collapsed")] - public long? Collapsed { get; set; } - - public class EventDataDue - { - [JsonProperty("date")] - public DateTimeOffset? Date { get; set; } - - [JsonProperty("timezone")] - public string Timezone { get; set; } - - [JsonProperty("is_recurring")] - public bool IsRecurring { get; set; } - - [JsonProperty("string")] - public string String { get; set; } - - [JsonProperty("lang")] - public string Lang { get; set; } - } - } -} diff --git a/TodoistSync/Models/Todoist/Task.cs b/TodoistSync/Models/Todoist/Task.cs deleted file mode 100644 index 98cdec7..0000000 --- a/TodoistSync/Models/Todoist/Task.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace TodoistSync.Models.Todoist -{ - public class Task - { - [JsonProperty("id")] - public long Id { get; set; } - - [JsonProperty("project_id")] - public long ProjectId { get; set; } - - [JsonProperty("section_id")] - public long SectionId { get; set; } - - [JsonProperty("order")] - public long Order { get; set; } - - [JsonProperty("content")] - public string Content { get; set; } - - [JsonProperty("completed")] - public bool Completed { get; set; } - - [JsonProperty("label_ids")] - public List LabelIds { get; set; } - - [JsonProperty("priority")] - public long Priority { get; set; } - - [JsonProperty("comment_count")] - public long CommentCount { get; set; } - - [JsonProperty("created")] - public DateTimeOffset Created { get; set; } - - [JsonProperty("due")] - public TaskDue Due { get; set; } - - [JsonProperty("url")] - public Uri Url { get; set; } - } -} diff --git a/TodoistSync/Models/Todoist/TaskDue.cs b/TodoistSync/Models/Todoist/TaskDue.cs deleted file mode 100644 index 793eb91..0000000 --- a/TodoistSync/Models/Todoist/TaskDue.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace TodoistSync.Models.Todoist -{ - public class TaskDue - { - public bool Recurring { get; set; } - public string String { get; set; } - public DateTimeOffset? Date { get; set; } - } -} diff --git a/TodoistSync/Models/Todoist/User.cs b/TodoistSync/Models/Todoist/User.cs deleted file mode 100644 index e8348f1..0000000 --- a/TodoistSync/Models/Todoist/User.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; - -namespace TodoistSync.Models.Todoist -{ - public class User - { - [JsonProperty("is_premium")] - public bool IsPremium { get; set; } - - [JsonProperty("image_id")] - public string ImageId { get; set; } - - [JsonProperty("id")] - public long? Id { get; set; } - - [JsonProperty("full_name")] - public string FullName { get; set; } - - [JsonProperty("email")] - public string Email { get; set; } - } -} diff --git a/TodoistSync/Models/Todoist/WebhookEvent.cs b/TodoistSync/Models/Todoist/WebhookEvent.cs deleted file mode 100644 index 7058cf0..0000000 --- a/TodoistSync/Models/Todoist/WebhookEvent.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; - -namespace TodoistSync.Models.Todoist -{ - public class WebhookEvent - { - [JsonProperty("event_name")] - public string EventName { get; set; } - - [JsonProperty("initiator")] - public User Initiator { get; set; } - - [JsonProperty("version")] - public string Version { get; set; } - - [JsonProperty("user_id")] - public long? UserId { get; set; } - - [JsonProperty("event_data")] - public EventData EventData { get; set; } - } -} diff --git a/TodoistSync/Program.cs b/TodoistSync/Program.cs new file mode 100644 index 0000000..48863a6 --- /dev/null +++ b/TodoistSync/Program.cs @@ -0,0 +1,25 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/TodoistSync/Properties/launchSettings.json b/TodoistSync/Properties/launchSettings.json new file mode 100644 index 0000000..ac9f344 --- /dev/null +++ b/TodoistSync/Properties/launchSettings.json @@ -0,0 +1,51 @@ +{ + "profiles": { + "http": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5023" + }, + "https": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7288;http://localhost:5023" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Docker": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", + "environmentVariables": { + "ASPNETCORE_URLS": "https://+:443;http://+:80" + }, + "publishAllPorts": true, + "useSSL": true + } + }, + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:62419", + "sslPort": 44311 + } + } +} \ No newline at end of file diff --git a/TodoistSync/Repositories/ClickupRepository.cs b/TodoistSync/Repositories/ClickupRepository.cs deleted file mode 100644 index 19502b5..0000000 --- a/TodoistSync/Repositories/ClickupRepository.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Extensions.Configuration; -using Newtonsoft.Json; -using TimeZoneConverter; -using TodoistSync.Utilities; -using Clickup = TodoistSync.Models.Clickup; - -namespace TodoistSync.Repositories -{ - public class ClickupRepository - { - public readonly string ClickupUserId; - private readonly HttpClient _client; - - public ClickupRepository(IConfiguration configuration) - { - _client = new HttpClient(); - ClickupUserId = configuration["CLICKUP_USER_ID"]; - _client.BaseAddress = new Uri("https://api.clickup.com/api/v2/"); - _client.DefaultRequestHeaders.Add("Accept", "application/json"); - _client.DefaultRequestHeaders.Authorization = - new AuthenticationHeaderValue(configuration["CLICKUP_API_KEY"]); - } - - public async Task GetTaskById(string taskId) - { - try - { - var content = await _client.GetStringAsync($"task/{taskId}"); - - return JsonConvert.DeserializeObject(content); - } - catch - { - return null; - } - } - - public async Task CompleteTask(string taskId) - { - var json = JsonConvert.SerializeObject(new - { - status = "closed", - }); - - var content = new StringContent(json, Encoding.UTF8, "application/json"); - - await _client.PutAsync($"task/{taskId}", content); - } - - public async Task UpdateTask(string taskId, long? dueDate) - { - var json = JsonConvert.SerializeObject(new - { - due_date = dueDate, - }); - - var content = new StringContent(json, Encoding.UTF8, "application/json"); - await _client.PutAsync($"task/{taskId}", content); - } - } -} diff --git a/TodoistSync/Repositories/TodoistRepository.cs b/TodoistSync/Repositories/TodoistRepository.cs deleted file mode 100644 index 86eca69..0000000 --- a/TodoistSync/Repositories/TodoistRepository.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Extensions.Configuration; -using Newtonsoft.Json; -using TimeZoneConverter; -using Todoist = TodoistSync.Models.Todoist; - -namespace TodoistSync.Repositories -{ - public class TodoistRepository - { - public readonly long ClickupLabelId; - public readonly TimeZoneInfo TodoistTimeZone; - private readonly HttpClient _client; - private const string TodoistBaseUrl = "https://api.todoist.com/rest/v1/"; - - public TodoistRepository(IConfiguration configuration) - { - _client = new HttpClient(); - ClickupLabelId = long.Parse(configuration["TODOIST_CLICKUP_LABEL_ID"]); - TodoistTimeZone = TZConvert.GetTimeZoneInfo("Central Standard Time"); - _client.BaseAddress = new Uri(TodoistBaseUrl); - _client.DefaultRequestHeaders.Authorization = - new AuthenticationHeaderValue("Bearer", configuration["TODOIST_API_KEY"]); - } - - public async Task> GetTasksByLabelId(long labelId) - { - var content = await _client.GetStringAsync($"tasks?label_id={labelId}"); - - return JsonConvert.DeserializeObject>(content); - } - - public async Task DeleteTask(Todoist.Task task) - { - await _client.DeleteAsync($"tasks/{task.Id}"); - } - - public async Task CreateTask( - string content, - List labelIds, - long? parent = null, - string dueDate = null, - DateTimeOffset? dueDatetime = null) - { - var json = JsonConvert.SerializeObject(new TaskPostBody - { - Content = content, - LabelIds = labelIds, - Parent = parent, - DueDate = dueDate, - DueDatetime = dueDatetime, - }); - - var postContent = new StringContent(json, Encoding.UTF8, "application/json"); - await _client.PostAsync("tasks", postContent); - } - - public async Task UpdateTask( - Todoist.Task task, - string content = null, - List labelIds = null, - string dueDate = null, - DateTimeOffset? dueDatetime = null) - { - var json = JsonConvert.SerializeObject(new TaskPostBody - { - Content = content, - LabelIds = labelIds, - DueDate = dueDate, - DueDatetime = dueDatetime, - }); - var postContent = new StringContent(json, Encoding.UTF8, "application/json"); - await _client.PostAsync($"tasks/{task.Id}", postContent); - } - - public async Task CompleteTask(Todoist.Task task) - { - await _client.PostAsync($"tasks/{task.Id}/close", null); - } - - [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] - private class TaskPostBody - { - [JsonProperty("content")] public string Content { get; set; } - - [JsonProperty("label_ids")] public List LabelIds { get; set; } - - [JsonProperty("parent")] public long? Parent { get; set; } - - [JsonProperty("due_date")] public string DueDate { get; set; } - - [JsonProperty("due_datetime")] public DateTimeOffset? DueDatetime { get; set; } - } - } -} diff --git a/TodoistSync/Services/ClickupService.cs b/TodoistSync/Services/ClickupService.cs deleted file mode 100644 index b06b51f..0000000 --- a/TodoistSync/Services/ClickupService.cs +++ /dev/null @@ -1,203 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using TimeZoneConverter; -using TodoistSync.Repositories; -using TodoistSync.Utilities; -using Clickup = TodoistSync.Models.Clickup; -using Todoist = TodoistSync.Models.Todoist; - -namespace TodoistSync.Services -{ - public class ClickupService - { - private readonly TodoistRepository _todoistRepository; - private readonly ClickupRepository _clickupRepository; - - public ClickupService(TodoistRepository todoistRepository, ClickupRepository clickupRepository) - { - _todoistRepository = todoistRepository; - _clickupRepository = clickupRepository; - } - - public async Task DeleteTodoistTaskIfExists(string clickupTaskId) - { - var todoistClickupTasks = await _todoistRepository.GetTasksByLabelId(_todoistRepository.ClickupLabelId); - - var existingTask = todoistClickupTasks - .FirstOrDefault(t => GetClickupIdFromTodoistTask(t) == clickupTaskId); - - if (existingTask == null) - { - return; - } - - await _todoistRepository.DeleteTask(existingTask); - } - - public async Task CreateOrUpdateTodoistTask(string taskId) - { - // Fire off tasks then await later so they're executed in parallel - var clickupRequestTask = _clickupRepository.GetTaskById(taskId); - var todoistRequestTask = _todoistRepository.GetTasksByLabelId(_todoistRepository.ClickupLabelId); - - var clickupTask = await clickupRequestTask; - var allTodoistClickupTasks = await todoistRequestTask; - - if (clickupTask == null) - { - return; - } - - var existingTodoistTask = allTodoistClickupTasks - .FirstOrDefault(t => GetClickupIdFromTodoistTask(t) == clickupTask.Id); - - var clickupUser = clickupTask.Assignees.FirstOrDefault(u => u.Id == _clickupRepository.ClickupUserId); - - var hasBeenAssignedToOurClickupUser = clickupUser != null; - - // If the task is not assigned to the user we're syncing for and it's not in Todoist that - // means clickup is notifying us about a task we don't care about and we don't do anything - if (!hasBeenAssignedToOurClickupUser && existingTodoistTask == null) - { - return; - } - - // If the task is not assigned but it is in Todoist then it must have been - // unassigned in Clickup and needs removed from Todoist - if (!hasBeenAssignedToOurClickupUser) - { - await _todoistRepository.DeleteTask(existingTodoistTask); - return; - } - - // If the task is assigned and in Todoist then we need to make sure all the - // to update any new details - if (existingTodoistTask != null) - { - await UpdateClickupTaskInTodoist(clickupTask, existingTodoistTask); - return; - } - - // At this point we know the task is assigned to our clickup user, but it's not in Todoist and - // it probably needs created. However, we need to make sure the task isn't marked as closed in Clickup. - // This check allows us to clear a task in Todoist and have it clear in Clickup without being recreated. - if (clickupTask.Status.Type == "closed") - { - return; - } - - // After the above checks we know we need to create the task in Todoist. - // We do that right away if the current task is not a child task - if (string.IsNullOrEmpty(clickupTask.Parent)) - { - await CreateClickupTaskInTodoist(clickupTask); - return; - } - - var parentTodoistTask = allTodoistClickupTasks - .FirstOrDefault(t => GetClickupIdFromTodoistTask(t) == clickupTask.Parent); - - // If we can't find the parent task in Todoist for some reason (e.g. the parent task - // wasn't assigned to our Clickup user) we just create it normally - if (parentTodoistTask == null) - { - await CreateClickupTaskInTodoist(clickupTask); - return; - } - - // Otherwise if we do have a parent task we create the todoist task under that task - await CreateClickupTaskInTodoist(clickupTask, parentTodoistTask.Id); - } - - private async Task CreateClickupTaskInTodoist(Clickup.Task clickupTask, long? parent) - { - var content = FormatTodoistContent(clickupTask); - - await _todoistRepository.CreateTask( - content, - new List { _todoistRepository.ClickupLabelId }, - parent, - dueDatetime: clickupTask.DueDate - ); - } - - private Task CreateClickupTaskInTodoist(Clickup.Task clickupTask) - { - return CreateClickupTaskInTodoist(clickupTask, null); - } - - private async Task UpdateClickupTaskInTodoist(Clickup.Task clickupTask, Todoist.Task todoistTask) - { - if (clickupTask.Status.Type == "closed") - { - await _todoistRepository.CompleteTask(todoistTask); - return; - } - - var updatedContent = FormatTodoistContent(clickupTask); - - if ( - updatedContent == todoistTask.Content && - clickupTask.DueDate == todoistTask.Due?.Date.UpdateTimeZone(_todoistRepository.TodoistTimeZone) - ) - { - return; - } - - await _todoistRepository.UpdateTask( - todoistTask, - updatedContent, - dueDatetime: null - ); - } - - public async Task UpdateClickupTask(string taskId, DateTimeOffset? dueDate) - { - var clickupTask = await _clickupRepository.GetTaskById(taskId); - - if (clickupTask == null) - { - return; - } - - dueDate = dueDate.UpdateTimeZone(_todoistRepository.TodoistTimeZone); - - if (clickupTask.DueDate == dueDate) - { - return; - } - - await _clickupRepository.UpdateTask(taskId, dueDate?.ToUnixTimeMilliseconds()); - } - - public async Task CompleteTask(string taskId) - { - await _clickupRepository.CompleteTask(taskId); - } - - public string GetClickupIdFromTodoistContent(string content) - { - var clickupLink = content - .Split('(', ')') - .FirstOrDefault(s => s.StartsWith("https://app.clickup.com/")); - - return clickupLink == null - ? null - : clickupLink - .Replace("https://app.clickup.com/t/", "") - .Replace("/", ""); - } - - public string GetClickupIdFromTodoistTask(Todoist.Task task) - { - return GetClickupIdFromTodoistContent(task.Content); - } - - private string FormatTodoistContent(Clickup.Task clickupTask) - { - return $"{clickupTask.Name} - [(Clickup Task)]({clickupTask.Url})"; - } - } -} diff --git a/TodoistSync/Services/TodoistService.cs b/TodoistSync/Services/TodoistService.cs deleted file mode 100644 index 516a2de..0000000 --- a/TodoistSync/Services/TodoistService.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using Microsoft.Extensions.Configuration; -using TodoistSync.Repositories; -using Clickup = TodoistSync.Models.Clickup; - -namespace TodoistSync.Services -{ - public class TodoistService - { - public long ClickupLabelId => _todoistRepository.ClickupLabelId; - - private readonly TodoistRepository _todoistRepository; - - public TodoistService(TodoistRepository todoistRepository) - { - _todoistRepository = todoistRepository; - } - } -} diff --git a/TodoistSync/Startup.cs b/TodoistSync/Startup.cs deleted file mode 100644 index 8c4e17b..0000000 --- a/TodoistSync/Startup.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using TodoistSync.Middleware; -using TodoistSync.Repositories; -using TodoistSync.Services; - -namespace TodoistSync -{ - public class Startup - { - public static IConfiguration Configuration { get; private set; } - - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - // This method gets called by the runtime. Use this method to add services to the container - public void ConfigureServices(IServiceCollection services) - { - services - .AddControllers() - .AddNewtonsoftJson(); - - services.AddTransient(); - services.AddTransient(); - services.AddHttpClient(); - services.AddHttpClient(); - } - - // 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(); - } - - if (!env.IsDevelopment()) - { - app.UseHttpsRedirection(); - // Ensures Lambda is kept alive until errors can be properly reported - app.UseMiddleware(); - } - - app.UseRouting(); - - app.UseAuthorization(); - - app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); - } - } -} diff --git a/TodoistSync/TodoistSync.csproj b/TodoistSync/TodoistSync.csproj index 7163f93..f88149e 100644 --- a/TodoistSync/TodoistSync.csproj +++ b/TodoistSync/TodoistSync.csproj @@ -1,15 +1,17 @@ - - netcoreapp3.1 - true - Lambda - - - - - - - - - - \ No newline at end of file + + + net7.0 + enable + enable + 83c69c34-ae59-4bb9-a245-13bbadf13c54 + Linux + + + + + + + + + diff --git a/TodoistSync/Utilities/EpochDateTimeOffsetConverter.cs b/TodoistSync/Utilities/EpochDateTimeOffsetConverter.cs deleted file mode 100644 index 8f92437..0000000 --- a/TodoistSync/Utilities/EpochDateTimeOffsetConverter.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using Newtonsoft.Json; - -namespace TodoistSync.Utilities -{ - public class EpochDateTimeOffsetConverter : JsonConverter - { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new NotImplementedException(); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - if (reader.Value == null) - { - return null; - } - - var epoch = long.Parse((string)reader.Value); - return DateTimeOffset.FromUnixTimeMilliseconds(epoch); - } - - public override bool CanConvert(Type objectType) - { - return objectType == typeof(DateTimeOffset?); - } - } -} diff --git a/TodoistSync/Utilities/Utils.cs b/TodoistSync/Utilities/Utils.cs deleted file mode 100644 index 71a9753..0000000 --- a/TodoistSync/Utilities/Utils.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace TodoistSync.Utilities -{ - public static class Utils - { - // Updates a time timezone on a DateTimeOffset without changing any underlying values - public static DateTimeOffset? UpdateTimeZone(this DateTimeOffset? dateTime, TimeZoneInfo timeZone) - { - if (dateTime == null) - { - return null; - } - - var modifiedDateTime = TimeZoneInfo.ConvertTime(dateTime.Value, timeZone); - - return dateTime.Value.Subtract(modifiedDateTime.Offset).ToOffset(modifiedDateTime.Offset); - } - } -} diff --git a/TodoistSync/WeatherForecast.cs b/TodoistSync/WeatherForecast.cs new file mode 100644 index 0000000..9f2cf97 --- /dev/null +++ b/TodoistSync/WeatherForecast.cs @@ -0,0 +1,13 @@ +namespace TodoistSync +{ + public class WeatherForecast + { + public DateOnly Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } + } +} \ No newline at end of file diff --git a/TodoistSync/appsettings.Development.json b/TodoistSync/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/TodoistSync/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/TodoistSync/appsettings.json b/TodoistSync/appsettings.json index 82efe81..10f68b8 100644 --- a/TodoistSync/appsettings.json +++ b/TodoistSync/appsettings.json @@ -1,7 +1,9 @@ { - "Logging": { - "LogLevel": { - "Default": "Information" - } + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" } + }, + "AllowedHosts": "*" } diff --git a/TodoistSync/aws-lambda-tools-defaults.json b/TodoistSync/aws-lambda-tools-defaults.json deleted file mode 100644 index 5f19e13..0000000 --- a/TodoistSync/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "Information": [ - "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", - "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", - "dotnet lambda help", - "All the command line options for the Lambda command can be specified in this file." - ], - "profile": "personal", - "region": "us-east-2", - "configuration": "Release", - "framework": "netcoreapp3.1", - "function-name": "TodoistSync", - "function-runtime": "dotnetcore3.1" -}