diff --git a/AzureDevopsStateTracker/AzureDevopsStateTracker.csproj b/AzureDevopsStateTracker/AzureDevopsStateTracker.csproj
deleted file mode 100644
index 647ec7b..0000000
--- a/AzureDevopsStateTracker/AzureDevopsStateTracker.csproj
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
- netcoreapp3.1
- false
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/Configurations/Configuration.cs b/AzureDevopsStateTracker/Configurations/Configuration.cs
deleted file mode 100644
index a20ca36..0000000
--- a/AzureDevopsStateTracker/Configurations/Configuration.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using AzureDevopsStateTracker.Adapters;
-using AzureDevopsStateTracker.Data;
-using AzureDevopsStateTracker.Data.Context;
-using AzureDevopsStateTracker.Interfaces;
-using AzureDevopsStateTracker.Interfaces.Internals;
-using AzureDevopsStateTracker.Services;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.DependencyInjection;
-using System;
-
-namespace AzureDevopsStateTracker.Configurations
-{
- public static class Configuration
- {
- public static IServiceCollection AddAzureDevopsStateTracker(this IServiceCollection services, DataBaseConfig configurations)
- {
- services.AddDbContext(options =>
- options.UseSqlServer(DataBaseConfig.ConnectionsString));
-
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
-
- return services;
- }
-
- public static IApplicationBuilder UseAzureDevopsStateTracker(this IApplicationBuilder app, IServiceProvider serviceProvider)
- {
- var context = serviceProvider.GetService();
- context.Database.Migrate();
-
- return app;
- }
- }
-}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/Data/DataBaseConfig.cs b/AzureDevopsStateTracker/Data/DataBaseConfig.cs
deleted file mode 100644
index fbf1079..0000000
--- a/AzureDevopsStateTracker/Data/DataBaseConfig.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using AzureDevopsStateTracker.Extensions;
-using System;
-
-namespace AzureDevopsStateTracker.Data
-{
- public class DataBaseConfig
- {
- public DataBaseConfig(string connectionsString, string schemaName = "dbo")
- {
- if (connectionsString.IsNullOrEmpty())
- throw new ArgumentException("The ConnectionsString is required");
-
- ConnectionsString = connectionsString;
- SchemaName = schemaName;
- }
-
- public static string ConnectionsString { get; private set; }
- public static string SchemaName { get; private set; }
- }
-}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/Data/Repository.cs b/AzureDevopsStateTracker/Data/Repository.cs
deleted file mode 100644
index 23d4673..0000000
--- a/AzureDevopsStateTracker/Data/Repository.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using AzureDevopsStateTracker.Data.Context;
-using AzureDevopsStateTracker.Entities;
-using AzureDevopsStateTracker.Interfaces.Internals;
-using Microsoft.EntityFrameworkCore;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace AzureDevopsStateTracker.Data
-{
- internal abstract class Repository : IRepository where TEntity : Entity
- {
- protected readonly AzureDevopsStateTrackerContext Db;
- protected readonly DbSet DbSet;
-
- public Repository(AzureDevopsStateTrackerContext db)
- {
- Db = db;
- DbSet = db.Set();
- }
-
- public virtual void Add(TEntity entity)
- {
- DbSet.Add(entity);
- }
-
- public virtual void Add(IEnumerable entities)
- {
- DbSet.AddRange(entities);
- }
-
- public virtual void Update(TEntity entity)
- {
- DbSet.Update(entity);
- }
-
- public virtual void Update(IEnumerable entities)
- {
- DbSet.UpdateRange(entities);
- }
-
- public virtual void Delete(TEntity entity)
- {
- DbSet.Remove(entity);
- }
-
- public virtual TEntity GetById(string id)
- {
- return DbSet
- .Where(x => x.Id == id)
- .FirstOrDefault();
- }
-
- public bool Exist(string id)
- {
- return DbSet
- .Any(x => x.Id == id);
- }
-
- public void SaveChanges()
- {
- Db.SaveChanges();
- }
-
- public void Dispose()
- {
- GC.SuppressFinalize(this);
- }
- }
-}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/Data/WorkItemRepository.cs b/AzureDevopsStateTracker/Data/WorkItemRepository.cs
deleted file mode 100644
index 853f884..0000000
--- a/AzureDevopsStateTracker/Data/WorkItemRepository.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using AzureDevopsStateTracker.Data.Context;
-using AzureDevopsStateTracker.Entities;
-using AzureDevopsStateTracker.Interfaces.Internals;
-using Microsoft.EntityFrameworkCore;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace AzureDevopsStateTracker.Data
-{
- internal class WorkItemRepository : Repository, IWorkItemRepository
- {
- public WorkItemRepository(AzureDevopsStateTrackerContext context) : base(context) { }
-
- public WorkItem GetByWorkItemId(string workItemId)
- {
- return DbSet
- .Include(x => x.WorkItemsChanges)
- .Include(x => x.TimeByStates)
- .FirstOrDefault(x => x.Id == workItemId);
- }
-
- public IEnumerable ListByWorkItemId(IEnumerable workItemsId)
- {
- return DbSet
- .Include(x => x.WorkItemsChanges)
- .Include(x => x.TimeByStates)
- .Where(x => workItemsId.Contains(x.Id));
- }
-
- public IEnumerable ListByIterationPath(string iterationPath)
- {
- return DbSet
- .Include(x => x.WorkItemsChanges)
- .Include(x => x.TimeByStates)
- .Where(x => x.IterationPath == iterationPath);
- }
-
- public void RemoveAllTimeByState(List timeByStates)
- {
- Db.TimeByStates.RemoveRange(timeByStates);
- }
- }
-}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/Entities/WorkItemChange.cs b/AzureDevopsStateTracker/Entities/WorkItemChange.cs
deleted file mode 100644
index b7baac5..0000000
--- a/AzureDevopsStateTracker/Entities/WorkItemChange.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using AzureDevopsStateTracker.Extensions;
-using System;
-
-namespace AzureDevopsStateTracker.Entities
-{
- public class WorkItemChange : Entity
- {
- public string WorkItemId { get; private set; }
- public DateTime NewDate { get; private set; }
- public DateTime? OldDate { get; private set; }
- public string NewState { get; private set; }
- public string OldState { get; private set; }
- public string ChangedBy { get; private set; }
- public WorkItem WorkItem { get; private set; }
-
- private WorkItemChange() { }
-
- public WorkItemChange(string workItemId, string changedBy, DateTime newDate, string newState, string oldState, DateTime? oldDate)
- {
- WorkItemId = workItemId;
- NewDate = newDate;
- OldDate = oldDate;
- NewState = newState;
- OldState = oldState;
- ChangedBy = changedBy;
-
- Validate();
- }
-
- public void Validate()
- {
- if (WorkItemId.IsNullOrEmpty() || Convert.ToInt64(WorkItemId) <= 0)
- throw new Exception("WorkItemId is required");
- }
-
- public TimeSpan CalculateTotalTime()
- {
- return OldDate == null ? TimeSpan.Zero : NewDate - OldDate.GetValueOrDefault();
- }
-
- public TimeSpan CalculateTotalWorkedTime()
- {
- if (OldDate.GetValueOrDefault() == DateTime.MinValue)
- return TimeSpan.Zero;
-
- TimeSpan hoursWorked = TimeSpan.Zero;
- for (var i = OldDate.GetValueOrDefault(); i <= NewDate; i = i.AddHours(1))
- {
- if (i.DayOfWeek != DayOfWeek.Saturday && i.DayOfWeek != DayOfWeek.Sunday)
- {
- if ((i.TimeOfDay.Hours >= 8 && i.TimeOfDay.Hours < 12) || (i.TimeOfDay.Hours >= 14 && i.TimeOfDay.Hours < 18))
- hoursWorked += (NewDate.TimeOfDay - i.TimeOfDay);
- }
- }
-
- return hoursWorked;
- }
- }
-}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/Interfaces/IAzureDevopsStateTrackerService.cs b/AzureDevopsStateTracker/Interfaces/IAzureDevopsStateTrackerService.cs
deleted file mode 100644
index a0ef0f9..0000000
--- a/AzureDevopsStateTracker/Interfaces/IAzureDevopsStateTrackerService.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using AzureDevopsStateTracker.DTOs;
-using AzureDevopsStateTracker.DTOs.Create;
-using AzureDevopsStateTracker.DTOs.Update;
-
-namespace AzureDevopsStateTracker.Interfaces
-{
- public interface IAzureDevopsStateTrackerService
- {
- void Create(CreateWorkItemDTO createDto);
- void Update(UpdatedWorkItemDTO updateDto);
- WorkItemDTO GetByWorkItemId(string workItemId);
- }
-}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/Interfaces/Internals/IRepository.cs b/AzureDevopsStateTracker/Interfaces/Internals/IRepository.cs
deleted file mode 100644
index adbfb76..0000000
--- a/AzureDevopsStateTracker/Interfaces/Internals/IRepository.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using AzureDevopsStateTracker.Entities;
-using System;
-using System.Collections.Generic;
-
-namespace AzureDevopsStateTracker.Interfaces.Internals
-{
- public interface IRepository : IDisposable where TEntity : Entity
- {
- void Add(TEntity entity);
- void Add(IEnumerable entities);
- TEntity GetById(string id);
- bool Exist(string id);
- void Update(TEntity entity);
- void Update(IEnumerable entities);
- void Delete(TEntity entity);
- void SaveChanges();
- }
-}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/Interfaces/Internals/IWorkItemRepository.cs b/AzureDevopsStateTracker/Interfaces/Internals/IWorkItemRepository.cs
deleted file mode 100644
index 82e93b9..0000000
--- a/AzureDevopsStateTracker/Interfaces/Internals/IWorkItemRepository.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using AzureDevopsStateTracker.Entities;
-using System.Collections.Generic;
-
-namespace AzureDevopsStateTracker.Interfaces.Internals
-{
- public interface IWorkItemRepository : IRepository
- {
- WorkItem GetByWorkItemId(string workItemId);
- IEnumerable ListByWorkItemId(IEnumerable workItemsId);
- IEnumerable ListByIterationPath(string iterationPath);
- void RemoveAllTimeByState(List timeByStates);
- }
-}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/Adapters/WorkItemAdapter.cs b/AzureDevopsTracker/Adapters/WorkItemAdapter.cs
similarity index 90%
rename from AzureDevopsStateTracker/Adapters/WorkItemAdapter.cs
rename to AzureDevopsTracker/Adapters/WorkItemAdapter.cs
index 904f362..6ea1a4b 100644
--- a/AzureDevopsStateTracker/Adapters/WorkItemAdapter.cs
+++ b/AzureDevopsTracker/Adapters/WorkItemAdapter.cs
@@ -1,10 +1,12 @@
-using AzureDevopsStateTracker.DTOs;
-using AzureDevopsStateTracker.Entities;
-using AzureDevopsStateTracker.Interfaces;
+using AzureDevopsTracker.DTOs;
+using AzureDevopsTracker.Entities;
+using AzureDevopsTracker.Extensions;
+using AzureDevopsTracker.Interfaces;
+using System;
using System.Collections.Generic;
using System.Linq;
-namespace AzureDevopsStateTracker.Adapters
+namespace AzureDevopsTracker.Adapters
{
internal class WorkItemAdapter : IWorkItemAdapter
{
@@ -86,8 +88,8 @@ public TimeByStateDTO ToTimeByStateDTO(TimeByState workItemStatusTime)
{
CreatedAt = workItemStatusTime.CreatedAt,
State = workItemStatusTime.State,
- //TotalTime = workItemStatusTime.TotalTimeText,
- //TotalWorkedTime = workItemStatusTime.TotalWorkedTimeText
+ TotalTime = TimeSpan.FromSeconds(workItemStatusTime.TotalTime).ToTextTime(),
+ TotalWorkedTime = TimeSpan.FromSeconds(workItemStatusTime.TotalWorkedTime).ToTextTime()
};
}
diff --git a/AzureDevopsTracker/AzureDevopsTracker.csproj b/AzureDevopsTracker/AzureDevopsTracker.csproj
new file mode 100644
index 0000000..84bf675
--- /dev/null
+++ b/AzureDevopsTracker/AzureDevopsTracker.csproj
@@ -0,0 +1,41 @@
+
+
+
+ netcoreapp3.1
+ true
+ AzureDevOpsTracker
+ Elvis Souza | Diego Galante
+ TypingHard
+ Azure DevOps Tracker
+
+ https://github.com/typinghard/azure-devops-tracker
+ https://github.com/typinghard/azure-devops-tracker
+ adst_icon.png
+
+ GitHub
+ Azure DevOps Tracker Columns State Tracking Track Board Scrum Kanbam Time Column Timing Workitem Worked Hours Team Performance
+ en
+ LICENSE.md.txt
+ A NuGet that allows you to use a Azure DevOps Service Hook to track workitems changes in a simply and detailed way.
+ 1.0.0.0
+ 1.0.0.0
+ 1.0.1
+
+
+
+
+
+
+
+
+
+ True
+
+
+
+ True
+
+
+
+
+
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/AzureDevopsStateTracker.sln b/AzureDevopsTracker/AzureDevopsTracker.sln
similarity index 69%
rename from AzureDevopsStateTracker/AzureDevopsStateTracker.sln
rename to AzureDevopsTracker/AzureDevopsTracker.sln
index 1a63535..5610a58 100644
--- a/AzureDevopsStateTracker/AzureDevopsStateTracker.sln
+++ b/AzureDevopsTracker/AzureDevopsTracker.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31402.337
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureDevopsStateTracker", "AzureDevopsStateTracker.csproj", "{E00DFF81-08B1-4A71-82C4-7CED951299BE}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureDevopsTracker", "AzureDevopsTracker.csproj", "{26FE19B9-7CD6-4418-9112-2E3C363985BF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -11,10 +11,10 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {E00DFF81-08B1-4A71-82C4-7CED951299BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {E00DFF81-08B1-4A71-82C4-7CED951299BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {E00DFF81-08B1-4A71-82C4-7CED951299BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {E00DFF81-08B1-4A71-82C4-7CED951299BE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {26FE19B9-7CD6-4418-9112-2E3C363985BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {26FE19B9-7CD6-4418-9112-2E3C363985BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {26FE19B9-7CD6-4418-9112-2E3C363985BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {26FE19B9-7CD6-4418-9112-2E3C363985BF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/AzureDevopsTracker/Configurations/Configuration.cs b/AzureDevopsTracker/Configurations/Configuration.cs
new file mode 100644
index 0000000..2fc0d46
--- /dev/null
+++ b/AzureDevopsTracker/Configurations/Configuration.cs
@@ -0,0 +1,37 @@
+using AzureDevopsTracker.Adapters;
+using AzureDevopsTracker.Data;
+using AzureDevopsTracker.Data.Context;
+using AzureDevopsTracker.Interfaces;
+using AzureDevopsTracker.Interfaces.Internals;
+using AzureDevopsTracker.Services;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+
+namespace AzureDevopsTracker.Configurations
+{
+ public static class Configuration
+ {
+ public static IServiceCollection AddAzureDevopsTracker(this IServiceCollection services, DataBaseConfig configurations)
+ {
+ services.AddDbContext(options =>
+ options.UseSqlServer(DataBaseConfig.ConnectionsString));
+
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+
+ return services;
+ }
+
+ public static IApplicationBuilder UseAzureDevopsTracker(this IApplicationBuilder app, IServiceProvider serviceProvider)
+ {
+ var context = serviceProvider.GetService();
+ context.Database.Migrate();
+
+ return app;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/DTOs/Create/CreateWorkItemDTO.cs b/AzureDevopsTracker/DTOs/Create/CreateWorkItemDTO.cs
similarity index 64%
rename from AzureDevopsStateTracker/DTOs/Create/CreateWorkItemDTO.cs
rename to AzureDevopsTracker/DTOs/Create/CreateWorkItemDTO.cs
index e6282cd..bcaa31e 100644
--- a/AzureDevopsStateTracker/DTOs/Create/CreateWorkItemDTO.cs
+++ b/AzureDevopsTracker/DTOs/Create/CreateWorkItemDTO.cs
@@ -1,18 +1,22 @@
using Newtonsoft.Json;
+using System.Text.Json.Serialization;
-namespace AzureDevopsStateTracker.DTOs.Create
+namespace AzureDevopsTracker.DTOs.Create
{
public class CreateWorkItemDTO
{
+ [JsonPropertyName("resource")]
[JsonProperty("resource")]
public Resource Resource { get; set; }
}
public class Resource
{
+ [JsonPropertyName("id")]
[JsonProperty("id")]
public string Id { get; set; }
+ [JsonPropertyName("fields")]
[JsonProperty("fields")]
public Fields Fields { get; set; }
}
diff --git a/AzureDevopsStateTracker/DTOs/Fields.cs b/AzureDevopsTracker/DTOs/Fields.cs
similarity index 59%
rename from AzureDevopsStateTracker/DTOs/Fields.cs
rename to AzureDevopsTracker/DTOs/Fields.cs
index 1351315..4086f45 100644
--- a/AzureDevopsStateTracker/DTOs/Fields.cs
+++ b/AzureDevopsTracker/DTOs/Fields.cs
@@ -1,59 +1,80 @@
using Newtonsoft.Json;
using System;
+using System.Text.Json.Serialization;
-namespace AzureDevopsStateTracker.DTOs
+namespace AzureDevopsTracker.DTOs
{
public class Fields
{
+ [JsonPropertyName("System.AreaPath")]
[JsonProperty("System.AreaPath")]
public string AreaPath { get; set; }
+ [JsonPropertyName("System.TeamProject")]
[JsonProperty("System.TeamProject")]
public string TeamProject { get; set; }
+ [JsonPropertyName("System.IterationPath")]
[JsonProperty("System.IterationPath")]
public string IterationPath { get; set; }
+ [JsonPropertyName("System.AssignedTo")]
[JsonProperty("System.AssignedTo")]
public string AssignedTo { get; set; }
+ [JsonPropertyName("System.WorkItemType")]
[JsonProperty("System.WorkItemType")]
public string Type { get; set; }
+ [JsonPropertyName("System.CreatedDate")]
[JsonProperty("System.CreatedDate")]
public DateTime CreatedDate { get; set; }
+ [JsonPropertyName("System.CreatedBy")]
[JsonProperty("System.CreatedBy")]
public string CreatedBy { get; set; }
+ [JsonPropertyName("System.ChangedBy")]
[JsonProperty("System.ChangedBy")]
public string ChangedBy { get; set; }
+ [JsonPropertyName("System.State")]
[JsonProperty("System.State")]
public string State { get; set; }
+ [JsonPropertyName("System.Title")]
[JsonProperty("System.Title")]
public string Title { get; set; }
+ [JsonPropertyName("System.Tags")]
[JsonProperty("System.Tags")]
public string Tags { get; set; }
+ [JsonPropertyName("System.Parent")]
[JsonProperty("System.Parent")]
- public string Parent { get; set; }
+ public string Parent { get; set; }
+ [JsonPropertyName("Microsoft.VSTS.Scheduling.StoryPoints")]
[JsonProperty("Microsoft.VSTS.Scheduling.StoryPoints")]
public string StoryPoints { get; set; }
+ [JsonPropertyName("Microsoft.VSTS.Scheduling.OriginalEstimate")]
[JsonProperty("Microsoft.VSTS.Scheduling.OriginalEstimate")]
public string OriginalEstimate { get; set; }
+ [JsonPropertyName("Microsoft.VSTS.Scheduling.RemainingWork")]
[JsonProperty("Microsoft.VSTS.Scheduling.RemainingWork")]
public string RemainingWork { get; set; }
+ [JsonPropertyName("Microsoft.VSTS.Scheduling.Effort")]
[JsonProperty("Microsoft.VSTS.Scheduling.Effort")]
public string Effort { get; set; }
+ [JsonPropertyName("Microsoft.VSTS.Common.Activity")]
[JsonProperty("Microsoft.VSTS.Common.Activity")]
public string Activity { get; set; }
+
+ [JsonProperty("Custom.01f51eeb-416d-49b1-b7f9-b92f3a675de1")]
+ public string Lancado { get; set; }
}
}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/DTOs/Update/UpdateWorkItemDTO.cs b/AzureDevopsTracker/DTOs/Update/UpdateWorkItemDTO.cs
similarity index 67%
rename from AzureDevopsStateTracker/DTOs/Update/UpdateWorkItemDTO.cs
rename to AzureDevopsTracker/DTOs/Update/UpdateWorkItemDTO.cs
index d0ba441..8907979 100644
--- a/AzureDevopsStateTracker/DTOs/Update/UpdateWorkItemDTO.cs
+++ b/AzureDevopsTracker/DTOs/Update/UpdateWorkItemDTO.cs
@@ -1,68 +1,73 @@
using Newtonsoft.Json;
using System;
+using System.Text.Json.Serialization;
-namespace AzureDevopsStateTracker.DTOs.Update
+namespace AzureDevopsTracker.DTOs.Update
{
public class UpdatedWorkItemDTO
{
+ [JsonPropertyName("resource")]
[JsonProperty("resource")]
public Resource Resource { get; set; }
}
public class Resource
{
+ [JsonPropertyName("workItemId")]
[JsonProperty("workItemId")]
public string WorkItemId { get; set; }
+ [JsonPropertyName("fields")]
[JsonProperty("fields")]
public ResourceFields Fields { get; set; }
+ [JsonPropertyName("revision")]
[JsonProperty("revision")]
public Revision Revision { get; set; }
}
public class Revision
{
+ [JsonPropertyName("fields")]
[JsonProperty("fields")]
public Fields Fields { get; set; }
}
public class ResourceFields
{
+ [JsonPropertyName("System.State")]
[JsonProperty("System.State")]
public OldNewValues State { get; set; }
+ [JsonPropertyName("Microsoft.VSTS.Common.StateChangeDate")]
[JsonProperty("Microsoft.VSTS.Common.StateChangeDate")]
public DateTimeOldNewValues StateChangeDate { get; set; }
+ [JsonPropertyName("System.ChangedBy")]
[JsonProperty("System.ChangedBy")]
- public ChangedByOldNewValues ChangedBy { get; set; }
+ public OldNewValues ChangedBy { get; set; }
}
public class OldNewValues
{
+ [JsonPropertyName("oldValue")]
[JsonProperty("oldValue")]
public string OldValue { get; set; }
+ [JsonPropertyName("newValue")]
[JsonProperty("newValue")]
public string NewValue { get; set; }
}
public class DateTimeOldNewValues
{
+ [JsonPropertyName("oldValue")]
[JsonProperty("oldValue")]
public DateTime OldValue { get; set; }
+ [JsonPropertyName("newValue")]
[JsonProperty("newValue")]
public DateTime NewValue { get; set; }
}
- public class ChangedByOldNewValues
- {
- [JsonProperty("oldValue")]
- public string OldValue { get; set; }
-
- [JsonProperty("newValue")]
- public string NewValue { get; set; }
- }
}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/DTOs/WorkItemDTO.cs b/AzureDevopsTracker/DTOs/WorkItemDTO.cs
similarity index 98%
rename from AzureDevopsStateTracker/DTOs/WorkItemDTO.cs
rename to AzureDevopsTracker/DTOs/WorkItemDTO.cs
index d9990a4..e79e1fd 100644
--- a/AzureDevopsStateTracker/DTOs/WorkItemDTO.cs
+++ b/AzureDevopsTracker/DTOs/WorkItemDTO.cs
@@ -2,7 +2,7 @@
using System;
using System.Collections.Generic;
-namespace AzureDevopsStateTracker.DTOs
+namespace AzureDevopsTracker.DTOs
{
public class WorkItemDTO
{
diff --git a/AzureDevopsStateTracker/Data/Context/AzureDevopsStateTrackerContext.cs b/AzureDevopsTracker/Data/Context/AzureDevopsTrackerContext.cs
similarity index 78%
rename from AzureDevopsStateTracker/Data/Context/AzureDevopsStateTrackerContext.cs
rename to AzureDevopsTracker/Data/Context/AzureDevopsTrackerContext.cs
index 18113a6..e6f534d 100644
--- a/AzureDevopsStateTracker/Data/Context/AzureDevopsStateTrackerContext.cs
+++ b/AzureDevopsTracker/Data/Context/AzureDevopsTrackerContext.cs
@@ -1,13 +1,13 @@
-using AzureDevopsStateTracker.Entities;
+using AzureDevopsTracker.Entities;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
-namespace AzureDevopsStateTracker.Data.Context
+namespace AzureDevopsTracker.Data.Context
{
- public class AzureDevopsStateTrackerContext : DbContext, IDisposable
+ public class AzureDevopsTrackerContext : DbContext, IDisposable
{
- public AzureDevopsStateTrackerContext(DbContextOptions options) : base(options)
+ public AzureDevopsTrackerContext(DbContextOptions options) : base(options)
{ }
public DbSet WorkItems { get; set; }
diff --git a/AzureDevopsTracker/Data/DataBaseConfig.cs b/AzureDevopsTracker/Data/DataBaseConfig.cs
new file mode 100644
index 0000000..47bd959
--- /dev/null
+++ b/AzureDevopsTracker/Data/DataBaseConfig.cs
@@ -0,0 +1,29 @@
+using AzureDevopsTracker.Extensions;
+using System;
+using System.Runtime.InteropServices;
+
+namespace AzureDevopsTracker.Data
+{
+ public class DataBaseConfig
+ {
+ public DataBaseConfig(string connectionsString, string schemaName = "dbo", TimeZoneInfo timeZoneInfo = null)
+ {
+ if (connectionsString.IsNullOrEmpty())
+ throw new ArgumentException("The ConnectionsString is required");
+
+ if (timeZoneInfo == null)
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("E. South America Standard Time");
+ else
+ timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Brazil/East");
+
+ ConnectionsString = connectionsString;
+ SchemaName = schemaName;
+ TimeZoneInfo = timeZoneInfo;
+ }
+
+ public static string ConnectionsString { get; private set; }
+ public static string SchemaName { get; private set; }
+ public static TimeZoneInfo TimeZoneInfo { get; private set; }
+ }
+}
\ No newline at end of file
diff --git a/AzureDevopsTracker/Data/Repository.cs b/AzureDevopsTracker/Data/Repository.cs
new file mode 100644
index 0000000..3bf46b4
--- /dev/null
+++ b/AzureDevopsTracker/Data/Repository.cs
@@ -0,0 +1,69 @@
+using AzureDevopsTracker.Data.Context;
+using AzureDevopsTracker.Entities;
+using AzureDevopsTracker.Interfaces.Internals;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace AzureDevopsTracker.Data
+{
+ internal abstract class Repository : IRepository where TEntity : Entity
+ {
+ protected readonly AzureDevopsTrackerContext Db;
+ protected readonly DbSet DbSet;
+
+ public Repository(AzureDevopsTrackerContext db)
+ {
+ Db = db;
+ DbSet = db.Set();
+ }
+
+ public virtual async Task Add(TEntity entity)
+ {
+ await DbSet.AddAsync(entity);
+ }
+
+ public virtual async Task Add(IEnumerable entities)
+ {
+ await DbSet.AddRangeAsync(entities);
+ }
+
+ public virtual void Update(TEntity entity)
+ {
+ DbSet.Update(entity);
+ }
+
+ public virtual void Update(IEnumerable entities)
+ {
+ DbSet.UpdateRange(entities);
+ }
+
+ public virtual void Delete(TEntity entity)
+ {
+ DbSet.Remove(entity);
+ }
+
+ public virtual async Task GetById(string id)
+ {
+ return await DbSet
+ .FirstOrDefaultAsync(x => x.Id == id);
+ }
+
+ public async Task Exist(string id)
+ {
+ return await DbSet
+ .AnyAsync(x => x.Id == id);
+ }
+
+ public async Task SaveChangesAsync()
+ {
+ await Db.SaveChangesAsync();
+ }
+
+ public void Dispose()
+ {
+ GC.SuppressFinalize(this);
+ }
+ }
+}
\ No newline at end of file
diff --git a/AzureDevopsTracker/Data/WorkItemRepository.cs b/AzureDevopsTracker/Data/WorkItemRepository.cs
new file mode 100644
index 0000000..864f5b7
--- /dev/null
+++ b/AzureDevopsTracker/Data/WorkItemRepository.cs
@@ -0,0 +1,49 @@
+using AzureDevopsTracker.Data.Context;
+using AzureDevopsTracker.Entities;
+using AzureDevopsTracker.Interfaces.Internals;
+using Microsoft.EntityFrameworkCore;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace AzureDevopsTracker.Data
+{
+ internal class WorkItemRepository : Repository, IWorkItemRepository
+ {
+ public WorkItemRepository(AzureDevopsTrackerContext context) : base(context) { }
+
+ public async Task GetByWorkItemId(string workItemId)
+ {
+ return await DbSet
+ .Include(x => x.WorkItemsChanges)
+ .Include(x => x.TimeByStates)
+ .FirstOrDefaultAsync(x => x.Id == workItemId);
+ }
+
+ public async Task> ListByWorkItemId(IEnumerable workItemsId)
+ {
+ return await DbSet
+ .Include(x => x.WorkItemsChanges)
+ .Include(x => x.TimeByStates)
+ .Where(x => workItemsId.Contains(x.Id))
+ .ToListAsync();
+ }
+
+ public async Task> ListByIterationPath(string iterationPath)
+ {
+ return await DbSet
+ .Include(x => x.WorkItemsChanges)
+ .Include(x => x.TimeByStates)
+ .Where(x => x.IterationPath == iterationPath)
+ .ToListAsync();
+ }
+
+ public void RemoveAllTimeByState(List timeByStates)
+ {
+ if (!timeByStates.Any())
+ return;
+
+ Db.TimeByStates.RemoveRange(timeByStates);
+ }
+ }
+}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/Entities/Entity.cs b/AzureDevopsTracker/Entities/Entity.cs
similarity index 90%
rename from AzureDevopsStateTracker/Entities/Entity.cs
rename to AzureDevopsTracker/Entities/Entity.cs
index a685622..21e5f98 100644
--- a/AzureDevopsStateTracker/Entities/Entity.cs
+++ b/AzureDevopsTracker/Entities/Entity.cs
@@ -1,12 +1,11 @@
using System;
-namespace AzureDevopsStateTracker.Entities
+namespace AzureDevopsTracker.Entities
{
public abstract class Entity
{
public string Id { get; protected set; }
public DateTime CreatedAt { get; private set; }
-
public Entity(string id)
{
Id = id;
diff --git a/AzureDevopsStateTracker/Entities/TimeByState.cs b/AzureDevopsTracker/Entities/TimeByState.cs
similarity index 91%
rename from AzureDevopsStateTracker/Entities/TimeByState.cs
rename to AzureDevopsTracker/Entities/TimeByState.cs
index 4145ebb..febfbe5 100644
--- a/AzureDevopsStateTracker/Entities/TimeByState.cs
+++ b/AzureDevopsTracker/Entities/TimeByState.cs
@@ -1,7 +1,7 @@
-using AzureDevopsStateTracker.Extensions;
+using AzureDevopsTracker.Extensions;
using System;
-namespace AzureDevopsStateTracker.Entities
+namespace AzureDevopsTracker.Entities
{
public class TimeByState : Entity
{
diff --git a/AzureDevopsStateTracker/Entities/WorkItem.cs b/AzureDevopsTracker/Entities/WorkItem.cs
similarity index 92%
rename from AzureDevopsStateTracker/Entities/WorkItem.cs
rename to AzureDevopsTracker/Entities/WorkItem.cs
index 64aa79c..513d51a 100644
--- a/AzureDevopsStateTracker/Entities/WorkItem.cs
+++ b/AzureDevopsTracker/Entities/WorkItem.cs
@@ -1,9 +1,9 @@
-using AzureDevopsStateTracker.Extensions;
+using AzureDevopsTracker.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
-namespace AzureDevopsStateTracker.Entities
+namespace AzureDevopsTracker.Entities
{
public class WorkItem : Entity
{
@@ -20,6 +20,7 @@ public class WorkItem : Entity
public string StoryPoints { get; private set; }
public string WorkItemParentId { get; private set; }
public string Activity { get; private set; }
+ public string Lancado { get; private set; }
private readonly List _workItemsChanges;
public IReadOnlyCollection WorkItemsChanges => _workItemsChanges;
@@ -50,7 +51,8 @@ public void Update(string title,
string effort,
string storyPoint,
string originalEstimate,
- string activity)
+ string activity,
+ string lancado)
{
TeamProject = teamProject;
AreaPath = areaPath;
@@ -65,6 +67,7 @@ public void Update(string title,
StoryPoints = storyPoint;
OriginalEstimate = originalEstimate;
Activity = activity;
+ Lancado = lancado;
}
public void Validate()
@@ -116,7 +119,7 @@ public IEnumerable CalculateTotalTimeByState()
foreach (var data in workItemChange)
{
totalTime += data.CalculateTotalTime();
- totalWorkedTime += data.CalculateTotalWorkedTime();
+ totalWorkedTime += TimeSpan.FromSeconds(data.CalculateTotalWorkedTime());
}
timesByStateList.Add(new TimeByState(Id, workItemChange.Key, totalTime, totalWorkedTime));
diff --git a/AzureDevopsTracker/Entities/WorkItemChange.cs b/AzureDevopsTracker/Entities/WorkItemChange.cs
new file mode 100644
index 0000000..f00a73d
--- /dev/null
+++ b/AzureDevopsTracker/Entities/WorkItemChange.cs
@@ -0,0 +1,167 @@
+using AzureDevopsTracker.Extensions;
+using System;
+
+namespace AzureDevopsTracker.Entities
+{
+ public class WorkItemChange : Entity
+ {
+ public string WorkItemId { get; private set; }
+ public DateTime NewDate { get; private set; }
+ public DateTime? OldDate { get; private set; }
+ public string NewState { get; private set; }
+ public string OldState { get; private set; }
+ public string ChangedBy { get; private set; }
+ public string IterationPath { get; private set; }
+ public double TotalWorkedTime { get; private set; }
+
+ public WorkItem WorkItem { get; private set; }
+
+ private WorkItemChange() { }
+
+ public WorkItemChange(string workItemId, string changedBy, string iterationPath, DateTime newDate, string newState, string oldState, DateTime? oldDate)
+ {
+ WorkItemId = workItemId;
+ NewDate = newDate;
+ OldDate = oldDate;
+ NewState = newState;
+ OldState = oldState;
+ ChangedBy = changedBy;
+ IterationPath = iterationPath;
+ TotalWorkedTime = CalculateTotalWorkedTime();
+
+ Validate();
+ }
+
+ public void Validate()
+ {
+ if (WorkItemId.IsNullOrEmpty() || Convert.ToInt64(WorkItemId) <= 0)
+ throw new Exception("WorkItemId is required");
+ }
+
+ public TimeSpan CalculateTotalTime()
+ {
+ return OldDate == null ? TimeSpan.Zero : NewDate.ToDateTimeFromTimeZoneInfo() - OldDate.Value.ToDateTimeFromTimeZoneInfo();
+ }
+
+ public double CalculateTotalWorkedTime()
+ {
+ if (OldDate.GetValueOrDefault() == DateTime.MinValue)
+ return 0;
+
+ var oldDate = OldDate.Value.ToDateTimeFromTimeZoneInfo();
+ var newDate = NewDate.ToDateTimeFromTimeZoneInfo();
+
+ var secondsWorked = 0D;
+ var majorDateBeforeLunch = DateTime.MinValue;
+ var minorDateBeforeLunch = DateTime.MinValue;
+ var majorDateAfterLunch = DateTime.MinValue;
+ var minorDateAfterLunch = DateTime.MinValue;
+
+ DateTime dataAux = DateTime.MinValue;
+ int diasCompletos = 0;
+
+ TimeSpan afterLunch;
+ TimeSpan beforeLunch;
+
+ for (var dateAux = oldDate; dateAux <= newDate; dateAux = dateAux.AddSeconds(1))
+ {
+ if (dateAux.DayOfWeek == DayOfWeek.Saturday || dateAux.DayOfWeek == DayOfWeek.Sunday)
+ continue;
+
+ if (dateAux.TimeOfDay.Hours >= 12 && dateAux.TimeOfDay.Hours < 14)
+ continue;
+
+ if (dateAux.TimeOfDay.Hours > 18 && dateAux.TimeOfDay.Hours < 23 ||
+ dateAux.TimeOfDay.Hours >= 0 && dateAux.TimeOfDay.Hours < 8)
+ continue;
+
+ if (dataAux == DateTime.MinValue)
+ dataAux = dateAux;
+
+ if (dataAux != DateTime.MinValue && dataAux.Date != dateAux.Date)
+ {
+ beforeLunch = SubtractDates(majorDateBeforeLunch, minorDateBeforeLunch);
+ afterLunch = SubtractDates(majorDateAfterLunch, minorDateAfterLunch);
+
+ if ((beforeLunch + afterLunch).Hours == 8)
+ diasCompletos++;
+ else
+ secondsWorked += (beforeLunch + afterLunch).TotalSeconds;
+
+ majorDateBeforeLunch = DateTime.MinValue;
+ minorDateBeforeLunch = DateTime.MinValue;
+
+ majorDateAfterLunch = DateTime.MinValue;
+ minorDateAfterLunch = DateTime.MinValue;
+ dataAux = dateAux;
+ }
+
+ if (dateAux.TimeOfDay.Hours >= 8 && dateAux.TimeOfDay.Hours < 12)
+ {
+ if (minorDateBeforeLunch == DateTime.MinValue || dateAux < minorDateBeforeLunch)
+ minorDateBeforeLunch = dateAux;
+
+ if (majorDateBeforeLunch == DateTime.MinValue || dateAux > majorDateBeforeLunch)
+ majorDateBeforeLunch = dateAux;
+
+ continue;
+ }
+
+ if (dateAux.TimeOfDay.Hours >= 14 && dateAux.TimeOfDay.Hours < 18)
+ {
+ if (minorDateAfterLunch == DateTime.MinValue || dateAux < minorDateAfterLunch)
+ minorDateAfterLunch = dateAux;
+
+ if (majorDateAfterLunch == DateTime.MinValue || dateAux > majorDateAfterLunch)
+ majorDateAfterLunch = dateAux;
+
+ continue;
+ }
+
+ }
+
+ if (dataAux != DateTime.MinValue &&
+ oldDate.Date == newDate.Date ||
+ (majorDateBeforeLunch != DateTime.MinValue || minorDateBeforeLunch != DateTime.MinValue) ||
+ (majorDateAfterLunch != DateTime.MinValue || minorDateAfterLunch != DateTime.MinValue))
+ {
+ beforeLunch = SubtractDates(majorDateBeforeLunch, minorDateBeforeLunch);
+ afterLunch = SubtractDates(majorDateAfterLunch, minorDateAfterLunch);
+
+ secondsWorked += (beforeLunch + afterLunch).TotalSeconds;
+ }
+
+ if (diasCompletos > 0)
+ secondsWorked += diasCompletos * 28800;
+
+ return secondsWorked;
+ }
+
+ private TimeSpan SubtractDates(DateTime biger, DateTime minor)
+ {
+ if (biger.Hour == minor.Hour)
+ {
+ return biger.Subtract(minor);
+ }
+ else if (biger.Hour > 8 && biger.Hour == 11 && biger.Minute == 59)
+ {
+ var newMajorDate = new DateTime(biger.Year, biger.Month, biger.Day, 12, 0, 0);
+ return newMajorDate.Subtract(minor);
+ }
+ else if (biger.Hour > 14 && biger.Hour < minor.Hour)
+ {
+ var newMinorDate = new DateTime(minor.Year, minor.Month, minor.Day, 14, 0, 0);
+ return biger.Subtract(newMinorDate);
+ }
+ else if (biger.Hour > 14 && biger.Hour == 17 && biger.Minute == 59)
+ {
+ var newMajorDate = new DateTime(biger.Year, biger.Month, biger.Day, 18, 0, 0);
+ return newMajorDate.Subtract(minor);
+ }
+ else
+ {
+ return biger.Subtract(minor);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/Extensions/HelperExtenions.cs b/AzureDevopsTracker/Extensions/HelperExtenions.cs
similarity index 75%
rename from AzureDevopsStateTracker/Extensions/HelperExtenions.cs
rename to AzureDevopsTracker/Extensions/HelperExtenions.cs
index 286b592..372e2dd 100644
--- a/AzureDevopsStateTracker/Extensions/HelperExtenions.cs
+++ b/AzureDevopsTracker/Extensions/HelperExtenions.cs
@@ -1,7 +1,8 @@
-using System;
+using AzureDevopsTracker.Data;
+using System;
using System.Linq;
-namespace AzureDevopsStateTracker.Extensions
+namespace AzureDevopsTracker.Extensions
{
public static class HelperExtenions
{
@@ -24,7 +25,7 @@ public static string ExtractEmail(this string user)
public static string ToTextTime(this TimeSpan timeSpan)
{
if (timeSpan.Days > 0)
- return $@"{timeSpan:%d} Dia(s) {timeSpan:%h} h e {timeSpan:%m} min e {timeSpan:%s} s";
+ return $@"{timeSpan:%d} Day(s) {timeSpan:%h} h e {timeSpan:%m} min e {timeSpan:%s} s";
if (timeSpan.Hours > 0)
return $@"{timeSpan:%h} h e {timeSpan:%m} min e {timeSpan:%s} s";
@@ -37,5 +38,10 @@ public static string ToTextTime(this TimeSpan timeSpan)
return "-";
}
+
+ public static DateTime ToDateTimeFromTimeZoneInfo(this DateTime date)
+ {
+ return TimeZoneInfo.ConvertTimeFromUtc(date, DataBaseConfig.TimeZoneInfo);
+ }
}
}
\ No newline at end of file
diff --git a/AzureDevopsTracker/Interfaces/IAzureDevopsTrackerService.cs b/AzureDevopsTracker/Interfaces/IAzureDevopsTrackerService.cs
new file mode 100644
index 0000000..0d2e1fa
--- /dev/null
+++ b/AzureDevopsTracker/Interfaces/IAzureDevopsTrackerService.cs
@@ -0,0 +1,14 @@
+using AzureDevopsTracker.DTOs;
+using AzureDevopsTracker.DTOs.Create;
+using AzureDevopsTracker.DTOs.Update;
+using System.Threading.Tasks;
+
+namespace AzureDevopsTracker.Interfaces
+{
+ public interface IAzureDevopsTrackerService
+ {
+ Task Create(CreateWorkItemDTO createDto, bool addWorkItemChange = true);
+ Task Update(UpdatedWorkItemDTO updateDto);
+ Task GetByWorkItemId(string workItemId);
+ }
+}
\ No newline at end of file
diff --git a/AzureDevopsStateTracker/Interfaces/IWorkItemAdapter.cs b/AzureDevopsTracker/Interfaces/IWorkItemAdapter.cs
similarity index 62%
rename from AzureDevopsStateTracker/Interfaces/IWorkItemAdapter.cs
rename to AzureDevopsTracker/Interfaces/IWorkItemAdapter.cs
index 5fb5db8..79f33b6 100644
--- a/AzureDevopsStateTracker/Interfaces/IWorkItemAdapter.cs
+++ b/AzureDevopsTracker/Interfaces/IWorkItemAdapter.cs
@@ -1,8 +1,8 @@
-using AzureDevopsStateTracker.DTOs;
-using AzureDevopsStateTracker.Entities;
+using AzureDevopsTracker.DTOs;
+using AzureDevopsTracker.Entities;
using System.Collections.Generic;
-namespace AzureDevopsStateTracker.Interfaces
+namespace AzureDevopsTracker.Interfaces
{
public interface IWorkItemAdapter
{
diff --git a/AzureDevopsTracker/Interfaces/Internals/IRepository.cs b/AzureDevopsTracker/Interfaces/Internals/IRepository.cs
new file mode 100644
index 0000000..a7d1db3
--- /dev/null
+++ b/AzureDevopsTracker/Interfaces/Internals/IRepository.cs
@@ -0,0 +1,19 @@
+using AzureDevopsTracker.Entities;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace AzureDevopsTracker.Interfaces.Internals
+{
+ public interface IRepository : IDisposable where TEntity : Entity
+ {
+ Task Add(TEntity entity);
+ Task Add(IEnumerable entities);
+ Task GetById(string id);
+ Task Exist(string id);
+ void Update(TEntity entity);
+ void Update(IEnumerable entities);
+ void Delete(TEntity entity);
+ Task SaveChangesAsync();
+ }
+}
\ No newline at end of file
diff --git a/AzureDevopsTracker/Interfaces/Internals/IWorkItemRepository.cs b/AzureDevopsTracker/Interfaces/Internals/IWorkItemRepository.cs
new file mode 100644
index 0000000..c7c56d6
--- /dev/null
+++ b/AzureDevopsTracker/Interfaces/Internals/IWorkItemRepository.cs
@@ -0,0 +1,14 @@
+using AzureDevopsTracker.Entities;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace AzureDevopsTracker.Interfaces.Internals
+{
+ public interface IWorkItemRepository : IRepository
+ {
+ Task GetByWorkItemId(string workItemId);
+ Task> ListByWorkItemId(IEnumerable workItemsId);
+ Task> ListByIterationPath(string iterationPath);
+ void RemoveAllTimeByState(List timeByStates);
+ }
+}
\ No newline at end of file
diff --git a/AzureDevopsTracker/LICENSE.md.txt b/AzureDevopsTracker/LICENSE.md.txt
new file mode 100644
index 0000000..1d938e9
--- /dev/null
+++ b/AzureDevopsTracker/LICENSE.md.txt
@@ -0,0 +1,11 @@
+# Released under MIT License
+
+Copyright (c) 2013 Mark Otto.
+
+Copyright (c) 2017 Andrew Fong.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs b/AzureDevopsTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs
similarity index 96%
rename from AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs
rename to AzureDevopsTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs
index b7fa1cf..859edc1 100644
--- a/AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs
+++ b/AzureDevopsTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs
@@ -1,16 +1,16 @@
//
using System;
-using AzureDevopsStateTracker.Data;
-using AzureDevopsStateTracker.Data.Context;
+using AzureDevopsTracker.Data;
+using AzureDevopsTracker.Data.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-namespace AzureDevopsStateTracker.Migrations
+namespace AzureDevopsTracker.Migrations
{
- [DbContext(typeof(AzureDevopsStateTrackerContext))]
+ [DbContext(typeof(AzureDevopsTrackerContext))]
[Migration("20210719163846_AzureDevopsStateTrackerInitial")]
partial class AzureDevopsStateTrackerInitial
{
diff --git a/AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs b/AzureDevopsTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs
similarity index 98%
rename from AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs
rename to AzureDevopsTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs
index de24b1a..60017e3 100644
--- a/AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs
+++ b/AzureDevopsTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs
@@ -1,8 +1,8 @@
using System;
-using AzureDevopsStateTracker.Data;
+using AzureDevopsTracker.Data;
using Microsoft.EntityFrameworkCore.Migrations;
-namespace AzureDevopsStateTracker.Migrations
+namespace AzureDevopsTracker.Migrations
{
public partial class AzureDevopsStateTrackerInitial : Migration
{
diff --git a/AzureDevopsTracker/Migrations/20210720105645_FunctionToTimeInitial.Designer.cs b/AzureDevopsTracker/Migrations/20210720105645_FunctionToTimeInitial.Designer.cs
new file mode 100644
index 0000000..7e06153
--- /dev/null
+++ b/AzureDevopsTracker/Migrations/20210720105645_FunctionToTimeInitial.Designer.cs
@@ -0,0 +1,154 @@
+//
+using System;
+using AzureDevopsTracker.Data;
+using AzureDevopsTracker.Data.Context;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace AzureDevopsTracker.Migrations
+{
+ [DbContext(typeof(AzureDevopsTrackerContext))]
+ [Migration("20210720105645_FunctionToTimeInitial")]
+ partial class FunctionToTimeInitial
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema(DataBaseConfig.SchemaName)
+ .HasAnnotation("ProductVersion", "3.1.16")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.TimeByState", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("varchar(200)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("State")
+ .HasColumnType("varchar(200)");
+
+ b.Property("TotalTime")
+ .HasColumnType("float");
+
+ b.Property("TotalWorkedTime")
+ .HasColumnType("float");
+
+ b.Property("WorkItemId")
+ .HasColumnType("varchar(200)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("WorkItemId");
+
+ b.ToTable("TimeByStates");
+ });
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItem", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Activity")
+ .HasColumnType("varchar(200)");
+
+ b.Property("AreaPath")
+ .HasColumnType("varchar(200)");
+
+ b.Property("AssignedTo")
+ .HasColumnType("varchar(200)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("CreatedBy")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Effort")
+ .HasColumnType("varchar(200)");
+
+ b.Property("IterationPath")
+ .HasColumnType("varchar(200)");
+
+ b.Property("OriginalEstimate")
+ .HasColumnType("varchar(200)");
+
+ b.Property("StoryPoints")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Tags")
+ .HasColumnType("varchar(200)");
+
+ b.Property("TeamProject")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Title")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Type")
+ .HasColumnType("varchar(200)");
+
+ b.Property("WorkItemParentId")
+ .HasColumnType("varchar(200)");
+
+ b.HasKey("Id");
+
+ b.ToTable("WorkItems");
+ });
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItemChange", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("varchar(200)");
+
+ b.Property("ChangedBy")
+ .HasColumnType("varchar(200)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("NewDate")
+ .HasColumnType("datetime2");
+
+ b.Property("NewState")
+ .HasColumnType("varchar(200)");
+
+ b.Property("OldDate")
+ .HasColumnType("datetime2");
+
+ b.Property("OldState")
+ .HasColumnType("varchar(200)");
+
+ b.Property("WorkItemId")
+ .HasColumnType("varchar(200)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("WorkItemId");
+
+ b.ToTable("WorkItemsChange");
+ });
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.TimeByState", b =>
+ {
+ b.HasOne("AzureDevopsStateTracker.Entities.WorkItem", "WorkItem")
+ .WithMany("TimeByStates")
+ .HasForeignKey("WorkItemId");
+ });
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItemChange", b =>
+ {
+ b.HasOne("AzureDevopsStateTracker.Entities.WorkItem", "WorkItem")
+ .WithMany("WorkItemsChanges")
+ .HasForeignKey("WorkItemId");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/AzureDevopsTracker/Migrations/20210720105645_FunctionToTimeInitial.cs b/AzureDevopsTracker/Migrations/20210720105645_FunctionToTimeInitial.cs
new file mode 100644
index 0000000..51dce04
--- /dev/null
+++ b/AzureDevopsTracker/Migrations/20210720105645_FunctionToTimeInitial.cs
@@ -0,0 +1,50 @@
+using AzureDevopsTracker.Data;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace AzureDevopsTracker.Migrations
+{
+ public partial class FunctionToTimeInitial : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ var rawFunction = @"CREATE OR ALTER FUNCTION ToTime (@seconds int)
+ RETURNS varchar(50)
+ AS BEGIN
+ declare @seconds_in_a_day int = 86400;
+ declare @seconds_in_an_hour int = 3600;
+ declare @seconds_in_a_minute int = 60;
+
+ declare @text_to_return varchar(50) = '';
+ if(@seconds >= @seconds_in_a_day)
+ begin
+ declare @completed_days int = @seconds/@seconds_in_a_day;
+ select @text_to_return = CONCAT(@text_to_return, @completed_days, ' day(s)')
+ select @seconds = @seconds - (@seconds_in_a_day * @completed_days)
+ end
+
+ if(@seconds >= @seconds_in_an_hour)
+ begin
+ declare @completed_hours int = @seconds/@seconds_in_an_hour;
+ select @text_to_return = CONCAT(@text_to_return, ' ', @completed_hours, ' hour(s)')
+ select @seconds = @seconds - (@seconds_in_an_hour * @completed_hours)
+ end
+
+ if(@seconds >= @seconds_in_a_minute)
+ begin
+ declare @completed_minutes int = @seconds/@seconds_in_a_minute;
+ select @text_to_return = CONCAT(@text_to_return, ' ', @completed_minutes, ' minute(s)')
+ select @seconds = @seconds - (@seconds_in_a_minute * @completed_minutes)
+ end
+
+ return LTRIM(RTRIM(@text_to_return));
+ END";
+ migrationBuilder.Sql(rawFunction);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ var dropFunction = @$"DROP FUNCTION IF EXISTS dbo.ToTime";
+ migrationBuilder.Sql(dropFunction);
+ }
+ }
+}
diff --git a/AzureDevopsTracker/Migrations/20210831213210_UpdatingColumns.Designer.cs b/AzureDevopsTracker/Migrations/20210831213210_UpdatingColumns.Designer.cs
new file mode 100644
index 0000000..686f2eb
--- /dev/null
+++ b/AzureDevopsTracker/Migrations/20210831213210_UpdatingColumns.Designer.cs
@@ -0,0 +1,160 @@
+//
+using System;
+using AzureDevopsTracker.Data;
+using AzureDevopsTracker.Data.Context;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace AzureDevopsTracker.Migrations
+{
+ [DbContext(typeof(AzureDevopsTrackerContext))]
+ [Migration("20210831213210_UpdatingColumns")]
+ partial class UpdatingColumns
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema(DataBaseConfig.SchemaName)
+ .HasAnnotation("ProductVersion", "3.1.18")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.TimeByState", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("varchar(200)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("State")
+ .HasColumnType("varchar(200)");
+
+ b.Property("TotalTime")
+ .HasColumnType("float");
+
+ b.Property("TotalWorkedTime")
+ .HasColumnType("float");
+
+ b.Property("WorkItemId")
+ .HasColumnType("varchar(200)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("WorkItemId");
+
+ b.ToTable("TimeByStates");
+ });
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItem", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Activity")
+ .HasColumnType("varchar(200)");
+
+ b.Property("AreaPath")
+ .HasColumnType("varchar(200)");
+
+ b.Property("AssignedTo")
+ .HasColumnType("varchar(200)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("CreatedBy")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Effort")
+ .HasColumnType("varchar(200)");
+
+ b.Property("IterationPath")
+ .HasColumnType("varchar(200)");
+
+ b.Property("OriginalEstimate")
+ .HasColumnType("varchar(200)");
+
+ b.Property("StoryPoints")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Tags")
+ .HasColumnType("varchar(200)");
+
+ b.Property("TeamProject")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Title")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Type")
+ .HasColumnType("varchar(200)");
+
+ b.Property("WorkItemParentId")
+ .HasColumnType("varchar(200)");
+
+ b.HasKey("Id");
+
+ b.ToTable("WorkItems");
+ });
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItemChange", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("varchar(200)");
+
+ b.Property("ChangedBy")
+ .HasColumnType("varchar(200)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("IterationPath")
+ .HasColumnType("varchar(200)");
+
+ b.Property("NewDate")
+ .HasColumnType("datetime2");
+
+ b.Property("NewState")
+ .HasColumnType("varchar(200)");
+
+ b.Property("OldDate")
+ .HasColumnType("datetime2");
+
+ b.Property("OldState")
+ .HasColumnType("varchar(200)");
+
+ b.Property("TotalWorkedTime")
+ .HasColumnType("float");
+
+ b.Property("WorkItemId")
+ .HasColumnType("varchar(200)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("WorkItemId");
+
+ b.ToTable("WorkItemsChange");
+ });
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.TimeByState", b =>
+ {
+ b.HasOne("AzureDevopsStateTracker.Entities.WorkItem", "WorkItem")
+ .WithMany("TimeByStates")
+ .HasForeignKey("WorkItemId");
+ });
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItemChange", b =>
+ {
+ b.HasOne("AzureDevopsStateTracker.Entities.WorkItem", "WorkItem")
+ .WithMany("WorkItemsChanges")
+ .HasForeignKey("WorkItemId");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/AzureDevopsTracker/Migrations/20210831213210_UpdatingColumns.cs b/AzureDevopsTracker/Migrations/20210831213210_UpdatingColumns.cs
new file mode 100644
index 0000000..f1cdc86
--- /dev/null
+++ b/AzureDevopsTracker/Migrations/20210831213210_UpdatingColumns.cs
@@ -0,0 +1,38 @@
+using AzureDevopsTracker.Data;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace AzureDevopsTracker.Migrations
+{
+ public partial class UpdatingColumns : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "IterationPath",
+ schema: DataBaseConfig.SchemaName,
+ table: "WorkItemsChange",
+ type: "varchar(200)",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "TotalWorkedTime",
+ schema: DataBaseConfig.SchemaName,
+ table: "WorkItemsChange",
+ nullable: false,
+ defaultValue: 0.0);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "IterationPath",
+ schema: DataBaseConfig.SchemaName,
+ table: "WorkItemsChange");
+
+ migrationBuilder.DropColumn(
+ name: "TotalWorkedTime",
+ schema: DataBaseConfig.SchemaName,
+ table: "WorkItemsChange");
+ }
+ }
+}
diff --git a/AzureDevopsTracker/Migrations/20210831213948_UpdatingCustomColumn.Designer.cs b/AzureDevopsTracker/Migrations/20210831213948_UpdatingCustomColumn.Designer.cs
new file mode 100644
index 0000000..c439c30
--- /dev/null
+++ b/AzureDevopsTracker/Migrations/20210831213948_UpdatingCustomColumn.Designer.cs
@@ -0,0 +1,163 @@
+//
+using System;
+using AzureDevopsTracker.Data;
+using AzureDevopsTracker.Data.Context;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace AzureDevopsTracker.Migrations
+{
+ [DbContext(typeof(AzureDevopsTrackerContext))]
+ [Migration("20210831213948_UpdatingCustomColumn")]
+ partial class UpdatingCustomColumn
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema(DataBaseConfig.SchemaName)
+ .HasAnnotation("ProductVersion", "3.1.18")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.TimeByState", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("varchar(200)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("State")
+ .HasColumnType("varchar(200)");
+
+ b.Property("TotalTime")
+ .HasColumnType("float");
+
+ b.Property("TotalWorkedTime")
+ .HasColumnType("float");
+
+ b.Property("WorkItemId")
+ .HasColumnType("varchar(200)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("WorkItemId");
+
+ b.ToTable("TimeByStates");
+ });
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItem", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Activity")
+ .HasColumnType("varchar(200)");
+
+ b.Property("AreaPath")
+ .HasColumnType("varchar(200)");
+
+ b.Property("AssignedTo")
+ .HasColumnType("varchar(200)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("CreatedBy")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Effort")
+ .HasColumnType("varchar(200)");
+
+ b.Property("IterationPath")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Lancado")
+ .HasColumnType("varchar(200)");
+
+ b.Property("OriginalEstimate")
+ .HasColumnType("varchar(200)");
+
+ b.Property("StoryPoints")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Tags")
+ .HasColumnType("varchar(200)");
+
+ b.Property("TeamProject")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Title")
+ .HasColumnType("varchar(200)");
+
+ b.Property("Type")
+ .HasColumnType("varchar(200)");
+
+ b.Property("WorkItemParentId")
+ .HasColumnType("varchar(200)");
+
+ b.HasKey("Id");
+
+ b.ToTable("WorkItems");
+ });
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItemChange", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("varchar(200)");
+
+ b.Property("ChangedBy")
+ .HasColumnType("varchar(200)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("IterationPath")
+ .HasColumnType("varchar(200)");
+
+ b.Property("NewDate")
+ .HasColumnType("datetime2");
+
+ b.Property("NewState")
+ .HasColumnType("varchar(200)");
+
+ b.Property("OldDate")
+ .HasColumnType("datetime2");
+
+ b.Property("OldState")
+ .HasColumnType("varchar(200)");
+
+ b.Property("TotalWorkedTime")
+ .HasColumnType("float");
+
+ b.Property("WorkItemId")
+ .HasColumnType("varchar(200)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("WorkItemId");
+
+ b.ToTable("WorkItemsChange");
+ });
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.TimeByState", b =>
+ {
+ b.HasOne("AzureDevopsStateTracker.Entities.WorkItem", "WorkItem")
+ .WithMany("TimeByStates")
+ .HasForeignKey("WorkItemId");
+ });
+
+ modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItemChange", b =>
+ {
+ b.HasOne("AzureDevopsStateTracker.Entities.WorkItem", "WorkItem")
+ .WithMany("WorkItemsChanges")
+ .HasForeignKey("WorkItemId");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/AzureDevopsTracker/Migrations/20210831213948_UpdatingCustomColumn.cs b/AzureDevopsTracker/Migrations/20210831213948_UpdatingCustomColumn.cs
new file mode 100644
index 0000000..1a77107
--- /dev/null
+++ b/AzureDevopsTracker/Migrations/20210831213948_UpdatingCustomColumn.cs
@@ -0,0 +1,26 @@
+using AzureDevopsTracker.Data;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace AzureDevopsTracker.Migrations
+{
+ public partial class UpdatingCustomColumn : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "Lancado",
+ schema: DataBaseConfig.SchemaName,
+ table: "WorkItems",
+ type: "varchar(200)",
+ nullable: true);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "Lancado",
+ schema: DataBaseConfig.SchemaName,
+ table: "WorkItems");
+ }
+ }
+}
diff --git a/AzureDevopsStateTracker/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs b/AzureDevopsTracker/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs
similarity index 90%
rename from AzureDevopsStateTracker/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs
rename to AzureDevopsTracker/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs
index 7baa9b1..c33ffdb 100644
--- a/AzureDevopsStateTracker/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs
+++ b/AzureDevopsTracker/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs
@@ -1,15 +1,15 @@
//
using System;
-using AzureDevopsStateTracker.Data;
-using AzureDevopsStateTracker.Data.Context;
+using AzureDevopsTracker.Data;
+using AzureDevopsTracker.Data.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-namespace AzureDevopsStateTracker.Migrations
+namespace AzureDevopsTracker.Migrations
{
- [DbContext(typeof(AzureDevopsStateTrackerContext))]
+ [DbContext(typeof(AzureDevopsTrackerContext))]
partial class AzureDevopsStateTrackerContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
@@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema(DataBaseConfig.SchemaName)
- .HasAnnotation("ProductVersion", "3.1.16")
+ .HasAnnotation("ProductVersion", "3.1.18")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
@@ -74,6 +74,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property("IterationPath")
.HasColumnType("varchar(200)");
+ b.Property("Lancado")
+ .HasColumnType("varchar(200)");
+
b.Property("OriginalEstimate")
.HasColumnType("varchar(200)");
@@ -111,6 +114,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property("CreatedAt")
.HasColumnType("datetime2");
+ b.Property("IterationPath")
+ .HasColumnType("varchar(200)");
+
b.Property("NewDate")
.HasColumnType("datetime2");
@@ -123,6 +129,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property("OldState")
.HasColumnType("varchar(200)");
+ b.Property("TotalWorkedTime")
+ .HasColumnType("float");
+
b.Property("WorkItemId")
.HasColumnType("varchar(200)");
diff --git a/AzureDevopsStateTracker/Services/AzureDevopsStateTrackerService.cs b/AzureDevopsTracker/Services/AzureDevopsTrackerService.cs
similarity index 62%
rename from AzureDevopsStateTracker/Services/AzureDevopsStateTrackerService.cs
rename to AzureDevopsTracker/Services/AzureDevopsTrackerService.cs
index 7b1f699..676ff54 100644
--- a/AzureDevopsStateTracker/Services/AzureDevopsStateTrackerService.cs
+++ b/AzureDevopsTracker/Services/AzureDevopsTrackerService.cs
@@ -1,28 +1,29 @@
-using AzureDevopsStateTracker.DTOs;
-using AzureDevopsStateTracker.DTOs.Create;
-using AzureDevopsStateTracker.DTOs.Update;
-using AzureDevopsStateTracker.Entities;
-using AzureDevopsStateTracker.Extensions;
-using AzureDevopsStateTracker.Interfaces;
-using AzureDevopsStateTracker.Interfaces.Internals;
+using AzureDevopsTracker.DTOs;
+using AzureDevopsTracker.DTOs.Create;
+using AzureDevopsTracker.DTOs.Update;
+using AzureDevopsTracker.Entities;
+using AzureDevopsTracker.Extensions;
+using AzureDevopsTracker.Interfaces;
+using AzureDevopsTracker.Interfaces.Internals;
using System;
using System.Linq;
+using System.Threading.Tasks;
-namespace AzureDevopsStateTracker.Services
+namespace AzureDevopsTracker.Services
{
- public class AzureDevopsStateTrackerService : IAzureDevopsStateTrackerService
+ public class AzureDevopsTrackerService : IAzureDevopsTrackerService
{
public readonly IWorkItemRepository _workItemRepository;
public readonly IWorkItemAdapter _workItemAdapter;
- public AzureDevopsStateTrackerService(
+ public AzureDevopsTrackerService(
IWorkItemAdapter workItemAdapter, IWorkItemRepository workItemRepository)
{
_workItemAdapter = workItemAdapter;
_workItemRepository = workItemRepository;
}
- public void Create(CreateWorkItemDTO create)
+ public async Task Create(CreateWorkItemDTO create, bool addWorkItemChange = true)
{
var workItem = new WorkItem(create.Resource.Id);
@@ -38,17 +39,36 @@ public void Create(CreateWorkItemDTO create)
create.Resource.Fields.Effort,
create.Resource.Fields.StoryPoints,
create.Resource.Fields.OriginalEstimate,
- create.Resource.Fields.Activity);
+ create.Resource.Fields.Activity,
+ create.Resource.Fields.Lancado);
- AddWorkItemChange(workItem, create);
+ if (addWorkItemChange)
+ AddWorkItemChange(workItem, create);
- _workItemRepository.Add(workItem);
- _workItemRepository.SaveChanges();
+ await _workItemRepository.Add(workItem);
+ await _workItemRepository.SaveChangesAsync();
}
- public void Update(UpdatedWorkItemDTO update)
+ public async Task Create(UpdatedWorkItemDTO updateDto)
{
- var workItem = _workItemRepository.GetByWorkItemId(update.Resource.WorkItemId);
+ var createDto = new CreateWorkItemDTO()
+ {
+ Resource = new DTOs.Create.Resource()
+ {
+ Fields = updateDto.Resource.Revision.Fields,
+ Id = updateDto.Resource.WorkItemId,
+ }
+ };
+
+ await Create(createDto, false);
+ }
+
+ public async Task Update(UpdatedWorkItemDTO update)
+ {
+ if (!_workItemRepository.Exist(update.Resource.WorkItemId).Result)
+ await Create(update);
+
+ var workItem = await _workItemRepository.GetByWorkItemId(update.Resource.WorkItemId);
if (workItem is null)
return;
@@ -57,24 +77,25 @@ public void Update(UpdatedWorkItemDTO update)
update.Resource.Revision.Fields.AreaPath,
update.Resource.Revision.Fields.IterationPath,
update.Resource.Revision.Fields.Type,
- update.Resource.Revision.Fields.CreatedBy,
- update.Resource.Revision.Fields.AssignedTo,
+ update.Resource.Revision.Fields.CreatedBy.ExtractEmail(),
+ update.Resource.Revision.Fields.AssignedTo.ExtractEmail(),
update.Resource.Revision.Fields.Tags,
update.Resource.Revision.Fields.Parent,
update.Resource.Revision.Fields.Effort,
update.Resource.Revision.Fields.StoryPoints,
update.Resource.Revision.Fields.OriginalEstimate,
- update.Resource.Revision.Fields.Activity);
+ update.Resource.Revision.Fields.Activity,
+ update.Resource.Revision.Fields.Lancado);
AddWorkItemChange(workItem, update);
_workItemRepository.Update(workItem);
- _workItemRepository.SaveChanges();
+ await _workItemRepository.SaveChangesAsync();
}
- public WorkItemDTO GetByWorkItemId(string workItemId)
+ public async Task GetByWorkItemId(string workItemId)
{
- var workItem = _workItemRepository.GetByWorkItemId(workItemId);
+ var workItem = await _workItemRepository.GetByWorkItemId(workItemId);
if (workItem is null)
return null;
@@ -82,16 +103,20 @@ public WorkItemDTO GetByWorkItemId(string workItemId)
}
#region Support Methods
- public WorkItemChange ToWorkItemChange(string workItemId, string changedBy, DateTime newDate, string newState, string oldState = null, DateTime? oldDate = null)
+ public WorkItemChange ToWorkItemChange(
+ string workItemId, string changedBy,
+ string iterationPath, DateTime newDate, string newState,
+ string oldState = null, DateTime? oldDate = null)
{
- return new WorkItemChange(workItemId, changedBy.ExtractEmail(), newDate, newState, oldState, oldDate);
+ return new WorkItemChange(workItemId, changedBy.ExtractEmail(), iterationPath, newDate, newState, oldState, oldDate);
}
public void AddWorkItemChange(WorkItem workItem, CreateWorkItemDTO create)
{
var workItemChange = ToWorkItemChange(workItem.Id,
create.Resource.Fields.ChangedBy,
- create.Resource.Fields.CreatedDate,
+ workItem.IterationPath,
+ create.Resource.Fields.CreatedDate.ToDateTimeFromTimeZoneInfo(),
create.Resource.Fields.State);
workItem.AddWorkItemChange(workItemChange);
@@ -102,10 +127,11 @@ public void AddWorkItemChange(WorkItem workItem, UpdatedWorkItemDTO update)
var changedBy = update.Resource.Revision.Fields.ChangedBy ?? update.Resource.Fields.ChangedBy.NewValue;
var workItemChange = ToWorkItemChange(workItem.Id,
changedBy,
- update.Resource.Fields.StateChangeDate.NewValue,
+ workItem.IterationPath,
+ update.Resource.Fields.StateChangeDate.NewValue.ToDateTimeFromTimeZoneInfo(),
update.Resource.Fields.State.NewValue,
update.Resource.Fields.State.OldValue,
- update.Resource.Fields.StateChangeDate.OldValue);
+ update.Resource.Fields.StateChangeDate.OldValue.ToDateTimeFromTimeZoneInfo());
workItem.AddWorkItemChange(workItemChange);