Building out App
This commit is contained in:
parent
a510abd7f7
commit
da24314614
|
|
@ -60,4 +60,25 @@ public class TicketController(
|
|||
return BadRequest(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for a ticket with a given ticketId and validates it against the event associated with it.
|
||||
/// </summary>
|
||||
/// <param name="ticketId">A string representing a GUID value</param>
|
||||
/// <returns>Ticket Search Result</returns>
|
||||
[HttpGet]
|
||||
public ActionResult<TicketSearch> Get(string ticketId)
|
||||
{
|
||||
//TODO: Protect Endpoint
|
||||
|
||||
try
|
||||
{
|
||||
var result = ticketManager.SearchTicket(ticketId);
|
||||
return Ok(result);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return BadRequest(e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
using models.Core;
|
||||
using models.Response;
|
||||
|
||||
namespace api.Interfaces;
|
||||
|
||||
public interface ITicketManager
|
||||
{
|
||||
void SaveMintedTicket(Ticket ticket);
|
||||
|
||||
TicketSearch SearchTicket(string ticketId);
|
||||
}
|
||||
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
18
source/ticketAPI/data/Events/AddTicket.cs
Normal file
18
source/ticketAPI/data/Events/AddTicket.cs
Normal file
|
|
@ -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<Event>("events");
|
||||
var filter = Builders<Event>.Filter.Eq(e => e.Id, eventId);
|
||||
|
||||
var update = Builders<Event>.Update.Push("TicketIds", ticketId);
|
||||
|
||||
collection.FindOneAndUpdate(filter, update);
|
||||
}
|
||||
}
|
||||
15
source/ticketAPI/data/Events/Find.cs
Normal file
15
source/ticketAPI/data/Events/Find.cs
Normal file
|
|
@ -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<Event>("events");
|
||||
var filter = Builders<Event>.Filter.Eq("Id", eventId);
|
||||
return collection.Find(filter).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ public class Update
|
|||
var database = MongoFactory.GetDatabase();
|
||||
var collection = database.GetCollection<Event>("events");
|
||||
|
||||
var filter = Builders<Event>.Filter.Eq(e => e.Id, request.Id);
|
||||
var filter = Builders<Event>.Filter.Eq("_id", request.Id);
|
||||
|
||||
var newEvent = new Event
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
|||
/// <param name="config"></param>
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
15
source/ticketAPI/data/Tickets/Find.cs
Normal file
15
source/ticketAPI/data/Tickets/Find.cs
Normal file
|
|
@ -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<Ticket>("tickets");
|
||||
var filter = Builders<Ticket>.Filter.Eq("Id", ticketId);
|
||||
return collection.Find(filter).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
|
||||
namespace models.Core;
|
||||
|
||||
public class Talent
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
9
source/ticketAPI/models/Enumerations/TicketValidity.cs
Normal file
9
source/ticketAPI/models/Enumerations/TicketValidity.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
namespace models.Enumerations;
|
||||
|
||||
public enum TicketValidity
|
||||
{
|
||||
Valid,
|
||||
Expired,
|
||||
Early,
|
||||
Invalid
|
||||
}
|
||||
9
source/ticketAPI/models/Response/TicketSearch.cs
Normal file
9
source/ticketAPI/models/Response/TicketSearch.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
using models.Enumerations;
|
||||
|
||||
namespace models.Response;
|
||||
|
||||
public class TicketSearch
|
||||
{
|
||||
public TicketType Type { get; set; }
|
||||
public TicketValidity Validity { get; set; }
|
||||
}
|
||||
|
|
@ -2,4 +2,5 @@
|
|||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AConnectionString_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fb1a941e9ba91a5a4d64a4ebc59b771c12c16aeea8b9c9da3f70b88f93ae4d7_003FConnectionString_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEndpointRoutingApplicationBuilderExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F929ca880328a40769fd3ef8963dc5388e5400_003F20_003F918ae4ba_003FEndpointRoutingApplicationBuilderExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEnsure_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Ffea93ee2ea48db69df97b9196fe77e86f2428c362835f6eda284e2df33bc5db_003FEnsure_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFieldDefinition_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F2b48dfdf26ab2a566afcd1aceb264cd8416dabae58c6f655499d62d8119690_003FFieldDefinition_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AServer_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Ffe3b1716bf2f8f83ac793e7e3faa60f88a7868347653f77591f74b86d0d97675_003FServer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
|
|
@ -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<Event | null> = 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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<string> = signal('');
|
||||
public validitySignal: WritableSignal<TicketValidity | null> = 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<TicketValidity>(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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}`;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
6
source/ticketUI/src/models/enums/ticket-validity.enum.ts
Normal file
6
source/ticketUI/src/models/enums/ticket-validity.enum.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export enum TicketValidity {
|
||||
Valid,
|
||||
Expired,
|
||||
Early,
|
||||
Invalid
|
||||
}
|
||||
11
source/ticketUI/src/models/request/patch-event.ts
Normal file
11
source/ticketUI/src/models/request/patch-event.ts
Normal file
|
|
@ -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
|
||||
}
|
||||
7
source/ticketUI/src/models/response/ticket-search.ts
Normal file
7
source/ticketUI/src/models/response/ticket-search.ts
Normal file
|
|
@ -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
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user