Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: merge Lorem Fitsum features into Reference Implementation feeds #215

Merged
merged 21 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UserSecretsId>aspnet-BookingSystem.AspNetCore-443B4F82-A20C-41CE-9924-329A0BCF0D14</UserSecretsId>
<Configurations>Release;Debug</Configurations>
</PropertyGroup>

<ItemGroup>
Expand All @@ -22,4 +23,5 @@
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " />
</Project>
358 changes: 230 additions & 128 deletions Examples/BookingSystem.AspNetCore/Feeds/FacilitiesFeeds.cs

Large diffs are not rendered by default.

449 changes: 340 additions & 109 deletions Examples/BookingSystem.AspNetCore/Feeds/SessionsFeeds.cs

Large diffs are not rendered by default.

252 changes: 252 additions & 0 deletions Examples/BookingSystem.AspNetCore/Helpers/FeedGenerationHelper.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
"profiles": {
"BookingSystem.AspNetCore": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "https://localhost:5001/openactive",
"launchUrl": "https://localhost:5002/openactive",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have just spotted a typo, so will fix if this current CI run passes

"applicationUrl": "https://localhost:5001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
Expand Down
23 changes: 23 additions & 0 deletions Examples/BookingSystem.AspNetCore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,26 @@ This implementation is also used as a reference implementation for the [Test Sui

`ApplicationHostBaseUrl: http://localhost:{PORT}`
3. Now, re-run the project. You're good to go 👍


## Reference Implementation Data Generation

Reference Implementation has three main uses that make it very important in the OpenActive ecosystem:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to do either:

  1. Make it clear that "BookingSystem.AspNetCore" is synonymous with "Reference Implementation", which is not exactly explicit in the top section of this README
  2. Or just always call the project BookingSystem.AspNetCore in the README

My personal opinion is # 2 because OpenActive may need to broaden the meaning of "Reference Implementation" at a later date (e.g. if there are future reference implementations in other languages)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep makes sense, I've added a comment about that.

- For data publishers / booking systems: It is used to demonstrate the properties and shape of data and APIs, according to the OpenActive specifications
- For data users / brokers: It is used as a trial integration where testing can be done with no ramifications
- For contributors: It is used to ensure the Test Suite tests are correct and passing, for different combinations of Open Booking API features.
Comment on lines +39 to +41
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unbelievably useful to finally spell this out — good shout!


The data for the sample feeds are generated in two places:
- BookingSystem.AspNetCore/Feeds/*Feeds.cs
- OpenActive.FakeDatabase.NET/Fakes/FakeBookingSystem.cs

The FakeBookingSystem within OpenActive.FakeDatabase.NET acts as the interface to an example database.
The example Feeds within BookingSystem.AspNetCore query this interface and translate the data to conform with the OpenActive Modelling Spec.

Due to this split of functionality, the sample data in the feeds are created/transformed in both files, depending on whether they are important to booking
or not. For example, `Price` is important to booking and there is generated in FakeBookingSystem at startup and stored in the in-memory database. However `Terms Of Service` is not
needed for booking, and therefore is generated at request time.
Comment on lines +50 to +52
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also appreciated!


### Golden Records
Golden records are randomly generated records that contain all possible fields specified by the OpenActive Modelling Specification.
They are unrealistic representations of data, and the presence of all the fields should not be relied on when developing front-end representations of the data.
7 changes: 4 additions & 3 deletions Examples/BookingSystem.AspNetCore/Stores/FacilityStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BookingSystem.AspNetCore.Helpers;
using OpenActive.DatasetSite.NET;
using OpenActive.FakeDatabase.NET;
using OpenActive.NET;
Expand Down Expand Up @@ -320,7 +321,7 @@ protected override async Task GetOrderItems(List<OrderItemContext<FacilityOpport
}),
Name = facility.Name,
Url = new Uri("https://example.com/events/" + slot.FacilityUseId),
Location = _fakeBookingSystem.Database.GetPlaceById(facility.PlaceId),
Location = FeedGenerationHelper.GetPlaceById(facility.PlaceId),
FacilityType = new List<Concept> {
new Concept
{
Expand Down Expand Up @@ -374,11 +375,11 @@ protected override async Task GetOrderItems(List<OrderItemContext<FacilityOpport
// Note this should always be driven from the database, with new FacilityOpportunity's instantiated
Id = RenderOpportunityId(new FacilityOpportunity
{
OpportunityType = _appSettings.FeatureFlags.FacilityUseHasSlots ? OpportunityType.FacilityUseSlot : OpportunityType.IndividualFacilityUseSlot,
OpportunityType = _appSettings.FeatureFlags.FacilityUseHasSlots ? OpportunityType.FacilityUseSlot : OpportunityType.IndividualFacilityUseSlot,
FacilityUseId = slot.FacilityUseId,
SlotId = slot.Id,
IndividualFacilityUseId = !_appSettings.FeatureFlags.FacilityUseHasSlots ? slot.IndividualFacilityUseId : null,
}),
}),
FacilityUse = slotParent,
StartDate = (DateTimeOffset)slot.Start,
EndDate = (DateTimeOffset)slot.End,
Expand Down
4 changes: 2 additions & 2 deletions Examples/BookingSystem.AspNetCore/Stores/SessionStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using OpenActive.FakeDatabase.NET;
using RequiredStatusType = OpenActive.FakeDatabase.NET.RequiredStatusType;
using System.Threading.Tasks;

using BookingSystem.AspNetCore.Helpers;

namespace BookingSystem
{
Expand Down Expand Up @@ -361,7 +361,7 @@ protected override async Task GetOrderItems(List<OrderItemContext<SessionOpportu
}),
Name = @class.Title,
Url = new Uri("https://example.com/events/" + occurrence.ClassId),
Location = _fakeBookingSystem.Database.GetPlaceById(@class.PlaceId),
Location = FeedGenerationHelper.GetPlaceById(@class.PlaceId),
Activity = new List<Concept>
{
new Concept
Expand Down
116 changes: 2 additions & 114 deletions Fakes/OpenActive.FakeDatabase.NET/FakeBookingSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -644,118 +644,6 @@ await db.InsertAsync(new OrderTable
}
}

public OpenActive.NET.Place GetPlaceById(long placeId)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this to FeedGenerationHelper as it doesn't really belong in FakeBookingSystem

{
// Three hardcoded fake places
switch (placeId)
{
case 1:
return new OpenActive.NET.Place
{
Identifier = 1,
Name = "Post-ercise Plaza",
Description = "Sorting Out Your Fitness One Parcel Lift at a Time! Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
Address = new OpenActive.NET.PostalAddress
{
StreetAddress = "Kings Mead House",
AddressLocality = "Oxford",
AddressRegion = "Oxfordshire",
PostalCode = "OX1 1AA",
AddressCountry = "GB"
},
Geo = new OpenActive.NET.GeoCoordinates
{
Latitude = (decimal?)51.7502,
Longitude = (decimal?)-1.2674
},
Image = new List<OpenActive.NET.ImageObject> {
new OpenActive.NET.ImageObject
{
Url = new Uri("https://upload.wikimedia.org/wikipedia/commons/e/e5/Oxford_StAldates_PostOffice.jpg")
},
},
Telephone = "01865 000001",
Url = new Uri("https://en.wikipedia.org/wiki/Post_Office_Limited"),
AmenityFeature = new List<OpenActive.NET.LocationFeatureSpecification>
{
new OpenActive.NET.ChangingFacilities { Name = "Changing Facilities", Value = true },
new OpenActive.NET.Showers { Name = "Showers", Value = true },
new OpenActive.NET.Lockers { Name = "Lockers", Value = true },
new OpenActive.NET.Towels { Name = "Towels", Value = false },
new OpenActive.NET.Creche { Name = "Creche", Value = false },
new OpenActive.NET.Parking { Name = "Parking", Value = false }
}
};
case 2:
return new OpenActive.NET.Place
{
Identifier = 2,
Name = "Premier Lifters",
Description = "Where your Fitness Goals are Always Inn-Sight. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
Address = new OpenActive.NET.PostalAddress
{
StreetAddress = "Greyfriars Court, Paradise Square",
AddressLocality = "Oxford",
AddressRegion = "Oxfordshire",
PostalCode = "OX1 1BB",
AddressCountry = "GB"
},
Geo = new OpenActive.NET.GeoCoordinates
{
Latitude = (decimal?)51.7504933,
Longitude = (decimal?)-1.2620685
},
Image = new List<OpenActive.NET.ImageObject> {
new OpenActive.NET.ImageObject
{
Url = new Uri("https://upload.wikimedia.org/wikipedia/commons/5/53/Cambridge_Orchard_Park_Premier_Inn.jpg")
},
},
Telephone = "01865 000002",
Url = new Uri("https://en.wikipedia.org/wiki/Premier_Inn"),
AmenityFeature = new List<OpenActive.NET.LocationFeatureSpecification>
{
new OpenActive.NET.ChangingFacilities { Name = "Changing Facilities", Value = false },
new OpenActive.NET.Showers { Name = "Showers", Value = false },
new OpenActive.NET.Lockers { Name = "Lockers", Value = false },
new OpenActive.NET.Towels { Name = "Towels", Value = true },
new OpenActive.NET.Creche { Name = "Creche", Value = true },
new OpenActive.NET.Parking { Name = "Parking", Value = true }
}
};
case 3:
return new OpenActive.NET.Place
{
Identifier = 3,
Name = "Stroll & Stretch",
Description = "Casual Calisthenics in the Heart of Commerce. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
Address = new OpenActive.NET.PostalAddress
{
StreetAddress = "Norfolk Street",
AddressLocality = "Oxford",
AddressRegion = "Oxfordshire",
PostalCode = "OX1 1UU",
AddressCountry = "GB"
},
Geo = new OpenActive.NET.GeoCoordinates
{
Latitude = (decimal?)51.749826,
Longitude = (decimal?)-1.261492
},
Image = new List<OpenActive.NET.ImageObject> {
new OpenActive.NET.ImageObject
{
Url = new Uri("https://upload.wikimedia.org/wikipedia/commons/2/28/Westfield_Garden_State_Plaza_-_panoramio.jpg")
},
},
Telephone = "01865 000003",
Url = new Uri("https://en.wikipedia.org/wiki/Shopping_center"),
};
default:
return null;
}
}

public async Task<(bool, FacilityUseTable, SlotTable, BookedOrderItemInfo)> GetSlotAndBookedOrderItemInfoBySlotId(Guid uuid, long? slotId)
{
using (var db = await Mem.Database.OpenAsync())
Expand Down Expand Up @@ -1497,13 +1385,13 @@ private static async Task CreateFakeFacilitiesAndSlots(IDbConnection db, bool fa
var slotId = 0;
List<(FacilityUseTable facility, List<SlotTable> slots)> facilitiesAndSlots = opportunitySeeds.Select((seed) =>
{
var facilityUseName = $"{Faker.Commerce.ProductMaterial()} {Faker.PickRandomParam("Sports Hall", "Swimming Pool Hall", "Running Hall", "Jumping Hall")}";
var facilityUseName = $"{Faker.Commerce.ProductMaterial()} {Faker.PickRandomParam("Sports Hall", "Squash Court", "Badminton Court", "Cricket Net")}";
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These have matching facility types in the Facility Types JSONLD

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use an enum for these, rather than string matching?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is facility type name, not the Facility Type

var facility = new FacilityUseTable
{
Id = seed.Id,
Deleted = false,
Name = facilityUseName,
SellerId = Faker.Random.Bool(0.8f) ? Faker.Random.Long(1, 2) : Faker.Random.Long(3, 5), // distribution: 80% 1-2, 20% 3-5
SellerId = Faker.Random.Bool(0.8f) ? Faker.Random.Long(1, 2) : Faker.Random.Long(3, 4), // distribution: 80% 1-2, 20% 3-5
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seller 5 is an individual seller which doesn't make sense for a facility

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have just spotted a typo, so will fix if this current CI run passes

PlaceId = Faker.PickRandom(new[] { 1, 2, 3 })
};

Expand Down
Loading