Ignore:
Timestamp:
09/01/26 06:11:34 (4 weeks ago)
Author:
mmilevski <markomilevski3@…>
Branches:
main
Children:
d2eccb3
Parents:
08aefc6
Message:

Added major improvements.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • KernelRecordsMVC.Web/Controllers/AdminController.cs

    r08aefc6 rfa0fbaf  
    1 using Microsoft.AspNetCore.Mvc;
     1using KernelRecordsMVC.Application.ViewModels;
     2using KernelRecordsMVC.Domain.Enums;
     3using KernelRecordsMVC.Infrastructure.Data;
     4using KernelRecordsMVC.Models;
     5using Microsoft.AspNetCore.Mvc;
    26using Microsoft.EntityFrameworkCore;
    3 using KernelRecordsMVC.Data;
    4 using KernelRecordsMVC.Models;
    5 using KernelRecordsMVC.Domain.Enums;
    6 using KernelRecordsMVC.Application.ViewModels;
    7 using Microsoft.AspNetCore.Http;
    8 
    9 namespace KernelRecordsMVC.Controllers;
     7
     8namespace KernelRecordsMVC.Web.Controllers;
    109
    1110public class AdminController : Controller
    … …  
    1918
    2019
    21     // ==========================================
     20    // =========================================================
    2221    // ADMIN DASHBOARD
    23     // ==========================================
     22    // =========================================================
    2423
    2524    [HttpGet]
    … …  
    2928            return Forbid();
    3029
     30
     31        ViewBag.ProductCount =
     32            _context.Products.Count();
     33
     34        ViewBag.ReleaseCount =
     35            _context.Releases.Count();
     36
     37        ViewBag.OutOfStockCount =
     38            _context.Products.Count(x =>
     39                x.Stock <= 0);
     40
     41        ViewBag.LowStockCount =
     42            _context.Products.Count(x =>
     43                x.Stock > 0 &&
     44                x.Stock <= 5);
     45
     46
    3147        return View();
    3248    }
    3349
    3450
    35     // ==========================================
    36     // UC008
    37     // NEW PRODUCT - GET
    38     // ==========================================
     51    // =========================================================
     52    // PRODUCTS
     53    // =========================================================
     54
     55    [HttpGet]
     56    public IActionResult Products()
     57    {
     58        if (!IsProductManager())
     59            return Forbid();
     60
     61
     62        var products = _context.Products
     63            .Include(p => p.Release)
     64            .OrderBy(p => p.Release.Title)
     65            .ThenBy(p => p.Format)
     66            .ToList();
     67
     68
     69        return View(products);
     70    }
     71
     72
     73    // =========================================================
     74    // CREATE PRODUCT - GET
     75    // =========================================================
    3976
    4077    [HttpGet]
    … …  
    4481            return Forbid();
    4582
    46         ViewBag.Releases = _context.Releases
    47             .OrderBy(x => x.Title)
    48             .ToList();
    49 
    50         return View(new CreateProductViewModel());
    51     }
    52 
    53 
    54     // ==========================================
    55     // UC008
    56     // NEW PRODUCT - POST
    57     // ==========================================
     83
     84        LoadReleases();
     85
     86
     87        return View(
     88            new CreateProductViewModel());
     89    }
     90
     91
     92    // =========================================================
     93    // CREATE PRODUCT - POST
     94    // =========================================================
    5895
    5996    [HttpPost]
    … …  
    65102            return Forbid();
    66103
     104
    67105        if (!ModelState.IsValid)
    68106        {
    69107            LoadReleases();
     108
    70109            return View(model);
    71110        }
    72111
    73112
    74         // Make sure the release actually exists.
    75113        var release = _context.Releases
    76114            .FirstOrDefault(x =>
    77115                x.ReleaseId == model.ReleaseId);
    78116
     117
    79118        if (release == null)
    80119        {
    81120            ModelState.AddModelError(
    82                 "ReleaseId",
     121                nameof(model.ReleaseId),
    83122                "The selected release does not exist.");
    84123
     124
    85125            LoadReleases();
     126
     127
    86128            return View(model);
    87129        }
    88130
    89131
    90         // Don't allow duplicate format for
    91         // the same release.
    92         var alreadyExists = _context.Products.Any(p =>
    93             p.ReleaseId == model.ReleaseId &&
    94             p.Format == model.Format);
     132        var alreadyExists =
     133            _context.Products.Any(p =>
     134                p.ReleaseId == model.ReleaseId &&
     135                p.Format == model.Format);
     136
    95137
    96138        if (alreadyExists)
    97139        {
    98140            ModelState.AddModelError(
    99                 "Format",
     141                nameof(model.Format),
    100142                "This release already has a product in this format.");
    101143
     144
    102145            LoadReleases();
     146
     147
    103148            return View(model);
    104149        }
    105150
    106151
    107         var product = new Product
    108         {
    109             ProductId = GetNextProductId(),
    110 
    111             ReleaseId = model.ReleaseId,
    112 
    113             Format = model.Format,
    114 
    115             Price = model.Price,
    116 
    117             ProductDescription =
    118                 model.ProductDescription,
    119 
    120             Stock = model.Stock
    121         };
    122 
    123 
    124         _context.Products.Add(product);
    125 
    126         _context.SaveChanges();
    127 
    128 
    129         // Record the modification.
    130         CreateModification(
    131             ModificationType.CREATE,
    132             product.ProductId);
    133 
    134 
    135         TempData["Success"] =
    136             "Product created successfully.";
    137 
    138 
    139         return RedirectToAction(
    140             nameof(Index));
    141     }
    142 
    143 
    144     // ==========================================
    145     // HELPERS
    146     // ==========================================
     152        using var transaction =
     153            _context.Database.BeginTransaction();
     154
     155
     156        try
     157        {
     158            var product = new Product
     159            {
     160                ProductId =
     161                    GetNextProductId(),
     162
     163                ReleaseId =
     164                    model.ReleaseId,
     165
     166                Format =
     167                    model.Format,
     168
     169                Price =
     170                    model.Price,
     171
     172                ProductDescription =
     173                    model.ProductDescription,
     174
     175                Stock =
     176                    model.Stock
     177            };
     178
     179
     180            _context.Products.Add(product);
     181
     182            _context.SaveChanges();
     183
     184
     185            CreateModification(
     186                ModificationType.CREATE,
     187                product.ProductId);
     188
     189
     190            transaction.Commit();
     191
     192
     193            TempData["Success"] =
     194                $"{release.Title} ({product.Format}) was created successfully.";
     195
     196
     197            return RedirectToAction(
     198                nameof(Products));
     199        }
     200        catch
     201        {
     202            transaction.Rollback();
     203
     204            throw;
     205        }
     206    }
     207
     208
     209    // =========================================================
     210    // EDIT PRODUCT - GET
     211    // =========================================================
     212
     213    [HttpGet]
     214    public IActionResult EditProduct(long id)
     215    {
     216        if (!IsProductManager())
     217            return Forbid();
     218
     219
     220        var product = _context.Products
     221            .Include(p => p.Release)
     222            .FirstOrDefault(p =>
     223                p.ProductId == id);
     224
     225
     226        if (product == null)
     227            return NotFound();
     228
     229
     230        var model =
     231            new EditProductViewModel
     232            {
     233                ProductId =
     234                    product.ProductId,
     235
     236                ReleaseId =
     237                    product.ReleaseId,
     238
     239                ReleaseTitle =
     240                    product.Release.Title,
     241
     242                Format =
     243                    product.Format,
     244
     245                Price =
     246                    product.Price,
     247
     248                ProductDescription =
     249                    product.ProductDescription,
     250
     251                Stock =
     252                    product.Stock,
     253
     254                ModificationType =
     255                    ModificationType.UPDATE
     256            };
     257
     258
     259        return View(model);
     260    }
     261
     262
     263    // =========================================================
     264    // EDIT PRODUCT - POST
     265    // =========================================================
     266
     267    [HttpPost]
     268    [ValidateAntiForgeryToken]
     269    public IActionResult EditProduct(
     270        EditProductViewModel model)
     271    {
     272        if (!IsProductManager())
     273            return Forbid();
     274
     275
     276        var product = _context.Products
     277            .Include(p => p.Release)
     278            .FirstOrDefault(p =>
     279                p.ProductId == model.ProductId);
     280
     281
     282        if (product == null)
     283            return NotFound();
     284
     285
     286        // These values come from the database.
     287        model.ReleaseId =
     288            product.ReleaseId;
     289
     290        model.ReleaseTitle =
     291            product.Release.Title;
     292
     293        model.Format =
     294            product.Format;
     295
     296
     297        // Display-only fields should not block
     298        // validation of the submitted form.
     299        ModelState.Remove(
     300            nameof(model.ReleaseId));
     301
     302        ModelState.Remove(
     303            nameof(model.ReleaseTitle));
     304
     305        ModelState.Remove(
     306            nameof(model.Format));
     307
     308
     309        // =====================================================
     310        // DISCOUNT VALIDATION
     311        // =====================================================
     312
     313        if (model.ModificationType ==
     314            ModificationType.DISCOUNT)
     315        {
     316            if (!model.Discount.HasValue)
     317            {
     318                ModelState.AddModelError(
     319                    nameof(model.Discount),
     320                    "Please enter a discount percentage.");
     321            }
     322            else if (
     323                model.Discount.Value <= 0 ||
     324                model.Discount.Value >= 100)
     325            {
     326                ModelState.AddModelError(
     327                    nameof(model.Discount),
     328                    "Discount must be greater than 0 and less than 100.");
     329            }
     330        }
     331
     332
     333        if (!ModelState.IsValid)
     334            return View(model);
     335
     336
     337        using var transaction =
     338            _context.Database.BeginTransaction();
     339
     340
     341        try
     342        {
     343            // =================================================
     344            // APPLY DISCOUNT
     345            // =================================================
     346
     347            if (model.ModificationType ==
     348                ModificationType.DISCOUNT)
     349            {
     350                var discountPercentage =
     351                    model.Discount!.Value;
     352
     353
     354                var oldPrice =
     355                    product.Price;
     356
     357
     358                var discountAmount =
     359                    oldPrice *
     360                    (discountPercentage / 100m);
     361
     362
     363                var newPrice =
     364                    oldPrice - discountAmount;
     365
     366
     367                newPrice =
     368                    Math.Round(
     369                        newPrice,
     370                        2,
     371                        MidpointRounding.AwayFromZero);
     372
     373
     374                // Product.Price becomes the
     375                // actual current sale price.
     376                product.Price =
     377                    newPrice;
     378
     379
     380                _context.Products.Update(
     381                    product);
     382
     383                _context.SaveChanges();
     384
     385
     386                CreateModification(
     387                    ModificationType.DISCOUNT,
     388                    product.ProductId,
     389                    discountPercentage);
     390
     391
     392                transaction.Commit();
     393
     394
     395                TempData["Success"] =
     396                    $"{discountPercentage:0.##}% discount applied. " +
     397                    $"Price changed from {oldPrice:C} to {newPrice:C}.";
     398
     399
     400                return RedirectToAction(
     401                    nameof(Products));
     402            }
     403
     404
     405            // =================================================
     406            // NORMAL UPDATE
     407            // =================================================
     408
     409            product.Price =
     410                model.Price;
     411
     412            product.ProductDescription =
     413                model.ProductDescription;
     414
     415            product.Stock =
     416                model.Stock;
     417
     418
     419            _context.Products.Update(
     420                product);
     421
     422            _context.SaveChanges();
     423
     424
     425            CreateModification(
     426                ModificationType.UPDATE,
     427                product.ProductId);
     428
     429
     430            transaction.Commit();
     431
     432
     433            TempData["Success"] =
     434                $"{product.Release.Title} was updated successfully.";
     435
     436
     437            return RedirectToAction(
     438                nameof(Products));
     439        }
     440        catch
     441        {
     442            transaction.Rollback();
     443
     444            throw;
     445        }
     446    }
     447
     448
     449    // =========================================================
     450    // CREATE RELEASE - GET
     451    // =========================================================
     452
     453    [HttpGet]
     454    public IActionResult CreateRelease()
     455    {
     456        if (!IsAdmin())
     457            return Forbid();
     458
     459
     460        LoadArtists();
     461
     462
     463        var model =
     464            new CreateReleaseViewModel
     465            {
     466                ReleaseDate =
     467                    DateTime.Today,
     468
     469                ReleaseType =
     470                    "ALBUM",
     471
     472                // Start an album with one empty track.
     473                Tracks =
     474                    new List<CreateTrackViewModel>
     475                    {
     476                        new CreateTrackViewModel()
     477                    }
     478            };
     479
     480
     481        return View(model);
     482    }
     483
     484
     485    // =========================================================
     486    // CREATE RELEASE - POST
     487    // =========================================================
     488
     489    [HttpPost]
     490    [ValidateAntiForgeryToken]
     491    public IActionResult CreateRelease(
     492        CreateReleaseViewModel model)
     493    {
     494        if (!IsAdmin())
     495            return Forbid();
     496
     497
     498        // =====================================================
     499        // RELEASE TYPE VALIDATION
     500        // =====================================================
     501
     502        if (model.ReleaseType != "ALBUM" &&
     503            model.ReleaseType != "SINGLE")
     504        {
     505            ModelState.AddModelError(
     506                nameof(model.ReleaseType),
     507                "Please select Album or Single.");
     508        }
     509
     510
     511        // =====================================================
     512        // MAIN ARTIST VALIDATION
     513        // =====================================================
     514
     515        var mainArtistExists =
     516            _context.Artists.Any(a =>
     517                a.ArtistId ==
     518                model.MainArtistId);
     519
     520
     521        if (!mainArtistExists)
     522        {
     523            ModelState.AddModelError(
     524                nameof(model.MainArtistId),
     525                "Please select a valid main artist.");
     526        }
     527
     528
     529        // =====================================================
     530        // FEATURED ARTISTS
     531        // =====================================================
     532
     533        model.FeaturedArtistIds ??=
     534            new List<long>();
     535
     536
     537        model.FeaturedArtistIds =
     538            model.FeaturedArtistIds
     539                .Distinct()
     540                .ToList();
     541
     542
     543        // Do not allow the main artist
     544        // to also be a featured artist.
     545        model.FeaturedArtistIds.Remove(
     546            model.MainArtistId);
     547
     548
     549        // Validate that featured artists exist.
     550        if (model.FeaturedArtistIds.Count > 0)
     551        {
     552            var validFeaturedArtistCount =
     553                _context.Artists.Count(a =>
     554                    model.FeaturedArtistIds
     555                        .Contains(a.ArtistId));
     556
     557
     558            if (validFeaturedArtistCount !=
     559                model.FeaturedArtistIds.Count)
     560            {
     561                ModelState.AddModelError(
     562                    nameof(model.FeaturedArtistIds),
     563                    "One or more featured artists are invalid.");
     564            }
     565        }
     566
     567
     568        // =====================================================
     569        // SINGLE VALIDATION
     570        // =====================================================
     571
     572        if (model.ReleaseType == "SINGLE")
     573        {
     574            if (string.IsNullOrWhiteSpace(
     575                model.SingleDuration))
     576            {
     577                ModelState.AddModelError(
     578                    nameof(model.SingleDuration),
     579                    "Duration is required for a single.");
     580            }
     581        }
     582
     583
     584        // =====================================================
     585        // ALBUM VALIDATION
     586        // =====================================================
     587
     588        if (model.ReleaseType == "ALBUM")
     589        {
     590            model.Tracks ??=
     591                new List<CreateTrackViewModel>();
     592
     593
     594            // Remove completely empty rows.
     595            model.Tracks =
     596                model.Tracks
     597                    .Where(t =>
     598                        !string.IsNullOrWhiteSpace(
     599                            t.SongName) ||
     600                        !string.IsNullOrWhiteSpace(
     601                            t.SongDuration))
     602                    .ToList();
     603
     604
     605            if (model.Tracks.Count == 0)
     606            {
     607                ModelState.AddModelError(
     608                    nameof(model.Tracks),
     609                    "An album must contain at least one track.");
     610            }
     611
     612
     613            for (var i = 0;
     614                 i < model.Tracks.Count;
     615                 i++)
     616            {
     617                var track =
     618                    model.Tracks[i];
     619
     620
     621                if (string.IsNullOrWhiteSpace(
     622                    track.SongName))
     623                {
     624                    ModelState.AddModelError(
     625                        $"Tracks[{i}].SongName",
     626                        "Track name is required.");
     627                }
     628
     629
     630                if (string.IsNullOrWhiteSpace(
     631                    track.SongDuration))
     632                {
     633                    ModelState.AddModelError(
     634                        $"Tracks[{i}].SongDuration",
     635                        "Track duration is required.");
     636                }
     637
     638
     639                track.ArtistIds ??=
     640                    new List<long>();
     641
     642
     643                track.ArtistIds =
     644                    track.ArtistIds
     645                        .Distinct()
     646                        .ToList();
     647
     648
     649                // Validate selected track artists.
     650                if (track.ArtistIds.Count > 0)
     651                {
     652                    var validTrackArtistCount =
     653                        _context.Artists.Count(a =>
     654                            track.ArtistIds.Contains(
     655                                a.ArtistId));
     656
     657
     658                    if (validTrackArtistCount !=
     659                        track.ArtistIds.Count)
     660                    {
     661                        ModelState.AddModelError(
     662                            $"Tracks[{i}].ArtistIds",
     663                            "One or more selected track artists are invalid.");
     664                    }
     665                }
     666            }
     667        }
     668
     669
     670        if (!ModelState.IsValid)
     671        {
     672            LoadArtists();
     673
     674            return View(model);
     675        }
     676
     677
     678        using var transaction =
     679            _context.Database.BeginTransaction();
     680
     681
     682        try
     683        {
     684            // =================================================
     685            // CREATE RELEASE
     686            // =================================================
     687
     688            var release =
     689                new Release
     690                {
     691                    ReleaseId =
     692                        GetNextReleaseId(),
     693
     694                    Title =
     695                        model.Title.Trim(),
     696
     697                    RecordLabel =
     698                        string.IsNullOrWhiteSpace(
     699                            model.RecordLabel)
     700                            ? null
     701                            : model.RecordLabel.Trim(),
     702
     703                    Genre =
     704                        model.Genre.Trim(),
     705
     706                    ReleaseDate =
     707                        model.ReleaseDate,
     708
     709                    CoverPhoto =
     710                        model.CoverPhoto.Trim()
     711                };
     712
     713
     714            _context.Releases.Add(
     715                release);
     716
     717            _context.SaveChanges();
     718
     719
     720            // =================================================
     721            // MAIN RELEASE ARTIST
     722            // =================================================
     723
     724            var mainReleaseArtist =
     725                new ReleaseArtist
     726                {
     727                    ReleaseId =
     728                        release.ReleaseId,
     729
     730                    ArtistId =
     731                        model.MainArtistId,
     732
     733                    ReleaseOrdinal = 1,
     734
     735                    Type =
     736                        ArtistReleaseType.MAIN
     737                };
     738
     739
     740            _context.ReleaseArtists.Add(
     741                mainReleaseArtist);
     742
     743
     744            // =================================================
     745            // FEATURED RELEASE ARTISTS
     746            // =================================================
     747
     748            long releaseOrdinal = 2;
     749
     750
     751            foreach (var artistId
     752                     in model.FeaturedArtistIds)
     753            {
     754                var featuredArtist =
     755                    new ReleaseArtist
     756                    {
     757                        ReleaseId =
     758                            release.ReleaseId,
     759
     760                        ArtistId =
     761                            artistId,
     762
     763                        ReleaseOrdinal =
     764                            releaseOrdinal++,
     765
     766                        Type =
     767                            ArtistReleaseType.FEATURE
     768                    };
     769
     770
     771                _context.ReleaseArtists.Add(
     772                    featuredArtist);
     773            }
     774
     775
     776            _context.SaveChanges();
     777
     778
     779            // =================================================
     780            // ALBUM
     781            // =================================================
     782
     783            if (model.ReleaseType == "ALBUM")
     784            {
     785                var album =
     786                    new Album
     787                    {
     788                        ReleaseId =
     789                            release.ReleaseId
     790                    };
     791
     792
     793                _context.Albums.Add(
     794                    album);
     795
     796                _context.SaveChanges();
     797
     798
     799                // =============================================
     800                // TRACKS
     801                // =============================================
     802
     803                foreach (var trackModel
     804                         in model.Tracks)
     805                {
     806                    var song =
     807                        new Song
     808                        {
     809                            SongId =
     810                                GetNextSongId(),
     811
     812                            SongName =
     813                                trackModel
     814                                    .SongName
     815                                    .Trim(),
     816
     817                            SongDuration =
     818                                trackModel
     819                                    .SongDuration
     820                                    .Trim()
     821                        };
     822
     823
     824                    _context.Songs.Add(
     825                        song);
     826
     827                    _context.SaveChanges();
     828
     829
     830                    // =========================================
     831                    // LINK SONG TO ALBUM
     832                    // =========================================
     833
     834                    var albumSong =
     835                        new AlbumSong
     836                        {
     837                            AlbumId =
     838                                release.ReleaseId,
     839
     840                            SongId =
     841                                song.SongId
     842                        };
     843
     844
     845                    _context.AlbumSongs.Add(
     846                        albumSong);
     847
     848
     849                    // =========================================
     850                    // SONG ARTISTS
     851                    // =========================================
     852
     853                    var trackArtistIds =
     854                        trackModel.ArtistIds
     855                            .Distinct()
     856                            .ToList();
     857
     858
     859                    // If no track artists were selected,
     860                    // automatically use the release's
     861                    // main artist.
     862                    if (trackArtistIds.Count == 0)
     863                    {
     864                        trackArtistIds.Add(
     865                            model.MainArtistId);
     866                    }
     867
     868
     869                    long songOrdinal = 1;
     870
     871
     872                    foreach (var artistId
     873                             in trackArtistIds)
     874                    {
     875                        var songArtist =
     876                            new SongArtist
     877                            {
     878                                SongId =
     879                                    song.SongId,
     880
     881                                ArtistId =
     882                                    artistId,
     883
     884                                SongOrdinal =
     885                                    songOrdinal++
     886                            };
     887
     888
     889                        _context.SongArtists.Add(
     890                            songArtist);
     891                    }
     892
     893
     894                    _context.SaveChanges();
     895                }
     896            }
     897
     898
     899            // =================================================
     900            // SINGLE
     901            // =================================================
     902
     903            else
     904            {
     905                var single =
     906                    new SingleRelease
     907                    {
     908                        ReleaseId =
     909                            release.ReleaseId,
     910
     911                        Duration =
     912                            model.SingleDuration!
     913                                .Trim()
     914                    };
     915
     916
     917                _context.SingleReleases.Add(
     918                    single);
     919
     920                _context.SaveChanges();
     921            }
     922
     923
     924            transaction.Commit();
     925
     926
     927            TempData["Success"] =
     928                $"{release.Title} was created successfully.";
     929
     930
     931            return RedirectToAction(
     932                nameof(Index));
     933        }
     934        catch
     935        {
     936            transaction.Rollback();
     937
     938            throw;
     939        }
     940    }
     941
     942
     943    // =========================================================
     944    // AUTHORIZATION HELPERS
     945    // =========================================================
    147946
    148947    private bool IsAdmin()
    149948    {
    150949        return HttpContext.Session
    151             .GetString("Role") == "Admin";
     950            .GetString("Role") ==
     951            "Admin";
    152952    }
    153953
    … …  
    155955    private bool IsProductManager()
    156956    {
    157         var role = HttpContext.Session
    158             .GetString("Role");
    159 
    160         var adminType = HttpContext.Session
    161             .GetString("AdminType");
     957        var role =
     958            HttpContext.Session
     959                .GetString("Role");
     960
     961        var adminType =
     962            HttpContext.Session
     963                .GetString("AdminType");
     964
    162965
    163966        return role == "Admin" &&
    164                (adminType == "PRODUCT_MANAGER" ||
    165                 adminType == "SUPER_ADMIN");
    166     }
    167 
     967               (
     968                   adminType == "PRODUCT_MANAGER" ||
     969                   adminType == "SUPER_ADMIN"
     970               );
     971    }
     972
     973
     974    // =========================================================
     975    // CURRENT ADMIN ID
     976    // =========================================================
    168977
    169978    private long? GetCurrentUserId()
    170979    {
    171         var value = HttpContext.Session
    172             .GetString("UserId");
    173 
    174         if (long.TryParse(value, out var userId))
    175             return userId;
    176 
    177         return null;
    178     }
    179 
     980        var userId =
     981            HttpContext.Session
     982                .GetInt32("UserId");
     983
     984
     985        if (!userId.HasValue)
     986            return null;
     987
     988
     989        return userId.Value;
     990    }
     991
     992
     993    // =========================================================
     994    // LOAD RELEASES
     995    // =========================================================
     996
     997    private void LoadReleases()
     998    {
     999        ViewBag.Releases =
     1000            _context.Releases
     1001                .OrderBy(x =>
     1002                    x.Title)
     1003                .ToList();
     1004    }
     1005
     1006
     1007    // =========================================================
     1008    // LOAD ARTISTS
     1009    // =========================================================
     1010
     1011    private void LoadArtists()
     1012    {
     1013        ViewBag.Artists =
     1014            _context.Artists
     1015                .OrderBy(a =>
     1016                    a.ArtistName)
     1017                .ToList();
     1018    }
     1019
     1020
     1021    // =========================================================
     1022    // NEXT PRODUCT ID
     1023    // =========================================================
    1801024
    1811025    private long GetNextProductId()
    1821026    {
    183         var maxId = _context.Products
    184             .Select(x => (long?)x.ProductId)
    185             .Max();
     1027        var maxId =
     1028            _context.Products
     1029                .Select(x =>
     1030                    (long?)x.ProductId)
     1031                .Max();
     1032
    1861033
    1871034        return (maxId ?? 0) + 1;
    … …  
    1891036
    1901037
    191     private void LoadReleases()
    192     {
    193         ViewBag.Releases = _context.Releases
    194             .OrderBy(x => x.Title)
    195             .ToList();
    196     }
    197 
     1038    // =========================================================
     1039    // NEXT RELEASE ID
     1040    // =========================================================
     1041
     1042    private long GetNextReleaseId()
     1043    {
     1044        var maxId =
     1045            _context.Releases
     1046                .Select(x =>
     1047                    (long?)x.ReleaseId)
     1048                .Max();
     1049
     1050
     1051        return (maxId ?? 0) + 1;
     1052    }
     1053
     1054
     1055    // =========================================================
     1056    // NEXT SONG ID
     1057    // =========================================================
     1058
     1059    private long GetNextSongId()
     1060    {
     1061        var maxId =
     1062            _context.Songs
     1063                .Select(x =>
     1064                    (long?)x.SongId)
     1065                .Max();
     1066
     1067
     1068        return (maxId ?? 0) + 1;
     1069    }
     1070
     1071
     1072    // =========================================================
     1073    // NEXT MODIFICATION ID
     1074    // =========================================================
     1075
     1076    private long GetNextModificationId()
     1077    {
     1078        var maxId =
     1079            _context.Modifications
     1080                .Select(x =>
     1081                    (long?)x.ModificationId)
     1082                .Max();
     1083
     1084
     1085        return (maxId ?? 0) + 1;
     1086    }
     1087
     1088
     1089    // =========================================================
     1090    // CREATE MODIFICATION RECORD
     1091    // =========================================================
    1981092
    1991093    private void CreateModification(
    … …  
    2021096        decimal? discount = null)
    2031097    {
    204         var adminId = GetCurrentUserId();
     1098        var adminId =
     1099            GetCurrentUserId();
     1100
    2051101
    2061102        if (adminId == null)
    207             return;
    208 
    209 
    210         var modification = new Modification
    211         {
    212             ModificationId =
    213                 GetNextModificationId(),
    214 
    215             AdminId = adminId.Value,
    216 
    217             DateModified = DateTime.Today,
    218 
    219             TypeOfModification = type,
    220 
    221             Discount = discount
    222         };
    223 
    224 
    225         _context.Modifications.Add(modification);
     1103        {
     1104            throw new InvalidOperationException(
     1105                "The current admin could not be identified.");
     1106        }
     1107
     1108
     1109        var modification =
     1110            new Modification
     1111            {
     1112                ModificationId =
     1113                    GetNextModificationId(),
     1114
     1115                AdminId =
     1116                    adminId.Value,
     1117
     1118                DateModified =
     1119                    DateTime.Today,
     1120
     1121                TypeOfModification =
     1122                    type,
     1123
     1124                Discount =
     1125                    discount
     1126            };
     1127
     1128
     1129        _context.Modifications.Add(
     1130            modification);
    2261131
    2271132        _context.SaveChanges();
    … …  
    2341139                    modification.ModificationId,
    2351140
    236                 ProductId = productId
     1141                ProductId =
     1142                    productId
    2371143            };
    2381144
    … …  
    2431149        _context.SaveChanges();
    2441150    }
    245 
    246 
    247     private long GetNextModificationId()
    248     {
    249         var maxId = _context.Modifications
    250             .Select(x => (long?)x.ModificationId)
    251             .Max();
    252 
    253         return (maxId ?? 0) + 1;
    254     }
    255     // ==========================================
    256 // UC009
    257 // MODIFY PRODUCT - GET
    258 // ==========================================
    259 
    260     [HttpGet]
    261     public IActionResult EditProduct(long id)
    262     {
    263         if (!IsProductManager())
    264             return Forbid();
    265 
    266         var product = _context.Products
    267             .Include(p => p.Release)
    268             .FirstOrDefault(p => p.ProductId == id);
    269 
    270         if (product == null)
    271             return NotFound();
    272 
    273         var model = new EditProductViewModel
    274         {
    275             ProductId = product.ProductId,
    276             ReleaseId = product.ReleaseId,
    277             ReleaseTitle = product.Release.Title,
    278             Format = product.Format,
    279             Price = product.Price,
    280             ProductDescription = product.ProductDescription,
    281             Stock = product.Stock
    282         };
    283 
    284         return View(model);
    285     }
    286     // ==========================================
    287 // UC009
    288 // MODIFY PRODUCT - POST
    289 // ==========================================
    290 
    291 [HttpPost]
    292 [ValidateAntiForgeryToken]
    293 public IActionResult EditProduct(
    294     EditProductViewModel model)
    295 {
    296     if (!IsProductManager())
    297         return Forbid();
    298 
    299     var product = _context.Products
    300         .Include(p => p.Release)
    301         .FirstOrDefault(p =>
    302             p.ProductId == model.ProductId);
    303 
    304     if (product == null)
    305         return NotFound();
    306 
    307     if (!ModelState.IsValid)
    308     {
    309         model.ReleaseTitle = product.Release.Title;
    310         model.ReleaseId = product.ReleaseId;
    311         model.Format = product.Format;
    312 
    313         return View(model);
    314     }
    315 
    316 
    317     // ==========================================
    318     // DISCOUNT
    319     // ==========================================
    320 
    321     if (model.ModificationType ==
    322         ModificationType.DISCOUNT)
    323     {
    324         if (!model.Discount.HasValue)
    325         {
    326             ModelState.AddModelError(
    327                 "Discount",
    328                 "Please enter a discount percentage.");
    329 
    330             model.ReleaseTitle = product.Release.Title;
    331             model.ReleaseId = product.ReleaseId;
    332             model.Format = product.Format;
    333 
    334             return View(model);
    335         }
    336 
    337         product.Price =
    338             product.Price *
    339             (1 - model.Discount.Value / 100m);
    340     }
    341     else
    342     {
    343         // ==========================================
    344         // NORMAL UPDATE
    345         // ==========================================
    346 
    347         product.Price = model.Price;
    348 
    349         product.ProductDescription =
    350             model.ProductDescription;
    351 
    352         product.Stock = model.Stock;
    353     }
    354 
    355 
    356     _context.SaveChanges();
    357 
    358 
    359     // ==========================================
    360     // RECORD MODIFICATION
    361     // ==========================================
    362 
    363     CreateModification(
    364         model.ModificationType,
    365         product.ProductId,
    366         model.Discount);
    367 
    368 
    369     TempData["Success"] =
    370         "Product modified successfully.";
    371 
    372     return RedirectToAction(nameof(Index));
    3731151}
    374 [HttpGet]
    375 public IActionResult Products()
    376 {
    377     if (!IsProductManager())
    378         return Forbid();
    379 
    380     var products = _context.Products
    381         .Include(p => p.Release)
    382         .OrderBy(p => p.Release.Title)
    383         .ThenBy(p => p.Format)
    384         .ToList();
    385 
    386     return View(products);
    387 }
    388 }
Note: See TracChangeset for help on using the changeset viewer.