Made a start on the Issues page

pull/3554/head
Jamie Rees 4 years ago
parent 03fc7d4c19
commit c787e58f3b

@ -9,6 +9,7 @@ namespace Ombi.Core.Engine.Interfaces
{ {
public interface IMovieEngineV2 public interface IMovieEngineV2
{ {
Task<MovieFullInfoViewModel> GetMovieInfoByRequestId(int requestId, CancellationToken cancellationToken, string langCode = null);
Task<MovieFullInfoViewModel> GetFullMovieInformation(int theMovieDbId, CancellationToken cancellationToken, string langCode = null); Task<MovieFullInfoViewModel> GetFullMovieInformation(int theMovieDbId, CancellationToken cancellationToken, string langCode = null);
Task<IEnumerable<SearchMovieViewModel>> SimilarMovies(int theMovieDbId, string langCode); Task<IEnumerable<SearchMovieViewModel>> SimilarMovies(int theMovieDbId, string langCode);
Task<IEnumerable<SearchMovieViewModel>> PopularMovies(); Task<IEnumerable<SearchMovieViewModel>> PopularMovies();

@ -7,6 +7,7 @@ namespace Ombi.Core.Engine.Interfaces
public interface IMusicSearchEngineV2 public interface IMusicSearchEngineV2
{ {
Task<ArtistInformation> GetArtistInformation(string artistId); Task<ArtistInformation> GetArtistInformation(string artistId);
Task<ArtistInformation> GetArtistInformationByRequestId(int requestId);
Task<AlbumArt> GetReleaseGroupArt(string musicBrainzId, CancellationToken token); Task<AlbumArt> GetReleaseGroupArt(string musicBrainzId, CancellationToken token);
} }
} }

@ -6,5 +6,6 @@ namespace Ombi.Core
public interface ITVSearchEngineV2 public interface ITVSearchEngineV2
{ {
Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid); Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid);
Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId);
} }
} }

@ -48,6 +48,16 @@ namespace Ombi.Core.Engine.V2
return await ProcessSingleMovie(movieInfo); return await ProcessSingleMovie(movieInfo);
} }
public async Task<MovieFullInfoViewModel> GetMovieInfoByRequestId(int requestId, CancellationToken cancellationToken, string langCode = null)
{
langCode = await DefaultLanguageCode(langCode);
var request = await RequestService.MovieRequestService.Find(requestId);
var movieInfo = await Cache.GetOrAdd(nameof(GetFullMovieInformation) + request.TheMovieDbId + langCode,
async () => await MovieApi.GetFullMovieInfo(request.TheMovieDbId, cancellationToken, langCode), DateTime.Now.AddHours(12), cancellationToken);
return await ProcessSingleMovie(movieInfo);
}
public async Task<MovieCollectionsViewModel> GetCollection(int collectionId, CancellationToken cancellationToken, string langCode = null) public async Task<MovieCollectionsViewModel> GetCollection(int collectionId, CancellationToken cancellationToken, string langCode = null)
{ {
langCode = await DefaultLanguageCode(langCode); langCode = await DefaultLanguageCode(langCode);

@ -118,6 +118,12 @@ namespace Ombi.Core.Engine.V2
return new AlbumArt(); return new AlbumArt();
} }
public async Task<ArtistInformation> GetArtistInformationByRequestId(int requestId)
{
var request = await RequestService.MusicRequestRepository.Find(requestId);
return await GetArtistInformation(request.ForeignArtistId);
}
private List<BandMember> GetBandMembers(Artist artist) private List<BandMember> GetBandMembers(Artist artist)
{ {

@ -21,6 +21,7 @@ using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External; using Ombi.Core.Settings.Models.External;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using TraktSharp.Entities; using TraktSharp.Entities;
using Microsoft.EntityFrameworkCore;
namespace Ombi.Core.Engine.V2 namespace Ombi.Core.Engine.V2
{ {
@ -48,7 +49,12 @@ namespace Ombi.Core.Engine.V2
private IEmbyContentRepository EmbyContentRepo { get; } private IEmbyContentRepository EmbyContentRepo { get; }
private ITraktApi TraktApi { get; } private ITraktApi TraktApi { get; }
public async Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId)
{
var request = await RequestService.TvRequestService.GetChild().Include(x => x.ParentRequest).FirstOrDefaultAsync(x => x.Id == requestId);
return await GetShowInformation(request.ParentRequest.TvDbId);
}
public async Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid) public async Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid)
{ {
var tvdbshow = await Cache.GetOrAdd(nameof(GetShowInformation) + tvdbid, var tvdbshow = await Cache.GetOrAdd(nameof(GetShowInformation) + tvdbid,
@ -60,11 +66,11 @@ namespace Ombi.Core.Engine.V2
var show = await Cache.GetOrAdd("GetTvFullInformation" + tvdbshow.id, var show = await Cache.GetOrAdd("GetTvFullInformation" + tvdbshow.id,
async () => await TvMazeApi.GetTvFullInformation(tvdbshow.id), DateTime.Now.AddHours(12)); async () => await TvMazeApi.GetTvFullInformation(tvdbshow.id), DateTime.Now.AddHours(12));
if (show == null) if (show == null)
{ {
// We don't have enough information // We don't have enough information
return null; return null;
} }
// Setup the task so we can get the data later on if we have a IMDBID // Setup the task so we can get the data later on if we have a IMDBID
Task<TraktShow> traktInfoTask = new Task<TraktShow>(() => null); Task<TraktShow> traktInfoTask = new Task<TraktShow>(() => null);
if (show.externals?.imdb.HasValue() ?? false) if (show.externals?.imdb.HasValue() ?? false)
@ -147,7 +153,7 @@ namespace Ombi.Core.Engine.V2
private async Task<SearchFullInfoTvShowViewModel> GetExtraInfo(Task<TraktShow> showInfoTask, SearchFullInfoTvShowViewModel model) private async Task<SearchFullInfoTvShowViewModel> GetExtraInfo(Task<TraktShow> showInfoTask, SearchFullInfoTvShowViewModel model)
{ {
var result = await showInfoTask; var result = await showInfoTask;
if(result == null) if (result == null)
{ {
return model; return model;
} }

@ -1,5 +1,4 @@
 <!-- <p-growl [value]="notificationService.messages" [life]="3000"></p-growl>
<!-- <p-growl [value]="notificationService.messages" [life]="3000"></p-growl>
<nav *ngIf="showNav" class="navbar navbar-default navbar-fixed-top"> <nav *ngIf="showNav" class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid"> <div class="container-fluid">
<div class="navbar-header"> <div class="navbar-header">
@ -169,10 +168,10 @@
<div> <div>
<app-my-nav [showNav]="showNav" [isAdmin]="isAdmin" [applicationName]="applicationName" [username]="username" (logoutClick)="logOut();" <app-my-nav [showNav]="showNav" [isAdmin]="isAdmin" [applicationName]="applicationName" [username]="username" (logoutClick)="logOut();" (themeChange)="onSetTheme($event)">
(themeChange)="onSetTheme($event)"></app-my-nav> </app-my-nav>
</div> </div>

@ -25,7 +25,6 @@ export class AppComponent implements OnInit {
public customizationSettings: ICustomizationSettings; public customizationSettings: ICustomizationSettings;
public customPageSettings: ICustomPage; public customPageSettings: ICustomPage;
public issuesEnabled = false;
public user: ILocalUser; public user: ILocalUser;
public showNav: boolean; public showNav: boolean;
public updateAvailable: boolean; public updateAvailable: boolean;
@ -90,7 +89,6 @@ export class AppComponent implements OnInit {
}); });
} }
}); });
this.settingsService.issueEnabled().subscribe(x => this.issuesEnabled = x);
this.settingsService.voteEnabled().subscribe(x => this.voteEnabled = x); this.settingsService.voteEnabled().subscribe(x => this.voteEnabled = x);
this.router.events.subscribe((event: NavigationStart) => { this.router.events.subscribe((event: NavigationStart) => {

@ -32,4 +32,5 @@ export interface INavBar {
name: string; name: string;
link: string; link: string;
requiresAdmin: boolean; requiresAdmin: boolean;
enabled: boolean;
} }

@ -1,28 +1,21 @@
<table mat-table <!-- <table mat-table [dataSource]="pendingIssues" multiTemplateDataRows class="mat-elevation-z8">
[dataSource]="pendingIssues" multiTemplateDataRows <ng-container matColumnDef="{{column}}" *ngFor="let column of columnsToDisplay">
class="mat-elevation-z8"> <th mat-header-cell *matHeaderCellDef> {{column}} </th>
<ng-container matColumnDef="{{column}}" *ngFor="let column of columnsToDisplay"> <td mat-cell *matCellDef="let element"> {{element[column]}} </td>
<th mat-header-cell *matHeaderCellDef> {{column}} </th> </ng-container>
<td mat-cell *matCellDef="let element"> {{element[column]}} </td>
</ng-container>
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns --> <ng-container matColumnDef="expandedDetail">
<ng-container matColumnDef="expandedDetail"> <td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplay.length">
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplay.length"> <div class="example-element-detail" [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
<div class="example-element-detail" <div class="example-element-diagram">
[@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'"> <div class="example-element-position"> {{element.requestId}} </div>
<div class="example-element-diagram"> </div>
<div class="example-element-position"> {{element.requestId}} </div> </div>
</div> </td>
</div> </ng-container>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr> <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
<tr mat-row *matRowDef="let element; columns: columnsToDisplay;" <tr mat-row *matRowDef="let element; columns: columnsToDisplay;" class="example-element-row" [class.example-expanded-row]="expandedElement === element" (click)="expandedElement = expandedElement === element ? null : element">
class="example-element-row" </tr>
[class.example-expanded-row]="expandedElement === element" <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
(click)="expandedElement = expandedElement === element ? null : element"> </table> -->
</tr>
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
</table>

@ -6,6 +6,7 @@ import { IIssueCount, IIssues, IPagenator, IssueStatus } from "../../../interfac
import { COLUMNS } from "./issues-list.constants"; import { COLUMNS } from "./issues-list.constants";
@Component({ @Component({
selector: "issues-list",
templateUrl: "issues-list.component.html", templateUrl: "issues-list.component.html",
}) })
export class IssuesListComponent implements OnInit { export class IssuesListComponent implements OnInit {

@ -1,28 +1,25 @@
<h1 id="issuesTitle" [translate]="'Issues.Title'"></h1> <div class="small-middle-container">
<mat-tab-group>
<ngb-tabset *ngIf="count"> <mat-tab label="{{'Issues.PendingTitle' | translate}}">
<ngb-tab *ngIf="count.pending > 0"> <ng-template matTabContent>
<ng-template ngbTabTitle>{{'Issues.PendingTitle' | translate}} <span class="badge">{{count.pending}}</span></ng-template> <div *ngIf="pendingIssues">
<ng-template ngbTabContent> <issues-table [issues]="pendingIssues" (changePage)="changePagePending($event)" [totalRecords]="count.pending"></issues-table>
<div *ngIf="pendingIssues"> </div>
<issues-table [issues]="pendingIssues" (changePage)="changePagePending($event)" [totalRecords]="count.pending"></issues-table> </ng-template>
</div> </mat-tab>
</ng-template> <mat-tab *ngIf="inProgressIssues.length > 0" label="{{'Issues.InProgressTitle' | translate}}">
</ngb-tab> <ng-template matTabContent>
<ngb-tab *ngIf="count.inProgress > 0"> <div *ngIf="inProgressIssues">
<ng-template ngbTabTitle>{{'Issues.InProgressTitle' | translate}} <span class="badge">{{count.inProgress}}</span></ng-template> <issues-table [issues]="inProgressIssues" (changePage)="changePageInProg($event)" [totalRecords]="count.inProgress"></issues-table>
<ng-template ngbTabContent> </div>
<div *ngIf="inProgressIssues"> </ng-template>
<issues-table [issues]="inProgressIssues" (changePage)="changePageInProg($event)" [totalRecords]="count.inProgress"></issues-table> </mat-tab>
</div> <mat-tab label="{{'Issues.ResolvedTitle' | translate}}">
</ng-template> <ng-template matTabContent>
</ngb-tab> <div *ngIf="resolvedIssues">
<ngb-tab *ngIf="count.resolved > 0"> <issues-table [issues]="resolvedIssues" (changePage)="changePageResolved($event)" [totalRecords]="count.resolved"></issues-table>
<ng-template ngbTabTitle>{{'Issues.ResolvedTitle' | translate}} <span class="badge">{{count.resolved}}</span></ng-template> </div>
<ng-template ngbTabContent> </ng-template>
<div *ngIf="resolvedIssues"> </mat-tab>
<issues-table [issues]="resolvedIssues" (changePage)="changePageResolved($event)" [totalRecords]="count.resolved"></issues-table> </mat-tab-group>
</div> </div>
</ng-template>
</ngb-tab>
</ngb-tabset>

@ -0,0 +1,4 @@
.small-middle-container {
margin: auto;
width: 95%;
}

@ -6,6 +6,7 @@ import { IIssueCount, IIssues, IPagenator, IssueStatus } from "../interfaces";
@Component({ @Component({
templateUrl: "issues.component.html", templateUrl: "issues.component.html",
styleUrls: ['issues.component.scss']
}) })
export class IssuesComponent implements OnInit { export class IssuesComponent implements OnInit {

@ -21,7 +21,7 @@ import { IssuesListComponent } from "./components/issues-list/issues-list.compon
import * as fromComponents from "./components"; import * as fromComponents from "./components";
const routes: Routes = [ const routes: Routes = [
{ path: "", component: IssuesListComponent, canActivate: [AuthGuard] }, { path: "", component: IssuesComponent, canActivate: [AuthGuard] },
{ path: ":id", component: IssueDetailsComponent, canActivate: [AuthGuard] }, { path: ":id", component: IssueDetailsComponent, canActivate: [AuthGuard] },
]; ];

@ -1,4 +1,68 @@
<table class="table table-striped table-hover table-responsive table-condensed"> <table mat-table [dataSource]="issues" class="table" matSort matSortDisableClear>
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Issues.ColumnTitle' | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.title}} </td>
</ng-container>
<ng-container matColumnDef="category">
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Issues.Category' | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.issueCategory.value}} </td>
</ng-container>
<ng-container matColumnDef="subject">
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Issues.Subject' | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.subject}} </td>
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Issues.Status' | translate}} </th>
<td mat-cell *matCellDef="let element"> {{IssueStatus[element.status] | humanize}} </td>
</ng-container>
<ng-container matColumnDef="reportedBy">
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Issues.ReportedBy' | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.userReported.userAlias}} </td>
</ng-container>
<!-- <ng-container matColumnDef="requestedUser.requestedBy">
<th mat-header-cell *matHeaderCellDef> {{'Requests.RequestedBy' | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.requestedUser?.userAlias}} </td>
</ng-container>
<ng-container matColumnDef="requestedDate">
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Requests.RequestDate' | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.requestedDate | amLocal | amDateFormat: 'LL'}} </td>
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Requests.Status' | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.status}} </td>
</ng-container>
<ng-container matColumnDef="requestStatus">
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Requests.RequestStatus' | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element.requestStatus | translate}} </td>
</ng-container>-->
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> </th>
<td mat-cell *matCellDef="let element">
<button *ngIf="element.requestType === 1" mat-raised-button color="accent" [routerLink]="'/details/movie/request/' + element.requestId">{{ 'Issues.Details' | translate}}</button>
<button *ngIf="element.requestType === 0" mat-raised-button color="accent" [routerLink]="'/details/tv/' + element.requestId">{{ 'Issues.Details' | translate}}</button>
<button *ngIf="element.requestType === 2" mat-raised-button color="accent" [routerLink]="'/details/artist/' + element.requestId">{{ 'Issues.Details' | translate}}</button>
<!-- <button mat-raised-button color="warn" (click)="openOptions(element)" *ngIf="isAdmin"> {{ 'Requests.Options' | translate}}</button> -->
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<!-- <table class="table table-striped table-hover table-responsive table-condensed">
<thead> <thead>
<tr> <tr>
<th (click)="setOrder('title', $event)"> <th (click)="setOrder('title', $event)">
@ -52,4 +116,4 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
<p-paginator [rows]="rowCount" [totalRecords]="totalRecords" (onPageChange)="paginate($event)"></p-paginator> <p-paginator [rows]="rowCount" [totalRecords]="totalRecords" (onPageChange)="paginate($event)"></p-paginator> -->

@ -13,6 +13,7 @@ export class IssuesTableComponent {
@Output() public changePage = new EventEmitter<IPagenator>(); @Output() public changePage = new EventEmitter<IPagenator>();
public displayedColumns = ["title", "category", "subject", "status", "reportedBy", "actions"]
public IssueStatus = IssueStatus; public IssueStatus = IssueStatus;
public order: string = "id"; public order: string = "id";

@ -30,14 +30,36 @@ export class MovieDetailsComponent {
public dialog: MatDialog, private requestService: RequestService, public dialog: MatDialog, private requestService: RequestService,
public messageService: MessageService, private auth: AuthService) { public messageService: MessageService, private auth: AuthService) {
this.route.params.subscribe((params: any) => { this.route.params.subscribe((params: any) => {
this.theMovidDbId = params.movieDbId;
this.load(); this.theMovidDbId = params.movieDbId;
if (params.requestId) {
this.load(+params.requestId);
} else {
this.load(undefined);
}
}); });
} }
public load() { public async load(requestId: number|undefined) {
this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser"); this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser");
if (requestId) {
var result = await this.searchService.getFullMovieDetailsByRequestId(requestId);
this.theMovidDbId = result.id
this.movie = result;
if (this.movie.requestId > 0) {
// Load up this request
this.hasRequest = true;
this.movieRequest = await this.requestService.getMovieRequest(this.movie.requestId);
}
this.imageService.getMovieBanner(this.theMovidDbId.toString()).subscribe(x => {
this.movie.background = this.sanitizer.bypassSecurityTrustStyle
("url(" + x + ")");
});
} else {
this.searchService.getFullMovieDetails(this.theMovidDbId).subscribe(async x => { this.searchService.getFullMovieDetails(this.theMovidDbId).subscribe(async x => {
this.movie = x; this.movie = x;
if (this.movie.requestId > 0) { if (this.movie.requestId > 0) {
@ -50,7 +72,7 @@ export class MovieDetailsComponent {
("url(" + x + ")"); ("url(" + x + ")");
}); });
}); });
}
} }
public async request() { public async request() {
@ -87,7 +109,7 @@ export class MovieDetailsComponent {
public async issue() { public async issue() {
const dialogRef = this.dialog.open(NewIssueComponent, { const dialogRef = this.dialog.open(NewIssueComponent, {
width: '500px', width: '500px',
data: {requestId: this.movieRequest ? this.movieRequest.id : null, requestType: RequestType.movie, imdbid: this.movie.imdbId} data: {requestId: this.movieRequest ? this.movieRequest.id : null, requestType: RequestType.movie, imdbid: this.movie.imdbId, title: this.movie.title}
}); });
} }

@ -10,4 +10,5 @@ export interface IIssueDialogData {
requestType: RequestType; requestType: RequestType;
requestId: number; requestId: number;
imdbId: string; imdbId: string;
title: string;
} }

@ -31,7 +31,7 @@ export class NewIssueComponent implements OnInit {
comments: [], comments: [],
requestId: data.requestId, requestId: data.requestId,
requestType: data.requestType, requestType: data.requestType,
title: "", title: data.title,
providerId: data.imdbId, providerId: data.imdbId,
userReported: undefined, userReported: undefined,
}; };

@ -18,6 +18,7 @@ import { ArtistDetailsComponent } from "./components/artist/artist-details.compo
const routes: Routes = [ const routes: Routes = [
{ path: "movie/:movieDbId", component: MovieDetailsComponent, canActivate: [AuthGuard] }, { path: "movie/:movieDbId", component: MovieDetailsComponent, canActivate: [AuthGuard] },
{ path: "movie/request/:requestId", component: MovieDetailsComponent, canActivate: [AuthGuard] },
{ path: "tv/:tvdbId/:search", component: TvDetailsComponent, canActivate: [AuthGuard] }, { path: "tv/:tvdbId/:search", component: TvDetailsComponent, canActivate: [AuthGuard] },
{ path: "tv/:tvdbId", component: TvDetailsComponent, canActivate: [AuthGuard] }, { path: "tv/:tvdbId", component: TvDetailsComponent, canActivate: [AuthGuard] },
{ path: "artist/:artistId", component: ArtistDetailsComponent, canActivate: [AuthGuard] }, { path: "artist/:artistId", component: ArtistDetailsComponent, canActivate: [AuthGuard] },

@ -3,7 +3,7 @@
<mat-toolbar>{{applicationName}}</mat-toolbar> <mat-toolbar>{{applicationName}}</mat-toolbar>
<mat-nav-list> <mat-nav-list>
<span *ngFor="let nav of navItems"> <span *ngFor="let nav of navItems">
<a *ngIf="nav.requiresAdmin && isAdmin || !nav.requiresAdmin" mat-list-item [routerLink]="nav.link" <a *ngIf="(nav.requiresAdmin && isAdmin || !nav.requiresAdmin) && nav.enabled" mat-list-item [routerLink]="nav.link"
[routerLinkActive]="getTheme()"> [routerLinkActive]="getTheme()">
<mat-icon aria-label="Side nav toggle icon">{{nav.icon}}</mat-icon> <mat-icon aria-label="Side nav toggle icon">{{nav.icon}}</mat-icon>
&nbsp;{{nav.name | translate}} &nbsp;{{nav.name | translate}}

@ -4,6 +4,7 @@ import { Observable } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { INavBar } from '../interfaces/ICommon'; import { INavBar } from '../interfaces/ICommon';
import { StorageService } from '../shared/storage/storage-service'; import { StorageService } from '../shared/storage/storage-service';
import { SettingsService } from '../services';
@Component({ @Component({
selector: 'app-my-nav', selector: 'app-my-nav',
@ -24,27 +25,33 @@ export class MyNavComponent implements OnInit {
@Output() public logoutClick = new EventEmitter(); @Output() public logoutClick = new EventEmitter();
@Output() public themeChange = new EventEmitter<string>(); @Output() public themeChange = new EventEmitter<string>();
public theme: string; public theme: string;
public issuesEnabled: boolean = false;
public navItems: INavBar[];
constructor(private breakpointObserver: BreakpointObserver, constructor(private breakpointObserver: BreakpointObserver,
private settingsService: SettingsService,
private store: StorageService) { private store: StorageService) {
} }
public ngOnInit(): void { public async ngOnInit() {
this.issuesEnabled = await this.settingsService.issueEnabled().toPromise();
console.log("issues enabled: " + this.issuesEnabled);
this.theme = this.store.get("theme"); this.theme = this.store.get("theme");
if(!this.theme) { if(!this.theme) {
this.store.save("theme","dark"); this.store.save("theme","dark");
} }
this.navItems = [
{ name: "NavigationBar.Discover", icon: "find_replace", link: "/discover", requiresAdmin: false, enabled: true },
{ name: "NavigationBar.Requests", icon: "list", link: "/requests-list", requiresAdmin: false, enabled: true },
{ name: "NavigationBar.Issues", icon: "notification_important", link: "/issues", requiresAdmin: false, enabled: this.issuesEnabled },
{ name: "NavigationBar.UserManagement", icon: "account_circle", link: "/usermanagement", requiresAdmin: true, enabled: true },
{ name: "NavigationBar.Calendar", icon: "calendar_today", link: "/calendar", requiresAdmin: false, enabled: true },
{ name: "NavigationBar.Settings", icon: "settings", link: "/Settings/About", requiresAdmin: true, enabled: true },
{ name: "NavigationBar.UserPreferences", icon: "person", link: "/user-preferences", requiresAdmin: false, enabled: true },
];
} }
public navItems: INavBar[] = [
{ name: "NavigationBar.Discover", icon: "find_replace", link: "/discover", requiresAdmin: false },
{ name: "NavigationBar.Requests", icon: "list", link: "/requests-list", requiresAdmin: false },
{ name: "NavigationBar.UserManagement", icon: "account_circle", link: "/usermanagement", requiresAdmin: true },
{ name: "NavigationBar.Calendar", icon: "calendar_today", link: "/calendar", requiresAdmin: false },
{ name: "NavigationBar.Settings", icon: "settings", link: "/Settings/About", requiresAdmin: true },
{ name: "NavigationBar.UserPreferences", icon: "person", link: "/user-preferences", requiresAdmin: false },
]
public logOut() { public logOut() {
this.logoutClick.emit(); this.logoutClick.emit();
} }

@ -23,6 +23,11 @@ export class SearchV2Service extends ServiceHelpers {
public getFullMovieDetails(theMovieDbId: number): Observable<ISearchMovieResultV2> { public getFullMovieDetails(theMovieDbId: number): Observable<ISearchMovieResultV2> {
return this.http.get<ISearchMovieResultV2>(`${this.url}/Movie/${theMovieDbId}`); return this.http.get<ISearchMovieResultV2>(`${this.url}/Movie/${theMovieDbId}`);
} }
public getFullMovieDetailsByRequestId(requestId: number): Promise<ISearchMovieResultV2> {
return this.http.get<ISearchMovieResultV2>(`${this.url}/Movie/request/${requestId}`).toPromise();
}
public getFullMovieDetailsPromise(theMovieDbId: number): Promise<ISearchMovieResultV2> { public getFullMovieDetailsPromise(theMovieDbId: number): Promise<ISearchMovieResultV2> {
return this.http.get<ISearchMovieResultV2>(`${this.url}/Movie/${theMovieDbId}`).toPromise(); return this.http.get<ISearchMovieResultV2>(`${this.url}/Movie/${theMovieDbId}`).toPromise();
} }

@ -246,7 +246,7 @@ namespace Ombi.Controllers.V1
/// <summary> /// <summary>
/// Deletes a comment on a issue /// Deletes a comment on a issue
/// </summary> /// </summary>
[HttpDelete("comments/{id:int}")] [HttpDelete("comments/{id}")]
[PowerUser] [PowerUser]
public async Task<bool> DeleteComment(int id) public async Task<bool> DeleteComment(int id)
{ {
@ -256,6 +256,16 @@ namespace Ombi.Controllers.V1
return true; return true;
} }
[HttpDelete("{id}")]
[PowerUser]
public async Task<bool> DeleteIssue(int id)
{
var issue = await _issues.GetAll().FirstOrDefaultAsync(x => x.Id == id);
await _issues.Delete(issue);
return true;
}
[HttpPost("status")] [HttpPost("status")]
public async Task<bool> UpdateStatus([FromBody] IssueStateViewModel model) public async Task<bool> UpdateStatus([FromBody] IssueStateViewModel model)
{ {

@ -61,6 +61,15 @@ namespace Ombi.Controllers.V2
return await _movieEngineV2.GetFullMovieInformation(movieDbId, Request.HttpContext.RequestAborted); return await _movieEngineV2.GetFullMovieInformation(movieDbId, Request.HttpContext.RequestAborted);
} }
/// <summary>
/// Returns details for a single movie
/// </summary>
[HttpGet("movie/request/{requestId}")]
public async Task<MovieFullInfoViewModel> GetMovieByRequest(int requestId)
{
return await _movieEngineV2.GetMovieInfoByRequestId(requestId, Request.HttpContext.RequestAborted);
}
/// <summary> /// <summary>
/// Returns basic information about the provided collection /// Returns basic information about the provided collection
/// </summary> /// </summary>
@ -83,6 +92,17 @@ namespace Ombi.Controllers.V2
return await _tvEngineV2.GetShowInformation(tvdbid); return await _tvEngineV2.GetShowInformation(tvdbid);
} }
/// <summary>
/// Returns details for a single show
/// </summary>
/// <remarks>TVMaze is the TV Show Provider</remarks>
///
[HttpGet("tv/request/{requestId}")]
public async Task<SearchFullInfoTvShowViewModel> GetTvInfoByRequest(int requestId)
{
return await _tvEngineV2.GetShowByRequest(requestId);
}
/// <summary> /// <summary>
/// Returns details for a single show /// Returns details for a single show
/// </summary> /// </summary>
@ -357,6 +377,14 @@ namespace Ombi.Controllers.V2
return await _musicEngine.GetArtistInformation(artistId); return await _musicEngine.GetArtistInformation(artistId);
} }
[HttpGet("artist/request/{requestId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<ArtistInformation> GetArtistInformationByRequestId(int requestId)
{
return await _musicEngine.GetArtistInformationByRequestId(requestId);
}
[HttpGet("releasegroupart/{musicBrainzId}")] [HttpGet("releasegroupart/{musicBrainzId}")]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType] [ProducesDefaultResponseType]

Loading…
Cancel
Save