mirror of https://github.com/abpframework/eventhub
committed by
GitHub
26 changed files with 5732 additions and 2561 deletions
@ -0,0 +1,10 @@ |
|||||
|
using Volo.Abp.BlobStoring; |
||||
|
|
||||
|
namespace EventHub.Organizations |
||||
|
{ |
||||
|
[BlobContainerName("organization-profile-pictures")] |
||||
|
public class OrganizationProfilePictureContainer |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,73 @@ |
|||||
|
using System; |
||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
|
||||
|
namespace EventHub.Migrations |
||||
|
{ |
||||
|
public partial class Added_Blob_Database : Migration |
||||
|
{ |
||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.CreateTable( |
||||
|
name: "AbpBlobContainers", |
||||
|
columns: table => new |
||||
|
{ |
||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false), |
||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), |
||||
|
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false), |
||||
|
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true), |
||||
|
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true) |
||||
|
}, |
||||
|
constraints: table => |
||||
|
{ |
||||
|
table.PrimaryKey("PK_AbpBlobContainers", x => x.Id); |
||||
|
}); |
||||
|
|
||||
|
migrationBuilder.CreateTable( |
||||
|
name: "AbpBlobs", |
||||
|
columns: table => new |
||||
|
{ |
||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false), |
||||
|
ContainerId = table.Column<Guid>(type: "uniqueidentifier", nullable: false), |
||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), |
||||
|
Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false), |
||||
|
Content = table.Column<byte[]>(type: "varbinary(max)", maxLength: 2147483647, nullable: true), |
||||
|
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true), |
||||
|
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true) |
||||
|
}, |
||||
|
constraints: table => |
||||
|
{ |
||||
|
table.PrimaryKey("PK_AbpBlobs", x => x.Id); |
||||
|
table.ForeignKey( |
||||
|
name: "FK_AbpBlobs_AbpBlobContainers_ContainerId", |
||||
|
column: x => x.ContainerId, |
||||
|
principalTable: "AbpBlobContainers", |
||||
|
principalColumn: "Id", |
||||
|
onDelete: ReferentialAction.Cascade); |
||||
|
}); |
||||
|
|
||||
|
migrationBuilder.CreateIndex( |
||||
|
name: "IX_AbpBlobContainers_TenantId_Name", |
||||
|
table: "AbpBlobContainers", |
||||
|
columns: new[] { "TenantId", "Name" }); |
||||
|
|
||||
|
migrationBuilder.CreateIndex( |
||||
|
name: "IX_AbpBlobs_ContainerId", |
||||
|
table: "AbpBlobs", |
||||
|
column: "ContainerId"); |
||||
|
|
||||
|
migrationBuilder.CreateIndex( |
||||
|
name: "IX_AbpBlobs_TenantId_ContainerId_Name", |
||||
|
table: "AbpBlobs", |
||||
|
columns: new[] { "TenantId", "ContainerId", "Name" }); |
||||
|
} |
||||
|
|
||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.DropTable( |
||||
|
name: "AbpBlobs"); |
||||
|
|
||||
|
migrationBuilder.DropTable( |
||||
|
name: "AbpBlobContainers"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,40 @@ |
|||||
|
using System.IO; |
||||
|
using System.Threading.Tasks; |
||||
|
using EventHub.Organizations; |
||||
|
using EventHub.Web.Pages.Organizations; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
|
||||
|
namespace EventHub.Web.Controllers |
||||
|
{ |
||||
|
[Route("api/organization")] |
||||
|
public class OrganizationController : AbpController |
||||
|
{ |
||||
|
private readonly IOrganizationAppService _organizationAppService; |
||||
|
|
||||
|
public OrganizationController(IOrganizationAppService organizationAppService) |
||||
|
{ |
||||
|
_organizationAppService = organizationAppService; |
||||
|
} |
||||
|
|
||||
|
[HttpPost] |
||||
|
[Authorize] |
||||
|
[Route("save-profile-picture")] |
||||
|
public async Task SaveProfilePicture([FromForm] OrganizationProfilePictureInput input) |
||||
|
{ |
||||
|
byte[] profilePictureContent = new byte[] {}; |
||||
|
|
||||
|
if (input.ProfilePictureFile != null && input.ProfilePictureFile.Length > 0) |
||||
|
{ |
||||
|
using (var memoryStream = new MemoryStream()) |
||||
|
{ |
||||
|
await input.ProfilePictureFile.CopyToAsync(memoryStream); |
||||
|
profilePictureContent = memoryStream.ToArray(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
await _organizationAppService.SaveProfilePictureAsync(input.OrganizationId, profilePictureContent); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using Microsoft.AspNetCore.Http; |
||||
|
|
||||
|
namespace EventHub.Web.Helpers |
||||
|
{ |
||||
|
public class AllowedExtensionsAttribute : ValidationAttribute |
||||
|
{ |
||||
|
private readonly string[] _allowedExtensions; |
||||
|
|
||||
|
public AllowedExtensionsAttribute(string[] allowedExtensions) |
||||
|
{ |
||||
|
_allowedExtensions = allowedExtensions; |
||||
|
} |
||||
|
|
||||
|
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) |
||||
|
{ |
||||
|
if (value == null) |
||||
|
{ |
||||
|
return ValidationResult.Success; |
||||
|
} |
||||
|
|
||||
|
var file = value as IFormFile; |
||||
|
var extension = Path.GetExtension(file.FileName); |
||||
|
|
||||
|
if (file.Length > 0 && file != null) |
||||
|
{ |
||||
|
if (!_allowedExtensions.Contains(extension.ToLower())) |
||||
|
{ |
||||
|
return new ValidationResult("This file extension is not allowed. Allowed extensions: " + string.Join(",", _allowedExtensions)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return ValidationResult.Success; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Microsoft.AspNetCore.Http; |
||||
|
|
||||
|
namespace EventHub.Web.Helpers |
||||
|
{ |
||||
|
public class MaxFileSizeAttribute : ValidationAttribute |
||||
|
{ |
||||
|
private readonly int _maxFileSize; |
||||
|
|
||||
|
public MaxFileSizeAttribute(int maxFileSize) |
||||
|
{ |
||||
|
_maxFileSize = maxFileSize; |
||||
|
} |
||||
|
|
||||
|
protected override ValidationResult IsValid( |
||||
|
object value, ValidationContext validationContext) |
||||
|
{ |
||||
|
if (value == null) |
||||
|
{ |
||||
|
return ValidationResult.Success; |
||||
|
} |
||||
|
|
||||
|
var file = value as IFormFile; |
||||
|
|
||||
|
if (file.Length > 0) |
||||
|
{ |
||||
|
if (file.Length > _maxFileSize) |
||||
|
{ |
||||
|
return new ValidationResult("Maximum file size: " + _maxFileSize); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return ValidationResult.Success; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,118 @@ |
|||||
|
$(function () { |
||||
|
var l = abp.localization.getResource('EventHub'); |
||||
|
|
||||
|
var fileInput = document.getElementById("organization-profile-picture"); |
||||
|
var file; |
||||
|
|
||||
|
fileInput.addEventListener('change', function () { |
||||
|
var showModal = true; |
||||
|
|
||||
|
file = fileInput.files[0]; |
||||
|
|
||||
|
if(file == undefined) { |
||||
|
$("#choose-cover-image").html(l("ChooseOrganizationProfilePicture")); |
||||
|
return; |
||||
|
} |
||||
|
else { |
||||
|
$("#choose-cover-image").html(file.name); |
||||
|
} |
||||
|
|
||||
|
var permittedExtensions = ["jpg", "jpeg", "png"] |
||||
|
var fileExtension = $(this).val().split('.').pop(); |
||||
|
|
||||
|
if (permittedExtensions.indexOf(fileExtension) === -1) { |
||||
|
showModal = false; |
||||
|
abp.message.error(l("OrganizationProfilePictureExtensionNotAllowed")) |
||||
|
.then(() => { |
||||
|
$("#choose-cover-image").html(l("ChooseOrganizationProfilePicture")); |
||||
|
file = null; |
||||
|
}); |
||||
|
} |
||||
|
//1mb
|
||||
|
else if(file.size > 1024 * 1024) { |
||||
|
showModal = false; |
||||
|
abp.message.error(l("OrganizationProfilePictureSizeExceedMessage")) |
||||
|
.then(() => { |
||||
|
$("#choose-cover-image").html(l("ChooseOrganizationProfilePicture")); |
||||
|
file = null; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
var img = new Image(); |
||||
|
img.onload = function () { |
||||
|
var imageError = true; |
||||
|
var sizes = { |
||||
|
width: this.width, |
||||
|
height: this.height |
||||
|
}; |
||||
|
|
||||
|
URL.revokeObjectURL(this.src); |
||||
|
|
||||
|
if(showModal && imageError) { |
||||
|
readURL(file); |
||||
|
$("#picturePreviewModal").modal('show'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var objectURL = URL.createObjectURL(file); |
||||
|
img.src = objectURL; |
||||
|
}); |
||||
|
|
||||
|
function readURL(input) { |
||||
|
if (input) { |
||||
|
var reader = new FileReader(); |
||||
|
|
||||
|
reader.onload = function (e) { |
||||
|
$('#img-upload').attr('src', e.target.result); |
||||
|
} |
||||
|
|
||||
|
reader.readAsDataURL(input); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
$("form#EditOrganizationProfileForm").submit(function (e) { |
||||
|
e.preventDefault(); |
||||
|
|
||||
|
var organizationId = document.getElementById("organization-id").value; |
||||
|
var organizationName = document.getElementById("organization-name").value; |
||||
|
|
||||
|
if(file === undefined) { |
||||
|
file = null; |
||||
|
} |
||||
|
|
||||
|
var formData = new FormData(); |
||||
|
formData.append("OrganizationId", organizationId); |
||||
|
formData.append("ProfilePictureFile", file); |
||||
|
|
||||
|
$.ajax({ |
||||
|
xhr: function() { |
||||
|
var xhr = new window.XMLHttpRequest(); |
||||
|
xhr.upload.addEventListener("progress", function(evt) { |
||||
|
if (evt.lengthComputable) { |
||||
|
var percentage = evt.loaded / evt.total; |
||||
|
percentage = parseInt(percentage * 100); |
||||
|
if(percentage !== 100){ |
||||
|
$('#btnSubmit').prop("disabled", true); |
||||
|
} |
||||
|
} |
||||
|
}, false); |
||||
|
|
||||
|
return xhr; |
||||
|
}, |
||||
|
url: `/api/organization/save-profile-picture`, |
||||
|
data: formData, |
||||
|
type: 'POST', |
||||
|
contentType: false, |
||||
|
processData: false, |
||||
|
success: function(data){ |
||||
|
abp.message |
||||
|
.success(l("OrganizationProfilePictureEditSuccessMessage")) |
||||
|
.then(data => window.location.href = "/Organizations/" + organizationName); |
||||
|
}, |
||||
|
error: function (data) { |
||||
|
abp.message.error(data.responseJSON.error.message); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
}); |
||||
|
}); |
||||
Loading…
Reference in new issue