(function() { 'use strict'; var mod = angular.module('myMessages'); var serviceId = 'myMessagesService'; mod.factory(serviceId, ['$q', 'myMessagesContext', 'myUsersDataContext', 'datacontext', 'user', '$filter', 'common', 'fileUpload', myMessagesService]); function myMessagesService($q, myMessagesContext, myUsersDataContext, datacontext, user, $filter, common, fileUpload) { var serviceData = { conversations: null, unreadConversations: null, users: [], viewConversation: null, allUserTags: [], currentUser: {} } var getLogFn = common.logger.getLogFn; var log = getLogFn(serviceId); var logSuccess = getLogFn(serviceId, 'success'); var logError = getLogFn(serviceId, 'error'); var logWarning = getLogFn(serviceId, 'warning'); user.getProfile().then(function(data) { serviceData.currentUser = data; }); var service = { getAllConversations: getAllConversations, setAllConversations: setAllConversations, getUnreadConversations: getUnreadConversations, setUnreadConversations: setUnreadConversations, getUsers: getUsers, getUnreadUsers: getUnreadUsers, getAllUserTags: getAllUserTags, setViewConversation: setViewConversation, getViewConversation: getViewConversation, addTag: addTag, removeTag: removeTag, replyToConversation: replyToConversation, createNewConversation: createNewConversation, startNewConversation: startNewConversation, getRequirementsForSelectedConversationType: getRequirementsForSelectedConversationType, selectParticipant: selectParticipant, isSelectedUserInParticipants: isSelectedUserInParticipants, checkForExistingConversation: checkForExistingConversation, getAttachmentType: getAttachmentType }; return service; function getAllConversations() { return serviceData.conversations; } function setAllConversations() { serviceData.conversations = myMessagesContext.getConversations(); return serviceData.conversations; } function getUnreadConversations() { return serviceData.unreadConversations; } function setUnreadConversations() { if (serviceData.unreadConversations == null) serviceData.unreadConversations = myMessagesContext.getUnreadConversations(); return serviceData.unreadConversations; } function getUsers() { var done = $q.defer(); if (serviceData.users.length === 0) { getUserIds().then(function (userIds) { var runningList = []; angular.forEach(userIds, function (userId) { if (runningList.indexOf(userId) === -1) { serviceData.users.push({ userId: userId }); runningList.push(userId); } }); done.resolve(serviceData.users); // we can use the user service for this as it will be cached. //getAllUserDetails(userIds).then(function(data) { // serviceData.users = data; //}); }); } else done.resolve(serviceData.users); return done.promise; function getUserIds() { var deferred = $q.defer(); var promises = []; var usersIds; return myUsersDataContext.getOrganisations().then(function (orgs) { // add the functions which return promises to the arrays promises.push(myMessagesContext.getParticipantsForUser()); angular.forEach(orgs, function (org) { promises.push(myUsersDataContext.getUserIdsForOrg(org.id)); }); // we need both functions to have finished then we can return all the user ids $q.all(promises).then(function (userIdsFromCalls) { var userids = [] angular.forEach(userIdsFromCalls, function (call) { angular.forEach(call, function (userId) { userids.push(userId) }); }); deferred.resolve(userids); }); return deferred.promise; }); } } function getAllUserDetails(userIds) { var details = {}; var deferred = $q.defer(); datacontext.getUserSummary({ userIds: userIds }).then(function (data) { angular.forEach(data, function (user) { details[user.userId] = user; }); deferred.resolve(details); }); return deferred.promise; } function getUnreadUsers() { return myMessagesContext.getParticipantsForUser(function(userIds) { getAllUserDetails(userIds).then(function(data) { return data; }); }); } function getAllUserTags() { var deferred = $q.defer(); if (serviceData.allUserTags.length === 0) { myMessagesContext.getAllUserTagsForConversations().then(function (data) { serviceData.allUserTags = data; angular.forEach(serviceData.allUserTags, function (tag) { tag.searchTag = tag.value.replace(/-/g, ' '); }); deferred.resolve(serviceData.allUserTags); }); } else deferred.resolve(serviceData.allUserTags); return deferred.promise; } function setViewConversation(conversation) { serviceData.viewConversation = conversation; if (conversation.isUnreadForUser) { myMessagesContext.setReadStatusForConversation(conversation); conversation.isUnreadForUser = false; } } function getViewConversation() { if (serviceData.viewConversation) return serviceData.viewConversation; else return null; } function addTag(newTag, participant) { newTag = newTag.replace(/[^a-zA-Z0-9\s]/g, '').replace(/^\s+|\s+$/, '').replace(/\s+/g, '-').toLowerCase(); var existing = false; angular.forEach(participant.tags, function(tag) { if (tag.value === newTag) existing = true; }); if (!existing) { participant.tags.push({ value: newTag, searchTag: newTag.replace(/-/g, ' ') }); if (serviceData.allUserTags.indexOf(newTag) === -1) serviceData.allUserTags.push({ value: newTag }); myMessagesContext.addTagsToConversation(participant).then(logSuccess('Tag added successfully.')); } else { logWarning('This tag has already been used on this conversation.') } }; function removeTag(tag, participant) { participant.tags.splice(participant.tags.indexOf(tag), 1); serviceData.allUserTags.splice(serviceData.allUserTags.indexOf(tag.value), 1); myMessagesContext.removeTagsFromConversation(participant).then(logSuccess('Tag removed successfully.')) } function replyToConversation(parentConversation, messageContent, attachments) { // we need to upload any attachments if there are any before we can attach them to the message var deferred = $q.defer(); if (attachments) { uploadAttachments(attachments).then(function (uploaded) { deferred.resolve(uploaded); }); } else deferred.resolve(null); return deferred.promise.then(function (attachments) { var message = createNewMessageObject(messageContent, parentConversation.id, attachments); parentConversation.dateLastUpdated = $filter('date')(Date.now(), 'medium'); return myMessagesContext.addMessageToConversation(message); }); } function createNewMessageObject(messageContent, parentConversationId, uploadedAttachments) { var newMessage = { content: messageContent, messageSenders: [{userId: serviceData.currentUser.userId}], dateCreated: $filter('date')(Date.now(), 'medium'), dateLastUpdated: $filter('date')(Date.now(), 'medium'), messageRecipients: [], attachments: [] } if (parentConversationId) newMessage.conversationId = parentConversationId; if (uploadedAttachments) angular.forEach(uploadedAttachments, function (attachment) { newMessage.attachments.push({ fileUrl: attachment.fileUrl, fileExtension: attachment.fileExtension, fileName: attachment.fileName, attachmentType: attachment.attachmentType }); }); return newMessage; } function createNewConversation(participants, messageContent, conversationName, requirements, attachments) { // we need to upload any attachments if there are any before we can attach them to the message var deferred = $q.defer(); if (attachments) { uploadAttachments(attachments).then(function (uploaded) { deferred.resolve(uploaded); }); } else deferred.resolve(null); return deferred.promise.then(function (attachments) { var message = createNewMessageObject(messageContent, null, attachments); participants.unshift({ userId: serviceData.currentUser.userId }); if (requirements.requiredUsers) angular.forEach(requirements.requiredUsers, function (requiredUser) { participants.push(requiredUser); }); var conversation = { creator: serviceData.currentUser.userId, messages: [message], participants: participants, subject: conversationName, type: requirements.typeEnum } var checked = checkConversationAgainstRequirements(conversation); if (checked === true) return myMessagesContext.createConversation(conversation); return checked; }); function checkConversationAgainstRequirements(conversation) { if (requirements.minParticipants > conversation.participants.length) return 'You haven\'t selected enough people'; else if (requirements.maxParticipants && requirements.maxParticipants < conversation.participants.length) return 'You have selected too many people'; else if (requirements.requiredName && conversation.subject == null) return 'You need to supply a name or subject'; else return true; } } function startNewConversation(conversationContainer) { conversationContainer.newMessageContent = null; conversationContainer.newGroupName = null; conversationContainer.participants = []; return {}; } function getRequirementsForSelectedConversationType(type) { var requirements = {}; if (type === 'chat') { requirements = { type: type, typeEnum: 0, minParticipants: 2, maxParticipants: 2, requiredUsers: null, requiredName: null }; } else if (type === 'groupConversation') { requirements = { type: type, typeEnum: 0, minParticipants: 3, maxParticipants: null, requiredUsers: null, requiredName: true }; } else if (type === 'broadcast') { requirements = { type: type, typeEnum: 1, minParticipants: 3, maxParticipants: null, requiredUsers: null, requiredName: true }; } else if (type === 'provideFeedback') { requirements = { type: type, typeEnum: 2, minParticipants: 3, maxParticipants: null, requiredUsers: [/*Add the feedback user ids*/], requiredName: null }; } else if (type === 'contactSupport') { requirements = { type: type, typeEnum: 3, minParticipants: 2, maxParticipants: null, requiredUsers: [/*Add the support user ids*/], requiredName: null }; } else if (type === 'systemBroadcast') { requirements = { type: type, typeEnum: 1, minParticipants: 2, maxParticipants: null, requiredName: null }; } return requirements; } function selectParticipant(participants, selectedUser) { var existing = isSelectedUserInParticipants(participants, selectedUser); if (!existing) addSelectedParticipant(participants, selectedUser); else removeSelectedParticipant(participants, existing) return participants; function addSelectedParticipant(array, user) { array.push({ userId: user.userId }); } function removeSelectedParticipant(array, participant) { array.splice(array.indexOf(participant), 1); } } function isSelectedUserInParticipants(array, user) { var existingParticipant = $filter('filter')(array, function (participant) { if (participant.userId === user.userId) return participant; })[0]; return existingParticipant; } function checkForExistingConversation(conversations, participants) { var filteredConversations = $filter('filter')(conversations, function (conv) { if (conv.participants.length === 2) { var participantInConversation = $filter('filter')(conv.participants, function (part) { return part.userId === participants[0].userId; })[0]; if (participantInConversation) return conv.id } }); return filteredConversations[0]; } function uploadAttachments(attachments) { var numberOfFiles = attachments.length; var uploadedFiles = []; var deferred = $q.defer(); angular.forEach(attachments, function (attachment) { attachment.fileName = attachment.name.replace(/[()]/g, '').replace(/\s+/g, '-').toLowerCase(); //remove brackets and spaces attachment.fileExtension = attachment.fileName.split('.').pop(); attachment.attachmentType = getAttachmentType(attachment.type); fileUpload.uploadFile(attachment, attachment, fileUploadSuccess, UploadProgress, UploadError, cloudinaryUploadPath); }); return deferred.promise; function fileUploadSuccess(files, data) { handleUploadResponse(files, data); return; } function handleUploadResponse(files, response) { numberOfFiles = numberOfFiles - 1; uploadedFiles.push(files); if (numberOfFiles === 0) deferred.resolve(uploadedFiles); } // Generate the image upload process percentage function UploadProgress(percentComplete) { //$scope.progress = percentComplete; //$scope.uploadStatus = "Uploading... " + percentComplete + "%"; //console.log($scope.uploadStatus); } function UploadError() { // Throw an error } } function getAttachmentType(type) { if (type.includes('image')) return 0; if (type.includes('video')) return 1; return 2; // add showcase } } })();