feature: user contact details
This commit is contained in:
@@ -146,6 +146,8 @@
|
|||||||
<Compile Include="Services\Messaging\Email.cs" />
|
<Compile Include="Services\Messaging\Email.cs" />
|
||||||
<Compile Include="Services\Messaging\EmailAttachment.cs" />
|
<Compile Include="Services\Messaging\EmailAttachment.cs" />
|
||||||
<Compile Include="Services\Plugins\Details\DetailsResult.cs" />
|
<Compile Include="Services\Plugins\Details\DetailsResult.cs" />
|
||||||
|
<Compile Include="Services\Users\Contact\UserContact.cs" />
|
||||||
|
<Compile Include="Services\Users\Contact\UserContactType.cs" />
|
||||||
<Compile Include="Services\Searching\DeviceSearchResultItem.cs" />
|
<Compile Include="Services\Searching\DeviceSearchResultItem.cs" />
|
||||||
<Compile Include="Services\Searching\ISearchResultItem.cs" />
|
<Compile Include="Services\Searching\ISearchResultItem.cs" />
|
||||||
<Compile Include="Services\Searching\JobSearchResultItem.cs" />
|
<Compile Include="Services\Searching\JobSearchResultItem.cs" />
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Disco.Models.Services.Messaging
|
namespace Disco.Models.Services.Messaging
|
||||||
{
|
{
|
||||||
@@ -27,5 +29,10 @@ namespace Disco.Models.Services.Messaging
|
|||||||
Subject = subject;
|
Subject = subject;
|
||||||
Body = body;
|
Body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<string> ParseEmailAddresses(string emailAddresses)
|
||||||
|
{
|
||||||
|
return emailAddresses.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
using Disco.Models.Repository;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Disco.Models.Services.Users.Contact
|
||||||
|
{
|
||||||
|
public abstract class UserContact
|
||||||
|
{
|
||||||
|
public User User { get; }
|
||||||
|
public UserContactType ContactType { get; }
|
||||||
|
public string Source { get; }
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public abstract string Value { get; }
|
||||||
|
|
||||||
|
public UserContact(User user, UserContactType contactType, string source, string name)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
ContactType = contactType;
|
||||||
|
Source = source;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static bool TryParse<T>(User user, string source, Regex validator, string value, Func<User, string, string, string, T> generator, out T instance) where T : UserContact
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
instance = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var match = validator.Match(value);
|
||||||
|
|
||||||
|
if (!match.Success)
|
||||||
|
{
|
||||||
|
instance = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = match.Value;
|
||||||
|
var name = default(string);
|
||||||
|
if (match.Index > 0)
|
||||||
|
{
|
||||||
|
name = value.Substring(0, match.Index).Trim();
|
||||||
|
if (name.Length > 0)
|
||||||
|
{
|
||||||
|
switch (name.Last())
|
||||||
|
{
|
||||||
|
case '<':
|
||||||
|
case '[':
|
||||||
|
case '(':
|
||||||
|
case '{':
|
||||||
|
case '-':
|
||||||
|
name = name.Substring(0, name.Length - 1).Trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (name.Length == 0)
|
||||||
|
name = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance = generator(user, source, name, result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(Name))
|
||||||
|
{
|
||||||
|
return $"{Name} <{Value}>";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class UserContactEmail : UserContact
|
||||||
|
{
|
||||||
|
private static Regex validator = new Regex(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
|
public string EmailAddress { get; }
|
||||||
|
public override string Value => EmailAddress;
|
||||||
|
|
||||||
|
public UserContactEmail(User user, string source, string name, string emailAddress)
|
||||||
|
: base(user, UserContactType.Email, source, name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(emailAddress))
|
||||||
|
throw new ArgumentNullException(nameof(emailAddress));
|
||||||
|
|
||||||
|
EmailAddress = emailAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryParse(User user, string source, string value, out UserContactEmail contact) =>
|
||||||
|
TryParse(user, source, validator, value,
|
||||||
|
(u, s, name, emailAddress) => new UserContactEmail(u, s, name, emailAddress),
|
||||||
|
out contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class UserContactAustralianPhone : UserContact
|
||||||
|
{
|
||||||
|
private static Regex validator = new Regex(@"(?:\+?61\s*[0-9][ \-\.]*?|0[0-9][ \-\.]*?|[(\[]\s*0[0-9]\s*[)\]])\s*(?:[0-9][ \-\.]*?){8}(?=\s*[>\]})\-]?\s*$)", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
public string PhoneNumber { get; }
|
||||||
|
public override string Value => PhoneNumber;
|
||||||
|
|
||||||
|
public UserContactAustralianPhone(User user, string source, string name, string phoneNumber)
|
||||||
|
: base(user, UserContactType.Phone, source, name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(phoneNumber))
|
||||||
|
throw new ArgumentNullException(nameof(phoneNumber));
|
||||||
|
|
||||||
|
PhoneNumber = phoneNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryParse(User user, string source, string value, out UserContactAustralianPhone contact) =>
|
||||||
|
TryParse(user, source, validator, value,
|
||||||
|
(u, s, name, phoneNumber) => new UserContactAustralianPhone(u, s, name, phoneNumber),
|
||||||
|
out contact);
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(Name))
|
||||||
|
return $"{Name} <{PhoneNumber}>";
|
||||||
|
else
|
||||||
|
return PhoneNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class UserContactAustralianMobile : UserContact
|
||||||
|
{
|
||||||
|
private static Regex validator = new Regex(@"(?:\+?61\s*4[ \-\.]*?|04[ \-\.]*?|[(\[]\s*04\s*[)\]])\s*(?:[0-9][ \-\.]*?){8}(?=\s*[>\]})\-]?\s*$)", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
public string PhoneNumber { get; }
|
||||||
|
public override string Value => PhoneNumber;
|
||||||
|
|
||||||
|
public UserContactAustralianMobile(User user, string source, string name, string phoneNumber)
|
||||||
|
: base(user, UserContactType.MobilePhone, source, name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(phoneNumber))
|
||||||
|
throw new ArgumentNullException(nameof(phoneNumber));
|
||||||
|
|
||||||
|
PhoneNumber = phoneNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryParse(User user, string source, string value, out UserContactAustralianPhone contact) =>
|
||||||
|
TryParse(user, source, validator, value,
|
||||||
|
(u, s, name, phoneNumber) => new UserContactAustralianPhone(u, s, name, phoneNumber),
|
||||||
|
out contact);
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(Name))
|
||||||
|
return $"{Name} <{PhoneNumber}>";
|
||||||
|
else
|
||||||
|
return PhoneNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Disco.Models.Services.Users.Contact
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum UserContactType
|
||||||
|
{
|
||||||
|
Email = 1,
|
||||||
|
MobilePhone,
|
||||||
|
Phone,
|
||||||
|
AddressMail,
|
||||||
|
AddressHome,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -396,6 +396,7 @@
|
|||||||
<Compile Include="Plugins\Features\DetailsProvider\DetailsProviderExtensions.cs" />
|
<Compile Include="Plugins\Features\DetailsProvider\DetailsProviderExtensions.cs" />
|
||||||
<Compile Include="Plugins\Features\DetailsProvider\DetailsProviderFeature.cs" />
|
<Compile Include="Plugins\Features\DetailsProvider\DetailsProviderFeature.cs" />
|
||||||
<Compile Include="Plugins\Features\DetailsProvider\DetailsProviderService.cs" />
|
<Compile Include="Plugins\Features\DetailsProvider\DetailsProviderService.cs" />
|
||||||
|
<Compile Include="Plugins\Features\DetailsProvider\UserContactFeature.cs" />
|
||||||
<Compile Include="Plugins\Features\DocumentHandlerProvider\DocumentHandlerProviderFeature.cs" />
|
<Compile Include="Plugins\Features\DocumentHandlerProvider\DocumentHandlerProviderFeature.cs" />
|
||||||
<Compile Include="Plugins\Features\WirelessProfileProvider\ProvisionWirelessProfilesResult.cs" />
|
<Compile Include="Plugins\Features\WirelessProfileProvider\ProvisionWirelessProfilesResult.cs" />
|
||||||
<Compile Include="Plugins\Features\WirelessProfileProvider\WirelessProfile.cs" />
|
<Compile Include="Plugins\Features\WirelessProfileProvider\WirelessProfile.cs" />
|
||||||
@@ -456,6 +457,7 @@
|
|||||||
<Compile Include="Plugins\Features\UIExtension\UIExtensions.cs" />
|
<Compile Include="Plugins\Features\UIExtension\UIExtensions.cs" />
|
||||||
<Compile Include="Users\Cache.cs" />
|
<Compile Include="Users\Cache.cs" />
|
||||||
<Compile Include="Users\CacheCleanTask.cs" />
|
<Compile Include="Users\CacheCleanTask.cs" />
|
||||||
|
<Compile Include="Users\Contact\UserContactService.cs" />
|
||||||
<Compile Include="Users\UserExtensions.cs" />
|
<Compile Include="Users\UserExtensions.cs" />
|
||||||
<Compile Include="Users\UserFlags\Cache.cs" />
|
<Compile Include="Users\UserFlags\Cache.cs" />
|
||||||
<Compile Include="Users\UserFlags\UserFlagExtensions.cs" />
|
<Compile Include="Users\UserFlags\UserFlagExtensions.cs" />
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Models.Services.Users.Contact;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Disco.Services.Plugins.Features.DetailsProvider
|
||||||
|
{
|
||||||
|
[PluginFeatureCategory(DisplayName = "User Contact Providers")]
|
||||||
|
public abstract class UserContactFeature : PluginFeature
|
||||||
|
{
|
||||||
|
public abstract IEnumerable<UserContact> GetContacts(DiscoDataContext database, User user, UserContactType? contactType = null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Models.Services.Users.Contact;
|
||||||
|
using Disco.Services.Plugins.Features.DetailsProvider;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using ZXing;
|
||||||
|
|
||||||
|
namespace Disco.Services.Users.Contact
|
||||||
|
{
|
||||||
|
public static class UserContactService
|
||||||
|
{
|
||||||
|
public static List<UserContact> GetContacts(DiscoDataContext database, User user)
|
||||||
|
=> GetContacts(database, user, null);
|
||||||
|
|
||||||
|
public static List<UserContact> GetContacts(DiscoDataContext database, User user, UserContactType? contactType = null)
|
||||||
|
{
|
||||||
|
var contacts = new List<UserContact>();
|
||||||
|
|
||||||
|
if (!contactType.HasValue || contactType.Value.HasFlag(UserContactType.Email))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(user.EmailAddress) &&
|
||||||
|
UserContactEmail.TryParse(user, "Active Directory", $"{user.DisplayName} <{user.EmailAddress}>", out var contact))
|
||||||
|
{
|
||||||
|
contacts.Add(contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var foundMobilePhone = false;
|
||||||
|
if (!contactType.HasValue || contactType.Value.HasFlag(UserContactType.MobilePhone))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(user.PhoneNumber) &&
|
||||||
|
UserContactAustralianMobile.TryParse(user, "Active Directory", $"{user.DisplayName} <{user.PhoneNumber}>", out var contact))
|
||||||
|
{
|
||||||
|
contacts.Add(contact);
|
||||||
|
foundMobilePhone = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundMobilePhone && (!contactType.HasValue || contactType.Value.HasFlag(UserContactType.Phone)))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(user.PhoneNumber) &&
|
||||||
|
UserContactAustralianPhone.TryParse(user, "Active Directory", $"{user.DisplayName} <{user.PhoneNumber}>", out var contact))
|
||||||
|
{
|
||||||
|
contacts.Add(contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// from plugin feature
|
||||||
|
var features = Plugins.Plugins.GetPluginFeatures(typeof(UserContactFeature));
|
||||||
|
foreach (var feature in features)
|
||||||
|
{
|
||||||
|
var instance = feature.CreateInstance<UserContactFeature>();
|
||||||
|
contacts.AddRange(instance.GetContacts(database, user, contactType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// from user details
|
||||||
|
contacts.AddRange(GetContactsFromUserDetails(database, user, contactType));
|
||||||
|
|
||||||
|
return contacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<UserContact> GetContactsFromUserDetails(DiscoDataContext database, User user, UserContactType? contactType = null)
|
||||||
|
{
|
||||||
|
var service = new DetailsProviderService(database);
|
||||||
|
|
||||||
|
user = database.Users.First(u => u.UserId == user.UserId);
|
||||||
|
var details = service.GetDetails(user);
|
||||||
|
|
||||||
|
if ((details?.Details?.Count ?? 0) == 0)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
foreach (var item in details.Details)
|
||||||
|
{
|
||||||
|
if (!contactType.HasValue || contactType.Value.HasFlag(UserContactType.Email))
|
||||||
|
{
|
||||||
|
if (UserContactEmail.TryParse(user, item.Key, item.Value, out var contact))
|
||||||
|
{
|
||||||
|
yield return contact;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contactType.HasValue || contactType.Value.HasFlag(UserContactType.MobilePhone))
|
||||||
|
{
|
||||||
|
if (UserContactAustralianMobile.TryParse(user, item.Key, item.Value, out var contact))
|
||||||
|
{
|
||||||
|
yield return contact;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contactType.HasValue || contactType.Value.HasFlag(UserContactType.Phone))
|
||||||
|
{
|
||||||
|
if (UserContactAustralianPhone.TryParse(user, item.Key, item.Value, out var contact))
|
||||||
|
{
|
||||||
|
yield return contact;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user