mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-11 07:46:05 -07:00
Merge branch 'DotNetCore' of https://github.com/tidusjar/Ombi into DotNetCore
This commit is contained in:
commit
4c95b1f70b
20 changed files with 478 additions and 94 deletions
|
@ -11,5 +11,9 @@ namespace Ombi.Core.Engine
|
|||
Task<RequestEngineResult> RequestMovie(SearchMovieViewModel model);
|
||||
bool ShouldAutoApprove(RequestType requestType);
|
||||
Task<IEnumerable<RequestViewModel>> GetRequests();
|
||||
Task<IEnumerable<RequestViewModel>> GetRequests(int count, int position);
|
||||
Task<IEnumerable<RequestViewModel>> SearchRequest(string search);
|
||||
Task RemoveRequest(int requestId);
|
||||
Task<RequestViewModel> UpdateRequest(RequestViewModel request);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models.Requests;
|
||||
|
@ -7,6 +8,7 @@ using Ombi.Core.Models.Search;
|
|||
using Ombi.Core.Requests.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.TheMovieDbApi;
|
||||
using Ombi.Helpers;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
{
|
||||
|
@ -233,7 +235,41 @@ namespace Ombi.Core.Engine
|
|||
public async Task<IEnumerable<RequestViewModel>> GetRequests()
|
||||
{
|
||||
var allRequests = await RequestService.GetAllAsync();
|
||||
var viewModel = allRequests.Select(movie => new RequestViewModel
|
||||
var viewModel = MapToVm(allRequests);
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RequestViewModel>> GetRequests(int count, int position)
|
||||
{
|
||||
var allRequests = await RequestService.GetAllAsync(count, position);
|
||||
var viewModel = MapToVm(allRequests);
|
||||
return viewModel;
|
||||
}
|
||||
public async Task<IEnumerable<RequestViewModel>> SearchRequest(string search)
|
||||
{
|
||||
var allRequests = await RequestService.GetAllAsync();
|
||||
var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase));
|
||||
var viewModel = MapToVm(results);
|
||||
return viewModel;
|
||||
}
|
||||
public async Task<RequestViewModel> UpdateRequest(RequestViewModel request)
|
||||
{
|
||||
var allRequests = await RequestService.GetAllAsync();
|
||||
var results = allRequests.FirstOrDefault(x => x.Id == request.Id);
|
||||
|
||||
var model = RequestService.UpdateRequest(results);
|
||||
return MapToVm(new List<RequestModel>{model}).FirstOrDefault();
|
||||
}
|
||||
|
||||
public async Task RemoveRequest(int requestId)
|
||||
{
|
||||
await RequestService.DeleteRequestAsync(requestId);
|
||||
}
|
||||
|
||||
|
||||
private IEnumerable<RequestViewModel> MapToVm(IEnumerable<RequestModel> model)
|
||||
{
|
||||
return model.Select(movie => new RequestViewModel
|
||||
{
|
||||
ProviderId = movie.ProviderId,
|
||||
Type = movie.Type,
|
||||
|
@ -259,8 +295,6 @@ namespace Ombi.Core.Engine
|
|||
//RootFolders = rootFolders.ToArray(),
|
||||
//CurrentRootPath = radarr.Enabled ? GetRootPath(movie.RootFolderSelected, radarr).Result : null
|
||||
}).ToList();
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -16,11 +16,13 @@ namespace Ombi.Core.Requests.Models
|
|||
Task<RequestModel> CheckRequestAsync(int providerId);
|
||||
Task<RequestModel> CheckRequestAsync(string musicId);
|
||||
void DeleteRequest(RequestModel request);
|
||||
Task DeleteRequestAsync(int request);
|
||||
Task DeleteRequestAsync(RequestModel request);
|
||||
RequestModel Get(int id);
|
||||
IEnumerable<RequestModel> GetAll();
|
||||
Task<IEnumerable<RequestModel>> GetAllAsync();
|
||||
Task<IEnumerable<RequestModel>> GetAllAsync(int count, int position);
|
||||
Task<RequestModel> GetAsync(int id);
|
||||
RequestBlobs UpdateRequest(RequestModel model);
|
||||
RequestModel UpdateRequest(RequestModel model);
|
||||
}
|
||||
}
|
|
@ -92,11 +92,19 @@ namespace Ombi.Core.Models.Requests
|
|||
var blob = await Repo.GetAsync(request.Id).ConfigureAwait(false);
|
||||
Repo.Delete(blob);
|
||||
}
|
||||
|
||||
public RequestBlobs UpdateRequest(RequestModel model)
|
||||
public async Task DeleteRequestAsync(int request)
|
||||
{
|
||||
var entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId, Id = model.Id };
|
||||
return Repo.Update(entity);
|
||||
var blob = await Repo.GetAsync(request).ConfigureAwait(false);
|
||||
Repo.Delete(blob);
|
||||
}
|
||||
|
||||
public RequestModel UpdateRequest(RequestModel model)
|
||||
{
|
||||
var b = Repo.Get(model.Id);
|
||||
b.Content = ByteConverterHelper.ReturnBytes(model);
|
||||
var blob = Repo.Update(b);
|
||||
return model;
|
||||
|
||||
}
|
||||
|
||||
public RequestModel Get(int id)
|
||||
|
@ -159,6 +167,24 @@ namespace Ombi.Core.Models.Requests
|
|||
return retVal;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RequestModel>> GetAllAsync(int count, int position)
|
||||
{
|
||||
var blobs = await Repo.GetAllAsync(count, position).ConfigureAwait(false);
|
||||
var retVal = new List<RequestModel>();
|
||||
|
||||
foreach (var b in blobs)
|
||||
{
|
||||
if (b == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var model = ByteConverterHelper.ReturnObject<RequestModel>(b.Content);
|
||||
model.Id = b.Id;
|
||||
retVal.Add(model);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public void BatchUpdate(IEnumerable<RequestModel> model)
|
||||
{
|
||||
var entities = model.Select(m => new RequestBlobs { Type = m.Type, Content = ByteConverterHelper.ReturnBytes(m), ProviderId = m.ProviderId, Id = m.Id }).ToList();
|
||||
|
|
12
Ombi/Ombi.Helpers/StringHelper.cs
Normal file
12
Ombi/Ombi.Helpers/StringHelper.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System.Globalization;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
{
|
||||
public static class StringHelper
|
||||
{
|
||||
public static bool Contains(this string paragraph, string word, CompareOptions opts)
|
||||
{
|
||||
return CultureInfo.CurrentUICulture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ namespace Ombi.Store.Repository
|
|||
RequestBlobs Get(int id);
|
||||
IEnumerable<RequestBlobs> GetAll();
|
||||
Task<IEnumerable<RequestBlobs>> GetAllAsync();
|
||||
Task<IEnumerable<RequestBlobs>> GetAllAsync(int count, int position);
|
||||
Task<RequestBlobs> GetAsync(int id);
|
||||
RequestBlobs Insert(RequestBlobs entity);
|
||||
Task<RequestBlobs> InsertAsync(RequestBlobs entity);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -61,6 +62,18 @@ namespace Ombi.Store.Repository
|
|||
//}, 5);
|
||||
//return item;
|
||||
}
|
||||
public async Task<IEnumerable<RequestBlobs>> GetAllAsync(int count, int position)
|
||||
{
|
||||
//var key = "GetAll";
|
||||
//var item = await Cache.GetOrSetAsync(key, async () =>
|
||||
//{
|
||||
|
||||
var page = await Db.Requests.ToListAsync().ConfigureAwait(false);
|
||||
return page.Skip(position).Take(count);
|
||||
|
||||
//}, 5);
|
||||
//return item;
|
||||
}
|
||||
|
||||
public RequestBlobs Get(int id)
|
||||
{
|
||||
|
@ -99,9 +112,17 @@ namespace Ombi.Store.Repository
|
|||
|
||||
public RequestBlobs Update(RequestBlobs entity)
|
||||
{
|
||||
try
|
||||
{
|
||||
Db.SaveChanges();
|
||||
|
||||
return Db.Requests.Update(entity).Entity;
|
||||
Db.SaveChanges();
|
||||
return entity;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: BaseApiController.cs
|
||||
// File: BaseV1ApiController.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
@ -29,8 +29,9 @@ using Microsoft.AspNetCore.Mvc;
|
|||
|
||||
namespace Ombi.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
public class BaseApiController : Controller
|
||||
[Route(ApiBase)]
|
||||
public class BaseV1ApiController : Controller
|
||||
{
|
||||
protected const string ApiBase = "api/v1/[controller]";
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ using Ombi.Core.Models.Search;
|
|||
|
||||
namespace Ombi.Controllers
|
||||
{
|
||||
public class RequestController : BaseApiController
|
||||
public class RequestController : BaseV1ApiController
|
||||
{
|
||||
public RequestController(IRequestEngine engine)
|
||||
{
|
||||
|
@ -22,10 +22,34 @@ namespace Ombi.Controllers
|
|||
return await RequestEngine.GetRequests();
|
||||
}
|
||||
|
||||
[HttpGet("{count:int}/{position:int}", Name = "GetRequestsByCount")]
|
||||
public async Task<IEnumerable<RequestViewModel>> GetRequests(int count, int position)
|
||||
{
|
||||
return await RequestEngine.GetRequests(count, position);
|
||||
}
|
||||
|
||||
[HttpPost("movie")]
|
||||
public async Task<RequestEngineResult> SearchMovie([FromBody]SearchMovieViewModel movie)
|
||||
public async Task<RequestEngineResult> RequestMovie([FromBody]SearchMovieViewModel movie)
|
||||
{
|
||||
return await RequestEngine.RequestMovie(movie);
|
||||
}
|
||||
|
||||
[HttpGet("search/{searchTerm}")]
|
||||
public async Task<IEnumerable<RequestViewModel>> Search(string searchTerm)
|
||||
{
|
||||
return await RequestEngine.SearchRequest(searchTerm);
|
||||
}
|
||||
|
||||
[HttpDelete("{requestId:int}")]
|
||||
public async Task DeleteRequest(int requestId)
|
||||
{
|
||||
await RequestEngine.RemoveRequest(requestId);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<RequestViewModel> UpdateRequest([FromBody]RequestViewModel model)
|
||||
{
|
||||
return await RequestEngine.UpdateRequest(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ using Ombi.Core.Models.Search;
|
|||
|
||||
namespace Ombi.Controllers
|
||||
{
|
||||
public class SearchController : BaseApiController
|
||||
public class SearchController : BaseV1ApiController
|
||||
{
|
||||
public SearchController(IMovieEngine movie)
|
||||
{
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace Ombi
|
|||
{
|
||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||
loggerFactory.AddDebug();
|
||||
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
|
@ -60,7 +60,7 @@ namespace Ombi
|
|||
});
|
||||
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
{
|
||||
routes.MapRoute(
|
||||
name: "default",
|
||||
template: "{controller=Home}/{action=Index}/{id?}");
|
||||
|
|
|
@ -31,7 +31,7 @@ var paths = {
|
|||
'@angular/platform-browser-dynamic',
|
||||
'@angular/http',
|
||||
'@angular/router',
|
||||
'@angular/forms'
|
||||
'@angular/forms',
|
||||
],
|
||||
dest: './lib'
|
||||
},
|
||||
|
@ -56,7 +56,7 @@ var paths = {
|
|||
'./bower_components/PACE/pace.js',
|
||||
'./node_modules/bootstrap/dist/js/bootstrap.js',
|
||||
'./node_modules/tether/dist/js/tether.js',
|
||||
'./systemjs.config.js'
|
||||
'./systemjs.config.js',
|
||||
],
|
||||
dest: './lib/'
|
||||
},
|
||||
|
@ -118,7 +118,12 @@ var paths = {
|
|||
name: 'primeng',
|
||||
src: './node_modules/primeng/**/*.js',
|
||||
dest: './lib/primeng/'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "angular2-infinite-scroll",
|
||||
src: ['./node_modules/angular2-infinite-scroll/**/*.js', '!./node_modules/angular2-infinite-scroll/bundles/**/*.js'],
|
||||
dest:"./lib/angular2-infinite-scroll/"
|
||||
},
|
||||
],
|
||||
sass: { // Simple sass->css compilation
|
||||
src: ['./Styles/**/*.scss', '!./Styles/primeng/**'],
|
||||
|
|
|
@ -16,10 +16,12 @@
|
|||
"@angular/router": "^4.0.0",
|
||||
"@types/jquery": "^2.0.33",
|
||||
"@types/systemjs": "^0.20.2",
|
||||
"angular2-infinite-scroll": "^0.3.4",
|
||||
"bootstrap": "3.3.6",
|
||||
"core-js": "^2.4.1",
|
||||
"del": "^2.2.2",
|
||||
"gulp": "~3.9.1",
|
||||
"gulp-changed": "^1.3.0",
|
||||
"gulp-changed": "^1.3.0",
|
||||
"gulp-clean-css": "^3.0.4",
|
||||
"gulp-filter": "^5.0.0",
|
||||
"gulp-if": "^2.0.2",
|
||||
|
@ -39,7 +41,6 @@
|
|||
"systemjs-builder": "^0.15.34",
|
||||
"tether": "^1.4.0",
|
||||
"typescript": "^2.2.1",
|
||||
"zone.js": "^0.8.5",
|
||||
"bootstrap": "3.3.6"
|
||||
"zone.js": "^0.8.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import { AppComponent } from './app.component';
|
|||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { HttpModule } from '@angular/http';
|
||||
|
||||
import { InfiniteScrollModule } from 'angular2-infinite-scroll/angular2-infinite-scroll'
|
||||
|
||||
import { SearchComponent } from './search/search.component';
|
||||
import { RequestComponent } from './requests/request.component';
|
||||
import { PageNotFoundComponent } from './errors/not-found.component';
|
||||
|
@ -41,7 +43,8 @@ const routes: Routes = [
|
|||
FormsModule,
|
||||
SettingsModule,
|
||||
DataTableModule,
|
||||
SharedModule
|
||||
SharedModule,
|
||||
InfiniteScrollModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
|
|
|
@ -24,4 +24,9 @@
|
|||
export enum RequestType {
|
||||
movie = 1,
|
||||
tvShow = 2
|
||||
}
|
||||
|
||||
export interface IRequestsPageScroll {
|
||||
count: number,
|
||||
position:number
|
||||
}
|
|
@ -1,46 +1,182 @@
|
|||
<h1 id="searchTitle">Requests</h1>
|
||||
|
||||
|
||||
<input #gb type="text" pInputText size="50" placeholder="Search">
|
||||
<p-dataTable [value]="requests" expandableRows="true" [rows]="15" [paginator]="true" [pageLinks]="3" [rowsPerPageOptions]="[5,10,20,50]" [globalFilter]="gb">
|
||||
<p-column expander="true" styleClass="col-icon"></p-column>
|
||||
<p-column field="title" header="Title" [sortable]="true"></p-column>
|
||||
<p-column field="requestedDate" header="Requested Date" [sortable]="true"></p-column>
|
||||
<p-column field="approved" header="Approved" [sortable]="true">
|
||||
<ng-template let-col let-request="rowData" pTemplate="body">
|
||||
<span *ngIf="requests[col]" class="fa fa-check"></span>
|
||||
<span *ngIf="!requests[col]" class="fa fa-times"></span>
|
||||
</ng-template>
|
||||
</p-column>
|
||||
<ng-template let-request pTemplate="rowexpansion">
|
||||
<div class="ui-grid ui-grid-responsive ui-fluid" style="font-size:16px;padding:20px">
|
||||
<div class="ui-grid-row">
|
||||
<div class="ui-grid-col-3" style="text-align:center">
|
||||
<i class="fa fa-search" (click)="showCar(car)" style="cursor:pointer;float:left;margin-top:40px"></i>
|
||||
<img src="https://image.tmdb.org/t/p/w150/{{request.posterPath}}">
|
||||
<img *ngIf="request.type === 2" src="{{request.posterPath}}">
|
||||
</div>
|
||||
<div class="ui-grid-col-9">
|
||||
<div class="ui-grid ui-grid-responsive ui-grid-pad">
|
||||
<div class="ui-grid-row">
|
||||
<div class="ui-grid-col-2 label">Type: </div>
|
||||
<div class="ui-grid-col-10">{{request.type}}</div>
|
||||
</div>
|
||||
<div class="ui-grid-row">
|
||||
<div class="ui-grid-col-2 label">Status: </div>
|
||||
<div class="ui-grid-col-10">{{request.status}}</div>
|
||||
</div>
|
||||
<div class="ui-grid-row">
|
||||
<div class="ui-grid-col-2 label">Approved: </div>
|
||||
<div class="ui-grid-col-10">{{request.approved}}</div>
|
||||
</div>
|
||||
<div class="ui-grid-row">
|
||||
<div class="ui-grid-col-2 label">Available: </div>
|
||||
<div class="ui-grid-col-10">{{request.available}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</p-dataTable>
|
||||
<h1 id="searchTitle">Requests</h1>
|
||||
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<input type="text" class="form-control form-control-custom" placeholder="Search" (keyup)="search($event)">
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
<div infinite-scroll
|
||||
[infiniteScrollDistance]="1"
|
||||
[infiniteScrollThrottle]="100"
|
||||
(scrolled)="loadMore()">
|
||||
|
||||
|
||||
<div *ngFor="let request of requests">
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
|
||||
<img *ngIf="request.type == 1" class="img-responsive" src="https://image.tmdb.org/t/p/w150/{{request.posterPath}}" alt="poster">
|
||||
<img *ngIf="request.type == 2" class="img-responsive" src="https://image.tmdb.org/t/p/w150/{{request.posterPath}}" alt="poster">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-sm-5 ">
|
||||
<div>
|
||||
<a href="http://www.imdb.com/title/{{request.imdb}}/" target="_blank">
|
||||
<h4 class="request-title">{{request.title}} ({{request.releaseDate | date: yyyy}})</h4>
|
||||
</a>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<span>Status: </span>
|
||||
<span class="label label-success">{{request.status}}</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Request status: </span>
|
||||
<span *ngIf="request.available" class="label label-success">Request Available</span>
|
||||
<span *ngIf="request.approved" class="label label-info">Processing Request</span>
|
||||
<span *ngIf="request.denied" class="label label-danger">Request Denied</span>
|
||||
<span *ngIf="request.deniedReason" title="{{request.deniedReason}}"><i class="fa fa-info-circle"></i></span>
|
||||
<span *ngIf="!request.approved && !request.availble" class="label label-warning">Pending Approval</span>
|
||||
|
||||
</div>
|
||||
<div *ngIf="request.denied">
|
||||
Denied: <i style="color:red;" class="fa fa-check"></i>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div>Release Date: {{request.releaseDate}}</div>
|
||||
|
||||
|
||||
<!--{{#if_eq type "tv"}}
|
||||
{{#if episodes}}
|
||||
Episodes: <span class="customTooltip" data-tooltip-content="#{{requestId}}toolTipContent"><i class="fa fa-info-circle"></i></span>
|
||||
{{else}}
|
||||
<div>@UI.Requests_SeasonsRequested: {{seriesRequested}}</div>
|
||||
|
||||
{{/if}}
|
||||
{{/if_eq}}-->
|
||||
<div *ngIf="request.requestedUsers">Requested By: {{request.requestedUsers}}</div>
|
||||
|
||||
<div>Requested Date: {{request.requestedDate}}</div>
|
||||
<!--{{#if admin}}
|
||||
{{#if currentRootPath}}
|
||||
<div class="{{requestId}}rootPathMain">Root Path: <span id="{{requestId}}currentRootPath">{{currentRootPath}}</span></div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<div>
|
||||
{{#if_eq issueId 0}}
|
||||
@*Nothing*@
|
||||
{{else}}
|
||||
@UI.Issues_Issue: <a href="@formAction/issues/{{issueId}}"><i class="fa fa-check"></i></a>
|
||||
{{/if_eq}}
|
||||
</div>-->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="col-sm-3 col-sm-push-3">
|
||||
<div *ngIf="!request.admin">
|
||||
<div *ngIf="!request.approved">
|
||||
<input name="requestId" type="text" value="{{request.requestId}}" hidden="hidden" />
|
||||
<div *ngIf="request.hasQualities" class="btn-group btn-split">
|
||||
<button type="button" (click)="approve(request)" class="btn btn-sm btn-success-outline approve"><i class="fa fa-plus"></i> Approve</button>
|
||||
<button type="button" class="btn btn-success-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="caret"></span>
|
||||
<span class="sr-only">Toggle Dropdown</span>
|
||||
</button>
|
||||
<!--<ul class="dropdown-menu">
|
||||
{{#each qualities}}
|
||||
<li><a href="#" class="approve-with-quality" id="{{id}}">{{name}}</a></li>
|
||||
{{/each}}
|
||||
</ul>-->
|
||||
</div>
|
||||
|
||||
|
||||
<button *ngIf="!request.hasQualities" (click)="approve(request)" style="text-align: right" class="btn btn-sm btn-success-outline approve" type="submit"><i class="fa fa-plus"></i> Approve</button>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--<form method="POST" action="@formAction/requests/changeRootFolder{{#if_eq type "tv"}}tv{{else}}movie{{/if_eq}}" id="changeFolder{{requestId}}">
|
||||
<input name="requestId" type="text" value="{{requestId}}" hidden="hidden" />
|
||||
{{#if_eq hasRootFolders true}}
|
||||
<div class="btn-group btn-split">
|
||||
<button type="button" class="btn btn-sm btn-success-outline" id="changeRootFolderBtn{{requestId}}" custom-button="{{requestId}}">@*<i class="fa fa-plus"></i>*@ Change Root Folder</button>
|
||||
<button type="button" class="btn btn-success-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="caret"></span>
|
||||
<span class="sr-only">@UI.Requests_ToggleDropdown</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
{{#each rootFolders}}
|
||||
<li><a href="#" class="change-root-folder" id="{{id}}" requestId="{{requestId}}">{{path}}</a></li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
{{/if_eq}}
|
||||
</form>-->
|
||||
|
||||
|
||||
|
||||
<div *ngIf="!request.denied">
|
||||
<input name="requestId" type="text" value="{{request.requestId}}" hidden="hidden" />
|
||||
<input name="reason" type="text" hidden="hidden" />
|
||||
<div class="btn-group btn-split">
|
||||
<button type="button" (click)="deny(request)" class="btn btn-sm btn-danger-outline deny"><i class="fa fa-times"></i> Deny</button>
|
||||
<button type="button" class="btn btn-danger-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="caret"></span>
|
||||
<span class="sr-only">@UI.Requests_ToggleDropdown</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="deny-with-reason" id="denyReason{{request.requestId}}" href="#" data-toggle="modal" data-target="#denyReasonModal">Deny with a reason</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button (click)="removeRequest(request)" style="text-align: right" class="btn btn-sm btn-danger-outline delete"><i class="fa fa-minus"></i> Remove</button>
|
||||
|
||||
<button *ngIf="request.available" (click)="changeAvailability(request, true)" style="text-align: right" value="false" class="btn btn-sm btn-info-outline change"><i class="fa fa-minus"></i> Mark Unavailable</button>
|
||||
<button *ngIf="!request.available" (click)="changeAvailability(request, false)" style="text-align: right" value="true" class="btn btn-sm btn-success-outline change"><i class="fa fa-plus"></i> Mark Available</button>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<input name="requestId" type="text" value="{{request.requestId}}" hidden="hidden" />
|
||||
<div class="dropdown">
|
||||
<button id="{{request.requestId}}" class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<i class="fa fa-plus"></i> Report Issue
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||
<li><a id="{{request.requestId}}" issue-select="0" class="dropdownIssue" href="#">@UI.Issues_WrongAudio</a></li>
|
||||
<li><a id="{{request.requestId}}" issue-select="1" class="dropdownIssue" href="#">@UI.Issues_NoSubs</a></li>
|
||||
<li><a id="{{request.requestId}}" issue-select="2" class="dropdownIssue" href="#">@UI.Issues_WrongContent</a></li>
|
||||
<li><a id="{{request.requestId}}" issue-select="3" class="dropdownIssue" href="#">@UI.Issues_Playback</a></li>
|
||||
<li><a id="{{request.requestId}}" issue-select="4" class="dropdownIssue" href="#" data-toggle="modal" data-target="#myModal">@UI.Issues_Other</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
import 'rxjs/add/operator/debounceTime';
|
||||
import 'rxjs/add/operator/distinctUntilChanged';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
|
||||
import 'rxjs/add/operator/debounceTime';
|
||||
import 'rxjs/add/operator/distinctUntilChanged';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
@ -14,11 +20,83 @@ import { IRequestModel } from '../interfaces/IRequestModel';
|
|||
providers: [RequestService]
|
||||
})
|
||||
export class RequestComponent implements OnInit {
|
||||
constructor(private requestService: RequestService) { }
|
||||
constructor(private requestService: RequestService) {
|
||||
this.searchChanged
|
||||
.debounceTime(600) // Wait Xms afterthe last event before emitting last event
|
||||
.distinctUntilChanged() // only emit if value is different from previous value
|
||||
.subscribe(x => {
|
||||
this.searchText = x as string;
|
||||
if (this.searchText === "") {
|
||||
this.resetSearch();
|
||||
return;
|
||||
}
|
||||
this.requestService.searchRequests(this.searchText).subscribe(x => this.requests = x);
|
||||
});
|
||||
}
|
||||
|
||||
requests: IRequestModel[];
|
||||
|
||||
searchChanged: Subject<string> = new Subject<string>();
|
||||
searchText: string;
|
||||
|
||||
private currentlyLoaded: number;
|
||||
private amountToLoad : number;
|
||||
|
||||
ngOnInit() {
|
||||
this.requestService.getAllRequests().subscribe(x => this.requests = x);
|
||||
this.amountToLoad = 5;
|
||||
this.currentlyLoaded = 5;
|
||||
this.loadInit();
|
||||
}
|
||||
|
||||
loadMore() {
|
||||
this.requestService.getRequests(this.amountToLoad, this.currentlyLoaded + 1).subscribe(x => {
|
||||
this.requests.push.apply(this.requests, x);
|
||||
this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad;
|
||||
});
|
||||
}
|
||||
|
||||
search(text: any) {
|
||||
this.searchChanged.next(text.target.value);
|
||||
}
|
||||
|
||||
removeRequest(request: IRequestModel) {
|
||||
this.requestService.removeRequest(request).subscribe();
|
||||
this.removeRequestFromUi(request);
|
||||
}
|
||||
|
||||
changeAvailability(request: IRequestModel, available: boolean) {
|
||||
request.available = available;
|
||||
this.updateRequest(request);
|
||||
}
|
||||
|
||||
approve(request: IRequestModel) {
|
||||
request.approved = true;
|
||||
this.updateRequest(request);
|
||||
}
|
||||
|
||||
deny(request: IRequestModel) {
|
||||
request.approved = false;
|
||||
request.denied = true;
|
||||
this.updateRequest(request);
|
||||
}
|
||||
|
||||
private updateRequest(request: IRequestModel) {
|
||||
this.requestService.updateRequest(request).subscribe(x => request = x);
|
||||
}
|
||||
|
||||
private loadInit() {
|
||||
this.requestService.getRequests(this.amountToLoad, 0).subscribe(x => this.requests = x);
|
||||
}
|
||||
|
||||
private resetSearch() {
|
||||
this.currentlyLoaded = 5;
|
||||
this.loadInit();
|
||||
}
|
||||
|
||||
private removeRequestFromUi(key : IRequestModel) {
|
||||
var index = this.requests.indexOf(key, 0);
|
||||
if (index > -1) {
|
||||
this.requests.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,16 +8,32 @@ import { ISearchMovieResult } from '../interfaces/ISearchMovieResult';
|
|||
import { IRequestModel } from '../interfaces/IRequestModel';
|
||||
|
||||
@Injectable()
|
||||
export class RequestService {
|
||||
constructor(private http: Http) {
|
||||
export class RequestService extends ServiceHelpers {
|
||||
constructor(http: Http) {
|
||||
super(http, '/api/v1/Request/');
|
||||
}
|
||||
|
||||
requestMovie(movie: ISearchMovieResult): Observable<IRequestEngineResult> {
|
||||
return this.http.post('/api/Request/Movie/', JSON.stringify(movie), ServiceHelpers.RequestOptions).map(ServiceHelpers.extractData);
|
||||
return this.http.post(`${this.url}/Movie/`, JSON.stringify(movie), { headers: this.headers }).map(this.extractData);
|
||||
}
|
||||
|
||||
getAllRequests(): Observable<IRequestModel[]> {
|
||||
return this.http.get('/api/request').map(ServiceHelpers.extractData);
|
||||
return this.http.get(this.url).map(this.extractData);
|
||||
}
|
||||
|
||||
getRequests(count: number, position: number): Observable<IRequestModel[]> {
|
||||
return this.http.get(`${this.url}/${count}/${position}`).map(this.extractData);
|
||||
}
|
||||
|
||||
searchRequests(search: string): Observable<IRequestModel[]> {
|
||||
return this.http.get(`${this.url}/search/${search}`).map(this.extractData);
|
||||
}
|
||||
|
||||
removeRequest(request: IRequestModel): Observable<void> {
|
||||
return this.http.delete(`${this.url}/${request.id}`).map(this.extractData);
|
||||
}
|
||||
|
||||
updateRequest(request: IRequestModel) : Observable<IRequestModel> {
|
||||
return this.http.post(`${this.url}/`, JSON.stringify(request), { headers: this.headers }).map(this.extractData);
|
||||
}
|
||||
}
|
|
@ -6,24 +6,25 @@ import { ServiceHelpers } from './service.helpers';
|
|||
import { ISearchMovieResult } from '../interfaces/ISearchMovieResult';
|
||||
|
||||
@Injectable()
|
||||
export class SearchService {
|
||||
constructor(private http: Http) {
|
||||
export class SearchService extends ServiceHelpers {
|
||||
constructor(http: Http) {
|
||||
super(http, "/api/v1/search");
|
||||
}
|
||||
|
||||
searchMovie(searchTerm: string): Observable<ISearchMovieResult[]> {
|
||||
return this.http.get('/api/Search/Movie/' + searchTerm).map(ServiceHelpers.extractData);
|
||||
return this.http.get(`${this.url}/Movie/` + searchTerm).map(this.extractData);
|
||||
}
|
||||
|
||||
popularMovies(): Observable<ISearchMovieResult[]> {
|
||||
return this.http.get('/api/Search/Movie/Popular').map(ServiceHelpers.extractData);
|
||||
return this.http.get(`${this.url}/Movie/Popular`).map(this.extractData);
|
||||
}
|
||||
upcomignMovies(): Observable<ISearchMovieResult[]> {
|
||||
return this.http.get('/api/Search/Movie/upcoming').map(ServiceHelpers.extractData);
|
||||
return this.http.get(`${this.url}/Movie/upcoming`).map(this.extractData);
|
||||
}
|
||||
nowPlayingMovies(): Observable<ISearchMovieResult[]> {
|
||||
return this.http.get('/api/Search/Movie/nowplaying').map(ServiceHelpers.extractData);
|
||||
return this.http.get(`${this.url}/Movie/nowplaying`).map(this.extractData);
|
||||
}
|
||||
topRatedMovies(): Observable<ISearchMovieResult[]> {
|
||||
return this.http.get('/api/Search/Movie/toprated').map(ServiceHelpers.extractData);
|
||||
return this.http.get(`${this.url}/Movie/toprated`).map(this.extractData);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,29 @@
|
|||
import { Headers, RequestOptions, Response } from '@angular/http';
|
||||
import { Headers, Response, Http } from '@angular/http';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
export class ServiceHelpers {
|
||||
public static Headers = new Headers({ 'Content-Type': 'application/json' });
|
||||
|
||||
public static RequestOptions = new RequestOptions({
|
||||
headers: ServiceHelpers.Headers
|
||||
});
|
||||
|
||||
public static extractData(res: Response) {
|
||||
console.log(res);
|
||||
return res.json();
|
||||
constructor(protected http: Http, protected url: string) {
|
||||
this.headers = new Headers();
|
||||
this.headers.append('Content-Type', 'application/json; charset=utf-8');
|
||||
}
|
||||
|
||||
protected headers: Headers;
|
||||
|
||||
protected extractData(res: Response) {
|
||||
let body = res.json();
|
||||
//console.log('extractData', body || {});
|
||||
return body || {};
|
||||
}
|
||||
|
||||
protected handleError(error: any) {
|
||||
// In a real world app, we might use a remote logging infrastructure
|
||||
// We'd also dig deeper into the error to get a better message
|
||||
let errMsg = (error.message) ? error.message :
|
||||
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
|
||||
console.error(errMsg); // log to console instead
|
||||
return Observable.throw(errMsg);
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue