Skip to content

Commit

Permalink
add filtering method
Browse files Browse the repository at this point in the history
  • Loading branch information
SashimiDaBest committed Jan 29, 2025
1 parent e46c7cb commit edfb15c
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 31 deletions.
140 changes: 124 additions & 16 deletions Controllers/BuildingController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ int FuzzScore(Building building)
[Authorize(Roles = "Admin")]
public async Task<ActionResult> Post(Building building)
{
if (building is DinningCourt dinningCourt)
{
// Handle DinningCourt-specific initialization if necessary
}

// Prepare the Geocoding API request
string url = $"https://maps.googleapis.com/maps/api/geocode/json?address={building.Address}&key={_googleApiKey}";

Expand Down Expand Up @@ -254,35 +259,138 @@ private class BuildingOutline
public List<Coordinate> Coordinates { get; set; } = new List<Coordinate>();
}

[HttpGet("filterByType")]
public async Task<IEnumerable<Building>> GetByType(
/// <summary>
/// Filters buildings by type and specific criteria, including room-level attributes for Housing.
/// </summary>
/// <param name="type">The type of building (e.g., Housing, DinningCourt).</param>
/// <param name="criteria">A JSON object containing filtering criteria.</param>
/// <returns>A filtered list of buildings.</returns>
[HttpGet("filter")]
public async Task<ActionResult<IEnumerable<Building>>> Filter(
[FromQuery] string type,
[FromQuery] string? query = null)
[FromQuery] string? criteria)
{
// Ensure type is valid
if (type != nameof(DinningCourt) && type != nameof(Housing))
if (string.IsNullOrEmpty(type))
{
return null;
return BadRequest("Building type is required.");
}

// MongoDB filter for BuildingType
var filter = Builders<Building>.Filter.Eq("buildingType", type);
// Parse criteria JSON into a dictionary
Dictionary<string, object>? filters = null;
if (!string.IsNullOrEmpty(criteria))
{
try
{
filters = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(criteria);
}
catch
{
return BadRequest("Invalid criteria format.");
}
}

// Fetch buildings of the given type
var buildings = await _buildings.Find(filter).ToListAsync();
// Base filter for building type
var typeFilter = Builders<Building>.Filter.Eq("buildingType", type);
var filter = typeFilter;

if (!string.IsNullOrEmpty(query))
// Add additional filters based on criteria
if (filters != null)
{
int FuzzScore(Building building)
foreach (var filterKey in filters.Keys)
{
return building.Name == null ? 0 : Fuzz.Ratio(query, building.Name);
switch (filterKey.ToLower())
{
// Filters specific to Housing
case "pianonum":
if (type == nameof(Housing))
filter &= Builders<Building>.Filter.Gte("pianoNum", Convert.ToInt32(filters[filterKey]));
break;

case "kitchennum":
if (type == nameof(Housing))
filter &= Builders<Building>.Filter.Gte("kitchenNum", Convert.ToInt32(filters[filterKey]));
break;

case "havedinningcourt":
if (type == nameof(Housing))
filter &= Builders<Building>.Filter.Eq("haveDinningCourt", Convert.ToBoolean(filters[filterKey]));
break;

case "haveboilermarket":
if (type == nameof(Housing))
filter &= Builders<Building>.Filter.Eq("haveBoilerMarket", Convert.ToBoolean(filters[filterKey]));
break;

case "studyspacenum":
if (type == nameof(Housing))
filter &= Builders<Building>.Filter.Gte("studySpaceNum", Convert.ToInt32(filters[filterKey]));
break;

// Room-specific filters for Housing
// case "roomcapacity":
// if (type == nameof(Housing))
// filter &= Builders<Building>.Filter.ElemMatch<Housing>(h => h.Rooms, r => r.Capacity >= Convert.ToInt32(filters[filterKey]));
// break;

// case "roomcost":
// if (type == nameof(Housing))
// filter &= Builders<Building>.Filter.ElemMatch<Housing>(h => h.Rooms, r => r.Cost <= Convert.ToDecimal(filters[filterKey]));
// break;

// case "roomfeatures":
// if (type == nameof(Housing))
// filter &= Builders<Building>.Filter.ElemMatch<Housing>(h => h.Rooms, r => r.Features.Contains(filters[filterKey]?.ToString() ?? ""));
// break;

// case "roomhousingrate":
// if (type == nameof(Housing))
// filter &= Builders<Building>.Filter.ElemMatch<Housing>(h => h.Rooms, r => r.HousingRate >= Convert.ToDouble(filters[filterKey]));
// break;

// case "roomissharedbathroom":
// if (type == nameof(Housing))
// filter &= Builders<Building>.Filter.ElemMatch<Housing>(h => h.Rooms, r => r.IsSharedBathroom == Convert.ToBoolean(filters[filterKey]));
// break;

// Filters specific to DinningCourt
case "acceptsswipes":
if (type == nameof(DinningCourt))
filter &= Builders<Building>.Filter.Eq("acceptsSwipes", Convert.ToBoolean(filters[filterKey]));
break;

case "acceptsdiningdollars":
if (type == nameof(DinningCourt))
filter &= Builders<Building>.Filter.Eq("acceptsDiningDollars", Convert.ToBoolean(filters[filterKey]));
break;

case "acceptsboilerexpress":
if (type == nameof(DinningCourt))
filter &= Builders<Building>.Filter.Eq("acceptsBoilerExpress", Convert.ToBoolean(filters[filterKey]));
break;

case "stabiloptions":
if (type == nameof(DinningCourt))
filter &= Builders<Building>.Filter.AnyEq("stableOptions", filters[filterKey]?.ToString());
break;

case "busyhours":
if (type == nameof(DinningCourt))
filter &= Builders<Building>.Filter.AnyEq("busyHours", filters[filterKey]?.ToString());
break;

default:
// Ignore unknown filters
break;
}
}

buildings.Sort((b1, b2) => FuzzScore(b2).CompareTo(FuzzScore(b1)));
}

return buildings;
// Query the database
var buildings = await _buildings.Find(filter).ToListAsync();

return Ok(buildings);
}

}

}
19 changes: 10 additions & 9 deletions Entities/DinningCourt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,29 @@ namespace SimpleWebAppReact.Entities;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
/// <summary>
/// Class structure matches 1-1 with Building Table in database
/// Class structure matches 1-1 with the Building table in the database
/// </summary>
public class DinningCourt : Building
{
// food options always available at the court (ex/ salad bar, la fonda, deli bar)
// Food options always available at the court (e.g., salad bar, la fonda, deli bar)
[BsonElement("stableOptions"), BsonRepresentation(BsonType.Array)]
public Array? StableOptions { get; set; }
public List<string> StableOptions { get; set; }

Check warning on line 11 in Entities/DinningCourt.cs

View workflow job for this annotation

GitHub Actions / test

Non-nullable property 'StableOptions' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.


// whether or not swipes are accepted
// Whether or not meal swipes are accepted
[BsonElement("acceptsSwipes"), BsonRepresentation(BsonType.Boolean)]
public bool? AcceptsSwipes { get; set; }

// an array of hours when the location is busiest (strings?)
// An array of hours when the location is busiest
[BsonElement("busyHours"), BsonRepresentation(BsonType.Array)]
public bool? BusyHours { get; set; }
public List<string> BusyHours { get; set; } = new();

// whether or not dining dollars are accepted
// Whether or not dining dollars are accepted
[BsonElement("acceptsDiningDollars"), BsonRepresentation(BsonType.Boolean)]
public bool? AcceptsDiningDollars { get; set; }

// whether or not boilerExpress is accepted
// Whether or not BoilerExpress is accepted
[BsonElement("acceptsBoilerExpress"), BsonRepresentation(BsonType.Boolean)]
public bool? AcceptsBoilerExpress { get; set; }

}
}
13 changes: 9 additions & 4 deletions Entities/Housing.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
namespace SimpleWebAppReact.Entities;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System.Collections.Generic;

/// <summary>
/// Represents a housing building with specific attributes.
/// </summary>
public class Housing : Building
{
//Store a list of room objects, each object store attributes such as cost, capacity, features, etc.
// List of room objects, each storing attributes such as cost, capacity, and features
[BsonElement("rooms")]
public List<Room> Rooms { get; set; } = new List<Room>();

[BsonElement("pianoNum"), BsonRepresentation(BsonType.Int32)]
public int PianoNum { get; set; }

[BsonElement("kitchenNum"), BsonRepresentation(BsonType.Int32)]
public int KitchenNum { get; set; }
public int KitchenNum { get; set; }

[BsonElement("haveDinningCourt"), BsonRepresentation(BsonType.Boolean)]
public bool HaveDinningCourt { get; set; }
Expand All @@ -21,5 +26,5 @@ public class Housing : Building

[BsonElement("studySpaceNum"), BsonRepresentation(BsonType.Int32)]
public int StudySpaceNum { get; set; }

}
}
10 changes: 8 additions & 2 deletions Entities/Room.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@
using MongoDB.Bson.Serialization.Attributes;
public class Room
{
public string? Type { get; set; }
public int Capacity { get; set; }
[BsonElement("capacity"), BsonRepresentation(BsonType.Int32)]
public int Capacity { get; set; }

[BsonElement("features")]
public List<string> Features { get; set; } = new List<string>();

[BsonElement("cost"), BsonRepresentation(BsonType.Decimal128)]
public decimal Cost { get; set; }

public double HousingRate {get; set; }

Expand Down

0 comments on commit edfb15c

Please sign in to comment.