Adding functionality

This commit is contained in:
Tara Wilson 2024-12-19 15:58:37 -05:00
parent 6731c4e5f4
commit 6812f48c59
26 changed files with 267 additions and 72 deletions

View File

@ -56,15 +56,16 @@ public class EventController(IEventManager eventManager) : ControllerBase
/// </summary>
/// <param name="startDate">Start date for the event search</param>
/// <param name="endDate">End date for the event search</param>
/// <param name="seasonId">Season to find events for</param>
/// <returns></returns>
[HttpGet]
public ActionResult<List<Event>> Get(DateTime? startDate, DateTime? endDate)
public ActionResult<List<Event>> Get(DateTime? startDate, DateTime? endDate, string? seasonId)
{
try
{
if (startDate == null && endDate == null)
{
return Ok(eventManager.GetAllEvents());
return Ok(seasonId == null ? eventManager.GetAllEvents() : eventManager.GetBySeason(new Guid(seasonId)));
}
return Ok(eventManager.GetEvents(startDate, endDate));
}
@ -73,4 +74,24 @@ public class EventController(IEventManager eventManager) : ControllerBase
return BadRequest(e.Message);
}
}
/// <summary>
/// Deletes an event
/// </summary>
/// <param name="eventId">Event to delete</param>
/// <returns></returns>
[HttpDelete]
public IActionResult Delete(Guid eventId)
{
// TODO: Protect Endpoint
try
{
eventManager.DeleteEvent(eventId);
return Ok();
}
catch (Exception e)
{
return BadRequest(e.Message);
}
}
}

View File

@ -53,18 +53,39 @@ public class SeasonController(ISeasonManager seasonManager) : ControllerBase
}
/// <summary>
/// Adds an event to a season
/// Updates a season
/// </summary>
/// <param name="seasonId">Season Id</param>
/// <param name="eventId">Event Id</param>
/// <param name="request">Updated season information</param>
/// <returns></returns>
[HttpPut]
public IActionResult Put(Guid eventId, Guid seasonId)
[HttpPatch]
public IActionResult Patch(PatchSeason request)
{
//TODO: Protect Endpoint
try
{
seasonManager.AddEventToSeason(eventId, seasonId);
seasonManager.PatchSeason(request);
return Ok();
}
catch (Exception e)
{
return BadRequest(e.Message);
}
}
/// <summary>
/// Deletes a season
/// </summary>
/// <param name="seasonId">SeasonId to delete</param>
/// <returns></returns>
[HttpDelete]
public IActionResult Delete(Guid seasonId)
{
//TODO: Protect Endpoint
try
{
seasonManager.DeleteSeason(seasonId);
return Ok();
}
catch (Exception e)

View File

@ -11,4 +11,6 @@ public interface IEventManager
List<Event> GetEvents(DateTime? startDate, DateTime? endDate);
List<Event> GetAllEvents();
EventDetails GetEvent(Guid id);
void DeleteEvent(Guid eventId);
List<Event> GetBySeason(Guid seasonId);
}

View File

@ -7,5 +7,6 @@ public interface ISeasonManager
{
void AddSeason(AddSeason season);
List<Season> GetSeasons();
void AddEventToSeason(Guid eventId, Guid seasonId);
void PatchSeason(PatchSeason request);
void DeleteSeason(Guid seasonId);
}

View File

@ -63,3 +63,9 @@ Content-Type: application/json
GET {{api_HostAddress}}/event
Accept: application/json
Content-Type: application/json
###
GET {{api_HostAddress}}/event?seasonId={{seasonId}}
Accept: application/json
Content-Type: application/json

View File

@ -18,7 +18,13 @@ public class EmailService(IConfiguration config) : IEmailService
config.GetSection("Email:Password").Value);
client.Credentials = auth;
var from = new MailAddress(config.GetSection("Email:From").Value);
var from = new MailAddress(config.GetSection("Email:From").Value ?? string.Empty);
if (from.Address != config.GetSection("Email:From").Value)
{
throw new Exception("Invalid email address");
}
var to = new MailAddress(ticket.Patron.Email);
var emailMessage = new MailMessage(from, to);

View File

@ -22,7 +22,6 @@ public class EventManager : IEventManager
};
new Save().Execute(@event);
new data.Seasons.AddEvent().Execute(@event.Id, request.SeasonId);
}
public void PatchEvent(PatchEvent request)
@ -44,4 +43,14 @@ public class EventManager : IEventManager
{
return new GetDetails().Execute(id);
}
public void DeleteEvent(Guid eventId)
{
new Delete().Execute(eventId);
}
public List<Event> GetBySeason(Guid seasonId)
{
return new GetBySeason().Execute(seasonId);
}
}

View File

@ -2,7 +2,6 @@ using api.Interfaces;
using data.Seasons;
using models.Core;
using models.Request;
using AddEvent = data.Seasons.AddEvent;
namespace api.Services;
@ -27,8 +26,13 @@ public class SeasonManager : ISeasonManager
return new GetAll().Execute();
}
public void AddEventToSeason(Guid eventId, Guid seasonId)
public void PatchSeason(PatchSeason request)
{
new AddEvent().Execute(eventId, seasonId);
new Update().Execute(request);
}
public void DeleteSeason(Guid seasonId)
{
new Delete().Execute(seasonId);
}
}

View File

@ -10,7 +10,6 @@ public class TicketManager : ITicketManager
public void SaveMintedTicket(Ticket ticket)
{
new data.Tickets.Save().Execute(ticket);
new data.Events.AddTicket().Execute(ticket.Id, ticket.EventId);
}
public TicketSearch SearchTicket(Guid ticketId)

View File

@ -3,16 +3,14 @@ using MongoDB.Driver;
namespace data.Events;
public class AddTicket
public class Delete
{
public void Execute(Guid ticketId, Guid eventId)
public void Execute(Guid eventId)
{
var database = MongoFactory.GetDatabase();
var collection = database.GetCollection<Event>("events");
var filter = Builders<Event>.Filter.Eq(e => e.Id, eventId);
var collection = database.GetCollection<Event>("events");
var update = Builders<Event>.Update.Push("TicketIds", ticketId);
collection.FindOneAndUpdate(filter, update);
collection.DeleteOne(filter);
}
}

View File

@ -9,7 +9,7 @@ public class Find
{
var database = MongoFactory.GetDatabase();
var collection = database.GetCollection<Event>("events");
var filter = Builders<Event>.Filter.Eq("Id", eventId);
var filter = Builders<Event>.Filter.Eq(e => e.Id, eventId);
return collection.Find(filter).FirstOrDefault();
}
}

View File

@ -0,0 +1,16 @@
using models.Core;
using MongoDB.Driver;
namespace data.Events;
public class GetBySeason
{
public List<Event> Execute(Guid seasonId)
{
var database = MongoFactory.GetDatabase();
var collection = database.GetCollection<Event>("events");
var filter = Builders<Event>.Filter.Eq(e => e.SeasonId, seasonId);
return collection.Find(filter).ToList();
}
}

View File

@ -6,16 +6,17 @@ namespace data.Events;
public class Update
{
public bool Execute(PatchEvent request)
public void Execute(PatchEvent request)
{
var database = MongoFactory.GetDatabase();
var collection = database.GetCollection<Event>("events");
var filter = Builders<Event>.Filter.Eq("_id", request.Id);
var filter = Builders<Event>.Filter.Eq(e => e.Id, request.Id);
var newEvent = new Event
{
Id = request.Id,
SeasonId = request.SeasonId,
Date = request.Date,
Name = request.Name,
Description = request.Description,
@ -23,6 +24,6 @@ public class Update
Talent = request.Talent,
};
return collection.ReplaceOne(filter, newEvent).IsAcknowledged;
collection.ReplaceOne(filter, newEvent);
}
}

View File

@ -3,16 +3,14 @@ using MongoDB.Driver;
namespace data.Seasons;
public class AddEvent
public class Delete
{
public void Execute(Guid eventId, Guid seasonId)
public void Execute(Guid seasonId)
{
var database = MongoFactory.GetDatabase();
var collection = database.GetCollection<Season>("seasons");
var filter = Builders<Season>.Filter.Eq(s => s.Id, seasonId);
var collection = database.GetCollection<Season>("seasons");
var update = Builders<Season>.Update.Push("EventIds", eventId);
collection.FindOneAndUpdate(filter, update);
collection.DeleteOne(filter);
}
}

View File

@ -0,0 +1,27 @@
using models.Core;
using models.Request;
using MongoDB.Driver;
namespace data.Seasons;
public class Update
{
public void Execute(PatchSeason request)
{
var database = MongoFactory.GetDatabase();
var collection = database.GetCollection<Season>("seasons");
var filter = Builders<Season>.Filter.Eq(s => s.Id, request.Id);
var newSeason = new Season
{
Id = request.Id,
Name = request.Name,
Description = request.Description,
StartDate = request.StartDate,
EndDate = request.EndDate,
};
collection.ReplaceOne(filter, newSeason);
}
}

View File

@ -9,5 +9,4 @@ public class Event
public string? Description { get; set; }
public required Venue Venue { get; set; }
public required Talent Talent { get; set; }
public List<Guid> TicketIds { get; set; } = [];
}

View File

@ -7,5 +7,4 @@ public class Season
public string? Description { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public List<Guid> EventIds { get; set; } = [];
}

View File

@ -5,6 +5,7 @@ namespace models.Request;
public class PatchEvent
{
public Guid Id { get; set; }
public Guid SeasonId { get; set; }
public DateTime Date { get; set; }
public required string Name { get; set; }
public string? Description { get; set; }

View File

@ -0,0 +1,10 @@
namespace models.Request;
public class PatchSeason
{
public Guid Id { get; set; }
public required string Name { get; set; }
public string? Description { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}

View File

@ -17,7 +17,7 @@ export class EventBrowserComponent implements OnInit {
public selectedEventId$: WritableSignal<string> = signal('');
public ngOnInit() {
this.eventService.searchAllEvents();
this.eventService.searchEvents(undefined, undefined, undefined);
}
public click(eventId: string): void {

View File

@ -1,31 +1,13 @@
import {HttpHeaders, HttpParams} from '@angular/common/http';
import {HttpHeaders} from '@angular/common/http';
export class ApiUtils {
protected setHttpRequestOptions(params?: any): any {
protected setHttpRequestOptions(): any {
let headers: HttpHeaders = new HttpHeaders();
headers = headers.set('Content-Type', 'application/json');
const options: any = {
return {
headers,
observe: 'response'
};
if (params) {
options.params = this.setHttpParams(params);
}
return options;
}
private setHttpParams(query: object): HttpParams {
const params = new HttpParams();
for (const key in query) {
// @ts-ignore
if (query[key] && query.hasOwnProperty(key)) {
// @ts-ignore
params.append(key, query[key]);
}
}
return params;
}
}

View File

@ -7,6 +7,7 @@ import {Endpoints} from '../../models/endpoints';
import {catchError, map, of} from 'rxjs';
import {SnackbarService} from './snackbar.service';
import {Event} from '../../models/core/event';
import {PatchEvent} from '../../models/request/patch-event';
@Injectable({
providedIn: 'root'
@ -21,7 +22,6 @@ export class EventService extends ApiUtils {
}
public addEvent(request: AddEventRequest): void {
//TODO: Remove hard coded venue and talent information
const options = this.setHttpRequestOptions();
const url = environment.apiBase + Endpoints.EVENT;
@ -34,40 +34,80 @@ export class EventService extends ApiUtils {
).subscribe(res => {
if(res !== null) {
this.snackbar.showMessage('Event added successfully.');
this.searchAllEvents();
this.searchEvents(undefined, undefined, undefined);
}
});
}
public searchAllEvents(): void {
/**
* Searches for events, returns all events if parameters are not provided
* @param startDate If provided with an end date, will search in the date range
* @param endDate If provided with a start date, will search in the date range
* @param seasonId If provided, returns all events for a season
*/
public searchEvents(startDate: Date | undefined,
endDate: Date | undefined,
seasonId: string | undefined): void {
const options = this.setHttpRequestOptions();
let url: string = '';
if (startDate && endDate) {
url = environment.apiBase + Endpoints.EVENT_DATE_SEARCH(startDate, endDate);
} else if (seasonId) {
url = environment.apiBase + Endpoints.EVENT_SEASON_SEARCH(seasonId);
} else {
url = environment.apiBase + Endpoints.EVENT;
}
this.httpClient.get(url, options)
.pipe(
map((response: any) => response.body),
catchError(error => {
this.snackbar.showError(error.error);
return of(undefined);
})
).subscribe(res => {
if(res !== null) {
this.events$.set(res);
} else {
this.snackbar.showError('No events found.');
}
});
}
public updateEvent(request: PatchEvent): void {
const options = this.setHttpRequestOptions();
const url = environment.apiBase + Endpoints.EVENT;
this.httpClient.get(url, options)
this.httpClient.patch(url, JSON.stringify(request), options)
.pipe(
map((response: any) => response.body),
catchError(error => {
this.snackbar.showError(error.error);
return of(undefined);
})
).subscribe(res => {
this.events$.set(res);
});
if(res !== null) {
this.snackbar.showMessage('Event updated successfully.');
this.searchEvents(undefined, undefined, undefined);
}
})
}
public searchEvents(startDate: Date, endDate: Date): void {
public deleteEvent(eventId: string): void {
const options = this.setHttpRequestOptions();
const url = environment.apiBase + Endpoints.EVENT_DATE_SEARCH(startDate, endDate);
const url = environment.apiBase + Endpoints.EVENT_DELETE(eventId);
this.httpClient.get(url, options)
this.httpClient.delete(url, options)
.pipe(
map((response: any) => response.body),
catchError(error => {
this.snackbar.showError(error.error);
return of(undefined);
})
).subscribe(res => {
this.events$.set(res);
});
if(res !== null) {
this.snackbar.showMessage('Event deleted successfully.');
this.searchEvents(undefined, undefined, undefined);
}
})
}
}

View File

@ -7,6 +7,7 @@ import {environment} from '../../environments/environment';
import {Endpoints} from '../../models/endpoints';
import {catchError, map, of} from 'rxjs';
import {AddSeason} from '../../models/request/add-season';
import {PatchSeason} from '../../models/request/patch-season';
@Injectable({
providedIn: 'root'
@ -39,7 +40,7 @@ export class SeasonService extends ApiUtils {
}
public saveSeason(request: AddSeason): void {
const options = this.setHttpRequestOptions(request);
const options = this.setHttpRequestOptions();
const url = environment.apiBase + Endpoints.SEASON;
this.httpClient.post(url, JSON.stringify(request), options)
@ -68,4 +69,40 @@ export class SeasonService extends ApiUtils {
})
).subscribe();
}
public updateSeason(request: PatchSeason): void {
const options = this.setHttpRequestOptions();
const url = environment.apiBase + Endpoints.SEASON;
this.httpClient.patch(url, JSON.stringify(request), options)
.pipe(
catchError(error => {
this.snackbar.showError(error.error);
return of(undefined);
})
).subscribe(res => {
if (res !== null) {
this.snackbar.showMessage('Season updated successfully.');
this.getSeasons();
}
});
}
public deleteSeason(seasonId: string): void {
const options = this.setHttpRequestOptions();
const url = environment.apiBase + Endpoints.SEASON_DELETE(seasonId);
this.httpClient.delete(url, options)
.pipe(
catchError(error => {
this.snackbar.showError(error.error);
return of(undefined);
})
).subscribe(res => {
if (res !== null) {
this.snackbar.showMessage('Season deleted successfully.');
this.getSeasons();
}
});
}
}

View File

@ -8,6 +8,5 @@ export interface Event {
name: string,
description: string | null,
venue: Venue,
talent: Talent,
ticketIds: Array<string>
talent: Talent
}

View File

@ -22,6 +22,14 @@ export class Endpoints {
return `${Endpoints.EVENT}?startDate=${startDate}&endDate=${endDate}`;
}
public static EVENT_SEASON_SEARCH(seasonId: string): string {
return `${Endpoints.EVENT}?seasonId=${seasonId}`;
}
public static EVENT_DELETE(eventId: string): string {
return `${Endpoints.EVENT}?eventId=${eventId}`;
}
/* Season Routes */
public static readonly SEASON: string = 'season';
@ -29,4 +37,8 @@ export class Endpoints {
public static SEASON_ADD_EVENT(eventId: string, seasonId: string): string {
return `${Endpoints.SEASON}?eventId=${eventId}&seasonId=${seasonId}`;
}
public static SEASON_DELETE(seasonId: string): string {
return `${Endpoints.SEASON}?seasonId=${seasonId}`;
}
}

View File

@ -0,0 +1,7 @@
export interface PatchSeason {
id: string,
name: string,
description: string | null,
startDate: Date,
endDate: Date
}