Рефакторинг + DI

This commit is contained in:
Danil Kislov
2019-03-15 17:49:58 +03:00
parent fd02201b42
commit d56094febb
19 changed files with 288 additions and 105 deletions
+4
View File
@@ -13,6 +13,10 @@
<assemblyIdentity name="RestSharp" publicKeyToken="598062e77f915f75" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-106.6.9.0" newVersion="106.6.9.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Autofac" publicKeyToken="17863af14b0044da" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.9.1.0" newVersion="4.9.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
@@ -1,10 +1,10 @@
using System;
using System.Text;
using System.Security.Cryptography;
using System.Text;
namespace JiraTimeBotForm.Passwords
namespace JiraTimeBotForm.Configuration
{
public class EncryptionClass
public class PasswordEncryptionClass
{
private byte[] GetEntropy(string EntropyString)
{
+32
View File
@@ -1,4 +1,7 @@
using System;
using System.IO;
using System.Windows.Forms;
using Newtonsoft.Json;
namespace JiraTimeBotForm.Configuration
{
@@ -14,5 +17,34 @@ namespace JiraTimeBotForm.Configuration
public TimeSpan ActivationTime { get; set; }
public bool DummyMode { get; set; }
public bool AddCommentsToWorklog { get; set; }
public static Settings Load()
{
var settingsPath = Path.Combine(Application.UserAppDataPath, _settingsFileName);
if (!File.Exists(settingsPath))
{
return null;
}
var settingsText = File.ReadAllText(settingsPath);
var settings = JsonConvert.DeserializeObject<Settings>(settingsText);
var password = new PasswordEncryptionClass().Decrypt(settings.JiraUserName, settings.JiraPassword, settings.JiraUrl);
settings.JiraPassword = password;
return settings;
}
public void Save()
{
var password = new PasswordEncryptionClass().Encrypt(this.JiraUserName, this.JiraPassword, this.JiraUrl);
this.JiraPassword = password;
var settingsPath = Path.Combine(Application.UserAppDataPath, _settingsFileName);
var settingsString = JsonConvert.SerializeObject(this);
File.WriteAllText(settingsPath, settingsString);
}
private static string _settingsFileName = "settings.json";
}
}
+42
View File
@@ -0,0 +1,42 @@
using System.Windows.Forms;
using Autofac;
using Autofac.Extras.AggregateService;
using JiraTimeBotForm.JiraIntegration;
using JiraTimeBotForm.Mercurial;
using JiraTimeBotForm.TaskProcessors;
using JiraTimeBotForm.TasksProcessors;
using JiraTimeBotForm.TaskTime;
using JiraTimeBotForm.UI;
namespace JiraTimeBotForm.DI
{
public class Bootstrapper
{
private readonly ContainerBuilder _builder;
public Bootstrapper()
{
_builder = new ContainerBuilder();
}
public IContainer Build(TextBox logTextBox)
{
_builder.Register(f => new Logger(logTextBox)).As<ILog>().AsSelf();
_builder.Register(f => new TrayMenu()).As<ITrayMenu>().AsSelf();
_builder.Register(c => new CommitSkipper()).As<ICommitSkipper>();
_builder.Register(c => new MercurialLog(c.Resolve<ILog>(), c.Resolve<ICommitSkipper>())).As<IMercurialLog>().AsSelf();
_builder.Register(c => new TaskTimeDiscoverer(c.Resolve<ILog>())).As<ITaskTimeDiscoverer>().AsSelf();
_builder.RegisterType<WorkLogTasksProcessor>().AsSelf().As<ITasksProcessor>();
_builder.RegisterType<MeetingProcessor>().AsSelf().As<ITasksProcessor>();
_builder.RegisterAggregateService<ITasksProcessors>();
_builder.Register(c => new JiraApi(c.Resolve<ILog>())).AsSelf().AsImplementedInterfaces();
_builder.Register(c => new Job(c.Resolve<IMercurialLog>(), c.Resolve<ITaskTimeDiscoverer>(), c.Resolve<ILog>())).AsSelf();
return _builder.Build();
}
}
}
+9 -10
View File
@@ -9,9 +9,7 @@ namespace JiraTimeBotForm.JiraIntegration
{
public class JiraApi
{
private readonly Settings _settings;
private readonly ILog _log;
private Jira _jira;
private readonly List<string> _dummyComments = new List<string>
{
@@ -19,18 +17,17 @@ namespace JiraTimeBotForm.JiraIntegration
"кодинг", "написание кода и тестов"
};
public JiraApi(Settings settings, ILog log = null)
public JiraApi(ILog log = null)
{
_settings = settings;
_log = log;
_jira = Jira.CreateRestClient(_settings.JiraUrl, _settings.JiraUserName, _settings.JiraPassword);
}
public string GetTaskName(string branch)
public string GetTaskName(string branch, Settings settings)
{
var jira = Jira.CreateRestClient(settings.JiraUrl, settings.JiraUserName, settings.JiraPassword);
try
{
var issue = _jira.Issues.Queryable.FirstOrDefault(f => f.Key == branch);
var issue = jira.Issues.Queryable.FirstOrDefault(f => f.Key == branch);
return issue?.Summary;
}
catch (Exception)
@@ -39,8 +36,10 @@ namespace JiraTimeBotForm.JiraIntegration
}
}
public void SetTodayWorklog(List<TaskTimeItem> taskTimeItems, DateTime? date = null, bool dummy = false, bool addCommentsToWorklog = false)
public void SetTodayWorklog(List<TaskTimeItem> taskTimeItems, Settings settings, DateTime? date = null, bool dummy = false, bool addCommentsToWorklog = false)
{
var jira = Jira.CreateRestClient(settings.JiraUrl, settings.JiraUserName, settings.JiraPassword);
if (date == null)
{
date = DateTime.Now.Date;
@@ -52,7 +51,7 @@ namespace JiraTimeBotForm.JiraIntegration
Issue issue = null;
try
{
issue = _jira.Issues.Queryable.FirstOrDefault(f => f.Key == taskTimeItem.Branch);
issue = jira.Issues.Queryable.FirstOrDefault(f => f.Key == taskTimeItem.Branch);
}
catch (Exception)
{
@@ -69,7 +68,7 @@ namespace JiraTimeBotForm.JiraIntegration
foreach (var workLog in workLogs)
{
var timeSpent = TimeSpan.FromSeconds(workLog.TimeSpentInSeconds);
if (workLog.CreateDate.GetValueOrDefault().Date == date && workLog.Author == _settings.JiraUserName)
if (workLog.CreateDate.GetValueOrDefault().Date == date && workLog.Author == settings.JiraUserName)
{
var timeDiff = Math.Abs((timeSpent - taskTimeItem.Time).TotalMinutes);
if (timeDiff > 1)
+19 -4
View File
@@ -38,6 +38,15 @@
<Reference Include="Atlassian.Jira, Version=10.4.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Atlassian.SDK.10.4.0\lib\net452\Atlassian.Jira.dll</HintPath>
</Reference>
<Reference Include="Autofac, Version=4.9.1.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
<HintPath>..\packages\Autofac.4.9.1\lib\net45\Autofac.dll</HintPath>
</Reference>
<Reference Include="Autofac.Extras.AggregateService, Version=4.1.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
<HintPath>..\packages\Autofac.Extras.AggregateService.4.1.0\lib\net45\Autofac.Extras.AggregateService.dll</HintPath>
</Reference>
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="Mercurial.Net, Version=1.1.1.607, Culture=neutral, PublicKeyToken=9e2fabf3af85dba9, processorArchitecture=MSIL">
<HintPath>..\packages\Mercurial.Net.1.1.1.607\lib\net35-Client\Mercurial.Net.dll</HintPath>
</Reference>
@@ -71,20 +80,25 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="DI\ContainerBuilder.cs" />
<Compile Include="Extensions\Extensions.cs" />
<Compile Include="Job.cs" />
<Compile Include="Logger.cs" />
<Compile Include="Configuration\Settings.cs" />
<Compile Include="frmMain.cs">
<Compile Include="Mercurial\CommitSkipper.cs" />
<Compile Include="Mercurial\ICommitSkipper.cs" />
<Compile Include="Mercurial\IMercurialLog.cs" />
<Compile Include="TasksProcessors\ITasksProcessors.cs" />
<Compile Include="UI\frmMain.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="frmMain.Designer.cs">
<Compile Include="UI\frmMain.Designer.cs">
<DependentUpon>frmMain.cs</DependentUpon>
</Compile>
<Compile Include="JiraIntegration\JiraApi.cs" />
<Compile Include="Mercurial\MercurialCommitItem.cs" />
<Compile Include="Mercurial\MercurialLog.cs" />
<Compile Include="Passwords\EncryptionClass.cs" />
<Compile Include="Configuration\PasswordEncryptionClass.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TasksProcessors\ITasksProcessor.cs" />
@@ -93,7 +107,8 @@
<Compile Include="TaskTime\ITaskTimeDiscoverer.cs" />
<Compile Include="TaskTime\TaskTimeDiscoverer.cs" />
<Compile Include="TaskTime\TaskTimeItem.cs" />
<EmbeddedResource Include="frmMain.resx">
<Compile Include="UI\TrayMenu.cs" />
<EmbeddedResource Include="UI\frmMain.resx">
<DependentUpon>frmMain.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
+3 -3
View File
@@ -13,11 +13,11 @@ namespace JiraTimeBotForm
{
class Job
{
private readonly MercurialLog _mercurialLog;
private readonly TaskTimeDiscoverer _taskTimeDiscoverer;
private readonly IMercurialLog _mercurialLog;
private readonly ITaskTimeDiscoverer _taskTimeDiscoverer;
private readonly ILog _log;
public Job(MercurialLog mercurialLog, TaskTimeDiscoverer taskTimeDiscoverer, ILog log)
public Job(IMercurialLog mercurialLog, ITaskTimeDiscoverer taskTimeDiscoverer, ILog log)
{
_mercurialLog = mercurialLog;
_taskTimeDiscoverer = taskTimeDiscoverer;
@@ -0,0 +1,24 @@
using System;
namespace JiraTimeBotForm.Mercurial
{
public class CommitSkipper : ICommitSkipper
{
public bool IsNeedToSkip(string branch, string commitMessage)
{
if (!branch.Contains("-"))
{
return true;
}
//Пропускаем Close и Merge коммиты
if (commitMessage.StartsWith($"Close {branch} ", StringComparison.InvariantCultureIgnoreCase) ||
commitMessage.StartsWith($"Merge with ", StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
return false;
}
}
}
@@ -0,0 +1,12 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiraTimeBotForm.Mercurial
{
public interface ICommitSkipper
{
bool IsNeedToSkip(string branch, string commitMessage);
}
}
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Threading;
using JiraTimeBotForm.Configuration;
namespace JiraTimeBotForm.Mercurial
{
public interface IMercurialLog
{
List<MercurialCommitItem> GetMercurialLog(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default(CancellationToken));
}
}
+5 -20
View File
@@ -9,13 +9,15 @@ using Mercurial;
namespace JiraTimeBotForm.Mercurial
{
public class MercurialLog
public class MercurialLog: IMercurialLog
{
private readonly ILog _log;
private readonly ICommitSkipper _commitSkipper;
public MercurialLog(ILog log)
public MercurialLog(ILog log, ICommitSkipper commitSkipper)
{
_log = log;
_commitSkipper = commitSkipper;
}
public List<MercurialCommitItem> GetMercurialLog(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default(CancellationToken))
@@ -54,7 +56,7 @@ namespace JiraTimeBotForm.Mercurial
}
var commitMessage = FixEncoding(changeset.CommitMessage);
if (IsNeedToSkip(changeset.Branch, commitMessage))
if (_commitSkipper.IsNeedToSkip(changeset.Branch, commitMessage))
{
continue;
}
@@ -113,23 +115,6 @@ namespace JiraTimeBotForm.Mercurial
return message;
}
private bool IsNeedToSkip(string branch, string commitMessage)
{
if (!branch.Contains("-"))
{
return true;
}
//Пропускаем Close и Merge коммиты
if (commitMessage.StartsWith($"Close {branch} ", StringComparison.InvariantCultureIgnoreCase) ||
commitMessage.StartsWith($"Merge with ", StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
return false;
}
private string FixEncoding(string source)
{
//перекодируем сообщение - ибо оно криво забирается в 1252
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiraTimeBotForm.TasksProcessors
{
public interface ITasksProcessors
{
WorkLogTasksProcessor WorkLogTasksProcessor { get; }
MeetingProcessor MeetingProcessor { get; }
}
}
@@ -8,24 +8,24 @@ using JiraTimeBotForm.TaskTime;
namespace JiraTimeBotForm.TasksProcessors
{
class MeetingProcessor : ITasksProcessor
public class MeetingProcessor : ITasksProcessor
{
private readonly ILog _log;
private readonly JiraApi _jiraApi;
public MeetingProcessor(ILog log)
public MeetingProcessor(ILog log, JiraApi jiraApi)
{
_log = log;
_jiraApi = jiraApi;
}
public void Process(DateTime date, List<TaskTimeItem> taskTimes, Settings settings)
{
var jira = new JiraApi(settings, _log);
_log.Trace($"На реальную дату {date:dd.MM.yyyy} распределение по задачам:");
foreach (var taskTime in taskTimes.OrderByDescending(f => f.Time))
{
var taskName = jira.GetTaskName(taskTime.Branch);
var taskName = _jiraApi.GetTaskName(taskTime.Branch, settings);
_log.Trace($" - [{taskTime.Branch}, коммитов {taskTime.Commits}]: {taskName} - {taskTime.Time}");
}
}
@@ -7,13 +7,15 @@ using JiraTimeBotForm.TaskTime;
namespace JiraTimeBotForm.TasksProcessors
{
class WorkLogTasksProcessor : ITasksProcessor
public class WorkLogTasksProcessor : ITasksProcessor
{
private readonly ILog _log;
private readonly JiraApi _jiraApi;
public WorkLogTasksProcessor(ILog log)
public WorkLogTasksProcessor(ILog log, JiraApi jiraApi)
{
_log = log;
_jiraApi = jiraApi;
}
public void Process(DateTime date, List<TaskTimeItem> taskTimes, Settings settings)
@@ -24,8 +26,7 @@ namespace JiraTimeBotForm.TasksProcessors
_log.Trace($"- {taskTime.Branch} (коммитов {taskTime.Commits}): {taskTime.Time}");
}
var jira = new JiraApi(settings, _log);
jira.SetTodayWorklog(taskTimes, dummy: settings.DummyMode, addCommentsToWorklog: settings.AddCommentsToWorklog);
_jiraApi.SetTodayWorklog(taskTimes, settings, dummy: settings.DummyMode, addCommentsToWorklog: settings.AddCommentsToWorklog);
}
}
}
+65
View File
@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace JiraTimeBotForm.UI
{
public class TrayMenu: ITrayMenu
{
private NotifyIcon _trayIcon;
public NotifyIcon Create(frmMain form)
{
var trayMenu = new ContextMenu();
trayMenu.MenuItems.Add("Exit", OnExit);
_trayIcon = new NotifyIcon
{
Text = "JiraTimeBot",
Icon = form.Icon,
ContextMenu = trayMenu,
Visible = false,
Tag = form
};
_trayIcon.Click += btnTray_Click;
_trayIcon.DoubleClick += btnTray_Click;
return _trayIcon;
}
public void Show()
{
_trayIcon.Visible = true;
}
public void Hide()
{
_trayIcon.Visible = false;
}
private void OnExit(object sender, EventArgs e)
{
Application.Exit();
}
private void btnTray_Click(object sender, EventArgs e)
{
var icon = (NotifyIcon) sender;
var form = (frmMain) icon.Tag;
form.Visible = true;
form.Activate();
form.BringToFront();
Extensions.Extensions.Restore(form);
}
}
public interface ITrayMenu
{
NotifyIcon Create(frmMain form);
void Show();
void Hide();
}
}
@@ -4,11 +4,13 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Autofac;
using JiraTimeBotForm.Configuration;
using JiraTimeBotForm.DI;
using JiraTimeBotForm.Mercurial;
using JiraTimeBotForm.Passwords;
using JiraTimeBotForm.TasksProcessors;
using JiraTimeBotForm.TaskTime;
using JiraTimeBotForm.UI;
using Newtonsoft.Json;
// This is the code for your desktop app.
@@ -18,11 +20,12 @@ namespace JiraTimeBotForm
{
public partial class frmMain : Form
{
private readonly string _settingsPath;
private readonly ILog _log;
private readonly NotifyIcon _trayIcon;
private Job _job;
private readonly Job _job;
private readonly IReadOnlyList<Control> _controls;
private readonly IContainer _container;
private readonly ITasksProcessors _tasksProcessors;
private readonly ITrayMenu _trayIcon;
private CancellationTokenSource _tokenSource;
private CancellationTokenSource GetTokenSource()
@@ -40,46 +43,21 @@ namespace JiraTimeBotForm
public frmMain()
{
InitializeComponent();
_settingsPath = Path.Combine(Application.UserAppDataPath, "settings.json");
_log = new Logger(txtLog);
_container = new Bootstrapper().Build(txtLog);
var trayMenu = new ContextMenu();
trayMenu.MenuItems.Add("Exit", OnExit);
_trayIcon = _container.Resolve<ITrayMenu>();
_trayIcon.Create(this);
_trayIcon = new NotifyIcon
{
Text = "JiraTimeBot",
Icon = this.Icon,
ContextMenu = trayMenu,
Visible = false,
};
_trayIcon.Click += btnTray_Click;
_trayIcon.DoubleClick += btnTray_Click;
var mercurialLog = new MercurialLog(_log);
var taskTimeDiscoverer = new TaskTimeDiscoverer(_log);
_job = new Job(mercurialLog, taskTimeDiscoverer, _log);
_job = _container.Resolve<Job>();
_log = _container.Resolve<ILog>();
_tasksProcessors = _container.Resolve<ITasksProcessors>();
_controls = new Control[] { txtJiraLogin, txtJiraPassword, txtMercurialEmail, actTime, txtRepoPath, txtDummyMode, btnSave, btnStart, btnMeeting, chkAddComments };
}
private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{
_trayIcon.Visible = false;
}
private void OnExit(object sender, EventArgs e)
{
Application.Exit();
}
private void btnTray_Click(object sender, EventArgs e)
{
this.Visible = true;
this.Activate();
this.BringToFront();
Extensions.Extensions.Restore(this);
_trayIcon.Hide();
}
public Settings ReadSettingsAndLock()
@@ -116,33 +94,29 @@ namespace JiraTimeBotForm
var settings = ReadSettingsAndLock();
LockUnlock(true);
var password = new EncryptionClass().Encrypt(settings.JiraUserName, settings.JiraPassword, settings.JiraUrl);
settings.JiraPassword = password;
var settingsString = JsonConvert.SerializeObject(settings);
File.WriteAllText(_settingsPath, settingsString);
settings.Save();
MessageBox.Show("Settings saved.");
LoadSettings();
settings = Settings.Load();
if (settings != null)
{
SetSettings(settings);
}
}
private void Form1_Load(object sender, EventArgs e)
{
if (File.Exists(_settingsPath))
var settings = Settings.Load();
if (settings != null)
{
LoadSettings();
SetSettings(settings);
}
}
private void LoadSettings()
private void SetSettings(Settings settings)
{
var settingsText = File.ReadAllText(_settingsPath);
var settings = JsonConvert.DeserializeObject<Settings>(settingsText);
var password = new EncryptionClass().Decrypt(settings.JiraUserName, settings.JiraPassword, settings.JiraUrl);
txtJiraLogin.Text = settings.JiraUserName;
txtJiraPassword.Text = password;
txtJiraPassword.Text = settings.JiraPassword;
txtMercurialEmail.Text = settings.MercurialAuthorEmail;
txtRepoPath.Text = settings.RepositoryPath;
actTime.Text = settings.ActivationTime.ToString("hh\\:mm\\:ss");
@@ -162,7 +136,7 @@ namespace JiraTimeBotForm
using (_tokenSource = GetTokenSource())
{
await _job.DoTheJob(settings, new WorkLogTasksProcessor(_log), _tokenSource.Token);
await _job.DoTheJob(settings, _tasksProcessors.WorkLogTasksProcessor, _tokenSource.Token);
}
LockUnlock(true);
@@ -172,13 +146,13 @@ namespace JiraTimeBotForm
{
if (FormWindowState.Minimized == this.WindowState)
{
_trayIcon.Visible = true;
_trayIcon.Show();
this.Hide();
}
else if (FormWindowState.Normal == this.WindowState)
{
_trayIcon.Visible = false;
_trayIcon.Hide();
}
}
@@ -208,7 +182,7 @@ namespace JiraTimeBotForm
using (var tokenSource = GetTokenSource())
{
await _job.DoTheJob(settings, new WorkLogTasksProcessor(_log), tokenSource.Token);
await _job.DoTheJob(settings, _tasksProcessors.WorkLogTasksProcessor, tokenSource.Token);
}
LockUnlock(true);
@@ -227,7 +201,7 @@ namespace JiraTimeBotForm
using (_tokenSource = GetTokenSource())
{
await _job.DoTheJob(settings, new MeetingProcessor(_log), _tokenSource.Token);
await _job.DoTheJob(settings, _tasksProcessors.MeetingProcessor, _tokenSource.Token);
}
LockUnlock(true);
+3
View File
@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Atlassian.SDK" version="10.4.0" targetFramework="net461" />
<package id="Autofac" version="4.9.1" targetFramework="net461" />
<package id="Autofac.Extras.AggregateService" version="4.1.0" targetFramework="net461" />
<package id="Castle.Core" version="4.0.0" targetFramework="net461" />
<package id="Mercurial.Net" version="1.1.1.607" targetFramework="net461" />
<package id="Newtonsoft.Json" version="12.0.1" targetFramework="net461" />
<package id="NLog" version="4.5.11" targetFramework="net461" />