From 7a85f8ab7cf796a2b44df1928cb5e1a8fecdeeae Mon Sep 17 00:00:00 2001 From: tidusjar Date: Sat, 22 May 2021 23:03:50 +0100 Subject: [PATCH 1/3] Added back the ability for users with ManageOwnRequests role to manage their requests! #4203 --- .../tv-requests-panel.component.html | 5 +++-- .../tv-requests-panel.component.ts | 8 ++++--- .../components/tv/tv-details.component.html | 2 +- .../components/tv/tv-details.component.ts | 2 ++ .../movies-grid/movies-grid.component.html | 2 +- .../movies-grid/movies-grid.component.ts | 22 ++++++++++--------- .../options/request-options.component.html | 6 ++--- .../components/requests-list.component.ts | 5 +++-- 8 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/Ombi/ClientApp/src/app/media-details/components/tv/panels/tv-requests/tv-requests-panel.component.html b/src/Ombi/ClientApp/src/app/media-details/components/tv/panels/tv-requests/tv-requests-panel.component.html index 8bca28fb5..0945c5a51 100644 --- a/src/Ombi/ClientApp/src/app/media-details/components/tv/panels/tv-requests/tv-requests-panel.component.html +++ b/src/Ombi/ClientApp/src/app/media-details/components/tv/panels/tv-requests/tv-requests-panel.component.html @@ -69,10 +69,11 @@ - - +
+ +
diff --git a/src/Ombi/ClientApp/src/app/media-details/components/tv/panels/tv-requests/tv-requests-panel.component.ts b/src/Ombi/ClientApp/src/app/media-details/components/tv/panels/tv-requests/tv-requests-panel.component.ts index e51414902..d4e8f894c 100644 --- a/src/Ombi/ClientApp/src/app/media-details/components/tv/panels/tv-requests/tv-requests-panel.component.ts +++ b/src/Ombi/ClientApp/src/app/media-details/components/tv/panels/tv-requests/tv-requests-panel.component.ts @@ -1,9 +1,10 @@ import { Component, Input } from "@angular/core"; import { IChildRequests, RequestType } from "../../../../../interfaces"; -import { RequestService } from "../../../../../services/request.service"; -import { MessageService } from "../../../../../services"; -import { MatDialog } from "@angular/material/dialog"; + import { DenyDialogComponent } from "../../../shared/deny-dialog/deny-dialog.component"; +import { MatDialog } from "@angular/material/dialog"; +import { MessageService } from "../../../../../services"; +import { RequestService } from "../../../../../services/request.service"; import { RequestServiceV2 } from "../../../../../services/requestV2.service"; @Component({ @@ -14,6 +15,7 @@ import { RequestServiceV2 } from "../../../../../services/requestV2.service"; export class TvRequestsPanelComponent { @Input() public tvRequest: IChildRequests[]; @Input() public isAdmin: boolean; + @Input() public manageOwnRequests: boolean; public displayedColumns: string[] = ['number', 'title', 'airDate', 'status']; diff --git a/src/Ombi/ClientApp/src/app/media-details/components/tv/tv-details.component.html b/src/Ombi/ClientApp/src/app/media-details/components/tv/tv-details.component.html index d0590ad1b..dc8902a1b 100644 --- a/src/Ombi/ClientApp/src/app/media-details/components/tv/tv-details.component.html +++ b/src/Ombi/ClientApp/src/app/media-details/components/tv/tv-details.component.html @@ -126,7 +126,7 @@ {{'Requests.Title' | translate}} - + diff --git a/src/Ombi/ClientApp/src/app/media-details/components/tv/tv-details.component.ts b/src/Ombi/ClientApp/src/app/media-details/components/tv/tv-details.component.ts index f9b686a48..7b1c98ba8 100644 --- a/src/Ombi/ClientApp/src/app/media-details/components/tv/tv-details.component.ts +++ b/src/Ombi/ClientApp/src/app/media-details/components/tv/tv-details.component.ts @@ -27,6 +27,7 @@ export class TvDetailsComponent implements OnInit { public showRequest: ITvRequests; public fromSearch: boolean; public isAdmin: boolean; + public manageOwnRequests: boolean; public advancedOptions: IAdvancedData; public showAdvanced: boolean; // Set on the UI public requestType = RequestType.tvShow; @@ -53,6 +54,7 @@ export class TvDetailsComponent implements OnInit { this.issuesEnabled = this.settingsState.getIssue(); this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser"); + this.manageOwnRequests = this.auth.hasRole('ManageOwnRequests'); if (this.isAdmin) { this.showAdvanced = await this.sonarrService.isEnabled(); diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html index e8926b69a..00cd67d6e 100644 --- a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html +++ b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html @@ -76,7 +76,7 @@ - + diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts index c73084c2b..69fd0da77 100644 --- a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts +++ b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts @@ -1,18 +1,18 @@ -import { Component, AfterViewInit, ViewChild, EventEmitter, Output, ChangeDetectorRef, OnInit } from "@angular/core"; +import { AfterViewInit, ChangeDetectorRef, Component, EventEmitter, OnInit, Output, ViewChild } from "@angular/core"; import { IMovieRequests, IRequestEngineResult, IRequestsViewModel } from "../../../interfaces"; -import { MatPaginator } from "@angular/material/paginator"; -import { MatSort } from "@angular/material/sort"; -import { merge, Observable, of as observableOf, forkJoin } from 'rxjs'; +import { NotificationService, RequestService } from "../../../services"; +import { Observable, forkJoin, merge, of as observableOf } from 'rxjs'; import { catchError, map, startWith, switchMap } from 'rxjs/operators'; -import { RequestServiceV2 } from "../../../services/requestV2.service"; import { AuthService } from "../../../auth/auth.service"; -import { StorageService } from "../../../shared/storage/storage-service"; +import { MatPaginator } from "@angular/material/paginator"; +import { MatSort } from "@angular/material/sort"; +import { MatTableDataSource } from "@angular/material/table"; import { RequestFilterType } from "../../models/RequestFilterType"; +import { RequestServiceV2 } from "../../../services/requestV2.service"; import { SelectionModel } from "@angular/cdk/collections"; -import { NotificationService, RequestService } from "../../../services"; +import { StorageService } from "../../../shared/storage/storage-service"; import { TranslateService } from "@ngx-translate/core"; -import { MatTableDataSource } from "@angular/material/table"; @Component({ templateUrl: "./movies-grid.component.html", @@ -26,6 +26,7 @@ export class MoviesGridComponent implements OnInit, AfterViewInit { public displayedColumns: string[] = ['title', 'requestedUser.requestedBy', 'status', 'requestStatus','requestedDate', 'actions']; public gridCount: string = "15"; public isAdmin: boolean; + public manageOwnRequests: boolean; public defaultSort: string = "requestedDate"; public defaultOrder: string = "desc"; public currentFilter: RequestFilterType = RequestFilterType.All; @@ -39,7 +40,7 @@ export class MoviesGridComponent implements OnInit, AfterViewInit { private storageKeyGridCount = "Movie_DefaultGridCount"; private storageKeyCurrentFilter = "Movie_DefaultFilter"; - @Output() public onOpenOptions = new EventEmitter<{ request: any, filter: any, onChange: any }>(); + @Output() public onOpenOptions = new EventEmitter<{ request: any, filter: any, onChange: any, manageOwnRequests: boolean, isAdmin: boolean }>(); @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; @@ -53,6 +54,7 @@ export class MoviesGridComponent implements OnInit, AfterViewInit { public ngOnInit() { this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser"); + this.manageOwnRequests = this.auth.hasRole("ManageOwnRequests") if (this.isAdmin) { this.displayedColumns.unshift('select'); } @@ -135,7 +137,7 @@ export class MoviesGridComponent implements OnInit, AfterViewInit { this.ref.detectChanges(); }; - this.onOpenOptions.emit({ request: request, filter: filter, onChange: onChange }); + this.onOpenOptions.emit({ request: request, filter: filter, onChange: onChange, manageOwnRequests: this.manageOwnRequests, isAdmin: this.isAdmin }); } public switchFilter(type: RequestFilterType) { diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/options/request-options.component.html b/src/Ombi/ClientApp/src/app/requests-list/components/options/request-options.component.html index 399b35e16..ac974ece8 100644 --- a/src/Ombi/ClientApp/src/app/requests-list/components/options/request-options.component.html +++ b/src/Ombi/ClientApp/src/app/requests-list/components/options/request-options.component.html @@ -1,11 +1,11 @@ - + {{'Requests.RequestPanel.Delete' | translate}} - + {{'Requests.RequestPanel.Approve' | translate}} - + {{'Requests.RequestPanel.ChangeAvailability' | translate}} \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/requests-list.component.ts b/src/Ombi/ClientApp/src/app/requests-list/components/requests-list.component.ts index 6cdd84af3..5487a08a1 100644 --- a/src/Ombi/ClientApp/src/app/requests-list/components/requests-list.component.ts +++ b/src/Ombi/ClientApp/src/app/requests-list/components/requests-list.component.ts @@ -1,8 +1,9 @@ import { Component, ViewChild } from "@angular/core"; + import { MatBottomSheet } from "@angular/material/bottom-sheet"; +import { MoviesGridComponent } from "./movies-grid/movies-grid.component"; import { RequestOptionsComponent } from "./options/request-options.component"; import { UpdateType } from "../models/UpdateType"; -import { MoviesGridComponent } from "./movies-grid/movies-grid.component"; @Component({ templateUrl: "./requests-list.component.html", @@ -12,7 +13,7 @@ export class RequestsListComponent { constructor(private bottomSheet: MatBottomSheet) { } - public onOpenOptions(event: { request: any, filter: any, onChange: any }) { + public onOpenOptions(event: { request: any, filter: any, onChange: any, manageOwnRequests: boolean, isAdmin: boolean }) { const ref = this.bottomSheet.open(RequestOptionsComponent, { data: { id: event.request.id, type: event.request.requestType, canApprove: event.request.canApprove } }); ref.afterDismissed().subscribe((result) => { From dee2abcb382aa262293cffa086f0775f01269f48 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Sat, 22 May 2021 23:05:32 +0100 Subject: [PATCH 2/3] Added the ability for the admin to be able to copy the app link to send to users that have the app installed so they can automatically be authenticated --- .../usermanagement-user.component.html | 5 ++-- .../usermanagement-user.component.ts | 26 ++++++++++++++----- .../usermanagement/usermanagement.module.ts | 26 ++++++++----------- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/Ombi/ClientApp/src/app/usermanagement/usermanagement-user.component.html b/src/Ombi/ClientApp/src/app/usermanagement/usermanagement-user.component.html index 74770a3d8..e247f0ea1 100644 --- a/src/Ombi/ClientApp/src/app/usermanagement/usermanagement-user.component.html +++ b/src/Ombi/ClientApp/src/app/usermanagement/usermanagement-user.component.html @@ -145,13 +145,14 @@
-
+
- +
diff --git a/src/Ombi/ClientApp/src/app/usermanagement/usermanagement-user.component.ts b/src/Ombi/ClientApp/src/app/usermanagement/usermanagement-user.component.ts index bfbabd0a3..c091d3861 100644 --- a/src/Ombi/ClientApp/src/app/usermanagement/usermanagement-user.component.ts +++ b/src/Ombi/ClientApp/src/app/usermanagement/usermanagement-user.component.ts @@ -1,9 +1,10 @@ -import { Location } from "@angular/common"; -import { AfterViewInit, Component, OnInit } from "@angular/core"; -import { ActivatedRoute, Router } from "@angular/router"; +import { ActivatedRoute, Router } from "@angular/router"; +import { Component, OnInit } from "@angular/core"; +import { ICheckbox, ICustomizationSettings, INotificationAgent, INotificationPreferences, IRadarrProfile, IRadarrRootFolder, ISonarrProfile, ISonarrRootFolder, IUser, UserType } from "../interfaces"; +import { IdentityService, MessageService, RadarrService, SettingsService, SonarrService } from "../services"; -import { ICheckbox, INotificationAgent, INotificationPreferences, IRadarrProfile, IRadarrRootFolder, ISonarrProfile, ISonarrRootFolder, IUser, UserType } from "../interfaces"; -import { IdentityService, RadarrService, SonarrService, MessageService } from "../services"; +import { Clipboard } from '@angular/cdk/clipboard'; +import { Location } from "@angular/common"; @Component({ templateUrl: "./usermanagement-user.component.html", @@ -27,12 +28,17 @@ export class UserManagementUserComponent implements OnInit { public countries: string[]; + private customization: ICustomizationSettings; + private accessToken: string; + constructor(private identityService: IdentityService, private notificationService: MessageService, + private readonly settingsService: SettingsService, private router: Router, private route: ActivatedRoute, private sonarrService: SonarrService, private radarrService: RadarrService, + private clipboard: Clipboard, private location: Location) { this.route.params.subscribe((params: any) => { @@ -60,6 +66,9 @@ export class UserManagementUserComponent implements OnInit { this.radarrService.getQualityProfilesFromSettings().subscribe(x => this.radarrQualities = x); this.radarrService.getRootFoldersFromSettings().subscribe(x => this.radarrRootFolders = x); + this.settingsService.getCustomization().subscribe(x => this.customization = x); + this.identityService.getAccessToken().subscribe(x => this.accessToken = x); + if(!this.edit) { this.user = { alias: "", @@ -178,7 +187,12 @@ export class UserManagementUserComponent implements OnInit { } }); } - + + public async appLink() { + this.clipboard.copy(`ombi://${this.customization.applicationUrl}|${this.accessToken}`); + this.notificationService.send("Copied!"); + } + public back() { this.location.back(); } diff --git a/src/Ombi/ClientApp/src/app/usermanagement/usermanagement.module.ts b/src/Ombi/ClientApp/src/app/usermanagement/usermanagement.module.ts index 885e6e2e4..a55702101 100644 --- a/src/Ombi/ClientApp/src/app/usermanagement/usermanagement.module.ts +++ b/src/Ombi/ClientApp/src/app/usermanagement/usermanagement.module.ts @@ -1,23 +1,19 @@ -import { CommonModule } from "@angular/common"; -import { NgModule } from "@angular/core"; -import { FormsModule, ReactiveFormsModule } from "@angular/forms"; -import { RouterModule, Routes } from "@angular/router"; -import { ConfirmDialogModule } from "primeng/confirmdialog"; -import { MultiSelectModule } from "primeng/multiselect"; -import { SidebarModule } from "primeng/sidebar"; -import { TooltipModule } from "primeng/tooltip"; - -import { UserManagementUserComponent } from "./usermanagement-user.component"; -import { UserManagementComponent } from "./usermanagement.component"; - -import { PipeModule } from "../pipes/pipe.module"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { IdentityService, PlexService, RadarrService, SonarrService } from "../services"; +import { RouterModule, Routes } from "@angular/router"; import { AuthGuard } from "../auth/auth.guard"; - +import { CommonModule } from "@angular/common"; +import { ConfirmDialogModule } from "primeng/confirmdialog"; +import { MultiSelectModule } from "primeng/multiselect"; +import { NgModule } from "@angular/core"; import { OrderModule } from "ngx-order-pipe"; - +import { PipeModule } from "../pipes/pipe.module"; import { SharedModule } from "../shared/shared.module"; +import { SidebarModule } from "primeng/sidebar"; +import { TooltipModule } from "primeng/tooltip"; +import { UserManagementComponent } from "./usermanagement.component"; +import { UserManagementUserComponent } from "./usermanagement-user.component"; const routes: Routes = [ { path: "", component: UserManagementComponent, canActivate: [AuthGuard] }, From b18f5bf7b5cfa1186b35b08f59755fdf61b9c22c Mon Sep 17 00:00:00 2001 From: tidusjar Date: Sat, 22 May 2021 23:15:48 +0100 Subject: [PATCH 3/3] Added the Open Mobile app to the navbar when on small devices (mobile) --- src/Ombi/ClientApp/src/app/app.component.html | 12 +++++++- src/Ombi/ClientApp/src/app/app.component.ts | 2 ++ .../src/app/my-nav/my-nav.component.html | 7 +++++ .../src/app/my-nav/my-nav.component.scss | 11 +++++++ .../src/app/my-nav/my-nav.component.ts | 29 +++++++++++++------ 5 files changed, 51 insertions(+), 10 deletions(-) diff --git a/src/Ombi/ClientApp/src/app/app.component.html b/src/Ombi/ClientApp/src/app/app.component.html index a8e527a6b..351b8ef49 100644 --- a/src/Ombi/ClientApp/src/app/app.component.html +++ b/src/Ombi/ClientApp/src/app/app.component.html @@ -170,7 +170,17 @@
- + diff --git a/src/Ombi/ClientApp/src/app/app.component.ts b/src/Ombi/ClientApp/src/app/app.component.ts index 356107039..038fcc7d7 100644 --- a/src/Ombi/ClientApp/src/app/app.component.ts +++ b/src/Ombi/ClientApp/src/app/app.component.ts @@ -33,6 +33,7 @@ export class AppComponent implements OnInit { public applicationName: string = "Ombi" public isAdmin: boolean; public username: string; + public accessToken: string; private hubConnected: boolean; @@ -55,6 +56,7 @@ export class AppComponent implements OnInit { if (this.authService.loggedIn()) { this.user = this.authService.claims(); this.username = this.user.name; + this.identity.getAccessToken().subscribe(x => this.accessToken = x); if (!this.hubConnected) { this.signalrNotification.initialize(); this.hubConnected = true; diff --git a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.html b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.html index f73c9bbc8..95f31198b 100644 --- a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.html +++ b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.html @@ -28,6 +28,13 @@
+ + + +  {{ 'NavigationBar.OpenMobileApp' | translate }} + + diff --git a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.scss b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.scss index 753759af1..f76109b96 100644 --- a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.scss +++ b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.scss @@ -107,10 +107,21 @@ margin-right:5px; } +#nav-openMobile { + display: none; +} + @media (max-width: 600px) { .profile-username{ display:none; } + +} + +@media (max-width: 950px) { + #nav-openMobile { + display: block; + } } .profile-img img { diff --git a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.ts b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.ts index d65307bdb..57bfaca91 100644 --- a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.ts +++ b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.ts @@ -1,16 +1,17 @@ -import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; -import { INavBar } from '../interfaces/ICommon'; -import { StorageService } from '../shared/storage/storage-service'; -import { SettingsService, SettingsStateService } from '../services'; -import { MatSlideToggleChange } from '@angular/material/slide-toggle'; -import { SearchFilter } from './SearchFilter'; -import { Md5 } from 'ts-md5/dist/md5'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { IUser, RequestType, UserType } from '../interfaces'; +import { SettingsService, SettingsStateService } from '../services'; + import { FilterService } from '../discover/services/filter-service'; import { ILocalUser } from '../auth/IUserLogin'; +import { INavBar } from '../interfaces/ICommon'; +import { MatSlideToggleChange } from '@angular/material/slide-toggle'; +import { Md5 } from 'ts-md5/dist/md5'; +import { Observable } from 'rxjs'; +import { SearchFilter } from './SearchFilter'; +import { StorageService } from '../shared/storage/storage-service'; +import { map } from 'rxjs/operators'; export enum SearchFilterType { Movie = 1, @@ -34,6 +35,8 @@ export class MyNavComponent implements OnInit { @Input() public showNav: boolean; @Input() public applicationName: string; @Input() public applicationLogo: string; + @Input() public applicationUrl: string; + @Input() public accessToken: string; @Input() public username: string; @Input() public isAdmin: string; @Input() public email: string; @@ -122,4 +125,12 @@ export class MyNavComponent implements OnInit { var fallback = this.applicationLogo ? this.applicationLogo : 'https://raw.githubusercontent.com/Ombi-app/Ombi/gh-pages/img/android-chrome-512x512.png'; return `https://www.gravatar.com/avatar/${this.emailHash}?d=${fallback}`; } + + public openMobileApp(event: any) { + event.preventDefault(); + + const url = `ombi://${this.applicationUrl}|${this.accessToken}`; + window.location.assign(url); +} + }