From acd9ebde3313a289983b2cd872f521cac08148f6 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 7 Jul 2017 23:49:29 +0100 Subject: [PATCH] Started reworking the usermanagement page #1456 #865 Started implimenting the Email Token functionality so we can send the user when creating a email with a token they can click on to set their username and password. --- .../IdentityResolver/UserIdentityManager.cs | 15 ++++++- src/Ombi.DependencyInjection/IocExtensions.cs | 1 + .../Settings/Models/OmbiSettings.cs | 1 + src/Ombi.Store/Context/IOmbiContext.cs | 1 + src/Ombi.Store/Context/OmbiContext.cs | 1 + src/Ombi.Store/Entities/EmailTokens.cs | 18 ++++++++ src/Ombi.Store/Repository/ITokenRepository.cs | 12 ++++++ src/Ombi.Store/Repository/TokenRepository.cs | 30 +++++++++++++ src/Ombi/ClientApp/app/app.module.ts | 12 ++---- .../ClientApp/app/interfaces/ISettings.ts | 3 +- .../app/requests/movierequests.component.html | 2 +- .../app/requests/tvrequests.component.html | 2 +- .../app/search/moviesearch.component.html | 2 +- .../app/search/tvsearch.component.html | 2 +- .../app/services/applications/plex.service.ts | 2 +- .../app/settings/ombi/ombi.component.html | 34 ++++++++------- .../app/settings/ombi/ombi.component.ts | 32 ++++++++------ .../app/settings/plex/plex.component.ts | 3 +- .../usermanagement-add.component.html | 42 +++++++++++++++++++ .../usermanagement-add.component.ts | 41 ++++++++++++++++++ .../usermanagement-edit.component.html | 38 +++++++---------- .../usermanagement-edit.component.ts | 31 ++++++++------ .../usermanagement.component.html | 6 +-- .../usermanagement/usermanagement.module.ts | 42 +++++++++++++++++++ src/Ombi/Controllers/IdentityController.cs | 2 +- src/Ombi/Styles/base.scss | 13 ++++-- 26 files changed, 298 insertions(+), 90 deletions(-) create mode 100644 src/Ombi.Store/Entities/EmailTokens.cs create mode 100644 src/Ombi.Store/Repository/ITokenRepository.cs create mode 100644 src/Ombi.Store/Repository/TokenRepository.cs create mode 100644 src/Ombi/ClientApp/app/usermanagement/usermanagement-add.component.html create mode 100644 src/Ombi/ClientApp/app/usermanagement/usermanagement-add.component.ts create mode 100644 src/Ombi/ClientApp/app/usermanagement/usermanagement.module.ts diff --git a/src/Ombi.Core/IdentityResolver/UserIdentityManager.cs b/src/Ombi.Core/IdentityResolver/UserIdentityManager.cs index 2802d70e5..37c0c2ab5 100644 --- a/src/Ombi.Core/IdentityResolver/UserIdentityManager.cs +++ b/src/Ombi.Core/IdentityResolver/UserIdentityManager.cs @@ -1,4 +1,5 @@ using AutoMapper; +using Hangfire; using Microsoft.AspNetCore.Cryptography.KeyDerivation; using Ombi.Core.Models; using Ombi.Store.Entities; @@ -13,14 +14,16 @@ namespace Ombi.Core.IdentityResolver { public class UserIdentityManager : IUserIdentityManager { - public UserIdentityManager(IUserRepository userRepository, IMapper mapper) + public UserIdentityManager(IUserRepository userRepository, IMapper mapper, ITokenRepository token) { UserRepository = userRepository; Mapper = mapper; + TokenRepository = token; } private IMapper Mapper { get; } private IUserRepository UserRepository { get; } + private ITokenRepository TokenRepository { get; } public async Task CredentialsValid(string username, string password) { @@ -50,11 +53,19 @@ namespace Ombi.Core.IdentityResolver { var user = Mapper.Map(userDto); user.Claims.RemoveAll(x => x.Type == ClaimTypes.Country); // This is a hack around the Mapping Profile - var result = HashPassword(user.Password); + var result = HashPassword(Guid.NewGuid().ToString("N")); // Since we do not allow the admin to set up the password. We send an email to the user user.Password = result.HashedPass; user.Salt = result.Salt; await UserRepository.CreateUser(user); + await TokenRepository.CreateToken(new EmailTokens + { + UserId = user.Id, + ValidUntil = DateTime.UtcNow.AddDays(7), + }); + + //BackgroundJob.Enqueue(() => ); + return Mapper.Map(user); } diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index 7860710c9..81050608f 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -83,6 +83,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(typeof(ISettingsService<>), typeof(SettingsService<>)); } public static void RegisterServices(this IServiceCollection services) diff --git a/src/Ombi.Settings/Settings/Models/OmbiSettings.cs b/src/Ombi.Settings/Settings/Models/OmbiSettings.cs index ccfa1b198..15263ff3a 100644 --- a/src/Ombi.Settings/Settings/Models/OmbiSettings.cs +++ b/src/Ombi.Settings/Settings/Models/OmbiSettings.cs @@ -7,6 +7,7 @@ public bool CollectAnalyticData { get; set; } public bool Wizard { get; set; } + public string ExternalUrl { get; set; } public string ApiKey { get; set; } } } \ No newline at end of file diff --git a/src/Ombi.Store/Context/IOmbiContext.cs b/src/Ombi.Store/Context/IOmbiContext.cs index 455539e8e..7bd8279b1 100644 --- a/src/Ombi.Store/Context/IOmbiContext.cs +++ b/src/Ombi.Store/Context/IOmbiContext.cs @@ -28,5 +28,6 @@ namespace Ombi.Store.Context DbSet ChildRequests { get; set; } DbSet MovieIssues { get; set; } DbSet TvIssues { get; set; } + DbSet EmailTokens { get; set; } } } \ No newline at end of file diff --git a/src/Ombi.Store/Context/OmbiContext.cs b/src/Ombi.Store/Context/OmbiContext.cs index 0330443a6..8d9902290 100644 --- a/src/Ombi.Store/Context/OmbiContext.cs +++ b/src/Ombi.Store/Context/OmbiContext.cs @@ -32,6 +32,7 @@ namespace Ombi.Store.Context public DbSet ChildRequests { get; set; } public DbSet MovieIssues { get; set; } public DbSet TvIssues { get; set; } + public DbSet EmailTokens { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) diff --git a/src/Ombi.Store/Entities/EmailTokens.cs b/src/Ombi.Store/Entities/EmailTokens.cs new file mode 100644 index 000000000..3412e376c --- /dev/null +++ b/src/Ombi.Store/Entities/EmailTokens.cs @@ -0,0 +1,18 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Ombi.Store.Entities +{ + [Table("EmailTokens")] + public class EmailTokens : Entity + { + public Guid Token { get; set; } + public int UserId { get; set; } + public DateTime ValidUntil { get; set; } + public bool Used { get; set; } + public DateTime DateUsed { get; set; } + + [ForeignKey(nameof(UserId))] + public User User { get; set; } + } +} diff --git a/src/Ombi.Store/Repository/ITokenRepository.cs b/src/Ombi.Store/Repository/ITokenRepository.cs new file mode 100644 index 000000000..db8b47547 --- /dev/null +++ b/src/Ombi.Store/Repository/ITokenRepository.cs @@ -0,0 +1,12 @@ +using System; +using System.Threading.Tasks; +using Ombi.Store.Entities; + +namespace Ombi.Store.Repository +{ + public interface ITokenRepository + { + Task CreateToken(EmailTokens token); + Task GetToken(Guid tokenId); + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Repository/TokenRepository.cs b/src/Ombi.Store/Repository/TokenRepository.cs new file mode 100644 index 000000000..fb51c3660 --- /dev/null +++ b/src/Ombi.Store/Repository/TokenRepository.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore; +using Ombi.Store.Context; +using Ombi.Store.Entities; +using System; +using System.Threading.Tasks; + +namespace Ombi.Store.Repository +{ + public class TokenRepository : ITokenRepository + { + public TokenRepository(IOmbiContext db) + { + Db = db; + } + + private IOmbiContext Db { get; } + + public async Task CreateToken(EmailTokens token) + { + token.Token = Guid.NewGuid(); + await Db.EmailTokens.AddAsync(token); + await Db.SaveChangesAsync(); + } + + public async Task GetToken(Guid tokenId) + { + return await Db.EmailTokens.FirstOrDefaultAsync(x => x.Token == tokenId); + } + } +} diff --git a/src/Ombi/ClientApp/app/app.module.ts b/src/Ombi/ClientApp/app/app.module.ts index a547cd915..a49844bd1 100644 --- a/src/Ombi/ClientApp/app/app.module.ts +++ b/src/Ombi/ClientApp/app/app.module.ts @@ -28,8 +28,6 @@ import { RequestCardComponent } from './request-grid/request-card.component'; import { LoginComponent } from './login/login.component'; import { LandingPageComponent } from './landingpage/landingpage.component'; -import { UserManagementComponent } from './usermanagement/usermanagement.component'; -import { UserManagementEditComponent } from './usermanagement/usermanagement-edit.component'; import { PageNotFoundComponent } from './errors/not-found.component'; // Services @@ -47,6 +45,7 @@ import { StatusService } from './services/status.service'; import { SettingsModule } from './settings/settings.module'; import { WizardModule } from './wizard/wizard.module'; import { SearchModule } from './search/search.module'; +import { UserManagementModule } from './usermanagement/usermanagement.module'; const routes: Routes = [ { path: '*', component: PageNotFoundComponent }, @@ -54,9 +53,7 @@ const routes: Routes = [ { path: 'requests', component: RequestComponent, canActivate: [AuthGuard] }, //{ path: 'requests-grid', component: RequestGridComponent }, { path: 'login', component: LoginComponent }, - { path: 'landingpage', component: LandingPageComponent }, - { path: 'usermanagement', component: UserManagementComponent, canActivate: [AuthGuard] }, - { path: 'usermanagement/edit/:id', component: UserManagementEditComponent, canActivate: [AuthGuard] }, + { path: 'landingpage', component: LandingPageComponent } ]; @NgModule({ @@ -82,7 +79,8 @@ const routes: Routes = [ MdCardModule, MdInputModule, MdTabsModule, - ReactiveFormsModule + ReactiveFormsModule, + UserManagementModule ], declarations: [ AppComponent, @@ -90,12 +88,10 @@ const routes: Routes = [ RequestComponent, LoginComponent, LandingPageComponent, - UserManagementComponent, MovieRequestsComponent, TvRequestsComponent, //RequestGridComponent, RequestCardComponent, - UserManagementEditComponent, ], providers: [ RequestService, diff --git a/src/Ombi/ClientApp/app/interfaces/ISettings.ts b/src/Ombi/ClientApp/app/interfaces/ISettings.ts index e38eda9d1..f00822267 100644 --- a/src/Ombi/ClientApp/app/interfaces/ISettings.ts +++ b/src/Ombi/ClientApp/app/interfaces/ISettings.ts @@ -14,7 +14,8 @@ export interface IOmbiSettings extends ISettings { //baseUrl:string, collectAnalyticData: boolean, wizard: boolean, - apiKey: string + apiKey: string, + externalUrl:string, } export interface IEmbySettings extends IExternalSettings { diff --git a/src/Ombi/ClientApp/app/requests/movierequests.component.html b/src/Ombi/ClientApp/app/requests/movierequests.component.html index 87cfb657a..57ee08304 100644 --- a/src/Ombi/ClientApp/app/requests/movierequests.component.html +++ b/src/Ombi/ClientApp/app/requests/movierequests.component.html @@ -1,6 +1,6 @@ 
- +

diff --git a/src/Ombi/ClientApp/app/requests/tvrequests.component.html b/src/Ombi/ClientApp/app/requests/tvrequests.component.html index 49cb44395..17d6e97f0 100644 --- a/src/Ombi/ClientApp/app/requests/tvrequests.component.html +++ b/src/Ombi/ClientApp/app/requests/tvrequests.component.html @@ -1,6 +1,6 @@ 
- +

diff --git a/src/Ombi/ClientApp/app/search/moviesearch.component.html b/src/Ombi/ClientApp/app/search/moviesearch.component.html index 4984cc8e6..b09b1eb25 100644 --- a/src/Ombi/ClientApp/app/search/moviesearch.component.html +++ b/src/Ombi/ClientApp/app/search/moviesearch.component.html @@ -1,7 +1,7 @@ 
- +