mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-14 01:02:57 -07:00
parent
51fbd56c44
commit
ace90da7ed
15 changed files with 383 additions and 64 deletions
|
@ -90,6 +90,7 @@ namespace Ombi.DependencyInjection
|
|||
{
|
||||
services.AddTransient<IRequestServiceMain, RequestService>();
|
||||
services.AddSingleton<INotificationService, NotificationService>();
|
||||
services.AddSingleton<IEmailProvider, GenericEmailProvider>();
|
||||
services.AddTransient<INotificationHelper, NotificationHelper>();
|
||||
|
||||
|
||||
|
|
|
@ -16,10 +16,11 @@ namespace Ombi.Notifications.Agents
|
|||
{
|
||||
public class EmailNotification : BaseNotification<EmailNotificationSettings>, IEmailNotification
|
||||
{
|
||||
public EmailNotification(ISettingsService<EmailNotificationSettings> settings, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t) : base(settings, r, m, t)
|
||||
public EmailNotification(ISettingsService<EmailNotificationSettings> settings, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, IEmailProvider prov) : base(settings, r, m, t)
|
||||
{
|
||||
EmailProvider = prov;
|
||||
}
|
||||
|
||||
private IEmailProvider EmailProvider { get; }
|
||||
public override string NotificationName => nameof(EmailNotification);
|
||||
|
||||
protected override bool ValidateConfiguration(EmailNotificationSettings settings)
|
||||
|
@ -166,44 +167,7 @@ namespace Ombi.Notifications.Agents
|
|||
|
||||
protected override async Task Send(NotificationMessage model, EmailNotificationSettings settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
var body = new BodyBuilder
|
||||
{
|
||||
HtmlBody = model.Message,
|
||||
//TextBody = model.Other["PlainTextBody"]
|
||||
};
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
Body = body.ToMessageBody(),
|
||||
Subject = model.Subject
|
||||
};
|
||||
message.From.Add(new MailboxAddress(settings.Sender, settings.Sender));
|
||||
message.To.Add(new MailboxAddress(model.To, model.To));
|
||||
|
||||
using (var client = new SmtpClient())
|
||||
{
|
||||
client.Connect(settings.Host, settings.Port); // Let MailKit figure out the correct SecureSocketOptions.
|
||||
|
||||
// Note: since we don't have an OAuth2 token, disable
|
||||
// the XOAUTH2 authentication mechanism.
|
||||
client.AuthenticationMechanisms.Remove("XOAUTH2");
|
||||
|
||||
if (settings.Authentication)
|
||||
{
|
||||
client.Authenticate(settings.Username, settings.Password);
|
||||
}
|
||||
//Log.Info("sending message to {0} \r\n from: {1}\r\n Are we authenticated: {2}", message.To, message.From, client.IsAuthenticated);
|
||||
await client.SendAsync(message);
|
||||
await client.DisconnectAsync(true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//Log.Error(e);
|
||||
throw new InvalidOperationException(e.Message);
|
||||
}
|
||||
await EmailProvider.Send(model, settings);
|
||||
}
|
||||
|
||||
protected override async Task Test(NotificationOptions model, EmailNotificationSettings settings)
|
||||
|
|
54
src/Ombi.Notifications/GenericEmailProvider.cs
Normal file
54
src/Ombi.Notifications/GenericEmailProvider.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MailKit.Net.Smtp;
|
||||
using MimeKit;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Settings.Settings.Models.Notifications;
|
||||
|
||||
namespace Ombi.Notifications
|
||||
{
|
||||
public class GenericEmailProvider : IEmailProvider
|
||||
{
|
||||
public async Task Send(NotificationMessage model, EmailNotificationSettings settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
var body = new BodyBuilder
|
||||
{
|
||||
HtmlBody = model.Message,
|
||||
//TextBody = model.Other["PlainTextBody"]
|
||||
};
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
Body = body.ToMessageBody(),
|
||||
Subject = model.Subject
|
||||
};
|
||||
message.From.Add(new MailboxAddress(settings.Sender, settings.Sender));
|
||||
message.To.Add(new MailboxAddress(model.To, model.To));
|
||||
|
||||
using (var client = new SmtpClient())
|
||||
{
|
||||
client.Connect(settings.Host, settings.Port); // Let MailKit figure out the correct SecureSocketOptions.
|
||||
|
||||
// Note: since we don't have an OAuth2 token, disable
|
||||
// the XOAUTH2 authentication mechanism.
|
||||
client.AuthenticationMechanisms.Remove("XOAUTH2");
|
||||
|
||||
if (settings.Authentication)
|
||||
{
|
||||
client.Authenticate(settings.Username, settings.Password);
|
||||
}
|
||||
//Log.Info("sending message to {0} \r\n from: {1}\r\n Are we authenticated: {2}", message.To, message.From, client.IsAuthenticated);
|
||||
await client.SendAsync(message);
|
||||
await client.DisconnectAsync(true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//Log.Error(e);
|
||||
throw new InvalidOperationException(e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
src/Ombi.Notifications/IEmailProvider.cs
Normal file
11
src/Ombi.Notifications/IEmailProvider.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System.Threading.Tasks;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Settings.Settings.Models.Notifications;
|
||||
|
||||
namespace Ombi.Notifications
|
||||
{
|
||||
public interface IEmailProvider
|
||||
{
|
||||
Task Send(NotificationMessage model, EmailNotificationSettings settings);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ import { RouterModule, Routes } from '@angular/router';
|
|||
import { HttpModule } from '@angular/http';
|
||||
|
||||
// Third Party
|
||||
import { ButtonModule, DialogModule } from 'primeng/primeng';
|
||||
import { ButtonModule, DialogModule, CaptchaModule } from 'primeng/primeng';
|
||||
import { GrowlModule } from 'primeng/components/growl/growl';
|
||||
import { DataTableModule, SharedModule } from 'primeng/primeng';
|
||||
//import { DragulaModule, DragulaService } from 'ng2-dragula/ng2-dragula';
|
||||
|
@ -17,6 +17,8 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
|||
import { AppComponent } from './app.component';
|
||||
|
||||
import { LoginComponent } from './login/login.component';
|
||||
import { ResetPasswordComponent } from './login/resetpassword.component';
|
||||
import { TokenResetPasswordComponent } from './login/tokenresetpassword.component';
|
||||
import { LandingPageComponent } from './landingpage/landingpage.component';
|
||||
import { PageNotFoundComponent } from './errors/not-found.component';
|
||||
|
||||
|
@ -44,6 +46,7 @@ const routes: Routes = [
|
|||
|
||||
//{ path: 'requests-grid', component: RequestGridComponent },
|
||||
{ path: 'login', component: LoginComponent },
|
||||
{ path: 'reset', component: ResetPasswordComponent },
|
||||
{ path: 'landingpage', component: LandingPageComponent }
|
||||
];
|
||||
|
||||
|
@ -71,13 +74,16 @@ const routes: Routes = [
|
|||
MdTabsModule,
|
||||
ReactiveFormsModule,
|
||||
UserManagementModule,
|
||||
RequestsModule
|
||||
RequestsModule,
|
||||
CaptchaModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
PageNotFoundComponent,
|
||||
LoginComponent,
|
||||
LandingPageComponent,
|
||||
ResetPasswordComponent,
|
||||
TokenResetPasswordComponent
|
||||
],
|
||||
providers: [
|
||||
RequestService,
|
||||
|
|
|
@ -30,3 +30,8 @@ export interface IUpdateLocalUser extends IUser {
|
|||
confirmNewPassword: string
|
||||
}
|
||||
|
||||
export interface IResetPasswordToken{
|
||||
email:string,
|
||||
token:string,
|
||||
password:string
|
||||
}
|
|
@ -17,8 +17,8 @@ include the remember me checkbox
|
|||
<input type="password" id="inputPassword" class="form-control" formControlName="password" placeholder="Password">
|
||||
<button class="btn btn-success-outline" [disabled]="form.invalid" type="submit">Sign in</button>
|
||||
</form><!-- /form -->
|
||||
<a href="#" class="forgot-password">
|
||||
Forgot the password?
|
||||
<a [routerLink]="['/reset']" class="forgot-password">
|
||||
Reset your password?
|
||||
</a>
|
||||
</div><!-- /card-container -->
|
||||
</div><!-- /container -->
|
||||
|
|
20
src/Ombi/ClientApp/app/login/resetpassword.component.html
Normal file
20
src/Ombi/ClientApp/app/login/resetpassword.component.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
<!--
|
||||
you can substitue the span of reauth email for a input with the email and
|
||||
include the remember me checkbox
|
||||
-->
|
||||
<div *ngIf="form && customizationSettings">
|
||||
<div class="container" id="login">
|
||||
<div class="card card-container">
|
||||
<!-- <img class="profile-img-card" src="//lh3.googleusercontent.com/-6V8xOA6M7BA/AAAAAAAAAAI/AAAAAAAAAAA/rzlHcD0KYwo/photo.jpg?sz=120" alt="" /> -->
|
||||
<div *ngIf="!customizationSettings.logo"><img id="profile-img" class="profile-img-card" src="/images/ms-icon-150x150.png" /></div>
|
||||
<div *ngIf="customizationSettings.logo"><img id="profile-img" class="profile-img-card" [src]="customizationSettings.logo" /></div>
|
||||
<p id="profile-name" class="profile-name-card"></p>
|
||||
|
||||
<form class="form-signin" novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">
|
||||
<input type="email" id="inputEmail" class="form-control" formControlName="email" placeholder="Email Address" autofocus>
|
||||
<button class="btn btn-success-outline" [disabled]="form.invalid" type="submit">Reset Password</button>
|
||||
|
||||
</form><!-- /form -->
|
||||
</div><!-- /card-container -->
|
||||
</div><!-- /container -->
|
||||
</div>
|
42
src/Ombi/ClientApp/app/login/resetpassword.component.ts
Normal file
42
src/Ombi/ClientApp/app/login/resetpassword.component.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormGroup, Validators, FormBuilder } from '@angular/forms';
|
||||
|
||||
import { IdentityService } from '../services/identity.service';
|
||||
import { NotificationService } from '../services/notification.service';
|
||||
import { SettingsService } from '../services/settings.service';
|
||||
import { ICustomizationSettings } from '../interfaces/ISettings';
|
||||
|
||||
@Component({
|
||||
templateUrl: './resetpassword.component.html',
|
||||
styleUrls: ['./login.component.scss']
|
||||
})
|
||||
export class ResetPasswordComponent implements OnInit {
|
||||
|
||||
|
||||
constructor(private identityService: IdentityService, private notify: NotificationService,
|
||||
private fb: FormBuilder, private settingsService: SettingsService) {
|
||||
this.form = this.fb.group({
|
||||
email: ["", [Validators.required]],
|
||||
});
|
||||
}
|
||||
|
||||
form: FormGroup;
|
||||
customizationSettings: ICustomizationSettings;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.settingsService.getCustomization().subscribe(x => this.customizationSettings = x);
|
||||
}
|
||||
|
||||
|
||||
onSubmit(form: FormGroup): void {
|
||||
if (form.invalid) {
|
||||
this.notify.error("Validation", "Email address is required");
|
||||
return
|
||||
}
|
||||
this.identityService.submitResetPassword(form.value.email).subscribe(x => {
|
||||
x.errors.forEach((val) => {
|
||||
this.notify.success("Password Reset", val);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<!--
|
||||
you can substitue the span of reauth email for a input with the email and
|
||||
include the remember me checkbox
|
||||
-->
|
||||
<div *ngIf="form && customizationSettings">
|
||||
<div class="container" id="login">
|
||||
<div class="card card-container">
|
||||
<!-- <img class="profile-img-card" src="//lh3.googleusercontent.com/-6V8xOA6M7BA/AAAAAAAAAAI/AAAAAAAAAAA/rzlHcD0KYwo/photo.jpg?sz=120" alt="" /> -->
|
||||
<div *ngIf="!customizationSettings.logo"><img id="profile-img" class="profile-img-card" src="/images/ms-icon-150x150.png" /></div>
|
||||
<div *ngIf="customizationSettings.logo"><img id="profile-img" class="profile-img-card" [src]="customizationSettings.logo" /></div>
|
||||
<p id="profile-name" class="profile-name-card"></p>
|
||||
|
||||
|
||||
<div *ngIf="form.value.password !== form.value.confirmPassword" class="alert alert-danger">The passwords do not match</div>
|
||||
<div *ngIf="form.invalid && form.dirty" class="alert alert-danger">
|
||||
|
||||
<div *ngIf="form.get('password').hasError('required')">The Password is required</div>
|
||||
<div *ngIf="form.get('email').hasError('required')">The Email is required</div>
|
||||
<div *ngIf="form.get('confirmPassword').hasError('required')">The Confirm Password is required</div>
|
||||
</div>
|
||||
|
||||
<form class="form-signin" novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">
|
||||
<input type="email" id="inputEmail" class="form-control" formControlName="email" placeholder="Email Address" autofocus>
|
||||
<input type="password" class="form-control" formControlName="password">
|
||||
<input type="password" class="form-control" formControlName="confirmPassword">
|
||||
<button class="btn btn-success-outline" [disabled]="form.invalid || !captcha" type="submit">Reset Password</button>
|
||||
|
||||
</form>
|
||||
<!-- /form -->
|
||||
<a href="#" class="forgot-password">
|
||||
Forgot the password?
|
||||
</a>
|
||||
</div>
|
||||
<!-- /card-container -->
|
||||
</div>
|
||||
<!-- /container -->
|
||||
</div>
|
57
src/Ombi/ClientApp/app/login/tokenresetpassword.component.ts
Normal file
57
src/Ombi/ClientApp/app/login/tokenresetpassword.component.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { FormGroup, Validators, FormBuilder } from '@angular/forms';
|
||||
|
||||
import { IdentityService } from '../services/identity.service';
|
||||
import { NotificationService } from '../services/notification.service';
|
||||
import { SettingsService } from '../services/settings.service';
|
||||
import { ICustomizationSettings } from '../interfaces/ISettings';
|
||||
|
||||
@Component({
|
||||
templateUrl: './tokenresetpassword.component.html',
|
||||
styleUrls: ['./login.component.scss']
|
||||
})
|
||||
export class TokenResetPasswordComponent implements OnInit {
|
||||
constructor(private identityService: IdentityService, private router: Router, private route: ActivatedRoute, private notify: NotificationService,
|
||||
private fb: FormBuilder, private settingsService: SettingsService) {
|
||||
|
||||
this.route.params
|
||||
.subscribe(params => {
|
||||
this.form = this.fb.group({
|
||||
email: ["", [Validators.required]],
|
||||
password: ["", [Validators.required]],
|
||||
confirmPassword: ["", [Validators.required]],
|
||||
token: [params['token']]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
form: FormGroup;
|
||||
customizationSettings: ICustomizationSettings;
|
||||
|
||||
|
||||
ngOnInit(): void {
|
||||
this.settingsService.getCustomization().subscribe(x => this.customizationSettings = x);
|
||||
}
|
||||
|
||||
|
||||
onSubmit(form: FormGroup): void {
|
||||
if (form.invalid) {
|
||||
this.notify.error("Validation", "Email address is required");
|
||||
return
|
||||
}
|
||||
|
||||
this.identityService.resetPassword(form.value).subscribe(x => {
|
||||
if (x.successful) {
|
||||
this.notify.success("Success", `Your Password has been reset`)
|
||||
this.router.navigate(['login']);
|
||||
} else {
|
||||
x.errors.forEach((val) => {
|
||||
this.notify.error("Error", val);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ import { Http } from '@angular/http';
|
|||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { ServiceAuthHelpers } from './service.helpers';
|
||||
import { IUser, IUpdateLocalUser, ICheckbox, IIdentityResult } from '../interfaces/IUser';
|
||||
import { IUser, IUpdateLocalUser, ICheckbox, IIdentityResult, IResetPasswordToken } from '../interfaces/IUser';
|
||||
|
||||
|
||||
@Injectable()
|
||||
|
@ -47,6 +47,14 @@ export class IdentityService extends ServiceAuthHelpers {
|
|||
return this.http.delete(`${this.url}/${user.id}`, { headers: this.headers }).map(this.extractData);
|
||||
}
|
||||
|
||||
submitResetPassword(email:string): Observable<IIdentityResult>{
|
||||
return this.regularHttp.post(this.url + 'reset', JSON.stringify({email:email}), { headers: this.headers }).map(this.extractData);
|
||||
}
|
||||
|
||||
resetPassword(token: IResetPasswordToken):Observable<IIdentityResult>{
|
||||
return this.regularHttp.post(this.url + 'resetpassword', JSON.stringify(token), { headers: this.headers }).map(this.extractData);
|
||||
}
|
||||
|
||||
hasRole(role: string): boolean {
|
||||
var roles = localStorage.getItem("roles") as string[] | null;
|
||||
if (roles) {
|
||||
|
|
|
@ -9,15 +9,22 @@ using Microsoft.AspNetCore.Identity;
|
|||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Ombi.Attributes;
|
||||
using Ombi.Config;
|
||||
using Ombi.Core.Claims;
|
||||
using Ombi.Core.Helpers;
|
||||
using Ombi.Core.Models.UI;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Models;
|
||||
using Ombi.Models.Identity;
|
||||
using Ombi.Notifications;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Settings.Settings.Models.Notifications;
|
||||
using Ombi.Store.Entities;
|
||||
using IdentityResult = Ombi.Models.Identity.IdentityResult;
|
||||
using OmbiIdentityResult = Ombi.Models.Identity.IdentityResult;
|
||||
|
||||
namespace Ombi.Controllers
|
||||
{
|
||||
|
@ -28,16 +35,27 @@ namespace Ombi.Controllers
|
|||
[PowerUser]
|
||||
public class IdentityController : BaseV1ApiController
|
||||
{
|
||||
public IdentityController(UserManager<OmbiUser> user, IMapper mapper, RoleManager<IdentityRole> rm)
|
||||
public IdentityController(UserManager<OmbiUser> user, IMapper mapper, RoleManager<IdentityRole> rm, IEmailProvider prov,
|
||||
ISettingsService<EmailNotificationSettings> s,
|
||||
ISettingsService<CustomizationSettings> c,
|
||||
IOptions<UserSettings> userSettings)
|
||||
{
|
||||
UserManager = user;
|
||||
Mapper = mapper;
|
||||
RoleManager = rm;
|
||||
EmailProvider = prov;
|
||||
EmailSettings = s;
|
||||
CustomizationSettings = c;
|
||||
UserSettings = userSettings;
|
||||
}
|
||||
|
||||
private UserManager<OmbiUser> UserManager { get; }
|
||||
private RoleManager<IdentityRole> RoleManager { get; }
|
||||
private IMapper Mapper { get; }
|
||||
private IEmailProvider EmailProvider { get; }
|
||||
private ISettingsService<EmailNotificationSettings> EmailSettings { get; }
|
||||
private ISettingsService<CustomizationSettings> CustomizationSettings { get; }
|
||||
private IOptions<UserSettings> UserSettings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// This is what the Wizard will call when creating the user for the very first time.
|
||||
|
@ -167,7 +185,7 @@ namespace Ombi.Controllers
|
|||
/// <param name = "user" > The user.</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IdentityResult> CreateUser([FromBody] UserViewModel user)
|
||||
public async Task<OmbiIdentityResult> CreateUser([FromBody] UserViewModel user)
|
||||
{
|
||||
if (!EmailValidator.IsValidEmail(user.EmailAddress))
|
||||
{
|
||||
|
@ -185,7 +203,7 @@ namespace Ombi.Controllers
|
|||
if (!userResult.Succeeded)
|
||||
{
|
||||
// We did not create the user
|
||||
return new IdentityResult
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Errors = userResult.Errors.Select(x => x.Description).ToList()
|
||||
};
|
||||
|
@ -201,13 +219,13 @@ namespace Ombi.Controllers
|
|||
messages.AddRange(errors.Errors.Select(x => x.Description).ToList());
|
||||
}
|
||||
|
||||
return new IdentityResult
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Errors = messages
|
||||
};
|
||||
}
|
||||
|
||||
return new IdentityResult
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Successful = true
|
||||
};
|
||||
|
@ -220,7 +238,7 @@ namespace Ombi.Controllers
|
|||
/// <returns></returns>
|
||||
[HttpPut("local")]
|
||||
[Authorize]
|
||||
public async Task<IdentityResult> UpdateLocalUser([FromBody] UpdateLocalUserModel ui)
|
||||
public async Task<OmbiIdentityResult> UpdateLocalUser([FromBody] UpdateLocalUserModel ui)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ui.CurrentPassword))
|
||||
{
|
||||
|
@ -260,7 +278,7 @@ namespace Ombi.Controllers
|
|||
var updateResult = await UserManager.UpdateAsync(user);
|
||||
if (!updateResult.Succeeded)
|
||||
{
|
||||
return new IdentityResult
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Errors = updateResult.Errors.Select(x => x.Description).ToList()
|
||||
};
|
||||
|
@ -272,13 +290,13 @@ namespace Ombi.Controllers
|
|||
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
return new IdentityResult
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Errors = result.Errors.Select(x => x.Description).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
return new IdentityResult
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Successful = true
|
||||
};
|
||||
|
@ -291,7 +309,7 @@ namespace Ombi.Controllers
|
|||
/// <param name = "ui" > The user.</param>
|
||||
/// <returns></returns>
|
||||
[HttpPut]
|
||||
public async Task<IdentityResult> UpdateUser([FromBody] UserViewModel ui)
|
||||
public async Task<OmbiIdentityResult> UpdateUser([FromBody] UserViewModel ui)
|
||||
{
|
||||
if (!EmailValidator.IsValidEmail(ui.EmailAddress))
|
||||
{
|
||||
|
@ -304,7 +322,7 @@ namespace Ombi.Controllers
|
|||
var updateResult = await UserManager.UpdateAsync(user);
|
||||
if (!updateResult.Succeeded)
|
||||
{
|
||||
return new IdentityResult
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Errors = updateResult.Errors.Select(x => x.Description).ToList()
|
||||
};
|
||||
|
@ -327,13 +345,13 @@ namespace Ombi.Controllers
|
|||
messages.AddRange(errors.Errors.Select(x => x.Description).ToList());
|
||||
}
|
||||
|
||||
return new IdentityResult
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Errors = messages
|
||||
};
|
||||
}
|
||||
|
||||
return new IdentityResult
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Successful = true
|
||||
};
|
||||
|
@ -346,7 +364,7 @@ namespace Ombi.Controllers
|
|||
/// <param name="userId">The user.</param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete("{userId}")]
|
||||
public async Task<IdentityResult> DeleteUser(string userId)
|
||||
public async Task<OmbiIdentityResult> DeleteUser(string userId)
|
||||
{
|
||||
|
||||
var userToDelete = await UserManager.Users.FirstOrDefaultAsync(x => x.Id == userId);
|
||||
|
@ -355,13 +373,13 @@ namespace Ombi.Controllers
|
|||
var result = await UserManager.DeleteAsync(userToDelete);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
return new IdentityResult
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Successful = true
|
||||
};
|
||||
}
|
||||
|
||||
return new IdentityResult
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Errors = result.Errors.Select(x => x.Description).ToList()
|
||||
};
|
||||
|
@ -391,6 +409,86 @@ namespace Ombi.Controllers
|
|||
return claims;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send out the email with the reset link
|
||||
/// </summary>
|
||||
/// <param name="email"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("reset")]
|
||||
[AllowAnonymous]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public async Task<OmbiIdentityResult> SubmitResetPassword([FromBody]SubmitPasswordReset email)
|
||||
{
|
||||
// Check if account exists
|
||||
var user = await UserManager.FindByEmailAsync(email.Email);
|
||||
|
||||
var defaultMessage = new OmbiIdentityResult
|
||||
{
|
||||
Successful = true,
|
||||
Errors = new List<string> { "If this account exists you should recieve a password reset link." }
|
||||
};
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return defaultMessage;
|
||||
}
|
||||
|
||||
// We have the user
|
||||
var token = await UserManager.GeneratePasswordResetTokenAsync(user);
|
||||
|
||||
// We now need to email the user with this token
|
||||
var emailSettings = await EmailSettings.GetSettingsAsync();
|
||||
var customizationSettings = await CustomizationSettings.GetSettingsAsync();
|
||||
var appName = (string.IsNullOrEmpty(customizationSettings.ApplicationName)
|
||||
? "Ombi"
|
||||
: customizationSettings.ApplicationName);
|
||||
await EmailProvider.Send(new NotificationMessage
|
||||
{
|
||||
To = user.Email,
|
||||
Subject = $"{appName} Password Reset",
|
||||
Message = $"Hello {user.UserName}, <br/> You recently made a request to reset your {appName} account. Please click the link below to complete the process.<br/><br/>" +
|
||||
$"<a href=\"{UserSettings.Value.WebsiteUrl}/reset/{token}\"> Reset </a>"
|
||||
}, emailSettings);
|
||||
|
||||
return defaultMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the password
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("resetpassword")]
|
||||
[AllowAnonymous]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public async Task<OmbiIdentityResult> ResetPassword(ResetPasswordToken token)
|
||||
{
|
||||
var user = await UserManager.FindByEmailAsync(token.Email);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Successful = false,
|
||||
Errors = new List<string> { "Please check you email." }
|
||||
};
|
||||
}
|
||||
|
||||
var tokenValid = await UserManager.ResetPasswordAsync(user, token.Token, token.Password);
|
||||
|
||||
if (tokenValid.Succeeded)
|
||||
{
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Successful = true,
|
||||
};
|
||||
}
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Errors = tokenValid.Errors.Select(x => x.Description).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<List<Microsoft.AspNetCore.Identity.IdentityResult>> AddRoles(IEnumerable<ClaimCheckboxes> roles, OmbiUser ombiUser)
|
||||
{
|
||||
var roleResult = new List<Microsoft.AspNetCore.Identity.IdentityResult>();
|
||||
|
@ -404,9 +502,9 @@ namespace Ombi.Controllers
|
|||
return roleResult;
|
||||
}
|
||||
|
||||
private IdentityResult Error(string message)
|
||||
private OmbiIdentityResult Error(string message)
|
||||
{
|
||||
return new IdentityResult
|
||||
return new OmbiIdentityResult
|
||||
{
|
||||
Errors = new List<string> { message }
|
||||
};
|
||||
|
|
9
src/Ombi/Models/Identity/ResetPasswordToken.cs
Normal file
9
src/Ombi/Models/Identity/ResetPasswordToken.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Ombi.Models.Identity
|
||||
{
|
||||
public class ResetPasswordToken
|
||||
{
|
||||
public string Token { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
7
src/Ombi/Models/Identity/SubmitPasswordReset.cs
Normal file
7
src/Ombi/Models/Identity/SubmitPasswordReset.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Ombi.Models.Identity
|
||||
{
|
||||
public class SubmitPasswordReset
|
||||
{
|
||||
public string Email { get; set; }
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue