Added the ability to deny a request with a reason

This commit is contained in:
TidusJar 2018-12-17 15:56:24 +00:00
parent bd3a243af9
commit e6d48e5364
7 changed files with 73 additions and 40 deletions

View file

@ -49,7 +49,7 @@ namespace Ombi.Notifications
} }
Overview = req?.Overview; Overview = req?.Overview;
Year = req?.ReleaseDate.Year.ToString(); Year = req?.ReleaseDate.Year.ToString();
DenyReason = req?.DeniedReason;
if (req?.RequestType == RequestType.Movie) if (req?.RequestType == RequestType.Movie)
{ {
PosterImage = string.Format((req?.PosterPath ?? string.Empty).StartsWith("/", StringComparison.InvariantCultureIgnoreCase) PosterImage = string.Format((req?.PosterPath ?? string.Empty).StartsWith("/", StringComparison.InvariantCultureIgnoreCase)
@ -88,6 +88,7 @@ namespace Ombi.Notifications
UserName = req?.RequestedUser?.UserName; UserName = req?.RequestedUser?.UserName;
} }
DenyReason = req?.DeniedReason;
Alias = (req?.RequestedUser?.Alias.HasValue() ?? false) ? req?.RequestedUser?.Alias : req?.RequestedUser?.UserName; Alias = (req?.RequestedUser?.Alias.HasValue() ?? false) ? req?.RequestedUser?.Alias : req?.RequestedUser?.UserName;
Title = title; Title = title;
RequestedDate = req?.RequestedDate.ToString("D"); RequestedDate = req?.RequestedDate.ToString("D");
@ -126,6 +127,7 @@ namespace Ombi.Notifications
{ {
title = req?.ParentRequest.Title; title = req?.ParentRequest.Title;
} }
DenyReason = req?.DeniedReason;
ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty; ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty;
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName; ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName;
RequestedUser = req?.RequestedUser?.UserName; RequestedUser = req?.RequestedUser?.UserName;
@ -217,7 +219,6 @@ namespace Ombi.Notifications
public string UserName { get; set; } public string UserName { get; set; }
public string IssueUser => UserName; public string IssueUser => UserName;
public string Alias { get; set; } public string Alias { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string RequestedDate { get; set; } public string RequestedDate { get; set; }
public string Type { get; set; } public string Type { get; set; }
@ -235,6 +236,7 @@ namespace Ombi.Notifications
public string IssueSubject { get; set; } public string IssueSubject { get; set; }
public string NewIssueComment { get; set; } public string NewIssueComment { get; set; }
public string UserPreference { get; set; } public string UserPreference { get; set; }
public string DenyReason { get; set; }
// System Defined // System Defined
private string LongDate => DateTime.Now.ToString("D"); private string LongDate => DateTime.Now.ToString("D");
@ -269,6 +271,7 @@ namespace Ombi.Notifications
{nameof(UserName),UserName}, {nameof(UserName),UserName},
{nameof(Alias),Alias}, {nameof(Alias),Alias},
{nameof(UserPreference),UserPreference}, {nameof(UserPreference),UserPreference},
{nameof(DenyReason),DenyReason},
}; };
} }
} }

View file

@ -55,6 +55,10 @@ export interface IAlbumUpdateModel {
id: number; id: number;
} }
export interface IDenyAlbumModel extends IAlbumUpdateModel {
reason: string;
}
export interface IFullBaseRequest extends IBaseRequest { export interface IFullBaseRequest extends IBaseRequest {
imdbId: string; imdbId: string;
overview: string; overview: string;
@ -117,6 +121,10 @@ export interface ITvUpdateModel {
id: number; id: number;
} }
export interface ITvDenyModel extends ITvUpdateModel {
reason: string;
}
export enum OrderType { export enum OrderType {
RequestedDateAsc = 1, RequestedDateAsc = 1,
RequestedDateDesc = 2, RequestedDateDesc = 2,

View file

@ -92,7 +92,7 @@
</div> </div>
<div *ngIf="request.denied" id="requestDenied"> <div *ngIf="request.denied" id="requestDenied">
{{ 'Requests.Denied' | translate }} {{ 'Requests.Denied' | translate }}
<i style="color:red;" class="fa fa-check"></i> <i style="color:red;" class="fa fa-check" pTooltip="{{request.deniedReason}}"></i>
</div> </div>
@ -265,4 +265,15 @@
<button class="btn btn-sm btn-primary-outline" (click)="clearFilter($event)"> <button class="btn btn-sm btn-primary-outline" (click)="clearFilter($event)">
<i class="fa fa-filter"></i> {{ 'Filter.ClearFilter' | translate }}</button> <i class="fa fa-filter"></i> {{ 'Filter.ClearFilter' | translate }}</button>
</p-sidebar> </p-sidebar>
<p-dialog *ngIf="requestToDeny" header="Deny Request '{{requestToDeny.title}}''" [(visible)]="denyDisplay" [draggable]="false">
<span>Please enter a rejection reason, the user will be notified of this:</span>
<textarea [(ngModel)]="rejectionReason" class="form-control-custom form-control"></textarea>
<p-footer>
<button type="button" (click)="denyRequest();" label="Reject" class="btn btn-success">Deny</button>
<button type="button"(click)="denyDisplay=false" label="Close" class="btn btn-danger">Close</button>
</p-footer>
</p-dialog>

View file

@ -34,6 +34,9 @@ export class MusicRequestsComponent implements OnInit {
public orderType: OrderType = OrderType.RequestedDateDesc; public orderType: OrderType = OrderType.RequestedDateDesc;
public OrderType = OrderType; public OrderType = OrderType;
public denyDisplay: boolean;
public requestToDeny: IAlbumRequest;
public rejectionReason: string;
public totalAlbums: number = 100; public totalAlbums: number = 100;
private currentlyLoaded: number; private currentlyLoaded: number;
@ -126,23 +129,22 @@ export class MusicRequestsComponent implements OnInit {
} }
public deny(request: IAlbumRequest) { public deny(request: IAlbumRequest) {
request.denied = true; this.requestToDeny = request;
this.denyRequest(request); this.denyDisplay = true;
} }
// public selectRootFolder(searchResult: IAlbumRequest, rootFolderSelected: IRadarrRootFolder, event: any) { public denyRequest() {
// event.preventDefault(); this.requestService.denyAlbum({ id: this.requestToDeny.id, reason: this.rejectionReason })
// // searchResult.rootPathOverride = rootFolderSelected.id; .subscribe(x => {
// this.setOverride(searchResult); if (x.result) {
// this.updateRequest(searchResult); this.notificationService.success(
// } `Request for ${this.requestToDeny.title} has been denied successfully`);
} else {
// public selectQualityProfile(searchResult: IMovieRequests, profileSelected: IRadarrProfile, event: any) { this.notificationService.warning("Request Denied", x.message ? x.message : x.errorMessage);
// event.preventDefault(); this.requestToDeny.denied = false;
// searchResult.qualityOverride = profileSelected.id; }
// this.setOverride(searchResult); });
// this.updateRequest(searchResult); }
// }
public reportIssue(catId: IIssueCategory, req: IAlbumRequest) { public reportIssue(catId: IIssueCategory, req: IAlbumRequest) {
this.issueRequest = req; this.issueRequest = req;
@ -266,19 +268,6 @@ export class MusicRequestsComponent implements OnInit {
}); });
} }
private denyRequest(request: IAlbumRequest) {
this.requestService.denyAlbum({ id: request.id })
.subscribe(x => {
if (x.result) {
this.notificationService.success(
`Request for ${request.title} has been denied successfully`);
} else {
this.notificationService.warning("Request Denied", x.message ? x.message : x.errorMessage);
request.denied = false;
}
});
}
private loadInit() { private loadInit() {
this.requestService.getAlbumRequests(this.amountToLoad, 0, this.orderType, this.filter) this.requestService.getAlbumRequests(this.amountToLoad, 0, this.orderType, this.filter)
.subscribe(x => { .subscribe(x => {

View file

@ -21,7 +21,8 @@
<button id="unavailableBtn" *ngIf="child.available" (click)="changeAvailability(child, false)" style="text-align: right" value="false" class="btn btn-sm btn-info-outline change"><i class="fa fa-minus"></i> {{ 'Requests.MarkUnavailable' | translate }}</button> <button id="unavailableBtn" *ngIf="child.available" (click)="changeAvailability(child, false)" style="text-align: right" value="false" class="btn btn-sm btn-info-outline change"><i class="fa fa-minus"></i> {{ 'Requests.MarkUnavailable' | translate }}</button>
<button id="availableBtn" *ngIf="!child.available" (click)="changeAvailability(child, true)" style="text-align: right" value="true" class="btn btn-sm btn-success-outline change"><i class="fa fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}</button> <button id="availableBtn" *ngIf="!child.available" (click)="changeAvailability(child, true)" style="text-align: right" value="true" class="btn btn-sm btn-success-outline change"><i class="fa fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}</button>
<button id="denyBtn" *ngIf="!child.denied" type="button" (click)="deny(child)" class="btn btn-sm btn-danger-outline deny"><i class="fa fa-times"></i> {{ 'Requests.Deny' | translate }}</button> <button id="denyBtn" *ngIf="!child.denied" type="button" (click)="deny(child)" class="btn btn-sm btn-danger-outline deny">
<i class="fa fa-times"></i> {{ 'Requests.Deny' | translate }}</button>
</div> </div>
<div *ngIf="isAdmin || isRequestUser(child)"> <div *ngIf="isAdmin || isRequestUser(child)">
@ -76,7 +77,9 @@
{{ep.airDate | amLocal | amDateFormat: 'L' }} {{ep.airDate | amLocal | amDateFormat: 'L' }}
</td> </td>
<td> <td>
<span *ngIf="child.denied" class="label label-danger" id="deniedLabel" [translate]="'Common.Denied'"></span> <span *ngIf="child.denied" class="label label-danger" id="deniedLabel" [translate]="'Common.Denied'">
<i style="color:red;" class="fa fa-check" pTooltip="{{child.deniedReason}}"></i>
</span>
<span *ngIf="!child.denied && ep.available" class="label label-success" id="availableLabel" [translate]="'Common.Available'"></span> <span *ngIf="!child.denied && ep.available" class="label label-success" id="availableLabel" [translate]="'Common.Available'"></span>
<span *ngIf="!child.denied &&ep.approved && !ep.available" class="label label-info" id="processingRequestLabel" [translate]="'Common.ProcessingRequest'"></span> <span *ngIf="!child.denied &&ep.approved && !ep.available" class="label label-info" id="processingRequestLabel" [translate]="'Common.ProcessingRequest'"></span>
<div *ngIf="!child.denied && !ep.approved"> <div *ngIf="!child.denied && !ep.approved">
@ -98,3 +101,12 @@
</div> </div>
</div> </div>
<p-dialog *ngIf="requestToDeny" header="Deny Request '{{requestToDeny.title}}''" [(visible)]="denyDisplay" [draggable]="false">
<span>Please enter a rejection reason, the user will be notified of this:</span>
<textarea [(ngModel)]="rejectionReason" class="form-control-custom form-control"></textarea>
<p-footer>
<button type="button" (click)="denyRequest();" label="Reject" class="btn btn-success">Deny</button>
<button type="button"(click)="denyDisplay=false" label="Close" class="btn btn-danger">Close</button>
</p-footer>
</p-dialog>

View file

@ -11,6 +11,10 @@ export class TvRequestChildrenComponent {
@Input() public childRequests: IChildRequests[]; @Input() public childRequests: IChildRequests[];
@Input() public isAdmin: boolean; @Input() public isAdmin: boolean;
@Input() public currentUser: string; @Input() public currentUser: string;
public denyDisplay: boolean;
public requestToDeny: IChildRequests;
public rejectionReason: string;
@Output() public requestDeleted = new EventEmitter<number>(); @Output() public requestDeleted = new EventEmitter<number>();
@ -57,20 +61,26 @@ export class TvRequestChildrenComponent {
public deny(request: IChildRequests) { public deny(request: IChildRequests) {
request.denied = true; request.denied = true;
this.requestToDeny = request;
this.denyDisplay = true;
request.seasonRequests.forEach((season) => { request.seasonRequests.forEach((season) => {
season.episodes.forEach((ep) => { season.episodes.forEach((ep) => {
ep.approved = false; ep.approved = false;
}); });
}); });
this.requestService.denyChild({ id: request.id }) }
public denyRequest() {
this.requestService.denyChild({ id: this.requestToDeny.id, reason: this.rejectionReason })
.subscribe(x => { .subscribe(x => {
this.denyDisplay = false;
if (x.result) { if (x.result) {
this.notificationService.success( this.notificationService.success(
`Request has been denied successfully`); `Request has been denied successfully`);
} else { } else {
this.notificationService.warning("Request Denied", x.message ? x.message : x.errorMessage); this.notificationService.warning("Request Denied", x.message ? x.message : x.errorMessage);
request.approved = false; this.requestToDeny.approved = false;
} }
}); });
} }

View file

@ -5,8 +5,8 @@ import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs"; import { Observable } from "rxjs";
import { TreeNode } from "primeng/primeng"; import { TreeNode } from "primeng/primeng";
import { FilterType, IAlbumRequest, IAlbumRequestModel, IAlbumUpdateModel, IChildRequests, IDenyMovieModel, IFilter, IMovieRequestModel, import { FilterType, IAlbumRequest, IAlbumRequestModel, IAlbumUpdateModel, IChildRequests, IDenyAlbumModel, IDenyMovieModel, IFilter,
IMovieRequests, IMovieUpdateModel, IRequestEngineResult, IRequestsViewModel, ITvRequests, ITvUpdateModel, OrderType } from "../interfaces"; IMovieRequestModel, IMovieRequests, IMovieUpdateModel, IRequestEngineResult, IRequestsViewModel, ITvDenyModel, ITvRequests, ITvUpdateModel, OrderType } from "../interfaces";
import { ITvRequestViewModel } from "../interfaces"; import { ITvRequestViewModel } from "../interfaces";
import { ServiceHelpers } from "./service.helpers"; import { ServiceHelpers } from "./service.helpers";
@ -118,7 +118,7 @@ export class RequestService extends ServiceHelpers {
return this.http.put<IChildRequests>(`${this.url}tv/child`, JSON.stringify(child), {headers: this.headers}); return this.http.put<IChildRequests>(`${this.url}tv/child`, JSON.stringify(child), {headers: this.headers});
} }
public denyChild(child: ITvUpdateModel): Observable<IRequestEngineResult> { public denyChild(child: ITvDenyModel): Observable<IRequestEngineResult> {
return this.http.put<IRequestEngineResult>(`${this.url}tv/deny`, JSON.stringify(child), {headers: this.headers}); return this.http.put<IRequestEngineResult>(`${this.url}tv/deny`, JSON.stringify(child), {headers: this.headers});
} }
@ -161,7 +161,7 @@ export class RequestService extends ServiceHelpers {
return this.http.post<IRequestEngineResult>(`${this.url}music/Approve`, JSON.stringify(Album), {headers: this.headers}); return this.http.post<IRequestEngineResult>(`${this.url}music/Approve`, JSON.stringify(Album), {headers: this.headers});
} }
public denyAlbum(Album: IAlbumUpdateModel): Observable<IRequestEngineResult> { public denyAlbum(Album: IDenyAlbumModel): Observable<IRequestEngineResult> {
return this.http.put<IRequestEngineResult>(`${this.url}music/Deny`, JSON.stringify(Album), {headers: this.headers}); return this.http.put<IRequestEngineResult>(`${this.url}music/Deny`, JSON.stringify(Album), {headers: this.headers});
} }