Skip to content

Commit

Permalink
Add project files.
Browse files Browse the repository at this point in the history
  • Loading branch information
EdKaim committed Feb 25, 2020
1 parent 0e51edd commit dba9056
Show file tree
Hide file tree
Showing 81 changed files with 32,724 additions and 0 deletions.
25 changes: 25 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
395 changes: 395 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions LICENSE-CODE
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
The MIT License (MIT)
Copyright (c) Microsoft Corporation

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

# Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.microsoft.com.

When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [[email protected]](mailto:[email protected]) with any additional questions or comments.

# Legal Notices

Microsoft and any contributors grant you a license to the Microsoft documentation and other content
in this repository under the [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/legalcode),
see the [LICENSE](LICENSE) file, and grant you a license to any code in the repository under the [MIT License](https://opensource.org/licenses/MIT), see the
[LICENSE-CODE](LICENSE-CODE) file.

Microsoft, Windows, Microsoft Azure and/or other Microsoft products and services referenced in the documentation
may be either trademarks or registered trademarks of Microsoft in the United States and/or other countries.
The licenses for this project do not grant you rights to use any Microsoft names, logos, or trademarks.
Microsoft's general trademark guidelines can be found at http://go.microsoft.com/fwlink/?LinkID=254653.

Privacy information can be found at https://privacy.microsoft.com/en-us/

Microsoft and any contributors reserve all other rights, whether under their respective copyrights, patents,
or trademarks, whether by implication, estoppel or otherwise.
17 changes: 17 additions & 0 deletions Tailspin.SpaceGame.Web.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tailspin.SpaceGame.Web", "Tailspin.SpaceGame.Web\Tailspin.SpaceGame.Web.csproj", "{A0C4E31E-AC75-4F39-9F59-0AA19D9B8F46}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A0C4E31E-AC75-4F39-9F59-0AA19D9B8F46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A0C4E31E-AC75-4F39-9F59-0AA19D9B8F46}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A0C4E31E-AC75-4F39-9F59-0AA19D9B8F46}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A0C4E31E-AC75-4F39-9F59-0AA19D9B8F46}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
139 changes: 139 additions & 0 deletions Tailspin.SpaceGame.Web/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using TailSpin.SpaceGame.Web.Models;

namespace TailSpin.SpaceGame.Web.Controllers
{
public class HomeController : Controller
{
// High score repository.
private readonly IDocumentDBRepository<Score> _scoreRepository;
// User profile repository.
private readonly IDocumentDBRepository<Profile> _profileRespository;

public HomeController(
IDocumentDBRepository<Score> scoreRepository,
IDocumentDBRepository<Profile> profileRespository
)
{
_scoreRepository = scoreRepository;
_profileRespository = profileRespository;
}

public async Task<IActionResult> Index(
int page = 1,
int pageSize = 10,
string mode = "",
string region = ""
)
{
// Create the view model with initial values we already know.
var vm = new LeaderboardViewModel
{
Page = page,
PageSize = pageSize,
SelectedMode = mode,
SelectedRegion = region,

GameModes = new List<string>()
{
"Solo",
"Duo",
"Trio"
},

GameRegions = new List<string>()
{
"Milky Way",
"Andromeda",
"Pinwheel",
"NGC 1300",
"Messier 82",
}
};

try
{
// Form the query predicate.
// This expression selects all scores that match the provided game
// mode and region (map).
// Select the score if the game mode or region is empty.
Expression<Func<Score, bool>> queryPredicate = score =>
(string.IsNullOrEmpty(mode) || score.GameMode == mode) &&
(string.IsNullOrEmpty(region) || score.GameRegion == region);

// Fetch the total number of results in the background.
var countItemsTask = _scoreRepository.CountItemsAsync(queryPredicate);

// Fetch the scores that match the current filter.
IEnumerable<Score> scores = await _scoreRepository.GetItemsAsync(
queryPredicate, // the predicate defined above
score => score.HighScore, // sort descending by high score
page - 1, // subtract 1 to make the query 0-based
pageSize
);

// Wait for the total count.
vm.TotalResults = await countItemsTask;

// Set previous and next hyperlinks.
if (page > 1)
{
vm.PrevLink = $"/?page={page - 1}&pageSize={pageSize}&mode={mode}&region={region}#leaderboard";
}
if (vm.TotalResults > page * pageSize)
{
vm.NextLink = $"/?page={page + 1}&pageSize={pageSize}&mode={mode}&region={region}#leaderboard";
}

// Fetch the user profile for each score.
// This creates a list that's parallel with the scores collection.
var profiles = new List<Task<Profile>>();
foreach (var score in scores)
{
profiles.Add(_profileRespository.GetItemAsync(score.ProfileId));
}
Task<Profile>.WaitAll(profiles.ToArray());

// Combine each score with its profile.
vm.Scores = scores.Zip(profiles, (score, profile) => new ScoreProfile { Score = score, Profile = profile.Result });

return View(vm);
}
catch (Exception)
{
return View(vm);
}
}

[Route("/profile/{id}")]
public async Task<IActionResult> Profile(string id, string rank="")
{
try
{
// Fetch the user profile with the given identifier.
return View(new ProfileViewModel { Profile = await _profileRespository.GetItemAsync(id), Rank = rank });
}
catch (Exception)
{
return RedirectToAction("/");
}
}

public IActionResult Privacy()
{
return View();
}

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
22 changes: 22 additions & 0 deletions Tailspin.SpaceGame.Web/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["Tailspin.SpaceGame.Web/Tailspin.SpaceGame.Web.csproj", "Tailspin.SpaceGame.Web/"]
RUN dotnet restore "Tailspin.SpaceGame.Web/Tailspin.SpaceGame.Web.csproj"
COPY . .
WORKDIR "/src/Tailspin.SpaceGame.Web"
RUN dotnet build "Tailspin.SpaceGame.Web.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "Tailspin.SpaceGame.Web.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Tailspin.SpaceGame.Web.dll"]
50 changes: 50 additions & 0 deletions Tailspin.SpaceGame.Web/IDocumentDBRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
using TailSpin.SpaceGame.Web.Models;

namespace TailSpin.SpaceGame.Web
{
public interface IDocumentDBRepository<T> where T : Model
{
/// <summary>
/// Retrieves the item from the store with the given identifier.
/// </summary>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the retrieved item.
/// </returns>
/// <param name="id">The identifier of the item to retrieve.</param>
Task<T> GetItemAsync(string id);

/// <summary>
/// Retrieves items from the store that match the given query predicate.
/// Results are given in descending order by the given ordering predicate.
/// </summary>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the collection of retrieved items.
/// </returns>
/// <param name="queryPredicate">Predicate that specifies which items to select.</param>
/// <param name="orderDescendingPredicate">Predicate that specifies how to sort the results in descending order.</param>
/// <param name="page">The 1-based page of results to return.</param>
/// <param name="pageSize">The number of items on a page.</param>
Task<IEnumerable<T>> GetItemsAsync(
Expression<Func<T, bool>> queryPredicate,
Expression<Func<T, int>> orderDescendingPredicate,
int page = 1,
int pageSize = 10
);

/// <summary>
/// Retrieves the number of items that match the given query predicate.
/// </summary>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the number of items that match the query predicate.
/// </returns>
/// <param name="queryPredicate">Predicate that specifies which items to select.</param>
Task<int> CountItemsAsync(Expression<Func<T, bool>> queryPredicate);
}
}
81 changes: 81 additions & 0 deletions Tailspin.SpaceGame.Web/LocalDocumentDBRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Newtonsoft.Json;
using TailSpin.SpaceGame.Web.Models;

namespace TailSpin.SpaceGame.Web
{
public class LocalDocumentDBRepository<T> : IDocumentDBRepository<T> where T : Model
{
// An in-memory list of all items in the collection.
private readonly List<T> _items;

public LocalDocumentDBRepository(string fileName)
{
// Serialize the items from the provided JSON document.
_items = JsonConvert.DeserializeObject<List<T>>(File.ReadAllText(fileName));
}

/// <summary>
/// Retrieves the item from the store with the given identifier.
/// </summary>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the retrieved item.
/// </returns>
/// <param name="id">The identifier of the item to retrieve.</param>
public Task<T> GetItemAsync(string id)
{
return Task<T>.FromResult(_items.Single(item => item.Id == id));
}

/// <summary>
/// Retrieves items from the store that match the given query predicate.
/// Results are given in descending order by the given ordering predicate.
/// </summary>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the collection of retrieved items.
/// </returns>
/// <param name="queryPredicate">Predicate that specifies which items to select.</param>
/// <param name="orderDescendingPredicate">Predicate that specifies how to sort the results in descending order.</param>
/// <param name="page">The 1-based page of results to return.</param>
/// <param name="pageSize">The number of items on a page.</param>
public Task<IEnumerable<T>> GetItemsAsync(
Expression<Func<T, bool>> queryPredicate,
Expression<Func<T, int>> orderDescendingPredicate,
int page = 1, int pageSize = 10
)
{
var result = _items.AsQueryable()
.Where(queryPredicate) // filter
.OrderByDescending(orderDescendingPredicate) // sort
.Skip(page * pageSize) // find page
.Take(pageSize) // take items
.AsEnumerable(); // make enumeratable

return Task<IEnumerable<T>>.FromResult(result);
}

/// <summary>
/// Retrieves the number of items that match the given query predicate.
/// </summary>
/// <returns>
/// A task that represents the asynchronous operation.
/// The task result contains the number of items that match the query predicate.
/// </returns>
/// <param name="queryPredicate">Predicate that specifies which items to select.</param>
public Task<int> CountItemsAsync(Expression<Func<T, bool>> queryPredicate)
{
var count = _items.AsQueryable()
.Where(queryPredicate) // filter
.Count(); // count

return Task<int>.FromResult(count);
}
}
}
Loading

0 comments on commit dba9056

Please sign in to comment.