/* * * (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. * */ using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Security; using ASC.Api.Core; using ASC.Api.CRM; using ASC.Api.Utils; using ASC.Common.Web; using ASC.Core.Notify.Signalr; using ASC.Core.Tenants; using ASC.CRM.ApiModels; using ASC.CRM.Core; using ASC.CRM.Core.Dao; using ASC.CRM.Core.Entities; using ASC.CRM.Core.Enums; using ASC.CRM.Resources; using ASC.Data.Storage; using ASC.VoipService; using ASC.VoipService.Dao; using ASC.VoipService.Twilio; using ASC.Web.Api.Routing; using ASC.Web.CRM.Classes; using ASC.Web.Studio.Utility; using AutoMapper; using Microsoft.AspNetCore.Mvc; using SecurityContext = ASC.Core.SecurityContext; namespace ASC.CRM.Api { public class VoIPController : BaseApiController { private readonly SignalrServiceClient _signalrServiceClient; private readonly ApiContext _apiContext; private readonly VoipEngine _voipEngine; private readonly TenantUtil _tenantUtil; private readonly SecurityContext _securityContext; private readonly CommonLinkUtility _commonLinkUtility; private readonly StorageFactory _storageFactory; private readonly ContactPhotoManager _contactPhotoManager; private readonly Global _global; public VoIPController(CrmSecurity crmSecurity, DaoFactory daoFactory, Global global, ContactPhotoManager contactPhotoManager, StorageFactory storageFactory, CommonLinkUtility commonLinkUtility, SecurityContext securityContext, TenantUtil tenantUtil, VoipEngine voipEngine, ApiContext apiContext, SignalrServiceClient signalrServiceClient, IMapper mapper) : base(daoFactory, crmSecurity, mapper) { _global = global; _contactPhotoManager = contactPhotoManager; _storageFactory = storageFactory; _commonLinkUtility = commonLinkUtility; _securityContext = securityContext; _tenantUtil = tenantUtil; _voipEngine = voipEngine; _apiContext = apiContext; _signalrServiceClient = signalrServiceClient; } /// /// /// /// /// Voip /// /// /// [Read(@"voip/numbers/available")] public IEnumerable GetAvailablePhoneNumbers(PhoneNumberType numberType, string isoCountryCode) { if (!_crmSecurity.IsAdmin) throw _crmSecurity.CreateSecurityException(); if (string.IsNullOrEmpty(isoCountryCode)) throw new ArgumentException(); return _daoFactory.GetVoipDao().GetProvider().GetAvailablePhoneNumbers(numberType, isoCountryCode); } /// /// /// /// /// Voip /// /// [Read(@"voip/numbers/unlinked")] public IEnumerable GetUnlinkedPhoneNumbers() { if (!_crmSecurity.IsAdmin) throw _crmSecurity.CreateSecurityException(); var listPhones = _daoFactory.GetVoipDao().GetProvider().GetExistingPhoneNumbers(); var buyedPhones = _daoFactory.GetVoipDao().GetNumbers(); return listPhones.Where(r => buyedPhones.All(b => r.Id != b.Id)).ToList(); } /// /// /// /// /// Voip /// /// [Read(@"voip/numbers/existing")] public IEnumerable GetExistingPhoneNumbers() { if (!_crmSecurity.IsAdmin) throw _crmSecurity.CreateSecurityException(); return _daoFactory.GetVoipDao().GetNumbers(); } /// /// /// /// /// Voip /// /// [Create(@"voip/numbers")] public VoipPhone BuyNumber([FromBody] string number) { if (!_crmSecurity.IsAdmin) throw _crmSecurity.CreateSecurityException(); var newPhone = _daoFactory.GetVoipDao().GetProvider().BuyNumber(number); _daoFactory.GetVoipDao().GetProvider().CreateQueue(newPhone); SetDefaultAudio(newPhone); _daoFactory.GetVoipDao().GetProvider().UpdateSettings(newPhone); return _daoFactory.GetVoipDao().SaveOrUpdateNumber(newPhone); } /// /// /// /// /// Voip /// /// [Create(@"voip/numbers/link")] public VoipPhone LinkNumber([FromBody] string id) { if (!_crmSecurity.IsAdmin) throw _crmSecurity.CreateSecurityException(); var newPhone = _daoFactory.GetVoipDao().GetProvider().GetPhone(id); _daoFactory.GetVoipDao().GetProvider().CreateQueue(newPhone); SetDefaultAudio(newPhone); _daoFactory.GetVoipDao().GetProvider().UpdateSettings(newPhone); return _daoFactory.GetVoipDao().SaveOrUpdateNumber(newPhone); } public void SetDefaultAudio(VoipPhone newPhone) { var storage = _storageFactory.GetStorage("", "crm"); const string path = "default/"; var files = storage.ListFilesRelative("voip", path, "*.*", true) .Select(filePath => new { path = _commonLinkUtility.GetFullAbsolutePath(storage.GetUri("voip", Path.Combine(path, filePath)).ToString()), audioType = (AudioType)Enum.Parse(typeof(AudioType), Directory.GetParent(filePath).Name, true) }).ToList(); var audio = files.Find(r => r.audioType == AudioType.Greeting); newPhone.Settings.GreetingAudio = audio != null ? audio.path : ""; audio = files.Find(r => r.audioType == AudioType.HoldUp); newPhone.Settings.HoldAudio = audio != null ? audio.path : ""; audio = files.Find(r => r.audioType == AudioType.VoiceMail); newPhone.Settings.VoiceMail = audio != null ? audio.path : ""; audio = files.Find(r => r.audioType == AudioType.Queue); newPhone.Settings.Queue.WaitUrl = audio != null ? audio.path : ""; } /// /// /// /// /// Voip /// /// [Delete(@"voip/numbers/{numberId:regex(\w+)}")] public VoipPhone DeleteNumber(string numberId) { if (!_crmSecurity.IsAdmin) throw _crmSecurity.CreateSecurityException(); var dao = _daoFactory.GetVoipDao(); var phone = dao.GetNumber(numberId).NotFoundIfNull(); _daoFactory.GetVoipDao().GetProvider().DisablePhone(phone); dao.DeleteNumber(numberId); new SignalRHelper(phone.Number, _signalrServiceClient).Reload(); return phone; } /// /// /// /// /// Voip /// /// [Read(@"voip/numbers/{numberId:regex(\w+)}")] public VoipPhone GetNumber(string numberId) { return _daoFactory.GetVoipDao().GetNumber(numberId).NotFoundIfNull(); } /// /// /// /// /// Voip /// [Read(@"voip/numbers/current")] public VoipPhone GetCurrentNumber() { return _daoFactory.GetVoipDao().GetCurrentNumber().NotFoundIfNull(); } /// /// /// /// /// Voip /// [Read(@"voip/token")] public string GetToken() { return _daoFactory.GetVoipDao().GetProvider().GetToken(GetCurrentNumber().Caller); } /// /// /// /// /// Voip /// /// [Update(@"voip/numbers/{numberId:regex(\w+)}/settings")] public VoipPhone UpdateSettings(string numberId, string greeting, string holdUp, string wait, string voiceMail, WorkingHours workingHours, bool? allowOutgoingCalls, bool? record, string alias) { if (!_crmSecurity.IsAdmin) throw _crmSecurity.CreateSecurityException(); var dao = _daoFactory.GetVoipDao(); var number = dao.GetNumber(numberId).NotFoundIfNull(); number.Alias = Update.IfNotEmptyAndNotEquals(number.Alias, alias); number.Settings.GreetingAudio = Update.IfNotEmptyAndNotEquals(number.Settings.GreetingAudio, greeting); number.Settings.HoldAudio = Update.IfNotEmptyAndNotEquals(number.Settings.HoldAudio, holdUp); number.Settings.VoiceMail = Update.IfNotEmptyAndNotEquals(number.Settings.VoiceMail, voiceMail); number.Settings.WorkingHours = Update.IfNotEmptyAndNotEquals(number.Settings.WorkingHours, workingHours); if (!string.IsNullOrEmpty(wait)) { number.Settings.Queue.WaitUrl = wait; } if (allowOutgoingCalls.HasValue) { number.Settings.AllowOutgoingCalls = allowOutgoingCalls.Value; if (!number.Settings.AllowOutgoingCalls) { number.Settings.Operators.ForEach(r => r.AllowOutgoingCalls = false); } } if (record.HasValue) { number.Settings.Record = record.Value; if (!number.Settings.Record) { number.Settings.Operators.ForEach(r => r.Record = false); } } dao.SaveOrUpdateNumber(number); return number; } /// /// /// /// /// Voip /// /// [Update(@"voip/numbers/settings")] public object UpdateSettings(Queue queue, bool pause) { if (!_crmSecurity.IsAdmin) throw _crmSecurity.CreateSecurityException(); var dao = _daoFactory.GetVoipDao(); var numbers = dao.GetNumbers(); if (queue != null) { foreach (var number in numbers) { if (number.Settings.Queue == null || string.IsNullOrEmpty(number.Settings.Queue.Id)) { var phone = number as TwilioPhone; if (phone != null) { queue = phone.CreateQueue(phone.Number, queue.Size, queue.WaitUrl, queue.WaitTime * 60); } queue.Name = number.Number; number.Settings.Queue = queue; } else { var oldQueue = number.Settings.Queue; oldQueue.Size = Update.IfNotEmptyAndNotEquals(oldQueue.Size, queue.Size); oldQueue.WaitTime = Update.IfNotEmptyAndNotEquals(oldQueue.WaitTime, queue.WaitTime * 60); oldQueue.WaitUrl = Update.IfNotEmptyAndNotEquals(oldQueue.WaitUrl, queue.WaitUrl); } number.Settings.Pause = pause; dao.SaveOrUpdateNumber(number); } } return new { queue, pause }; } /// /// /// /// /// Voip /// /// [Read(@"voip/numbers/settings")] public object GetVoipSettings() { if (!_crmSecurity.IsAdmin) throw _crmSecurity.CreateSecurityException(); var dao = _daoFactory.GetVoipDao(); var number = dao.GetNumbers().FirstOrDefault(r => r.Settings.Queue != null); if (number != null) { return new { queue = number.Settings.Queue, pause = number.Settings.Pause }; } var files = _storageFactory.GetStorage("", "crm").ListFiles("voip", "default/" + AudioType.Queue.ToString().ToLower(), "*.*", true); var file = files.FirstOrDefault(); return new { queue = new Queue(null, "Default", 5, file != null ? _commonLinkUtility.GetFullAbsolutePath(file.ToString()) : "", 5), pause = false }; } /// /// /// /// /// Voip /// /// [Read(@"voip/uploads")] public IEnumerable GetUploadedFilesUri() { if (!_crmSecurity.IsAdmin) throw _crmSecurity.CreateSecurityException(); var result = new List(); foreach (var audioType in Enum.GetNames(typeof(AudioType))) { var type = (AudioType)Enum.Parse(typeof(AudioType), audioType); var path = audioType.ToLower(); var store = _global.GetStore(); var filePaths = store.ListFilesRelative("voip", path, "*", true); result.AddRange( filePaths.Select(filePath => GetVoipUpload(store.GetUri("voip", Path.Combine(path, filePath)), Path.GetFileName(filePath), type))); path = "default/" + audioType.ToLower(); store = _storageFactory.GetStorage("", "crm"); filePaths = store.ListFilesRelative("voip", path, "*.*", true); result.AddRange( filePaths.Select(filePath => GetVoipUpload(store.GetUri("voip", Path.Combine(path, filePath)), Path.GetFileName(filePath), type, true))); } return result; } private VoipUpload GetVoipUpload(Uri link, string fileName, AudioType audioType, bool isDefault = false) { return new VoipUpload { Path = _commonLinkUtility.GetFullAbsolutePath(link.ToString()), Name = fileName, AudioType = audioType, IsDefault = isDefault }; } /// /// /// /// /// Voip /// /// /// [Delete(@"voip/uploads")] public VoipUpload DeleteUploadedFile(AudioType audioType, string fileName) { if (!_crmSecurity.IsAdmin) throw _crmSecurity.CreateSecurityException(); var store = _global.GetStore(); var path = Path.Combine(audioType.ToString().ToLower(), fileName); var result = new VoipUpload { AudioType = audioType, Name = fileName, Path = _commonLinkUtility.GetFullAbsolutePath(store.GetUri(path).ToString()) }; if (!store.IsFile("voip", path)) throw new ItemNotFoundException(); store.Delete("voip", path); var dao = _daoFactory.GetVoipDao(); var numbers = dao.GetNumbers(); var defAudio = _storageFactory.GetStorage("", "crm").ListFiles("voip", "default/" + audioType.ToString().ToLower(), "*.*", true).FirstOrDefault(); if (defAudio == null) return result; foreach (var number in numbers) { switch (audioType) { case AudioType.Greeting: if (number.Settings.GreetingAudio == result.Path) { number.Settings.GreetingAudio = _commonLinkUtility.GetFullAbsolutePath(defAudio.ToString()); } break; case AudioType.HoldUp: if (number.Settings.HoldAudio == result.Path) { number.Settings.HoldAudio = _commonLinkUtility.GetFullAbsolutePath(defAudio.ToString()); } break; case AudioType.Queue: var queue = number.Settings.Queue; if (queue != null && queue.WaitUrl == result.Path) { queue.WaitUrl = _commonLinkUtility.GetFullAbsolutePath(defAudio.ToString()); } break; case AudioType.VoiceMail: if (number.Settings.VoiceMail == result.Path) { number.Settings.VoiceMail = _commonLinkUtility.GetFullAbsolutePath(defAudio.ToString()); } break; } dao.SaveOrUpdateNumber(number); } return result; } /// /// /// /// /// Voip /// /// [Read(@"voip/numbers/{numberId:regex(\w+)}/oper")] public IEnumerable GetOperators(string numberId) { return _daoFactory.GetVoipDao().GetNumber(numberId).Settings.Operators.Select(r => r.Id); } /// /// /// /// /// Voip /// /// /// [Update(@"voip/numbers/{numberId:regex(\w+)}/oper")] public IEnumerable AddOperators(string numberId, IEnumerable operators) { if (!_crmSecurity.IsAdmin) throw _crmSecurity.CreateSecurityException(); if (_daoFactory.GetVoipDao().GetNumbers().SelectMany(r => r.Settings.Operators).Any(r => operators.Contains(r.Id))) { throw new ArgumentException("Duplicate", "operators"); } var dao = _daoFactory.GetVoipDao(); var phone = dao.GetNumber(numberId); var lastOper = phone.Settings.Operators.LastOrDefault(); var startOperId = lastOper != null ? Convert.ToInt32(lastOper.PostFix) + 1 : 100; var addedOperators = operators.Select(o => new Agent(o, AnswerType.Client, phone, (startOperId++).ToString(CultureInfo.InvariantCulture))).ToList(); phone.Settings.Operators.AddRange(addedOperators); dao.SaveOrUpdateNumber(phone); return addedOperators; } /// /// /// /// /// Voip /// /// [Delete(@"voip/numbers/{numberId:regex(\w+)}/oper")] public Guid DeleteOperator(string numberId, Guid oper) { if (!_crmSecurity.IsAdmin) throw _crmSecurity.CreateSecurityException(); var dao = _daoFactory.GetVoipDao(); var phone = dao.GetNumber(numberId); var startOperId = 100; phone.Settings.Operators.RemoveAll(r => r.Id == oper); phone.Settings.Operators.ToList() .ForEach(r => { r.PhoneNumber = phone.Number; r.PostFix = startOperId.ToString(CultureInfo.InvariantCulture); startOperId++; }); dao.SaveOrUpdateNumber(phone); return oper; } /// /// /// /// /// Voip /// /// [Update(@"voip/opers/{operatorId}")] public Agent UpdateOperator(Guid operatorId, AgentStatus? status, bool? allowOutgoingCalls, bool? record, AnswerType? answerType, string redirectToNumber) { if (!_crmSecurity.IsAdmin && !operatorId.Equals(_securityContext.CurrentAccount.ID)) throw _crmSecurity.CreateSecurityException(); var dao = _daoFactory.GetVoipDao(); var phone = dao.GetNumbers().FirstOrDefault(r => r.Settings.Operators.Exists(a => a.Id == operatorId)).NotFoundIfNull(); var oper = phone.Settings.Operators.Find(r => r.Id == operatorId); if (status.HasValue) { oper.Status = status.Value; } if (allowOutgoingCalls.HasValue) { oper.AllowOutgoingCalls = phone.Settings.AllowOutgoingCalls && allowOutgoingCalls.Value; } if (record.HasValue) { oper.Record = phone.Settings.Record && record.Value; } if (answerType.HasValue) { oper.Answer = answerType.Value; } if (!string.IsNullOrEmpty(redirectToNumber)) { oper.RedirectToNumber = redirectToNumber; } dao.SaveOrUpdateNumber(phone); if (allowOutgoingCalls.HasValue) { new SignalRHelper(phone.Number, _signalrServiceClient).Reload(operatorId.ToString()); } return oper; } /// /// /// /// /// Voip /// /// [Create(@"voip/call")] public VoipCallDto MakeCall([FromForm] string to, [FromForm] string contactId) { var number = _daoFactory.GetVoipDao().GetCurrentNumber().NotFoundIfNull(); if (!number.Settings.Caller.AllowOutgoingCalls) throw new SecurityException(CRMErrorsResource.AccessDenied); var contactPhone = to.TrimStart('+'); ContactDto contact; if (String.IsNullOrEmpty(contactId)) { var ids = _daoFactory.GetContactDao().GetContactIDsByContactInfo(ContactInfoType.Phone, contactPhone, null, null); contact = _daoFactory.GetContactDao().GetContacts(ids.ToArray()).ConvertAll(x => _mapper.Map(x)).FirstOrDefault(); } else { contact = _mapper.Map(_daoFactory.GetContactDao().GetByID(Convert.ToInt32(contactId))); } if (contact == null) { contact = _mapper.Map(_voipEngine.CreateContact(contactPhone)); } contact = GetContactWithFotos(contact); var call = number.Call(to, contact.Id.ToString(CultureInfo.InvariantCulture)); return _mapper.Map(call); } /// /// /// /// /// Voip /// [Create(@"voip/call/{callId:regex(\w+)}/answer")] public VoipCallDto AnswerCall([FromRoute] string callId) { var dao = _daoFactory.GetVoipDao(); var call = dao.GetCall(callId).NotFoundIfNull(); var number = dao.GetCurrentNumber().NotFoundIfNull(); number.AnswerQueueCall(call.Id); return _mapper.Map(call); } /// /// /// /// /// Voip /// [Create(@"voip/call/{callId:regex(\w+)}/reject")] public VoipCallDto RejectCall([FromRoute] string callId) { var dao = _daoFactory.GetVoipDao(); var call = dao.GetCall(callId).NotFoundIfNull(); var number = dao.GetCurrentNumber().NotFoundIfNull(); number.RejectQueueCall(call.Id); return _mapper.Map(call); } /// /// /// /// /// Voip /// [Create(@"voip/call/{callId:regex(\w+)}/redirect")] public VoipCallDto ReditectCall([FromRoute] string callId, [FromForm] string to) { var dao = _daoFactory.GetVoipDao(); var call = dao.GetCall(callId).NotFoundIfNull(); var number = dao.GetCurrentNumber().NotFoundIfNull(); if (call.ContactId != 0) { var contact = _daoFactory.GetContactDao().GetByID(call.ContactId); var managers = _crmSecurity.GetAccessSubjectGuidsTo(contact); if (!managers.Contains(Guid.Parse(to))) { managers.Add(Guid.Parse(to)); _crmSecurity.SetAccessTo(contact, managers); } } number.RedirectCall(call.Id, to); return _mapper.Map(call); } /// /// /// /// /// Voip /// [Create(@"voip/call/{callId:regex(\w+)}")] public VoipCallDto SaveCall( [FromRoute] string callId, [FromForm] string from, [FromForm] string to, [FromForm] Guid answeredBy, [FromForm] VoipCallStatus? status, [FromForm] string contactId, [FromForm] decimal? price) { var dao = _daoFactory.GetVoipDao(); var call = dao.GetCall(callId) ?? new VoipCall(); call.Id = callId; call.From = Update.IfNotEmptyAndNotEquals(call.From, from); call.To = Update.IfNotEmptyAndNotEquals(call.To, to); call.AnsweredBy = Update.IfNotEmptyAndNotEquals(call.AnsweredBy, answeredBy); try { if (call.ContactId == 0) { var contactPhone = call.Status == VoipCallStatus.Incoming || call.Status == VoipCallStatus.Answered ? call.From : call.To; if (!string.IsNullOrEmpty(contactId)) { call.ContactId = Convert.ToInt32(contactId); } else { _voipEngine.GetContact(call); } if (call.ContactId == 0) { contactPhone = contactPhone.TrimStart('+'); var peopleInst = new Person { FirstName = contactPhone, LastName = _tenantUtil.DateTimeFromUtc(DateTime.UtcNow).ToString("yyyy-MM-dd hh:mm"), ShareType = ShareType.None }; peopleInst.ID = _daoFactory.GetContactDao().SaveContact(peopleInst); _crmSecurity.SetAccessTo(peopleInst, new List { _securityContext.CurrentAccount.ID }); var person = (PersonDto)_mapper.Map(peopleInst); _daoFactory.GetContactInfoDao().Save(new ContactInfo { ContactID = person.Id, IsPrimary = true, InfoType = ContactInfoType.Phone, Data = contactPhone }); call.ContactId = person.Id; } } } catch (Exception) { } if (status.HasValue) { call.Status = status.Value; } if (call.Price == 0 && price.HasValue) { call.Price = price.Value; } call = dao.SaveOrUpdateCall(call); return _mapper.Map(call); } /// /// /// /// /// Voip /// [Create(@"voip/price/{callId:regex(\w+)}")] public void SavePrice([FromRoute] string callId) { _voipEngine.SaveAdditionalInfo(callId); } /// /// /// /// /// Voip /// [Read(@"voip/call")] public IEnumerable GetCalls(string callType, ApiDateTime from, ApiDateTime to, Guid? agent, int? client, int? contactID) { var voipDao = _daoFactory.GetVoipDao(); var filter = new VoipCallFilter { Type = callType, FromDate = from != null ? from.UtcTime : (DateTime?)null, ToDate = to != null ? to.UtcTime.AddDays(1).AddMilliseconds(-1) : (DateTime?)null, Agent = agent, Client = client, ContactID = contactID, SortBy = _apiContext.SortBy, SortOrder = !_apiContext.SortDescending, SearchText = _apiContext.FilterValue, Offset = _apiContext.StartIndex, Max = _apiContext.Count, }; _apiContext.SetDataPaginated(); _apiContext.SetDataFiltered(); _apiContext.SetDataSorted(); _apiContext.TotalCount = voipDao.GetCallsCount(filter); var defaultSmallPhoto = _contactPhotoManager.GetSmallSizePhoto(-1, false); var calls = voipDao.GetCalls(filter).Select( r => { ContactDto contact; if (r.ContactId != 0) { contact = r.ContactIsCompany ? (ContactDto)new CompanyDto() { DisplayName = r.ContactTitle, Id = r.ContactId } : new PersonDto() { DisplayName = r.ContactTitle, Id = r.ContactId }; contact.SmallFotoUrl = _contactPhotoManager.GetSmallSizePhoto(contact.Id, contact.IsCompany); } else { contact = new PersonDto() { SmallFotoUrl = defaultSmallPhoto, Id = -1 }; } var item = _mapper.Map(r); item.Contact = contact; return item; }).ToList(); return calls; } /// /// /// /// /// Voip /// [Read(@"voip/call/missed")] public IEnumerable GetMissedCalls() { var voipDao = _daoFactory.GetVoipDao(); var defaultSmallPhoto = _contactPhotoManager.GetSmallSizePhoto(-1, false); var calls = voipDao.GetMissedCalls(_securityContext.CurrentAccount.ID, 10, DateTime.UtcNow.AddDays(-7)).Select( r => { ContactDto contact; if (r.ContactId != 0) { contact = r.ContactIsCompany ? (ContactDto)new CompanyDto() { DisplayName = r.ContactTitle, Id = r.ContactId } : new PersonDto() { DisplayName = r.ContactTitle, Id = r.ContactId }; contact.SmallFotoUrl = _contactPhotoManager.GetSmallSizePhoto(contact.Id, contact.IsCompany); } else { contact = new PersonDto() { SmallFotoUrl = defaultSmallPhoto, Id = -1 }; } var item = _mapper.Map(r); item.Contact = contact; return item; }).ToList(); _apiContext.SetDataPaginated(); _apiContext.SetDataFiltered(); _apiContext.SetDataSorted(); _apiContext.TotalCount = calls.Count; return calls; } /// /// /// /// /// Voip /// [Read(@"voip/call/{callId:regex(\w+)}")] public VoipCallDto GetCall(string callId) { var call = _daoFactory.GetVoipDao().GetCall(callId); _voipEngine.GetContact(call); return _mapper.Map(call); } private ContactDto GetContactWithFotos(ContactDto contact) { contact.SmallFotoUrl = _contactPhotoManager.GetSmallSizePhoto(contact.Id, contact.IsCompany); contact.MediumFotoUrl = _contactPhotoManager.GetMediumSizePhoto(contact.Id, contact.IsCompany); return contact; } } }