Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Windows
pEp for Outlook
Commits
5dc06dbb
Commit
5dc06dbb
authored
Sep 27, 2021
by
Thomas
Browse files
Merge branch 'OUT-815' into OUT-789
parents
6715b121
78ac1768
Changes
10
Hide whitespace changes
Inline
Side-by-side
DPE/DPEWebClient.cs
View file @
5dc06dbb
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
(
ArgumentNull
Exception
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
(
HttpRequest
Exception
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
(
HttpRequest
Exception
ex
)
{
Log
.
Error
(
"SupportPatch: Error supporting patch. "
+
ex
.
ToString
());
Log
.
Error
(
"SupportPatch: Error supporting patch. "
+
ex
);
throw
ex
;
}
}
}
...
...
DPE/DistributedPolicyEngine.cs
View file @
5dc06dbb
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
);
}
...
...
DPE/Interfaces/IDistributedPolicyEngine.cs
View file @
5dc06dbb
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
);
}
}
Extensions/MailItemExtensions.cs
View file @
5dc06dbb
...
...
@@ -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"
;
...
...
PEPSettings.cs
View file @
5dc06dbb
...
...
@@ -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>
...
...
UI/FormRegionDPE.cs
View file @
5dc06dbb
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
;
}
}
}
}
UI/ViewModels/FormControlPatchViewModel.cs
View file @
5dc06dbb
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
...
...
UI/ViewModels/PatchDialogViewModel.cs
View file @
5dc06dbb
...
...
@@ -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
}
}
UI/Views/FormControlPatchView.xaml
View file @
5dc06dbb
...
...
@@ -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"
...
...
UI/Views/PatchDialogView.xaml
View file @
5dc06dbb
...
...
@@ -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}"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment