/* * * (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 ASC.Api.Collections; using ASC.Api.CRM.Wrappers; using ASC.Common.Web; using ASC.Core; using ASC.Core.Users; using ASC.CRM.Core; using ASC.CRM.Core.Entities; using ASC.CRM.Core.Enums; using ASC.ElasticSearch; using ASC.MessagingSystem; using ASC.Web.Api.Routing; using ASC.Web.Files.Services.WCFService; using System; using System.Collections.Generic; using System.Linq; namespace ASC.Api.CRM { public partial class CRMController { /// /// Close the case with the ID specified in the request /// /// Close case /// Cases /// Case ID /// /// /// /// Case /// [Update(@"case/{caseid:int}/close")] public CasesWrapper CloseCases(int caseid) { if (caseid <= 0) throw new ArgumentException(); var cases = DaoFactory.GetCasesDao().CloseCases(caseid); if (cases == null) throw new ItemNotFoundException(); MessageService.Send(MessageAction.CaseClosed, MessageTarget.Create(cases.ID), cases.Title); return CasesWrapperHelper.Get(cases); } /// /// Resume the case with the ID specified in the request /// /// Resume case /// Cases /// Case ID /// /// /// /// Case /// [Update(@"case/{caseid:int}/reopen")] public CasesWrapper ReOpenCases(int caseid) { if (caseid <= 0) throw new ArgumentException(); var cases = DaoFactory.GetCasesDao().ReOpenCases(caseid); if (cases == null) throw new ItemNotFoundException(); MessageService.Send(MessageAction.CaseOpened, MessageTarget.Create(cases.ID), cases.Title); return CasesWrapperHelper.Get(cases); } /// /// Creates the case with the parameters specified in the request /// /// Create case /// Case title /// Participants /// User field list /// Case privacy: private or not /// List of users with access to the case /// Notify users in accessList about the case /// Case /// Cases /// /// /// /// [Create(@"case")] public CasesWrapper CreateCases( string title, IEnumerable members, IEnumerable> customFieldList, bool isPrivate, IEnumerable accessList, bool isNotify) { if (string.IsNullOrEmpty(title)) throw new ArgumentException(); var casesID = DaoFactory.GetCasesDao().CreateCases(title); var cases = new Cases { ID = casesID, Title = title, CreateBy = SecurityContext.CurrentAccount.ID, CreateOn = DateTime.UtcNow }; SetAccessToCases(cases, isPrivate, accessList, isNotify, false); var membersList = members != null ? members.ToList() : new List(); if (membersList.Any()) { var contacts = DaoFactory.GetContactDao().GetContacts(membersList.ToArray()).Where(CRMSecurity.CanAccessTo).ToList(); membersList = contacts.Select(m => m.ID).ToList(); DaoFactory.GetCasesDao().SetMembers(cases.ID, membersList.ToArray()); } if (customFieldList != null) { var existingCustomFieldList = DaoFactory.GetCustomFieldDao().GetFieldsDescription(EntityType.Case).Select(fd => fd.ID).ToList(); foreach (var field in customFieldList) { if (string.IsNullOrEmpty(field.Value) || !existingCustomFieldList.Contains(field.Key)) continue; DaoFactory.GetCustomFieldDao().SetFieldValue(EntityType.Case, cases.ID, field.Key, field.Value); } } return CasesWrapperHelper.Get(DaoFactory.GetCasesDao().GetByID(casesID)); } /// /// Updates the selected case with the parameters specified in the request /// /// Update case /// Case ID /// Case title /// Participants /// User field list /// Case privacy: private or not /// List of users with access to the case /// Notify users in accessList about the case /// Cases /// Case /// /// /// /// /// [Update(@"case/{caseid:int}")] public CasesWrapper UpdateCases( int caseid, string title, IEnumerable members, IEnumerable> customFieldList, bool isPrivate, IEnumerable accessList, bool isNotify) { if ((caseid <= 0) || (string.IsNullOrEmpty(title))) throw new ArgumentException(); var cases = DaoFactory.GetCasesDao().GetByID(caseid); if (cases == null) throw new ItemNotFoundException(); cases.Title = title; DaoFactory.GetCasesDao().UpdateCases(cases); if (CRMSecurity.IsAdmin || cases.CreateBy == SecurityContext.CurrentAccount.ID) { SetAccessToCases(cases, isPrivate, accessList, isNotify, false); } var membersList = members != null ? members.ToList() : new List(); if (membersList.Any()) { var contacts = DaoFactory.GetContactDao().GetContacts(membersList.ToArray()).Where(CRMSecurity.CanAccessTo).ToList(); membersList = contacts.Select(m => m.ID).ToList(); DaoFactory.GetCasesDao().SetMembers(cases.ID, membersList.ToArray()); } if (customFieldList != null) { var existingCustomFieldList = DaoFactory.GetCustomFieldDao().GetFieldsDescription(EntityType.Case).Select(fd => fd.ID).ToList(); foreach (var field in customFieldList) { if (string.IsNullOrEmpty(field.Value) || !existingCustomFieldList.Contains(field.Key)) continue; DaoFactory.GetCustomFieldDao().SetFieldValue(EntityType.Case, cases.ID, field.Key, field.Value); } } return CasesWrapperHelper.Get(cases); } /// /// Sets access rights for the selected case with the parameters specified in the request /// /// Case ID /// Case privacy: private or not /// List of users with access to the case /// Set rights to case /// Cases /// /// /// /// Case /// [Update(@"case/{caseid:int}/access")] public CasesWrapper SetAccessToCases(int caseid, bool isPrivate, IEnumerable accessList) { if (caseid <= 0) throw new ArgumentException(); var cases = DaoFactory.GetCasesDao().GetByID(caseid); if (cases == null) throw new ItemNotFoundException(); if (!(CRMSecurity.IsAdmin || cases.CreateBy == SecurityContext.CurrentAccount.ID)) throw CRMSecurity.CreateSecurityException(); return SetAccessToCases(cases, isPrivate, accessList, false, true); } private CasesWrapper SetAccessToCases(Cases cases, bool isPrivate, IEnumerable accessList, bool isNotify, bool isMessageServicSende) { var accessListLocal = accessList != null ? accessList.Distinct().ToList() : new List(); if (isPrivate && accessListLocal.Any()) { if (isNotify) { accessListLocal = accessListLocal.Where(u => u != SecurityContext.CurrentAccount.ID).ToList(); NotifyClient.SendAboutSetAccess(EntityType.Case, cases.ID, DaoFactory, accessListLocal.ToArray()); } if (!accessListLocal.Contains(SecurityContext.CurrentAccount.ID)) { accessListLocal.Add(SecurityContext.CurrentAccount.ID); } CRMSecurity.SetAccessTo(cases, accessListLocal); if (isMessageServicSende) { var users = GetUsersByIdList(accessListLocal); MessageService.Send(MessageAction.CaseRestrictedAccess, MessageTarget.Create(cases.ID), cases.Title, users.Select(x => x.DisplayUserName(false, DisplayUserSettingsHelper))); } } else { CRMSecurity.MakePublic(cases); if (isMessageServicSende) { MessageService.Send(MessageAction.CaseOpenedAccess, MessageTarget.Create(cases.ID), cases.Title); } } return CasesWrapperHelper.Get(cases); } /// /// Sets access rights for other users to the list of cases with the IDs specified in the request /// /// Case ID list /// Case privacy: private or not /// List of users with access /// Set case access rights /// Cases /// /// /// /// Case list /// [Update(@"case/access")] public IEnumerable SetAccessToBatchCases(IEnumerable casesid, bool isPrivate, IEnumerable accessList) { var result = new List(); var cases = DaoFactory.GetCasesDao().GetCases(casesid); if (!cases.Any()) return new List(); foreach (var c in cases) { if (c == null) throw new ItemNotFoundException(); if (!(CRMSecurity.IsAdmin || c.CreateBy == SecurityContext.CurrentAccount.ID)) continue; SetAccessToCases(c, isPrivate, accessList, false, true); result.Add(c); } return ToListCasesWrappers(result); } /// /// Sets access rights for other users to the list of all cases matching the parameters specified in the request /// /// Contact ID /// Case status /// Tags /// Case privacy: private or not /// List of users with access /// Set case access rights /// Cases /// /// /// /// Case list /// [Update(@"case/filter/access")] public IEnumerable SetAccessToBatchCases( int contactid, bool? isClosed, IEnumerable tags, bool isPrivate, IEnumerable accessList ) { var result = new List(); var caseses = DaoFactory.GetCasesDao().GetCases(ApiContext.FilterValue, contactid, isClosed, tags, 0, 0, null); if (!caseses.Any()) return new List(); foreach (var casese in caseses) { if (casese == null) throw new ItemNotFoundException(); if (!(CRMSecurity.IsAdmin || casese.CreateBy == SecurityContext.CurrentAccount.ID)) continue; SetAccessToCases(casese, isPrivate, accessList, false, true); result.Add(casese); } return ToListCasesWrappers(result); } /// /// Returns the detailed information about the case with the ID specified in the request /// /// Get case by ID /// Cases /// Case ID /// /// [Read(@"case/{caseid:int}")] public CasesWrapper GetCaseByID(int caseid) { if (caseid <= 0) throw new ItemNotFoundException(); var cases = DaoFactory.GetCasesDao().GetByID(caseid); if (cases == null || !CRMSecurity.CanAccessTo(cases)) throw new ItemNotFoundException(); return CasesWrapperHelper.Get(cases); } /// /// Returns the list of all cases matching the parameters specified in the request /// /// Get case list /// Contact ID /// Case status /// Tags /// Cases /// /// Case list /// [Read(@"case/filter")] public IEnumerable GetCases(int contactid, bool? isClosed, IEnumerable tags) { IEnumerable result; SortedByType sortBy; OrderBy casesOrderBy; var searchString = ApiContext.FilterValue; if (ASC.CRM.Classes.EnumExtension.TryParse(ApiContext.SortBy, true, out sortBy)) { casesOrderBy = new OrderBy(sortBy, !ApiContext.SortDescending); } else if (string.IsNullOrEmpty(ApiContext.SortBy)) { casesOrderBy = new OrderBy(SortedByType.Title, true); } else { casesOrderBy = null; } var fromIndex = (int)ApiContext.StartIndex; var count = (int)ApiContext.Count; if (casesOrderBy != null) { result = ToListCasesWrappers( DaoFactory .GetCasesDao() .GetCases( searchString, contactid, isClosed, tags, fromIndex, count, casesOrderBy)).ToList(); ApiContext.SetDataPaginated(); ApiContext.SetDataFiltered(); ApiContext.SetDataSorted(); } else { result = ToListCasesWrappers( DaoFactory .GetCasesDao() .GetCases( searchString, contactid, isClosed, tags, 0, 0, null)).ToList(); } int totalCount; if (result.Count() < count) { totalCount = fromIndex + result.Count(); } else { totalCount = DaoFactory.GetCasesDao().GetCasesCount(searchString, contactid, isClosed, tags); } ApiContext.SetTotalCount(totalCount); return result; } /// /// Deletes the case with the ID specified in the request /// /// Delete case /// Case ID /// Cases /// /// /// /// Case /// [Delete(@"case/{caseid:int}")] public CasesWrapper DeleteCase(int caseid) { if (caseid <= 0) throw new ArgumentException(); var cases = DaoFactory.GetCasesDao().DeleteCases(caseid); if (cases == null) throw new ItemNotFoundException(); MessageService.Send(MessageAction.CaseDeleted, MessageTarget.Create(cases.ID), cases.Title); return CasesWrapperHelper.Get(cases); } /// /// Deletes the group of cases with the IDs specified in the request /// /// Case ID list /// /// /// Delete case group /// Cases /// /// Case list /// [Update(@"case")] public IEnumerable DeleteBatchCases(IEnumerable casesids) { if (casesids == null) throw new ArgumentException(); casesids = casesids.Distinct(); var caseses = DaoFactory.GetCasesDao().DeleteBatchCases(casesids.ToArray()); if (caseses == null || !caseses.Any()) return new List(); MessageService.Send(MessageAction.CasesDeleted, MessageTarget.Create(casesids), caseses.Select(c => c.Title)); return ToListCasesWrappers(caseses); } /// /// Deletes the list of all cases matching the parameters specified in the request /// /// Contact ID /// Case status /// Tags /// /// /// Delete case group /// Cases /// /// Case list /// [Delete(@"case/filter")] public IEnumerable DeleteBatchCases(int contactid, bool? isClosed, IEnumerable tags) { var caseses = DaoFactory.GetCasesDao().GetCases(ApiContext.FilterValue, contactid, isClosed, tags, 0, 0, null); if (!caseses.Any()) return new List(); caseses = DaoFactory.GetCasesDao().DeleteBatchCases(caseses); MessageService.Send(MessageAction.CasesDeleted, MessageTarget.Create(caseses.Select(c => c.ID)), caseses.Select(c => c.Title)); return ToListCasesWrappers(caseses); } /// /// Returns the list of all contacts associated with the case with the ID specified in the request /// /// Get all case contacts /// Case ID /// Cases /// Contact list /// [Read(@"case/{caseid:int}/contact")] public IEnumerable GetCasesMembers(int caseid) { var contactIDs = DaoFactory.GetCasesDao().GetMembers(caseid); return contactIDs == null ? new ItemList() : ToListContactWrapper(DaoFactory.GetContactDao().GetContacts(contactIDs)); } /// /// Adds the selected contact to the case with the ID specified in the request /// /// Add case contact /// Cases /// Case ID /// Contact ID /// /// /// /// Participant /// [Create(@"case/{caseid:int}/contact")] public ContactWrapper AddMemberToCases(int caseid, int contactid) { if ((caseid <= 0) || (contactid <= 0)) throw new ArgumentException(); var cases = DaoFactory.GetCasesDao().GetByID(caseid); if (cases == null || !CRMSecurity.CanAccessTo(cases)) throw new ItemNotFoundException(); var contact = DaoFactory.GetContactDao().GetByID(contactid); if (contact == null || !CRMSecurity.CanAccessTo(contact)) throw new ItemNotFoundException(); DaoFactory.GetCasesDao().AddMember(caseid, contactid); var messageAction = contact is Company ? MessageAction.CaseLinkedCompany : MessageAction.CaseLinkedPerson; MessageService.Send(messageAction, MessageTarget.Create(cases.ID), cases.Title, contact.GetTitle()); return ToContactWrapper(contact); } /// /// Delete the selected contact from the case with the ID specified in the request /// /// Delete case contact /// Cases /// Case ID /// Contact ID /// /// /// /// Participant /// [Delete(@"case/{caseid:int}/contact/{contactid:int}")] public ContactWrapper DeleteMemberFromCases(int caseid, int contactid) { if ((caseid <= 0) || (contactid <= 0)) throw new ArgumentException(); var cases = DaoFactory.GetCasesDao().GetByID(caseid); if (cases == null || !CRMSecurity.CanAccessTo(cases)) throw new ItemNotFoundException(); var contact = DaoFactory.GetContactDao().GetByID(contactid); if (contact == null || !CRMSecurity.CanAccessTo(contact)) throw new ItemNotFoundException(); var result = ToContactWrapper(contact); DaoFactory.GetCasesDao().RemoveMember(caseid, contactid); var messageAction = contact is Company ? MessageAction.CaseUnlinkedCompany : MessageAction.CaseUnlinkedPerson; MessageService.Send(messageAction, MessageTarget.Create(cases.ID), cases.Title, contact.GetTitle()); return result; } /// /// Returns the list of 30 cases in the CRM module with prefix /// /// /// /// Cases /// /// Cases list /// /// false [Read(@"case/byprefix")] public IEnumerable GetCasesByPrefix(string prefix, int contactID) { var result = new List(); if (contactID > 0) { var findedCases = DaoFactory.GetCasesDao().GetCases(string.Empty, contactID, null, null, 0, 0, null); foreach (var item in findedCases) { if (item.Title.IndexOf(prefix, StringComparison.Ordinal) != -1) { result.Add(CasesWrapperHelper.Get(item)); } } ApiContext.SetTotalCount(findedCases.Count); } else { const int maxItemCount = 30; var findedCases = DaoFactory.GetCasesDao().GetCasesByPrefix(prefix, 0, maxItemCount); foreach (var item in findedCases) { result.Add(CasesWrapperHelper.Get(item)); } } return result; } private IEnumerable ToListCasesWrappers(ICollection items) { if (items == null || items.Count == 0) return new List(); var result = new List(); var contactIDs = new List(); var casesIDs = items.Select(item => item.ID).ToArray(); var customFields = DaoFactory.GetCustomFieldDao() .GetEnityFields(EntityType.Case, casesIDs) .GroupBy(item => item.EntityID) .ToDictionary(item => item.Key, item => item.Select(ToCustomFieldBaseWrapper)); var casesMembers = DaoFactory.GetCasesDao().GetMembers(casesIDs); foreach (var value in casesMembers.Values) { contactIDs.AddRange(value); } var contacts = DaoFactory .GetContactDao() .GetContacts(contactIDs.Distinct().ToArray()) .ToDictionary(item => item.ID, x => ContactWrapperHelper.GetContactBaseWrapper(x)); foreach (var cases in items) { var casesWrapper = CasesWrapperHelper.Get(cases); casesWrapper.CustomFields = customFields.ContainsKey(cases.ID) ? customFields[cases.ID] : new List(); casesWrapper.Members = casesMembers.ContainsKey(cases.ID) ? casesMembers[cases.ID].Where(contacts.ContainsKey).Select(item => contacts[item]) : new List(); result.Add(casesWrapper); } return result; } private IEnumerable GetUsersByIdList(IEnumerable ids) { return UserManager.GetUsers().Where(x => ids.Contains(x.ID)); } } }