Merge pull request #1 from StevanFreeborn/production

Production
This commit is contained in:
StevanFreeborn
2022-06-19 16:44:42 -05:00
committed by GitHub
19 changed files with 371 additions and 85 deletions
+1 -30
View File
@@ -5,39 +5,10 @@
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title> <title>React App</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body> </body>
</html> </html>
+8 -1
View File
@@ -51,7 +51,14 @@ export default class App extends Component {
} }
async populateWeatherData() { async populateWeatherData() {
const response = await fetch('https://criminalminds-server.azurewebsites.net/weatherforecast');
const url = '/api/seasons';
if (process.env.NODE_ENV == 'production') {
url = 'https://criminalminds-server.azurewebsites.net' + url;
}
const response = await fetch(url);
const data = await response.json(); const data = await response.json();
this.setState({ forecasts: data, loading: false }); this.setState({ forecasts: data, loading: false });
} }
+1 -1
View File
@@ -1,7 +1,7 @@
const { createProxyMiddleware } = require('http-proxy-middleware'); const { createProxyMiddleware } = require('http-proxy-middleware');
const context = [ const context = [
"/weatherforecast", '/api/seasons'
]; ];
module.exports = function (app) { module.exports = function (app) {
+57
View File
@@ -0,0 +1,57 @@
using Microsoft.AspNetCore.Mvc;
using server.Models;
using server.Persistence.Repositories;
namespace server.Controllers
{
[ApiController]
[Route("api/seasons")]
[Produces("application/json")]
public class SeasonsController : ControllerBase
{
private readonly ISeasonRepository _seasonRepository;
public SeasonsController(ISeasonRepository seasonRepository)
{
_seasonRepository = seasonRepository;
}
[HttpGet]
[ProducesResponseType(typeof(List<Season>), 200)]
[ProducesResponseType(500)]
public async Task<ActionResult<List<Season>>> GetSeasonsAsync()
{
try
{
var seasons = await _seasonRepository.GetSeasonsAsync();
return Ok(seasons);
}
catch (Exception e)
{
Console.WriteLine(e);
return StatusCode(StatusCodes.Status500InternalServerError, "Failed to get seasons");
}
}
[HttpGet("{number:int}")]
[ProducesResponseType(typeof(Season), 200)]
[ProducesResponseType(typeof(ErrorResponse), 404)]
[ProducesResponseType(500)]
public async Task<ActionResult<Season>> GetSeasonByNumberAsync(int number)
{
try
{
var season = await _seasonRepository.GetSeasonByNumberAsync(number);
if (season == null) return NotFound(new ErrorResponse($"Could not find season number {number}"));
return Ok(season);
}
catch (Exception e)
{
Console.WriteLine(e);
return StatusCode(StatusCodes.Status500InternalServerError, "Failed to get season");
}
}
}
}
@@ -1,33 +0,0 @@
using Microsoft.AspNetCore.Mvc;
namespace server.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}
+36
View File
@@ -0,0 +1,36 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace server.Models
{
public class Character
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string? Id { get; set; }
[BsonElement("firstName")]
public string? FirstName { get; set; }
[BsonElement("lastName")]
public string? LastName { get; set; }
[BsonElement("actorFirstName")]
public string? ActorFirstName { get; set; }
[BsonElement("actorLastName")]
public string? ActorLastName { get; set; }
[BsonElement("seasons")]
public int[]? Seasons { get; set; }
[BsonElement("firstEpisode")]
public string? FirstEpisode { get; set; }
[BsonElement("lastEpisode")]
public string? LastEpisode { get; set; }
[BsonElement("image")]
public string? Image { get; set; }
}
}
+40
View File
@@ -0,0 +1,40 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace server.Models
{
public class Episode
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string? Id { get; set; }
[BsonElement("season")]
public int? Season { get; set; }
[BsonElement("numberInSeries")]
public int? NumberInSeries { get; set; }
[BsonElement("numberInSeason")]
public int? NumberInSeason { get; set; }
[BsonElement("title")]
public string? Title { get; set; }
[BsonElement("summary")]
public string? Summary { get; set; }
[BsonElement("directedBy")]
public string? DirectedBy { get; set; }
[BsonElement("writtenBy")]
public string[]? WrittenBy { get; set; }
[BsonElement("airDate")]
public DateTime? AirDate { get; set; }
[BsonElement("usViewersInMillions")]
public double? UsViewersInMillions { get; set; }
}
}
+12
View File
@@ -0,0 +1,12 @@
namespace server.Models
{
public class ErrorResponse
{
public string Error { get; set; }
public ErrorResponse(string error)
{
Error = error;
}
}
}
+27
View File
@@ -0,0 +1,27 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace server.Models
{
public class Quote
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string? Id { get; set; }
[BsonElement("season")]
public int? Season { get; set; }
[BsonElement("episode")]
public int Episode { get; set; }
[BsonElement("text")]
public string? Text { get; set; }
[BsonElement("source")]
public string? Source { get; set; }
[BsonElement("narrator")]
public string? Narrator { get; set; }
}
}
+24
View File
@@ -0,0 +1,24 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace server.Models
{
public class Season
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string? Id { get; set; }
[BsonElement("seasonNumber")]
public int? SeasonNumber { get; set; }
[BsonElement("numberOfEpisodes")]
public int? NumberOfEpisodes { get; set; }
[BsonElement("dateFirstAired")]
public DateTime? DateFirstAired { get; set; }
[BsonElement("dateLastAired")]
public DateTime? DateLastAired { get; set; }
}
}
+18
View File
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace server.Persistence
{
public class DatabaseSettings : IDatabaseSettings
{
public string? ConnectionString { get; set; }
public string? DatabaseName { get; set; }
public string? SeasonsCollection { get; set; }
public string? EpisodesCollection { get; set; }
public string? CharactersCollection { get; set; }
public string? QuotesCollection { get; set; }
}
}
+36
View File
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.OpenApi.Writers;
using MongoDB.Driver;
using server.Models;
namespace server.Persistence
{
public class DbContext : IDbContext
{
public IMongoCollection<Season> Seasons { get; set; }
public IMongoCollection<Episode> Episodes { get; set; }
public IMongoCollection<Character> Characters { get; set; }
public IMongoCollection<Quote> Quotes { get; set; }
public DbContext(IDatabaseSettings settings)
{
IMongoClient client = new MongoClient(settings.ConnectionString);
IMongoDatabase database = client.GetDatabase(settings.DatabaseName);
Seasons = database.GetCollection<Season>(settings.SeasonsCollection);
Episodes = database.GetCollection<Episode>(settings.EpisodesCollection);
Characters = database.GetCollection<Character>(settings.CharactersCollection);
Quotes = database.GetCollection<Quote>(settings.QuotesCollection);
}
}
}
+18
View File
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace server.Persistence
{
public interface IDatabaseSettings
{
string? ConnectionString { get; set; }
string? DatabaseName { get; set; }
string? SeasonsCollection { get; set; }
string? EpisodesCollection { get; set; }
string? CharactersCollection { get; set; }
string? QuotesCollection { get; set; }
}
}
+21
View File
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MongoDB.Driver;
using server.Models;
namespace server.Persistence
{
public interface IDbContext
{
public IMongoCollection<Season> Seasons { get; set; }
public IMongoCollection<Episode> Episodes { get; set; }
public IMongoCollection<Character> Characters { get; set; }
public IMongoCollection<Quote> Quotes { get; set; }
}
}
@@ -0,0 +1,10 @@
using server.Models;
namespace server.Persistence.Repositories
{
public interface ISeasonRepository
{
Task<List<Season>> GetSeasonsAsync();
Task<Season> GetSeasonByNumberAsync(int number);
}
}
@@ -0,0 +1,41 @@
using MongoDB.Driver;
using server.Models;
namespace server.Persistence.Repositories
{
public class SeasonRepository : ISeasonRepository
{
private readonly IDbContext _context;
public SeasonRepository(IDbContext context)
{
_context = context;
}
public async Task<List<Season>> GetSeasonsAsync()
{
try
{
return await _context.Seasons.Find(season => true).ToListAsync();
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public async Task<Season> GetSeasonByNumberAsync(int number)
{
try
{
return await _context.Seasons.Find(season => season.SeasonNumber == number).SingleOrDefaultAsync();
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
}
+18 -5
View File
@@ -1,5 +1,20 @@
using Microsoft.Extensions.Options;
using MongoDB.Driver;
using server.Persistence;
using server.Persistence.Repositories;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<DatabaseSettings>(
builder.Configuration.GetSection("MongoDBSettings"));
builder.Services.AddSingleton<IDatabaseSettings>(sp =>
sp.GetRequiredService<IOptions<DatabaseSettings>>().Value);
builder.Services.AddSingleton<IDbContext, DbContext>();
builder.Services.AddScoped<ISeasonRepository, SeasonRepository>();
builder.Services.AddControllers(); builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
@@ -7,11 +22,9 @@ builder.Services.AddSwaggerGen();
var app = builder.Build(); var app = builder.Build();
if (app.Environment.IsDevelopment()) app.UseSwagger();
{
app.UseSwagger(); app.UseSwaggerUI();
app.UseSwaggerUI();
}
app.UseHttpsRedirection(); app.UseHttpsRedirection();
-13
View File
@@ -1,13 +0,0 @@
namespace server
{
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}
+3 -2
View File
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
@@ -7,7 +7,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" /> <PackageReference Include="MongoDB.Driver" Version="2.16.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>