Commit 841acce8 authored by Andres Käver's avatar Andres Käver

OwnerAnimal index, service, rest backend, repo

parent 16167618
......@@ -3,15 +3,21 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Contracts.DAL.Base.Repositories;
using Domain;
using PublicApi.DTO.v1;
namespace Contracts.DAL.App.Repositories
{
public interface IOwnerAnimalRepository: IBaseRepository<OwnerAnimal>
public interface IOwnerAnimalRepository : IBaseRepository<OwnerAnimal>
{
Task<IEnumerable<OwnerAnimal>> AllAsync(Guid? userId = null);
Task<OwnerAnimal> FirstOrDefaultAsync(Guid id, Guid? userId = null);
Task<bool> ExistsAsync(Guid id, Guid? userId = null);
Task DeleteAsync(Guid id, Guid? userId = null);
// DTO methods
Task<IEnumerable<OwnerAnimalDTO>> DTOAllAsync(Guid? userId = null);
Task<OwnerAnimalDTO> DTOFirstOrDefaultAsync(Guid id, Guid? userId = null);
}
}
\ No newline at end of file
......@@ -6,6 +6,7 @@ using Contracts.DAL.App.Repositories;
using DAL.Base.EF.Repositories;
using Domain;
using Microsoft.EntityFrameworkCore;
using PublicApi.DTO.v1;
namespace DAL.App.EF.Repositories
{
......@@ -62,5 +63,46 @@ namespace DAL.App.EF.Repositories
var owner = await FirstOrDefaultAsync(id, userId);
base.Remove(owner);
}
public async Task<IEnumerable<OwnerAnimalDTO>> DTOAllAsync(Guid? userId = null)
{
var query = RepoDbSet
.Include(o => o.Owner)
.Include(o => o.Animal)
.AsQueryable();
if (userId != null)
{
query = query.Where(o => o.Animal!.AppUserId == userId && o.Owner!.AppUserId == userId);
}
return await query
.Select(o => new OwnerAnimalDTO()
{
Id = o.Id,
AnimalId = o.AnimalId,
OwnerId = o.OwnerId,
OwnedPercentage = o.OwnedPercentage,
Animal = new AnimalDTO()
{
Id = o.Animal!.Id,
AnimalName = o.Animal!.AnimalName,
BirthYear = o.Animal!.BirthYear,
OwnerCount = o.Animal!.Owners!.Count,
},
Owner = new OwnerDTO()
{
Id = o.Owner!.Id,
FirstName = o.Owner!.FirstName,
LastName = o.Owner!.LastName,
AnimalCount = o.Owner!.Animals!.Count
}
})
.ToListAsync();
}
public Task<OwnerAnimalDTO> DTOFirstOrDefaultAsync(Guid id, Guid? userId = null)
{
throw new NotImplementedException();
}
}
}
\ No newline at end of file
......@@ -7,7 +7,10 @@ namespace PublicApi.DTO.v1
public Guid Id { get; set; }
public Guid OwnerId { get; set; }
public OwnerDTO Owner { get; set; } = default!;
public Guid AnimalId { get; set; }
public AnimalDTO Animal { get; set; } = default!;
public int OwnedPercentage { get; set; }
}
......
......@@ -2,13 +2,16 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Contracts.DAL.App;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using DAL.App.EF;
using Domain;
using Extensions;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using PublicApi.DTO.v1;
namespace WebApp.ApiControllers
{
......@@ -18,17 +21,19 @@ namespace WebApp.ApiControllers
public class OwnerAnimalsController : ControllerBase
{
private readonly AppDbContext _context;
private readonly IAppUnitOfWork _uow;
public OwnerAnimalsController(AppDbContext context)
public OwnerAnimalsController(AppDbContext context, IAppUnitOfWork uow)
{
_context = context;
_uow = uow;
}
// GET: api/OwnerAnimals
[HttpGet]
public async Task<ActionResult<IEnumerable<OwnerAnimal>>> GetOwnerAnimals()
public async Task<ActionResult<IEnumerable<OwnerAnimalDTO>>> GetOwnerAnimals()
{
return await _context.OwnerAnimals.ToListAsync();
return Ok(await _uow.OwnerAnimals.DTOAllAsync(User.UserGuidId()));
}
// GET: api/OwnerAnimals/5
......
......@@ -36,6 +36,10 @@ export class App {
{ route: ['owneranimals', 'owneranimals/index'], name: 'owneranimals-index', moduleId: PLATFORM.moduleName('views/owneranimals/index'), nav: true, title: 'OwnerAnimals' },
{ route: ['owneranimals/details/:id?'], name: 'owneranimals-details', moduleId: PLATFORM.moduleName('views/owneranimals/details'), nav: false, title: 'OwnerAnimals Details' },
{ route: ['owneranimals/edit/:id?'], name: 'owneranimals-edit', moduleId: PLATFORM.moduleName('views/owneranimals/edit'), nav: false, title: 'OwnerAnimals Edit' },
{ route: ['owneranimals/delete/:id?'], name: 'owneranimals-delete', moduleId: PLATFORM.moduleName('views/owneranimals/delete'), nav: false, title: 'OwnerAnimals Delete' },
{ route: ['owneranimals/create'], name: 'owneranimals-create', moduleId: PLATFORM.moduleName('views/owneranimals/create'), nav: false, title: 'OwnerAnimals Create' },
]
);
......
import { IAnimal } from "./IAnimal";
import { IOwner } from "./IOwner";
export interface IOwnerAnimal {
id: string;
animalId: string;
animal: IAnimal;
ownerId: string;
owner: IOwner;
}
import { autoinject } from 'aurelia-framework';
import { HttpClient } from 'aurelia-fetch-client';
import { AppState } from 'state/app-state';
import { IFetchResponse } from 'types/IFetchResponse';
import { IAnimal } from 'domain/IAnimal';
import { IAnimalCreate } from 'domain/IAnimalCreate';
import { IAnimalEdit } from 'domain/IAnimalEdit';
import { IOwnerAnimal } from 'domain/IOwnerAnimal';
@autoinject
export class OwnerAnimalService {
constructor(private appState: AppState, private httpClient: HttpClient) {
this.httpClient.baseUrl = this.appState.baseUrl;
}
private readonly _baseUrl = 'owneranimals';
async getOwnerAnimals(): Promise<IFetchResponse<IOwnerAnimal[]>> {
try {
const response = await this.httpClient
.fetch(this._baseUrl, {
cache: "no-store",
headers: {
authorization: "Bearer " + this.appState.jwt
}
});
// happy case
if (response.status >= 200 && response.status < 300) {
const data = (await response.json()) as IOwnerAnimal[];
console.log(data);
return {
statusCode: response.status,
data: data
}
}
// something went wrong
return {
statusCode: response.status,
errorMessage: response.statusText
}
} catch (reason) {
return {
statusCode: 0,
errorMessage: JSON.stringify(reason)
}
}
}
async getOwnerAnimal(id: string): Promise<IFetchResponse<IOwnerAnimal>> {
try {
const response = await this.httpClient
.fetch(this._baseUrl + '/' + id, {
cache: "no-store",
headers: {
authorization: "Bearer " + this.appState.jwt
}
});
if (response.status >= 200 && response.status < 300) {
const data = (await response.json()) as IOwnerAnimal;
return {
statusCode: response.status,
data: data
}
}
return {
statusCode: response.status,
errorMessage: response.statusText
}
} catch (reason) {
return {
statusCode: 0,
errorMessage: JSON.stringify(reason)
}
}
}
async createAnimal(animal: IAnimalCreate): Promise<IFetchResponse<string>> {
try {
const response = await this.httpClient
.post(this._baseUrl, JSON.stringify(animal), {
cache: 'no-store',
headers: {
authorization: "Bearer " + this.appState.jwt
}
})
if (response.status >= 200 && response.status < 300) {
console.log('response', response);
return {
statusCode: response.status
// no data
}
}
return {
statusCode: response.status,
errorMessage: response.statusText
}
}
catch (reason) {
return {
statusCode: 0,
errorMessage: JSON.stringify(reason)
}
}
}
async updateAnimal(animal: IAnimalEdit): Promise<IFetchResponse<string>> {
try {
const response = await this.httpClient
.put(this._baseUrl + '/' + animal.id, JSON.stringify(animal), {
cache: 'no-store',
headers: {
authorization: "Bearer " + this.appState.jwt
}
});
if (response.status >= 200 && response.status < 300) {
return {
statusCode: response.status
// no data
}
}
return {
statusCode: response.status,
errorMessage: response.statusText
}
}
catch (reason) {
return {
statusCode: 0,
errorMessage: JSON.stringify(reason)
}
}
}
async deleteAnimal(id: string): Promise<IFetchResponse<string>> {
try {
const response = await this.httpClient
.delete(this._baseUrl + '/' + id, null, {
cache: 'no-store',
headers: {
authorization: "Bearer " + this.appState.jwt
}
});
if (response.status >= 200 && response.status < 300) {
return {
statusCode: response.status
// no data
}
}
return {
statusCode: response.status,
errorMessage: response.statusText
}
}
catch (reason) {
return {
statusCode: 0,
errorMessage: JSON.stringify(reason)
}
}
}
}
......@@ -3,7 +3,7 @@
<alert alert-data.bind="_alert"></alert>
<h1>Index</h1>
<h1>Index Animals</h1>
<p>
<a route-href="route: animals-create; params.bind: {}">Create New</a>
</p>
......
......@@ -6,9 +6,8 @@ import { AnimalService } from 'service/animal-service';
@autoinject
export class AnimalsIndex {
private _animals: IAnimal[] = [];
private _alert: IAlertData | null = null;
private _animals: IAnimal[] = [];
constructor(private animalService: AnimalService) {
......
<template>
<require from="../../components/alert"></require>
<alert alert-data.bind="_alert"></alert>
</template>
import { autoinject } from 'aurelia-framework';
import { RouteConfig, NavigationInstruction, Router } from 'aurelia-router';
import { IAlertData } from 'types/IAlertData';
import { AlertType } from 'types/AlertType';
@autoinject
export class OwnerAnimalsCreate {
private _alert: IAlertData | null = null;
constructor( private router: Router) {
}
attached() {
}
activate(params: any, routeConfig: RouteConfig, navigationInstruction: NavigationInstruction) {
}
}
<template>
<require from="../../components/alert"></require>
<alert alert-data.bind="_alert"></alert>
</template>
import { autoinject } from 'aurelia-framework';
import { RouteConfig, NavigationInstruction, Router } from 'aurelia-router';
import { IAlertData } from 'types/IAlertData';
import { AlertType } from 'types/AlertType';
@autoinject
export class OwnerAnimalsDelete {
private _alert: IAlertData | null = null;
constructor( private router: Router) {
}
attached() {
}
activate(params: any, routeConfig: RouteConfig, navigationInstruction: NavigationInstruction) {
}
}
<template>
<require from="../../components/alert"></require>
<alert alert-data.bind="_alert"></alert>
</template>
import { autoinject } from 'aurelia-framework';
import { RouteConfig, NavigationInstruction, Router } from 'aurelia-router';
import { IAlertData } from 'types/IAlertData';
import { AlertType } from 'types/AlertType';
@autoinject
export class OwnerAnimalsDetails {
private _alert: IAlertData | null = null;
constructor( private router: Router) {
}
attached() {
}
activate(params: any, routeConfig: RouteConfig, navigationInstruction: NavigationInstruction) {
}
}
<template>
<require from="../../components/alert"></require>
<alert alert-data.bind="_alert"></alert>
</template>
import { autoinject } from 'aurelia-framework';
import { RouteConfig, NavigationInstruction, Router } from 'aurelia-router';
import { IAlertData } from 'types/IAlertData';
import { AlertType } from 'types/AlertType';
@autoinject
export class OwnerAnimalsEdit {
private _alert: IAlertData | null = null;
constructor( private router: Router) {
}
attached() {
}
activate(params: any, routeConfig: RouteConfig, navigationInstruction: NavigationInstruction) {
}
}
<template>
OwnerAnimals index
<require from="../../components/alert"></require>
<alert alert-data.bind="_alert"></alert>
<h1>Index OwnerAnimals</h1>
<p>
<a route-href="route: owneranimals-create; params.bind: {}">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
Owner
</th>
<th>
Animal
</th>
<th>
OwnedPercentage
</th>
<th></th>
</tr>
</thead>
<tbody>
<tr repeat.for="ownerAnimal of _ownerAnimals">
<td>
${ownerAnimal.owner.firstName + ' ' + ownerAnimal.owner.lastName}
</td>
<td>
${ownerAnimal.animal.animalName}
</td>
<td>
${ownerAnimal.ownedPercentage}
</td>
<td>
<a route-href="route: owneranimals-edit; params.bind: { id: ownerAnimal.id }">Edit</a> |
<a route-href="route: owneranimals-details; params.bind: { id: ownerAnimal.id }">Details</a> |
<a route-href="route: owneranimals-delete; params.bind: { id: ownerAnimal.id }">Delete</a>
</td>
</tr>
</tbody>
</table>
</template>
import { OwnerAnimalService } from './../../service/owner-animal-service';
import { autoinject } from 'aurelia-framework';
import { RouteConfig, NavigationInstruction, Router } from 'aurelia-router';
import { IAlertData } from 'types/IAlertData';
import { AlertType } from 'types/AlertType';
import { IOwnerAnimal } from 'domain/IOwnerAnimal';
@autoinject
export class OwnerAnimalsIndex {
private _alert: IAlertData | null = null;
private _ownerAnimals: IOwnerAnimal[] = [];
constructor(private ownerAnimalService:OwnerAnimalService, private router: Router) {
}
attached() {
this.ownerAnimalService.getOwnerAnimals().then(
response => {
if (response.statusCode >= 200 && response.statusCode < 300) {
this._alert = null;
this._ownerAnimals = response.data!;
} else {
// show error message
this._alert = {
message: response.statusCode.toString() + ' - ' + response.errorMessage,
type: AlertType.Danger,
dismissable: true,
}
}
}
);
}
activate(params: any, routeConfig: RouteConfig, navigationInstruction: NavigationInstruction) {
}
}
......@@ -3,7 +3,7 @@
<alert alert-data.bind="_alert"></alert>
<h1>Index</h1>
<h1>Index Owners</h1>
<p>
<a route-href="route: owners-create; params.bind: {}">Create New</a>
</p>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment