2020-03-02 15:38:31 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* (c) Copyright Ascensio System Limited 2010-2018
|
|
|
|
*
|
|
|
|
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
|
|
|
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
|
|
|
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
|
|
|
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
|
|
|
*
|
|
|
|
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
|
|
|
*
|
|
|
|
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
|
|
|
*
|
|
|
|
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
|
|
|
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
|
|
|
*
|
|
|
|
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
|
|
|
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
|
|
|
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
|
|
|
* in every copy of the program you distribute.
|
|
|
|
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2021-03-01 17:36:18 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
|
|
|
|
2021-03-02 16:29:07 +00:00
|
|
|
using ASC.Common;
|
2020-04-14 07:59:07 +00:00
|
|
|
using ASC.Common.Logging;
|
2021-05-24 09:56:49 +00:00
|
|
|
using ASC.Common.Threading;
|
2020-03-02 15:38:31 +00:00
|
|
|
using ASC.Core;
|
|
|
|
using ASC.Core.Tenants;
|
|
|
|
using ASC.CRM.Core;
|
|
|
|
using ASC.CRM.Core.Dao;
|
|
|
|
using ASC.CRM.Core.Entities;
|
2020-04-02 19:42:03 +00:00
|
|
|
using ASC.CRM.Core.Enums;
|
|
|
|
using ASC.CRM.Resources;
|
2020-03-02 15:38:31 +00:00
|
|
|
using ASC.VoipService;
|
|
|
|
using ASC.VoipService.Dao;
|
2021-03-01 17:36:18 +00:00
|
|
|
|
2020-04-14 07:59:07 +00:00
|
|
|
using Microsoft.Extensions.Options;
|
2020-03-02 15:38:31 +00:00
|
|
|
|
|
|
|
namespace ASC.Web.CRM.Classes
|
|
|
|
{
|
2021-03-02 16:29:07 +00:00
|
|
|
[Scope]
|
2020-03-02 15:38:31 +00:00
|
|
|
public class VoipEngine
|
|
|
|
{
|
2021-05-24 09:56:49 +00:00
|
|
|
private readonly DistributedTaskQueue _queue;
|
|
|
|
|
|
|
|
public readonly DaoFactory _daoFactory;
|
|
|
|
public readonly VoipDao _voipDao;
|
|
|
|
public readonly TenantManager _tenantManager;
|
|
|
|
public readonly ILog _logger;
|
|
|
|
public readonly int _tenantId;
|
|
|
|
public readonly SecurityContext _securityContext;
|
|
|
|
public readonly TenantUtil _tenantUtil;
|
|
|
|
public readonly CrmSecurity _crmSecurity;
|
2021-03-01 17:36:18 +00:00
|
|
|
|
2020-04-14 07:59:07 +00:00
|
|
|
private readonly object Locker = new object();
|
2020-03-02 15:38:31 +00:00
|
|
|
|
2020-04-14 07:59:07 +00:00
|
|
|
public VoipEngine(DaoFactory daoFactory,
|
2021-05-05 14:09:05 +00:00
|
|
|
CrmSecurity crmSecurity,
|
2020-04-14 07:59:07 +00:00
|
|
|
TenantUtil tenantUtil,
|
2021-05-24 09:56:49 +00:00
|
|
|
DistributedTaskQueueOptionsManager optionsManager,
|
2020-04-14 07:59:07 +00:00
|
|
|
SecurityContext securityContext,
|
|
|
|
IOptionsMonitor<ILog> logger,
|
|
|
|
TenantManager tenantManager,
|
|
|
|
VoipDao voipDao)
|
2020-03-02 15:38:31 +00:00
|
|
|
{
|
2021-05-24 09:56:49 +00:00
|
|
|
_crmSecurity = crmSecurity;
|
|
|
|
_tenantUtil = tenantUtil;
|
|
|
|
_securityContext = securityContext;
|
|
|
|
_queue = optionsManager.Get<QueueItem>();
|
|
|
|
_logger = logger.Get("ASC.CRM");
|
|
|
|
_tenantManager = tenantManager;
|
|
|
|
_voipDao = voipDao;
|
|
|
|
_daoFactory = daoFactory;
|
2020-03-02 15:38:31 +00:00
|
|
|
}
|
2020-04-02 19:42:03 +00:00
|
|
|
|
2020-04-14 07:59:07 +00:00
|
|
|
|
2020-03-02 15:38:31 +00:00
|
|
|
public VoipCall SaveOrUpdateCall(VoipCall callHistory)
|
|
|
|
{
|
2021-05-24 09:56:49 +00:00
|
|
|
var dao = _daoFactory.GetVoipDao();
|
2020-03-02 15:38:31 +00:00
|
|
|
var call = dao.GetCall(callHistory.Id) ?? callHistory;
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(call.ParentID))
|
|
|
|
{
|
|
|
|
GetContact(call);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!callHistory.AnsweredBy.Equals(Guid.Empty))
|
|
|
|
{
|
|
|
|
call.AnsweredBy = callHistory.AnsweredBy;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!callHistory.Date.Equals(default(DateTime)))
|
|
|
|
{
|
|
|
|
call.Date = callHistory.Date;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!callHistory.EndDialDate.Equals(default(DateTime)))
|
|
|
|
{
|
|
|
|
call.EndDialDate = callHistory.EndDialDate;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (call.Price == 0 && callHistory.Price != default(decimal))
|
|
|
|
{
|
|
|
|
call.Price = callHistory.Price;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (call.DialDuration == 0)
|
|
|
|
{
|
|
|
|
call.DialDuration = callHistory.DialDuration;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (call.VoipRecord == null)
|
|
|
|
{
|
|
|
|
call.VoipRecord = new VoipRecord();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(call.VoipRecord.Id))
|
|
|
|
{
|
|
|
|
call.VoipRecord.Id = callHistory.VoipRecord.Id;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (call.VoipRecord.Price == default(decimal))
|
|
|
|
{
|
|
|
|
call.VoipRecord.Price = callHistory.VoipRecord.Price;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(call.VoipRecord.Uri))
|
|
|
|
{
|
|
|
|
call.VoipRecord.Uri = callHistory.VoipRecord.Uri;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (call.VoipRecord.Duration == 0)
|
|
|
|
{
|
|
|
|
call.VoipRecord.Duration = callHistory.VoipRecord.Duration;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (callHistory.Status.HasValue)
|
|
|
|
{
|
|
|
|
call.Status = callHistory.Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dao.SaveOrUpdateCall(call);
|
|
|
|
}
|
|
|
|
|
2020-04-14 07:59:07 +00:00
|
|
|
public void AddHistoryToCallContact(VoipCall call, DaoFactory daoFactory)
|
2020-03-02 15:38:31 +00:00
|
|
|
{
|
2020-04-14 07:59:07 +00:00
|
|
|
var listItemDao = daoFactory.GetListItemDao();
|
2020-03-02 15:38:31 +00:00
|
|
|
|
|
|
|
if (call == null || call.ContactId == 0) return;
|
|
|
|
|
|
|
|
var category = listItemDao.GetByTitle(ListType.HistoryCategory, CRMCommonResource.HistoryCategory_Call);
|
|
|
|
if (category == null)
|
|
|
|
{
|
|
|
|
category = new ListItem(CRMCommonResource.HistoryCategory_Call, "event_category_call.png");
|
|
|
|
category.ID = listItemDao.CreateItem(ListType.HistoryCategory, category);
|
|
|
|
}
|
2021-05-24 09:56:49 +00:00
|
|
|
|
2020-04-14 07:59:07 +00:00
|
|
|
var contact = daoFactory.GetContactDao().GetByID(call.ContactId);
|
2021-06-04 14:38:42 +00:00
|
|
|
|
2021-05-24 09:56:49 +00:00
|
|
|
if (contact != null && _crmSecurity.CanAccessTo(contact))
|
2020-03-02 15:38:31 +00:00
|
|
|
{
|
|
|
|
var note = call.Status == VoipCallStatus.Incoming || call.Status == VoipCallStatus.Answered
|
|
|
|
? CRMContactResource.HistoryVoipIncomingNote
|
|
|
|
: CRMContactResource.HistoryVoipOutcomingNote;
|
|
|
|
var content = string.Format(note, call.DialDuration);
|
|
|
|
|
|
|
|
var relationshipEvent = new RelationshipEvent
|
|
|
|
{
|
|
|
|
CategoryID = category.ID,
|
|
|
|
EntityType = EntityType.Any,
|
|
|
|
EntityID = 0,
|
|
|
|
Content = content,
|
|
|
|
ContactID = contact.ID,
|
2021-05-24 09:56:49 +00:00
|
|
|
CreateOn = _tenantUtil.DateTimeFromUtc(DateTime.UtcNow),
|
|
|
|
CreateBy = _securityContext.CurrentAccount.ID
|
2020-03-02 15:38:31 +00:00
|
|
|
};
|
|
|
|
|
2020-04-14 07:59:07 +00:00
|
|
|
daoFactory.GetRelationshipEventDao().CreateItem(relationshipEvent);
|
2020-03-02 15:38:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Contact GetContact(VoipCall call)
|
|
|
|
{
|
|
|
|
if (call.ContactId != 0)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
var contactPhone = call.Status == VoipCallStatus.Incoming || call.Status == VoipCallStatus.Answered ? call.From : call.To;
|
|
|
|
|
2021-05-24 09:56:49 +00:00
|
|
|
var newContactIds = _daoFactory.GetContactDao().GetContactIDsByContactInfo(ContactInfoType.Phone, contactPhone.TrimStart('+'), null, true);
|
2020-03-02 15:38:31 +00:00
|
|
|
|
|
|
|
foreach (var newContactId in newContactIds)
|
|
|
|
{
|
|
|
|
if (newContactId != 0)
|
|
|
|
{
|
2021-05-24 09:56:49 +00:00
|
|
|
var existContact = _daoFactory.GetContactDao().GetByID(newContactId);
|
|
|
|
if (_crmSecurity.CanAccessTo(existContact))
|
2020-03-02 15:38:31 +00:00
|
|
|
{
|
|
|
|
call.ContactId = newContactId;
|
|
|
|
return existContact;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<Contact> GetContacts(string contactPhone, DaoFactory daoFactory)
|
|
|
|
{
|
2020-04-14 07:59:07 +00:00
|
|
|
var dao = daoFactory.GetContactDao();
|
2020-03-02 15:38:31 +00:00
|
|
|
var ids = dao.GetContactIDsByContactInfo(ContactInfoType.Phone, contactPhone.TrimStart('+'), null, true);
|
|
|
|
return ids.Select(r => dao.GetByID(r)).ToList();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SaveAdditionalInfo(string callId)
|
|
|
|
{
|
|
|
|
lock (Locker)
|
2021-06-04 14:38:42 +00:00
|
|
|
{
|
2021-05-24 09:56:49 +00:00
|
|
|
var _queueItem = new QueueItem { CallID = callId, TenantID = _tenantId };
|
2020-03-02 15:38:31 +00:00
|
|
|
|
2021-05-24 09:56:49 +00:00
|
|
|
_queue.QueueTask((a, b) => SaveAdditionalInfoAction(_queueItem), _queueItem); ;
|
2020-03-02 15:38:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-14 07:59:07 +00:00
|
|
|
private void SaveAdditionalInfoAction(QueueItem queueItem)
|
2020-03-02 15:38:31 +00:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2021-05-24 09:56:49 +00:00
|
|
|
_tenantManager.SetCurrentTenant(queueItem.TenantID);
|
2020-04-14 07:59:07 +00:00
|
|
|
|
2021-05-24 09:56:49 +00:00
|
|
|
var voipEngine = new VoipEngine(_daoFactory,
|
|
|
|
_crmSecurity,
|
|
|
|
_tenantUtil,
|
|
|
|
null,
|
2021-06-04 14:38:42 +00:00
|
|
|
_securityContext,
|
2020-04-18 17:49:09 +00:00
|
|
|
null,
|
2021-05-24 09:56:49 +00:00
|
|
|
_tenantManager,
|
|
|
|
_voipDao);
|
2020-03-02 15:38:31 +00:00
|
|
|
|
2021-05-24 09:56:49 +00:00
|
|
|
var dao = _daoFactory.GetVoipDao();
|
2020-03-02 15:38:31 +00:00
|
|
|
|
2020-04-14 14:35:52 +00:00
|
|
|
var call = dao.GetCall(queueItem.CallID);
|
2020-03-02 15:38:31 +00:00
|
|
|
|
2020-04-14 14:35:52 +00:00
|
|
|
GetPriceAndDuration(call);
|
2020-03-02 15:38:31 +00:00
|
|
|
|
2020-04-14 14:35:52 +00:00
|
|
|
if (call.ChildCalls.Any())
|
|
|
|
{
|
|
|
|
call.ChildCalls.ForEach(r =>
|
2020-03-02 15:38:31 +00:00
|
|
|
{
|
2020-04-14 14:35:52 +00:00
|
|
|
GetPriceAndDuration(r);
|
|
|
|
voipEngine.SaveOrUpdateCall(r);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
call = voipEngine.SaveOrUpdateCall(call);
|
2020-03-02 15:38:31 +00:00
|
|
|
|
2020-04-14 14:35:52 +00:00
|
|
|
if (!string.IsNullOrEmpty(call.VoipRecord.Id))
|
|
|
|
{
|
2021-05-24 09:56:49 +00:00
|
|
|
call.VoipRecord = _voipDao.GetProvider().GetRecord((string)call.Id, (string)call.VoipRecord.Id);
|
2020-04-14 14:35:52 +00:00
|
|
|
voipEngine.SaveOrUpdateCall(call);
|
2020-03-02 15:38:31 +00:00
|
|
|
}
|
2020-04-14 14:35:52 +00:00
|
|
|
|
2021-08-18 14:04:16 +00:00
|
|
|
_securityContext.AuthenticateMeWithoutCookie(call.AnsweredBy);
|
2021-05-24 09:56:49 +00:00
|
|
|
AddHistoryToCallContact(call, _daoFactory);
|
2020-04-14 14:35:52 +00:00
|
|
|
|
2020-03-02 15:38:31 +00:00
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
2021-05-24 09:56:49 +00:00
|
|
|
_logger.ErrorFormat("SaveAdditionalInfo {0}, {1}", ex, ex.StackTrace);
|
2020-03-02 15:38:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-14 07:59:07 +00:00
|
|
|
private void GetPriceAndDuration(VoipCall call)
|
2020-03-02 15:38:31 +00:00
|
|
|
{
|
2021-05-24 09:56:49 +00:00
|
|
|
var provider = _voipDao.GetProvider();
|
2020-03-02 15:38:31 +00:00
|
|
|
var twilioCall = provider.GetCall(call.Id);
|
2021-06-04 14:38:42 +00:00
|
|
|
|
2020-03-02 15:38:31 +00:00
|
|
|
call.Price = twilioCall.Price;
|
|
|
|
call.DialDuration = twilioCall.DialDuration;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void AnswerCall(VoipCall call)
|
|
|
|
{
|
2021-05-24 09:56:49 +00:00
|
|
|
call.AnsweredBy = _securityContext.CurrentAccount.ID;
|
2020-03-02 15:38:31 +00:00
|
|
|
call.Status = VoipCallStatus.Answered;
|
2021-06-04 14:38:42 +00:00
|
|
|
|
2021-05-24 09:56:49 +00:00
|
|
|
_daoFactory.GetVoipDao().SaveOrUpdateCall(call);
|
2020-03-02 15:38:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public Contact CreateContact(string contactPhone)
|
|
|
|
{
|
|
|
|
var contact = new Person
|
|
|
|
{
|
|
|
|
FirstName = contactPhone,
|
2021-05-24 09:56:49 +00:00
|
|
|
LastName = _tenantUtil.DateTimeFromUtc(DateTime.UtcNow).ToString("yyyy-MM-dd hh:mm"),
|
2020-03-02 15:38:31 +00:00
|
|
|
ShareType = ShareType.None,
|
2021-05-24 09:56:49 +00:00
|
|
|
CreateBy = _securityContext.CurrentAccount.ID,
|
2020-03-02 15:38:31 +00:00
|
|
|
CreateOn = DateTime.UtcNow
|
|
|
|
};
|
|
|
|
|
2021-05-24 09:56:49 +00:00
|
|
|
contact.ID = _daoFactory.GetContactDao().SaveContact(contact);
|
2020-03-02 15:38:31 +00:00
|
|
|
|
2021-05-24 09:56:49 +00:00
|
|
|
_daoFactory.GetContactInfoDao()
|
2020-03-02 15:38:31 +00:00
|
|
|
.Save(new ContactInfo
|
|
|
|
{
|
|
|
|
ContactID = contact.ID,
|
|
|
|
IsPrimary = true,
|
|
|
|
InfoType = ContactInfoType.Phone,
|
|
|
|
Data = contactPhone
|
|
|
|
});
|
|
|
|
|
2021-05-24 09:56:49 +00:00
|
|
|
_crmSecurity.SetAccessTo(contact, new List<Guid> { _securityContext.CurrentAccount.ID });
|
2020-03-02 15:38:31 +00:00
|
|
|
|
|
|
|
return contact;
|
|
|
|
}
|
|
|
|
|
2021-05-24 09:56:49 +00:00
|
|
|
private class QueueItem : DistributedTask
|
2020-03-02 15:38:31 +00:00
|
|
|
{
|
|
|
|
public int TenantID { get; set; }
|
|
|
|
public string CallID { get; set; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|