Skip to content

Commit

Permalink
Added repository for mixes
Browse files Browse the repository at this point in the history
  • Loading branch information
fergalmoran committed Nov 29, 2024
1 parent 802c5c1 commit 2675fcb
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 150 deletions.
141 changes: 65 additions & 76 deletions mixyboos-api/Controllers/MixController.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Threading.Tasks;
Expand All @@ -17,30 +16,26 @@
using MixyBoos.Api.Data;
using MixyBoos.Api.Data.DTO;
using MixyBoos.Api.Data.Models;
using MixyBoos.Api.Data.Repositories;
using MixyBoos.Api.Services.Extensions;

namespace MixyBoos.Api.Controllers;

[Route("[controller]")]
public class MixController : _Controller {
private readonly IConfiguration _config;
private readonly MixyBoosContext _context;
private readonly UserManager<MixyBoosUser> _userManager;

public MixController(MixyBoosContext context,
IConfiguration config,
UserManager<MixyBoosUser> userManager,
ILogger<MixController> logger) : base(logger) {
_context = context;
_config = config;
_userManager = userManager;
}

public class MixController(
MixyBoosContext __context,
MixRepository repository,
IRepository<MixLike> mixLikeRepository,
IConfiguration config,
UserManager<MixyBoosUser> userManager,
ILogger<MixController> logger)
: _Controller(logger) {
[HttpGet]
[Produces(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<List<MixDTO>>> Get() {
var mixes = await _context.Mixes.Include(m => m.User).ToListAsync();
var mixes = await __context.Mixes.Include(m => m.User).ToListAsync();

var script = mixes.BuildAdapter()
.CreateMapExpression<MixDTO>()
.ToScript();
Expand All @@ -53,39 +48,28 @@ public async Task<ActionResult<List<MixDTO>>> Get() {
[Produces(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<List<MixDTO>>> GetByUser([FromQuery] string user) {
var mixes = await _context.Mixes
.Include(m => m.User)
.Where(m => m.User.Slug.Equals(user))
.Where(m => m.IsProcessed)
.ToListAsync();
var result = mixes.Adapt<List<MixDTO>>();
return Ok(result);
var mixes = await repository.GetByUser(user);
return Ok(mixes.Adapt<List<MixDTO>>());
}

[HttpGet("single")]
[Produces(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<MixDTO>> GetByUserAndMix([FromQuery] string user, [FromQuery] string mix) {
var mixes = await _context.Mixes
.Where(m => m.User.Slug.Equals(user))
.Where(m => m.Slug.Equals(mix))
.Include(m => m.User).FirstOrDefaultAsync();
if (mixes is null) {
public async Task<ActionResult<MixDTO>> GetByUserAndSlug([FromQuery] string user, [FromQuery] string mix) {
var result = await repository.GetByUserAndSlug(user, mix);
if (result is null) {
return NoContent();
}

var result = mixes.Adapt<MixDTO>();
return Ok(result);
return Ok(result.Adapt<MixDTO>());
}

[HttpGet("audiourl")]
[Produces(MediaTypeNames.Text.Plain)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<MixDTO>> GetAudioUrl([FromQuery] string id) {
var mix = await _context.Mixes
.Where(r => r.Id.Equals(Guid.Parse(id)))
.SingleOrDefaultAsync();
public async Task<ActionResult<MixDTO>> GetAudioUrl([FromQuery] Guid id) {
var mix = await repository.Get(id);

if (mix is null) {
return NotFound();
Expand All @@ -98,20 +82,20 @@ public async Task<ActionResult<MixDTO>> GetAudioUrl([FromQuery] string id) {
// User = user
// });
// await _context.SaveChangesAsync();
return Ok(Flurl.Url.Combine(_config["LiveServices:ListenUrl"], mix.Id.ToString(), $"{mix.Id}.m3u8"));
return Ok(
Flurl.Url.Combine(
config["LiveServices:ListenUrl"],
mix.Id.ToString(),
$"{mix.Id}.m3u8"));
}

[Authorize]
[HttpGet("feed")]
[Produces(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<List<MixDTO>>> GetFeed() {
var user = await _userManager.FindByNameAsync(User.Identity.Name);
var mixes = await _context.Mixes
.Where(m => m.User.Id.Equals(user.Id))
.Where(m => m.IsProcessed)
.OrderByDescending(m => m.DateCreated)
.ToListAsync();
var user = await userManager.FindByNameAsync(User.Identity.Name);
var mixes = await repository.GetFeedForUser(user.Id);
var result = mixes.Adapt<List<MixDTO>>();
return Ok(result);
}
Expand All @@ -124,9 +108,9 @@ public async Task<ActionResult<List<MixDTO>>> GetFeed() {
public async Task<ActionResult<MixDTO>> Post([FromBody] MixDTO mix) {
try {
var entity = mix.Adapt<Mix>();
var existing = await _context.Mixes
var existing = await __context.Mixes
.AsNoTracking()
.FirstOrDefaultAsync(m => m.Id.Equals(Guid.Parse(mix.Id)));
.FirstOrDefaultAsync(m => m.Id.Equals(mix.Id));
if (existing is not null) {
//we have a proxy mix from waveform generation
//that completed before the form was submitted
Expand All @@ -135,12 +119,10 @@ public async Task<ActionResult<MixDTO>> Post([FromBody] MixDTO mix) {
}

var faker = new Faker();
var user = await _userManager.FindByNameAsync(User.Identity.Name);
var user = await userManager.FindByNameAsync(User.Identity.Name);
entity.User = user;
entity.Image = entity.Image ?? faker.Image.LoremFlickrUrl();

await _context.AddOrUpdate(entity);
await _context.SaveChangesAsync();
entity.Image ??= faker.Image.LoremFlickrUrl();
await repository.AddOrUpdate(entity);

var response = entity.Adapt<MixDTO>();
return CreatedAtAction(nameof(Get), new {id = response.Id}, response);
Expand All @@ -158,7 +140,8 @@ public async Task<ActionResult<MixDTO>> Post([FromBody] MixDTO mix) {
public async Task<ActionResult<MixDTO>> Patch([FromBody] MixDTO mix) {
try {
var entity = mix.Adapt<Mix>();
var existing = await _context.Mixes.FirstOrDefaultAsync(m => m.Id.Equals(Guid.Parse(mix.Id)));
var existing = await repository.Get(mix.Id);

if (existing is null) {
return NotFound();
}
Expand All @@ -168,7 +151,7 @@ public async Task<ActionResult<MixDTO>> Patch([FromBody] MixDTO mix) {
existing.Description = entity.Description;
existing.Image = entity.Image;

await _context.SaveChangesAsync();
await repository.Update(existing);

var response = existing.Adapt<MixDTO>();
return CreatedAtAction(nameof(Get), new {id = response.Id}, response);
Expand All @@ -178,29 +161,43 @@ public async Task<ActionResult<MixDTO>> Patch([FromBody] MixDTO mix) {
}
}

[HttpPost("addlike")]
[HttpPost("togglelike")]
[Authorize]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<MixDTO>> AddLike([FromBody] string id) {
var user = await _userManager.FindByNameAsync(User.Identity.Name);
if (user is null) {
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult<MixDTO>> ToggleLike(Guid id) {
if (id.Equals(Guid.Empty)) {
return BadRequest();
}

var mix = await _context
.Mixes
.FirstOrDefaultAsync(m => m.Id.Equals(id));
var user = await userManager.FindByNameAsync(User.Identity.Name);
if (user is null) {
return Unauthorized();
}

var likes = await mixLikeRepository
.GetAll()
.Where(l => l.MixId.Equals(id) && l.UserId.Equals(user.Id))
.ToListAsync();

if (likes.Count != 0) {
__context.RemoveRange(likes);
await __context.SaveChangesAsync();
return NoContent();
}

var mix = await repository.Get(id);
if (mix is null) {
return NotFound();
}

//
// await _context.MixLikes.AddAsync(new MixLike {
// Mix = mix,
// User = user
// });
await __context.MixLikes.AddAsync(new MixLike {
Mix = mix,
User = user
});
await __context.SaveChangesAsync();
return Ok();
}

Expand All @@ -209,22 +206,14 @@ public async Task<ActionResult<MixDTO>> AddLike([FromBody] string id) {
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> Delete([FromQuery] string id) {
public async Task<IActionResult> Delete([FromQuery] Guid id) {
try {
var user = await _context.Mixes.FirstOrDefaultAsync(m => m.Id.Equals(Guid.Parse(id)));
if (user is null) {
return NotFound();
}

var mix = await _context
.Mixes
.FirstOrDefaultAsync(m => m.Id.Equals(id));
var mix = await repository.Get(id);
if (mix is null) {
return NotFound();
}

_context.Remove(user);
await _context.SaveChangesAsync();
await repository.Delete(mix);
return Ok(StatusCodes.Status204NoContent);
} catch (DbUpdateException ex) {
_logger.LogError("Error creating mix {Message}", ex.Message);
Expand Down
2 changes: 1 addition & 1 deletion mixyboos-api/Data/DTO/MixDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace MixyBoos.Api.Data.DTO;

public class MixDTO {
public string Id { get; set; }
public Guid Id { get; set; }
public string Slug { get; set; }
public string Title { get; set; }
public string Description { get; set; }
Expand Down
4 changes: 2 additions & 2 deletions mixyboos-api/Data/MixyBoosContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ private IEnumerable<PropertyBuilder> __getColumns(ModelBuilder modelBuilder, str
return modelBuilder.Model
.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => p.DeclaringEntityType.ClrType.IsSubclassOf(typeof(BaseEntity)))
.Where(p => p.DeclaringType.ClrType.IsSubclassOf(typeof(BaseEntity)))
.Where(p => p.Name == columnName)
.Select(p => modelBuilder.Entity(p.DeclaringEntityType.ClrType).Property(p.Name));
.Select(p => modelBuilder.Entity(p.DeclaringType.ClrType).Property(p.Name));
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
Expand Down
43 changes: 43 additions & 0 deletions mixyboos-api/Data/Repositories/MixRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MixyBoos.Api.Data.Models;

namespace MixyBoos.Api.Data.Repositories;

public class MixRepository : Repository<Mix> {
public MixRepository(MixyBoosContext context) : base(context) { }

private IQueryable<Mix> _internalGet(Expression<Func<Mix, bool>> predicate) {
return entities
.Where(predicate)
.Where(m => m.IsProcessed)
.Include(m => m.User)
.Include(m => m.Likes)
.Include(m => m.Plays)
.Include(m => m.Shares)
.Include(m => m.Downloads);
}

public async Task<IEnumerable<Mix>> GetByUser(string userSlug) {
return await _internalGet(m => m.User.Slug.Equals(userSlug))
.Where(m => m.IsProcessed)
.ToListAsync();
}

public async Task<Mix> GetByUserAndSlug(string userSlug, string mixSlug) {
return await _internalGet(m => m.User.Slug.Equals(userSlug) && m.Slug.Equals(mixSlug))
.FirstOrDefaultAsync();
}

public async Task<IEnumerable<Mix>> GetFeedForUser(Guid id) {
return await _internalGet(m => m.User.Id.Equals(id))
.Where(m => m.IsProcessed)
.OrderByDescending(m => m.DateCreated)
.ToListAsync();
}
}
66 changes: 66 additions & 0 deletions mixyboos-api/Data/Repositories/Repository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MixyBoos.Api.Data.Models;
using MixyBoos.Api.Services.Extensions;

namespace MixyBoos.Api.Data.Repositories;

public interface IRepository<T> where T : BaseEntity {
IQueryable<T> GetAll();

Task<T> Get(Guid id);

Task Insert(T entity);

Task Update(T entity);

Task Delete(T entity);
}

public class Repository<T> : IRepository<T> where T : BaseEntity {
private readonly MixyBoosContext context;
protected DbSet<T> entities;
string errorMessage = string.Empty;

public Repository(MixyBoosContext context) {
this.context = context;
entities = context.Set<T>();
}

public IQueryable<T> GetAll() {
return entities.AsQueryable<T>();
}

public async Task<T> Get(Guid id) {
return await entities.SingleOrDefaultAsync(s => s.Id.Equals(id));
}

public async Task Insert(T entity) {
ArgumentNullException.ThrowIfNull(entity);

entities.Add(entity);
await context.SaveChangesAsync();
}

public async Task Update(T entity) {
ArgumentNullException.ThrowIfNull(entity);

await context.SaveChangesAsync();
}

public async Task AddOrUpdate(T entity) {
ArgumentNullException.ThrowIfNull(entity);
await context.AddOrUpdate(entity);
await context.SaveChangesAsync();
}

public async Task Delete(T entity) {
ArgumentNullException.ThrowIfNull(entity);

entities.Remove(entity);
await context.SaveChangesAsync();
}
}
Loading

0 comments on commit 2675fcb

Please sign in to comment.