mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 21:33:15 -07:00
Started adding the ability for them to self manage their accounts
This commit is contained in:
parent
612fbb213f
commit
27f0d6e225
15 changed files with 385 additions and 181 deletions
|
@ -68,8 +68,11 @@ export interface IIdentityResult {
|
|||
successful: boolean;
|
||||
}
|
||||
|
||||
export interface IUpdateLocalUser extends IUser {
|
||||
export interface IUpdateLocalUser {
|
||||
currentPassword: string;
|
||||
password: string;
|
||||
id: string;
|
||||
emailAddress: string;
|
||||
confirmNewPassword: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,29 +8,29 @@
|
|||
<mat-nav-list>
|
||||
<span *ngFor="let nav of navItems">
|
||||
|
||||
<div *ngIf="(nav.requiresAdmin && isAdmin || !nav.requiresAdmin) && nav.enabled">
|
||||
<div class="menu-spacing" *ngIf="(nav.requiresAdmin && isAdmin || !nav.requiresAdmin) && nav.enabled">
|
||||
|
||||
|
||||
<a id="{{nav.id}}" *ngIf="nav.externalLink" mat-list-item [href]="nav.link" target="_blank"
|
||||
matTooltip="{{nav.toolTipMessage | translate}}" matTooltipPosition="right"
|
||||
[routerLinkActive]="'active-list-item'">
|
||||
|
||||
<i *ngIf="nav.icon" class="fa-lg {{nav.icon}}"
|
||||
<i *ngIf="nav.icon" class="fa-lg {{nav.icon}} icon-spacing"
|
||||
style="padding-left: 5px; padding-right: 5px;" aria-hidden="true"></i>
|
||||
{{nav.name | translate}}
|
||||
</a>
|
||||
<a id="{{nav.id}}" *ngIf="!nav.externalLink" mat-list-item [routerLink]="nav.link" [style]="nav.color"
|
||||
[routerLinkActive]="'active-list-item'">
|
||||
|
||||
<i class="fa-lg {{nav.icon}}"></i>
|
||||
<i class="fa-lg {{nav.icon}} icon-spacing"></i>
|
||||
{{nav.name | translate}}
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<a id="nav-logout" mat-list-item [routerLinkActive]="'active-list-item'"
|
||||
<a class="menu-spacing" id="nav-logout" mat-list-item [routerLinkActive]="'active-list-item'"
|
||||
aria-label="Toggle sidenav" (click)="logOut();">
|
||||
<i class="fa-lg fas fa-sign-out-alt"></i>
|
||||
<i class="fa-lg fas fa-sign-out-alt icon-spacing"></i>
|
||||
{{ 'NavigationBar.Logout' | translate }}
|
||||
</a>
|
||||
|
||||
|
@ -82,7 +82,7 @@
|
|||
</div>
|
||||
<div class="col-1">
|
||||
<a routerLink="/user-preferences">
|
||||
<img [matTooltip]="username" class="profile-img" [src]="getUserImage()" />
|
||||
<img [matTooltip]="username" id="profile-image" class="profile-img" [src]="getUserImage()" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -19,6 +19,14 @@
|
|||
display: flex;
|
||||
}
|
||||
|
||||
.menu-spacing {
|
||||
margin-bottom: 5%;
|
||||
}
|
||||
|
||||
.icon-spacing {
|
||||
margin-right: 5%;
|
||||
}
|
||||
|
||||
.example-form {
|
||||
min-width: 150px;
|
||||
max-width: 500px;
|
||||
|
|
|
@ -1,54 +1,135 @@
|
|||
<div class="small-middle-container" *ngIf="username">
|
||||
<h3 [translate]="'UserPreferences.Welcome'" [translateParams]="{username: username}"></h3>
|
||||
|
||||
|
||||
<hr>
|
||||
<div class="row top-spacing">
|
||||
<div class="col-4">
|
||||
<div>
|
||||
<small>{{'UserPreferences.LanguageDescription' | translate}}</small>
|
||||
<br>
|
||||
<mat-form-field>
|
||||
<mat-label [translate]="'UserPreferences.OmbiLanguage'"></mat-label>
|
||||
<mat-select id="langSelect" [(value)]="selectedLang" (selectionChange)="languageSelected();">
|
||||
<mat-option id="langSelect{{lang.value}}" *ngFor="let lang of availableLanguages" [value]="lang.value">
|
||||
{{lang.display}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
<div class="row h-100">
|
||||
<div class="col-1">
|
||||
<img class="profile-img" [src]="getProfileImage()">
|
||||
</div>
|
||||
<div class="col-1"></div>
|
||||
<div class="col-7">
|
||||
<mat-label [translate]="'UserPreferences.MobileQRCode'"></mat-label>
|
||||
<div id="noQrCode" *ngIf="!qrCodeEnabled" [translate]="'UserPreferences.NoQrCode'"></div>
|
||||
<qrcode id="qrCode" *ngIf="qrCodeEnabled" [qrdata]="qrCode" [size]="256" [level]="'L'"></qrcode>
|
||||
<button mat-raised-button (click)="openMobileApp($event)" *ngIf="customizationSettings.applicationUrl"> {{
|
||||
'UserPreferences.LegacyApp' | translate }}</button>
|
||||
<div class="col-11 align-middle">
|
||||
<h2 id="usernameTitle">{{username}} <small id="emailTitle" *ngIf="user.emailAddress">({{user.emailAddress}})</small></h2>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-4">
|
||||
<div>
|
||||
<small>{{'UserPreferences.StreamingCountryDescription' | translate}}</small>
|
||||
<br>
|
||||
<mat-form-field>
|
||||
<mat-label [translate]="'UserPreferences.StreamingCountry'"></mat-label>
|
||||
<mat-select id="streamingSelect" [(value)]="selectedCountry" (selectionChange)="countrySelected();">
|
||||
<mat-option id="streamingSelect{{value}}" *ngFor="let value of countries" [value]="value">
|
||||
{{value}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Profile">
|
||||
<div class="tab-content">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-1">
|
||||
User Type:
|
||||
</div>
|
||||
<div class="col-11">
|
||||
{{UserType[user.userType]}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<div>
|
||||
<small>{{'UserPreferences.LanguageDescription' | translate}}</small>
|
||||
<br>
|
||||
<mat-form-field>
|
||||
<mat-label [translate]="'UserPreferences.OmbiLanguage'"></mat-label>
|
||||
<mat-select id="langSelect" [(value)]="selectedLang" (selectionChange)="languageSelected();">
|
||||
<mat-option id="langSelect{{lang.value}}" *ngFor="let lang of availableLanguages"
|
||||
[value]="lang.value">
|
||||
{{lang.display}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-1"></div>
|
||||
|
||||
|
||||
<div class="col-4">
|
||||
<div>
|
||||
<small>{{'UserPreferences.StreamingCountryDescription' | translate}}</small>
|
||||
<br>
|
||||
<mat-form-field>
|
||||
<mat-label [translate]="'UserPreferences.StreamingCountry'"></mat-label>
|
||||
<mat-select id="streamingSelect" [(value)]="selectedCountry" (selectionChange)="countrySelected();">
|
||||
<mat-option id="streamingSelect{{value}}" *ngFor="let value of countries" [value]="value">
|
||||
{{value}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</mat-tab>
|
||||
<mat-tab *ngIf="user.userType === UserType.LocalUser" label="Security">
|
||||
<div class="tab-content">
|
||||
<h2>Change Details</h2>
|
||||
<form novalidate [formGroup]="passwordForm" (ngSubmit)="updatePassword()">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-12">
|
||||
<span>You need your current password to make any changes here</span>
|
||||
<mat-form-field appearance="outline" floatLabel=always>
|
||||
<mat-label>Current Password</mat-label>
|
||||
<input id="currentPassword" matInput type="password" formControlName="currentPassword">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-12">
|
||||
<mat-form-field appearance="outline" floatLabel=always>
|
||||
<mat-label>Email Address</mat-label>
|
||||
<input id="email" matInput formControlName="emailAddress">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-12">
|
||||
<mat-form-field appearance="outline" floatLabel=always>
|
||||
<mat-label>New Password</mat-label>
|
||||
<input id="newPassword" matInput type="password" formControlName="password">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-12">
|
||||
<mat-form-field appearance="outline" floatLabel=always>
|
||||
<mat-label>New Password Confirm</mat-label>
|
||||
<input id="confirmPassword" matInput type="password" formControlName="confirmPassword">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<button id="submitSecurity" mat-raised-button color="accent" type="submit">Update</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</mat-tab>
|
||||
|
||||
|
||||
<mat-tab label="Preferences"> Coming Soon... </mat-tab>
|
||||
|
||||
|
||||
<mat-tab label="Mobile">
|
||||
<div class="tab-content">
|
||||
<div class="col-7">
|
||||
<mat-label [translate]="'UserPreferences.MobileQRCode'"></mat-label>
|
||||
<div id="noQrCode" *ngIf="!qrCodeEnabled" [translate]="'UserPreferences.NoQrCode'"></div>
|
||||
<qrcode id="qrCode" *ngIf="qrCodeEnabled" [qrdata]="qrCode" [size]="256" [level]="'L'"></qrcode>
|
||||
<button mat-raised-button (click)="openMobileApp($event)" *ngIf="customizationSettings.applicationUrl"> {{
|
||||
'UserPreferences.LegacyApp' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
|
||||
|
||||
|
||||
</div>
|
|
@ -1,5 +1,23 @@
|
|||
.small-middle-container{
|
||||
margin: auto;
|
||||
margin-top: 3%;
|
||||
width: 80%;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.profile-img {
|
||||
border-radius: 100%;
|
||||
width: 75px;
|
||||
}
|
||||
.my-auto {
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
::ng-deep .mat-tab-body-content {
|
||||
height: 100%;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
margin-top: 1%;
|
||||
}
|
|
@ -2,9 +2,10 @@ import { Component, OnInit } from "@angular/core";
|
|||
import { AuthService } from "../../../auth/auth.service";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { AvailableLanguages, ILanguage } from "./user-preference.constants";
|
||||
import { StorageService } from "../../../shared/storage/storage-service";
|
||||
import { IdentityService, NotificationService, SettingsService } from "../../../services";
|
||||
import { ICustomizationSettings, IUser } from "../../../interfaces";
|
||||
import { IdentityService, NotificationService, SettingsService, ValidationService } from "../../../services";
|
||||
import { ICustomizationSettings, IUser, UserType } from "../../../interfaces";
|
||||
import { Md5 } from "ts-md5";
|
||||
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||
|
||||
@Component({
|
||||
templateUrl: "./user-preference.component.html",
|
||||
|
@ -20,6 +21,9 @@ export class UserPreferenceComponent implements OnInit {
|
|||
public countries: string[];
|
||||
public selectedCountry: string;
|
||||
public customizationSettings: ICustomizationSettings;
|
||||
public UserType = UserType;
|
||||
|
||||
public passwordForm: FormGroup;
|
||||
|
||||
private user: IUser;
|
||||
|
||||
|
@ -27,7 +31,9 @@ export class UserPreferenceComponent implements OnInit {
|
|||
private readonly translate: TranslateService,
|
||||
private readonly notification: NotificationService,
|
||||
private readonly identityService: IdentityService,
|
||||
private readonly settingsService: SettingsService) { }
|
||||
private readonly settingsService: SettingsService,
|
||||
private readonly fb: FormBuilder,
|
||||
private readonly validationService: ValidationService) { }
|
||||
|
||||
public async ngOnInit() {
|
||||
const user = this.authService.claims();
|
||||
|
@ -52,6 +58,23 @@ export class UserPreferenceComponent implements OnInit {
|
|||
this.identityService.getSupportedStreamingCountries().subscribe(x => this.countries = x);
|
||||
this.settingsService.getCustomization().subscribe(x => this.customizationSettings = x);
|
||||
|
||||
this.passwordForm = this.fb.group({
|
||||
password: [null],
|
||||
currentPassword: [null, Validators.required],
|
||||
confirmPassword: [null],
|
||||
emailAddress: [this.user.emailAddress, Validators.email]
|
||||
})
|
||||
|
||||
this.passwordForm.controls.password.valueChanges.subscribe(x => {
|
||||
if (x) {
|
||||
this.validationService.enableValidation(this.passwordForm, "confirmPassword");
|
||||
}
|
||||
});
|
||||
this.passwordForm.controls.confirmPassword.valueChanges.subscribe(x => {
|
||||
if (x) {
|
||||
this.validationService.enableValidation(this.passwordForm, "password");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public languageSelected() {
|
||||
|
@ -71,4 +94,55 @@ export class UserPreferenceComponent implements OnInit {
|
|||
window.location.assign(url);
|
||||
});
|
||||
}
|
||||
|
||||
public getProfileImage(): string {
|
||||
let emailHash: string|Int32Array;
|
||||
if (this.user.emailAddress) {
|
||||
const md5 = new Md5();
|
||||
emailHash = md5.appendStr(this.user.emailAddress).end();
|
||||
}
|
||||
var fallback = this.customizationSettings.logo ? this.customizationSettings.logo : 'https://raw.githubusercontent.com/Ombi-app/Ombi/gh-pages/img/android-chrome-512x512.png';
|
||||
return `https://www.gravatar.com/avatar/${emailHash}?d=${fallback}`;
|
||||
}
|
||||
|
||||
public updatePassword() {
|
||||
if (this.passwordForm.invalid) {
|
||||
this.passwordForm.markAsDirty();
|
||||
return;
|
||||
}
|
||||
|
||||
var values = this.passwordForm.value;
|
||||
|
||||
this.identityService.updateLocalUser({
|
||||
password: values.password,
|
||||
confirmNewPassword: values.confirmPassword,
|
||||
emailAddress: values.emailAddress,
|
||||
id: this.user.id,
|
||||
currentPassword: values.currentPassword
|
||||
}).subscribe(x => {
|
||||
if (x.successful) {
|
||||
this.notification.success("Updated your information");
|
||||
this.user.emailAddress = values.emailAddress;
|
||||
} else {
|
||||
this.notification.error(x.errors[0]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
private welcomeText: string;
|
||||
private setWelcomeText() {
|
||||
var d = new Date();
|
||||
var hour = d.getHours();
|
||||
|
||||
if (hour >= 0 && hour < 12) {
|
||||
this.welcomeText = 'NavigationBar.MorningWelcome';
|
||||
}
|
||||
if (hour >= 12 && hour < 18) {
|
||||
this.welcomeText = 'NavigationBar.AfternoonWelcome';
|
||||
}
|
||||
if (hour >= 18 && hour < 24) {
|
||||
this.welcomeText = 'NavigationBar.EveningWelcome';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,15 @@ import { SharedModule } from "../shared/shared.module";
|
|||
import { QRCodeModule } from 'angularx-qrcode';
|
||||
|
||||
import * as fromComponents from './components';
|
||||
import { ReactiveFormsModule } from "@angular/forms";
|
||||
import { ValidationService } from "../services";
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild(fromComponents.routes),
|
||||
SharedModule,
|
||||
ReactiveFormsModule,
|
||||
MatCheckboxModule,
|
||||
QRCodeModule,
|
||||
],
|
||||
|
@ -23,6 +26,7 @@ import * as fromComponents from './components';
|
|||
RouterModule,
|
||||
],
|
||||
providers: [
|
||||
ValidationService,
|
||||
],
|
||||
|
||||
})
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
<div *ngIf="form">
|
||||
|
||||
<h3>Hello {{form.value.username}}!</h3>
|
||||
<div class="col-md-6">
|
||||
<form novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">
|
||||
<div class="modal-body" style="margin-top:45px;">
|
||||
<div class="form-group">
|
||||
<label for="emailAddress" class="control-label">Email Address</label>
|
||||
<div>
|
||||
<input type="text" formControlName="emailAddress" class="form-control form-control-custom " id="emailAddress" name="emailAddress">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="currentPassword" class="control-label">Current Password</label>
|
||||
<div>
|
||||
<input type="password" formControlName="currentPassword" class="form-control form-control-custom " id="currentPassword" name="currentPassword">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password" class="control-label">New Password</label>
|
||||
<div>
|
||||
<input type="password" formControlName="password" class="form-control form-control-custom " id="password" name="password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="confirmPassword" class="control-label">Confirm New Password</label>
|
||||
<div>
|
||||
<input type="password" formControlName="confirmNewPassword" class="form-control form-control-custom " id="confirmPassword"
|
||||
name="confirmPassword">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" data-test="submitbtn" class="btn btn-primary-outline" [disabled]="form.invalid">Save</button>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div *ngIf="form.invalid && form.dirty" class="alert alert-danger">
|
||||
<div *ngIf="form.get('emailAddress').hasError('email')">Email address format is incorrect</div>
|
||||
<div *ngIf="form.get('password').hasError('required')">The Password is required</div>
|
||||
<div *ngIf="form.get('confirmNewPassword').hasError('required')">The Confirm New Password is required</div>
|
||||
<div *ngIf="form.get('currentPassword').hasError('required')">Your current password is required</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,59 +0,0 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||
|
||||
import { IUpdateLocalUser } from "../interfaces";
|
||||
import { IdentityService } from "../services";
|
||||
import { NotificationService } from "../services";
|
||||
|
||||
@Component({
|
||||
templateUrl: "./updatedetails.component.html",
|
||||
})
|
||||
export class UpdateDetailsComponent implements OnInit {
|
||||
public form: FormGroup;
|
||||
|
||||
constructor(private identityService: IdentityService,
|
||||
private notificationService: NotificationService,
|
||||
private fb: FormBuilder) { }
|
||||
|
||||
public ngOnInit() {
|
||||
this.identityService.getUser().subscribe(x => {
|
||||
const localUser = x as IUpdateLocalUser;
|
||||
this.form = this.fb.group({
|
||||
id: [localUser.id],
|
||||
username: [localUser.userName],
|
||||
emailAddress: [localUser.emailAddress, [Validators.email]],
|
||||
confirmNewPassword: [localUser.confirmNewPassword],
|
||||
currentPassword: [localUser.currentPassword, [Validators.required]],
|
||||
password: [localUser.password],
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public onSubmit(form: FormGroup) {
|
||||
if (form.invalid) {
|
||||
this.notificationService.error("Please check your entered values");
|
||||
return;
|
||||
}
|
||||
|
||||
if (form.controls.password.dirty) {
|
||||
if (form.value.password !== form.value.confirmNewPassword) {
|
||||
this.notificationService.error("Passwords do not match");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.identityService.updateLocalUser(this.form.value).subscribe(x => {
|
||||
if (x.successful) {
|
||||
this.notificationService.success(`All of your details have now been updated`);
|
||||
} else {
|
||||
x.errors.forEach((val) => {
|
||||
this.notificationService.error(val);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -7,8 +7,6 @@ import { MultiSelectModule } from "primeng/multiselect";
|
|||
import { SidebarModule } from "primeng/sidebar";
|
||||
import { TooltipModule } from "primeng/tooltip";
|
||||
|
||||
|
||||
import { UpdateDetailsComponent } from "./updatedetails.component";
|
||||
import { UserManagementUserComponent } from "./usermanagement-user.component";
|
||||
import { UserManagementComponent } from "./usermanagement.component";
|
||||
|
||||
|
@ -25,7 +23,6 @@ const routes: Routes = [
|
|||
{ path: "", component: UserManagementComponent, canActivate: [AuthGuard] },
|
||||
{ path: "user", component: UserManagementUserComponent, canActivate: [AuthGuard] },
|
||||
{ path: "user/:id", component: UserManagementUserComponent, canActivate: [AuthGuard] },
|
||||
{ path: "updatedetails", component: UpdateDetailsComponent, canActivate: [AuthGuard] },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
@ -44,7 +41,6 @@ const routes: Routes = [
|
|||
],
|
||||
declarations: [
|
||||
UserManagementComponent,
|
||||
UpdateDetailsComponent,
|
||||
UserManagementUserComponent,
|
||||
],
|
||||
exports: [
|
||||
|
|
|
@ -73,7 +73,7 @@ class NavBar {
|
|||
}
|
||||
|
||||
get userPreferences(): Cypress.Chainable<any> {
|
||||
return cy.get('#nav-userPreferences');
|
||||
return cy.get('#profile-image');
|
||||
}
|
||||
|
||||
get logout(): Cypress.Chainable<any> {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { BasePage } from "../base.page";
|
||||
|
||||
class UserPreferencesPage extends BasePage {
|
||||
|
||||
class ProfileTab {
|
||||
get languageSelectBox(): Cypress.Chainable<any> {
|
||||
return cy.get('#langSelect');
|
||||
}
|
||||
|
@ -17,6 +16,9 @@ class UserPreferencesPage extends BasePage {
|
|||
streamingSelectBoxOption(country: string): Cypress.Chainable<any> {
|
||||
return cy.get('#streamingSelect'+country);
|
||||
}
|
||||
}
|
||||
|
||||
class MobileTab {
|
||||
|
||||
get qrCode(): Cypress.Chainable<any> {
|
||||
return cy.get('#qrCode');
|
||||
|
@ -25,6 +27,59 @@ class UserPreferencesPage extends BasePage {
|
|||
get noQrCode(): Cypress.Chainable<any> {
|
||||
return cy.get('#noQrCode');
|
||||
}
|
||||
}
|
||||
|
||||
class SecurityTab {
|
||||
get currentPassword(): Cypress.Chainable<any> {
|
||||
return cy.get('#currentPassword');
|
||||
}
|
||||
|
||||
get email(): Cypress.Chainable<any> {
|
||||
return cy.get('#email');
|
||||
}
|
||||
|
||||
get newPassword(): Cypress.Chainable<any> {
|
||||
return cy.get('#newPassword');
|
||||
}
|
||||
|
||||
get confirmPassword(): Cypress.Chainable<any> {
|
||||
return cy.get('#confirmPassword');
|
||||
}
|
||||
|
||||
get submitButton(): Cypress.Chainable<any> {
|
||||
return cy.get('#submitSecurity');
|
||||
}
|
||||
}
|
||||
|
||||
class UserPreferencesPage extends BasePage {
|
||||
|
||||
|
||||
get username(): Cypress.Chainable<any> {
|
||||
return cy.get('#usernameTitle');
|
||||
}
|
||||
get email(): Cypress.Chainable<any> {
|
||||
return cy.get('#emailTitle');
|
||||
}
|
||||
|
||||
get profileTab(): Cypress.Chainable<any> {
|
||||
return cy.get('[role="tab"]').eq(0);
|
||||
}
|
||||
|
||||
get securityTab(): Cypress.Chainable<any> {
|
||||
return cy.get('[role="tab"]').eq(1);
|
||||
}
|
||||
|
||||
get preferencesTab(): Cypress.Chainable<any> {
|
||||
return cy.get('[role="tab"]').eq(2);
|
||||
}
|
||||
|
||||
get mobileTab(): Cypress.Chainable<any> {
|
||||
return cy.get('[role="tab"]').eq(3);
|
||||
}
|
||||
|
||||
profile = new ProfileTab();
|
||||
mobile = new MobileTab();
|
||||
security = new SecurityTab();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
|
|
@ -120,4 +120,6 @@ Cypress.Commands.add("getByData", (selector) => {
|
|||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { userPreferencesPage as Page } from "@/integration/page-objects";
|
||||
|
||||
describe("User Preferences Tests", () => {
|
||||
describe("User Preferences Profile Tests", () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
});
|
||||
|
@ -16,8 +16,8 @@ langs.forEach((l) => {
|
|||
cy.intercept('POST','/language').as('langSave');
|
||||
Page.visit();
|
||||
|
||||
Page.languageSelectBox.click();
|
||||
Page.languageSelectBoxOption(l.code).click();
|
||||
Page.profile.languageSelectBox.click();
|
||||
Page.profile.languageSelectBoxOption(l.code).click();
|
||||
|
||||
Page.navbar.discover.contains(l.discover);
|
||||
|
||||
|
@ -42,10 +42,10 @@ streamingCountries.forEach((country) => {
|
|||
Page.visit();
|
||||
cy.wait('@countryApi');
|
||||
|
||||
Page.streamingSelectBox.click();
|
||||
Page.streamingSelectBoxOption(country).click();
|
||||
Page.profile.streamingSelectBox.click();
|
||||
Page.profile.streamingSelectBoxOption(country).click();
|
||||
|
||||
Page.streamingSelectBox.should('have.attr','ng-reflect-value', country);
|
||||
Page.profile.streamingSelectBox.should('have.attr','ng-reflect-value', country);
|
||||
|
||||
cy.wait('@countryApiSave').then((intercept) => {
|
||||
expect(intercept.request.body.code).equal(country);
|
|
@ -0,0 +1,69 @@
|
|||
import { userPreferencesPage as Page } from "@/integration/page-objects";
|
||||
|
||||
describe("User Preferences Security Tests", () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
Page.visit();
|
||||
Page.securityTab.click();
|
||||
});
|
||||
|
||||
|
||||
it(`Change Email Address Requires Current Password`, () => {
|
||||
Page.security.email.clear();
|
||||
Page.security.email.type('test@test.com');
|
||||
Page.security.submitButton.click();
|
||||
|
||||
Page.security.currentPassword.should('have.class', 'ng-invalid');
|
||||
});
|
||||
|
||||
it(`Change Password Requires Current Password`, () => {
|
||||
Page.security.newPassword.type('test@test.com');
|
||||
Page.security.confirmPassword.type('test@test.com');
|
||||
Page.security.submitButton.click();
|
||||
|
||||
Page.security.currentPassword.should('have.class', 'ng-invalid');
|
||||
});
|
||||
|
||||
it(`Change Email incorrect password`, () => {
|
||||
Page.security.currentPassword.type('incorrect');
|
||||
Page.security.email.clear();
|
||||
Page.security.email.type('test@test.com');
|
||||
Page.security.submitButton.click();
|
||||
cy.verifyNotification('password is incorrect');
|
||||
});
|
||||
|
||||
it(`Change password, existing password incorrect`, () => {
|
||||
Page.security.currentPassword.type('incorrect');
|
||||
Page.security.newPassword.type('test@test.com');
|
||||
Page.security.confirmPassword.type('test@test.com');
|
||||
Page.security.submitButton.click();
|
||||
cy.verifyNotification('password is incorrect');
|
||||
});
|
||||
|
||||
it("Change password of user", () => {
|
||||
cy.generateUniqueId().then((id) => {
|
||||
const roles = [];
|
||||
roles.push({ value: "RequestMovie", enabled: true });
|
||||
cy.createUser(id, "a", roles).then(() => {
|
||||
cy.removeLogin();
|
||||
cy.loginWithCreds(id, "a");
|
||||
|
||||
Page.visit();
|
||||
Page.securityTab.click();
|
||||
|
||||
Page.security.currentPassword.type('a');
|
||||
Page.security.email.clear();
|
||||
Page.security.email.type('test@test.com');
|
||||
Page.security.newPassword.type('b');
|
||||
Page.security.confirmPassword.type('b');
|
||||
Page.security.submitButton.click();
|
||||
|
||||
cy.verifyNotification('Updated your information');
|
||||
|
||||
Page.email.should('have.text','(test@test.com)')
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue