change pw, change rank UI, auto-refresh on disconnect, new loading screen
This commit is contained in:
@@ -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"
|
||||
},
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
externals: ['http', 'fs'],
|
||||
node: {global: true, fs: 'empty'}
|
||||
}
|
||||
Generated
+6102
-2794
File diff suppressed because it is too large
Load Diff
@@ -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 <input name="preMember" [(ngModel)]="character.name" nbInput>, a
|
||||
And my main is <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> This is not reversible <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
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user