refactoring: voipService
This commit is contained in:
parent
420f34c3ee
commit
e42e0aa4e5
@ -28,23 +28,22 @@ namespace ASC.VoipService.Dao
|
||||
{
|
||||
public class AbstractDao
|
||||
{
|
||||
private readonly string dbid = "default";
|
||||
|
||||
private Lazy<VoipDbContext> LazyVoipDbContext { get; }
|
||||
protected VoipDbContext VoipDbContext { get => LazyVoipDbContext.Value; }
|
||||
|
||||
protected AbstractDao(DbContextManager<VoipDbContext> dbOptions, TenantManager tenantManager)
|
||||
{
|
||||
LazyVoipDbContext = new Lazy<VoipDbContext>(() => dbOptions.Get(dbid));
|
||||
TenantID = tenantManager.GetCurrentTenant().TenantId;
|
||||
}
|
||||
private readonly string _dbid = "default";
|
||||
private Lazy<VoipDbContext> _lazyVoipDbContext;
|
||||
|
||||
protected VoipDbContext VoipDbContext { get => _lazyVoipDbContext.Value; }
|
||||
protected int TenantID
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
protected AbstractDao(DbContextManager<VoipDbContext> dbOptions, TenantManager tenantManager)
|
||||
{
|
||||
_lazyVoipDbContext = new Lazy<VoipDbContext>(() => dbOptions.Get(_dbid));
|
||||
TenantID = tenantManager.GetCurrentTenant().TenantId;
|
||||
}
|
||||
|
||||
protected string GetTenantColumnName(string table)
|
||||
{
|
||||
const string tenant = "tenant_id";
|
||||
|
@ -23,78 +23,77 @@
|
||||
*
|
||||
*/
|
||||
|
||||
namespace ASC.VoipService.Dao
|
||||
namespace ASC.VoipService.Dao;
|
||||
|
||||
[Singletone]
|
||||
public class VoipDaoCache
|
||||
{
|
||||
[Singletone]
|
||||
public class VoipDaoCache
|
||||
internal readonly ICache _cache;
|
||||
private readonly ICacheNotify<CachedVoipItem> _notify;
|
||||
|
||||
public VoipDaoCache(ICacheNotify<CachedVoipItem> notify, ICache cache)
|
||||
{
|
||||
internal ICache Cache { get; }
|
||||
private ICacheNotify<CachedVoipItem> Notify { get; }
|
||||
|
||||
public VoipDaoCache(ICacheNotify<CachedVoipItem> notify, ICache cache)
|
||||
{
|
||||
Cache = cache;
|
||||
Notify = notify;
|
||||
Notify.Subscribe((c) => Cache.Remove(CachedVoipDao.GetCacheKey(c.Tenant)), Common.Caching.CacheNotifyAction.Any);
|
||||
}
|
||||
|
||||
public void ResetCache(int tenant)
|
||||
{
|
||||
Notify.Publish(new CachedVoipItem { Tenant = tenant }, Common.Caching.CacheNotifyAction.Any);
|
||||
}
|
||||
_cache = cache;
|
||||
_notify = notify;
|
||||
_notify.Subscribe((c) => _cache.Remove(CachedVoipDao.GetCacheKey(c.Tenant)), Common.Caching.CacheNotifyAction.Any);
|
||||
}
|
||||
|
||||
[Scope]
|
||||
public class CachedVoipDao : VoipDao
|
||||
public void ResetCache(int tenant)
|
||||
{
|
||||
private readonly ICache cache;
|
||||
private static readonly TimeSpan timeout = TimeSpan.FromDays(1);
|
||||
_notify.Publish(new CachedVoipItem { Tenant = tenant }, Common.Caching.CacheNotifyAction.Any);
|
||||
}
|
||||
}
|
||||
|
||||
private VoipDaoCache VoipDaoCache { get; }
|
||||
[Scope]
|
||||
public class CachedVoipDao : VoipDao
|
||||
{
|
||||
private static readonly TimeSpan timeout = TimeSpan.FromDays(1);
|
||||
|
||||
private readonly ICache _cache;
|
||||
private readonly VoipDaoCache _voipDaoCache;
|
||||
|
||||
public CachedVoipDao(
|
||||
TenantManager tenantManager,
|
||||
DbContextManager<VoipDbContext> dbOptions,
|
||||
AuthContext authContext,
|
||||
TenantUtil tenantUtil,
|
||||
SecurityContext securityContext,
|
||||
BaseCommonLinkUtility baseCommonLinkUtility,
|
||||
ConsumerFactory consumerFactory,
|
||||
VoipDaoCache voipDaoCache)
|
||||
: base(tenantManager, dbOptions, authContext, tenantUtil, securityContext, baseCommonLinkUtility, consumerFactory)
|
||||
{
|
||||
cache = voipDaoCache.Cache;
|
||||
VoipDaoCache = voipDaoCache;
|
||||
}
|
||||
public CachedVoipDao(
|
||||
TenantManager tenantManager,
|
||||
DbContextManager<VoipDbContext> dbOptions,
|
||||
AuthContext authContext,
|
||||
TenantUtil tenantUtil,
|
||||
SecurityContext securityContext,
|
||||
BaseCommonLinkUtility baseCommonLinkUtility,
|
||||
ConsumerFactory consumerFactory,
|
||||
VoipDaoCache voipDaoCache)
|
||||
: base(tenantManager, dbOptions, authContext, tenantUtil, securityContext, baseCommonLinkUtility, consumerFactory)
|
||||
{
|
||||
_cache = voipDaoCache._cache;
|
||||
_voipDaoCache = voipDaoCache;
|
||||
}
|
||||
|
||||
public override VoipPhone SaveOrUpdateNumber(VoipPhone phone)
|
||||
public override VoipPhone SaveOrUpdateNumber(VoipPhone phone)
|
||||
{
|
||||
var result = base.SaveOrUpdateNumber(phone);
|
||||
_voipDaoCache.ResetCache(TenantID);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void DeleteNumber(string phoneId = "")
|
||||
{
|
||||
base.DeleteNumber(phoneId);
|
||||
_voipDaoCache.ResetCache(TenantID);
|
||||
}
|
||||
|
||||
public override IEnumerable<VoipPhone> GetNumbers(params string[] ids)
|
||||
{
|
||||
var numbers = _cache.Get<List<VoipPhone>>(GetCacheKey(TenantID));
|
||||
if (numbers == null)
|
||||
{
|
||||
var result = base.SaveOrUpdateNumber(phone);
|
||||
VoipDaoCache.ResetCache(TenantID);
|
||||
return result;
|
||||
numbers = new List<VoipPhone>(base.GetAllNumbers());
|
||||
_cache.Insert(GetCacheKey(TenantID), numbers, DateTime.UtcNow.Add(timeout));
|
||||
}
|
||||
|
||||
public override void DeleteNumber(string phoneId = "")
|
||||
{
|
||||
base.DeleteNumber(phoneId);
|
||||
VoipDaoCache.ResetCache(TenantID);
|
||||
}
|
||||
return ids.Length > 0 ? numbers.Where(r => ids.Contains(r.Id) || ids.Contains(r.Number)).ToList() : numbers;
|
||||
}
|
||||
|
||||
public override IEnumerable<VoipPhone> GetNumbers(params string[] ids)
|
||||
{
|
||||
var numbers = cache.Get<List<VoipPhone>>(GetCacheKey(TenantID));
|
||||
if (numbers == null)
|
||||
{
|
||||
numbers = new List<VoipPhone>(base.GetAllNumbers());
|
||||
cache.Insert(GetCacheKey(TenantID), numbers, DateTime.UtcNow.Add(timeout));
|
||||
}
|
||||
|
||||
return ids.Length > 0 ? numbers.Where(r => ids.Contains(r.Id) || ids.Contains(r.Number)).ToList() : numbers;
|
||||
}
|
||||
|
||||
public static string GetCacheKey(int tenant)
|
||||
{
|
||||
return "voip" + tenant.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
public static string GetCacheKey(int tenant)
|
||||
{
|
||||
return "voip" + tenant.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
@ -23,92 +23,91 @@
|
||||
*
|
||||
*/
|
||||
|
||||
namespace ASC.VoipService.Dao
|
||||
namespace ASC.VoipService.Dao;
|
||||
|
||||
public class VoipCallFilter
|
||||
{
|
||||
public class VoipCallFilter
|
||||
public string Type { get; set; }
|
||||
|
||||
public DateTime? FromDate { get; set; }
|
||||
|
||||
public DateTime? ToDate { get; set; }
|
||||
|
||||
public Guid? Agent { get; set; }
|
||||
|
||||
public int? Client { get; set; }
|
||||
|
||||
public int? ContactID { get; set; }
|
||||
|
||||
public string Id { get; set; }
|
||||
|
||||
public string ParentId { get; set; }
|
||||
|
||||
public string SortBy { get; set; }
|
||||
|
||||
public bool SortOrder { get; set; }
|
||||
|
||||
public string SearchText { get; set; }
|
||||
|
||||
public long Offset { get; set; }
|
||||
|
||||
public long Max { get; set; }
|
||||
|
||||
public int? TypeStatus
|
||||
{
|
||||
public string Type { get; set; }
|
||||
|
||||
public DateTime? FromDate { get; set; }
|
||||
|
||||
public DateTime? ToDate { get; set; }
|
||||
|
||||
public Guid? Agent { get; set; }
|
||||
|
||||
public int? Client { get; set; }
|
||||
|
||||
public int? ContactID { get; set; }
|
||||
|
||||
public string Id { get; set; }
|
||||
|
||||
public string ParentId { get; set; }
|
||||
|
||||
public string SortBy { get; set; }
|
||||
|
||||
public bool SortOrder { get; set; }
|
||||
|
||||
public string SearchText { get; set; }
|
||||
|
||||
public long Offset { get; set; }
|
||||
|
||||
public long Max { get; set; }
|
||||
|
||||
public int? TypeStatus
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Type)) return null;
|
||||
if (TypeStatuses.TryGetValue(Type, out var status)) return status;
|
||||
if (string.IsNullOrWhiteSpace(Type)) return null;
|
||||
if (TypeStatuses.TryGetValue(Type, out var status)) return status;
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public string SortByColumn
|
||||
public string SortByColumn
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(SortBy)) return null;
|
||||
return SortColumns.ContainsKey(SortBy) ? SortColumns[SortBy] : null;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(SortBy)) return null;
|
||||
return SortColumns.ContainsKey(SortBy) ? SortColumns[SortBy] : null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, int> TypeStatuses
|
||||
private static Dictionary<string, int> TypeStatuses
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Dictionary<string, int>
|
||||
return new Dictionary<string, int>
|
||||
{
|
||||
{
|
||||
{
|
||||
"answered", (int)VoipCallStatus.Answered
|
||||
},
|
||||
{
|
||||
"missed", (int)VoipCallStatus.Missed
|
||||
},
|
||||
{
|
||||
"outgoing", (int)VoipCallStatus.Outcoming
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> SortColumns
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Dictionary<string, string>
|
||||
"answered", (int)VoipCallStatus.Answered
|
||||
},
|
||||
{
|
||||
{
|
||||
"date", "dial_date"
|
||||
},
|
||||
{
|
||||
"duration", "dial_duration"
|
||||
},
|
||||
{
|
||||
"price", "price"
|
||||
},
|
||||
};
|
||||
}
|
||||
"missed", (int)VoipCallStatus.Missed
|
||||
},
|
||||
{
|
||||
"outgoing", (int)VoipCallStatus.Outcoming
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> SortColumns
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Dictionary<string, string>
|
||||
{
|
||||
{
|
||||
"date", "dial_date"
|
||||
},
|
||||
{
|
||||
"duration", "dial_duration"
|
||||
},
|
||||
{
|
||||
"price", "price"
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -23,342 +23,338 @@
|
||||
*
|
||||
*/
|
||||
|
||||
namespace ASC.VoipService.Dao
|
||||
namespace ASC.VoipService.Dao;
|
||||
|
||||
[Scope(typeof(CachedVoipDao))]
|
||||
public class VoipDao : AbstractDao
|
||||
{
|
||||
[Scope(typeof(CachedVoipDao))]
|
||||
public class VoipDao : AbstractDao
|
||||
private readonly AuthContext _authContext;
|
||||
private readonly TenantUtil _tenantUtil;
|
||||
private readonly SecurityContext _securityContext;
|
||||
private readonly BaseCommonLinkUtility _baseCommonLinkUtility;
|
||||
private readonly ConsumerFactory _consumerFactory;
|
||||
|
||||
public VoipDao(
|
||||
TenantManager tenantManager,
|
||||
DbContextManager<VoipDbContext> dbOptions,
|
||||
AuthContext authContext,
|
||||
TenantUtil tenantUtil,
|
||||
SecurityContext securityContext,
|
||||
BaseCommonLinkUtility baseCommonLinkUtility,
|
||||
ConsumerFactory consumerFactory)
|
||||
: base(dbOptions, tenantManager)
|
||||
{
|
||||
public VoipDao(
|
||||
TenantManager tenantManager,
|
||||
DbContextManager<VoipDbContext> dbOptions,
|
||||
AuthContext authContext,
|
||||
TenantUtil tenantUtil,
|
||||
SecurityContext securityContext,
|
||||
BaseCommonLinkUtility baseCommonLinkUtility,
|
||||
ConsumerFactory consumerFactory)
|
||||
: base(dbOptions, tenantManager)
|
||||
_authContext = authContext;
|
||||
_tenantUtil = tenantUtil;
|
||||
_securityContext = securityContext;
|
||||
_baseCommonLinkUtility = baseCommonLinkUtility;
|
||||
_consumerFactory = consumerFactory;
|
||||
}
|
||||
|
||||
public virtual VoipPhone SaveOrUpdateNumber(VoipPhone phone)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(phone.Number))
|
||||
{
|
||||
AuthContext = authContext;
|
||||
TenantUtil = tenantUtil;
|
||||
SecurityContext = securityContext;
|
||||
BaseCommonLinkUtility = baseCommonLinkUtility;
|
||||
ConsumerFactory = consumerFactory;
|
||||
phone.Number = phone.Number.TrimStart('+');
|
||||
}
|
||||
|
||||
public virtual VoipPhone SaveOrUpdateNumber(VoipPhone phone)
|
||||
var voipNumber = new VoipNumber
|
||||
{
|
||||
if (!string.IsNullOrEmpty(phone.Number))
|
||||
{
|
||||
phone.Number = phone.Number.TrimStart('+');
|
||||
}
|
||||
Id = phone.Id,
|
||||
Number = phone.Number,
|
||||
Alias = phone.Alias,
|
||||
Settings = phone.Settings.ToString(),
|
||||
TenantId = TenantID
|
||||
};
|
||||
|
||||
var voipNumber = new VoipNumber
|
||||
{
|
||||
Id = phone.Id,
|
||||
Number = phone.Number,
|
||||
Alias = phone.Alias,
|
||||
Settings = phone.Settings.ToString(),
|
||||
TenantId = TenantID
|
||||
};
|
||||
VoipDbContext.VoipNumbers.Add(voipNumber);
|
||||
VoipDbContext.SaveChanges();
|
||||
|
||||
VoipDbContext.VoipNumbers.Add(voipNumber);
|
||||
VoipDbContext.SaveChanges();
|
||||
return phone;
|
||||
}
|
||||
|
||||
return phone;
|
||||
public virtual void DeleteNumber(string phoneId = "")
|
||||
{
|
||||
var number = VoipDbContext.VoipNumbers.Where(r => r.Id == phoneId && r.TenantId == TenantID).FirstOrDefault();
|
||||
VoipDbContext.VoipNumbers.Remove(number);
|
||||
VoipDbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public virtual IEnumerable<VoipPhone> GetAllNumbers()
|
||||
{
|
||||
return VoipDbContext.VoipNumbers
|
||||
.Where(r => r.TenantId == TenantID)
|
||||
.ToList()
|
||||
.ConvertAll(ToPhone);
|
||||
}
|
||||
|
||||
public virtual IEnumerable<VoipPhone> GetNumbers(params string[] ids)
|
||||
{
|
||||
var numbers = VoipDbContext.VoipNumbers.Where(r => r.TenantId == TenantID);
|
||||
|
||||
if (ids.Length > 0)
|
||||
{
|
||||
numbers = numbers.Where(r => ids.Any(a => a == r.Number || a == r.Id));
|
||||
}
|
||||
|
||||
public virtual void DeleteNumber(string phoneId = "")
|
||||
return numbers.ToList().ConvertAll(ToPhone);
|
||||
}
|
||||
|
||||
public VoipPhone GetNumber(string id)
|
||||
{
|
||||
return GetNumbers(id.TrimStart('+')).FirstOrDefault();
|
||||
}
|
||||
|
||||
public virtual VoipPhone GetCurrentNumber()
|
||||
{
|
||||
return GetNumbers().FirstOrDefault(r => r.Caller != null);
|
||||
}
|
||||
|
||||
|
||||
public VoipCall SaveOrUpdateCall(VoipCall call)
|
||||
{
|
||||
var voipCall = new DbVoipCall
|
||||
{
|
||||
var number = VoipDbContext.VoipNumbers.Where(r => r.Id == phoneId && r.TenantId == TenantID).FirstOrDefault();
|
||||
VoipDbContext.VoipNumbers.Remove(number);
|
||||
VoipDbContext.SaveChanges();
|
||||
TenantId = TenantID,
|
||||
Id = call.Id,
|
||||
NumberFrom = call.From,
|
||||
NumberTo = call.To,
|
||||
ContactId = call.ContactId
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(call.ParentID))
|
||||
{
|
||||
voipCall.ParentCallId = call.ParentID;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<VoipPhone> GetAllNumbers()
|
||||
if (call.Status.HasValue)
|
||||
{
|
||||
return VoipDbContext.VoipNumbers
|
||||
.Where(r => r.TenantId == TenantID)
|
||||
.ToList()
|
||||
.ConvertAll(ToPhone);
|
||||
voipCall.Status = (int)call.Status.Value;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<VoipPhone> GetNumbers(params string[] ids)
|
||||
if (!call.AnsweredBy.Equals(Guid.Empty))
|
||||
{
|
||||
var numbers = VoipDbContext.VoipNumbers.Where(r => r.TenantId == TenantID);
|
||||
|
||||
if (ids.Length > 0)
|
||||
{
|
||||
numbers = numbers.Where(r => ids.Any(a => a == r.Number || a == r.Id));
|
||||
}
|
||||
|
||||
return numbers.ToList().ConvertAll(ToPhone);
|
||||
voipCall.AnsweredBy = call.AnsweredBy;
|
||||
}
|
||||
|
||||
public VoipPhone GetNumber(string id)
|
||||
if (call.DialDate == DateTime.MinValue)
|
||||
{
|
||||
return GetNumbers(id.TrimStart('+')).FirstOrDefault();
|
||||
call.DialDate = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public virtual VoipPhone GetCurrentNumber()
|
||||
voipCall.DialDate = _tenantUtil.DateTimeToUtc(call.DialDate);
|
||||
|
||||
if (call.DialDuration > 0)
|
||||
{
|
||||
return GetNumbers().FirstOrDefault(r => r.Caller != null);
|
||||
voipCall.DialDuration = call.DialDuration;
|
||||
}
|
||||
|
||||
|
||||
public VoipCall SaveOrUpdateCall(VoipCall call)
|
||||
if (call.Price > decimal.Zero)
|
||||
{
|
||||
var voipCall = new DbVoipCall
|
||||
{
|
||||
TenantId = TenantID,
|
||||
Id = call.Id,
|
||||
NumberFrom = call.From,
|
||||
NumberTo = call.To,
|
||||
ContactId = call.ContactId
|
||||
};
|
||||
voipCall.Price = call.Price;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(call.ParentID))
|
||||
if (call.VoipRecord != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(call.VoipRecord.Id))
|
||||
{
|
||||
voipCall.ParentCallId = call.ParentID;
|
||||
voipCall.RecordSid = call.VoipRecord.Id;
|
||||
}
|
||||
|
||||
if (call.Status.HasValue)
|
||||
if (!string.IsNullOrEmpty(call.VoipRecord.Uri))
|
||||
{
|
||||
voipCall.Status = (int)call.Status.Value;
|
||||
voipCall.RecordUrl = call.VoipRecord.Uri;
|
||||
}
|
||||
|
||||
if (!call.AnsweredBy.Equals(Guid.Empty))
|
||||
if (call.VoipRecord.Duration != 0)
|
||||
{
|
||||
voipCall.AnsweredBy = call.AnsweredBy;
|
||||
voipCall.RecordDuration = call.VoipRecord.Duration;
|
||||
}
|
||||
|
||||
if (call.DialDate == DateTime.MinValue)
|
||||
if (call.VoipRecord.Price != default)
|
||||
{
|
||||
call.DialDate = DateTime.UtcNow;
|
||||
voipCall.RecordPrice = call.VoipRecord.Price;
|
||||
}
|
||||
}
|
||||
|
||||
voipCall.DialDate = TenantUtil.DateTimeToUtc(call.DialDate);
|
||||
VoipDbContext.VoipCalls.Add(voipCall);
|
||||
VoipDbContext.SaveChanges();
|
||||
|
||||
if (call.DialDuration > 0)
|
||||
{
|
||||
voipCall.DialDuration = call.DialDuration;
|
||||
}
|
||||
return call;
|
||||
}
|
||||
|
||||
if (call.Price > decimal.Zero)
|
||||
{
|
||||
voipCall.Price = call.Price;
|
||||
}
|
||||
public IEnumerable<VoipCall> GetCalls(VoipCallFilter filter)
|
||||
{
|
||||
var query = GetCallsQuery(filter);
|
||||
|
||||
if (call.VoipRecord != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(call.VoipRecord.Id))
|
||||
{
|
||||
voipCall.RecordSid = call.VoipRecord.Id;
|
||||
}
|
||||
if (filter.SortByColumn != null)
|
||||
{
|
||||
query.OrderBy(filter.SortByColumn, filter.SortOrder);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(call.VoipRecord.Uri))
|
||||
{
|
||||
voipCall.RecordUrl = call.VoipRecord.Uri;
|
||||
}
|
||||
query = query.Skip((int)filter.Offset);
|
||||
query = query.Take((int)filter.Max * 3);
|
||||
|
||||
if (call.VoipRecord.Duration != 0)
|
||||
{
|
||||
voipCall.RecordDuration = call.VoipRecord.Duration;
|
||||
}
|
||||
|
||||
if (call.VoipRecord.Price != default)
|
||||
{
|
||||
voipCall.RecordPrice = call.VoipRecord.Price;
|
||||
}
|
||||
}
|
||||
|
||||
VoipDbContext.VoipCalls.Add(voipCall);
|
||||
VoipDbContext.SaveChanges();
|
||||
var calls = query.ToList().ConvertAll(ToCall);
|
||||
|
||||
calls = calls.GroupJoin(calls, call => call.Id, h => h.ParentID, (call, h) =>
|
||||
{
|
||||
call.ChildCalls.AddRange(h);
|
||||
return call;
|
||||
}
|
||||
}).Where(r => string.IsNullOrEmpty(r.ParentID)).ToList();
|
||||
|
||||
public IEnumerable<VoipCall> GetCalls(VoipCallFilter filter)
|
||||
return calls;
|
||||
}
|
||||
|
||||
public VoipCall GetCall(string id)
|
||||
{
|
||||
return GetCalls(new VoipCallFilter { Id = id }).FirstOrDefault();
|
||||
}
|
||||
|
||||
public int GetCallsCount(VoipCallFilter filter)
|
||||
{
|
||||
return GetCallsQuery(filter).Where(r => r.DbVoipCall.ParentCallId == "").Count();
|
||||
}
|
||||
|
||||
public IEnumerable<VoipCall> GetMissedCalls(Guid agent, long count = 0, DateTime? from = null)
|
||||
{
|
||||
var query = GetCallsQuery(new VoipCallFilter { Agent = agent, SortBy = "date", SortOrder = true, Type = "missed" });
|
||||
|
||||
if (from.HasValue)
|
||||
{
|
||||
var query = GetCallsQuery(filter);
|
||||
|
||||
if (filter.SortByColumn != null)
|
||||
{
|
||||
query.OrderBy(filter.SortByColumn, filter.SortOrder);
|
||||
}
|
||||
|
||||
query = query.Skip((int)filter.Offset);
|
||||
query = query.Take((int)filter.Max * 3);
|
||||
|
||||
var calls = query.ToList().ConvertAll(ToCall);
|
||||
|
||||
calls = calls.GroupJoin(calls, call => call.Id, h => h.ParentID, (call, h) =>
|
||||
{
|
||||
call.ChildCalls.AddRange(h);
|
||||
return call;
|
||||
}).Where(r => string.IsNullOrEmpty(r.ParentID)).ToList();
|
||||
|
||||
return calls;
|
||||
query = query.Where(r => r.DbVoipCall.DialDate >= _tenantUtil.DateTimeFromUtc(from.Value));
|
||||
}
|
||||
|
||||
public VoipCall GetCall(string id)
|
||||
if (count != 0)
|
||||
{
|
||||
return GetCalls(new VoipCallFilter { Id = id }).FirstOrDefault();
|
||||
query = query.Take((int)count);
|
||||
}
|
||||
|
||||
public int GetCallsCount(VoipCallFilter filter)
|
||||
var a = query.Select(ca => new
|
||||
{
|
||||
return GetCallsQuery(filter).Where(r => r.DbVoipCall.ParentCallId == "").Count();
|
||||
}
|
||||
dbVoipCall = ca,
|
||||
tmpDate = VoipDbContext.VoipCalls
|
||||
.Where(tmp => tmp.TenantId == ca.DbVoipCall.TenantId)
|
||||
.Where(tmp => tmp.NumberFrom == ca.DbVoipCall.NumberFrom || tmp.NumberTo == ca.DbVoipCall.NumberFrom)
|
||||
.Where(tmp => tmp.Status <= (int)VoipCallStatus.Missed)
|
||||
.Max(tmp => tmp.DialDate)
|
||||
}).Where(r => r.dbVoipCall.DbVoipCall.DialDate >= r.tmpDate || r.tmpDate == default);
|
||||
|
||||
public IEnumerable<VoipCall> GetMissedCalls(Guid agent, long count = 0, DateTime? from = null)
|
||||
return a.ToList().ConvertAll(r => ToCall(r.dbVoipCall));
|
||||
}
|
||||
|
||||
private IQueryable<CallContact> GetCallsQuery(VoipCallFilter filter)
|
||||
{
|
||||
var q = VoipDbContext.VoipCalls
|
||||
.Where(r => r.TenantId == TenantID);
|
||||
|
||||
if (!string.IsNullOrEmpty(filter.Id))
|
||||
{
|
||||
var query = GetCallsQuery(new VoipCallFilter { Agent = agent, SortBy = "date", SortOrder = true, Type = "missed" });
|
||||
|
||||
if (from.HasValue)
|
||||
{
|
||||
query = query.Where(r => r.DbVoipCall.DialDate >= TenantUtil.DateTimeFromUtc(from.Value));
|
||||
}
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
query = query.Take((int)count);
|
||||
}
|
||||
|
||||
var a = query.Select(ca => new
|
||||
{
|
||||
dbVoipCall = ca,
|
||||
tmpDate = VoipDbContext.VoipCalls
|
||||
.Where(tmp => tmp.TenantId == ca.DbVoipCall.TenantId)
|
||||
.Where(tmp => tmp.NumberFrom == ca.DbVoipCall.NumberFrom || tmp.NumberTo == ca.DbVoipCall.NumberFrom)
|
||||
.Where(tmp => tmp.Status <= (int)VoipCallStatus.Missed)
|
||||
.Max(tmp => tmp.DialDate)
|
||||
}).Where(r => r.dbVoipCall.DbVoipCall.DialDate >= r.tmpDate || r.tmpDate == default);
|
||||
|
||||
return a.ToList().ConvertAll(r => ToCall(r.dbVoipCall));
|
||||
q = q.Where(r => r.Id == filter.Id || r.ParentCallId == filter.Id);
|
||||
}
|
||||
|
||||
private IQueryable<CallContact> GetCallsQuery(VoipCallFilter filter)
|
||||
if (filter.ContactID.HasValue)
|
||||
{
|
||||
var q = VoipDbContext.VoipCalls
|
||||
.Where(r => r.TenantId == TenantID);
|
||||
|
||||
if (!string.IsNullOrEmpty(filter.Id))
|
||||
{
|
||||
q = q.Where(r => r.Id == filter.Id || r.ParentCallId == filter.Id);
|
||||
}
|
||||
|
||||
if (filter.ContactID.HasValue)
|
||||
{
|
||||
q = q.Where(r => r.ContactId == filter.ContactID.Value);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.SearchText))
|
||||
{
|
||||
q = q.Where(r => r.Id.StartsWith(filter.SearchText));
|
||||
}
|
||||
|
||||
if (filter.TypeStatus.HasValue)
|
||||
{
|
||||
q = q.Where(r => r.Status == filter.TypeStatus.Value);
|
||||
}
|
||||
|
||||
if (filter.FromDate.HasValue)
|
||||
{
|
||||
q = q.Where(r => r.DialDate >= filter.FromDate.Value);
|
||||
}
|
||||
|
||||
if (filter.ToDate.HasValue)
|
||||
{
|
||||
q = q.Where(r => r.DialDate <= filter.ToDate.Value);
|
||||
}
|
||||
|
||||
if (filter.Agent.HasValue)
|
||||
{
|
||||
q = q.Where(r => r.AnsweredBy == filter.Agent.Value);
|
||||
}
|
||||
|
||||
return q
|
||||
.GroupBy(r => r.Id, r => r)
|
||||
.Join(
|
||||
VoipDbContext.CrmContact.DefaultIfEmpty(),
|
||||
r => r.FirstOrDefault().ContactId,
|
||||
c => c.Id,
|
||||
(call, contact) => new CallContact { DbVoipCall = call.FirstOrDefault(), CrmContact = contact })
|
||||
;
|
||||
q = q.Where(r => r.ContactId == filter.ContactID.Value);
|
||||
}
|
||||
|
||||
class CallContact
|
||||
if (!string.IsNullOrWhiteSpace(filter.SearchText))
|
||||
{
|
||||
public DbVoipCall DbVoipCall { get; set; }
|
||||
public CrmContact CrmContact { get; set; }
|
||||
q = q.Where(r => r.Id.StartsWith(filter.SearchText));
|
||||
}
|
||||
|
||||
#region Converters
|
||||
|
||||
private VoipPhone ToPhone(VoipNumber r)
|
||||
if (filter.TypeStatus.HasValue)
|
||||
{
|
||||
return GetProvider().GetPhone(r);
|
||||
q = q.Where(r => r.Status == filter.TypeStatus.Value);
|
||||
}
|
||||
|
||||
private VoipCall ToCall(CallContact dbVoipCall)
|
||||
if (filter.FromDate.HasValue)
|
||||
{
|
||||
var call = new VoipCall
|
||||
q = q.Where(r => r.DialDate >= filter.FromDate.Value);
|
||||
}
|
||||
|
||||
if (filter.ToDate.HasValue)
|
||||
{
|
||||
q = q.Where(r => r.DialDate <= filter.ToDate.Value);
|
||||
}
|
||||
|
||||
if (filter.Agent.HasValue)
|
||||
{
|
||||
q = q.Where(r => r.AnsweredBy == filter.Agent.Value);
|
||||
}
|
||||
|
||||
return q
|
||||
.GroupBy(r => r.Id, r => r)
|
||||
.Join(
|
||||
VoipDbContext.CrmContact.DefaultIfEmpty(),
|
||||
r => r.FirstOrDefault().ContactId,
|
||||
c => c.Id,
|
||||
(call, contact) => new CallContact { DbVoipCall = call.FirstOrDefault(), CrmContact = contact })
|
||||
;
|
||||
}
|
||||
|
||||
class CallContact
|
||||
{
|
||||
public DbVoipCall DbVoipCall { get; set; }
|
||||
public CrmContact CrmContact { get; set; }
|
||||
}
|
||||
|
||||
|
||||
private VoipPhone ToPhone(VoipNumber r)
|
||||
{
|
||||
return GetProvider().GetPhone(r);
|
||||
}
|
||||
|
||||
private VoipCall ToCall(CallContact dbVoipCall)
|
||||
{
|
||||
var call = new VoipCall
|
||||
{
|
||||
Id = dbVoipCall.DbVoipCall.Id,
|
||||
ParentID = dbVoipCall.DbVoipCall.ParentCallId,
|
||||
From = dbVoipCall.DbVoipCall.NumberFrom,
|
||||
To = dbVoipCall.DbVoipCall.NumberTo,
|
||||
AnsweredBy = dbVoipCall.DbVoipCall.AnsweredBy,
|
||||
DialDate = _tenantUtil.DateTimeFromUtc(dbVoipCall.DbVoipCall.DialDate),
|
||||
DialDuration = dbVoipCall.DbVoipCall.DialDuration,
|
||||
Price = dbVoipCall.DbVoipCall.Price,
|
||||
Status = (VoipCallStatus)dbVoipCall.DbVoipCall.Status,
|
||||
VoipRecord = new VoipRecord
|
||||
{
|
||||
Id = dbVoipCall.DbVoipCall.Id,
|
||||
ParentID = dbVoipCall.DbVoipCall.ParentCallId,
|
||||
From = dbVoipCall.DbVoipCall.NumberFrom,
|
||||
To = dbVoipCall.DbVoipCall.NumberTo,
|
||||
AnsweredBy = dbVoipCall.DbVoipCall.AnsweredBy,
|
||||
DialDate = TenantUtil.DateTimeFromUtc(dbVoipCall.DbVoipCall.DialDate),
|
||||
DialDuration = dbVoipCall.DbVoipCall.DialDuration,
|
||||
Price = dbVoipCall.DbVoipCall.Price,
|
||||
Status = (VoipCallStatus)dbVoipCall.DbVoipCall.Status,
|
||||
VoipRecord = new VoipRecord
|
||||
{
|
||||
Id = dbVoipCall.DbVoipCall.RecordSid,
|
||||
Uri = dbVoipCall.DbVoipCall.RecordUrl,
|
||||
Duration = dbVoipCall.DbVoipCall.RecordDuration,
|
||||
Price = dbVoipCall.DbVoipCall.RecordPrice
|
||||
},
|
||||
ContactId = dbVoipCall.CrmContact.Id,
|
||||
ContactIsCompany = dbVoipCall.CrmContact.IsCompany,
|
||||
};
|
||||
Id = dbVoipCall.DbVoipCall.RecordSid,
|
||||
Uri = dbVoipCall.DbVoipCall.RecordUrl,
|
||||
Duration = dbVoipCall.DbVoipCall.RecordDuration,
|
||||
Price = dbVoipCall.DbVoipCall.RecordPrice
|
||||
},
|
||||
ContactId = dbVoipCall.CrmContact.Id,
|
||||
ContactIsCompany = dbVoipCall.CrmContact.IsCompany,
|
||||
};
|
||||
|
||||
if (call.ContactId != 0)
|
||||
{
|
||||
call.ContactTitle = call.ContactIsCompany
|
||||
? dbVoipCall.CrmContact.CompanyName
|
||||
: dbVoipCall.CrmContact.FirstName == null || dbVoipCall.CrmContact.LastName == null ? null : $"{dbVoipCall.CrmContact.FirstName} {dbVoipCall.CrmContact.LastName}";
|
||||
}
|
||||
|
||||
return call;
|
||||
}
|
||||
|
||||
public Consumer Consumer
|
||||
if (call.ContactId != 0)
|
||||
{
|
||||
get { return ConsumerFactory.GetByKey("twilio"); }
|
||||
call.ContactTitle = call.ContactIsCompany
|
||||
? dbVoipCall.CrmContact.CompanyName
|
||||
: dbVoipCall.CrmContact.FirstName == null || dbVoipCall.CrmContact.LastName == null ? null : $"{dbVoipCall.CrmContact.FirstName} {dbVoipCall.CrmContact.LastName}";
|
||||
}
|
||||
|
||||
public TwilioProvider GetProvider()
|
||||
return call;
|
||||
}
|
||||
|
||||
public Consumer Consumer
|
||||
{
|
||||
get { return _consumerFactory.GetByKey("twilio"); }
|
||||
}
|
||||
|
||||
public TwilioProvider GetProvider()
|
||||
{
|
||||
return new TwilioProvider(Consumer["twilioAccountSid"], Consumer["twilioAuthToken"], _authContext, _tenantUtil, _securityContext, _baseCommonLinkUtility);
|
||||
}
|
||||
|
||||
public bool ConfigSettingsExist
|
||||
{
|
||||
get
|
||||
{
|
||||
return new TwilioProvider(Consumer["twilioAccountSid"], Consumer["twilioAuthToken"], AuthContext, TenantUtil, SecurityContext, BaseCommonLinkUtility);
|
||||
return !string.IsNullOrEmpty(Consumer["twilioAccountSid"]) &&
|
||||
!string.IsNullOrEmpty(Consumer["twilioAuthToken"]);
|
||||
}
|
||||
|
||||
public bool ConfigSettingsExist
|
||||
{
|
||||
get
|
||||
{
|
||||
return !string.IsNullOrEmpty(Consumer["twilioAccountSid"]) &&
|
||||
!string.IsNullOrEmpty(Consumer["twilioAuthToken"]);
|
||||
}
|
||||
}
|
||||
|
||||
private AuthContext AuthContext { get; }
|
||||
private TenantUtil TenantUtil { get; }
|
||||
private SecurityContext SecurityContext { get; }
|
||||
private BaseCommonLinkUtility BaseCommonLinkUtility { get; }
|
||||
private ConsumerFactory ConsumerFactory { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -23,32 +23,31 @@
|
||||
*
|
||||
*/
|
||||
|
||||
namespace ASC.VoipService
|
||||
namespace ASC.VoipService;
|
||||
|
||||
public interface IVoipProvider
|
||||
{
|
||||
public interface IVoipProvider
|
||||
{
|
||||
IEnumerable<VoipPhone> GetExistingPhoneNumbers();
|
||||
IEnumerable<VoipPhone> GetExistingPhoneNumbers();
|
||||
|
||||
IEnumerable<VoipPhone> GetAvailablePhoneNumbers(PhoneNumberType phoneNumberType, string isoCountryCode);
|
||||
IEnumerable<VoipPhone> GetAvailablePhoneNumbers(PhoneNumberType phoneNumberType, string isoCountryCode);
|
||||
|
||||
VoipPhone BuyNumber(string phoneNumber);
|
||||
VoipPhone BuyNumber(string phoneNumber);
|
||||
|
||||
VoipPhone DeleteNumber(VoipPhone phone);
|
||||
VoipPhone DeleteNumber(VoipPhone phone);
|
||||
|
||||
VoipPhone GetPhone(VoipNumber r);
|
||||
VoipPhone GetPhone(VoipNumber r);
|
||||
|
||||
VoipPhone GetPhone(string id);
|
||||
VoipPhone GetPhone(string id);
|
||||
|
||||
VoipCall GetCall(string callId);
|
||||
VoipCall GetCall(string callId);
|
||||
|
||||
string GetToken(Agent agent, int seconds = 60 * 60 * 24);
|
||||
string GetToken(Agent agent, int seconds = 60 * 60 * 24);
|
||||
|
||||
void UpdateSettings(VoipPhone phone);
|
||||
void UpdateSettings(VoipPhone phone);
|
||||
|
||||
VoipRecord GetRecord(string callId, string recordId);
|
||||
VoipRecord GetRecord(string callId, string recordId);
|
||||
|
||||
void CreateQueue(VoipPhone newPhone);
|
||||
void CreateQueue(VoipPhone newPhone);
|
||||
|
||||
void DisablePhone(VoipPhone phone);
|
||||
}
|
||||
void DisablePhone(VoipPhone phone);
|
||||
}
|
||||
|
@ -27,8 +27,7 @@ namespace ASC.VoipService.Twilio
|
||||
{
|
||||
public class TwilioPhone : VoipPhone
|
||||
{
|
||||
private readonly TwilioRestClient twilio;
|
||||
|
||||
private readonly TwilioRestClient _twilio;
|
||||
public TwilioPhone(
|
||||
TwilioRestClient twilio,
|
||||
AuthContext authContext,
|
||||
@ -37,7 +36,7 @@ namespace ASC.VoipService.Twilio
|
||||
BaseCommonLinkUtility baseCommonLinkUtility) :
|
||||
base(authContext, tenantUtil, securityContext, baseCommonLinkUtility)
|
||||
{
|
||||
this.twilio = twilio;
|
||||
_twilio = twilio;
|
||||
Settings = new TwilioVoipSettings(authContext, tenantUtil, securityContext, baseCommonLinkUtility);
|
||||
}
|
||||
|
||||
@ -52,7 +51,7 @@ namespace ASC.VoipService.Twilio
|
||||
SendDigits = number.Length > 1 ? number[1] + "#" : string.Empty,
|
||||
Record = Settings.Caller.Record,
|
||||
Url = new System.Uri(Settings.Connect(contactId: contactId))
|
||||
}, twilio);
|
||||
}, _twilio);
|
||||
|
||||
return new VoipCall { Id = call.Sid, From = call.From, To = call.To };
|
||||
}
|
||||
@ -64,7 +63,7 @@ namespace ASC.VoipService.Twilio
|
||||
|
||||
public override VoipCall RedirectCall(string callId, string to)
|
||||
{
|
||||
var call = CallResource.Update(callId, url: new System.Uri(Settings.Redirect(to)), method: HttpMethod.Post, client: twilio);
|
||||
var call = CallResource.Update(callId, url: new System.Uri(Settings.Redirect(to)), method: HttpMethod.Post, client: _twilio);
|
||||
return new VoipCall { Id = call.Sid, To = to };
|
||||
}
|
||||
|
||||
@ -79,24 +78,24 @@ namespace ASC.VoipService.Twilio
|
||||
|
||||
public Queue CreateQueue(string name, int size, string waitUrl, int waitTime)
|
||||
{
|
||||
var queues = QueueResource.Read(new ReadQueueOptions(), twilio);
|
||||
var queues = QueueResource.Read(new ReadQueueOptions(), _twilio);
|
||||
var queue = queues.FirstOrDefault(r => r.FriendlyName == name);
|
||||
if (queue == null)
|
||||
{
|
||||
queue = QueueResource.Create(name, client: twilio);
|
||||
queue = QueueResource.Create(name, client: _twilio);
|
||||
}
|
||||
return new Queue(queue.Sid, name, size, waitUrl, waitTime);
|
||||
}
|
||||
|
||||
public string GetQueue(string name)
|
||||
{
|
||||
var queues = QueueResource.Read(new ReadQueueOptions(), twilio);
|
||||
var queues = QueueResource.Read(new ReadQueueOptions(), _twilio);
|
||||
return queues.First(r => r.FriendlyName == name).Sid;
|
||||
}
|
||||
|
||||
public IEnumerable<string> QueueCalls(string id)
|
||||
{
|
||||
var calls = MemberResource.Read(id, client: twilio);
|
||||
var calls = MemberResource.Read(id, client: _twilio);
|
||||
return calls.Select(r => r.CallSid);
|
||||
}
|
||||
|
||||
@ -106,7 +105,7 @@ namespace ASC.VoipService.Twilio
|
||||
if (calls.Contains(callId))
|
||||
{
|
||||
MemberResource.Update(queueId, callId, new System.Uri(Settings.Dequeue(reject)), HttpMethod.Post,
|
||||
client: twilio);
|
||||
client: _twilio);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,28 +31,27 @@ namespace ASC.VoipService.Twilio
|
||||
{
|
||||
public class TwilioProvider : IVoipProvider
|
||||
{
|
||||
private readonly string accountSid;
|
||||
private readonly string authToken;
|
||||
private readonly TwilioRestClient client;
|
||||
|
||||
private AuthContext AuthContext { get; }
|
||||
private TenantUtil TenantUtil { get; }
|
||||
private SecurityContext SecurityContext { get; }
|
||||
private BaseCommonLinkUtility BaseCommonLinkUtility { get; }
|
||||
private readonly string _accountSid;
|
||||
private readonly string _authToken;
|
||||
private readonly TwilioRestClient _client;
|
||||
private readonly AuthContext _authContext;
|
||||
private readonly TenantUtil _tenantUtil;
|
||||
private readonly SecurityContext _securityContext;
|
||||
private readonly BaseCommonLinkUtility _baseCommonLinkUtility;
|
||||
|
||||
public TwilioProvider(string accountSid, string authToken, AuthContext authContext, TenantUtil tenantUtil, SecurityContext securityContext, BaseCommonLinkUtility baseCommonLinkUtility)
|
||||
{
|
||||
if (string.IsNullOrEmpty(accountSid)) throw new ArgumentNullException(nameof(accountSid));
|
||||
if (string.IsNullOrEmpty(authToken)) throw new ArgumentNullException(nameof(authToken));
|
||||
|
||||
this.authToken = authToken;
|
||||
AuthContext = authContext;
|
||||
TenantUtil = tenantUtil;
|
||||
SecurityContext = securityContext;
|
||||
BaseCommonLinkUtility = baseCommonLinkUtility;
|
||||
this.accountSid = accountSid;
|
||||
_authToken = authToken;
|
||||
_authContext = authContext;
|
||||
_tenantUtil = tenantUtil;
|
||||
_securityContext = securityContext;
|
||||
_baseCommonLinkUtility = baseCommonLinkUtility;
|
||||
_accountSid = accountSid;
|
||||
|
||||
client = new TwilioRestClient(accountSid, authToken);
|
||||
_client = new TwilioRestClient(accountSid, authToken);
|
||||
}
|
||||
|
||||
#region Call
|
||||
@ -66,7 +65,7 @@ namespace ASC.VoipService.Twilio
|
||||
{
|
||||
try
|
||||
{
|
||||
var record = RecordingResource.Fetch(callId, recordSid, client: client);
|
||||
var record = RecordingResource.Fetch(callId, recordSid, client: _client);
|
||||
|
||||
if (!record.Price.HasValue)
|
||||
{
|
||||
@ -108,31 +107,31 @@ namespace ASC.VoipService.Twilio
|
||||
var newNumber = IncomingPhoneNumberResource.Create(
|
||||
new CreateIncomingPhoneNumberOptions
|
||||
{
|
||||
PathAccountSid = accountSid,
|
||||
PathAccountSid = _accountSid,
|
||||
PhoneNumber = new PhoneNumber(phoneNumber)
|
||||
}, client);
|
||||
}, _client);
|
||||
|
||||
return new TwilioPhone(client, AuthContext, TenantUtil, SecurityContext, BaseCommonLinkUtility) { Id = newNumber.Sid, Number = phoneNumber.Substring(1) };
|
||||
return new TwilioPhone(_client, _authContext, _tenantUtil, _securityContext, _baseCommonLinkUtility) { Id = newNumber.Sid, Number = phoneNumber.Substring(1) };
|
||||
}
|
||||
|
||||
public VoipPhone DeleteNumber(VoipPhone phone)
|
||||
{
|
||||
IncomingPhoneNumberResource.Delete(phone.Id, client: client);
|
||||
IncomingPhoneNumberResource.Delete(phone.Id, client: _client);
|
||||
return phone;
|
||||
}
|
||||
|
||||
public IEnumerable<VoipPhone> GetExistingPhoneNumbers()
|
||||
{
|
||||
var result = IncomingPhoneNumberResource.Read(client: client);
|
||||
return result.Select(r => new TwilioPhone(client, AuthContext, TenantUtil, SecurityContext, BaseCommonLinkUtility) { Id = r.Sid, Number = r.PhoneNumber.ToString() });
|
||||
var result = IncomingPhoneNumberResource.Read(client: _client);
|
||||
return result.Select(r => new TwilioPhone(_client, _authContext, _tenantUtil, _securityContext, _baseCommonLinkUtility) { Id = r.Sid, Number = r.PhoneNumber.ToString() });
|
||||
}
|
||||
|
||||
public IEnumerable<VoipPhone> GetAvailablePhoneNumbers(PhoneNumberType phoneNumberType, string isoCountryCode)
|
||||
{
|
||||
return phoneNumberType switch
|
||||
{
|
||||
PhoneNumberType.Local => LocalResource.Read(isoCountryCode, voiceEnabled: true, client: client).Select(r => new TwilioPhone(client, AuthContext, TenantUtil, SecurityContext, BaseCommonLinkUtility) { Number = r.PhoneNumber.ToString() }),
|
||||
PhoneNumberType.TollFree => TollFreeResource.Read(isoCountryCode, voiceEnabled: true, client: client).Select(r => new TwilioPhone(client, AuthContext, TenantUtil, SecurityContext, BaseCommonLinkUtility) { Number = r.PhoneNumber.ToString() }),
|
||||
PhoneNumberType.Local => LocalResource.Read(isoCountryCode, voiceEnabled: true, client: _client).Select(r => new TwilioPhone(_client, _authContext, _tenantUtil, _securityContext, _baseCommonLinkUtility) { Number = r.PhoneNumber.ToString() }),
|
||||
PhoneNumberType.TollFree => TollFreeResource.Read(isoCountryCode, voiceEnabled: true, client: _client).Select(r => new TwilioPhone(_client, _authContext, _tenantUtil, _securityContext, _baseCommonLinkUtility) { Number = r.PhoneNumber.ToString() }),
|
||||
|
||||
_ => new List<VoipPhone>(),
|
||||
};
|
||||
@ -140,13 +139,13 @@ namespace ASC.VoipService.Twilio
|
||||
|
||||
public VoipPhone GetPhone(string phoneSid)
|
||||
{
|
||||
var phone = IncomingPhoneNumberResource.Fetch(phoneSid, client: client);
|
||||
var phone = IncomingPhoneNumberResource.Fetch(phoneSid, client: _client);
|
||||
|
||||
var result = new TwilioPhone(client, AuthContext, TenantUtil, SecurityContext, BaseCommonLinkUtility)
|
||||
var result = new TwilioPhone(_client, _authContext, _tenantUtil, _securityContext, _baseCommonLinkUtility)
|
||||
{
|
||||
Id = phone.Sid,
|
||||
Number = phone.PhoneNumber.ToString(),
|
||||
Settings = new TwilioVoipSettings(AuthContext, TenantUtil, SecurityContext, BaseCommonLinkUtility)
|
||||
Settings = new TwilioVoipSettings(_authContext, _tenantUtil, _securityContext, _baseCommonLinkUtility)
|
||||
};
|
||||
|
||||
if (phone.VoiceUrl == null)
|
||||
@ -159,12 +158,12 @@ namespace ASC.VoipService.Twilio
|
||||
|
||||
public VoipPhone GetPhone(VoipNumber data)
|
||||
{
|
||||
return new TwilioPhone(client, AuthContext, TenantUtil, SecurityContext, BaseCommonLinkUtility)
|
||||
return new TwilioPhone(_client, _authContext, _tenantUtil, _securityContext, _baseCommonLinkUtility)
|
||||
{
|
||||
Id = data.Id,
|
||||
Number = data.Number,
|
||||
Alias = data.Alias,
|
||||
Settings = new TwilioVoipSettings(data.Settings, AuthContext)
|
||||
Settings = new TwilioVoipSettings(data.Settings, _authContext)
|
||||
};
|
||||
}
|
||||
|
||||
@ -177,7 +176,7 @@ namespace ASC.VoipService.Twilio
|
||||
{
|
||||
try
|
||||
{
|
||||
var call = CallResource.Fetch(result.Id, client: client);
|
||||
var call = CallResource.Fetch(result.Id, client: _client);
|
||||
if (!call.Price.HasValue || string.IsNullOrEmpty(call.Duration))
|
||||
{
|
||||
count--;
|
||||
@ -205,19 +204,19 @@ namespace ASC.VoipService.Twilio
|
||||
{
|
||||
new IncomingClientScope(agent.ClientID)
|
||||
};
|
||||
var capability = new ClientCapability(accountSid, authToken, scopes: scopes);
|
||||
var capability = new ClientCapability(_accountSid, _authToken, scopes: scopes);
|
||||
|
||||
return capability.ToJwt();
|
||||
}
|
||||
|
||||
public void UpdateSettings(VoipPhone phone)
|
||||
{
|
||||
IncomingPhoneNumberResource.Update(phone.Id, voiceUrl: new Uri(phone.Settings.Connect(false)), client: client);
|
||||
IncomingPhoneNumberResource.Update(phone.Id, voiceUrl: new Uri(phone.Settings.Connect(false)), client: _client);
|
||||
}
|
||||
|
||||
public void DisablePhone(VoipPhone phone)
|
||||
{
|
||||
IncomingPhoneNumberResource.Update(phone.Id, voiceUrl: new Uri("https://demo.twilio.com/welcome/voice/"), client: client);
|
||||
IncomingPhoneNumberResource.Update(phone.Id, voiceUrl: new Uri("https://demo.twilio.com/welcome/voice/"), client: _client);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -23,189 +23,187 @@
|
||||
*
|
||||
*/
|
||||
|
||||
namespace ASC.VoipService.Twilio
|
||||
namespace ASC.VoipService.Twilio;
|
||||
|
||||
public class TwilioResponseHelper
|
||||
{
|
||||
public class TwilioResponseHelper
|
||||
private readonly VoipSettings _settings;
|
||||
private readonly string _baseUrl;
|
||||
private readonly AuthContext _authContext;
|
||||
private readonly TenantUtil _tenantUtil;
|
||||
private readonly SecurityContext _securityContext;
|
||||
|
||||
public TwilioResponseHelper(
|
||||
VoipSettings settings,
|
||||
string baseUrl,
|
||||
AuthContext authContext,
|
||||
TenantUtil tenantUtil,
|
||||
SecurityContext securityContext)
|
||||
{
|
||||
private readonly VoipSettings settings;
|
||||
private readonly string baseUrl;
|
||||
_settings = settings;
|
||||
_authContext = authContext;
|
||||
_tenantUtil = tenantUtil;
|
||||
_securityContext = securityContext;
|
||||
_baseUrl = baseUrl.TrimEnd('/') + "/twilio/";
|
||||
}
|
||||
|
||||
private AuthContext AuthContext { get; }
|
||||
private TenantUtil TenantUtil { get; }
|
||||
private SecurityContext SecurityContext { get; }
|
||||
public VoiceResponse Inbound(Tuple<Agent, bool> agentTuple)
|
||||
{
|
||||
var agent = agentTuple?.Item1;
|
||||
var anyOnline = agentTuple != null && agentTuple.Item2;
|
||||
var response = new VoiceResponse();
|
||||
|
||||
public TwilioResponseHelper(
|
||||
VoipSettings settings,
|
||||
string baseUrl,
|
||||
AuthContext authContext,
|
||||
TenantUtil tenantUtil,
|
||||
SecurityContext securityContext)
|
||||
if (_settings.WorkingHours != null && _settings.WorkingHours.Enabled)
|
||||
{
|
||||
this.settings = settings;
|
||||
AuthContext = authContext;
|
||||
TenantUtil = tenantUtil;
|
||||
SecurityContext = securityContext;
|
||||
this.baseUrl = baseUrl.TrimEnd('/') + "/twilio/";
|
||||
var now = _tenantUtil.DateTimeFromUtc(DateTime.UtcNow);
|
||||
if (!(_settings.WorkingHours.From <= now.TimeOfDay && _settings.WorkingHours.To >= now.TimeOfDay))
|
||||
{
|
||||
return AddVoiceMail(response);
|
||||
}
|
||||
}
|
||||
|
||||
public VoiceResponse Inbound(Tuple<Agent, bool> agentTuple)
|
||||
if (anyOnline)
|
||||
{
|
||||
var agent = agentTuple?.Item1;
|
||||
var anyOnline = agentTuple != null && agentTuple.Item2;
|
||||
var response = new VoiceResponse();
|
||||
|
||||
if (settings.WorkingHours != null && settings.WorkingHours.Enabled)
|
||||
if (!string.IsNullOrEmpty(_settings.GreetingAudio))
|
||||
{
|
||||
var now = TenantUtil.DateTimeFromUtc(DateTime.UtcNow);
|
||||
if (!(settings.WorkingHours.From <= now.TimeOfDay && settings.WorkingHours.To >= now.TimeOfDay))
|
||||
{
|
||||
return AddVoiceMail(response);
|
||||
}
|
||||
response.Play(Uri.EscapeDataString(_settings.GreetingAudio));
|
||||
}
|
||||
|
||||
if (anyOnline)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(settings.GreetingAudio))
|
||||
{
|
||||
response.Play(Uri.EscapeDataString(settings.GreetingAudio));
|
||||
}
|
||||
|
||||
response.Enqueue(settings.Queue.Name, GetEcho("Enqueue", agent != null), "POST",
|
||||
GetEcho("Wait", agent != null), "POST");
|
||||
}
|
||||
|
||||
return AddVoiceMail(response);
|
||||
response.Enqueue(_settings.Queue.Name, GetEcho("Enqueue", agent != null), "POST",
|
||||
GetEcho("Wait", agent != null), "POST");
|
||||
}
|
||||
|
||||
public VoiceResponse Outbound()
|
||||
return AddVoiceMail(response);
|
||||
}
|
||||
|
||||
public VoiceResponse Outbound()
|
||||
{
|
||||
return !_settings.Caller.AllowOutgoingCalls
|
||||
? new VoiceResponse()
|
||||
: AddToResponse(new VoiceResponse(), _settings.Caller);
|
||||
}
|
||||
|
||||
public VoiceResponse Dial()
|
||||
{
|
||||
return new VoiceResponse();
|
||||
}
|
||||
|
||||
public VoiceResponse Queue()
|
||||
{
|
||||
return new VoiceResponse();
|
||||
}
|
||||
|
||||
public VoiceResponse Enqueue(string queueResult)
|
||||
{
|
||||
return queueResult == "leave" ? AddVoiceMail(new VoiceResponse()) : new VoiceResponse();
|
||||
}
|
||||
|
||||
public VoiceResponse Dequeue()
|
||||
{
|
||||
return AddToResponse(new VoiceResponse(), _settings.Caller);
|
||||
}
|
||||
|
||||
public VoiceResponse Leave()
|
||||
{
|
||||
return AddVoiceMail(new VoiceResponse());
|
||||
}
|
||||
|
||||
public VoiceResponse Wait(string queueTime, string queueSize)
|
||||
{
|
||||
var response = new VoiceResponse();
|
||||
var queue = _settings.Queue;
|
||||
|
||||
if (Convert.ToInt32(queueTime) > queue.WaitTime || Convert.ToInt32(queueSize) > queue.Size) return response.Leave();
|
||||
|
||||
if (!string.IsNullOrEmpty(queue.WaitUrl))
|
||||
{
|
||||
return !settings.Caller.AllowOutgoingCalls
|
||||
? new VoiceResponse()
|
||||
: AddToResponse(new VoiceResponse(), settings.Caller);
|
||||
var gather = new Gather(method: "POST", action: GetEcho("gatherQueue"));
|
||||
gather.Play(Uri.EscapeDataString(queue.WaitUrl));
|
||||
response.Gather(gather);
|
||||
}
|
||||
|
||||
public VoiceResponse Dial()
|
||||
else
|
||||
{
|
||||
return new VoiceResponse();
|
||||
response.Pause(queue.WaitTime);
|
||||
}
|
||||
|
||||
public VoiceResponse Queue()
|
||||
return response;
|
||||
}
|
||||
|
||||
public VoiceResponse GatherQueue(string digits, List<Agent> availableOperators)
|
||||
{
|
||||
var response = new VoiceResponse();
|
||||
|
||||
if (digits == "#") return AddVoiceMail(response);
|
||||
|
||||
var oper = _settings.Operators.Find(r => r.PostFix == digits && availableOperators.Contains(r)) ??
|
||||
_settings.Operators.FirstOrDefault(r => availableOperators.Contains(r));
|
||||
|
||||
return oper != null ? AddToResponse(response, oper) : response;
|
||||
}
|
||||
|
||||
public VoiceResponse Redirect(string to)
|
||||
{
|
||||
if (to == "hold")
|
||||
{
|
||||
return new VoiceResponse();
|
||||
return new VoiceResponse().Play(Uri.EscapeDataString(_settings.HoldAudio), 0);
|
||||
}
|
||||
|
||||
public VoiceResponse Enqueue(string queueResult)
|
||||
|
||||
if (Guid.TryParse(to, out var newCallerId))
|
||||
{
|
||||
return queueResult == "leave" ? AddVoiceMail(new VoiceResponse()) : new VoiceResponse();
|
||||
_securityContext.AuthenticateMeWithoutCookie(newCallerId);
|
||||
}
|
||||
|
||||
public VoiceResponse Dequeue()
|
||||
return new VoiceResponse().Enqueue(_settings.Queue.Name, GetEcho("enqueue"), "POST",
|
||||
GetEcho("wait") + "&RedirectTo=" + to, "POST");
|
||||
}
|
||||
|
||||
public VoiceResponse VoiceMail()
|
||||
{
|
||||
return new VoiceResponse();
|
||||
}
|
||||
|
||||
private VoiceResponse AddToResponse(VoiceResponse response, Agent agent)
|
||||
{
|
||||
var dial = new Dial(method: "POST", action: GetEcho("dial"), timeout: agent.TimeOut, record: agent.Record ? "record-from-answer" : "do-not-record");
|
||||
|
||||
switch (agent.Answer)
|
||||
{
|
||||
return AddToResponse(new VoiceResponse(), settings.Caller);
|
||||
case AnswerType.Number:
|
||||
response.Dial(dial.Number(agent.PhoneNumber, method: "POST", url: GetEcho("client")));
|
||||
break;
|
||||
case AnswerType.Client:
|
||||
response.Dial(dial.Client(agent.ClientID, "POST", GetEcho("client")));
|
||||
break;
|
||||
case AnswerType.Sip:
|
||||
response.Dial(dial.Sip(agent.ClientID, method: "POST", url: GetEcho("client")));
|
||||
break;
|
||||
}
|
||||
|
||||
public VoiceResponse Leave()
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
private VoiceResponse AddVoiceMail(VoiceResponse response)
|
||||
{
|
||||
return string.IsNullOrEmpty(_settings.VoiceMail)
|
||||
? response.Say("")
|
||||
: response.Play(Uri.EscapeDataString(_settings.VoiceMail)).Record(method: "POST", action: GetEcho("voiceMail"), maxLength: 30);
|
||||
}
|
||||
|
||||
public string GetEcho(string action, bool user = true)
|
||||
{
|
||||
var result = _baseUrl.TrimEnd('/');
|
||||
|
||||
if (!string.IsNullOrEmpty(action))
|
||||
{
|
||||
return AddVoiceMail(new VoiceResponse());
|
||||
result += "/" + action.TrimStart('/');
|
||||
}
|
||||
|
||||
public VoiceResponse Wait(string queueTime, string queueSize)
|
||||
if (user)
|
||||
{
|
||||
var response = new VoiceResponse();
|
||||
var queue = settings.Queue;
|
||||
|
||||
if (Convert.ToInt32(queueTime) > queue.WaitTime || Convert.ToInt32(queueSize) > queue.Size) return response.Leave();
|
||||
|
||||
if (!string.IsNullOrEmpty(queue.WaitUrl))
|
||||
{
|
||||
var gather = new Gather(method: "POST", action: GetEcho("gatherQueue"));
|
||||
gather.Play(Uri.EscapeDataString(queue.WaitUrl));
|
||||
response.Gather(gather);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.Pause(queue.WaitTime);
|
||||
}
|
||||
|
||||
return response;
|
||||
result += "?CallerId=" + _authContext.CurrentAccount.ID;
|
||||
}
|
||||
|
||||
public VoiceResponse GatherQueue(string digits, List<Agent> availableOperators)
|
||||
{
|
||||
var response = new VoiceResponse();
|
||||
|
||||
if (digits == "#") return AddVoiceMail(response);
|
||||
|
||||
var oper = settings.Operators.Find(r => r.PostFix == digits && availableOperators.Contains(r)) ??
|
||||
settings.Operators.FirstOrDefault(r => availableOperators.Contains(r));
|
||||
|
||||
return oper != null ? AddToResponse(response, oper) : response;
|
||||
}
|
||||
|
||||
public VoiceResponse Redirect(string to)
|
||||
{
|
||||
if (to == "hold")
|
||||
{
|
||||
return new VoiceResponse().Play(Uri.EscapeDataString(settings.HoldAudio), 0);
|
||||
}
|
||||
|
||||
|
||||
if (Guid.TryParse(to, out var newCallerId))
|
||||
{
|
||||
SecurityContext.AuthenticateMeWithoutCookie(newCallerId);
|
||||
}
|
||||
|
||||
return new VoiceResponse().Enqueue(settings.Queue.Name, GetEcho("enqueue"), "POST",
|
||||
GetEcho("wait") + "&RedirectTo=" + to, "POST");
|
||||
}
|
||||
|
||||
public VoiceResponse VoiceMail()
|
||||
{
|
||||
return new VoiceResponse();
|
||||
}
|
||||
|
||||
private VoiceResponse AddToResponse(VoiceResponse response, Agent agent)
|
||||
{
|
||||
var dial = new Dial(method: "POST", action: GetEcho("dial"), timeout: agent.TimeOut, record: agent.Record ? "record-from-answer" : "do-not-record");
|
||||
|
||||
switch (agent.Answer)
|
||||
{
|
||||
case AnswerType.Number:
|
||||
response.Dial(dial.Number(agent.PhoneNumber, method: "POST", url: GetEcho("client")));
|
||||
break;
|
||||
case AnswerType.Client:
|
||||
response.Dial(dial.Client(agent.ClientID, "POST", GetEcho("client")));
|
||||
break;
|
||||
case AnswerType.Sip:
|
||||
response.Dial(dial.Sip(agent.ClientID, method: "POST", url: GetEcho("client")));
|
||||
break;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
private VoiceResponse AddVoiceMail(VoiceResponse response)
|
||||
{
|
||||
return string.IsNullOrEmpty(settings.VoiceMail)
|
||||
? response.Say("")
|
||||
: response.Play(Uri.EscapeDataString(settings.VoiceMail)).Record(method: "POST", action: GetEcho("voiceMail"), maxLength: 30);
|
||||
}
|
||||
|
||||
public string GetEcho(string action, bool user = true)
|
||||
{
|
||||
var result = baseUrl.TrimEnd('/');
|
||||
|
||||
if (!string.IsNullOrEmpty(action))
|
||||
{
|
||||
result += "/" + action.TrimStart('/');
|
||||
}
|
||||
if (user)
|
||||
{
|
||||
result += "?CallerId=" + AuthContext.CurrentAccount.ID;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -26,58 +26,57 @@
|
||||
|
||||
using Uri = System.Uri;
|
||||
|
||||
namespace ASC.VoipService.Twilio
|
||||
namespace ASC.VoipService.Twilio;
|
||||
|
||||
public class TwilioVoipSettings : VoipSettings
|
||||
{
|
||||
public class TwilioVoipSettings : VoipSettings
|
||||
public TwilioVoipSettings(
|
||||
AuthContext authContext,
|
||||
TenantUtil tenantUtil,
|
||||
SecurityContext securityContext,
|
||||
BaseCommonLinkUtility baseCommonLinkUtility) :
|
||||
base(authContext, tenantUtil, securityContext, baseCommonLinkUtility)
|
||||
{ }
|
||||
|
||||
public TwilioVoipSettings(
|
||||
Uri voiceUrl,
|
||||
AuthContext authContext,
|
||||
TenantUtil tenantUtil,
|
||||
SecurityContext securityContext,
|
||||
BaseCommonLinkUtility baseCommonLinkUtility) :
|
||||
this(authContext, tenantUtil, securityContext, baseCommonLinkUtility)
|
||||
{
|
||||
public TwilioVoipSettings(
|
||||
AuthContext authContext,
|
||||
TenantUtil tenantUtil,
|
||||
SecurityContext securityContext,
|
||||
BaseCommonLinkUtility baseCommonLinkUtility) :
|
||||
base(authContext, tenantUtil, securityContext, baseCommonLinkUtility)
|
||||
{ }
|
||||
if (string.IsNullOrEmpty(voiceUrl.Query)) return;
|
||||
|
||||
public TwilioVoipSettings(
|
||||
Uri voiceUrl,
|
||||
AuthContext authContext,
|
||||
TenantUtil tenantUtil,
|
||||
SecurityContext securityContext,
|
||||
BaseCommonLinkUtility baseCommonLinkUtility) :
|
||||
this(authContext, tenantUtil, securityContext, baseCommonLinkUtility)
|
||||
JsonSettings = Encoding.UTF8.GetString(Convert.FromBase64String(HttpUtility.UrlDecode(HttpUtility.ParseQueryString(voiceUrl.Query)["settings"])));
|
||||
}
|
||||
|
||||
public TwilioVoipSettings(string settings, AuthContext authContext) : base(settings, authContext)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Connect(bool user = true, string contactId = null)
|
||||
{
|
||||
var result = GetEcho("", user);
|
||||
if (!string.IsNullOrEmpty(contactId))
|
||||
{
|
||||
if (string.IsNullOrEmpty(voiceUrl.Query)) return;
|
||||
|
||||
JsonSettings = Encoding.UTF8.GetString(Convert.FromBase64String(HttpUtility.UrlDecode(HttpUtility.ParseQueryString(voiceUrl.Query)["settings"])));
|
||||
result += "&ContactId=" + contactId;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public TwilioVoipSettings(string settings, AuthContext authContext) : base(settings, authContext)
|
||||
{
|
||||
}
|
||||
public override string Redirect(string to)
|
||||
{
|
||||
return GetEcho("redirect") + "&RedirectTo=" + to;
|
||||
}
|
||||
|
||||
public override string Connect(bool user = true, string contactId = null)
|
||||
{
|
||||
var result = GetEcho("", user);
|
||||
if (!string.IsNullOrEmpty(contactId))
|
||||
{
|
||||
result += "&ContactId=" + contactId;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public override string Dequeue(bool reject)
|
||||
{
|
||||
return GetEcho("dequeue") + "&Reject=" + reject;
|
||||
}
|
||||
|
||||
public override string Redirect(string to)
|
||||
{
|
||||
return GetEcho("redirect") + "&RedirectTo=" + to;
|
||||
}
|
||||
|
||||
public override string Dequeue(bool reject)
|
||||
{
|
||||
return GetEcho("dequeue") + "&Reject=" + reject;
|
||||
}
|
||||
|
||||
private string GetEcho(string method, bool user = true)
|
||||
{
|
||||
return new TwilioResponseHelper(this, BaseCommonLinkUtility.GetFullAbsolutePath(""), AuthContext, TenantUtil, SecurityContext).GetEcho(method, user);
|
||||
}
|
||||
private string GetEcho(string method, bool user = true)
|
||||
{
|
||||
return new TwilioResponseHelper(this, BaseCommonLinkUtility.GetFullAbsolutePath(""), AuthContext, TenantUtil, SecurityContext).GetEcho(method, user);
|
||||
}
|
||||
}
|
||||
|
@ -23,54 +23,53 @@
|
||||
*
|
||||
*/
|
||||
|
||||
namespace ASC.VoipService
|
||||
namespace ASC.VoipService;
|
||||
|
||||
public class VoipCall
|
||||
{
|
||||
public class VoipCall
|
||||
public string Id { get; set; }
|
||||
|
||||
public string ParentID { get; set; }
|
||||
|
||||
public string From { get; set; }
|
||||
|
||||
public string To { get; set; }
|
||||
|
||||
public Guid AnsweredBy { get; set; }
|
||||
|
||||
public DateTime DialDate { get; set; }
|
||||
|
||||
public int DialDuration { get; set; }
|
||||
|
||||
public VoipCallStatus? Status { get; set; }
|
||||
|
||||
public decimal Price { get; set; }
|
||||
|
||||
public int ContactId { get; set; }
|
||||
|
||||
public bool ContactIsCompany { get; set; }
|
||||
|
||||
public string ContactTitle { get; set; }
|
||||
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
public DateTime EndDialDate { get; set; }
|
||||
|
||||
public VoipRecord VoipRecord { get; set; }
|
||||
|
||||
public List<VoipCall> ChildCalls { get; set; }
|
||||
|
||||
public VoipCall()
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public string ParentID { get; set; }
|
||||
|
||||
public string From { get; set; }
|
||||
|
||||
public string To { get; set; }
|
||||
|
||||
public Guid AnsweredBy { get; set; }
|
||||
|
||||
public DateTime DialDate { get; set; }
|
||||
|
||||
public int DialDuration { get; set; }
|
||||
|
||||
public VoipCallStatus? Status { get; set; }
|
||||
|
||||
public decimal Price { get; set; }
|
||||
|
||||
public int ContactId { get; set; }
|
||||
|
||||
public bool ContactIsCompany { get; set; }
|
||||
|
||||
public string ContactTitle { get; set; }
|
||||
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
public DateTime EndDialDate { get; set; }
|
||||
|
||||
public VoipRecord VoipRecord { get; set; }
|
||||
|
||||
public List<VoipCall> ChildCalls { get; set; }
|
||||
|
||||
public VoipCall()
|
||||
{
|
||||
ChildCalls = new List<VoipCall>();
|
||||
VoipRecord = new VoipRecord();
|
||||
}
|
||||
ChildCalls = new List<VoipCall>();
|
||||
VoipRecord = new VoipRecord();
|
||||
}
|
||||
}
|
||||
|
||||
public enum VoipCallStatus
|
||||
{
|
||||
Incoming,
|
||||
Outcoming,
|
||||
Answered,
|
||||
Missed
|
||||
}
|
||||
public enum VoipCallStatus
|
||||
{
|
||||
Incoming,
|
||||
Outcoming,
|
||||
Answered,
|
||||
Missed
|
||||
}
|
@ -23,142 +23,137 @@
|
||||
*
|
||||
*/
|
||||
|
||||
namespace ASC.VoipService
|
||||
namespace ASC.VoipService;
|
||||
|
||||
public class Agent
|
||||
{
|
||||
public class Agent
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public AnswerType Answer { get; set; }
|
||||
|
||||
public string ClientID { get { return PhoneNumber + PostFix; } }
|
||||
|
||||
public bool Record { get; set; }
|
||||
|
||||
public int TimeOut { get; set; }
|
||||
|
||||
public AgentStatus Status { get; set; }
|
||||
|
||||
public bool AllowOutgoingCalls { get; set; }
|
||||
|
||||
public string PostFix { get; set; }
|
||||
|
||||
public string PhoneNumber { get; set; }
|
||||
|
||||
public string RedirectToNumber { get; set; }
|
||||
|
||||
public Agent()
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public AnswerType Answer { get; set; }
|
||||
|
||||
public string ClientID { get { return PhoneNumber + PostFix; } }
|
||||
|
||||
public bool Record { get; set; }
|
||||
|
||||
public int TimeOut { get; set; }
|
||||
|
||||
public AgentStatus Status { get; set; }
|
||||
|
||||
public bool AllowOutgoingCalls { get; set; }
|
||||
|
||||
public string PostFix { get; set; }
|
||||
|
||||
public string PhoneNumber { get; set; }
|
||||
|
||||
public string RedirectToNumber { get; set; }
|
||||
|
||||
public Agent()
|
||||
{
|
||||
Status = AgentStatus.Offline;
|
||||
TimeOut = 30;
|
||||
AllowOutgoingCalls = true;
|
||||
Record = true;
|
||||
}
|
||||
|
||||
public Agent(Guid id, AnswerType answer, VoipPhone phone, string postFix)
|
||||
: this()
|
||||
{
|
||||
Id = id;
|
||||
Answer = answer;
|
||||
PhoneNumber = phone.Number;
|
||||
AllowOutgoingCalls = phone.Settings.AllowOutgoingCalls;
|
||||
Record = phone.Settings.Record;
|
||||
PostFix = postFix;
|
||||
}
|
||||
Status = AgentStatus.Offline;
|
||||
TimeOut = 30;
|
||||
AllowOutgoingCalls = true;
|
||||
Record = true;
|
||||
}
|
||||
|
||||
public class Queue
|
||||
public Agent(Guid id, AnswerType answer, VoipPhone phone, string postFix)
|
||||
: this()
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public int Size { get; set; }
|
||||
public string WaitUrl { get; set; }
|
||||
public int WaitTime { get; set; }
|
||||
|
||||
public Queue() { }
|
||||
|
||||
public Queue(string id, string name, int size, string waitUrl, int waitTime)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
WaitUrl = waitUrl;
|
||||
WaitTime = waitTime;
|
||||
Size = size;
|
||||
}
|
||||
Id = id;
|
||||
Answer = answer;
|
||||
PhoneNumber = phone.Number;
|
||||
AllowOutgoingCalls = phone.Settings.AllowOutgoingCalls;
|
||||
Record = phone.Settings.Record;
|
||||
PostFix = postFix;
|
||||
}
|
||||
|
||||
public sealed class WorkingHours
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public TimeSpan? From { get; set; }
|
||||
public TimeSpan? To { get; set; }
|
||||
|
||||
public WorkingHours() { }
|
||||
|
||||
public WorkingHours(TimeSpan from, TimeSpan to)
|
||||
{
|
||||
From = from;
|
||||
To = to;
|
||||
}
|
||||
|
||||
|
||||
private bool Equals(WorkingHours other)
|
||||
{
|
||||
return Enabled.Equals(other.Enabled) && From.Equals(other.From) && To.Equals(other.To);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is null) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != GetType()) return false;
|
||||
return Equals((WorkingHours)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Enabled, From, To);
|
||||
}
|
||||
}
|
||||
|
||||
public class VoipUpload
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Path { get; set; }
|
||||
public AudioType AudioType { get; set; }
|
||||
public bool IsDefault { get; set; }
|
||||
}
|
||||
|
||||
#region Enum
|
||||
|
||||
public enum AnswerType
|
||||
{
|
||||
Number,
|
||||
Sip,
|
||||
Client
|
||||
}
|
||||
|
||||
public enum GreetingMessageVoice
|
||||
{
|
||||
Man,
|
||||
Woman,
|
||||
Alice
|
||||
}
|
||||
|
||||
public enum AgentStatus
|
||||
{
|
||||
Online,
|
||||
Paused,
|
||||
Offline
|
||||
}
|
||||
|
||||
public enum AudioType
|
||||
{
|
||||
Greeting,
|
||||
HoldUp,
|
||||
VoiceMail,
|
||||
Queue
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class Queue
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public int Size { get; set; }
|
||||
public string WaitUrl { get; set; }
|
||||
public int WaitTime { get; set; }
|
||||
|
||||
public Queue() { }
|
||||
|
||||
public Queue(string id, string name, int size, string waitUrl, int waitTime)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
WaitUrl = waitUrl;
|
||||
WaitTime = waitTime;
|
||||
Size = size;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class WorkingHours
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public TimeSpan? From { get; set; }
|
||||
public TimeSpan? To { get; set; }
|
||||
|
||||
public WorkingHours() { }
|
||||
|
||||
public WorkingHours(TimeSpan from, TimeSpan to)
|
||||
{
|
||||
From = from;
|
||||
To = to;
|
||||
}
|
||||
|
||||
|
||||
private bool Equals(WorkingHours other)
|
||||
{
|
||||
return Enabled.Equals(other.Enabled) && From.Equals(other.From) && To.Equals(other.To);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is null) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != GetType()) return false;
|
||||
return Equals((WorkingHours)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Enabled, From, To);
|
||||
}
|
||||
}
|
||||
|
||||
public class VoipUpload
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Path { get; set; }
|
||||
public AudioType AudioType { get; set; }
|
||||
public bool IsDefault { get; set; }
|
||||
}
|
||||
|
||||
public enum AnswerType
|
||||
{
|
||||
Number,
|
||||
Sip,
|
||||
Client
|
||||
}
|
||||
|
||||
public enum GreetingMessageVoice
|
||||
{
|
||||
Man,
|
||||
Woman,
|
||||
Alice
|
||||
}
|
||||
|
||||
public enum AgentStatus
|
||||
{
|
||||
Online,
|
||||
Paused,
|
||||
Offline
|
||||
}
|
||||
|
||||
public enum AudioType
|
||||
{
|
||||
Greeting,
|
||||
HoldUp,
|
||||
VoiceMail,
|
||||
Queue
|
||||
}
|
@ -23,63 +23,62 @@
|
||||
*
|
||||
*/
|
||||
|
||||
namespace ASC.VoipService
|
||||
namespace ASC.VoipService;
|
||||
|
||||
public class VoipPhone
|
||||
{
|
||||
public class VoipPhone
|
||||
public string Id { get; set; }
|
||||
public string Number { get; set; }
|
||||
public string Alias { get; set; }
|
||||
public VoipSettings Settings { get; set; }
|
||||
public Agent Caller
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Number { get; set; }
|
||||
public string Alias { get; set; }
|
||||
public VoipSettings Settings { get; set; }
|
||||
public Agent Caller
|
||||
{
|
||||
get { return Settings.Caller; }
|
||||
}
|
||||
|
||||
public VoipPhone(AuthContext authContext, TenantUtil tenantUtil, SecurityContext securityContext, BaseCommonLinkUtility baseCommonLinkUtility)
|
||||
{
|
||||
Settings = new VoipSettings(authContext, tenantUtil, securityContext, baseCommonLinkUtility);
|
||||
}
|
||||
|
||||
public virtual VoipCall Call(string to, string contactId = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual VoipCall LocalCall(string to)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual VoipCall RedirectCall(string callId, string to)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual VoipCall HoldUp(string callId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual void AnswerQueueCall(string callId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual void RejectQueueCall(string callId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
get { return Settings.Caller; }
|
||||
}
|
||||
|
||||
public class VoipRecord
|
||||
public VoipPhone(AuthContext authContext, TenantUtil tenantUtil, SecurityContext securityContext, BaseCommonLinkUtility baseCommonLinkUtility)
|
||||
{
|
||||
public string Id { get; set; }
|
||||
Settings = new VoipSettings(authContext, tenantUtil, securityContext, baseCommonLinkUtility);
|
||||
}
|
||||
|
||||
public string Uri { get; set; }
|
||||
public virtual VoipCall Call(string to, string contactId = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int Duration { get; set; }
|
||||
public virtual VoipCall LocalCall(string to)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public decimal Price { get; set; }
|
||||
public virtual VoipCall RedirectCall(string callId, string to)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual VoipCall HoldUp(string callId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual void AnswerQueueCall(string callId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual void RejectQueueCall(string callId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class VoipRecord
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public string Uri { get; set; }
|
||||
|
||||
public int Duration { get; set; }
|
||||
|
||||
public decimal Price { get; set; }
|
||||
}
|
@ -23,165 +23,164 @@
|
||||
*
|
||||
*/
|
||||
|
||||
namespace ASC.VoipService
|
||||
namespace ASC.VoipService;
|
||||
|
||||
public class VoipSettings
|
||||
{
|
||||
public class VoipSettings
|
||||
public string VoiceUrl { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<Agent> Operators { get; set; }
|
||||
|
||||
public Queue Queue { get; set; }
|
||||
|
||||
public Agent Caller { get { return Operators.FirstOrDefault(r => r.Id == AuthContext.CurrentAccount.ID); } }
|
||||
|
||||
public WorkingHours WorkingHours { get; set; }
|
||||
|
||||
public string VoiceMail { get; set; }
|
||||
|
||||
public string GreetingAudio { get; set; }
|
||||
|
||||
public string HoldAudio { get; set; }
|
||||
|
||||
public bool AllowOutgoingCalls { get; set; }
|
||||
|
||||
public bool Pause { get; set; }
|
||||
|
||||
public bool Record { get; set; }
|
||||
|
||||
internal string JsonSettings
|
||||
{
|
||||
public string VoiceUrl { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<Agent> Operators { get; set; }
|
||||
|
||||
public Queue Queue { get; set; }
|
||||
|
||||
public Agent Caller { get { return Operators.FirstOrDefault(r => r.Id == AuthContext.CurrentAccount.ID); } }
|
||||
|
||||
public WorkingHours WorkingHours { get; set; }
|
||||
|
||||
public string VoiceMail { get; set; }
|
||||
|
||||
public string GreetingAudio { get; set; }
|
||||
|
||||
public string HoldAudio { get; set; }
|
||||
|
||||
public bool AllowOutgoingCalls { get; set; }
|
||||
|
||||
public bool Pause { get; set; }
|
||||
|
||||
public bool Record { get; set; }
|
||||
|
||||
internal string JsonSettings
|
||||
get
|
||||
{
|
||||
get
|
||||
return JsonConvert.SerializeObject(
|
||||
new
|
||||
{
|
||||
Operators,
|
||||
GreetingAudio,
|
||||
Name,
|
||||
Queue,
|
||||
WorkingHours,
|
||||
VoiceMail,
|
||||
HoldAudio,
|
||||
AllowOutgoingCalls,
|
||||
Pause,
|
||||
Record
|
||||
},
|
||||
new JsonSerializerSettings { ContractResolver = CustomSerializeContractResolver.Instance });
|
||||
}
|
||||
set
|
||||
{
|
||||
try
|
||||
{
|
||||
return JsonConvert.SerializeObject(
|
||||
new
|
||||
{
|
||||
Operators,
|
||||
GreetingAudio,
|
||||
Name,
|
||||
Queue,
|
||||
WorkingHours,
|
||||
VoiceMail,
|
||||
HoldAudio,
|
||||
AllowOutgoingCalls,
|
||||
Pause,
|
||||
Record
|
||||
},
|
||||
new JsonSerializerSettings { ContractResolver = CustomSerializeContractResolver.Instance });
|
||||
var settings = JsonConvert.DeserializeObject<VoipSettings>(value, new JsonSerializerSettings { ContractResolver = CustomSerializeContractResolver.Instance });
|
||||
|
||||
Operators = settings.Operators ?? new List<Agent>();
|
||||
Name = settings.Name;
|
||||
Queue = settings.Queue;
|
||||
WorkingHours = settings.WorkingHours;
|
||||
GreetingAudio = settings.GreetingAudio;
|
||||
VoiceMail = settings.VoiceMail;
|
||||
HoldAudio = settings.HoldAudio;
|
||||
AllowOutgoingCalls = settings.AllowOutgoingCalls;
|
||||
Pause = settings.Pause;
|
||||
Record = settings.Record;
|
||||
}
|
||||
set
|
||||
catch (Exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = JsonConvert.DeserializeObject<VoipSettings>(value, new JsonSerializerSettings { ContractResolver = CustomSerializeContractResolver.Instance });
|
||||
|
||||
Operators = settings.Operators ?? new List<Agent>();
|
||||
Name = settings.Name;
|
||||
Queue = settings.Queue;
|
||||
WorkingHours = settings.WorkingHours;
|
||||
GreetingAudio = settings.GreetingAudio;
|
||||
VoiceMail = settings.VoiceMail;
|
||||
HoldAudio = settings.HoldAudio;
|
||||
AllowOutgoingCalls = settings.AllowOutgoingCalls;
|
||||
Pause = settings.Pause;
|
||||
Record = settings.Record;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected AuthContext AuthContext { get; }
|
||||
protected TenantUtil TenantUtil { get; }
|
||||
protected SecurityContext SecurityContext { get; }
|
||||
protected BaseCommonLinkUtility BaseCommonLinkUtility { get; }
|
||||
|
||||
public VoipSettings(AuthContext authContext, TenantUtil tenantUtil, SecurityContext securityContext, BaseCommonLinkUtility baseCommonLinkUtility)
|
||||
{
|
||||
Operators = new List<Agent>();
|
||||
AuthContext = authContext;
|
||||
TenantUtil = tenantUtil;
|
||||
SecurityContext = securityContext;
|
||||
BaseCommonLinkUtility = baseCommonLinkUtility;
|
||||
}
|
||||
|
||||
public VoipSettings(string settings, AuthContext authContext)
|
||||
{
|
||||
JsonSettings = settings;
|
||||
AuthContext = authContext;
|
||||
}
|
||||
|
||||
public virtual string Connect(bool user = true, string contactId = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual string Redirect(string to)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual string Dequeue(bool reject)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return JsonSettings;
|
||||
}
|
||||
|
||||
public VoipSettings GetSettings(string settings)
|
||||
{
|
||||
return new VoipSettings(AuthContext, TenantUtil, SecurityContext, BaseCommonLinkUtility) { JsonSettings = settings };
|
||||
}
|
||||
}
|
||||
|
||||
class CustomSerializeContractResolver : CamelCasePropertyNamesContractResolver
|
||||
protected AuthContext AuthContext { get; }
|
||||
protected TenantUtil TenantUtil { get; }
|
||||
protected SecurityContext SecurityContext { get; }
|
||||
protected BaseCommonLinkUtility BaseCommonLinkUtility { get; }
|
||||
|
||||
public VoipSettings(AuthContext authContext, TenantUtil tenantUtil, SecurityContext securityContext, BaseCommonLinkUtility baseCommonLinkUtility)
|
||||
{
|
||||
public static readonly CustomSerializeContractResolver Instance = new CustomSerializeContractResolver();
|
||||
|
||||
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
|
||||
{
|
||||
var property = base.CreateProperty(member, memberSerialization);
|
||||
|
||||
if (property.PropertyName == "voiceMail")
|
||||
{
|
||||
property.Converter = new VoiceMailConverter();
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
Operators = new List<Agent>();
|
||||
AuthContext = authContext;
|
||||
TenantUtil = tenantUtil;
|
||||
SecurityContext = securityContext;
|
||||
BaseCommonLinkUtility = baseCommonLinkUtility;
|
||||
}
|
||||
|
||||
class VoiceMailConverter : JsonConverter
|
||||
public VoipSettings(string settings, AuthContext authContext)
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
JsonSettings = settings;
|
||||
AuthContext = authContext;
|
||||
}
|
||||
|
||||
public virtual string Connect(bool user = true, string contactId = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual string Redirect(string to)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual string Dequeue(bool reject)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return JsonSettings;
|
||||
}
|
||||
|
||||
public VoipSettings GetSettings(string settings)
|
||||
{
|
||||
return new VoipSettings(AuthContext, TenantUtil, SecurityContext, BaseCommonLinkUtility) { JsonSettings = settings };
|
||||
}
|
||||
}
|
||||
|
||||
class CustomSerializeContractResolver : CamelCasePropertyNamesContractResolver
|
||||
{
|
||||
public static readonly CustomSerializeContractResolver Instance = new CustomSerializeContractResolver();
|
||||
|
||||
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
|
||||
{
|
||||
var property = base.CreateProperty(member, memberSerialization);
|
||||
|
||||
if (property.PropertyName == "voiceMail")
|
||||
{
|
||||
serializer.Serialize(writer, value);
|
||||
property.Converter = new VoiceMailConverter();
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
class VoiceMailConverter : JsonConverter
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
serializer.Serialize(writer, value);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.ValueType != null && reader.ValueType.Name == "String")
|
||||
{
|
||||
if (reader.ValueType != null && reader.ValueType.Name == "String")
|
||||
{
|
||||
return reader.Value;
|
||||
}
|
||||
|
||||
var jObject = JObject.Load(reader);
|
||||
var url = jObject.Value<string>("url");
|
||||
|
||||
return !string.IsNullOrEmpty(url) ? url : "";
|
||||
return reader.Value;
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
var jObject = JObject.Load(reader);
|
||||
var url = jObject.Value<string>("url");
|
||||
|
||||
return !string.IsNullOrEmpty(url) ? url : "";
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user