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
Compare Revisions
6715b121b57ea26ac2a2e3b52b5695c7a544c854...5dc06dbb69ffc29c35aae6c945a345e3c803ea5f
Commits (7)
Allow for custom editors to modify patches and set background color if patch is not open anymore
· 820a7def
Thomas
authored
Sep 21, 2021
820a7def
Fix creation of diff
· f625045a
Thomas
authored
Sep 22, 2021
f625045a
Do not add the a/b prefix to diffs
· b58c6e33
Thomas
authored
Sep 22, 2021
b58c6e33
Renaming
· 2b3974db
Thomas
authored
Sep 22, 2021
2b3974db
Execute all API calls in background and catch errors
· c72ce70a
Thomas
authored
Sep 23, 2021
c72ce70a
Adjust algorithm to find patch mail item
· 78ac1768
Thomas
authored
Sep 27, 2021
78ac1768
Merge branch 'OUT-815' into OUT-789
· 5dc06dbb
Thomas
authored
Sep 27, 2021
5dc06dbb
Hide whitespace changes
Inline
Side-by-side
DPE/DPEWebClient.cs
View file @
5dc06dbb
using
pEp.Extensions
;
using
pEp.Extensions
;
using
System
;
using
System
;
using
System.Net
;
using
System.Net.Http
;
using
System.Net.Http
;
using
System.Threading.Tasks
;
namespace
pEp.DPE
namespace
pEp.DPE
{
{
internal
static
class
DPEWebClient
internal
static
class
DPEWebClient
{
{
private
static
readonly
HttpClient
httpClient
=
new
HttpClient
();
private
static
readonly
HttpClient
httpClient
=
new
HttpClient
();
private
static
readonly
string
dbePostUrl
=
Globals
.
ThisAddIn
.
Settings
.
DPEWebClientUrl
+
"patches/"
;
private
static
readonly
string
DPE_POST_URL
=
Globals
.
ThisAddIn
.
Settings
.
DPEWebClientUrl
+
"patches/"
;
public
static
readonly
string
REJECT_PATCH_SUFFIX
=
"/reject/"
;
public
const
string
REJECT_PATCH_SUFFIX
=
"/reject/"
;
public
static
readonly
string
SUPPORT_PATCH_SUFFIX
=
"/support/"
;
public
const
string
SUPPORT_PATCH_SUFFIX
=
"/support/"
;
/// <summary>
/// <summary>
/// Rejects a given patch.
/// Rejects a given patch.
/// </summary>
/// </summary>
/// <param name="patch">The patch to reject.</param>
/// <param name="patch">The patch to reject.</param>
/// <param name="me">The own identity that rejects the patch.</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
try
{
{
HttpResponseMessage
response
=
return
await
DPEWebClient
.
httpClient
.
PostAsync
(
DPEWebClient
.
DPE_POST_URL
,
await
DPEWebClient
.
httpClient
.
PostAsync
(
DPEWebClient
.
dbePostUrl
,
new
StringContent
(
patch
.
Id
+
DPEWebClient
.
REJECT_PATCH_SUFFIX
));
new
StringContent
(
patch
.
Id
+
DPEWebClient
.
REJECT_PATCH_SUFFIX
));
Log
.
Verbose
(
$"SuggestPatch: Patch
{
patch
.
Id
}
rejected. Return status is
{
Enum
.
GetName
(
typeof
(
HttpStatusCode
),
response
.
StatusCode
)
}
"
);
}
}
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
...
@@ -39,20 +46,26 @@ namespace pEp.DPE
/// </summary>
/// </summary>
/// <param name="patch">The patch to suggest.</param>
/// <param name="patch">The patch to suggest.</param>
/// <param name="me">The own identity that suggests the patch.</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/
// POST http://localhost:port/pEpDPE/patches/
string
xml
=
patch
.
Serialize
();
try
try
{
{
HttpResponseMessage
response
=
string
xml
=
patch
.
Serialize
();
await
DPEWebClient
.
httpClient
.
PostAsync
(
DPEWebClient
.
dbePostUrl
,
return
await
DPEWebClient
.
httpClient
.
PostAsync
(
DPEWebClient
.
DPE_POST_URL
,
new
StringContent
(
xml
));
new
StringContent
(
xml
));
}
Log
.
Verbose
(
$"SuggestPatch: New patch posted. Return status is
{
Enum
.
GetName
(
typeof
(
HttpStatusCode
),
response
.
StatusCode
)
}
"
);
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
...
@@ -61,19 +74,26 @@ namespace pEp.DPE
/// </summary>
/// </summary>
/// <param name="patch">The patch to support.</param>
/// <param name="patch">The patch to support.</param>
/// <param name="me">The own identity that supports the patch.</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
try
{
{
HttpResponseMessage
response
=
return
await
DPEWebClient
.
httpClient
.
PostAsync
(
DPEWebClient
.
DPE_POST_URL
,
await
DPEWebClient
.
httpClient
.
PostAsync
(
DPEWebClient
.
dbePostUrl
,
new
StringContent
(
patch
.
Id
+
DPEWebClient
.
SUPPORT_PATCH_SUFFIX
));
new
StringContent
(
patch
.
Id
+
DPEWebClient
.
SUPPORT_PATCH_SUFFIX
));
}
Log
.
Verbose
(
$"SuggestPatch: Patch
{
patch
.
Id
}
supported. Return status is
{
Enum
.
GetName
(
typeof
(
HttpStatusCode
),
response
.
StatusCode
)
}
"
);
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.DPE.Interfaces
;
using
pEp.Extensions
;
using
pEp.Extensions
;
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.IO
;
using
System.Linq
;
using
System.Linq
;
using
System.Net
;
using
System.Net.Http
;
using
System.Threading.Tasks
;
using
Outlook
=
Microsoft
.
Office
.
Interop
.
Outlook
;
using
Outlook
=
Microsoft
.
Office
.
Interop
.
Outlook
;
namespace
pEp.DPE
namespace
pEp.DPE
...
@@ -12,10 +14,24 @@ namespace pEp.DPE
...
@@ -12,10 +14,24 @@ namespace pEp.DPE
{
{
private
static
readonly
string
DPE_FOLDER
=
Path
.
Combine
(
Globals
.
PEPUserFolder
,
"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"
);
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"
;
private
const
string
PATCH_MESSAGE_SUBJECT
=
"Configuration changes"
;
public
const
string
DPE_MESSAGE_CLASS
=
"IPM.Note.DPE"
;
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
PEPIdentity
ownIdentity
;
private
readonly
PatchEvents
patchEvents
;
private
readonly
PatchEvents
patchEvents
;
...
@@ -30,7 +46,7 @@ namespace pEp.DPE
...
@@ -30,7 +46,7 @@ namespace pEp.DPE
}
}
#
region
Event
handlers
#
region
Event
handlers
/// <summary>
/// <summary>
/// Event handler for when a patch has been accepted.
/// Event handler for when a patch has been accepted.
/// </summary>
/// </summary>
...
@@ -58,6 +74,10 @@ namespace pEp.DPE
...
@@ -58,6 +74,10 @@ namespace pEp.DPE
ThisAddIn
.
PEPEngine
.
ShowNotification
(
"New patch suggested"
,
patch
.
CommitMessage
+
" "
+
patch
.
Diff
);
ThisAddIn
.
PEPEngine
.
ShowNotification
(
"New patch suggested"
,
patch
.
CommitMessage
+
" "
+
patch
.
Diff
);
}
}
#
endregion
#
region
Methods
/// <summary>
/// <summary>
/// Creates a mail item that shows a suggested patch.
/// Creates a mail item that shows a suggested patch.
/// </summary>
/// </summary>
...
@@ -90,7 +110,8 @@ namespace pEp.DPE
...
@@ -90,7 +110,8 @@ namespace pEp.DPE
{
MapiProperty
.
PidTagMessageDeliveryTime
,
DateTime
.
UtcNow
}
{
MapiProperty
.
PidTagMessageDeliveryTime
,
DateTime
.
UtcNow
}
});
});
omi
.
SetMessageFlag
(
MapiPropertyValue
.
EnumPidTagMessageFlags
.
mfUnsent
,
false
);
omi
.
SetMessageFlag
(
MapiPropertyValue
.
EnumPidTagMessageFlags
.
mfUnsent
,
false
);
omi
.
SetUserProperty
(
MailItemExtensions
.
USER_PROPERTY_KEY_DPE_PATCH_ID
,
patch
.
Id
);
// Move to inbox and set Received time
// Move to inbox and set Received time
mi
=
omi
.
Move
(
Globals
.
ThisAddIn
.
Application
.
Session
.
GetDefaultFolder
(
Outlook
.
OlDefaultFolders
.
olFolderInbox
));
mi
=
omi
.
Move
(
Globals
.
ThisAddIn
.
Application
.
Session
.
GetDefaultFolder
(
Outlook
.
OlDefaultFolders
.
olFolderInbox
));
mi
.
Save
();
mi
.
Save
();
...
@@ -106,10 +127,6 @@ namespace pEp.DPE
...
@@ -106,10 +127,6 @@ namespace pEp.DPE
}
}
}
}
#
endregion
#
region
Methods
/// <summary>
/// <summary>
/// Disposes of all resources.
/// Disposes of all resources.
/// </summary>
/// </summary>
...
@@ -119,17 +136,161 @@ namespace pEp.DPE
...
@@ -119,17 +136,161 @@ namespace pEp.DPE
this
.
patchEvents
.
Dispose
();
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>
/// <summary>
/// Rejects a given patch.
/// Rejects a given patch.
/// </summary>
/// </summary>
/// <param name="patch">The patch to reject.</param>
/// <param name="patch">The patch to reject.</param>
/// <param name="me">The own identity that rejects the patch.</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
);
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>
/// <summary>
/// Subscribes to the given patch events.
/// Subscribes to the given patch events.
/// </summary>
/// </summary>
...
@@ -146,9 +307,13 @@ namespace pEp.DPE
...
@@ -146,9 +307,13 @@ namespace pEp.DPE
/// </summary>
/// </summary>
/// <param name="patch">The patch to suggest.</param>
/// <param name="patch">The patch to suggest.</param>
/// <param name="me">The own identity that suggests the patch.</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
);
AdapterExtensions
.
ShowNotification
(
"Patch suggested"
,
patch
.
CommitMessage
);
}
}
...
@@ -157,9 +322,14 @@ namespace pEp.DPE
...
@@ -157,9 +322,14 @@ namespace pEp.DPE
/// </summary>
/// </summary>
/// <param name="patch">The patch to support.</param>
/// <param name="patch">The patch to support.</param>
/// <param name="me">The own identity that supports the patch.</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
);
AdapterExtensions
.
ShowNotification
(
"Patch supported"
,
patch
.
CommitMessage
);
}
}
...
...
DPE/Interfaces/IDistributedPolicyEngine.cs
View file @
5dc06dbb
using
System
;
using
System
;
using
System.Threading.Tasks
;
namespace
pEp.DPE.Interfaces
namespace
pEp.DPE.Interfaces
{
{
...
@@ -6,8 +7,8 @@ namespace pEp.DPE.Interfaces
...
@@ -6,8 +7,8 @@ namespace pEp.DPE.Interfaces
{
{
void
Subscribe
(
PatchEvents
patchEvents
);
void
Subscribe
(
PatchEvents
patchEvents
);
void
Unsubscribe
(
PatchEvents
patchEvents
);
void
Unsubscribe
(
PatchEvents
patchEvents
);
void
Suggest
(
Patch
patch
,
PEPIdentity
me
);
Task
Suggest
(
Patch
patch
,
PEPIdentity
me
);
void
Support
(
Patch
patch
,
PEPIdentity
me
);
Task
Support
(
Patch
patch
,
PEPIdentity
me
);
void
Reject
(
Patch
patch
,
PEPIdentity
me
);
Task
Reject
(
Patch
patch
,
PEPIdentity
me
);
}
}
}
}
Extensions/MailItemExtensions.cs
View file @
5dc06dbb
...
@@ -19,6 +19,7 @@ namespace pEp
...
@@ -19,6 +19,7 @@ namespace pEp
{
{
public
const
string
USER_PROPERTY_KEY_DPE_PATCH_STATUS
=
"patchStatus"
;
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_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_INSPECTOR_CLOSED
=
"inspectorClosed"
;
public
const
string
USER_PROPERTY_KEY_IS_INCOMING
=
"isIncoming"
;
public
const
string
USER_PROPERTY_KEY_IS_INCOMING
=
"isIncoming"
;
public
const
string
USER_PROPERTY_KEY_IS_MIRROR
=
"isMirror"
;
public
const
string
USER_PROPERTY_KEY_IS_MIRROR
=
"isMirror"
;
...
...
PEPSettings.cs
View file @
5dc06dbb
...
@@ -62,8 +62,9 @@ namespace pEp
...
@@ -62,8 +62,9 @@ namespace pEp
public
const
string
CULTURE_CODE_DEFAULT
=
"en"
;
public
const
string
CULTURE_CODE_DEFAULT
=
"en"
;
public
const
bool
DELETE_MIRROR_MESSAGES_DEFAULT
=
false
;
public
const
bool
DELETE_MIRROR_MESSAGES_DEFAULT
=
false
;
public
const
string
DISCLAIMER_TEXT_DEFAULT
=
null
;
public
const
string
DISCLAIMER_TEXT_DEFAULT
=
null
;
public
static
readonly
string
DPE_WEB_CLIENT_URL_DEFAULT
=
"http://localhost:30457/pEpDPE/"
;
public
const
string
DPE_EDITOR_PATH_DEFAULT
=
"Notepad.exe"
;
public
static
readonly
string
DPE_WEB_SERVER_URL_DEFAULT
=
"http://localhost:30456/pEpDPE/"
;
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
ENABLE_NATIVE_METHODS_DEFAULT
=
true
;
public
const
bool
ENCRYPT_ACCOUNTS_BY_DEFAULT
=
true
;
public
const
bool
ENCRYPT_ACCOUNTS_BY_DEFAULT
=
true
;
public
const
bool
HIDE_INTERNAL_MESSAGES_DEFAULT
=
true
;
public
const
bool
HIDE_INTERNAL_MESSAGES_DEFAULT
=
true
;
...
@@ -172,6 +173,12 @@ namespace pEp
...
@@ -172,6 +173,12 @@ namespace pEp
/// </summary>
/// </summary>
public
bool
DeleteMirrorMessages
{
get
;
private
set
;
}
=
PEPSettings
.
DELETE_MIRROR_MESSAGES_DEFAULT
;
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>
/// <summary>
/// Gets the URL of the DPE Web client.
/// Gets the URL of the DPE Web client.
/// </summary>
/// </summary>
...
...
UI/FormRegionDPE.cs
View file @
5dc06dbb
using
pEp.DPE
;
using
pEp.DPE
;
using
pEp.UI.ViewModels
;
using
pEp.UI.ViewModels
;
using
System
;
using
System
;
using
System.ComponentModel
;
using
Outlook
=
Microsoft
.
Office
.
Interop
.
Outlook
;
using
Outlook
=
Microsoft
.
Office
.
Interop
.
Outlook
;
namespace
pEp
namespace
pEp
...
@@ -36,12 +35,12 @@ namespace pEp
...
@@ -36,12 +35,12 @@ namespace pEp
string
xml
=
omi
.
HTMLBody
;
string
xml
=
omi
.
HTMLBody
;
Patch
patch
=
Patch
.
Deserialize
(
xml
);
Patch
patch
=
Patch
.
Deserialize
(
xml
);
FormControlPatchViewModel
.
PatchStatus
patchStatus
=
FormControlPatchViewModel
.
PatchStatus
.
Open
;
DistributedPolicyEngine
.
PatchStatus
patchStatus
=
DistributedPolicyEngine
.
PatchStatus
.
Open
;
DateTime
?
editDate
=
null
;
DateTime
?
editDate
=
null
;
// Get patch status if available
// Get patch status if available
if
((
omi
.
GetUserProperty
(
MailItemExtensions
.
USER_PROPERTY_KEY_DPE_PATCH_STATUS
,
FormControlPatchViewModel
.
PatchStatus
.
Open
)
is
string
patchStatusString
)
&&
if
((
omi
.
GetUserProperty
(
MailItemExtensions
.
USER_PROPERTY_KEY_DPE_PATCH_STATUS
,
DistributedPolicyEngine
.
PatchStatus
.
Open
)
is
string
patchStatusString
)
&&
Enum
.
TryParse
(
patchStatusString
,
out
FormControlPatchViewModel
.
PatchStatus
status
))
Enum
.
TryParse
(
patchStatusString
,
out
DistributedPolicyEngine
.
PatchStatus
status
))
{
{
patchStatus
=
status
;
patchStatus
=
status
;
}
}
...
@@ -53,16 +52,10 @@ namespace pEp
...
@@ -53,16 +52,10 @@ namespace pEp
editDate
=
savedEditDate
;
editDate
=
savedEditDate
;
}
}
// Get the patch submitter
// Get the patch submitter
and set data context
if
(
PEPIdentity
.
GetFromIdentity
(
omi
,
out
PEPIdentity
submitter
)
==
Globals
.
ReturnStatus
.
Success
)
if
(
PEPIdentity
.
GetFromIdentity
(
omi
,
out
PEPIdentity
submitter
)
==
Globals
.
ReturnStatus
.
Success
)
{
{
this
.
FormControlPatchView
.
DataContext
=
new
FormControlPatchViewModel
(
patch
,
submitter
,
patchStatus
,
editDate
);
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
else
{
{
...
@@ -79,55 +72,11 @@ namespace pEp
...
@@ -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.
// Occurs when the form region is closed.
// Use this.OutlookItem to get a reference to the current Outlook item.
// Use this.OutlookItem to get a reference to the current Outlook item.
// Use this.OutlookFormRegion to get a reference to the form region.
// Use this.OutlookFormRegion to get a reference to the form region.
private
void
FormRegionDPE_FormRegionClosed
(
object
sender
,
EventArgs
e
)
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.DPE
;
using
pEp.UI.Models
;
using
System
;
using
System
;
using
System.Threading.Tasks
;
using
System.Windows
;
using
System.Windows.Documents
;
using
System.Windows.Documents
;
using
System.Windows.Media
;
namespace
pEp.UI.ViewModels
namespace
pEp.UI.ViewModels
{
{
internal
class
FormControlPatchViewModel
:
ViewModelBase
internal
class
FormControlPatchViewModel
:
ViewModelBase
{
{
public
enum
PatchStatus
{
Open
,
Accepted
,
Supported
,
Rejected
}
#
region
Fields
#
region
Fields
private
readonly
Patch
patch
;
private
readonly
Patch
patch
;
private
PatchStatus
_Status
=
PatchStatus
.
Open
;
private
Brush
_Background
=
Brushes
.
White
;
private
DateTime
?
_EditDate
=
null
;
private
FlowDocument
_DisplayDiff
=
null
;
private
string
_Explanation
=
null
;
private
DateTime
?
_EditDate
=
null
;
private
string
_Explanation
=
null
;
private
DistributedPolicyEngine
.
PatchStatus
_Status
=
DistributedPolicyEngine
.
PatchStatus
.
Open
;
#
endregion
#
endregion
#
region
Properties
#
region
Properties
/// <summary>
/// Gets or sets the background.
/// </summary>
public
Brush
Background
{
get
=>
this
.
_Background
;
set
=>
this
.
SetProperty
(
ref
this
.
_Background
,
value
);
}
/// <summary>
/// <summary>
/// The commit message of the patch.
/// The commit message of the patch.
/// </summary>
/// </summary>
...
@@ -58,9 +61,9 @@ namespace pEp.UI.ViewModels
...
@@ -58,9 +61,9 @@ namespace pEp.UI.ViewModels
}
}
/// <summary>
/// <summary>
/// Gets the diff of this patch as formatted flow document.
/// Gets
or sets
the diff of this patch as formatted flow document.
/// </summary>
/// </summary>
public
FlowDocument
DisplayDiff
=>
PatchDialogViewModel
.
FormatDiff
(
this
.
Diff
);
public
FlowDocument
DisplayDiff
{
get
=>
this
.
_DisplayDiff
;
set
=>
this
.
SetProperty
(
ref
this
.
_DisplayDiff
,
value
);
}
/// <summary>
/// <summary>
/// Gets or sets the last date the patch was edited.
/// Gets or sets the last date the patch was edited.
...
@@ -85,7 +88,7 @@ namespace pEp.UI.ViewModels
...
@@ -85,7 +88,7 @@ namespace pEp.UI.ViewModels
/// <summary>
/// <summary>
/// The command to accept the patch dialog.
/// The command to accept the patch dialog.
/// </summary>
/// </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>
/// <summary>
/// Gets the OK button text.
/// Gets the OK button text.
...
@@ -95,7 +98,7 @@ namespace pEp.UI.ViewModels
...
@@ -95,7 +98,7 @@ namespace pEp.UI.ViewModels
/// <summary>
/// <summary>
/// The command to reject the dialog.
/// The command to reject the dialog.
/// </summary>
/// </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>
/// <summary>
/// Gets the Reject button text.
/// Gets the Reject button text.
...
@@ -110,7 +113,7 @@ namespace pEp.UI.ViewModels
...
@@ -110,7 +113,7 @@ namespace pEp.UI.ViewModels
/// <summary>
/// <summary>
/// Gets or sets the status of this patch.
/// Gets or sets the status of this patch.
/// </summary>
/// </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>
/// <summary>
/// Gets or sets the tag of the patch.
/// Gets or sets the tag of the patch.
...
@@ -149,15 +152,14 @@ namespace pEp.UI.ViewModels
...
@@ -149,15 +152,14 @@ namespace pEp.UI.ViewModels
/// <param name="submitter">The submitter of the patch.</param>
/// <param name="submitter">The submitter of the patch.</param>
/// <param name="status">The status 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>
/// <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
.
EditDate
=
editDate
;
this
.
patch
=
patch
;
this
.
patch
=
patch
;
this
.
Submitter
=
submitter
;
this
.
Submitter
=
submitter
;
this
.
Status
=
status
;
this
.
IsRejectButtonVisible
=
true
;
this
.
IsRejectButtonVisible
=
true
;
this
.
OKButtonText
=
"Support"
;
this
.
OKButtonText
=
"Support"
;
this
.
SetExplanation
(
);
this
.
UpdateView
(
status
);
}
}
#
endregion
#
endregion
...
@@ -168,12 +170,24 @@ namespace pEp.UI.ViewModels
...
@@ -168,12 +170,24 @@ namespace pEp.UI.ViewModels
/// Rejects this patch.
/// Rejects this patch.
/// </summary>
/// </summary>
/// <param name="parameter">The command parameter.</param>
/// <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
());
try
this
.
Status
=
PatchStatus
.
Rejected
;
{
this
.
EditDate
=
DateTime
.
UtcNow
;
await
Globals
.
ThisAddIn
.
DistributedPolicyEngine
.
Reject
(
this
.
patch
,
new
PEPIdentity
());
this
.
SetExplanation
();
}
catch
(
Exception
ex
)
{
while
(
ex
.
InnerException
!=
null
)
{
ex
=
ex
.
InnerException
;
}
CustomMessageBox
.
ShowDialog
(
ex
.
Message
,
"Error"
,
"OK"
);
return
;
}
this
.
UpdateView
(
DistributedPolicyEngine
.
PatchStatus
.
Rejected
);
}
}
/// <summary>
/// <summary>
...
@@ -189,16 +203,16 @@ namespace pEp.UI.ViewModels
...
@@ -189,16 +203,16 @@ namespace pEp.UI.ViewModels
switch
(
this
.
Status
)
switch
(
this
.
Status
)
{
{
case
PatchStatus
.
Accepted
:
case
DistributedPolicyEngine
.
PatchStatus
.
Accepted
:
this
.
Explanation
=
$"Accepted on
{
editDate
}
"
;
this
.
Explanation
=
$"Accepted on
{
editDate
}
"
;
break
;
break
;
case
PatchStatus
.
Supported
:
case
DistributedPolicyEngine
.
PatchStatus
.
Supported
:
this
.
Explanation
=
$"Supported on
{
editDate
}
"
;
this
.
Explanation
=
$"Supported on
{
editDate
}
"
;
break
;
break
;
case
PatchStatus
.
Rejected
:
case
DistributedPolicyEngine
.
PatchStatus
.
Rejected
:
this
.
Explanation
=
$"Rejected on
{
editDate
}
"
;
this
.
Explanation
=
$"Rejected on
{
editDate
}
"
;
break
;
break
;
case
PatchStatus
.
Open
:
case
DistributedPolicyEngine
.
PatchStatus
.
Open
:
default
:
default
:
this
.
Explanation
=
"New configuration changes pending approval"
;
this
.
Explanation
=
"New configuration changes pending approval"
;
break
;
break
;
...
@@ -209,12 +223,39 @@ namespace pEp.UI.ViewModels
...
@@ -209,12 +223,39 @@ namespace pEp.UI.ViewModels
/// Supports this patch.
/// Supports this patch.
/// </summary>
/// </summary>
/// <param name="parameter">The command parameter.</param>
/// <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
;
this
.
Status
=
PatchStatus
.
Supported
;
this
.
EditDate
=
DateTime
.
UtcNow
;
this
.
EditDate
=
DateTime
.
UtcNow
;
this
.
SetExplanation
();
this
.
SetExplanation
();
this
.
DisplayDiff
=
PatchDialogViewModel
.
FormatDiff
(
this
.
Diff
,
this
.
Status
==
DistributedPolicyEngine
.
PatchStatus
.
Open
);
this
.
Background
=
(
patchStatus
==
DistributedPolicyEngine
.
PatchStatus
.
Open
)
?
Brushes
.
White
:
Brushes
.
WhiteSmoke
;
}
}
#
endregion
#
endregion
...
...
UI/ViewModels/PatchDialogViewModel.cs
View file @
5dc06dbb
...
@@ -27,8 +27,8 @@ namespace pEp.UI.ViewModels
...
@@ -27,8 +27,8 @@ namespace pEp.UI.ViewModels
private
ConfigFile
_SelectedFile
=
null
;
private
ConfigFile
_SelectedFile
=
null
;
private
FlowDocument
_VisibleDiff
=
null
;
private
FlowDocument
_VisibleDiff
=
null
;
private
const
string
FILE_A_PREFIX
=
"---
a
"
;
private
const
string
FILE_A_PREFIX
=
"---
"
;
private
const
string
FILE_B_PREFIX
=
"+++
b
"
;
private
const
string
FILE_B_PREFIX
=
"+++
"
;
#
endregion
#
endregion
...
@@ -330,6 +330,10 @@ namespace pEp.UI.ViewModels
...
@@ -330,6 +330,10 @@ namespace pEp.UI.ViewModels
/// <returns>The diff between the two files.</returns>
/// <returns>The diff between the two files.</returns>
private
string
CreateDiff
(
string
fileNameA
,
string
fileNameB
)
private
string
CreateDiff
(
string
fileNameA
,
string
fileNameB
)
{
{
// Use UNIX file names
fileNameA
=
fileNameA
.
Replace
(
'\\'
,
'/'
);
fileNameB
=
fileNameB
.
Replace
(
'\\'
,
'/'
);
if
(!(
File
.
Exists
(
fileNameA
)
&&
File
.
Exists
(
fileNameB
)))
if
(!(
File
.
Exists
(
fileNameA
)
&&
File
.
Exists
(
fileNameB
)))
{
{
Log
.
ErrorAndFailInDebugMode
(
"CreateDiff: Input file doesn't exist."
);
Log
.
ErrorAndFailInDebugMode
(
"CreateDiff: Input file doesn't exist."
);
...
@@ -412,7 +416,7 @@ namespace pEp.UI.ViewModels
...
@@ -412,7 +416,7 @@ namespace pEp.UI.ViewModels
break
;
break
;
}
}
}
}
index
++
;
index
=
(
index
>=
0
)
?
index
:
0
;
newFileIndex
=
newLines
[
index
].
Position
??
1
;
newFileIndex
=
newLines
[
index
].
Position
??
1
;
oldFileIndex
=
oldLines
[
index
].
Position
??
1
;
oldFileIndex
=
oldLines
[
index
].
Position
??
1
;
}
}
...
@@ -459,7 +463,7 @@ namespace pEp.UI.ViewModels
...
@@ -459,7 +463,7 @@ namespace pEp.UI.ViewModels
return
null
;
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>
/// <summary>
...
@@ -488,15 +492,20 @@ namespace pEp.UI.ViewModels
...
@@ -488,15 +492,20 @@ namespace pEp.UI.ViewModels
File
.
Copy
(
fileName
,
originalFileName
,
true
);
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
using
(
Process
modifyFileProcess
=
Process
.
Start
(
new
ProcessStartInfo
{
{
FileName
=
"Notepad.exe"
,
FileName
=
Globals
.
ThisAddIn
.
Settings
.
DPEEditorPath
,
Arguments
=
fileName
,
Arguments
=
fileName
,
UseShellExecute
=
false
,
UseShellExecute
=
false
,
CreateNoWindow
=
true
CreateNoWindow
=
true
}))
}))
{
{
while
(!
modifyFileProcess
.
HasExited
)
{
System
.
Threading
.
Thread
.
Sleep
(
200
);
}
modifyFileProcess
.
WaitForExit
();
modifyFileProcess
.
WaitForExit
();
}
}
...
@@ -529,21 +538,31 @@ namespace pEp.UI.ViewModels
...
@@ -529,21 +538,31 @@ namespace pEp.UI.ViewModels
/// <returns>The root URI</returns>
/// <returns>The root URI</returns>
private
string
GetRootUri
()
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
)
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
)
||
if
(
folderName
[
i
]
!=
rootUri
[
i
])
(
modifiedFile
.
FileName
[
i
]
==
rootUri
[
i
]))
{
{
continue
;
break
;
}
}
rootUri
=
rootUri
.
Substring
(
0
,
i
);
i
++;
break
;
}
}
rootUri
=
rootUri
.
Substring
(
0
,
i
);
}
}
return
rootUri
;
return
rootUri
;
...
@@ -573,8 +592,8 @@ namespace pEp.UI.ViewModels
...
@@ -573,8 +592,8 @@ namespace pEp.UI.ViewModels
}
}
// Remove root parts of URI
// 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_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_B_PREFIX
+
this
.
Dialog
.
Patch
.
Uri
+
"/"
,
PatchDialogViewModel
.
FILE_B_PREFIX
);
return
diff
.
TrimEnd
(
'\n'
);
return
diff
.
TrimEnd
(
'\n'
);
}
}
...
@@ -605,8 +624,10 @@ namespace pEp.UI.ViewModels
...
@@ -605,8 +624,10 @@ namespace pEp.UI.ViewModels
/// <summary>
/// <summary>
/// Formats the diff displaying colors of changes.
/// Formats the diff displaying colors of changes.
/// </summary>
/// </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>
/// <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
))
if
(
string
.
IsNullOrEmpty
(
diff
))
{
{
...
@@ -616,7 +637,7 @@ namespace pEp.UI.ViewModels
...
@@ -616,7 +637,7 @@ namespace pEp.UI.ViewModels
// Initialize the document with zero width to set the real width later
// Initialize the document with zero width to set the real width later
FlowDocument
document
=
new
FlowDocument
FlowDocument
document
=
new
FlowDocument
{
{
Background
=
Brushes
.
White
,
Background
=
isOpen
?
Brushes
.
White
:
Brushes
.
WhiteSmoke
,
PageWidth
=
0
PageWidth
=
0
};
};
...
@@ -665,7 +686,7 @@ namespace pEp.UI.ViewModels
...
@@ -665,7 +686,7 @@ namespace pEp.UI.ViewModels
return
document
;
return
document
;
}
}
#
endregion
#
endregion
}
}
}
}
UI/Views/FormControlPatchView.xaml
View file @
5dc06dbb
...
@@ -9,6 +9,7 @@
...
@@ -9,6 +9,7 @@
mc:Ignorable="d"
mc:Ignorable="d"
FontFamily="Segoe UI"
FontFamily="Segoe UI"
FontSize="12"
FontSize="12"
Background="{Binding Background}"
d:DataContext="{d:DesignInstance Type=vm:FormControlPatchViewModel}"
d:DataContext="{d:DesignInstance Type=vm:FormControlPatchViewModel}"
d:DesignHeight="450" d:DesignWidth="800">
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<UserControl.Resources>
...
@@ -27,7 +28,7 @@
...
@@ -27,7 +28,7 @@
<Grid>
<Grid>
<Grid.ColumnDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="
Auto
" />
<ColumnDefinition Width="
*
" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<Grid.RowDefinitions>
...
@@ -41,19 +42,19 @@
...
@@ -41,19 +42,19 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
</Grid.RowDefinitions>
<Label Grid.Column="0"
<Label Grid.Column="0"
Grid.Row="0"
Grid.ColumnSpan="2"
Grid.ColumnSpan="2"
Grid.Row="0"
Content="{Binding Explanation}"
Content="{Binding Explanation}"
FontWeight="Bold"
FontWeight="Bold"
Margin="10,5"/>
Margin="10,5"/>
<Label Grid.Column="0"
<Label Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="2"
Grid.ColumnSpan="2"
Grid.Row="1"
Content="{Binding Submitter.DisplayString}"
Content="{Binding Submitter.DisplayString}"
Margin="10,1" />
Margin="10,1" />
<Label Grid.Column="0"
<Label Grid.Column="0"
Grid.Row="2"
Grid.ColumnSpan="2"
Grid.ColumnSpan="2"
Grid.Row="2"
Content="{Binding CreationDateString}"
Content="{Binding CreationDateString}"
Margin="10,1" />
Margin="10,1" />
<Image Grid.Column="2"
<Image Grid.Column="2"
...
@@ -84,11 +85,11 @@
...
@@ -84,11 +85,11 @@
<TextBox Grid.Column="1"
<TextBox Grid.Column="1"
Grid.ColumnSpan="2"
Grid.ColumnSpan="2"
Grid.Row="4"
Grid.Row="4"
Background="{Binding Background}"
VerticalAlignment="Center"
VerticalAlignment="Center"
Padding="2"
Padding="2"
Text="{Binding Uri}"
Text="{Binding Uri}"
IsReadOnly="True"
IsReadOnly="True"
MinWidth="400"
Margin="5,10,10,10"/>
Margin="5,10,10,10"/>
<Label Grid.Column="0"
<Label Grid.Column="0"
Grid.Row="5"
Grid.Row="5"
...
@@ -97,11 +98,11 @@
...
@@ -97,11 +98,11 @@
<TextBox Grid.Column="1"
<TextBox Grid.Column="1"
Grid.ColumnSpan="2"
Grid.ColumnSpan="2"
Grid.Row="5"
Grid.Row="5"
Background="{Binding Background}"
VerticalAlignment="Center"
VerticalAlignment="Center"
Padding="2"
Padding="2"
Text="{Binding CommitMessage}"
Text="{Binding CommitMessage}"
IsReadOnly="True"
IsReadOnly="True"
MinWidth="400"
Margin="5,10,10,10"/>
Margin="5,10,10,10"/>
<Label Grid.Column="0"
<Label Grid.Column="0"
Grid.Row="6"
Grid.Row="6"
...
@@ -110,11 +111,11 @@
...
@@ -110,11 +111,11 @@
<TextBox Grid.Column="1"
<TextBox Grid.Column="1"
Grid.ColumnSpan="2"
Grid.ColumnSpan="2"
Grid.Row="6"
Grid.Row="6"
Background="{Binding Background}"
VerticalAlignment="Center"
VerticalAlignment="Center"
Padding="2"
Padding="2"
Text="{Binding Tag}"
Text="{Binding Tag}"
IsReadOnly="True"
IsReadOnly="True"
MinWidth="400"
Margin="5,10,10,10"/>
Margin="5,10,10,10"/>
<StackPanel Grid.Column="0"
<StackPanel Grid.Column="0"
Grid.ColumnSpan="3"
Grid.ColumnSpan="3"
...
...
UI/Views/PatchDialogView.xaml
View file @
5dc06dbb
...
@@ -98,6 +98,7 @@
...
@@ -98,6 +98,7 @@
<Button Content="{Binding OKButtonText}"
<Button Content="{Binding OKButtonText}"
Command="{Binding OKButtonCommand}"
Command="{Binding OKButtonCommand}"
IsEnabled="{Binding IsValid}"
IsEnabled="{Binding IsValid}"
IsDefault="True"
Margin="10"
Margin="10"
Style="{StaticResource StyleButtonGray}"/>
Style="{StaticResource StyleButtonGray}"/>
<Button Content="{Binding CancelButtonText}"
<Button Content="{Binding CancelButtonText}"
...
...