Commit 5dc06dbb authored by Thomas's avatar Thomas
Browse files

Merge branch 'OUT-815' into OUT-789

parents 6715b121 78ac1768
using pEp.Extensions;
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace pEp.DPE
{
internal static class DPEWebClient
{
private static readonly HttpClient httpClient = new HttpClient();
private static readonly string dbePostUrl = Globals.ThisAddIn.Settings.DPEWebClientUrl + "patches/";
private static readonly HttpClient httpClient = new HttpClient();
private static readonly string DPE_POST_URL = Globals.ThisAddIn.Settings.DPEWebClientUrl + "patches/";
public static readonly string REJECT_PATCH_SUFFIX = "/reject/";
public static readonly string SUPPORT_PATCH_SUFFIX = "/support/";
public const string REJECT_PATCH_SUFFIX = "/reject/";
public const string SUPPORT_PATCH_SUFFIX = "/support/";
/// <summary>
/// Rejects a given patch.
/// </summary>
/// <param name="patch">The patch to reject.</param>
/// <param name="me">The own identity that rejects the patch.</param>
public static async void RejectPatch(Patch patch, PEPIdentity me)
/// <exception cref="ArgumentNullException" />
/// <exception cref="HttpRequestException" />
/// <returns>The Http response.</returns>
public static async Task<HttpResponseMessage> RejectPatch(Patch patch, PEPIdentity me)
{
// POST http://server:port/pEpDPE/patches/patch_id/reject
// POST http://localhost:port/pEpDPE/patches/patch_id/reject
try
{
HttpResponseMessage response =
await DPEWebClient.httpClient.PostAsync(DPEWebClient.dbePostUrl,
new StringContent(patch.Id + DPEWebClient.REJECT_PATCH_SUFFIX));
Log.Verbose($"SuggestPatch: Patch { patch.Id } rejected. Return status is { Enum.GetName(typeof(HttpStatusCode), response.StatusCode) }");
return await DPEWebClient.httpClient.PostAsync(DPEWebClient.DPE_POST_URL,
new StringContent(patch.Id + DPEWebClient.REJECT_PATCH_SUFFIX));
}
catch (Exception ex)
catch (ArgumentNullException ex)
{
Log.Error("RejectPatch: Error rejecting patch. " + ex.ToString());
Log.ErrorAndFailInDebugMode("RejectPatch: Error rejecting patch. " + ex);
throw ex;
}
catch (HttpRequestException ex)
{
Log.Error("RejectPatch: Error rejecting patch. " + ex);
throw ex;
}
}
......@@ -39,20 +46,26 @@ namespace pEp.DPE
/// </summary>
/// <param name="patch">The patch to suggest.</param>
/// <param name="me">The own identity that suggests the patch.</param>
public static async void SuggestPatch(Patch patch, PEPIdentity me)
/// <exception cref="ArgumentNullException" />
/// <exception cref="HttpRequestException" />
/// <returns>The Http response.</returns>
public static async Task<HttpResponseMessage> SuggestPatch(Patch patch, PEPIdentity me)
{
// POST http://server:port/pEpDPE/patches/
string xml = patch.Serialize();
// POST http://localhost:port/pEpDPE/patches/
try
{
HttpResponseMessage response =
await DPEWebClient.httpClient.PostAsync(DPEWebClient.dbePostUrl,
new StringContent(xml));
Log.Verbose($"SuggestPatch: New patch posted. Return status is { Enum.GetName(typeof(HttpStatusCode), response.StatusCode) }");
string xml = patch.Serialize();
return await DPEWebClient.httpClient.PostAsync(DPEWebClient.DPE_POST_URL, new StringContent(xml));
}
catch (ArgumentNullException ex)
{
Log.ErrorAndFailInDebugMode("SuggestPatch: Error suggesting patch. " + ex);
throw ex;
}
catch (Exception ex)
catch (HttpRequestException ex)
{
Log.Error("SuggestPatch: Error suggesting patch. " + ex.ToString());
Log.Error("SuggestPatch: Error suggesting patch. " + ex);
throw ex;
}
}
......@@ -61,19 +74,26 @@ namespace pEp.DPE
/// </summary>
/// <param name="patch">The patch to support.</param>
/// <param name="me">The own identity that supports the patch.</param>
public static async void SupportPatch(Patch patch, PEPIdentity me)
/// <exception cref="ArgumentNullException" />
/// <exception cref="HttpRequestException" />
/// <returns>The Http response.</returns>
public static async Task<HttpResponseMessage> SupportPatch(Patch patch, PEPIdentity me)
{
// POST http://server:port/pEpDPE/patches/patch_id/support
// POST http://localhost:port/pEpDPE/patches/patch_id/support
try
{
HttpResponseMessage response =
await DPEWebClient.httpClient.PostAsync(DPEWebClient.dbePostUrl,
new StringContent(patch.Id + DPEWebClient.SUPPORT_PATCH_SUFFIX));
Log.Verbose($"SuggestPatch: Patch { patch.Id } supported. Return status is { Enum.GetName(typeof(HttpStatusCode), response.StatusCode) }");
return await DPEWebClient.httpClient.PostAsync(DPEWebClient.DPE_POST_URL,
new StringContent(patch.Id + DPEWebClient.SUPPORT_PATCH_SUFFIX));
}
catch (ArgumentNullException ex)
{
Log.ErrorAndFailInDebugMode("SupportPatch: Error supporting patch. " + ex);
throw ex;
}
catch (Exception ex)
catch (HttpRequestException ex)
{
Log.Error("SupportPatch: Error supporting patch. " + ex.ToString());
Log.Error("SupportPatch: Error supporting patch. " + ex);
throw ex;
}
}
}
......
using pEp.DPE.Interfaces;
using pEp.Extensions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace pEp.DPE
......@@ -12,10 +14,24 @@ namespace pEp.DPE
{
private static readonly string DPE_FOLDER = Path.Combine(Globals.PEPUserFolder, "DPE");
public static readonly string DPE_TEMP_LOCATION = Path.Combine(DistributedPolicyEngine.DPE_FOLDER, "temp");
private const string PATCH_EXTENSION = ".patch";
private const string PATCH_MESSAGE_SUBJECT = "Configuration changes";
public const string DPE_MESSAGE_CLASS = "IPM.Note.DPE";
public enum PatchStatus
{
Open,
Accepted,
Supported,
Rejected
}
private enum PostAction
{
Reject,
Suggest,
Support
}
private readonly PEPIdentity ownIdentity;
private readonly PatchEvents patchEvents;
......@@ -30,7 +46,7 @@ namespace pEp.DPE
}
#region Event handlers
/// <summary>
/// Event handler for when a patch has been accepted.
/// </summary>
......@@ -58,6 +74,10 @@ namespace pEp.DPE
ThisAddIn.PEPEngine.ShowNotification("New patch suggested", patch.CommitMessage + " " + patch.Diff);
}
#endregion
#region Methods
/// <summary>
/// Creates a mail item that shows a suggested patch.
/// </summary>
......@@ -90,7 +110,8 @@ namespace pEp.DPE
{ MapiProperty.PidTagMessageDeliveryTime, DateTime.UtcNow }
});
omi.SetMessageFlag(MapiPropertyValue.EnumPidTagMessageFlags.mfUnsent, false);
omi.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_DPE_PATCH_ID, patch.Id);
// Move to inbox and set Received time
mi = omi.Move(Globals.ThisAddIn.Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox));
mi.Save();
......@@ -106,10 +127,6 @@ namespace pEp.DPE
}
}
#endregion
#region Methods
/// <summary>
/// Disposes of all resources.
/// </summary>
......@@ -119,17 +136,161 @@ namespace pEp.DPE
this.patchEvents.Dispose();
}
/// <summary>
/// Gets the corresponding patch mail item.
/// </summary>
/// <param name="patch">The patch that this item belongs to.</param>
/// <returns>The patch mail item or null if not found.</returns>
public Outlook.MailItem GetPatchMailItem(Patch patch)
{
Outlook.Folder inbox = null;
Outlook.Items items = null;
try
{
inbox = Globals.ThisAddIn.Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder;
items = inbox?.Items;
if (items?.Count > 0)
{
Log.Verbose("GetPatchMailItem: " + items.Count + " items found in " + inbox.FolderPath);
// First filter out older items
items = items.Restrict("[ReceivedTime] >= '" + patch.CreationDate.ToString("g") + "'");
Log.Verbose("GetPatchMailItem: Items since receival of patch: " + items?.Count ?? "0");
Outlook.UserDefinedProperties up = inbox.UserDefinedProperties;
if (up.Find(MailItemExtensions.USER_PROPERTY_KEY_DPE_PATCH_ID) == null)
{
up.Add(MailItemExtensions.USER_PROPERTY_KEY_DPE_PATCH_ID, Outlook.OlUserPropertyType.olText);
}
// Now find the one with the respective patch id
string filter = string.Format("[{0}] = '{1}'", MailItemExtensions.USER_PROPERTY_KEY_DPE_PATCH_ID, patch.Id);
items = items.Restrict(filter);
if (items.Count > 1)
{
Log.Error("GetPatchMailItem: More than one item found with patch id " + patch.Id);
}
else if (items.Count < 1)
{
Log.Error("GetPatchMailItem: No item found with patch id " + patch.Id);
}
else
{
return items[1] as Outlook.MailItem;
}
}
else
{
Log.Verbose("GetPatchMailItem: No items were found or folder was null.");
}
}
catch (Exception ex)
{
Log.Error("GetPatchMailItem: Error occured. " + ex);
}
finally
{
inbox = null;
items = null;
}
return null;
}
/// <summary>
/// Performs the given post action.
/// </summary>
/// <param name="patch">The patch to post.</param>
/// <param name="me">The own identity.</param>
/// <param name="postAction">The POST action to perform.</param>
/// <returns></returns>
private async Task<Exception> PostAsync(Patch patch, PEPIdentity me, PostAction postAction)
{
// Determine the correct method to execute
Task<HttpResponseMessage> postTask = null;
switch (postAction)
{
case PostAction.Reject:
postTask = DPEWebClient.RejectPatch(patch, me);
break;
case PostAction.Suggest:
postTask = DPEWebClient.SuggestPatch(patch, me);
break;
case PostAction.Support:
postTask = DPEWebClient.SupportPatch(patch, me);
break;
default:
Log.ErrorAndFailInDebugMode("PostAsync: Unknown post action.");
break;
}
// Execute the task and return status
return await postTask.ContinueWith((task) =>
{
if (task.Exception != null)
{
Log.Error("ExecuteAsync: Error executing POST of type " + Enum.GetName(typeof(PostAction), postAction));
return task.Exception;
}
else
{
return (task.Result.StatusCode != HttpStatusCode.OK) ?
new Exception(Enum.GetName(typeof(HttpStatusCode), task.Result.StatusCode)) :
null;
}
});
}
/// <summary>
/// Rejects a given patch.
/// </summary>
/// <param name="patch">The patch to reject.</param>
/// <param name="me">The own identity that rejects the patch.</param>
public void Reject(Patch patch, PEPIdentity me)
public async Task Reject(Patch patch, PEPIdentity me)
{
DPEWebClient.RejectPatch(patch, me);
if (await this.PostAsync(patch, me, PostAction.Reject) is Exception ex)
{
throw ex;
}
this.UpdatePatchMailItem(patch, PatchStatus.Rejected);
AdapterExtensions.ShowNotification("Patch rejected", patch.CommitMessage);
}
/// <summary>
/// Updates the patch mail item after a successful change in the patch status.
/// </summary>
/// <param name="patch">The corresponding patch.</param>
/// <param name="patchStatus">The new patch status.</param>
/// <returns>True if the mail item was updated correctly, otherwise false.</returns>
private bool UpdatePatchMailItem(Patch patch, PatchStatus patchStatus)
{
Outlook.MailItem omi = null;
try
{
omi = this.GetPatchMailItem(patch);
// Update the user properties
if (omi != null)
{
omi.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_DPE_PATCH_STATUS, (int)patchStatus);
omi.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_DPE_PATCH_EDIT_DATE, DateTime.UtcNow);
omi.Save();
}
}
catch (Exception ex)
{
Log.Error("UpdatePatchMailItem: Error occured. " + ex);
return false;
}
return true;
}
/// <summary>
/// Subscribes to the given patch events.
/// </summary>
......@@ -146,9 +307,13 @@ namespace pEp.DPE
/// </summary>
/// <param name="patch">The patch to suggest.</param>
/// <param name="me">The own identity that suggests the patch.</param>
public void Suggest(Patch patch, PEPIdentity me)
public async Task Suggest(Patch patch, PEPIdentity me)
{
DPEWebClient.SuggestPatch(patch, me);
if (await this.PostAsync(patch, me, PostAction.Suggest) is Exception ex)
{
throw ex;
}
AdapterExtensions.ShowNotification("Patch suggested", patch.CommitMessage);
}
......@@ -157,9 +322,14 @@ namespace pEp.DPE
/// </summary>
/// <param name="patch">The patch to support.</param>
/// <param name="me">The own identity that supports the patch.</param>
public void Support(Patch patch, PEPIdentity me)
public async Task Support(Patch patch, PEPIdentity me)
{
DPEWebClient.SupportPatch(patch, me);
if (await this.PostAsync(patch, me, PostAction.Support) is Exception ex)
{
throw ex;
}
this.UpdatePatchMailItem(patch, PatchStatus.Supported);
AdapterExtensions.ShowNotification("Patch supported", patch.CommitMessage);
}
......
using System;
using System.Threading.Tasks;
namespace pEp.DPE.Interfaces
{
......@@ -6,8 +7,8 @@ namespace pEp.DPE.Interfaces
{
void Subscribe(PatchEvents patchEvents);
void Unsubscribe(PatchEvents patchEvents);
void Suggest(Patch patch, PEPIdentity me);
void Support(Patch patch, PEPIdentity me);
void Reject(Patch patch, PEPIdentity me);
Task Suggest(Patch patch, PEPIdentity me);
Task Support(Patch patch, PEPIdentity me);
Task Reject(Patch patch, PEPIdentity me);
}
}
......@@ -19,6 +19,7 @@ namespace pEp
{
public const string USER_PROPERTY_KEY_DPE_PATCH_STATUS = "patchStatus";
public const string USER_PROPERTY_KEY_DPE_PATCH_EDIT_DATE = "patchEditDate";
public const string USER_PROPERTY_KEY_DPE_PATCH_ID = "patchId";
public const string USER_PROPERTY_KEY_INSPECTOR_CLOSED = "inspectorClosed";
public const string USER_PROPERTY_KEY_IS_INCOMING = "isIncoming";
public const string USER_PROPERTY_KEY_IS_MIRROR = "isMirror";
......
......@@ -62,8 +62,9 @@ namespace pEp
public const string CULTURE_CODE_DEFAULT = "en";
public const bool DELETE_MIRROR_MESSAGES_DEFAULT = false;
public const string DISCLAIMER_TEXT_DEFAULT = null;
public static readonly string DPE_WEB_CLIENT_URL_DEFAULT = "http://localhost:30457/pEpDPE/";
public static readonly string DPE_WEB_SERVER_URL_DEFAULT = "http://localhost:30456/pEpDPE/";
public const string DPE_EDITOR_PATH_DEFAULT = "Notepad.exe";
public const string DPE_WEB_CLIENT_URL_DEFAULT = "http://localhost:30457/pEpDPE/";
public const string DPE_WEB_SERVER_URL_DEFAULT = "http://localhost:30456/pEpDPE/";
public const bool ENABLE_NATIVE_METHODS_DEFAULT = true;
public const bool ENCRYPT_ACCOUNTS_BY_DEFAULT = true;
public const bool HIDE_INTERNAL_MESSAGES_DEFAULT = true;
......@@ -172,6 +173,12 @@ namespace pEp
/// </summary>
public bool DeleteMirrorMessages { get; private set; } = PEPSettings.DELETE_MIRROR_MESSAGES_DEFAULT;
/// <summary>
/// Gets the path to the editor to use to edit config files.
/// Can only be set from the Registry.
/// </summary>
public string DPEEditorPath { get; private set; } = PEPSettings.DPE_EDITOR_PATH_DEFAULT;
/// <summary>
/// Gets the URL of the DPE Web client.
/// </summary>
......
using pEp.DPE;
using pEp.UI.ViewModels;
using System;
using System.ComponentModel;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace pEp
......@@ -36,12 +35,12 @@ namespace pEp
string xml = omi.HTMLBody;
Patch patch = Patch.Deserialize(xml);
FormControlPatchViewModel.PatchStatus patchStatus = FormControlPatchViewModel.PatchStatus.Open;
DistributedPolicyEngine.PatchStatus patchStatus = DistributedPolicyEngine.PatchStatus.Open;
DateTime? editDate = null;
// Get patch status if available
if ((omi.GetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_DPE_PATCH_STATUS, FormControlPatchViewModel.PatchStatus.Open) is string patchStatusString) &&
Enum.TryParse(patchStatusString, out FormControlPatchViewModel.PatchStatus status))
if ((omi.GetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_DPE_PATCH_STATUS, DistributedPolicyEngine.PatchStatus.Open) is string patchStatusString) &&
Enum.TryParse(patchStatusString, out DistributedPolicyEngine.PatchStatus status))
{
patchStatus = status;
}
......@@ -53,16 +52,10 @@ namespace pEp
editDate = savedEditDate;
}
// Get the patch submitter
// Get the patch submitter and set data context
if (PEPIdentity.GetFromIdentity(omi, out PEPIdentity submitter) == Globals.ReturnStatus.Success)
{
this.FormControlPatchView.DataContext = new FormControlPatchViewModel(patch, submitter, patchStatus, editDate);
// Subscribe to property changed event
if (this.FormControlPatchView.DataContext is FormControlPatchViewModel formControlPatchViewModel)
{
formControlPatchViewModel.PropertyChanged += this.FormRegionDPE_PropertyChanged;
}
}
else
{
......@@ -79,55 +72,11 @@ namespace pEp
}
}
/// <summary>
/// Event handler for when a property in the associated view model changes.
/// </summary>
private void FormRegionDPE_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// Set patch status and edit date as user properties if being changed
if ((e.PropertyName == nameof(FormControlPatchViewModel.Status)) ||
(e.PropertyName == nameof(FormControlPatchViewModel.EditDate)))
{
Outlook.MailItem omi = null;
try
{
omi = this.OutlookItem as Outlook.MailItem;
FormControlPatchViewModel.PatchStatus patchStatus = (sender as FormControlPatchViewModel).Status;
DateTime? editDate = (sender as FormControlPatchViewModel).EditDate;
if (patchStatus != FormControlPatchViewModel.PatchStatus.Open)
{
omi.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_DPE_PATCH_STATUS, Enum.GetName(typeof(FormControlPatchViewModel.PatchStatus), patchStatus));
}
if (editDate != null)
{
omi.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_DPE_PATCH_EDIT_DATE, editDate?.ToString("f"));
}
omi.Save();
}
catch (Exception ex)
{
Log.Error("FormRegionDPE_PropertyChanged: Error setting user property. " + ex);
}
finally
{
omi = null;
}
}
}
// Occurs when the form region is closed.
// Use this.OutlookItem to get a reference to the current Outlook item.
// Use this.OutlookFormRegion to get a reference to the form region.
private void FormRegionDPE_FormRegionClosed(object sender, EventArgs e)
{
// Unsubscribe from property changed event
if (this.FormControlPatchView.DataContext is FormControlPatchViewModel formControlPatchViewModel)
{
formControlPatchViewModel.PropertyChanged -= this.FormRegionDPE_PropertyChanged;
}
}
}
}
using pEp.DPE;
using pEp.UI.Models;
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
namespace pEp.UI.ViewModels
{
internal class FormControlPatchViewModel : ViewModelBase
{
public enum PatchStatus
{
Open,
Accepted,
Supported,
Rejected
}
#region Fields
private readonly Patch patch;
private PatchStatus _Status = PatchStatus.Open;
private DateTime? _EditDate = null;
private string _Explanation = null;
private Brush _Background = Brushes.White;
private FlowDocument _DisplayDiff = null;
private DateTime? _EditDate = null;
private string _Explanation = null;
private DistributedPolicyEngine.PatchStatus _Status = DistributedPolicyEngine.PatchStatus.Open;
#endregion
#region Properties
/// <summary>
/// Gets or sets the background.
/// </summary>
public Brush Background { get => this._Background; set => this.SetProperty(ref this._Background, value); }
/// <summary>
/// The commit message of the patch.
/// </summary>
......@@ -58,9 +61,9 @@ namespace pEp.UI.ViewModels
}
/// <summary>
/// Gets the diff of this patch as formatted flow document.
/// Gets or sets the diff of this patch as formatted flow document.
/// </summary>
public FlowDocument DisplayDiff => PatchDialogViewModel.FormatDiff(this.Diff);
public FlowDocument DisplayDiff { get => this._DisplayDiff; set => this.SetProperty(ref this._DisplayDiff, value); }
/// <summary>
/// Gets or sets the last date the patch was edited.
......@@ -85,7 +88,7 @@ namespace pEp.UI.ViewModels
/// <summary>
/// The command to accept the patch dialog.
/// </summary>
public RelayCommand OKButtonCommand => new RelayCommand(this.SupportPatch, p => (this.Status == PatchStatus.Open));
public RelayCommand OKButtonCommand => new RelayCommand(this.SupportPatch, p => (this.Status == DistributedPolicyEngine.PatchStatus.Open));
/// <summary>
/// Gets the OK button text.
......@@ -95,7 +98,7 @@ namespace pEp.UI.ViewModels
/// <summary>
/// The command to reject the dialog.
/// </summary>
public RelayCommand RejectButtonCommand => new RelayCommand(this.RejectPatch, p => (this.Status == PatchStatus.Open));
public RelayCommand RejectButtonCommand => new RelayCommand(this.RejectPatch, p => (this.Status == DistributedPolicyEngine.PatchStatus.Open));
/// <summary>
/// Gets the Reject button text.
......@@ -110,7 +113,7 @@ namespace pEp.UI.ViewModels
/// <summary>
/// Gets or sets the status of this patch.
/// </summary>
public PatchStatus Status { get => this._Status; set => this.SetProperty(ref this._Status, value); }
public DistributedPolicyEngine.PatchStatus Status { get => this._Status; set => this.SetProperty(ref this._Status, value); }
/// <summary>
/// Gets or sets the tag of the patch.
......@@ -149,15 +152,14 @@ namespace pEp.UI.ViewModels
/// <param name="submitter">The submitter of the patch.</param>
/// <param name="status">The status of the patch.</param>
/// <param name="editDate">The last time this patch was edited (accepted/supported/rejected).</param>
public FormControlPatchViewModel(Patch patch, PEPIdentity submitter, PatchStatus status = PatchStatus.Open, DateTime? editDate = null)
public FormControlPatchViewModel(Patch patch, PEPIdentity submitter, DistributedPolicyEngine.PatchStatus status = DistributedPolicyEngine.PatchStatus.Open, DateTime? editDate = null)
{
this.EditDate = editDate;
this.patch = patch;
this.Submitter = submitter;
this.Status = status;
this.IsRejectButtonVisible = true;
this.OKButtonText = "Support";
this.SetExplanation();
this.UpdateView(status);
}
#endregion
......@@ -168,12 +170,24 @@ namespace pEp.UI.ViewModels
/// Rejects this patch.
/// </summary>
/// <param name="parameter">The command parameter.</param>
private void RejectPatch(object parameter)
private async void RejectPatch(object parameter)
{
Globals.ThisAddIn.DistributedPolicyEngine.Reject(this.patch, new PEPIdentity());
this.Status = PatchStatus.Rejected;
this.EditDate = DateTime.UtcNow;
this.SetExplanation();
try
{
await Globals.ThisAddIn.DistributedPolicyEngine.Reject(this.patch, new PEPIdentity());
}
catch (Exception ex)
{
while (ex.InnerException != null)
{
ex = ex.InnerException;
}
CustomMessageBox.ShowDialog(ex.Message, "Error", "OK");
return;
}
this.UpdateView(DistributedPolicyEngine.PatchStatus.Rejected);
}
/// <summary>
......@@ -189,16 +203,16 @@ namespace pEp.UI.ViewModels
switch (this.Status)
{
case PatchStatus.Accepted:
case DistributedPolicyEngine.PatchStatus.Accepted:
this.Explanation = $"Accepted on { editDate }";
break;
case PatchStatus.Supported:
case DistributedPolicyEngine.PatchStatus.Supported:
this.Explanation = $"Supported on { editDate }";
break;
case PatchStatus.Rejected:
case DistributedPolicyEngine.PatchStatus.Rejected:
this.Explanation = $"Rejected on { editDate }";
break;
case PatchStatus.Open:
case DistributedPolicyEngine.PatchStatus.Open:
default:
this.Explanation = "New configuration changes pending approval";
break;
......@@ -209,12 +223,39 @@ namespace pEp.UI.ViewModels
/// Supports this patch.
/// </summary>
/// <param name="parameter">The command parameter.</param>
private void SupportPatch(object parameter)
private async void SupportPatch(object parameter)
{
try
{
await Globals.ThisAddIn.DistributedPolicyEngine.Support(this.patch, new PEPIdentity());
}
catch (Exception ex)
{
Log.Error("SupportPatch: Error occured. " + ex);
while (ex.InnerException != null)
{
ex = ex.InnerException;
}
CustomMessageBox.ShowDialog(ex.Message, "Error", "OK");
return;
}
this.UpdateView(DistributedPolicyEngine.PatchStatus.Supported);
}
/// <summary>
/// Updates the view according to a new patch status.
/// </summary>
/// <param name="patchStatus">The new patch status.</param>
private void UpdateView(DistributedPolicyEngine.PatchStatus patchStatus)
{
Globals.ThisAddIn.DistributedPolicyEngine.Support(this.patch, new PEPIdentity());
this.Status = PatchStatus.Supported;
this.Status = patchStatus;
this.EditDate = DateTime.UtcNow;
this.SetExplanation();
this.DisplayDiff = PatchDialogViewModel.FormatDiff(this.Diff, this.Status == DistributedPolicyEngine.PatchStatus.Open);
this.Background = (patchStatus == DistributedPolicyEngine.PatchStatus.Open) ? Brushes.White : Brushes.WhiteSmoke;
}
#endregion
......
......@@ -27,8 +27,8 @@ namespace pEp.UI.ViewModels
private ConfigFile _SelectedFile = null;
private FlowDocument _VisibleDiff = null;
private const string FILE_A_PREFIX = "---a";
private const string FILE_B_PREFIX = "+++b";
private const string FILE_A_PREFIX = "--- ";
private const string FILE_B_PREFIX = "+++ ";
#endregion
......@@ -330,6 +330,10 @@ namespace pEp.UI.ViewModels
/// <returns>The diff between the two files.</returns>
private string CreateDiff(string fileNameA, string fileNameB)
{
// Use UNIX file names
fileNameA = fileNameA.Replace('\\', '/');
fileNameB = fileNameB.Replace('\\', '/');
if (!(File.Exists(fileNameA) && File.Exists(fileNameB)))
{
Log.ErrorAndFailInDebugMode("CreateDiff: Input file doesn't exist.");
......@@ -412,7 +416,7 @@ namespace pEp.UI.ViewModels
break;
}
}
index++;
index = (index >= 0) ? index : 0;
newFileIndex = newLines[index].Position ?? 1;
oldFileIndex = oldLines[index].Position ?? 1;
}
......@@ -459,7 +463,7 @@ namespace pEp.UI.ViewModels
return null;
}
return diff.Insert(0, $"{ PatchDialogViewModel.FILE_A_PREFIX }/{ fileNameB }\n{ PatchDialogViewModel.FILE_B_PREFIX }/{ fileNameB }\n").TrimEnd('\n');
return diff.Insert(0, $"{ PatchDialogViewModel.FILE_A_PREFIX }{ fileNameB }\n{ PatchDialogViewModel.FILE_B_PREFIX }{ fileNameB }\n").TrimEnd('\n');
}
/// <summary>
......@@ -488,15 +492,20 @@ namespace pEp.UI.ViewModels
File.Copy(fileName, originalFileName, true);
}
// Open temp file in Notepad for the user to edit
// Open temp file for the user to edit
using (Process modifyFileProcess = Process.Start(new ProcessStartInfo
{
FileName = "Notepad.exe",
FileName = Globals.ThisAddIn.Settings.DPEEditorPath,
Arguments = fileName,
UseShellExecute = false,
CreateNoWindow = true
}))
{
while (!modifyFileProcess.HasExited)
{
System.Threading.Thread.Sleep(200);
}
modifyFileProcess.WaitForExit();
}
......@@ -529,21 +538,31 @@ namespace pEp.UI.ViewModels
/// <returns>The root URI</returns>
private string GetRootUri()
{
string rootUri = this.ConfigFiles.First()?.FileName;
string firstFileName = this.ConfigFiles.First()?.FileName;
if (string.IsNullOrEmpty(firstFileName))
{
Log.ErrorAndFailInDebugMode("GetRootUri: First file name is empty");
return null;
}
string rootUri = Directory.GetParent(firstFileName).FullName.Replace('\\', '/');
foreach (ConfigFile modifiedFile in this.ConfigFiles)
{
for (int i = 0; i < modifiedFile.FileName.Length; i++)
string folderName = Directory.GetParent(modifiedFile.FileName).FullName.Replace('\\', '/');
int i = 0;
while ((i < folderName.Length) &&
(i < rootUri.Length))
{
if ((rootUri.Length <= i) ||
(modifiedFile.FileName[i] == rootUri[i]))
if (folderName[i] != rootUri[i])
{
continue;
break;
}
rootUri = rootUri.Substring(0, i);
break;
i++;
}
rootUri = rootUri.Substring(0, i);
}
return rootUri;
......@@ -573,8 +592,8 @@ namespace pEp.UI.ViewModels
}
// Remove root parts of URI
diff = diff.Replace(PatchDialogViewModel.FILE_A_PREFIX + "/" + this.Dialog.Patch.Uri, PatchDialogViewModel.FILE_A_PREFIX + "/");
diff = diff.Replace(PatchDialogViewModel.FILE_B_PREFIX + "/" + this.Dialog.Patch.Uri, PatchDialogViewModel.FILE_B_PREFIX + "/");
diff = diff.Replace(PatchDialogViewModel.FILE_A_PREFIX + this.Dialog.Patch.Uri + "/", PatchDialogViewModel.FILE_A_PREFIX);
diff = diff.Replace(PatchDialogViewModel.FILE_B_PREFIX + this.Dialog.Patch.Uri + "/", PatchDialogViewModel.FILE_B_PREFIX);
return diff.TrimEnd('\n');
}
......@@ -605,8 +624,10 @@ namespace pEp.UI.ViewModels
/// <summary>
/// Formats the diff displaying colors of changes.
/// </summary>
/// <param name="diff">The diff to format.</param>
/// <param name="isOpen">Whether the patch is still open.</param>
/// <returns>The formatted diff or null if no diff is available.</returns>
public static FlowDocument FormatDiff(string diff)
public static FlowDocument FormatDiff(string diff, bool isOpen = true)
{
if (string.IsNullOrEmpty(diff))
{
......@@ -616,7 +637,7 @@ namespace pEp.UI.ViewModels
// Initialize the document with zero width to set the real width later
FlowDocument document = new FlowDocument
{
Background = Brushes.White,
Background = isOpen ? Brushes.White : Brushes.WhiteSmoke,
PageWidth = 0
};
......@@ -665,7 +686,7 @@ namespace pEp.UI.ViewModels
return document;
}
#endregion
}
}
......@@ -9,6 +9,7 @@
mc:Ignorable="d"
FontFamily="Segoe UI"
FontSize="12"
Background="{Binding Background}"
d:DataContext="{d:DesignInstance Type=vm:FormControlPatchViewModel}"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
......@@ -27,7 +28,7 @@
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
......@@ -41,19 +42,19 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Column="0"
Grid.Row="0"
Grid.ColumnSpan="2"
Grid.Row="0"
Content="{Binding Explanation}"
FontWeight="Bold"
Margin="10,5"/>
<Label Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="2"
Grid.Row="1"
Content="{Binding Submitter.DisplayString}"
Margin="10,1" />
<Label Grid.Column="0"
Grid.Row="2"
Grid.ColumnSpan="2"
Grid.Row="2"
Content="{Binding CreationDateString}"
Margin="10,1" />
<Image Grid.Column="2"
......@@ -84,11 +85,11 @@
<TextBox Grid.Column="1"
Grid.ColumnSpan="2"
Grid.Row="4"
Background="{Binding Background}"
VerticalAlignment="Center"
Padding="2"
Text="{Binding Uri}"
IsReadOnly="True"
MinWidth="400"
Margin="5,10,10,10"/>
<Label Grid.Column="0"
Grid.Row="5"
......@@ -97,11 +98,11 @@
<TextBox Grid.Column="1"
Grid.ColumnSpan="2"
Grid.Row="5"
Background="{Binding Background}"
VerticalAlignment="Center"
Padding="2"
Text="{Binding CommitMessage}"
IsReadOnly="True"
MinWidth="400"
Margin="5,10,10,10"/>
<Label Grid.Column="0"
Grid.Row="6"
......@@ -110,11 +111,11 @@
<TextBox Grid.Column="1"
Grid.ColumnSpan="2"
Grid.Row="6"
Background="{Binding Background}"
VerticalAlignment="Center"
Padding="2"
Text="{Binding Tag}"
IsReadOnly="True"
MinWidth="400"
Margin="5,10,10,10"/>
<StackPanel Grid.Column="0"
Grid.ColumnSpan="3"
......
......@@ -98,6 +98,7 @@
<Button Content="{Binding OKButtonText}"
Command="{Binding OKButtonCommand}"
IsEnabled="{Binding IsValid}"
IsDefault="True"
Margin="10"
Style="{StaticResource StyleButtonGray}"/>
<Button Content="{Binding CancelButtonText}"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment