Example #1
0
        public async Task <IActionResult> UploadImage(UploadViewModel model, string albumId)
        {
            var album = await _context.Albums
                        .Include(a => a.Images)
                        .SingleAsync(a => a.Id == albumId);

            if (album == null)
            {
                return(BadRequest());
            }
            if (!await HasPermissionTo(album))
            {
                return(Forbid());
            }

            #region Compress and copy

            var          compressedByTinify = false;
            var          file = model.File;
            var          appTinifyEnabled = bool.Parse(await _settingsHelper.Get(Settings.EnableTinifyCompress));
            var          canCompressByTinify = new string[] { "image/jpeg", "image/png" }.Any(s => s.Contains(file.ContentType));
            MemoryStream imageStream;
            if (model.Compress && appTinifyEnabled && canCompressByTinify)
            {
                using (var ms = new MemoryStream())
                {
                    await file.CopyToAsync(ms);

                    var byteFile  = ms.ToArray();
                    var tinifyKey = await _settingsHelper.Get(Settings.TinifyApiKey);

                    var tinify = new Tinify(tinifyKey);
                    _logger.LogDebug("Starting upload to Tinify...");
                    var tinifyWatch = System.Diagnostics.Stopwatch.StartNew();
                    byteFile = await tinify.Compress(byteFile);

                    tinifyWatch.Stop();
                    _logger.LogDebug($"Upload to Tinify used: {tinifyWatch.ElapsedMilliseconds}ms");
                    imageStream        = new MemoryStream(byteFile);
                    compressedByTinify = true;
                }
            }
            else
            {
                _logger.LogWarning("Image will not compress by Tinify");
                imageStream = new MemoryStream();
                await file.CopyToAsync(imageStream);
            }
            #endregion

            #region Internal operation
            bool hasThumbnail;
            System.Drawing.Image tempThumbImage = null;
            imageStream.Position = 0;
            using (var image = System.Drawing.Image.FromStream(imageStream))
            {
                hasThumbnail = image.Width > 255;
                if (hasThumbnail)
                {
                    tempThumbImage = ImageToThumbnail(image);
                }
            }

            imageStream.Position = 0;
            var hash       = (new SHA1CryptoServiceProvider()).ComputeHash(imageStream);
            var imageModel = new Image
            {
                Name         = file.FileName,
                MimeType     = file.ContentType,
                Sha1         = BitConverter.ToString(hash).Replace("-", ""),
                FileSize     = imageStream.Length,
                OwnBy        = await _userManager.GetUserAsync(User),
                Album        = album,
                HasThumbnail = hasThumbnail,
                Compressed   = compressedByTinify
            };

            // May not work if compress enabled?
            var dup = _context.Images.Where(image => image.Sha1 == imageModel.Sha1).ToList();

            if (dup.Count > 0)
            {
                var dupImage = dup[0];
                StatusMessage = $"Image with SHA1 \"{dupImage.Sha1}\" already exist in album \"{dupImage.Album.Name}\"";
                return(RedirectToAction(nameof(Detail), new { id = albumId }));
            }

            if (string.IsNullOrEmpty(_bucketName))
            {
                throw new Exception("No S3 bucket name was set.");
            }
            #endregion

            #region Upload to S3
            imageStream.Position = 0;
            var s3 = await _awsHelper.GetS3Client();

            _logger.LogDebug("Starting upload to S3...");
            var s3Watch = System.Diagnostics.Stopwatch.StartNew();
            await s3.PutObjectAsync(new PutObjectRequest
            {
                BucketName  = _bucketName,
                Key         = imageModel.Id,
                InputStream = imageStream,
                ContentType = imageModel.MimeType
            });

            if (hasThumbnail)
            {
                await s3.PutObjectAsync(new PutObjectRequest
                {
                    BucketName  = _bucketName,
                    Key         = $"thumbnail/{imageModel.Id}",
                    InputStream = ImageToStream(tempThumbImage),
                    ContentType = GetMimeTypeFromImageFormat(ImageFormat.Jpeg)
                });
            }
            s3Watch.Stop();
            _logger.LogDebug($"Upload to S3 used: {s3Watch.ElapsedMilliseconds}ms");
            _context.Images.Add(imageModel);
            await _context.SaveChangesAsync();

            #endregion

            return(RedirectToAction(nameof(Detail), new { id = albumId }));
        }