change pw, change rank UI, auto-refresh on disconnect, new loading screen

This commit is contained in:
peter
2020-02-25 21:31:39 +01:00
parent de76d37768
commit 96651913cd
23 changed files with 6442 additions and 2964 deletions
+2 -6
View File
@@ -9,12 +9,8 @@
"projectType": "application",
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"builder": "@angular-devkit/build-angular:browser",
"options": {
"customWebpackConfig": {
"path": "./custom-webpack.config.js",
"replaceDuplicatePlugins": true
},
"preserveSymlinks": true,
"rebaseRootRelativeCssUrls": true,
"outputPath": "dist",
@@ -79,7 +75,7 @@
}
},
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "ngx-admin-demo:build"
},
-4
View File
@@ -1,4 +0,0 @@
module.exports = {
externals: ['http', 'fs'],
node: {global: true, fs: 'empty'}
}
+6102 -2794
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -50,7 +50,7 @@
"angular2-chartjs": "0.4.1",
"angular2-toaster": "^7.0.0",
"bootstrap": "4.3.1",
"chart.js": "2.7.1",
"chart.js": "^2.9.3",
"ckeditor": "4.7.3",
"classlist.js": "1.1.20150312",
"core-js": "2.5.1",
@@ -65,11 +65,11 @@
"ng2-smart-table": "1.3.5",
"ngx-cookie-service": "^2.2.0",
"ngx-echarts": "^4.0.1",
"node-sass": "^4.12.0",
"node-sass": "^4.13.1",
"normalize.css": "6.0.0",
"pace-js": "1.0.2",
"roboto-fontface": "0.8.0",
"rpclibrary": "^1.7.1",
"rpclibrary": "^1.8.3",
"rxjs": "6.5.2",
"rxjs-compat": "6.3.0",
"socicon": "3.0.5",
@@ -80,11 +80,11 @@
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.800.2",
"@angular-devkit/build-angular": "~0.803.24",
"@angular/cli": "^8.0.2",
"@angular/compiler-cli": "^8.0.0",
"@angular/language-service": "8.0.0",
"@compodoc/compodoc": "1.0.1",
"@compodoc/compodoc": "^1.1.11",
"@fortawesome/fontawesome-free": "^5.2.0",
"@types/d3-color": "1.0.5",
"@types/googlemaps": "^3.30.4",
@@ -1,9 +1,4 @@
<div class="header-container">
<div>
<a (click)="toggleSidebar()" href="#" class="sidebar-toggle">
<nb-icon icon="menu-2-outline"></nb-icon>
</a>
</div>
<div class="logo-container">
<a (click)="toggleSidebar()" href="#" class="sidebar-toggle">
<nb-icon icon="menu-2-outline"></nb-icon>
@@ -35,12 +35,7 @@
[maxlength]="15"
[attr.aria-invalid]="password.invalid && password.touched ? true : null">
</div>
<div class="form-control-group accept-group">
<nb-checkbox name="rememberMe" [(ngModel)]="user.rememberMe" *ngIf="rememberMe">Remember me</nb-checkbox>
<a class="forgot-password" routerLink="../request-password">Forgot Password?</a>
</div>
<br />
<button nbButton
fullWidth
status="primary"
@@ -35,28 +35,32 @@
[attr.aria-invalid]="password.invalid && password.touched ? true : null">
</div>
<div class="form-control-group accept-group">
<nb-checkbox name="rememberMe" [(ngModel)]="user.rememberMe" *ngIf="rememberMe">Remember me</nb-checkbox>
</div>
<nb-card>
<nb-card-body>
<nb-checkbox [(ngModel)]="showApplication" name="amMember" #checkbox><!--I am already a member-->I understand this is super beta and things might not work or are not very pretty</nb-checkbox>
<br />
<span > <!--*ngIf="showApplication"-->
And my main is &nbsp; <input name="preMember" [(ngModel)]="character.name" nbInput>, a
And my main is &nbsp; <input nbInput [required]="true" name="preMember" [(ngModel)]="character.name" >, a
<nb-select [(selected)]="character.race" placeholder="Race" (selectedChange)="onSelectRace()">
<nb-option *ngFor="let race of races" [value]="race">{{race}}</nb-option>
</nb-select>
<nb-select [(selected)]="character.spec" placeholder="Spec" (selectedChange)="onSelectSpec()">
<nb-select
[(selected)]="character.spec"
placeholder="Spec"
(selectedChange)="onSelectSpec()">
<nb-option *ngFor="let spec of specs" [value]="spec">{{spec}}</nb-option>
</nb-select>
<nb-select [(selected)]="character.class" placeholder="Class" (selectedChange)="onSelectClass()">
<nb-select
[(selected)]="character.class"
placeholder="Class"
(selectedChange)="onSelectClass()">
<nb-option *ngFor="let class of classes" [value]="class">{{class}}</nb-option>
</nb-select>
with rank
<nb-select [(selected)]="user.rank" placeholder="Rank">
<nb-select
[(selected)]="user.rank"
placeholder="Rank">
<nb-option *ngFor="let rank of ranks" [value]="rank" >{{rank}}</nb-option>
</nb-select>
</span>
@@ -195,7 +195,7 @@ export class FrontcraftRaidComponent implements OnInit, OnDestroy{
this.displayedtokens = this.tokens
}else{
this.displayedtokens = {}
Object.entries(this.tokens).forEach((e: [string, (Character & SRToken & Item)[]]) => {
Object.entries(this.tokens).forEach((e: [string /*itemname*/, (Character & SRToken & Item)[]]) => {
const filteredTokens = e[1].filter(item => {
return item.itemname.toLocaleLowerCase().includes(this.search.toLocaleLowerCase())
})
@@ -9,7 +9,7 @@ import { _Tiers, allItems, Tiers } from '../../../../../../backend/Types/Items';
@Component({
selector: 'buyToken',
template: `
<nb-card class="col-12 col-xl-9">
<nb-card style="width: 500px">
<nb-card-header>
Buy {{item.itemname}}
</nb-card-header>
@@ -19,8 +19,10 @@ import { _Tiers, allItems, Tiers } from '../../../../../../backend/Types/Items';
</p>
<div *ngIf="currency>0">
<nb-alert accent="danger" *ngIf="invalidatedTokens.length > 0">
Claiming this reserve invalidates the following streaks. <br />
This is not reversible.
Claiming this reserve puts the following streaks to zero <br />
<span>
<nb-icon icon="alert-triangle-outline" status="warning"></nb-icon>&nbsp;This is not reversible&nbsp;<nb-icon icon="alert-triangle-outline" status="warning"></nb-icon>
</span>
<ul *ngFor="let item of invalidatedTokens">
<li>
[ {{item.level}} ]
@@ -6,12 +6,65 @@ accent="info">
<h2 style="text-transform: capitalize;">{{user.username}}</h2>
</nb-card-header>
<nb-card-body>
{{user.MC}} MC
{{user.BWL}} BWL
{{user.ZG}} ZG
{{user.AQ20}} AQ20
{{user.AQ40}} AQ40
<h3>Rank</h3>
<span *ngIf="!manageUser">
{{user.rank}}
</span>
<nb-select
*ngIf="manageUser"
[(selected)]="user.rank"
placeholder="Rank"
(selectedChange)="onSelectRank()">
<nb-option *ngFor="let rank of ranks" [value]="rank" >{{rank}}</nb-option>
</nb-select>
<h3 *ngIf="myProfile || manageUser">Password</h3>
<form (ngSubmit)="submitPasswordChange()" #form="ngForm" aria-labelledby="title" *ngIf="myProfile || manageUser">
<input nbInput
fullWidth
type="password"
[(ngModel)]="newPw"
name="newPw"
id="input-newPw"
pattern=".+"
placeholder="New Password"
fieldSize="small"
autofocus
[required]="true">
<input nbInput
fullWidth
type="password"
[(ngModel)]="newPwConfirm"
name="newPwConfirm"
id="input-newPwConfirm"
pattern=".+"
placeholder="Confirm Password"
fieldSize="small"
autofocus
[required]="true">
<button nbButton
fullWidth
status="primary"
size="small"
[disabled]="!form.valid || newPw != newPwConfirm"
[class.btn-pulse]="submitted">
Change
</button>
</form>
<br />
<h3>Avaiable Reserves</h3>
{{user.MC}} MC |
{{user.BWL}} BWL |
{{user.ZG}} ZG |
{{user.AQ20}} AQ20 |
{{user.AQ40}} AQ40 |
{{user.Naxx}} Naxx
<br />
<ng-container *ngFor="let char of characters">
<character [name]="char.charactername" [link]="'character'"></character>
</ng-container>
@@ -1,9 +1,11 @@
import { Component, OnInit } from '@angular/core';
import { ApiService } from '../../services/login-api';
import { ApiService, hash } from '../../services/login-api';
import { Router, ActivatedRoute } from '@angular/router';
import { User, Spec, Character } from '../../../../../../backend/Types/Types';
import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
import { _Tiers } from '../../../../../../backend/Types/Items';
import { _Rank } from '../../../../../../backend/Types/Types';
import { NbToastrService } from '@nebular/theme';
@Component({
selector: 'user-component',
@@ -11,22 +13,31 @@ import { _Tiers } from '../../../../../../backend/Types/Items';
})
export class FrontcraftUserComponent implements OnInit{
newPw
newPwConfirm
ranks = _Rank
myProfile = false
manageUser
user:User = {} as any
characters : (Character & Spec)[] = []
constructor(
private route: ActivatedRoute,
private api : ApiService
private api : ApiService,
private toastr: NbToastrService
){}
async ngOnInit(){
const param = this.route.snapshot.paramMap.get('name');
const usr = await this.api.get('UserManager').getUser(param)
if(!usr) return
this.user = usr
this.manageUser = this.api.get('manageUser')
this.myProfile = this.api.getCurrentUser().username === this.user.username
const characters = await this.api.get('CharacterManager').getCharactersOfUser(this.user.username)
characters.forEach(async c => {
const tokens = await this.api.get('ItemManager').getTokens(c, _Tiers, true)
@@ -35,4 +46,24 @@ export class FrontcraftUserComponent implements OnInit{
})
this.characters = characters
}
async onSelectRank(){
const manage = this.api.get('manageUser')
if(!manage) return
await manage.changeRank(this.user, this.user.rank)
this.toastr.success("Rank changed to "+this.user.rank, "Update success")
}
async submitPasswordChange(){
const pw = await hash(this.newPw)
this.newPw = null
this.newPwConfirm = null
const manage = this.api.get('manageUser')
if(!manage){
await this.api.get('UserManager').changePassword(this.api.getAuth().token.value, pw)
}else{
await manage.adminChangePassword(this.user, pw)
}
}
}
@@ -6,6 +6,7 @@ import { CookieService } from 'ngx-cookie-service';
import { Router } from '@angular/router';
import { ShoutMessage } from '../../../../../backend/Components/Shoutbox/Interface';
import { saltedHash } from '../../../../../backend/Util/hash';
import { NbToastrService } from '@nebular/theme';
@Injectable()
export class ApiService{
@@ -16,7 +17,8 @@ export class ApiService{
constructor(
private injector: Injector,
private cookieSvc : CookieService,
private ngZone : NgZone
private ngZone : NgZone,
private toastr: NbToastrService
){}
getUnprivilegedSocket = () : RPCSocket & FrontcraftIfc => this.socket
@@ -30,30 +32,34 @@ export class ApiService{
auth.port,
window.location.hostname
)
const authSock = await sock.connect<RPCSocket & SomeOf<FrontcraftFeatureIfc>>(auth.token.value)
sock.hook('kick', () => {
console.log("I got kicked");
this.logout()
})
sock.hook('getUserData', () => auth)
sock.hook('navigate', (where:string) => {
this.ngZone.run( () => {
this.injector.get(Router).navigateByUrl(where)
})
})
sock.on('error', (e) => {
sock.destroy();
sock.on('close', async () => {
//handled via unprivileged socket
})
sock.on('error', async (e) => {
//handled via unprivileged socket
})
const authSock = await sock.connect<RPCSocket & SomeOf<FrontcraftFeatureIfc>>(auth.token.value)
this.auth = auth
this.privSocket = authSock
this.cookieSvc.set('token', JSON.stringify(auth))
return authSock
}catch(e){
//login failed
throw new Error(e)
if(this.privSocket) this.privSocket.destroy()
return;
}
}
@@ -76,12 +82,25 @@ export class ApiService{
login = async (username: string, password: string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
const pwHash = await hash(password)
const auth = await this.socket.UserManager.login(username, pwHash)
let auth
try{
auth = await this.socket.UserManager.login(username, pwHash)
}catch(e){
this.toastr.danger("Login failed", "Error")
return
}
if(!auth){
await this.logout()
this.toastr.danger("Login failed", "Error")
throw new Error("Login failed")
}
//attach error handler now so failed logins dont trigger reloads
this.socket.on('error', async (err) => {
location.reload()
})
const sock = await this.getPrivilegedSocket(auth)
return sock
}
@@ -93,26 +112,50 @@ export class ApiService{
logout = async () => {
this.cookieSvc.set('token', undefined)
if(this.auth) await this.socket.UserManager.logout(this.auth.user.username, this.auth.token.value)
if(this.auth){
try{
await this.socket.UserManager.logout(this.auth.user.username, this.auth.token.value)
}catch(e){
//socket is dead
}
}
if(this.privSocket) this.privSocket.destroy()
this.privSocket = null
this.auth = null
this.ngZone.run(() => {
this.injector.get(Router).navigate(['/auth']);
})
}
initialize = async () : Promise<any> => {
const sock = await RPCSocket.makeSocket<FrontcraftIfc>(20000, window.location.hostname)
if(this.socket){
this.socket.destroy()
this.socket = null
}
try{
let conn = new RPCSocket(20000, window.location.hostname)
conn.on('close', async () => {
})
this.socket = await conn.connect<FrontcraftIfc>()
}catch(e){
alert('Unable to connect. The server appears to be down.\nPress OK to refresh the page')
location.reload()
return;
}
this.socket = sock
try{
const cookie = JSON.parse(this.cookieSvc.get('token'))
if(cookie != null) {
try{
const auth = await sock.UserManager.getAuth(cookie.token.value)
if(!auth) return sock
const auth = await this.socket.UserManager.getAuth(cookie.token.value)
if(!auth) return this.socket
return await this.getPrivilegedSocket(auth)
}catch(e){
await this.logout()
+35 -12
View File
@@ -2,7 +2,35 @@
<html>
<head>
<meta charset="utf-8">
<title>ngx-admin Demo Application</title>
<title>Frontcraft</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat">
<style>
@import url('https://fonts.googleapis.com/css?family=Montserrat');
.loadTitle {
font-family: 'Montserrat';
text-align: center;
color: #FFF;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
letter-spacing: 1px;
padding-top: calc(50vh - 120px);
}
.loadH {
background-image: url('https://media.giphy.com/media/26BROrSHlmyzzHf3i/giphy.gif');
background-size: cover;
color: transparent;
background-clip: text;
-moz-background-clip: text;
-webkit-background-clip: text;
text-transform: uppercase;
font-size: min(10vw, 120px);
margin: 10px 0;
}
</style>
<base href="/">
@@ -11,17 +39,12 @@
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<ngx-app>Loading...</ngx-app>
<style>@-webkit-keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@-moz-keyframes spin{0%{-moz-transform:rotate(0)}100%{-moz-transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.spinner{position:fixed;top:0;left:0;width:100%;height:100%;z-index:1003;background: #000000;overflow:hidden} .spinner div:first-child{display:block;position:relative;left:50%;top:50%;width:150px;height:150px;margin:-75px 0 0 -75px;border-radius:50%;box-shadow:0 3px 3px 0 rgba(255,56,106,1);transform:translate3d(0,0,0);animation:spin 2s linear infinite} .spinner div:first-child:after,.spinner div:first-child:before{content:'';position:absolute;border-radius:50%} .spinner div:first-child:before{top:5px;left:5px;right:5px;bottom:5px;box-shadow:0 3px 3px 0 rgb(255, 228, 32);-webkit-animation:spin 3s linear infinite;animation:spin 3s linear infinite} .spinner div:first-child:after{top:15px;left:15px;right:15px;bottom:15px;box-shadow:0 3px 3px 0 rgba(61, 175, 255,1);animation:spin 1.5s linear infinite}</style>
<div id="nb-global-spinner" class="spinner">
<div class="blob blob-0"></div>
<div class="blob blob-1"></div>
<div class="blob blob-2"></div>
<div class="blob blob-3"></div>
<div class="blob blob-4"></div>
<div class="blob blob-5"></div>
<ngx-app></ngx-app>
<div id="nb-global-spinner" class="spinner" style="background-color: #111; height: 100vh;">
<div class="loadTitle">
<h1 class="loadH">Tranquil</h1>
</div>
</div>
</body>
</html>
+3
View File
@@ -55,3 +55,6 @@ import 'core-js/es7/object';
if (typeof SVGElement.prototype.contains === 'undefined') {
SVGElement.prototype.contains = HTMLDivElement.prototype.contains;
}
(window as any).global = window;
(window as any).global.Buffer = (window as any).global.Buffer || require('buffer').Buffer;