From da2431461498e011e6a26b611231d97b2fdf6915 Mon Sep 17 00:00:00 2001 From: Tara Wilson Date: Wed, 4 Dec 2024 15:57:49 -0500 Subject: [PATCH] Building out App --- .../api/Controllers/TicketController.cs | 21 ++++++++ .../api/Interfaces/ITicketManager.cs | 3 ++ source/ticketAPI/api/RestFiles/event.http | 5 +- source/ticketAPI/api/RestFiles/ticket.http | 8 ++- .../ticketAPI/api/Services/TicketManager.cs | 49 +++++++++++++++++-- source/ticketAPI/data/Events/AddTicket.cs | 18 +++++++ source/ticketAPI/data/Events/Find.cs | 15 ++++++ source/ticketAPI/data/Events/Update.cs | 2 +- source/ticketAPI/data/MongoFactory.cs | 5 ++ source/ticketAPI/data/Tickets/Find.cs | 15 ++++++ source/ticketAPI/models/Core/Event.cs | 4 -- source/ticketAPI/models/Core/Talent.cs | 3 -- source/ticketAPI/models/Core/Ticket.cs | 4 -- .../models/Enumerations/TicketValidity.cs | 9 ++++ .../ticketAPI/models/Response/TicketSearch.cs | 9 ++++ .../ticketAPI/ticketAPI.sln.DotSettings.user | 1 + .../src/app/services/event.service.ts | 16 +++++- .../src/app/services/ticket.service.ts | 24 ++++++++- source/ticketUI/src/models/endpoints.ts | 16 +++++- .../src/models/enums/ticket-validity.enum.ts | 6 +++ .../src/models/request/patch-event.ts | 11 +++++ .../src/models/response/ticket-search.ts | 7 +++ 22 files changed, 228 insertions(+), 23 deletions(-) create mode 100644 source/ticketAPI/data/Events/AddTicket.cs create mode 100644 source/ticketAPI/data/Events/Find.cs create mode 100644 source/ticketAPI/data/Tickets/Find.cs create mode 100644 source/ticketAPI/models/Enumerations/TicketValidity.cs create mode 100644 source/ticketAPI/models/Response/TicketSearch.cs create mode 100644 source/ticketUI/src/models/enums/ticket-validity.enum.ts create mode 100644 source/ticketUI/src/models/request/patch-event.ts create mode 100644 source/ticketUI/src/models/response/ticket-search.ts diff --git a/source/ticketAPI/api/Controllers/TicketController.cs b/source/ticketAPI/api/Controllers/TicketController.cs index df1fec6..537debe 100644 --- a/source/ticketAPI/api/Controllers/TicketController.cs +++ b/source/ticketAPI/api/Controllers/TicketController.cs @@ -60,4 +60,25 @@ public class TicketController( return BadRequest(e.Message); } } + + /// + /// Searches for a ticket with a given ticketId and validates it against the event associated with it. + /// + /// A string representing a GUID value + /// Ticket Search Result + [HttpGet] + public ActionResult Get(string ticketId) + { + //TODO: Protect Endpoint + + try + { + var result = ticketManager.SearchTicket(ticketId); + return Ok(result); + } + catch (Exception e) + { + return BadRequest(e.Message); + } + } } \ No newline at end of file diff --git a/source/ticketAPI/api/Interfaces/ITicketManager.cs b/source/ticketAPI/api/Interfaces/ITicketManager.cs index 7cf4fd7..fc229f9 100644 --- a/source/ticketAPI/api/Interfaces/ITicketManager.cs +++ b/source/ticketAPI/api/Interfaces/ITicketManager.cs @@ -1,8 +1,11 @@ using models.Core; +using models.Response; namespace api.Interfaces; public interface ITicketManager { void SaveMintedTicket(Ticket ticket); + + TicketSearch SearchTicket(string ticketId); } \ No newline at end of file diff --git a/source/ticketAPI/api/RestFiles/event.http b/source/ticketAPI/api/RestFiles/event.http index 4a97ac9..b6a6464 100644 --- a/source/ticketAPI/api/RestFiles/event.http +++ b/source/ticketAPI/api/RestFiles/event.http @@ -1,4 +1,5 @@ @api_HostAddress = http://localhost:5168 +@eventId = b9f4478b-701b-4223-9aaa-042b6f53b83a POST {{api_HostAddress}}/event Accept: application/json @@ -30,8 +31,8 @@ Accept: application/json Content-Type: application/json { - "Id": "1a06c032-b073-4715-9b95-9f3410e7abd9", - "Date": "2024-12-03T15:00:00.991Z", + "Id": "{{eventId}}", + "Date": "2024-12-05T15:00:00.991Z", "EventName": "Winter Concert", "EventDescription": "A wintery journey of classical music", "Venue": { diff --git a/source/ticketAPI/api/RestFiles/ticket.http b/source/ticketAPI/api/RestFiles/ticket.http index d8173d1..cf347d9 100644 --- a/source/ticketAPI/api/RestFiles/ticket.http +++ b/source/ticketAPI/api/RestFiles/ticket.http @@ -1,4 +1,6 @@ @api_HostAddress = http://localhost:5168 +@ticketId = 59ae05ea-fd07-481a-9a6b-663444cc426d +@eventId = b9f4478b-701b-4223-9aaa-042b6f53b83a POST {{api_HostAddress}}/ticket Accept: application/json @@ -6,7 +8,11 @@ Content-Type: application/json { "ticketType": "Single", - "eventId": "1a06c032-b073-4715-9b95-9f3410e7abd9" + "eventId": "{{eventId}}" } ### + +GET {{api_HostAddress}}/ticket?ticketId={{ticketId}} +Accept: application/json +Content-Type: application/json \ No newline at end of file diff --git a/source/ticketAPI/api/Services/TicketManager.cs b/source/ticketAPI/api/Services/TicketManager.cs index ddaa6fe..f7b9ffd 100644 --- a/source/ticketAPI/api/Services/TicketManager.cs +++ b/source/ticketAPI/api/Services/TicketManager.cs @@ -1,6 +1,7 @@ using api.Interfaces; -using data.Tickets; using models.Core; +using models.Enumerations; +using models.Response; namespace api.Services; @@ -8,7 +9,49 @@ public class TicketManager : ITicketManager { public void SaveMintedTicket(Ticket ticket) { - //TODO: Add Ticket to Event - new Save().Execute(ticket); + new data.Tickets.Save().Execute(ticket); + new data.Events.AddTicket().Execute(ticket.Id, ticket.EventId); + } + + public TicketSearch SearchTicket(string ticketId) + { + var ticket = new data.Tickets.Find().Execute(ticketId); + + if (ticket == null) + { + throw new Exception("Ticket not found"); + } + + var @event = new data.Events.Find().Execute(ticket.EventId); + + if (@event == null) + { + throw new Exception("Event not found"); + } + + var result = new TicketSearch + { + Type = ticket.Type, + Validity = DetermineValidity(@event) + }; + + return result; + } + + private static TicketValidity DetermineValidity(Event @event) + { + if (@event.Date < DateTime.Now) + { + return TicketValidity.Expired; + } + + if (@event.Date != DateTime.Today) return TicketValidity.Invalid; + + if (DateTime.Now.Hour < @event.Date.Hour - 2) + { + return TicketValidity.Early; + } + + return DateTime.Now.Hour > @event.Date.Hour + 5 ? TicketValidity.Expired : TicketValidity.Valid; } } \ No newline at end of file diff --git a/source/ticketAPI/data/Events/AddTicket.cs b/source/ticketAPI/data/Events/AddTicket.cs new file mode 100644 index 0000000..c024de6 --- /dev/null +++ b/source/ticketAPI/data/Events/AddTicket.cs @@ -0,0 +1,18 @@ +using models.Core; +using MongoDB.Driver; + +namespace data.Events; + +public class AddTicket +{ + public void Execute(Guid ticketId, Guid eventId) + { + var database = MongoFactory.GetDatabase(); + var collection = database.GetCollection("events"); + var filter = Builders.Filter.Eq(e => e.Id, eventId); + + var update = Builders.Update.Push("TicketIds", ticketId); + + collection.FindOneAndUpdate(filter, update); + } +} \ No newline at end of file diff --git a/source/ticketAPI/data/Events/Find.cs b/source/ticketAPI/data/Events/Find.cs new file mode 100644 index 0000000..f4da66a --- /dev/null +++ b/source/ticketAPI/data/Events/Find.cs @@ -0,0 +1,15 @@ +using models.Core; +using MongoDB.Driver; + +namespace data.Events; + +public class Find +{ + public Event Execute(Guid eventId) + { + var database = MongoFactory.GetDatabase(); + var collection = database.GetCollection("events"); + var filter = Builders.Filter.Eq("Id", eventId); + return collection.Find(filter).FirstOrDefault(); + } +} \ No newline at end of file diff --git a/source/ticketAPI/data/Events/Update.cs b/source/ticketAPI/data/Events/Update.cs index 3e5c2d4..365aaa3 100644 --- a/source/ticketAPI/data/Events/Update.cs +++ b/source/ticketAPI/data/Events/Update.cs @@ -11,7 +11,7 @@ public class Update var database = MongoFactory.GetDatabase(); var collection = database.GetCollection("events"); - var filter = Builders.Filter.Eq(e => e.Id, request.Id); + var filter = Builders.Filter.Eq("_id", request.Id); var newEvent = new Event { diff --git a/source/ticketAPI/data/MongoFactory.cs b/source/ticketAPI/data/MongoFactory.cs index 2e6ab44..8339827 100644 --- a/source/ticketAPI/data/MongoFactory.cs +++ b/source/ticketAPI/data/MongoFactory.cs @@ -1,4 +1,7 @@ using Microsoft.Extensions.Configuration; +using MongoDB.Bson; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver; namespace data; @@ -13,6 +16,8 @@ public static class MongoFactory /// public static void InitConfig(IConfiguration config) { + //set up the use of guids globally for the mongo connection + BsonSerializer.RegisterSerializer(new GuidSerializer(GuidRepresentation.Standard)); _config = config; } diff --git a/source/ticketAPI/data/Tickets/Find.cs b/source/ticketAPI/data/Tickets/Find.cs new file mode 100644 index 0000000..09afd59 --- /dev/null +++ b/source/ticketAPI/data/Tickets/Find.cs @@ -0,0 +1,15 @@ +using models.Core; +using MongoDB.Driver; + +namespace data.Tickets; + +public class Find +{ + public Ticket Execute(string ticketId) + { + var database = MongoFactory.GetDatabase(); + var collection = database.GetCollection("tickets"); + var filter = Builders.Filter.Eq("Id", ticketId); + return collection.Find(filter).FirstOrDefault(); + } +} \ No newline at end of file diff --git a/source/ticketAPI/models/Core/Event.cs b/source/ticketAPI/models/Core/Event.cs index 9cf2abd..c860925 100644 --- a/source/ticketAPI/models/Core/Event.cs +++ b/source/ticketAPI/models/Core/Event.cs @@ -1,11 +1,7 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; - namespace models.Core; public class Event { - [BsonGuidRepresentation(GuidRepresentation.Standard)] public Guid Id { get; set; } public DateTime Date { get; set; } public required string EventName { get; set; } diff --git a/source/ticketAPI/models/Core/Talent.cs b/source/ticketAPI/models/Core/Talent.cs index 4403510..b1902b6 100644 --- a/source/ticketAPI/models/Core/Talent.cs +++ b/source/ticketAPI/models/Core/Talent.cs @@ -1,6 +1,3 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; - namespace models.Core; public class Talent diff --git a/source/ticketAPI/models/Core/Ticket.cs b/source/ticketAPI/models/Core/Ticket.cs index f238560..169d716 100644 --- a/source/ticketAPI/models/Core/Ticket.cs +++ b/source/ticketAPI/models/Core/Ticket.cs @@ -1,14 +1,10 @@ using models.Enumerations; -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; namespace models.Core; public class Ticket { - [BsonGuidRepresentation(GuidRepresentation.Standard)] public Guid Id { get; set; } - [BsonGuidRepresentation(GuidRepresentation.Standard)] public Guid EventId { get; set; } public TicketType Type { get; set; } public required string QrCode { get; set; } diff --git a/source/ticketAPI/models/Enumerations/TicketValidity.cs b/source/ticketAPI/models/Enumerations/TicketValidity.cs new file mode 100644 index 0000000..137f9db --- /dev/null +++ b/source/ticketAPI/models/Enumerations/TicketValidity.cs @@ -0,0 +1,9 @@ +namespace models.Enumerations; + +public enum TicketValidity +{ + Valid, + Expired, + Early, + Invalid +} \ No newline at end of file diff --git a/source/ticketAPI/models/Response/TicketSearch.cs b/source/ticketAPI/models/Response/TicketSearch.cs new file mode 100644 index 0000000..9ce941b --- /dev/null +++ b/source/ticketAPI/models/Response/TicketSearch.cs @@ -0,0 +1,9 @@ +using models.Enumerations; + +namespace models.Response; + +public class TicketSearch +{ + public TicketType Type { get; set; } + public TicketValidity Validity { get; set; } +} \ No newline at end of file diff --git a/source/ticketAPI/ticketAPI.sln.DotSettings.user b/source/ticketAPI/ticketAPI.sln.DotSettings.user index 942f032..aa3a83d 100644 --- a/source/ticketAPI/ticketAPI.sln.DotSettings.user +++ b/source/ticketAPI/ticketAPI.sln.DotSettings.user @@ -2,4 +2,5 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded \ No newline at end of file diff --git a/source/ticketUI/src/app/services/event.service.ts b/source/ticketUI/src/app/services/event.service.ts index 1cbc82b..940984f 100644 --- a/source/ticketUI/src/app/services/event.service.ts +++ b/source/ticketUI/src/app/services/event.service.ts @@ -1,4 +1,4 @@ -import {inject, Injectable} from '@angular/core'; +import {inject, Injectable, signal, WritableSignal} from '@angular/core'; import {HttpClient} from '@angular/common/http'; import {AddEventRequest} from '../../models/request/add-event-request'; import {ApiUtils} from './api-utils'; @@ -10,6 +10,7 @@ import {catchError, of} from 'rxjs'; providedIn: 'root' }) export class EventService extends ApiUtils { + public eventSignal: WritableSignal = signal(null); private httpClient = inject(HttpClient); constructor() { @@ -45,4 +46,17 @@ export class EventService extends ApiUtils { }) ).subscribe(); } + + public searchEvents(startDate: Date, endDate: Date): void { + const options = this.setHttpRequestOptions(); + const url = environment.apiBase + Endpoints.EVENT; + + this.httpClient.get(url, options) + .pipe( + catchError(error => { + console.log(error); + return of(undefined); + }) + ).subscribe(); + } } diff --git a/source/ticketUI/src/app/services/ticket.service.ts b/source/ticketUI/src/app/services/ticket.service.ts index 841e9b3..017e0f8 100644 --- a/source/ticketUI/src/app/services/ticket.service.ts +++ b/source/ticketUI/src/app/services/ticket.service.ts @@ -1,4 +1,4 @@ -import {inject, Injectable} from '@angular/core'; +import {inject, Injectable, WritableSignal} from '@angular/core'; import {HttpClient} from '@angular/common/http'; import {signal} from '@angular/core'; import {catchError, map, of} from 'rxjs'; @@ -7,12 +7,14 @@ import {MintResponse} from '../../models/response/mint-response'; import {Endpoints} from '../../models/endpoints'; import {MintRequest} from '../../models/request/mint-request'; import {ApiUtils} from './api-utils'; +import {TicketValidity} from '../../models/enums/ticket-validity.enum'; @Injectable({ providedIn: 'root' }) export class TicketService extends ApiUtils { - public dataSignal = signal(''); + public dataSignal: WritableSignal = signal(''); + public validitySignal: WritableSignal = signal(null); private httpClient = inject(HttpClient); constructor() { @@ -36,4 +38,22 @@ export class TicketService extends ApiUtils { } }); } + + public searchTicket(ticketId: string): void { + const options = this.setHttpRequestOptions(); + const url = environment.apiBase + Endpoints.TICKET_SEARCH(ticketId); + + this.httpClient.get(url, options) + .pipe( + map((response: any) => response.body), + catchError(error => { + console.log(error); + return of(undefined); + }) + ).subscribe((res: TicketValidity) => { + if (res !== undefined) { + this.validitySignal.set(res); + } + }); + } } diff --git a/source/ticketUI/src/models/endpoints.ts b/source/ticketUI/src/models/endpoints.ts index a315e8e..3dcab34 100644 --- a/source/ticketUI/src/models/endpoints.ts +++ b/source/ticketUI/src/models/endpoints.ts @@ -1,5 +1,17 @@ export class Endpoints { - public static readonly TICKET = 'ticket'; + /* Ticket Routes */ + public static readonly TICKET: string = 'ticket'; - public static readonly EVENT = 'events'; + /* Calculated Routes */ + public static TICKET_SEARCH(ticketId: string): string { + return `${Endpoints.TICKET}?ticketId=${ticketId}`; + } + + /* Event Routes */ + public static readonly EVENT: string = 'events'; + + /* Calculated Routes */ + public static EVENT_DATE_SEARCH(startDate: Date, endDate: Date): string { + return `${Endpoints.EVENT}?startDate=${startDate}&endDate=${endDate}`; + } } diff --git a/source/ticketUI/src/models/enums/ticket-validity.enum.ts b/source/ticketUI/src/models/enums/ticket-validity.enum.ts new file mode 100644 index 0000000..3876b42 --- /dev/null +++ b/source/ticketUI/src/models/enums/ticket-validity.enum.ts @@ -0,0 +1,6 @@ +export enum TicketValidity { + Valid, + Expired, + Early, + Invalid +} diff --git a/source/ticketUI/src/models/request/patch-event.ts b/source/ticketUI/src/models/request/patch-event.ts new file mode 100644 index 0000000..1bd35eb --- /dev/null +++ b/source/ticketUI/src/models/request/patch-event.ts @@ -0,0 +1,11 @@ +import {Venue} from '../core/venue'; +import {Talent} from '../core/talent'; + +export interface PatchEvent { + id: string, + date: Date, + eventName: string, + eventDescription: string, + venue: Venue, + talent: Talent +} diff --git a/source/ticketUI/src/models/response/ticket-search.ts b/source/ticketUI/src/models/response/ticket-search.ts new file mode 100644 index 0000000..78de130 --- /dev/null +++ b/source/ticketUI/src/models/response/ticket-search.ts @@ -0,0 +1,7 @@ +import {TicketTypeEnum} from '../enums/ticket-type.enum'; +import {TicketValidity} from '../enums/ticket-validity.enum'; + +export interface TicketSearch { + ticketType: TicketTypeEnum, + ticketValidity: TicketValidity +}