angular.module('kalgudiApp').service('S3UploadService', ['$rootScope', '$q', '$state', 'helpandlegalservice', 'Upload', function ($rootScope, $q, $state, helpandlegalservice, Upload) { isStateSH = false; isStateQA = false; /** * List of constant S3 locations. */ this.S3LOCATIONS = { SH: 'data/activity/share-a-thought/', QA: 'data/activity/qa/', OTHERS: 'data/businessAttachments/' } getStateDetails = function () { // Try to get state details. try { var statename = $state.current.data.action; isStateSH = (statename === "shareAnUpdate"); isStateQA = (statename === "createQuestion" || statename === 'questionfullview'); } catch (e) { isStateQA = false; isStateSH = false; } } getStateDetails(); /** * Function to construct S3 file name to be uploaded. * File name is a combination of User profile key, * current time and file extension. */ constructFileName = function (fileName) { return ( $rootScope.loggedInUserBusinessProfile.profileKey + (new Date().getTime() / 1000.0) + "." + fileName.split('.').pop()); } /** * Returns file content type if specified in file. * Otherwise returns default file content tyOTHERSpe i.e. * 'application/octet-stream' */ getContentType = function (file) { return (file.type != '') ? file.type : 'application/octet-stream' } /** * According to environment it will select S3 bucket. */ this.getBucketName = function () { if (IP_DOMAIN.indexOf('devkalgudi') > -1) return "http://devkalgudidata"; else if (IP_DOMAIN.indexOf('rckalgudi') > -1) return "https://rckalgudidata"; else if (window.location.origin.includes('192.168')) return window.location.origin + ':8001/devkalgudidata/'; else return "https://kalgudidata"; } var s3Service = this; this.compressImage = function (file) { var defer = $q.defer(); //Create an image var img = document.createElement("img"); // Create a file reader var reader = new FileReader(); // Load files into file reader reader.readAsDataURL(file); // Set the image once loaded into file reader reader.onload = function(e) { img.src = e.target.result; s3Service.base64Image = e; var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0); var MAX_WIDTH = 960; var MAX_HEIGHT = 960; img.onload = function() { var width = img.width; var height = img.height; if (width > 0 || height > 0) { if (width > height) { if (width > MAX_WIDTH) { height *= MAX_WIDTH / width; width = MAX_WIDTH; } } else { if (height > MAX_HEIGHT) { width *= MAX_HEIGHT / height; height = MAX_HEIGHT; } } canvas.width = width; canvas.height = height; var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, width, height); var dataurl = canvas.toDataURL("image/jpeg",0.82); var byteString; if (dataurl.split(',')[0].indexOf('base64') >= 0) { byteString = atob(dataurl.split(',')[1]); } else { byteString = unescape(dataurl.split(',')[1]); } // separate out the mime component var mimeString = dataurl.split(',')[0].split(':')[1].split(';')[0]; // write the bytes of the string to a typed array var ia = new Uint8Array(byteString.length); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } var tempBlob = new Blob([ia], {type:"image/jpeg"}); tempBlob.name=file.name; defer.resolve(tempBlob); // return tempBlob; } else { defer.resolve(file); // return file; } } } return defer.promise; } /** * According to state it will pick stream type to get help * and legel policy from service. * * Returns 'stream' if current state is create question or * share an update. Otherwise return 'business' */ this.getStreamType = function (isShare) { getStateDetails(); return (isShare || isStateQA || isStateSH) ? "stream" : "business"; } /** * According to state it defines S3 location to upload an object. */ this.getS3Location = function () { getStateDetails(); if (isStateQA) return this.S3LOCATIONS.QA; else if (isStateSH) return this.S3LOCATIONS.SH; else return this.S3LOCATIONS.OTHERS; } /** * Gets, S3 policy data. Use this function before uploading * an object to S3. * * @param {1} fileType Content type to upload. */ this.getS3UploadPolicy = function (fileType, isStreamShare) { var deferred = $q.defer(); var streamType = this.getStreamType(isStreamShare); helpandlegalservice.uploadS3Policy(streamType, fileType) .then( function (policy) { deferred.resolve(policy); }, function (err) { deferred.reject(err); } ); return deferred.promise; }; /** * Function used to upload file to S3. * It return a promise object that made the upload service * call. * On success it resolves the uploaded URL. */ this.uploadFileToS3 = function (policyData, fileType, file, s3Loc) { var deferred = $q.defer(); var bucketName = this.getBucketName(); var s3Location = s3Loc || this.getS3Location(); var fileName = constructFileName(file.fileName || file.name); var contentType = getContentType(file); /* * Prepare S3 upload payload request object. */ var s3ReqPayload = { url: bucketName + (IS_DOCKER ? '': '.s3.amazonaws.com/'), // S3 upload url including bucket name method: 'POST', data: { key: s3Location + fileName, // Key to store file on S3, could be file name or customized AWSAccessKeyId: 'AKIAJPKIEGQPZLTARDXQ', // AWS acess key acl: 'public-read', // Sets access to uploaded file in bucket: private, public-read, ... policy: policyData.policy, // base64-encoded json policy signature: policyData.signature, // base64-encoded signature based on policy string "Content-Type": contentType, // Content type of file (NotEmpty) file: file.b64Data || file // Blob data to upload } }; // Upload file to S3 Upload.upload(s3ReqPayload) .then( function (res) { var url = resolveS3UploadedUrl(s3Location, fileName); deferred.resolve(url); }, function (err) { deferred.reject(err); } ); return deferred.promise; }; /** * Constructs URL of uploaded object based on domain, s3 upload * location, file name and secure environment. * * It returns URL of file uploaded to S3. */ resolveS3UploadedUrl = function (s3Location, fileName) { var prefixDomain = ''; if (IP_DOMAIN.split(':')[0] == 'http' || IP_DOMAIN.split(':')[0] == 'https') { prefixDomain = IP_DOMAIN.split('/')[2]; } else { prefixDomain = IP_DOMAIN; } var data = prefixDomain + "/" + s3Location + fileName; if (!IS_DOCKER && data.indexOf("www.") == -1) { data = "www." + data; } return window.env.secure + data; }; /** * Uploads a blob object to S3 and resolves uploaded URL. * * @param file * @param fileType */ this.uploadToS3 = function (file, fileType, s3Location) { var deferred = $q.defer(); // store reference of this var self = this; var isStreamShare = s3Location && (s3Location.length > 0) && !s3Location.includes(this.S3LOCATIONS.OTHERS); /* * Chain S3 file upload with two async functions. * First get policy data, if success then upload * file to S3. * If any error occurs reject the current upload * request. */ this.getS3UploadPolicy(fileType, isStreamShare) .then( function (policy) { // After getting policy data upload file to S3 self.uploadFileToS3(policy, fileType, file, s3Location).then ( function (res) { // Resolve the request deferred.resolve(res); }, function (err) { deferred.reject(err); } ) }, function (err) { deferred.reject(err); } ); return deferred.promise; }; } ] );