mirror of
				https://github.com/D4M13N-D3V/comissions-app-core-api.git
				synced 2025-10-31 01:25:27 +00:00 
			
		
		
		
	feat: cleanup controllers
This commit is contained in:
		
							parent
							
								
									cc2c4ff3c8
								
							
						
					
					
						commit
						facb0f88ce
					
				| @ -34,6 +34,7 @@ public class ArtistController : Controller | ||||
|         _dbContext = dbContext; | ||||
|     } | ||||
|      | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     public async Task<IActionResult> GetArtist() | ||||
| @ -51,103 +52,6 @@ public class ArtistController : Controller | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     [Route("Reviews")] | ||||
|     public async Task<IActionResult> GetArtistReviews([FromQuery]int offset = 0, [FromQuery]int limit = 10) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var Artist = await _dbContext.UserArtists.Include(x=>x.Requests).FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if(Artist==null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         var result = Artist.Requests.Where(x=>x.Reviewed).Skip(offset).Take(limit).Select(x=> new RequestReviewModel() | ||||
|         { | ||||
|             RequestId = x.Id, | ||||
|             Message = x.ReviewMessage, | ||||
|             Rating = x.Rating.Value, | ||||
|             ReviewDate = x.ReviewDate | ||||
|         }).ToList(); | ||||
|          | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     [Route("Reviews/Count")] | ||||
|     public async Task<IActionResult> ReviewCount() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var Artist = await _dbContext.UserArtists.Include(x=>x.Requests).FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if(Artist==null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         var result = Artist.Requests.Where(x=>x.Reviewed).Select(x=> new RequestReviewModel() | ||||
|         { | ||||
|             RequestId = x.Id, | ||||
|             Message = x.ReviewMessage, | ||||
|             Rating = x.Rating.Value, | ||||
|             ReviewDate = x.ReviewDate | ||||
|         }).ToList().Count; | ||||
|          | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     [Route("Stats")] | ||||
|     public async Task<IActionResult> GetArtistStats() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var Artist = await _dbContext.UserArtists.Include(x=>x.Requests).FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if(Artist==null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         var result = Artist.ToStatsModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     [Route("Payout")] | ||||
|     public async Task<IActionResult> Payout() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var Artist = await _dbContext.UserArtists.Include(x=>x.Requests).FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if(Artist==null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
| 
 | ||||
|         var account = _paymentService.GetAccount(Artist.StripeAccountId); | ||||
|         var balance = _paymentService.GetBalance(Artist.StripeAccountId); | ||||
|         var pendingBalance = _paymentService.GetPendingBalance(Artist.StripeAccountId); | ||||
|         var result = new PayoutModel() | ||||
|         { | ||||
|             Enabled = account.PayoutsEnabled, | ||||
|             Balance = balance, | ||||
|             PendingBalance = pendingBalance, | ||||
|             PayoutUrl =  _paymentService.CreateDashboardUrl(Artist.StripeAccountId) | ||||
|         }; | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpPut] | ||||
|     [Authorize("write:artist")] | ||||
|     public async Task<IActionResult> UpdateArtist(ArtistModel model) | ||||
| @ -184,6 +88,24 @@ public class ArtistController : Controller | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     [Route("Stats")] | ||||
|     public async Task<IActionResult> GetArtistStats() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var Artist = await _dbContext.UserArtists.Include(x=>x.Requests).FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if(Artist==null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         var result = Artist.ToStatsModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     [Route("Request")] | ||||
| @ -197,41 +119,6 @@ public class ArtistController : Controller | ||||
|         return Ok(result); | ||||
|     }    | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     [Route("Page")] | ||||
|     public async Task<IActionResult> GetArtistPage() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var Artist = await _dbContext.UserArtists.Include(x=>x.ArtistPageSettings).FirstOrDefaultAsync(artist=>artist.UserId==userId); | ||||
|         if(Artist==null) | ||||
|             return NotFound(); | ||||
|         var result = Artist.ArtistPageSettings.ToModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|      | ||||
|     [HttpPut] | ||||
|     [Authorize("write:artist")] | ||||
|     [Route("Page")] | ||||
|     public async Task<IActionResult> UpdateArtistPage([FromBody]ArtistPageSettingsModel model) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists | ||||
|             .Include(x=>x.ArtistPageSettings).FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         var updatedArtist = model.ToModel(existingArtist.ArtistPageSettings); | ||||
|         updatedArtist = _dbContext.ArtistPageSettings.Update(updatedArtist).Entity; | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|         var result = updatedArtist.ToModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpPost] | ||||
|     [Authorize("write:artist")] | ||||
| @ -262,148 +149,4 @@ public class ArtistController : Controller | ||||
|         return Ok(); | ||||
|     }    | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     [Route("{sellerServiceId:int}/Portfolio/{portfolioId:int}")] | ||||
|     public async Task<IActionResult> GetPortfolio(int sellerServiceId, int portfolioId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists.FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         if(existingArtist.Suspended) | ||||
|             return BadRequest(); | ||||
| 
 | ||||
|         var portfolio = await _dbContext.ArtistPortfolioPieces | ||||
|             .FirstAsync(x => x.ArtistId == existingArtist.Id && x.Id==portfolioId); | ||||
|         var content = await _storageService.DownloadImageAsync(portfolio.FileReference); | ||||
|         return new FileStreamResult(content, "application/octet-stream"); | ||||
|     } | ||||
| 
 | ||||
|     [HttpGet] | ||||
|     [Route("Portfolio")] | ||||
|     [Authorize("read:artist")] | ||||
|     public async Task<IActionResult> GetPortfolio() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists.FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         if(existingArtist.Suspended) | ||||
|             return BadRequest(); | ||||
|         var portfolio = await _dbContext.ArtistPortfolioPieces.Where(x=>x.ArtistId==existingArtist.Id).ToListAsync(); | ||||
|         var result = portfolio.Select(x=>x.ToModel()).ToList(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpPost] | ||||
|     [Route("Portfolio")] | ||||
|     [Authorize("write:artist")] | ||||
|     public async Task<IActionResult> AddPortfolio() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists.FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             return BadRequest(); | ||||
|         } | ||||
| 
 | ||||
|         if(existingArtist.Suspended) | ||||
|             return BadRequest(); | ||||
|         var url = await _storageService.UploadImageAsync(HttpContext.Request.Body, Guid.NewGuid().ToString()); | ||||
|         var portfolio = new ArtistPortfolioPiece() | ||||
|         { | ||||
|             ArtistId = existingArtist.Id, | ||||
|             FileReference = url | ||||
|         }; | ||||
|         portfolio.ArtistId = existingArtist.Id; | ||||
|         _dbContext.ArtistPortfolioPieces.Add(portfolio); | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|         var result = portfolio.ToModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpDelete] | ||||
|     [Authorize("write:artist")] | ||||
|     [Route("Portfolio/{portfolioId:int}")] | ||||
|     public async Task<IActionResult> DeletePortfolio(int portfolioId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists.FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         if(existingArtist.Suspended) | ||||
|             return BadRequest(); | ||||
|         var portfolio = await _dbContext.ArtistPortfolioPieces.FirstOrDefaultAsync(x=>x.Id==portfolioId); | ||||
|         if(portfolio==null) | ||||
|             return NotFound(); | ||||
|         if(portfolio.ArtistId!=existingArtist.Id) | ||||
|             return BadRequest(); | ||||
|         _dbContext.ArtistPortfolioPieces.Remove(portfolio); | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|         return Ok(); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("write:artist")] | ||||
|     [Route("Onboard")] | ||||
|     public async Task<IActionResult> PaymentAccountStatus() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists.FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return BadRequest(); | ||||
|         } | ||||
|          | ||||
|         if(existingArtist.Suspended) | ||||
|             return BadRequest(); | ||||
|         var result = _paymentService.ArtistAccountIsOnboarded(existingArtist.StripeAccountId); | ||||
|         return Ok(new ArtistOnboardStatusModel(){ Onboarded= result }); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("write:artist")] | ||||
|     [Route("Onboard/Url")] | ||||
|     public async Task<IActionResult> GetPaymentAccount() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists.FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         if(existingArtist.Suspended) | ||||
|             return BadRequest(); | ||||
|         if(existingArtist.StripeAccountId==null) | ||||
|             return BadRequest(); | ||||
| 
 | ||||
|         var result = _paymentService.CreateArtistAccountOnboardingUrl(existingArtist.StripeAccountId); | ||||
|         return Ok(new ArtistOnboardUrlModel() | ||||
|         { | ||||
|             OnboardUrl = result | ||||
|         }); | ||||
|     } | ||||
|      | ||||
| } | ||||
							
								
								
									
										63
									
								
								src/comissions.app.api/Controllers/ArtistPageController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/comissions.app.api/Controllers/ArtistPageController.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| using comissions.app.api.Extensions; | ||||
| using comissions.app.api.Models.Artist; | ||||
| using comissions.app.api.Services.Payment; | ||||
| using comissions.app.api.Services.Storage; | ||||
| using comissions.app.database; | ||||
| using Microsoft.AspNetCore.Authorization; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Novu; | ||||
| 
 | ||||
| namespace comissions.app.api.Controllers; | ||||
| 
 | ||||
| 
 | ||||
| [Route("api/Artist")] | ||||
| public class ArtistPageController: Controller | ||||
| { | ||||
|     private readonly ApplicationDbContext _dbContext; | ||||
|     private readonly IStorageService _storageService; | ||||
|     private readonly IPaymentService _paymentService; | ||||
|     private readonly NovuClient _client; | ||||
| 
 | ||||
|     public ArtistPageController(ApplicationDbContext dbContext, IPaymentService paymentService, IStorageService storageService, NovuClient client) | ||||
|     { | ||||
|         _client = client; | ||||
|         _paymentService = paymentService; | ||||
|         _storageService = storageService; | ||||
|         _dbContext = dbContext; | ||||
|     } | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     [Route("Page")] | ||||
|     public async Task<IActionResult> GetArtistPage() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var Artist = await _dbContext.UserArtists.Include(x=>x.ArtistPageSettings).FirstOrDefaultAsync(artist=>artist.UserId==userId); | ||||
|         if(Artist==null) | ||||
|             return NotFound(); | ||||
|         var result = Artist.ArtistPageSettings.ToModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpPut] | ||||
|     [Authorize("write:artist")] | ||||
|     [Route("Page")] | ||||
|     public async Task<IActionResult> UpdateArtistPage([FromBody]ArtistPageSettingsModel model) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists | ||||
|             .Include(x=>x.ArtistPageSettings).FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         var updatedArtist = model.ToModel(existingArtist.ArtistPageSettings); | ||||
|         updatedArtist = _dbContext.ArtistPageSettings.Update(updatedArtist).Entity; | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|         var result = updatedArtist.ToModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										106
									
								
								src/comissions.app.api/Controllers/ArtistPaymentController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/comissions.app.api/Controllers/ArtistPaymentController.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,106 @@ | ||||
| using comissions.app.api.Extensions; | ||||
| using comissions.app.api.Models.Artist; | ||||
| using comissions.app.api.Services.Payment; | ||||
| using comissions.app.api.Services.Storage; | ||||
| using comissions.app.database; | ||||
| using comissions.app.database.Entities; | ||||
| using comissions.app.database.Models; | ||||
| using Microsoft.AspNetCore.Authorization; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Novu; | ||||
| 
 | ||||
| namespace comissions.app.api.Controllers; | ||||
| 
 | ||||
| public class ArtistPaymentController:Controller | ||||
| { | ||||
|      | ||||
|     private readonly ApplicationDbContext _dbContext; | ||||
|     private readonly IStorageService _storageService; | ||||
|     private readonly IPaymentService _paymentService; | ||||
|     private readonly NovuClient _client; | ||||
| 
 | ||||
|     public ArtistPaymentController(ApplicationDbContext dbContext, IPaymentService paymentService, IStorageService storageService, NovuClient client) | ||||
|     { | ||||
|         _client = client; | ||||
|         _paymentService = paymentService; | ||||
|         _storageService = storageService; | ||||
|         _dbContext = dbContext; | ||||
|     } | ||||
|      | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     [Route("Payout")] | ||||
|     public async Task<IActionResult> Payout() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var Artist = await _dbContext.UserArtists.Include(x=>x.Requests).FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if(Artist==null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
| 
 | ||||
|         var account = _paymentService.GetAccount(Artist.StripeAccountId); | ||||
|         var balance = _paymentService.GetBalance(Artist.StripeAccountId); | ||||
|         var pendingBalance = _paymentService.GetPendingBalance(Artist.StripeAccountId); | ||||
|         var result = new PayoutModel() | ||||
|         { | ||||
|             Enabled = account.PayoutsEnabled, | ||||
|             Balance = balance, | ||||
|             PendingBalance = pendingBalance, | ||||
|             PayoutUrl =  _paymentService.CreateDashboardUrl(Artist.StripeAccountId) | ||||
|         }; | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("write:artist")] | ||||
|     [Route("Onboard")] | ||||
|     public async Task<IActionResult> PaymentAccountStatus() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists.FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return BadRequest(); | ||||
|         } | ||||
|          | ||||
|         if(existingArtist.Suspended) | ||||
|             return BadRequest(); | ||||
|         var result = _paymentService.ArtistAccountIsOnboarded(existingArtist.StripeAccountId); | ||||
|         return Ok(new ArtistOnboardStatusModel(){ Onboarded= result }); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("write:artist")] | ||||
|     [Route("Onboard/Url")] | ||||
|     public async Task<IActionResult> GetPaymentAccount() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists.FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         if(existingArtist.Suspended) | ||||
|             return BadRequest(); | ||||
|         if(existingArtist.StripeAccountId==null) | ||||
|             return BadRequest(); | ||||
| 
 | ||||
|         var result = _paymentService.CreateArtistAccountOnboardingUrl(existingArtist.StripeAccountId); | ||||
|         return Ok(new ArtistOnboardUrlModel() | ||||
|         { | ||||
|             OnboardUrl = result | ||||
|         }); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										128
									
								
								src/comissions.app.api/Controllers/ArtistPortfolioController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								src/comissions.app.api/Controllers/ArtistPortfolioController.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,128 @@ | ||||
| using comissions.app.api.Extensions; | ||||
| using comissions.app.api.Models.PortfolioModel; | ||||
| using comissions.app.api.Services.Payment; | ||||
| using comissions.app.api.Services.Storage; | ||||
| using comissions.app.database; | ||||
| using comissions.app.database.Entities; | ||||
| using Microsoft.AspNetCore.Authorization; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Novu; | ||||
| 
 | ||||
| namespace comissions.app.api.Controllers; | ||||
| 
 | ||||
| 
 | ||||
| [Route("api/Artist")] | ||||
| public class ArtistPortfolioController: Controller | ||||
| { | ||||
|     private readonly ApplicationDbContext _dbContext; | ||||
|     private readonly IStorageService _storageService; | ||||
|     private readonly IPaymentService _paymentService; | ||||
|     private readonly NovuClient _client; | ||||
| 
 | ||||
|     public ArtistPortfolioController(ApplicationDbContext dbContext, IPaymentService paymentService, IStorageService storageService, NovuClient client) | ||||
|     { | ||||
|         _client = client; | ||||
|         _paymentService = paymentService; | ||||
|         _storageService = storageService; | ||||
|         _dbContext = dbContext; | ||||
|     } | ||||
|      | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     [Route("{sellerServiceId:int}/Portfolio/{portfolioId:int}")] | ||||
|     public async Task<IActionResult> GetPortfolio(int sellerServiceId, int portfolioId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists.FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         if(existingArtist.Suspended) | ||||
|             return BadRequest(); | ||||
| 
 | ||||
|         var portfolio = await _dbContext.ArtistPortfolioPieces | ||||
|             .FirstAsync(x => x.ArtistId == existingArtist.Id && x.Id==portfolioId); | ||||
|         var content = await _storageService.DownloadImageAsync(portfolio.FileReference); | ||||
|         return new FileStreamResult(content, "application/octet-stream"); | ||||
|     } | ||||
| 
 | ||||
|     [HttpGet] | ||||
|     [Route("Portfolio")] | ||||
|     [Authorize("read:artist")] | ||||
|     public async Task<IActionResult> GetPortfolio() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists.FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         if(existingArtist.Suspended) | ||||
|             return BadRequest(); | ||||
|         var portfolio = await _dbContext.ArtistPortfolioPieces.Where(x=>x.ArtistId==existingArtist.Id).ToListAsync(); | ||||
|         var result = portfolio.Select(x=>x.ToModel()).ToList(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpPost] | ||||
|     [Route("Portfolio")] | ||||
|     [Authorize("write:artist")] | ||||
|     public async Task<IActionResult> AddPortfolio() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists.FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             return BadRequest(); | ||||
|         } | ||||
| 
 | ||||
|         if(existingArtist.Suspended) | ||||
|             return BadRequest(); | ||||
|         var url = await _storageService.UploadImageAsync(HttpContext.Request.Body, Guid.NewGuid().ToString()); | ||||
|         var portfolio = new ArtistPortfolioPiece() | ||||
|         { | ||||
|             ArtistId = existingArtist.Id, | ||||
|             FileReference = url | ||||
|         }; | ||||
|         portfolio.ArtistId = existingArtist.Id; | ||||
|         _dbContext.ArtistPortfolioPieces.Add(portfolio); | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|         var result = portfolio.ToModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpDelete] | ||||
|     [Authorize("write:artist")] | ||||
|     [Route("Portfolio/{portfolioId:int}")] | ||||
|     public async Task<IActionResult> DeletePortfolio(int portfolioId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var existingArtist = await _dbContext.UserArtists.FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if (existingArtist == null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         if(existingArtist.Suspended) | ||||
|             return BadRequest(); | ||||
|         var portfolio = await _dbContext.ArtistPortfolioPieces.FirstOrDefaultAsync(x=>x.Id==portfolioId); | ||||
|         if(portfolio==null) | ||||
|             return NotFound(); | ||||
|         if(portfolio.ArtistId!=existingArtist.Id) | ||||
|             return BadRequest(); | ||||
|         _dbContext.ArtistPortfolioPieces.Remove(portfolio); | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|         return Ok(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										393
									
								
								src/comissions.app.api/Controllers/ArtistRequestsController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										393
									
								
								src/comissions.app.api/Controllers/ArtistRequestsController.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,393 @@ | ||||
| using comissions.app.api.Extensions; | ||||
| using comissions.app.api.Services.Payment; | ||||
| using comissions.app.api.Services.Storage; | ||||
| using comissions.app.database; | ||||
| using comissions.app.database.Entities; | ||||
| using comissions.app.database.Models.Request; | ||||
| using Microsoft.AspNetCore.Authorization; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Novu; | ||||
| using Novu.DTO.Events; | ||||
| 
 | ||||
| namespace comissions.app.api.Controllers; | ||||
| 
 | ||||
| [Route("api/Requests")] | ||||
| public class ArtistRequestsController: Controller | ||||
| { | ||||
|      | ||||
|     private readonly ApplicationDbContext _dbContext; | ||||
|     private readonly IStorageService _storageService; | ||||
|     private readonly IPaymentService _paymentService; | ||||
|     private readonly NovuClient _client; | ||||
|     private readonly string _webHookSecret; | ||||
| 
 | ||||
|     public ArtistRequestsController(ApplicationDbContext dbContext, NovuClient client, IPaymentService paymentService, IStorageService storageService, IConfiguration configuration) | ||||
|     { | ||||
|         _client = client; | ||||
|         _webHookSecret = configuration.GetValue<string>("Stripe:WebHookSecret"); | ||||
|         _paymentService = paymentService; | ||||
|         _storageService = storageService; | ||||
|         _dbContext = dbContext; | ||||
|     } | ||||
|      | ||||
|      | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Route("Artist/{requestId:int}/References")] | ||||
|     [Authorize("read:request")] | ||||
|     public async Task<IActionResult> GetArtistReferences(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Where(x=>x.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|         var references = await _dbContext.RequestReferences | ||||
|             .Where(x=>x.RequestId==requestId) | ||||
|             .ToListAsync(); | ||||
|         var result = references.Select(x=>x.ToModel()).ToList(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Route("Artist/{requestId:int}/References/Count")] | ||||
|     [Authorize("read:request")] | ||||
|     public async Task<IActionResult> GetArtistReferencesCount(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Where(x=>x.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|         var references = await _dbContext.RequestReferences | ||||
|             .Where(x=>x.RequestId==requestId) | ||||
|             .ToListAsync(); | ||||
|         var result = references.Select(x=>x.ToModel()).Count(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Route("Artist/{requestId:int}/References/{referenceId:int}")] | ||||
|     [Authorize("read:request")] | ||||
|     public async Task<IActionResult> GetArtistReferenceImage(int requestId, int referenceId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Where(x=>x.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|         var reference = await _dbContext.RequestReferences | ||||
|             .Where(x=>x.RequestId==requestId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==referenceId); | ||||
|         if(reference==null) | ||||
|             return NotFound(); | ||||
|         var content = await _storageService.DownloadImageAsync(reference.FileReference); | ||||
|         return new FileStreamResult(content, "application/octet-stream"); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Route("Artist/{requestId:int}/Assets")] | ||||
|     [Authorize("read:request")] | ||||
|     public async Task<IActionResult> GetArtistAssets(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Where(x=>x.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|         var references = await _dbContext.RequestAssets | ||||
|             .Where(x=>x.RequestId==requestId) | ||||
|             .ToListAsync(); | ||||
|         var result = references.Select(x=>x.ToModel()).ToList(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Route("Artist/{requestId:int}/Assets/Count")] | ||||
|     [Authorize("read:request")] | ||||
|     public async Task<IActionResult> GetArtistAssetsCount(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Where(x=>x.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|         var references = await _dbContext.RequestAssets | ||||
|             .Where(x=>x.RequestId==requestId) | ||||
|             .ToListAsync(); | ||||
|         var result = references.Select(x=>x.ToModel()).Count(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Route("Artist/{requestId:int}/Assets/{referenceId:int}")] | ||||
|     [Authorize("read:request")] | ||||
|     public async Task<IActionResult> GetArtistAssetImage(int requestId, int referenceId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Where(x=>x.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|         var reference = await _dbContext.RequestAssets | ||||
|             .Where(x=>x.RequestId==requestId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==referenceId); | ||||
|         if(reference==null) | ||||
|             return NotFound(); | ||||
|         var content = await _storageService.DownloadImageAsync(reference.FileReference); | ||||
|         return new FileStreamResult(content, "application/octet-stream"); | ||||
|     } | ||||
|      | ||||
|      | ||||
|     [HttpPost] | ||||
|     [Route("Artist/{requestId:int}/References")] | ||||
|     [Authorize("write:request")] | ||||
|     public async Task<IActionResult> AddArtistAsset(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Where(x=>x.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
| 
 | ||||
|         if(request.Accepted==false) | ||||
|             return BadRequest("Request has not been accepted."); | ||||
|          | ||||
|         if(request.Paid==false) | ||||
|             return BadRequest("Request has not been paid."); | ||||
|          | ||||
|         if(request.Completed) | ||||
|             return BadRequest("Request has already been completed."); | ||||
|          | ||||
|         var references = await _dbContext.RequestAssets | ||||
|             .Where(x=>x.RequestId==requestId) | ||||
|             .ToListAsync(); | ||||
|          | ||||
|         if(references.Count>=10) | ||||
|             return BadRequest("You can only add 10 assets to a request."); | ||||
|          | ||||
|          | ||||
|          | ||||
|         var url = await _storageService.UploadImageAsync(HttpContext.Request.Body, Guid.NewGuid().ToString()); | ||||
|         var requestReference = new RequestAsset() | ||||
|         { | ||||
|             RequestId = request.Id, | ||||
|             FileReference = url | ||||
|         }; | ||||
|         _dbContext.RequestAssets.Add(requestReference); | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|         var result = requestReference.ToModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|      | ||||
|      | ||||
|      | ||||
|      | ||||
|      | ||||
|     [Authorize("read:request")] | ||||
|     [HttpGet] | ||||
|     [Route("Artist")] | ||||
|     public async Task<IActionResult> GetArtistRequests(string search="",int offset = 0, int pageSize = 10) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var query = _dbContext.Requests.Include(x=>x.Artist) | ||||
|             .Where(x => x.Artist.UserId == userId); | ||||
| 
 | ||||
| 
 | ||||
|         if (!string.IsNullOrWhiteSpace(search)) | ||||
|         { | ||||
|             query = query.Where(x => x.Artist.Name.Contains(search) || x.Message.Contains(search)); | ||||
|         } | ||||
| 
 | ||||
|         var requests = await query | ||||
|             .Include(x => x.Artist) | ||||
|             .Skip(offset) | ||||
|             .Take(pageSize) | ||||
|             .ToListAsync(); | ||||
| 
 | ||||
|         var result = requests.Select(x => x.ToModel()).ToList(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [Authorize("read:request")] | ||||
|     [HttpGet] | ||||
|     [Route("Artist/Count")] | ||||
|     public async Task<IActionResult> GetArtistRequestCount(string search="") | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var query = _dbContext.Requests.Include(x=>x.Artist) | ||||
|             .Where(x => x.Artist.UserId == userId); | ||||
|          | ||||
|         if (!string.IsNullOrWhiteSpace(search)) | ||||
|         { | ||||
|             query = query.Where(x => x.Artist.Name.Contains(search) || x.Message.Contains(search)); | ||||
|         } | ||||
| 
 | ||||
|         var result = query.Count(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [Authorize("read:request")] | ||||
|     [HttpGet] | ||||
|     [Route("Artist/{requestId:int}")] | ||||
|     public async Task<IActionResult> GetArtistRequest(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Include(x=>x.Artist) | ||||
|             .Where(x=>x.Artist.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|         var result = request.ToModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [Authorize("write:request")] | ||||
|     [HttpPut] | ||||
|     [Route("Artist/{requestId:int}/Complete")] | ||||
|     public async Task<IActionResult> CompleteRequest(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Include(x=>x.RequestAssets) | ||||
|             .Include(x=>x.RequestReferences) | ||||
|             .Include(x=>x.Artist) | ||||
|             .Where(x=>x.Artist.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|          | ||||
|         if(request.RequestAssets.Count()==0) | ||||
|             return BadRequest("You must add at least one asset to complete the request."); | ||||
|          | ||||
|         if(request.Accepted==false) | ||||
|             return BadRequest("Request has not been accepted."); | ||||
| 
 | ||||
|         if (request.Declined) | ||||
|             return BadRequest("Request has already been declined."); | ||||
|          | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|          | ||||
|         request.Completed = true; | ||||
|         request.CompletedDate = DateTime.UtcNow; | ||||
|         _dbContext.Entry(request).State = EntityState.Modified; | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|          | ||||
|         var result = request.ToModel(); | ||||
|         var newTriggerModel = new EventCreateData() | ||||
|         { | ||||
|             EventName = "requestcompleted", | ||||
|             To = | ||||
|             { | ||||
|                 SubscriberId = request.UserId | ||||
|             }, | ||||
|             Payload = { } | ||||
|         }; | ||||
|         await _client.Event.Trigger(newTriggerModel); | ||||
|         return Ok(result); | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     [Authorize("write:request")] | ||||
|     [HttpPut] | ||||
|     [Route("Artist/{requestId:int}/Accept")] | ||||
|     public async Task<IActionResult> AcceptRequest(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Include(x=>x.Artist) | ||||
|             .Where(x=>x.Artist.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|          | ||||
|         if(request.Completed) | ||||
|             return BadRequest("Request has already been completed."); | ||||
|          | ||||
|         if(request.Accepted) | ||||
|             return BadRequest("Request has already been accepted."); | ||||
| 
 | ||||
|         if (request.Declined) | ||||
|             return BadRequest("Request has already been declined."); | ||||
|          | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|         var paymentUrl = _paymentService.Charge(request.Id,request.Artist.StripeAccountId,Convert.ToDouble(request.Amount)); | ||||
|         request.Accepted = true; | ||||
|         request.AcceptedDate = DateTime.UtcNow; | ||||
|         request.Paid = false; | ||||
|         request.PaymentUrl = paymentUrl; | ||||
|         _dbContext.Entry(request).State = EntityState.Modified; | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|         var newTriggerModel = new EventCreateData() | ||||
|         { | ||||
|             EventName = "requestacceptedbuyer", | ||||
|             To = | ||||
|             { | ||||
|                 SubscriberId = request.UserId | ||||
|             }, | ||||
|             Payload = { } | ||||
|         }; | ||||
|         await _client.Event.Trigger(newTriggerModel); | ||||
|         var newTriggerArtistModel = new EventCreateData() | ||||
|         { | ||||
|             EventName = "requestacceptedartist", | ||||
|             To = | ||||
|             { | ||||
|                 SubscriberId = request.Artist.UserId | ||||
|             }, | ||||
|             Payload = { } | ||||
|         }; | ||||
|         await _client.Event.Trigger(newTriggerModel); | ||||
|          | ||||
|         var result = request.ToModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     [Authorize("write:request")] | ||||
|     [HttpPut] | ||||
|     [Route("Artist/{requestId:int}/Deny")] | ||||
|     public async Task<IActionResult> DenyRequest(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Include(x=>x.Artist) | ||||
|             .Where(x=>x.Artist.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|          | ||||
|         if(request.Completed) | ||||
|             return BadRequest("Request has already been completed."); | ||||
|          | ||||
|         if(request.Accepted) | ||||
|             return BadRequest("Request has already been accepted."); | ||||
| 
 | ||||
|         if (request.Declined) | ||||
|             return BadRequest("Request has already been declined."); | ||||
|         request.Declined = true; | ||||
|         request.DeclinedDate = DateTime.UtcNow; | ||||
|         _dbContext.Entry(request).State = EntityState.Modified; | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|         var result = request.ToModel(); | ||||
|         var newTriggerModel = new EventCreateData() | ||||
|         { | ||||
|             EventName = "requestdenied", | ||||
|             To = | ||||
|             { | ||||
|                 SubscriberId = request.UserId | ||||
|             }, | ||||
|             Payload = { } | ||||
|         }; | ||||
|         await _client.Event.Trigger(newTriggerModel); | ||||
|         return Ok(result); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										103
									
								
								src/comissions.app.api/Controllers/ArtistReviewsController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/comissions.app.api/Controllers/ArtistReviewsController.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | ||||
| using comissions.app.api.Extensions; | ||||
| using comissions.app.api.Models.Artist; | ||||
| using comissions.app.api.Services.Payment; | ||||
| using comissions.app.api.Services.Storage; | ||||
| using comissions.app.database; | ||||
| using comissions.app.database.Models.Request; | ||||
| using Microsoft.AspNetCore.Authorization; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Novu; | ||||
| 
 | ||||
| namespace comissions.app.api.Controllers; | ||||
| 
 | ||||
| [Route("api/Artist")] | ||||
| public class ArtistReviewsController: Controller | ||||
| { | ||||
|     private readonly ApplicationDbContext _dbContext; | ||||
|     private readonly IStorageService _storageService; | ||||
|     private readonly IPaymentService _paymentService; | ||||
|     private readonly NovuClient _client; | ||||
| 
 | ||||
|     public ArtistReviewsController(ApplicationDbContext dbContext, IPaymentService paymentService, IStorageService storageService, NovuClient client) | ||||
|     { | ||||
|         _client = client; | ||||
|         _paymentService = paymentService; | ||||
|         _storageService = storageService; | ||||
|         _dbContext = dbContext; | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     [Route("Reviews")] | ||||
|     public async Task<IActionResult> GetArtistReviews([FromQuery]int offset = 0, [FromQuery]int limit = 10) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var Artist = await _dbContext.UserArtists.Include(x=>x.Requests).FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if(Artist==null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         var result = Artist.Requests.Where(x=>x.Reviewed).Skip(offset).Take(limit).Select(x=> new RequestReviewModel() | ||||
|         { | ||||
|             RequestId = x.Id, | ||||
|             Message = x.ReviewMessage, | ||||
|             Rating = x.Rating.Value, | ||||
|             ReviewDate = x.ReviewDate | ||||
|         }).ToList(); | ||||
|          | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Authorize("read:artist")] | ||||
|     [Route("Reviews/Count")] | ||||
|     public async Task<IActionResult> ReviewCount() | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var Artist = await _dbContext.UserArtists.Include(x=>x.Requests).FirstOrDefaultAsync(Artist=>Artist.UserId==userId); | ||||
|         if(Artist==null) | ||||
|         { | ||||
|             var ArtistRequest = await _dbContext.ArtistRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false); | ||||
|             if(ArtistRequest!=null) | ||||
|                 return BadRequest(); | ||||
|             return Unauthorized(); | ||||
|         } | ||||
|         var result = Artist.Requests.Where(x=>x.Reviewed).Select(x=> new RequestReviewModel() | ||||
|         { | ||||
|             RequestId = x.Id, | ||||
|             Message = x.ReviewMessage, | ||||
|             Rating = x.Rating.Value, | ||||
|             ReviewDate = x.ReviewDate | ||||
|         }).ToList().Count; | ||||
|          | ||||
|         return Ok(result); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // using comissions.app.api.Services.Payment; | ||||
| // using comissions.app.api.Services.Storage; | ||||
| // using comissions.app.database; | ||||
| // using Novu; | ||||
| // | ||||
| // namespace comissions.app.api.Controllers; | ||||
| //[Route("api/Artist")] | ||||
| // public class ArtistReviews | ||||
| // { | ||||
| //     private readonly ApplicationDbContext _dbContext; | ||||
| //     private readonly IStorageService _storageService; | ||||
| //     private readonly IPaymentService _paymentService; | ||||
| //     private readonly NovuClient _client; | ||||
| // | ||||
| //     public ArtistReviews(ApplicationDbContext dbContext, IPaymentService paymentService, IStorageService storageService, NovuClient client) | ||||
| //     { | ||||
| //         _client = client; | ||||
| //         _paymentService = paymentService; | ||||
| //         _storageService = storageService; | ||||
| //         _dbContext = dbContext; | ||||
| //     } | ||||
| // } | ||||
| @ -16,8 +16,8 @@ using Stripe.Checkout; | ||||
| namespace comissions.app.api.Controllers; | ||||
| 
 | ||||
| [ApiController] | ||||
| [Route("api/[controller]")]
 | ||||
| public class RequestsController : Controller | ||||
| [Route("api/Requests")] | ||||
| public class CustomerRequestsController : Controller | ||||
| { | ||||
|     private readonly ApplicationDbContext _dbContext; | ||||
|     private readonly IStorageService _storageService; | ||||
| @ -25,7 +25,7 @@ public class RequestsController : Controller | ||||
|     private readonly NovuClient _client; | ||||
|     private readonly string _webHookSecret; | ||||
| 
 | ||||
|     public RequestsController(ApplicationDbContext dbContext, NovuClient client, IPaymentService paymentService, IStorageService storageService, IConfiguration configuration) | ||||
|     public CustomerRequestsController(ApplicationDbContext dbContext, NovuClient client, IPaymentService paymentService, IStorageService storageService, IConfiguration configuration) | ||||
|     { | ||||
|         _client = client; | ||||
|         _webHookSecret = configuration.GetValue<string>("Stripe:WebHookSecret"); | ||||
| @ -663,6 +663,8 @@ public class RequestsController : Controller | ||||
|         return Ok(); | ||||
|     } | ||||
|      | ||||
|      | ||||
|     #region Customer | ||||
|     [Authorize("read:request")] | ||||
|     [HttpGet] | ||||
|     [Route("Customer")] | ||||
| @ -766,35 +768,10 @@ public class RequestsController : Controller | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [Authorize("write:request")] | ||||
|     [HttpPost] | ||||
|     [Route("Artist/{requestId:int}/Asset")] | ||||
|     public async Task<IActionResult> AddAsset(int requestId, List<IFormFile> assetImages) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Where(x=>x.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|          | ||||
|         var references = new List<RequestAsset>(); | ||||
|         foreach (var file in assetImages) | ||||
|         { | ||||
|             var reference = new RequestAsset() | ||||
|             { | ||||
|                 RequestId = requestId, | ||||
|                 FileReference = await _storageService.UploadImageAsync(file.OpenReadStream(), Guid.NewGuid().ToString()) | ||||
|             }; | ||||
|             references.Add(reference); | ||||
|         } | ||||
|         _dbContext.RequestAssets.AddRange(references); | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|         return Ok(); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Route("Customer/{requestId:int}/Reference")] | ||||
|     [Route("Customer/{requestId:int}/References")] | ||||
|     [Authorize("read:request")] | ||||
|     public async Task<IActionResult> GetReferences(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
| @ -811,7 +788,79 @@ public class RequestsController : Controller | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Route("Customer/{requestId:int}/Asset")] | ||||
|     [Route("Customer/{requestId:int}/References/Count")] | ||||
|     [Authorize("read:request")] | ||||
|     public async Task<IActionResult> GetReferencesCount(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Where(x=>x.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|         var references = await _dbContext.RequestReferences | ||||
|             .Where(x=>x.RequestId==requestId) | ||||
|             .ToListAsync(); | ||||
|         var result = references.Select(x=>x.ToModel()).Count(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Route("Customer/{requestId:int}/References/{referenceId:int}")] | ||||
|     [Authorize("read:request")] | ||||
|     public async Task<IActionResult> GetReferenceImage(int requestId, int referenceId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Where(x=>x.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|         var reference = await _dbContext.RequestReferences | ||||
|             .Where(x=>x.RequestId==requestId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==referenceId); | ||||
|         if(reference==null) | ||||
|             return NotFound(); | ||||
|         var content = await _storageService.DownloadImageAsync(reference.FileReference); | ||||
|         return new FileStreamResult(content, "application/octet-stream"); | ||||
|     } | ||||
|      | ||||
|     [HttpPost] | ||||
|     [Route("Customer/{requestId:int}/References")] | ||||
|     [Authorize("write:request")] | ||||
|     public async Task<IActionResult> AddReference(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Where(x=>x.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
| 
 | ||||
|         if (request.Accepted || request.Declined) | ||||
|             return BadRequest("Request has already been accepted or declined."); | ||||
|          | ||||
|         var references = await _dbContext.RequestReferences | ||||
|             .Where(x=>x.RequestId==requestId) | ||||
|             .ToListAsync(); | ||||
|         if(references.Count>=10) | ||||
|             return BadRequest("You can only add 10 references to a request."); | ||||
|          | ||||
|         var url = await _storageService.UploadImageAsync(HttpContext.Request.Body, Guid.NewGuid().ToString()); | ||||
|         var requestReference = new RequestReference() | ||||
|         { | ||||
|             RequestId = request.Id, | ||||
|             FileReference = url | ||||
|         }; | ||||
|         _dbContext.RequestReferences.Add(requestReference); | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|         var result = requestReference.ToModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Route("Customer/{requestId:int}/Assets")] | ||||
|     [Authorize("read:request")] | ||||
|     public async Task<IActionResult> GetAssets(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
| @ -828,25 +877,9 @@ public class RequestsController : Controller | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Route("Artist/{requestId:int}/Reference")] | ||||
|     public async Task<IActionResult> GetArtistReferences(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Where(x=>x.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|         var references = await _dbContext.RequestReferences | ||||
|             .Where(x=>x.RequestId==requestId) | ||||
|             .ToListAsync(); | ||||
|         var result = references.Select(x=>x.ToModel()).ToList(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [HttpGet] | ||||
|     [Route("Artist/{requestId:int}/Asset")] | ||||
|     public async Task<IActionResult> GetArtistAssets(int requestId) | ||||
|     [Route("Customer/{requestId:int}/Assets/Count")] | ||||
|     [Authorize("read:request")] | ||||
|     public async Task<IActionResult> GetAssetsCount(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
| @ -857,202 +890,33 @@ public class RequestsController : Controller | ||||
|         var references = await _dbContext.RequestAssets | ||||
|             .Where(x=>x.RequestId==requestId) | ||||
|             .ToListAsync(); | ||||
|         var result = references.Select(x=>x.ToModel()).ToList(); | ||||
|         var result = references.Select(x=>x.ToModel()).Count(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [Authorize("read:request")] | ||||
|     [HttpGet] | ||||
|     [Route("Artist")] | ||||
|     public async Task<IActionResult> GetArtistRequests(string search="",int offset = 0, int pageSize = 10) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var query = _dbContext.Requests.Include(x=>x.Artist) | ||||
|             .Where(x => x.Artist.UserId == userId); | ||||
| 
 | ||||
| 
 | ||||
|         if (!string.IsNullOrWhiteSpace(search)) | ||||
|         { | ||||
|             query = query.Where(x => x.Artist.Name.Contains(search) || x.Message.Contains(search)); | ||||
|         } | ||||
| 
 | ||||
|         var requests = await query | ||||
|             .Include(x => x.Artist) | ||||
|             .Skip(offset) | ||||
|             .Take(pageSize) | ||||
|             .ToListAsync(); | ||||
| 
 | ||||
|         var result = requests.Select(x => x.ToModel()).ToList(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [Route("Customer/{requestId:int}/Assets/{referenceId:int}")] | ||||
|     [Authorize("read:request")] | ||||
|     [HttpGet] | ||||
|     [Route("Artist/Count")] | ||||
|     public async Task<IActionResult> GetArtistRequestCount(string search="") | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var query = _dbContext.Requests.Include(x=>x.Artist) | ||||
|             .Where(x => x.Artist.UserId == userId); | ||||
|          | ||||
|         if (!string.IsNullOrWhiteSpace(search)) | ||||
|         { | ||||
|             query = query.Where(x => x.Artist.Name.Contains(search) || x.Message.Contains(search)); | ||||
|         } | ||||
| 
 | ||||
|         var result = query.Count(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [Authorize("read:request")] | ||||
|     [HttpGet] | ||||
|     [Route("Artist/{requestId:int}")] | ||||
|     public async Task<IActionResult> GetArtistRequest(int requestId) | ||||
|     public async Task<IActionResult> GetAssetImage(int requestId, int referenceId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Include(x=>x.Artist) | ||||
|             .Where(x=>x.Artist.UserId==userId) | ||||
|             .Where(x=>x.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|         var result = request.ToModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
|      | ||||
|     [Authorize("write:request")] | ||||
|     [HttpPut] | ||||
|     [Route("Artist/{requestId:int}/Complete")] | ||||
|     public async Task<IActionResult> CompleteRequest(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Include(x=>x.Artist) | ||||
|             .Where(x=>x.Artist.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|          | ||||
|         if(request.Accepted==false) | ||||
|             return BadRequest("Request has not been accepted."); | ||||
| 
 | ||||
|         if (request.Declined) | ||||
|             return BadRequest("Request has already been declined."); | ||||
|          | ||||
|         if(request==null) | ||||
|         var reference = await _dbContext.RequestAssets | ||||
|             .Where(x=>x.RequestId==requestId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==referenceId); | ||||
|         if(reference==null) | ||||
|             return NotFound(); | ||||
|          | ||||
|         request.Completed = true; | ||||
|         request.CompletedDate = DateTime.UtcNow; | ||||
|         _dbContext.Entry(request).State = EntityState.Modified; | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|          | ||||
|         var result = request.ToModel(); | ||||
|         var newTriggerModel = new EventCreateData() | ||||
|         { | ||||
|             EventName = "requestcompleted", | ||||
|             To = | ||||
|             { | ||||
|                 SubscriberId = request.UserId | ||||
|             }, | ||||
|             Payload = { } | ||||
|         }; | ||||
|         await _client.Event.Trigger(newTriggerModel); | ||||
|         return Ok(result); | ||||
|         var content = await _storageService.DownloadImageAsync(reference.FileReference); | ||||
|         return new FileStreamResult(content, "application/octet-stream"); | ||||
|     } | ||||
|     #endregion | ||||
|      | ||||
|      | ||||
|     [Authorize("write:request")] | ||||
|     [HttpPut] | ||||
|     [Route("Artist/{requestId:int}/Accept")] | ||||
|     public async Task<IActionResult> AcceptRequest(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Include(x=>x.Artist) | ||||
|             .Where(x=>x.Artist.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|      | ||||
|         if(request.Completed) | ||||
|             return BadRequest("Request has already been completed."); | ||||
|          | ||||
|         if(request.Accepted) | ||||
|             return BadRequest("Request has already been accepted."); | ||||
| 
 | ||||
|         if (request.Declined) | ||||
|             return BadRequest("Request has already been declined."); | ||||
|          | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|         var paymentUrl = _paymentService.Charge(request.Id,request.Artist.StripeAccountId,Convert.ToDouble(request.Amount)); | ||||
|         request.Accepted = true; | ||||
|         request.AcceptedDate = DateTime.UtcNow; | ||||
|         request.Paid = false; | ||||
|         request.PaymentUrl = paymentUrl; | ||||
|         _dbContext.Entry(request).State = EntityState.Modified; | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|         var newTriggerModel = new EventCreateData() | ||||
|         { | ||||
|             EventName = "requestacceptedbuyer", | ||||
|             To = | ||||
|             { | ||||
|                 SubscriberId = request.UserId | ||||
|             }, | ||||
|             Payload = { } | ||||
|         }; | ||||
|         await _client.Event.Trigger(newTriggerModel); | ||||
|         var newTriggerArtistModel = new EventCreateData() | ||||
|         { | ||||
|             EventName = "requestacceptedartist", | ||||
|             To = | ||||
|             { | ||||
|                 SubscriberId = request.Artist.UserId | ||||
|             }, | ||||
|             Payload = { } | ||||
|         }; | ||||
|         await _client.Event.Trigger(newTriggerModel); | ||||
|          | ||||
|         var result = request.ToModel(); | ||||
|         return Ok(result); | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     [Authorize("write:request")] | ||||
|     [HttpPut] | ||||
|     [Route("Artist/{requestId:int}/Deny")] | ||||
|     public async Task<IActionResult> DenyRequest(int requestId) | ||||
|     { | ||||
|         var userId = User.GetUserId(); | ||||
|         var request = await _dbContext.Requests | ||||
|             .Include(x=>x.Artist) | ||||
|             .Where(x=>x.Artist.UserId==userId) | ||||
|             .FirstOrDefaultAsync(x=>x.Id==requestId); | ||||
|         if(request==null) | ||||
|             return NotFound(); | ||||
|          | ||||
|         if(request.Completed) | ||||
|             return BadRequest("Request has already been completed."); | ||||
|          | ||||
|         if(request.Accepted) | ||||
|             return BadRequest("Request has already been accepted."); | ||||
| 
 | ||||
|         if (request.Declined) | ||||
|             return BadRequest("Request has already been declined."); | ||||
|         request.Declined = true; | ||||
|         request.DeclinedDate = DateTime.UtcNow; | ||||
|         _dbContext.Entry(request).State = EntityState.Modified; | ||||
|         await _dbContext.SaveChangesAsync(); | ||||
|         var result = request.ToModel(); | ||||
|         var newTriggerModel = new EventCreateData() | ||||
|         { | ||||
|             EventName = "requestdenied", | ||||
|             To = | ||||
|             { | ||||
|                 SubscriberId = request.UserId | ||||
|             }, | ||||
|             Payload = { } | ||||
|         }; | ||||
|         await _client.Event.Trigger(newTriggerModel); | ||||
|         return Ok(result); | ||||
|     } | ||||
| 
 | ||||
|     [Authorize("write:request")] | ||||
|     [HttpPost] | ||||
| @ -13,7 +13,7 @@ using System.Reflection; | ||||
| [assembly: System.Reflection.AssemblyCompanyAttribute("comissions.app.database.migrator")] | ||||
| [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] | ||||
| [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] | ||||
| [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+c5fed0846312ca59c154d519173ea8bfac18d602")] | ||||
| [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+cc2c4ff3c89a7466e4e094e4da0675172ef50ce6")] | ||||
| [assembly: System.Reflection.AssemblyProductAttribute("comissions.app.database.migrator")] | ||||
| [assembly: System.Reflection.AssemblyTitleAttribute("comissions.app.database.migrator")] | ||||
| [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| 423f68777d61ee74d51ce0198a0ec1b7acb5b22c296ca2f357c18da0a527af9c | ||||
| c901efee444e48a2ac81df6448d2a1b2558f7eeb98830f81e82392ae9e03c84d | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Damien Ostler
						Damien Ostler