Skip to content

Commit

Permalink
Updates to the interview task
Browse files Browse the repository at this point in the history
Lets make the task better for the candidates
- Added CORS, to save the candidate some time
- Added another endpoint to have an even better starting point where
there are examples for query parameters and some more linq expressions
in the code
  • Loading branch information
Martin Klingenberg committed Oct 18, 2024
1 parent 202ccda commit 7a0e3c6
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 37 deletions.
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Palvkerings-oppgaven

## Hvordan komme i gang
Om man kjører applikasjonen fra host-mappa, så skal løsningen kunne åpnes på http://localhost:5000
``` shell
cd src/Alv.Parkering.Host
dotnet run
```


## Endepunkter

### http://localhost:5000/parkingspot?page=0&pageSize=25
``` json
[
{
"address": "\u00d8vre Langgate 28",
"freeParkingCount": 10,
"paidParkingCount": 0,
"charingSpotCount": 0,
"handicapSpotCount": 0,
"handicapDescription": "Det er vurdert at dette er en for liten og trang plass til å kunne tilrettelegge HC plass ihht kravene om utforming og st\u00f8rrelse. Det er kommunale HC plasser i nærheten (Conradisgt og Klostergaten)."
}
]
```


### http://localhost:5000/parkingspot/all
``` json
[
{
"address": "\u00d8vre Langgate 28",
"freeParkingCount": 10,
"paidParkingCount": 0,
"charingSpotCount": 0,
"handicapSpotCount": 0,
"handicapDescription": "Det er vurdert at dette er en for liten og trang plass til å kunne tilrettelegge HC plass ihht kravene om utforming og st\u00f8rrelse. Det er kommunale HC plasser i nærheten (Conradisgt og Klostergaten)."
}
]
```
4 changes: 3 additions & 1 deletion src/Alv.Parkering.Application/Interfaces/IParkingStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Alv.Parkering.Application.Interfaces;

public interface IParkingStore {
public interface IParkingStore
{
Task<List<ParkingSpot>> FetchParkingSpots(int page, int pageSize);
Task<List<ParkingSpot>> FetchAllParkingSpots();
}
47 changes: 22 additions & 25 deletions src/Alv.Parkering.Host/Alv.Parkering.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,53 +12,50 @@
<SpaProxyLaunchCommand>npm start</SpaProxyLaunchCommand>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="6.0.0-preview.7.21378.6" />
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="6.0.0-preview.7.21378.6"/>
</ItemGroup>

<ItemGroup>
<!-- Don't publish the SPA source files, but do show them in the project files list -->
<Content Remove="$(SpaRoot)**" />
<None Remove="$(SpaRoot)**" />
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
<Content Remove="$(SpaRoot)**"/>
<None Remove="$(SpaRoot)**"/>
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**"/>
</ItemGroup>

<ItemGroup>
<Content Include=".template.config\dotnetcli.host.json" />
<Content Include=".template.config\template.json" />
<Content Include=".template.config\dotnetcli.host.json"/>
<Content Include=".template.config\template.json"/>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Alv.Parkering.Application\Alv.Parkering.Application.csproj" />
<ProjectReference Include="..\Alv.Parkering.Infrastructure\Alv.Parkering.Infrastructure.csproj" />
<ProjectReference Include="..\Alv.Parkering.Domain\Alv.Parkering.Domain.csproj" />
<ProjectReference Include="..\Alv.Parkering.Application\Alv.Parkering.Application.csproj"/>
<ProjectReference Include="..\Alv.Parkering.Infrastructure\Alv.Parkering.Infrastructure.csproj"/>
<ProjectReference Include="..\Alv.Parkering.Domain\Alv.Parkering.Domain.csproj"/>
</ItemGroup>
<ItemGroup>
<None Update="./parkering.sqlite">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
<Output TaskParameter="ExitCode" PropertyName="ErrorCode"/>
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE."/>
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..."/>
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install"/>
</Target>

<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />

<Exec WorkingDirectory="$(SpaRoot)" Command="npm install"/>
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build"/>
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**"/>
<ResolvedFileToPublish Include="@(DistFiles-&gt;'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>

</Project>
2 changes: 0 additions & 2 deletions src/Alv.Parkering.Host/ClientApp/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ function App() {
<h4>Legg til kode her</h4>
</div>
<ul className={styles.tasks}>
<li>TODO: Klingen har laget et API. Kan du vise parkeringsmulighetene? <a href="http://localhost:5000/parkingSpot">Sjekk ut responsen her. </a> Vis om det er handicap-plasser, ladeplasser og om det er gratis eller betalt parkering. PS: Klingen har ikke enabla CORS på API'et ;)
</li>
<li>TODO: Vi vil bare ha parkeringene i nærheten av oss. Kan vi gjøre det slik at API'et tar inn longitude og latitude og gir oss parkeringer innenfor en 5km radius?</li>
<li>TODO: Gjør det mulig å bare hente gratis parkeringer</li>
<li>TODO: Gjør det mulig å bare hente parkeringer med lademuligheter</li>
Expand Down
12 changes: 11 additions & 1 deletion src/Alv.Parkering.Host/Controllers/ParkingSpotController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,19 @@ public ParkingSpotController(ILogger<ParkingSpotController> logger, IParkingStor
}

[HttpGet]
public async Task<IEnumerable<ParkingSpotDto>> Get([FromQuery] int page = 0, [FromQuery] int pageSize = 25)
public async Task<IEnumerable<ParkingSpotDto>> Get(
[FromQuery] int page = 0,
[FromQuery] int pageSize = 25
)
{
var parkingSpots = await parkingStore.FetchParkingSpots(page, pageSize);
return parkingSpots.Select(parkingSpot => parkingSpot.ToParkingSpotDto());
}

[HttpGet("all")]
public async Task<IEnumerable<ParkingSpotDto>> GetAll()
{
var parkingSpots = await parkingStore.FetchAllParkingSpots();
return parkingSpots.Select(parkingSpot => parkingSpot.ToParkingSpotDto());
}
}
13 changes: 13 additions & 0 deletions src/Alv.Parkering.Host/Program.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
using Alv.Parkering.Infrastructure;

var builder = WebApplication.CreateBuilder(args);
var AllowedOrigins = "_allowedOrigins";

// Add services to the container.

builder.Services.AddControllers();
builder.Services.AddInfrastructure();

builder.Services.AddCors(options =>
{
options.AddPolicy(
name: AllowedOrigins,
policy =>
{
policy.WithOrigins("*", "*");
}
);
});

var app = builder.Build();

app.UseCors(AllowedOrigins);
app.MapControllers();

app.Run();
Binary file added src/Alv.Parkering.Host/parkering.sqlite
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,43 @@ public ParkingSpotRepository(ParkeringContext context)
this.context = context;
}

public Task<List<ParkingSpot>> FetchAllParkingSpots()
{
return context
.Parkeringers.Join(
context.Detailjers,
parkering => parkering.Id,
detalj => detalj.Id,
(parkering, detalj) =>
new ParkingSpot(
parkering.Adresse ?? "",
detalj.AntallAvgiftsbelagtePlasser ?? 0,
detalj.AntallLadeplasser ?? 0,
detalj.AntallLadeplasser ?? 0,
detalj.AntallForflytningshemmede ?? 0,
detalj.VurderingForflytningshemmede ?? ""
)
)
.ToListAsync();
}

public Task<List<ParkingSpot>> FetchParkingSpots(int page, int pageSize)
{
return context.Parkeringers
.Join(context.Detailjers, parkering => parkering.Id, detalj => detalj.Id, (parkering, detalj) => new ParkingSpot(
parkering.Adresse ?? "",
detalj.AntallAvgiftsbelagtePlasser ?? 0,
detalj.AntallLadeplasser?? 0,
detalj.AntallLadeplasser ?? 0,
detalj.AntallForflytningshemmede ?? 0,
detalj.VurderingForflytningshemmede ?? ""))
return context
.Parkeringers.Join(
context.Detailjers,
parkering => parkering.Id,
detalj => detalj.Id,
(parkering, detalj) =>
new ParkingSpot(
parkering.Adresse ?? "",
detalj.AntallAvgiftsbelagtePlasser ?? 0,
detalj.AntallLadeplasser ?? 0,
detalj.AntallLadeplasser ?? 0,
detalj.AntallForflytningshemmede ?? 0,
detalj.VurderingForflytningshemmede ?? ""
)
)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
Expand Down

0 comments on commit 7a0e3c6

Please sign in to comment.