diff --git a/MusicService/AutoMapperProfile.cs b/MusicService/AutoMapperProfile.cs new file mode 100644 index 0000000..330533d --- /dev/null +++ b/MusicService/AutoMapperProfile.cs @@ -0,0 +1,17 @@ +using AutoMapper; +using MusicService.Dtos.Song; +using MusicService.Models; + +namespace MusicService +{ + public class AutoMapperProfile : Profile + { + public AutoMapperProfile() + { + //All "Song" related mappings + CreateMap(); + CreateMap(); + CreateMap(); + } + } +} diff --git a/MusicService/Controllers/SongController.cs b/MusicService/Controllers/SongController.cs new file mode 100644 index 0000000..3df834c --- /dev/null +++ b/MusicService/Controllers/SongController.cs @@ -0,0 +1,76 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using MusicService.Dtos.Song; +using MusicService.Services; +using MusicService.Services.Song; + +namespace MusicService.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class SongController : ControllerBase + { + + private readonly ISongService _songService; + + public SongController(ISongService songService) + { + _songService = songService; + } + + [HttpGet("all")] + public async Task>>> GetAllSongs() + { + var response = await _songService.GetAllSongs(); + + if (response.Data == null) + return StatusCode(StatusCodes.Status404NotFound, response); + + return StatusCode(StatusCodes.Status200OK, response); + } + + [HttpGet("{songId}")] + public async Task>> GetSong(int songId) + { + var response = await _songService.GetSong(songId); + + if (response.Data == null) + return StatusCode(StatusCodes.Status404NotFound, response); + + return StatusCode(StatusCodes.Status200OK, response); + } + + [HttpPost] + public async Task>> AddSong(AddSongDto request) + { + var songResponse = await _songService.AddSong(request); + + if (!songResponse.Success) + return StatusCode(StatusCodes.Status404NotFound, songResponse); + + return StatusCode(StatusCodes.Status201Created, songResponse); + } + + [HttpPut] + public async Task>> UpdateSong(UpdateSongDto request) + { + var response = await _songService.UpdateSong(request); + + if (response.Data == null) + return StatusCode(StatusCodes.Status404NotFound, response); + + return StatusCode(StatusCodes.Status200OK, response); + } + + /*[HttpDelete("{songId}")] + public async Task>> DeleteSong(int songId) + { + /*var response = await _songService; + + if (response.Data == null) + return StatusCode(StatusCodes.Status404NotFound, response); + + return StatusCode(StatusCodes.Status200OK, response); + }*/ + } +} diff --git a/MusicService/Controllers/WeatherForecastController.cs b/MusicService/Controllers/WeatherForecastController.cs deleted file mode 100644 index 3e46438..0000000 --- a/MusicService/Controllers/WeatherForecastController.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace MusicService.Controllers -{ - [ApiController] - [Route("[controller]")] - public class WeatherForecastController : ControllerBase - { - private static readonly string[] Summaries = new[] - { - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" - }; - - private readonly ILogger _logger; - - public WeatherForecastController(ILogger logger) - { - _logger = logger; - } - - [HttpGet(Name = "GetWeatherForecast")] - public IEnumerable Get() - { - return Enumerable.Range(1, 5).Select(index => new WeatherForecast - { - Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - TemperatureC = Random.Shared.Next(-20, 55), - Summary = Summaries[Random.Shared.Next(Summaries.Length)] - }) - .ToArray(); - } - } -} \ No newline at end of file diff --git a/MusicService/Data/DataContext.cs b/MusicService/Data/DataContext.cs index 09182a8..109479e 100644 --- a/MusicService/Data/DataContext.cs +++ b/MusicService/Data/DataContext.cs @@ -1,9 +1,18 @@ using Microsoft.EntityFrameworkCore; +using MusicService.Models; namespace MusicService.Data { public class DataContext : DbContext { + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseNpgsql("Host=localhost;Port=5432;Database=music;Username=postgres;Password=example"); + + public DataContext() + { + + } + public DataContext(DbContextOptions options) : base(options) { @@ -13,5 +22,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { } + + public DbSet song { get; set; } } } diff --git a/MusicService/Dtos/Song/AddSongDto.cs b/MusicService/Dtos/Song/AddSongDto.cs new file mode 100644 index 0000000..cfe01ef --- /dev/null +++ b/MusicService/Dtos/Song/AddSongDto.cs @@ -0,0 +1,9 @@ +namespace MusicService.Dtos.Song +{ + public class AddSongDto + { + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string Adress { get; set; } = string.Empty; + } +} diff --git a/MusicService/Dtos/Song/GetSongDto.cs b/MusicService/Dtos/Song/GetSongDto.cs new file mode 100644 index 0000000..d5128c3 --- /dev/null +++ b/MusicService/Dtos/Song/GetSongDto.cs @@ -0,0 +1,10 @@ +namespace MusicService.Dtos.Song +{ + public class GetSongDto + { + public int Id { get; set; } = 0; + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string Adress { get; set; } = string.Empty; + } +} diff --git a/MusicService/Dtos/Song/UpdateSongDto.cs b/MusicService/Dtos/Song/UpdateSongDto.cs new file mode 100644 index 0000000..5f54ab1 --- /dev/null +++ b/MusicService/Dtos/Song/UpdateSongDto.cs @@ -0,0 +1,10 @@ +namespace MusicService.Dtos.Song +{ + public class UpdateSongDto + { + public int Id { get; set; } = 0; + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string Adress { get; set; } = string.Empty; + } +} diff --git a/MusicService/Migrations/20240418225548_Initialcreate.Designer.cs b/MusicService/Migrations/20240418225548_Initialcreate.Designer.cs new file mode 100644 index 0000000..afb23a0 --- /dev/null +++ b/MusicService/Migrations/20240418225548_Initialcreate.Designer.cs @@ -0,0 +1,54 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MusicService.Data; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MusicService.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20240418225548_Initialcreate")] + partial class Initialcreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MusicService.Models.Song", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Adress") + .IsRequired() + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("song"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/MusicService/Migrations/20240418225548_Initialcreate.cs b/MusicService/Migrations/20240418225548_Initialcreate.cs new file mode 100644 index 0000000..2cc9539 --- /dev/null +++ b/MusicService/Migrations/20240418225548_Initialcreate.cs @@ -0,0 +1,37 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MusicService.Migrations +{ + /// + public partial class Initialcreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "song", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "text", nullable: false), + Description = table.Column(type: "text", nullable: false), + Adress = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_song", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "song"); + } + } +} diff --git a/MusicService/Migrations/DataContextModelSnapshot.cs b/MusicService/Migrations/DataContextModelSnapshot.cs new file mode 100644 index 0000000..ddae0ea --- /dev/null +++ b/MusicService/Migrations/DataContextModelSnapshot.cs @@ -0,0 +1,51 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MusicService.Data; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MusicService.Migrations +{ + [DbContext(typeof(DataContext))] + partial class DataContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MusicService.Models.Song", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Adress") + .IsRequired() + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("song"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/MusicService/Models/Song.cs b/MusicService/Models/Song.cs new file mode 100644 index 0000000..1f53b58 --- /dev/null +++ b/MusicService/Models/Song.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; + +namespace MusicService.Models +{ + public class Song + { + [Key] + public int Id { get; set; } + [Required] + public string Name { get; set; } = string.Empty; + [Required] + public string Description { get; set; } = string.Empty; + [Required] + public string Adress { get; set; } = string.Empty; + } +} diff --git a/MusicService/MusicService.csproj b/MusicService/MusicService.csproj index eaf2744..1a992b0 100644 --- a/MusicService/MusicService.csproj +++ b/MusicService/MusicService.csproj @@ -7,14 +7,13 @@ - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + - - - - - diff --git a/MusicService/Program.cs b/MusicService/Program.cs index 15eacee..a106f44 100644 --- a/MusicService/Program.cs +++ b/MusicService/Program.cs @@ -1,12 +1,19 @@ +using MusicService.Data; +using MusicService.Services.Song; + var builder = WebApplication.CreateBuilder(args); +builder.Services.AddDbContext(); // Add services to the container. - builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); +builder.Services.AddAutoMapper(typeof(Program).Assembly); + +builder.Services.AddScoped(); + var app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/MusicService/Services/Song/ISongService.cs b/MusicService/Services/Song/ISongService.cs new file mode 100644 index 0000000..119236f --- /dev/null +++ b/MusicService/Services/Song/ISongService.cs @@ -0,0 +1,13 @@ +using MusicService.Dtos.Song; + +namespace MusicService.Services.Song +{ + public interface ISongService + { + public Task>> GetAllSongs(); + public Task> GetSong(int songId); + public Task> AddSong(AddSongDto request); + public Task> UpdateSong(UpdateSongDto request); + public Task> DeleteSong(int songId); + } +} diff --git a/MusicService/Services/Song/SongService.cs b/MusicService/Services/Song/SongService.cs new file mode 100644 index 0000000..49651d5 --- /dev/null +++ b/MusicService/Services/Song/SongService.cs @@ -0,0 +1,122 @@ +using AutoMapper; +using Microsoft.EntityFrameworkCore; +using MusicService.Data; +using MusicService.Dtos.Song; +using MusicService.Models; + +namespace MusicService.Services.Song +{ + public class SongService : ISongService + { + private readonly IMapper _mapper; + private readonly DataContext _context; + + public SongService(IMapper mapper, DataContext context) + { + _mapper = mapper; + _context = context; + } + + public async Task>> GetAllSongs() + { + ServiceResponse> response = new ServiceResponse>(); + try + { + List songs = await _context.song.ToListAsync(); + + if (songs.Count > 0) + { + response.Data = songs.Select(s => _mapper.Map(s)).ToList(); + } + else + { + response.Success = false; + response.Message = "Nothing was found!"; + } + } + catch (Exception ex) + { + response.Success = false; + response.Message = ex.Message; + } + return response; + } + + public async Task> GetSong(int songId) + { + ServiceResponse? response = new ServiceResponse(); + try + { + Models.Song? song = await _context.song + .Where(b => b.Id == songId) + .FirstAsync(); + + if (song != null) + { + response.Data = _mapper.Map(song); + } + else + { + response.Success = false; + response.Message = "Nothing was found!"; + } + } + catch (Exception ex) + { + response.Success = false; + response.Message = ex.Message; + } + return response; + } + + public async Task> AddSong(AddSongDto request) + { + ServiceResponse response = new ServiceResponse(); + + try + { + Models.Song song = _mapper.Map(request); + _context.song.Add(song); + await _context.SaveChangesAsync(); + + response.Data = _mapper.Map(song); + } + catch (Exception ex) + { + response.Success = false; + response.Message = ex.Message; + } + + return response; + } + + public async Task> UpdateSong(UpdateSongDto request) + { + ServiceResponse response = new ServiceResponse(); + + try + { + Models.Song? song = _context.Find(request.Id); + song.Name = request.Name; + song.Description = request.Description; + song.Adress = request.Adress; + + await _context.SaveChangesAsync(); + + response.Data = _mapper.Map(song); + } + catch (Exception ex) + { + response.Success = false; + response.Message = ex.Message; + } + + return response; + } + + public Task> DeleteSong(int songId) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..940f57c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +# Use postgres/example user/password credentials +version: '3.9' + +services: + db: + image: postgres + restart: always + # set shared memory limit when using docker-compose + shm_size: 128mb + # or set shared memory limit when deploy via swarm stack + #volumes: + # - type: tmpfs + # target: /dev/shm + # tmpfs: + # size: 134217728 # 128*2^20 bytes = 128Mb + environment: + POSTGRES_PASSWORD: example + ports: + - 5432:5432 + + adminer: + image: adminer + restart: always + ports: + - 8080:8080