Skip to content

Commit d8bc228

Browse files
committed
fix: resolve critical and major SonarQube code quality issues
1 parent add609c commit d8bc228

8 files changed

Lines changed: 112 additions & 124 deletions

File tree

src/Ombi.Core/Engine/MusicRequestEngine.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ public async Task<RequestsViewModel<AlbumRequest>> GetRequestsByStatus(int count
559559
};
560560
}
561561

562-
public async Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int position, string sortProperty, string sortOrder, string requestedByUserId = null)
562+
public async Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int position, string sort, string sortOrder, string requestedByUserId = null)
563563
{
564564
var shouldHide = await HideFromOtherUsers();
565565
IQueryable<AlbumRequest> allRequests;
@@ -579,7 +579,7 @@ public async Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int po
579579
allRequests = FilterByRequestedUser(allRequests, requestedByUserId, shouldHide.IsAdmin);
580580

581581
var total = await allRequests.CountAsync();
582-
var requests = await ApplySortAlbums(allRequests, sortProperty, sortOrder)
582+
var requests = await ApplySortAlbums(allRequests, sort, sortOrder)
583583
.Skip(position).Take(count).ToListAsync();
584584

585585
await CheckForSubscription(shouldHide, requests);

src/Ombi.Core/Engine/TvRequestEngine.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ public async Task<RequestsViewModel<ChildRequests>> GetRequests(int count, int p
381381
return new RequestsViewModel<ChildRequests>();
382382
}
383383

384-
allRequests = FilterByRequestedUser(allRequests.AsQueryable(), requestedByUserId, shouldHide.IsAdmin).ToList();
384+
allRequests = FilterByRequestedUser(allRequests.AsQueryable(), requestedByUserId, shouldHide.IsAdmin).AsEnumerable().ToList();
385385

386386
allRequests = ApplySortTv(allRequests, sortProperty, sortOrder);
387387

@@ -418,7 +418,7 @@ public async Task<RequestsViewModel<ChildRequests>> GetRequests(int count, int p
418418

419419
}
420420

421-
allRequests = FilterByRequestedUser(allRequests.AsQueryable(), requestedByUserId, shouldHide.IsAdmin).ToList();
421+
allRequests = FilterByRequestedUser(allRequests.AsQueryable(), requestedByUserId, shouldHide.IsAdmin).AsEnumerable().ToList();
422422

423423
switch (status)
424424
{
@@ -483,7 +483,7 @@ public async Task<RequestsViewModel<ChildRequests>> GetUnavailableRequests(int c
483483
return new RequestsViewModel<ChildRequests>();
484484
}
485485

486-
allRequests = FilterByRequestedUser(allRequests.AsQueryable(), requestedByUserId, shouldHide.IsAdmin).ToList();
486+
allRequests = FilterByRequestedUser(allRequests.AsQueryable(), requestedByUserId, shouldHide.IsAdmin).AsEnumerable().ToList();
487487

488488
allRequests = ApplySortTv(allRequests, sortProperty, sortOrder);
489489

src/Ombi.Core/Rule/Rules/Search/AvailabilityRuleHelper.cs

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,13 @@ public static void CheckForUnairedEpisodes(SearchTvShowViewModel search)
3434
{
3535
var airedButNotAvailable = search.SeasonRequests.Any(x =>
3636
x.Episodes.Any(c => !c.Available && c.AirDate <= DateTime.Now.Date && c.AirDate != DateTime.MinValue));
37-
if (!airedButNotAvailable)
37+
38+
var unknownAirDateUnavailable = search.SeasonRequests.Any(x =>
39+
x.Episodes.Any(c => !c.Available && c.AirDate == DateTime.MinValue));
40+
41+
if (!airedButNotAvailable && !unknownAirDateUnavailable && search.PartlyAvailable)
3842
{
39-
var unknownAirDateUnavailable = search.SeasonRequests.Any(x =>
40-
x.Episodes.Any(c => !c.Available && c.AirDate == DateTime.MinValue));
41-
if (!unknownAirDateUnavailable)
42-
{
43-
// Only treat the remaining (unaired) episodes as non-blocking when we
44-
// actually have something available already. A show where nothing has
45-
// aired yet has no available episodes and must not be marked available.
46-
if (search.PartlyAvailable)
47-
{
48-
search.FullyAvailable = true;
49-
}
50-
}
43+
search.FullyAvailable = true;
5144
}
5245
}
5346

@@ -67,22 +60,21 @@ public static async Task SingleEpisodeCheck(bool useImdb, IQueryable<IMediaServe
6760
IMediaServerEpisode epExists = null;
6861
try
6962
{
70-
71-
if (useImdb)
63+
if (useImdb && !string.IsNullOrEmpty(item.ImdbId))
7264
{
7365
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
7466
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
7567
x.Series.ImdbId == item.ImdbId);
7668
}
7769

78-
if (useTheMovieDb)
70+
if (epExists == null && useTheMovieDb && !string.IsNullOrEmpty(item.TheMovieDbId))
7971
{
8072
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
8173
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
8274
x.Series.TheMovieDbId == item.TheMovieDbId);
8375
}
8476

85-
if (useTvDb)
77+
if (epExists == null && useTvDb && !string.IsNullOrEmpty(item.TvDbId))
8678
{
8779
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
8880
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&

src/Ombi.Core/Rule/Rules/Search/MediaServerAvailabilityRule.cs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
using System;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using System.Threading.Tasks;
5+
using Microsoft.EntityFrameworkCore;
46
using Microsoft.Extensions.Logging;
57
using Ombi.Core.Models.Search;
68
using Ombi.Core.Rule.Interfaces;
@@ -115,13 +117,38 @@ private async Task CheckEpisodeAvailability(SearchTvShowViewModel search, Conten
115117
}
116118

117119
var allEpisodes = GetAllEpisodes();
120+
var seriesEpisodes = new List<IMediaServerEpisode>();
121+
122+
try
123+
{
124+
if (lookup.UseImdb && !string.IsNullOrEmpty(item.ImdbId))
125+
{
126+
seriesEpisodes = await allEpisodes.Where(x => x.Series.ImdbId == item.ImdbId).ToListAsync();
127+
}
128+
else if (lookup.UseTheMovieDb && !string.IsNullOrEmpty(item.TheMovieDbId))
129+
{
130+
seriesEpisodes = await allEpisodes.Where(x => x.Series.TheMovieDbId == item.TheMovieDbId).ToListAsync();
131+
}
132+
else if (lookup.UseTvDb && !string.IsNullOrEmpty(item.TvDbId))
133+
{
134+
seriesEpisodes = await allEpisodes.Where(x => x.Series.TvDbId == item.TvDbId).ToListAsync();
135+
}
136+
}
137+
catch (Exception ex)
138+
{
139+
Log.LogError(ex, "Exception thrown when pre-fetching series episodes for availability check");
140+
}
141+
118142
foreach (var season in search.SeasonRequests.ToList())
119143
{
120144
foreach (var episode in season.Episodes.ToList())
121145
{
122-
await AvailabilityRuleHelper.SingleEpisodeCheck(
123-
lookup.UseImdb, allEpisodes, episode, season, item,
124-
lookup.UseTheMovieDb, lookup.UseTvDb, Log);
146+
var epExists = seriesEpisodes.FirstOrDefault(x =>
147+
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber);
148+
if (epExists != null)
149+
{
150+
episode.Available = true;
151+
}
125152
}
126153
}
127154

src/Ombi/ClientApp/src/app/discover/components/card/discover-card.component.html

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,20 @@
2727

2828
<!-- Request button -->
2929
<div class="card-actions" *ngIf="!result.available && !result.approved && !result.requested">
30-
<div *ngIf="is4kEnabled && requestable && result.type === RequestType.movie;then show4K else regular"></div>
31-
<ng-template #show4K>
32-
<button [matMenuTriggerFor]="menu" id="requestButton{{result.id}}{{result.type}}{{discoverType}}" mat-raised-button class="request-btn">
33-
<i *ngIf="!loading" class="fas fa-plus" aria-hidden="true"></i>
34-
<i *ngIf="loading" class="fas fa-spinner fa-pulse" aria-hidden="true"></i>
35-
<span>{{'Common.Request' | translate }}</span>
36-
</button>
37-
<mat-menu #menu="matMenu">
38-
<button mat-menu-item class="request-menu-item" (click)="request($event, false)">{{'Common.Request' | translate }}</button>
39-
<button mat-menu-item class="request-menu-item" (click)="request($event, true)">{{'Common.Request4K' | translate }}</button>
40-
</mat-menu>
41-
</ng-template>
42-
<ng-template #regular>
43-
<button id="requestButton{{result.id}}{{result.type}}{{discoverType}}" *ngIf="requestable" mat-raised-button class="request-btn" (click)="request($event, false)">
44-
<i *ngIf="!loading" class="fas fa-plus" aria-hidden="true"></i>
45-
<i *ngIf="loading" class="fas fa-spinner fa-pulse" aria-hidden="true"></i>
46-
<span>{{'Common.Request' | translate }}</span>
47-
</button>
48-
</ng-template>
30+
<button [matMenuTriggerFor]="is4kEnabled && requestable && result.type === RequestType.movie ? menu : null"
31+
id="requestButton{{result.id}}{{result.type}}{{discoverType}}"
32+
*ngIf="requestable"
33+
mat-raised-button
34+
class="request-btn"
35+
(click)="!(is4kEnabled && result.type === RequestType.movie) ? request($event, false) : null">
36+
<i *ngIf="!loading" class="fas fa-plus" aria-hidden="true"></i>
37+
<i *ngIf="loading" class="fas fa-spinner fa-pulse" aria-hidden="true"></i>
38+
<span>{{'Common.Request' | translate }}</span>
39+
</button>
40+
<mat-menu #menu="matMenu">
41+
<button mat-menu-item class="request-menu-item" (click)="request($event, false)">{{'Common.Request' | translate }}</button>
42+
<button mat-menu-item class="request-menu-item" (click)="request($event, true)">{{'Common.Request4K' | translate }}</button>
43+
</mat-menu>
4944
</div>
5045
</div>
5146
</div>

src/Ombi/ClientApp/src/app/pipes/HumanizePipe.spec.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,8 @@ describe('HumanizePipe', () => {
2727
it('should return non-string values as-is', () => {
2828
expect(pipe.transform(123 as any)).toBe(123);
2929
});
30+
31+
it('should return empty string as-is', () => {
32+
expect(pipe.transform('')).toBe('');
33+
});
3034
});
Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
import { Pipe, PipeTransform } from "@angular/core";
1+
import { Pipe, PipeTransform } from "@angular/core";
22

33
@Pipe({
44
standalone: true,
55
name: "humanize",
66
})
77
export class HumanizePipe implements PipeTransform {
8-
public transform(value: string) {
9-
if ((typeof value) !== "string") {
8+
public transform(value: any): any {
9+
if ((typeof value) !== "string" || !value) {
1010
return value;
1111
}
12-
value = value.split(/(?=[A-Z])/).join(" ");
13-
value = value[0].toUpperCase() + value.slice(1);
14-
return value;
12+
let str = value as string;
13+
str = str.split(/(?=[A-Z])/).join(" ");
14+
str = str[0].toUpperCase() + str.slice(1);
15+
return str;
1516
}
1617
}

src/Ombi/ClientApp/src/app/wizard/database/database.component.html

Lines changed: 42 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<div class="mediaserver-container">
1+
<div class="mediaserver-container">
22
<div class="left-container mediaserver">
33
<i class="fa fa-database text-logo"></i>
44
</div>
@@ -21,83 +21,52 @@ <h4>
2121
</p>
2222
</mat-tab>
2323
<mat-tab label="MySQL/MariaDB">
24-
<p class="space-or">
25-
Please enter your MySQL/MariaDB connection details below
26-
</p>
27-
<div>
28-
<mat-form-field>
29-
<input matInput type="text" formControlName="host" id="host" placeholder="Host">
30-
<mat-error>This field is required</mat-error>
31-
</mat-form-field>
32-
</div>
33-
<div>
34-
<mat-form-field>
35-
<input matInput type="number" formControlName="port" id="port" placeholder="Port">
36-
<mat-error>This field is required</mat-error>
37-
</mat-form-field>
38-
</div>
39-
<div>
40-
<mat-form-field>
41-
<input matInput type="text" formControlName="name" id="database" placeholder="Database Name">
42-
<mat-error>This field is required</mat-error>
43-
</mat-form-field>
44-
</div>
45-
<div>
46-
<mat-form-field>
47-
<input matInput type="text" formControlName="user" id="user" placeholder="User">
48-
</mat-form-field>
49-
</div>
50-
<div>
51-
<mat-form-field>
52-
<input matInput type="password" formControlName="password" id="password" placeholder="Password">
53-
</mat-form-field>
54-
</div>
55-
<p>{{connectionString | async}}</p>
56-
<div style="text-align: center; margin-top: 20px">
57-
<button (click)="save()" id="databaseSave" mat-raised-button color="accent" type="button" class="viewon-btn database" [disabled]="form.invalid">Save</button>
58-
<div id="spinner"></div>
59-
</div>
24+
<ng-container *ngTemplateOutlet="dbForm; context: { dbType: 'MySQL' }"></ng-container>
6025
</mat-tab>
6126

6227
<mat-tab label="Postgres">
63-
<p class="space-or">
64-
Please enter your Postgres connection details below
65-
</p>
66-
<div>
67-
<mat-form-field>
68-
<input matInput type="text" formControlName="host" id="host" placeholder="Host">
69-
<mat-error>This field is required</mat-error>
70-
</mat-form-field>
71-
</div>
72-
<div>
73-
<mat-form-field>
74-
<input matInput type="number" formControlName="port" id="port" placeholder="Port">
75-
<mat-error>This field is required</mat-error>
76-
</mat-form-field>
77-
</div>
78-
<div>
79-
<mat-form-field>
80-
<input matInput type="text" formControlName="name" id="database" placeholder="Database Name">
81-
<mat-error>This field is required</mat-error>
82-
</mat-form-field>
83-
</div>
84-
<div>
85-
<mat-form-field>
86-
<input matInput type="text" formControlName="user" id="user" placeholder="User">
87-
</mat-form-field>
88-
</div>
89-
<div>
90-
<mat-form-field>
91-
<input matInput type="password" formControlName="password" id="password" placeholder="Password">
92-
</mat-form-field>
93-
</div>
94-
<p>{{connectionString | async}}</p>
95-
<div style="text-align: center; margin-top: 20px">
96-
<button (click)="save()" id="databaseSave" mat-raised-button color="accent" type="button" class="viewon-btn database" [disabled]="form.invalid">Save</button>
97-
<div id="spinner"></div>
98-
</div>
28+
<ng-container *ngTemplateOutlet="dbForm; context: { dbType: 'Postgres' }"></ng-container>
9929
</mat-tab>
10030
</mat-tab-group>
31+
32+
<ng-template #dbForm let-dbType="dbType">
33+
<p class="space-or">
34+
Please enter your {{dbType}} connection details below
35+
</p>
36+
<div>
37+
<mat-form-field>
38+
<input matInput type="text" formControlName="host" [id]="dbType.toLowerCase() + '-host'" placeholder="Host">
39+
<mat-error>This field is required</mat-error>
40+
</mat-form-field>
41+
</div>
42+
<div>
43+
<mat-form-field>
44+
<input matInput type="number" formControlName="port" [id]="dbType.toLowerCase() + '-port'" placeholder="Port">
45+
<mat-error>This field is required</mat-error>
46+
</mat-form-field>
47+
</div>
48+
<div>
49+
<mat-form-field>
50+
<input matInput type="text" formControlName="name" [id]="dbType.toLowerCase() + '-database'" placeholder="Database Name">
51+
<mat-error>This field is required</mat-error>
52+
</mat-form-field>
53+
</div>
54+
<div>
55+
<mat-form-field>
56+
<input matInput type="text" formControlName="user" [id]="dbType.toLowerCase() + '-user'" placeholder="User">
57+
</mat-form-field>
58+
</div>
59+
<div>
60+
<mat-form-field>
61+
<input matInput type="password" formControlName="password" [id]="dbType.toLowerCase() + '-password'" placeholder="Password">
62+
</mat-form-field>
63+
</div>
64+
<p>{{connectionString | async}}</p>
65+
<div style="text-align: center; margin-top: 20px">
66+
<button (click)="save()" [id]="dbType.toLowerCase() + '-databaseSave'" mat-raised-button color="accent" type="button" class="viewon-btn database" [disabled]="form.invalid">Save</button>
67+
<div [id]="dbType.toLowerCase() + '-spinner'"></div>
68+
</div>
69+
</ng-template>
10170
</form>
10271
</div>
10372
</div>

0 commit comments

Comments
 (0)