浏览代码

SSR App

master
peter 5 年前
父节点
当前提交
b28f8bc7ce
共有 66 个文件被更改,包括 1352 次插入2836 次删除
  1. 0
    25
      angular.json
  2. 0
    5
      guild.json
  3. 0
    1
      index.html
  4. 103
    1989
      package-lock.json
  5. 13
    14
      package.json
  6. 28
    69
      src/backend/Admin/Admin.ts
  7. 0
    21
      src/backend/Admin/app.server.module.ts
  8. 211
    200
      src/backend/Components/User/UserManager.ts
  9. 0
    2
      src/backend/main.server.ts
  10. 0
    68
      src/backend/webpack.prod.js
  11. 22
    12
      src/frontend/angular.json
  12. 376
    7
      src/frontend/package-lock.json
  13. 22
    14
      src/frontend/package.json
  14. 47
    0
      src/frontend/server.ts
  15. 1
    10
      src/frontend/src/app/@core/core.module.ts
  16. 2
    2
      src/frontend/src/app/@theme/components/header/chat.component.ts
  17. 3
    4
      src/frontend/src/app/@theme/components/header/header.component.ts
  18. 1
    13
      src/frontend/src/app/@theme/components/tiny-mce/tiny-mce.component.ts
  19. 78
    9
      src/frontend/src/app/app-routing.module.ts
  20. 3
    15
      src/frontend/src/app/app.component.ts
  21. 13
    15
      src/frontend/src/app/app.module.ts
  22. 18
    0
      src/frontend/src/app/app.server.module.ts
  23. 1
    3
      src/frontend/src/app/frontcraft/auth/auth-layout.component.ts
  24. 0
    34
      src/frontend/src/app/frontcraft/auth/auth-routing.module.ts
  25. 0
    2
      src/frontend/src/app/frontcraft/auth/auth.module.ts
  26. 1
    1
      src/frontend/src/app/frontcraft/auth/login/login.component.html
  27. 15
    5
      src/frontend/src/app/frontcraft/auth/login/login.component.ts
  28. 6
    4
      src/frontend/src/app/frontcraft/auth/logout/logout.component.ts
  29. 3
    2
      src/frontend/src/app/frontcraft/auth/register/register.component.ts
  30. 1
    2
      src/frontend/src/app/frontcraft/pages/armory/armory.component.html
  31. 3
    2
      src/frontend/src/app/frontcraft/pages/armory/armory.component.ts
  32. 1
    2
      src/frontend/src/app/frontcraft/pages/character/character.component.html
  33. 3
    2
      src/frontend/src/app/frontcraft/pages/character/character.component.ts
  34. 2
    2
      src/frontend/src/app/frontcraft/pages/characters/characters.component.ts
  35. 16
    10
      src/frontend/src/app/frontcraft/pages/pages-layout.component.ts
  36. 0
    63
      src/frontend/src/app/frontcraft/pages/pages-routing.module.ts
  37. 0
    2
      src/frontend/src/app/frontcraft/pages/pages.module.ts
  38. 4
    3
      src/frontend/src/app/frontcraft/pages/raid/archive.component.ts
  39. 3
    2
      src/frontend/src/app/frontcraft/pages/raid/characterpicker.component.ts
  40. 44
    39
      src/frontend/src/app/frontcraft/pages/raid/raid.component.html
  41. 3
    2
      src/frontend/src/app/frontcraft/pages/raid/raid.component.ts
  42. 3
    2
      src/frontend/src/app/frontcraft/pages/raids/createraid.compontent.ts
  43. 3
    2
      src/frontend/src/app/frontcraft/pages/raids/raids.component.ts
  44. 15
    8
      src/frontend/src/app/frontcraft/pages/rules/rules.component.html
  45. 2
    2
      src/frontend/src/app/frontcraft/pages/rules/rules.component.ts
  46. 3
    2
      src/frontend/src/app/frontcraft/pages/shop/buytoken.component.ts
  47. 0
    2
      src/frontend/src/app/frontcraft/pages/shop/item.component.ts
  48. 3
    2
      src/frontend/src/app/frontcraft/pages/shop/itemselector.component.ts
  49. 4
    8
      src/frontend/src/app/frontcraft/pages/shop/shop.component.ts
  50. 0
    2
      src/frontend/src/app/frontcraft/pages/shop/wowhead.component.ts
  51. 8
    4
      src/frontend/src/app/frontcraft/pages/user/user.component.ts
  52. 3
    6
      src/frontend/src/app/frontcraft/permissions/changePermissions/changePermissions.component.ts
  53. 1
    2
      src/frontend/src/app/frontcraft/permissions/permissions-layout.component.ts
  54. 0
    24
      src/frontend/src/app/frontcraft/permissions/permissions-routing.module.ts
  55. 0
    2
      src/frontend/src/app/frontcraft/permissions/permissions.module.ts
  56. 23
    0
      src/frontend/src/app/frontcraft/services/ApiService.ts
  57. 28
    46
      src/frontend/src/app/frontcraft/services/client-login-api.ts
  58. 99
    0
      src/frontend/src/app/frontcraft/services/server-login-api.ts
  59. 9
    0
      src/frontend/src/main.server.ts
  60. 14
    3
      src/frontend/src/main.ts
  61. 0
    26
      src/frontend/src/tsconfig.app.json
  62. 24
    0
      src/frontend/tsconfig.app.json
  63. 9
    7
      src/frontend/tsconfig.json
  64. 15
    0
      src/frontend/tsconfig.server.json
  65. 36
    0
      src/frontend/webpack.server.config.js
  66. 3
    9
      tsconfig.json

+ 0
- 25
angular.json 查看文件

@@ -1,25 +0,0 @@
1
-{
2
-  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3
-  "version": 1,
4
-  "newProjectRoot": "projects",
5
-  "projects": {
6
-    "frontcraft": {
7
-      "projectType": "application",
8
-      "schematics": {},
9
-      "root": "",
10
-      "sourceRoot": "src/backend",
11
-      "prefix": "app",
12
-      "architect": {
13
-        "server": {
14
-          "builder": "@angular-devkit/build-angular:server",
15
-          "options": {
16
-            "outputPath": "dist/server",
17
-            "main": "src/backend/Launcher.ts",
18
-            "tsConfig": "tsconfig.json"
19
-          }
20
-        }
21
-      }
22
-    }
23
-  },
24
-  "defaultProject": "frontcraft"
25
-}

+ 0
- 5
guild.json 查看文件

@@ -1,5 +0,0 @@
1
-{
2
-  "name": "AAA",
3
-  "realm": "Gandling EU",
4
-  "description": "Wee woo"
5
-}

+ 0
- 1
index.html 查看文件

@@ -1 +0,0 @@
1
-<table><tr><td><!--nstart--><b class="q4">Spineshatter</b><!--nend--><!--ndstart--><!--ndend--><span class="q"><br>Item Level <!--ilvl-->73</span><br /><!--bo-->Binds when picked up<br />Unique<table width="100%"><tr><td>Main Hand</td><th><!--scstart2:4--><span class="q1">Mace</span><!--scend--></th></tr></table><table width="100%"><tr> <td><span><!--dmg-->99 - 184 Damage</span></td> <th>Speed <!--spd-->2.60</th> </tr></table><!--dps-->(54.42 damage per second)<br><span><!--stat4-->+9 Strength</span><br><span><!--stat7-->+16 Stamina</span><!--ebstats--><!--egstats--><!--eistats--><!--e--><!--ps--><br>Durability 105 / 105</td></tr></table><table><tr><td>Requires Level <!--rlvl-->60<br><span class="q2">Equip: <a href="https://classic.wowhead.com/spell=7518" class="q2">Increased Defense +5.</a></span><!--itemEffects:1--><div class="whtt-sellprice">Sell Price: <span class="moneygold">12</span> <span class="moneysilver">88</span> <span class="moneycopper">25</span></div><div class="whtt-extra whtt-droppedby">Dropped by: Razorgore the Untamed</div></td></tr></table>

+ 103
- 1989
package-lock.json
文件差异内容过多而无法显示
查看文件


+ 13
- 14
package.json 查看文件

@@ -4,19 +4,17 @@
4 4
   "version": "1.0.0",
5 5
   "scripts": {
6 6
     "tsc": "tsc",
7
-    "launch": "node dist/server/main.js",
7
+    "launch": "node lib/src/backend/Launcher.js",
8 8
     "start": "npm run build && npm run launch",
9 9
     "start-backend": "npm run build-backend && npm run launch",
10 10
     "test": "rm -rf data && npm run build-backend && mocha lib/test/backendTest.js",
11
-    "build": "npm run build-backend && npm run build-frontend",
12
-    "build-backend": "npm run clean-backend && tsc",
13
-    "build-frontend": "npm run clean-frontend && (mkdir static || rm -rf static/*) && npm run build-dashboard",
14
-    "build-dashboard": "cd src/frontend && npm i && npm run build && cp -r dist/* ../../static",
11
+    "build": "npm run build-frontend && npm run build-backend",
12
+    "build-backend": "npm run clean-backend && npm run tsc",
13
+    "build-frontend": "npm run clean-frontend && (mkdir dist || rm -rf dist/*) && npm run build-dashboard",
14
+    "build-dashboard": "cd src/frontend && npm run build && cp -r dist/* ../../dist",
15 15
     "clean": "rm -rf data && npm run clean-backend && npm run clean-frontend",
16
-    "clean-backend": "rm -rf lib plugins config widget .rpt2_cache *.js *.ts",
17
-    "clean-frontend": "rm -rf src/frontend/dist static",
18
-    "webpack": "webpack --config src/backend/webpack.prod.js --progress --colors",
19
-    "setangular": "ng update @angular/cli@8.2.2 @angular/core@8.2.2 @angular/compiler-cli@8.2.2"
16
+    "clean-backend": "rm -rf lib plugins config widget .rpt2_cache ",
17
+    "clean-frontend": "rm -rf src/frontend/dist dist"
20 18
   },
21 19
   "repository": {
22 20
     "type": "git",
@@ -32,6 +30,7 @@
32 30
     "circular-buffer": "^1.0.2",
33 31
     "crypto-js": "^3.1.9-1",
34 32
     "debug": "^4.1.1",
33
+    "domino": "^2.1.4",
35 34
     "express": "^4.16.4",
36 35
     "frontblock": "^0.15.2",
37 36
     "frontblock-generic": "^0.34.8",
@@ -42,6 +41,7 @@
42 41
     "loadson": "^1.0.0",
43 42
     "log4js": "^4.5.1",
44 43
     "lowdb": "^1.0.0",
44
+    "ngx-cookie-service": "^2.4.0",
45 45
     "node-fetch": "^2.6.0",
46 46
     "path": "^0.12.7",
47 47
     "reflect-metadata": "^0.1.13",
@@ -54,16 +54,15 @@
54 54
     "tsyringe": "^4.0.1",
55 55
     "upgiter": "^1.0.4",
56 56
     "uuid": "^3.3.3",
57
-    "xml2js": "^0.4.22"
57
+    "xml2js": "^0.4.22",
58
+    "xmlhttprequest": "^1.8.0"
58 59
   },
59 60
   "devDependencies": {
60 61
     "madge": "^3.6.0",
61
-    "mocha": "^7.0.0",
62
+    "mocha": "^7.1.0",
62 63
     "terser-webpack-plugin": "^1.4.1",
63 64
     "ts-loader": "^5.3.3",
64
-    "typescript": "^3.5.3",
65
-    "webpack": "^4.39.2",
66
-    "webpack-cli": "^3.3.5"
65
+    "typescript": "^3.5.3"
67 66
   },
68 67
   "files": [
69 68
     "lib/**/*"

+ 28
- 69
src/backend/Admin/Admin.ts 查看文件

@@ -1,6 +1,6 @@
1 1
 'use strict'
2 2
 
3
-import { getLogger } from 'frontblock-generic/Types';
3
+import { getLogger, Logger, } from "log4js";
4 4
 import { promises as fs, mkdirSync } from "fs"
5 5
 import { RPCServer } from 'rpclibrary'
6 6
 import * as Path from 'path'
@@ -22,12 +22,7 @@ import { Injector } from '../Injector/Injector';
22 22
 import { Shoutbox } from '../Components/Shoutbox/Shoutbox';
23 23
 import { PubSub } from '../Components/PubSub/PubSub';
24 24
 
25
-//import { ngExpressEngine } from '../../frontend/node_modules/@nguniversal/express-engine';
26
-//import { APP_BASE_HREF } from '../../frontend/';
27
-//import { AppServerModule } from './app.server.module';
28
-
29
-
30
-const logger = getLogger("admin", 'debug') 
25
+getLogger().level = 'debug'
31 26
 
32 27
 @RootComponent({
33 28
     injectable: IAdmin,
@@ -73,15 +68,15 @@ implements TableDefinitionExporter, IAdmin {
73 68
         await this.makeKnex()
74 69
         this.startWebsocket()
75 70
         await Promise.all( this.frontworkComponents.map(c => c.initialize?c.initialize():undefined ))
76
-        logger.debug(this.frontworkComponents.length+" components initialized")
77
-        this.startWebserver()
71
+        getLogger('Admin#start').debug(this.frontworkComponents.length+" components initialized")
72
+        await this.startWebserver()
78 73
     }
79 74
 
80 75
     stop(){
81 76
         Promise.all([ 
82 77
             ...this.frontworkComponents.map(c => c.stop?c.stop():undefined ),
83 78
         ])
84
-        .catch(e => logger.warn(e))
79
+        .catch(e => getLogger('Admin#stop').warn(e))
85 80
         .finally(() => { 
86 81
             this.rpcServer.destroy()
87 82
             process.exit(0)
@@ -123,92 +118,56 @@ implements TableDefinitionExporter, IAdmin {
123 118
         ], {
124 119
             visibility: '0.0.0.0'
125 120
         })
126
-        logger.debug("Websocket up on", 20000)
121
+        getLogger('Admin#startWebsocket').debug("Websocket up on", 20000)
127 122
     }
128 123
 
129
-    private startWebserver(){
124
+    private async startWebserver(){
130 125
         if(this.httpServer != null || this.express != null){
131
-            logger.warn("Webserver is already running")
126
+            getLogger('Admin#startWebserver').warn("Webserver is already running")
132 127
             return
133 128
         }
134 129
         
135 130
         let port:number = this.config.getConfig().httpPort
136 131
         this.express = express()
137 132
 
138
-    /*
139
-        this.express.engine('html', ngExpressEngine({
140
-            bootstrap: AppServerModule,
141
-        }));
142
-        
143
-        this.express.set('view engine', 'html');
144
-        this.express.set('views', 'static');
145
-        
146
-          // Serve static files from /browser
147
-        this.express.get('*.*', express.static('static', {
148
-            maxAge: '1y'
149
-        }));
150
-
151
-        this.express.get("/", (request, response) => {
152
-            response.status(200)
153
-            response.sendFile('index.html');
154
-        })
155
-
156
-          // All regular routes use the Universal engine
157
-        this.express.get('*', (req, res) => {
158
-            res.status(301)
159
-            res.redirect('/')
160
-            //res.render('index', { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
161
-        });
162
-*/
163
-/* */
164
-        // get the compiled FrontendPlugins.js
165
-        this.express.use('/', express.static('static'))
166
-
167
-        this.express.get('/plugins/:id'+".js", async (request, response) => {
168
-            const pth = Path.resolve("plugins/"+request.params.id, "FrontendPlugin.js");
169
-            const file = await fs.readFile(pth)
170
-            const frontend = file.toString()
171
-
172
-            response.status(200)
173
-            response.set('Content-Type', 'application/javascript')
174
-            response.send(frontend)
175
-        })
133
+        const distFolder = "../../../../dist"
134
+        const ngExpressServer = Path.join(__dirname, distFolder, 'server.js')
176 135
 
177
-        // serve the index.html from the static folder
178
-        this.express.get("/", (request, response) => {
179
-            response.status(200)
180
-            response.sendFile('index.html');
136
+        this.express.get('*.*', (req, res)=>{
137
+            //console.log('*.*', req.path);
138
+            res.sendFile(Path.join(__dirname, distFolder,'browser',decodeURIComponent(req.path)))
181 139
         })
182 140
 
183
-        // redirect all the other traffic to the single page app
184
-        this.express.get("*", (request, response) => {
185
-            response.status(301)
186
-            response.redirect('/')
187
-        })
141
+        try{
142
+            const req = require(distFolder+"/server.js")
143
+            await req.attachExpress(this.express)
144
+            getLogger('Admin#startWebserver').info('Frontend from '+ngExpressServer+" loaded")
145
+        }catch(e){
146
+            getLogger('Admin#startWebserver').error(e)
147
+            getLogger('Admin#startWebserver').warn("No angular SSR module was provided in "+ngExpressServer)
148
+            getLogger('Admin#startWebserver').warn("This is not fatal, but your page will not render on *"+port)
149
+        }
188 150
 
189
-        this.httpServer = new http.Server(this.express)
190
-        this.httpServer.listen(port, () => {
191
-            logger.info('Admin panel listening for HTTP on *'+port)
151
+        this.express.listen(port, () => {
152
+            getLogger('Admin#startWebserver').info('Admin panel listening for HTTP on *'+port)
192 153
         })
193
-
194
-/* */
195 154
     }
196 155
 
197 156
     private stopWebserver(){
198 157
         if(this.httpServer == null || this.express == null){
199
-            logger.warn("Webserver is not running")
158
+            getLogger('Admin#stopWebserver').warn("Webserver is not running")
200 159
             return
201 160
         }
202 161
         this.httpServer.close()
203 162
         this.httpServer = null
204 163
         this.express = null
205
-        logger.info("Webserver stopped")
164
+        getLogger('Admin#stopWebserver').info("Webserver stopped")
206 165
     }
207 166
 
208 167
     async makeKnex():Promise<Knex>{
209 168
         const conf:Knex.Config = this.config.getConfigKey("dbConf")
210 169
 
211
-        logger.debug("Making new knex:", conf)        
170
+        getLogger('Admin#makeKnex').debug("Making new knex:", conf)        
212 171
         if(conf.client === 'sqlite3'){
213 172
             mkdirSync(Path.dirname((<any>conf.connection).filename), {recursive: true})
214 173
         }
@@ -237,6 +196,6 @@ implements TableDefinitionExporter, IAdmin {
237 196
 }
238 197
 
239 198
 process.on( 'SIGINT', function() {
240
-    logger.info("Shutting down from SIGINT (Ctrl-C)" );
199
+    getLogger('process#SIGINT').info("Shutting down from SIGINT (Ctrl-C)" );
241 200
     Injector.resolve<FrontworkAdmin>(FrontworkAdmin).stop()
242 201
 })

+ 0
- 21
src/backend/Admin/app.server.module.ts 查看文件

@@ -1,21 +0,0 @@
1
-/*
2
-import { NgModule } from '../../frontend/node_modules/@angular/core';
3
-import { ServerModule } from '../../frontend/node_modules/@angular/platform-server';
4
-import { ModuleMapLoaderModule } from '../../frontend/node_modules/@nguniversal/module-map-ngfactory-loader';
5
-
6
-import { AppModule } from '../../frontend/src/app/app.module';
7
-import { AppComponent } from '../../frontend/src/app/app.component';
8
-
9
-@NgModule({
10
-  imports: [
11
-    AppModule,
12
-    ServerModule,
13
-    ModuleMapLoaderModule
14
-  ],
15
-  providers: [
16
-    // Add universal-only providers here
17
-  ],
18
-  bootstrap: [ AppComponent ],
19
-})
20
-export class AppServerModule {}
21
-*/

+ 211
- 200
src/backend/Components/User/UserManager.ts 查看文件

@@ -17,40 +17,42 @@ import { IRaidManager } from "../Raid/Interface";
17 17
 import { IItemManager } from "../Item/Interface";
18 18
 import { IGuildManager } from "../Guild/Interface";
19 19
 
20
+getLogger().level = "debug"
21
+
20 22
 const uuid = require('uuid/v4')
21 23
 
22 24
 const salt = "6pIbc6yjSN"
23
-const ONE_WEEK = 604800000 
25
+const ONE_WEEK = 604800000
24 26
 
25 27
 type Serverstate<SubresT, InterfaceT extends RPCInterface> = {
26 28
     server: RPCServer<SubresT, InterfaceT>,
27
-    port : number,
29
+    port: number,
28 30
 };
29 31
 
30 32
 
31 33
 @Injectable(IUserManager)
32 34
 export class UserManager
33
-implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManager{
35
+    implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManager {
34 36
     name = "UserManager" as "UserManager"
35 37
 
36 38
     @Inject(IAdmin)
37 39
     private admin: IAdmin
38 40
 
39 41
     @Inject(IGuildManager)
40
-    private guild : GuildManager
41
-    
42
+    private guild: GuildManager
43
+
42 44
     @Inject(IItemManager)
43
-    private item : ItemManager
44
-    
45
+    private item: ItemManager
46
+
45 47
     @Inject(IRaidManager)
46
-    private raid : RaidManager
47
-    
48
+    private raid: RaidManager
49
+
48 50
     @Inject(ICharacterManager)
49
-    private character : CharacterManager
50
-    
51
-    exporters :any[] = []
52
-    rankServer : Serverstate<{}, FrontcraftFeatureIfc>
53
-    userLogins : {[username in string] : UserRecord} = {}
51
+    private character: CharacterManager
52
+
53
+    exporters: any[] = []
54
+    rankServer: Serverstate<{}, FrontcraftFeatureIfc>
55
+    userLogins: { [username in string]: UserRecord } = {}
54 56
     allowed: string[] = []
55 57
 
56 58
     exportRPCs = () => [
@@ -64,46 +66,46 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
64 66
     ]
65 67
 
66 68
     exportRPCFeatures = () => [
67
-    {
68
-        name: 'manageUser' as 'manageUser',
69
-        exportRPCs: () => [
70
-            this.adminLogout,
71
-            this.changeRank,
72
-            this.adminChangePassword
73
-        ]
74
-    },{
75
-        name: 'modifyPermissions' as 'modifyPermissions',
76
-        exportRPCs: () => [
77
-            this.getPermissions,
78
-            this.setPermission,
79
-        ]
80
-    },{
81
-        name: 'softreserveCurrency' as 'softreserveCurrency',
82
-        exportRPCs: () => [
83
-            this.incrementCurrency,
84
-            this.decrementCurrency,
85
-            this.setCurrency
86
-        ]
87
-    }]
88
-
89
-    changeRank = async (user:User, rank:Rank): Promise<User> => {
69
+        {
70
+            name: 'manageUser' as 'manageUser',
71
+            exportRPCs: () => [
72
+                this.adminLogout,
73
+                this.changeRank,
74
+                this.adminChangePassword
75
+            ]
76
+        }, {
77
+            name: 'modifyPermissions' as 'modifyPermissions',
78
+            exportRPCs: () => [
79
+                this.getPermissions,
80
+                this.setPermission,
81
+            ]
82
+        }, {
83
+            name: 'softreserveCurrency' as 'softreserveCurrency',
84
+            exportRPCs: () => [
85
+                this.incrementCurrency,
86
+                this.decrementCurrency,
87
+                this.setCurrency
88
+            ]
89
+        }]
90
+
91
+    changeRank = async (user: User, rank: Rank): Promise<User> => {
90 92
         await this.admin
91
-        .knex('users')
92
-        .where({
93
-            username: user.username
94
-        }).update({
95
-            rank: rank
96
-        })
93
+            .knex('users')
94
+            .where({
95
+                username: user.username
96
+            }).update({
97
+                rank: rank
98
+            })
97 99
 
98 100
         await this.adminLogout(user.username)
99 101
 
100 102
         return await this.admin
101
-        .knex('users')
102
-        .where({
103
-            username: user.username
104
-        }).first()
103
+            .knex('users')
104
+            .where({
105
+                username: user.username
106
+            }).first()
105 107
     }
106
-    
108
+
107 109
     getTableDefinitions = (): TableDefiniton[] => [
108 110
         {
109 111
             name: 'users',
@@ -116,40 +118,40 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
116 118
                     table.integer(tier).defaultTo(1)
117 119
                 })
118 120
             }
119
-        },{
121
+        }, {
120 122
             name: 'rpcpermissions',
121 123
             tableBuilder: (table) => {
122 124
                 table.string("rpcname").primary().notNullable()
123 125
                 _Rank.forEach(r => {
124
-                    if(r === 'ADMIN')
126
+                    if (r === 'ADMIN')
125 127
                         table.boolean(r).defaultTo(true).notNullable()
126 128
                     else
127 129
                         table.boolean(r).defaultTo(false).notNullable()
128 130
                 })
129 131
             }
130 132
         }
131
-        ,...this.exporters.flatMap(exp => exp['getTableDefinitions']?exp['getTableDefinitions']():undefined)
133
+        , ...this.exporters.flatMap(exp => exp['getTableDefinitions'] ? exp['getTableDefinitions']() : undefined)
132 134
     ]
133 135
 
134 136
     initialize = async () => {
135
-        this.exporters = [this.guild, this.item, this.raid, this.character] 
137
+        this.exporters = [this.guild, this.item, this.raid, this.character]
136 138
         //set up permissions
137
-        getLogger('UserManager').debug('setting up permissions')
139
+        getLogger('UserManager#initialize').debug('setting up permissions')
138 140
 
139
-        await Promise.all( 
141
+        await Promise.all(
140 142
             [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
141
-            try{
142
-                await this.admin.knex.insert({ rpcname: feature.name }).into('rpcpermissions')
143
-            }catch(e){
144
-            }
145
-        })))
143
+                try {
144
+                    await this.admin.knex.insert({ rpcname: feature.name }).into('rpcpermissions')
145
+                } catch (e) {
146
+                }
147
+            })))
146 148
 
147 149
         const rankServer = await this.startRankServer(20001)
148 150
         this.rankServer = {
149 151
             server: rankServer,
150 152
             port: 20001
151 153
         }
152
-        setInterval(this.checkExpiredSessions, 600_000)   
154
+        setInterval(this.checkExpiredSessions, 600_000)
153 155
     }
154 156
 
155 157
     stop = async () => {
@@ -157,115 +159,111 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
157 159
             Object.values(x.connections).forEach(c => c.destroy())
158 160
         })
159 161
 
160
-        try{
162
+        try {
161 163
             return this.rankServer.server.destroy()
162
-        }catch(e){
163
-            //getLogger('UserManager').warn(e)
164
+        } catch (e) {
165
+            getLogger('UserManager#stop').debug(String(e))
164 166
         }
165 167
     }
166 168
 
167 169
     checkExpiredSessions = () => {
168 170
         Object.values(this.userLogins).map(userLogin => {
169 171
             const auth = userLogin.auth
170
-            if(!this.checkToken(auth.token.value)){
172
+            if (!this.checkToken(auth.token.value)) {
171 173
                 this.logout(auth.user.username, auth.token.value)
172 174
             }
173 175
         })
174 176
     }
175 177
 
176
-    checkConnection = async (socket: Socket) => {
177
-        
178
-        let data : any
179
-        let tries = 0
180
-        while(!data){
181
-            tries ++
182
-            if(tries === 5){
183
-                getLogger('UserManager').debug('Connection check failed for connection *'+socket.port)
184
-                socket.destroy()
185
-                return false
178
+    checkConnection = async (socket: Socket, retries = 0) : Promise<boolean> => {
179
+        if(retries < 0){
180
+            return false
181
+        }
182
+        //give the client some time to bind its hooks
183
+        await new Promise((res, rej) => { setTimeout(res, 150);})
184
+
185
+        let data
186
+        try{
187
+            data = await Promise.race([socket.call('getUserData'), new Promise((res, rej) => { setTimeout(res, 250);})])
188
+        }catch(e){
189
+            getLogger('UserManager#checkConnection').debug('Client didn\'t respond', e)
190
+            return false
191
+        }
192
+
193
+        if(!data) {
194
+            if(retries > 0){
195
+                return await this.checkConnection(socket, retries-1)
186 196
             }
187
-            data = await Promise.race([socket.call('getUserData'), new Promise((res, rej) => { setTimeout(res, 1000);})])
197
+            return false
188 198
         }
189
-        if(!this.userLogins[data.user.username]){
199
+
200
+        if (!this.userLogins[data.user.username]) {
190 201
             await this.logout(data.user.username, data.token.value)
191 202
             return false
192 203
         }
193 204
 
194 205
         this.userLogins[data.user.username].connections[socket.port] = socket
195
-        await socket.call('navigate', ["/frontcraft/dashboard"])
206
+        getLogger('UserManager#checkConnection').debug(this.userLogins, this.allowed);
207
+        
196 208
         return true
197 209
     }
198 210
 
199
-    changePassword = async (userToken:string, pwHash:string) : Promise<User> => {
211
+    changePassword = async (userToken: string, pwHash: string): Promise<User> => {
200 212
         const record = this.getUserRecordByToken(userToken)
201
-        if(!record) return {} as User
213
+        if (!record) return {} as User
202 214
         return await this.adminChangePassword(record.user, pwHash)
203 215
     }
204 216
 
205
-    adminChangePassword = async(user:User, pwHash:string) : Promise<User> => {
217
+    adminChangePassword = async (user: User, pwHash: string): Promise<User> => {
206 218
         const salted = await saltedHash(pwHash, salt)
207 219
         await this.admin.knex('users')
208
-        .update({pwhash: salted})
209
-        .where({
210
-            username: user.username
211
-        })
220
+            .update({ pwhash: salted })
221
+            .where({
222
+                username: user.username
223
+            })
212 224
 
213 225
         const usr = await this.getUser(user.username)
214
-        if(!usr) return {} as any
226
+        if (!usr) return {} as any
215 227
         await this.adminLogout(usr.username)
216 228
         return usr
217 229
     }
218 230
 
219 231
     setPermission = async (permission: RPCPermission) => {
220 232
         await this.admin.knex('rpcpermissions')
221
-        .where('rpcname', '=', permission.rpcname)
222
-        .update(permission)
233
+            .where('rpcname', '=', permission.rpcname)
234
+            .update(permission)
223 235
 
224 236
         await Promise.all(
225 237
             Object.entries(this.userLogins).map(([username, record]) => {
226
-                if(record.user.rank === "ADMIN") return
238
+                if (record.user.rank === "ADMIN") return
227 239
                 return this.adminLogout(username)
228 240
             })
229 241
         )
230 242
     }
231 243
 
232
-    getPermissions = async () : Promise<RPCPermission[]> => {
244
+    getPermissions = async (): Promise<RPCPermission[]> => {
233 245
         return await this.admin.knex.select('*').from('rpcpermissions')
234 246
     }
235 247
 
236
-    getPermission = async (feature: keyof FrontcraftFeatureIfc, rank:Rank) : Promise<boolean> => {
237
-        const perm : RPCPermission = await this.admin.knex
248
+    getPermission = async (feature: keyof FrontcraftFeatureIfc, rank: Rank): Promise<boolean> => {
249
+        const perm: RPCPermission = await this.admin.knex
238 250
             .select(rank)
239 251
             .from('rpcpermissions')
240 252
             .where('rpcname', '=', <string>feature)
241 253
             .first()
242 254
 
243
-        if(!perm) return false
255
+        if (!perm) return false
244 256
         return perm[rank]
245 257
     }
246 258
 
247
-    getRPCForRank = async (rank: Rank): Promise<AnyRPCExporter[]> => {
248
-        let rpcs = [
249
-            ...this.exportRPCFeatures(), 
250
-            ...this.exporters.flatMap((exp) => exp.exportRPCFeatures())
251
-        ]
252
-        
253
-        const bits = await  Promise.all(rpcs.map(async (feature) => {
254
-            const allowed = await this.getPermission(<keyof FrontcraftFeatureIfc> feature.name, rank)
255
-            return allowed
256
-        }))
257
-
258
-        return rpcs.filter(entry => bits.shift())
259
-    }
260
-
261
-    createUser = async(user:User): Promise<User> => {
262
-        if(user.rank === 'ADMIN'){
259
+    createUser = async (user: User): Promise<User> => {
260
+        if (user.rank === 'ADMIN') {
263 261
             const admins = await this.admin.knex
264 262
                 .select("*")
265 263
                 .from('users')
266
-                .where({rank: 'ADMIN'})
264
+                .where({ rank: 'ADMIN' })
267 265
 
268
-            if(admins.length > 0){
266
+            if (admins.length > 0) {
269 267
                 return {} as User
270 268
             }
271 269
         }
@@ -273,128 +271,139 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
273 271
         user.pwhash = await saltedHash(user.pwhash, salt)
274 272
 
275 273
         await this.admin.knex('users')
276
-        .insert(user)
274
+            .insert(user)
277 275
 
278 276
         const userRecord = await this.admin.knex
279
-        .select("*")
280
-        .from('users')
281
-        .where(user)
282
-        .first()
277
+            .select("*")
278
+            .from('users')
279
+            .where(user)
280
+            .first()
283 281
 
284 282
         return userRecord
285 283
     }
286 284
 
287
-    getUser = async (username: string) : Promise<User | void> => await this.admin
288
-    .knex('users')
289
-    .select('*')
290
-    .where({
291
-        username: username.toLowerCase()
292
-    })
293
-    .first()
285
+    getUser = async (username: string): Promise<User | void> => await this.admin
286
+        .knex('users')
287
+        .select('*')
288
+        .where({
289
+            username: username.toLowerCase()
290
+        })
291
+        .first()
294 292
 
295
-    logout = async (username:string, tokenValue : string) : Promise<void> => {
296
-        try{
297
-            if(!this.checkTokenOwnedByUser(username, tokenValue)) return
293
+    logout = async (username: string, tokenValue: string): Promise<void> => {
294
+        try {
295
+            if (!this.checkTokenOwnedByUser(username, tokenValue)) return
298 296
             return await this.adminLogout(username)
299
-        }catch(e){
297
+        } catch (e) {
300 298
 
301 299
         }
302 300
     }
303 301
 
304
-    adminLogout = async(username: string) : Promise<void> => {
305
-        try{
306
-            if(this.userLogins[username]){
307
-                await Promise.all (Object.values(this.userLogins[username].connections).map(async (sock) => {
308
-                    await sock.call('kick')
309
-                }))
310
-            
311
-                this.allowed = this.allowed.filter(allowed => allowed !== this.userLogins[username].auth.token.value)
302
+    adminLogout = async (username: string): Promise<void> => {
303
+        try {
304
+            if (this.userLogins[username]) {
305
+                const token = this.userLogins[username].auth.token.value
306
+                //doesn't matter if error or success
307
+                Object.values(this.userLogins[username].connections).forEach(async (sock) => {
308
+                    try{
309
+                        await sock.call('kick')
310
+                    }catch(e){
311
+                        //getLogger('UserManager#adminLogout#kick').debug(String(e))
312
+                    }
313
+                })
314
+                this.allowed = this.allowed.filter(allowed => {
315
+                    return allowed != token
316
+                })
312 317
                 delete this.userLogins[username]
313 318
             }
314
-        }catch(e){}
319
+        } catch (e) {
320
+            getLogger('UserManager#adminLogout').debug(String(e), this.userLogins)
321
+        }
315 322
     }
316 323
 
317 324
     wipeCurrency = async () => {
318 325
         await Promise.all(_Tiers.map(tier => {
319 326
             const update = {}
320 327
             update[tier] = 1
321
-    
328
+
322 329
             return this.admin.knex('users')
323
-            .update(update)
330
+                .update(update)
324 331
         }))
325 332
     }
326 333
 
327
-    login = async(username:string, pwHash:string) : Promise<Auth> => {
334
+    login = async (username: string, pwHash: string): Promise<Auth> => {
328 335
         username = username.toLowerCase()
329
-        const user:User = await this.admin.knex
330
-        .select('*')
331
-        .from('users')
332
-        .where({ username: username })
333
-        .first()
334
-         
336
+        const user: User = await this.admin.knex
337
+            .select('*')
338
+            .from('users')
339
+            .where({ username: username })
340
+            .first()
341
+
335 342
         const salted = await saltedHash(pwHash, salt)
336 343
 
337
-        if(user && salted === user.pwhash){
344
+        if (user && salted === user.pwhash) {
338 345
             delete user.pwhash
339 346
 
340 347
             //return existing auth
341
-            if(this.userLogins[username] != null){
348
+            if (this.userLogins[username] != null) {
342 349
                 return this.userLogins[username].auth
343 350
             }
344
-            
351
+
345 352
             const token = this.createToken(user)
346
-            const userAuth : Auth = {
353
+            const userAuth: Auth = {
347 354
                 token: token,
348 355
                 user: user,
349 356
                 port: this.rankServer.port
350 357
             }
351 358
 
352
-            this.userLogins[user.username] = {connections: {}, auth: userAuth, user:user}
359
+            this.userLogins[user.username] = { connections: {}, auth: userAuth, user: user }
353 360
             this.allowed.push(token.value)
354
-            return userAuth 
361
+
362
+            return userAuth
355 363
         }
356 364
 
357 365
         throw new Error('login failed')
358 366
     }
359 367
 
360
-    getUserRecordByToken(tokenValue: string){
368
+    getUserRecordByToken(tokenValue: string) {
361 369
         return Object.values(this.userLogins).find(login => login.auth.token.value === tokenValue)
362 370
     }
363 371
 
364
-    getAuth = async (tokenValue:string) : Promise<Auth | void> => {
372
+    getAuth = async (tokenValue: string): Promise<Auth | void> => {
365 373
         const maybeAuth = this.getUserRecordByToken(tokenValue)
366
-        if(maybeAuth)
374
+        if (maybeAuth)
367 375
             return maybeAuth.auth
368 376
         return
369 377
     }
370 378
 
371
-    startRankServer = async (port: number) : Promise<RPCServer<{},FrontcraftFeatureIfc>> => {
379
+    startRankServer = async (port: number): Promise<RPCServer<{}, FrontcraftFeatureIfc>> => {
372 380
         let rpcs = [
373
-            ...this.exportRPCFeatures(), 
381
+            ...this.exportRPCFeatures(),
374 382
             ...this.exporters.flatMap((exp) => exp.exportRPCFeatures())
375 383
         ]
376
-        let rpcServer = new RPCServer<{},FrontcraftFeatureIfc>(port, rpcs, {
384
+        let rpcServer = new RPCServer<{}, FrontcraftFeatureIfc>(port, rpcs, {
377 385
             accessFilter: async (sesame, exporter) => {
378 386
                 const record = this.getUserRecordByToken(sesame!)
379
-                if(!record) return false
387
+                if (!record) return false
380 388
                 return await this.getPermission(exporter.name, record.user.rank)
381 389
             },
382
-            closeHandler: (socket) => { 
383
-                Object.values(this.userLogins)
384
-                    .forEach(login => delete login.connections[socket.port])
385
-
390
+            closeHandler: (socket) => {
391
+                Object.values(this.userLogins).forEach(login => delete login.connections[socket.port])
392
+                getLogger('UserManager#closeHandler').debug(this.userLogins, this.allowed)
386 393
             },
387 394
             connectionHandler: (socket) => {
388
-                this.checkConnection(socket).then(res => {
389
-                    if(!res){
395
+                this.checkConnection(socket, 10).then(res => {
396
+                    if (!res) {
397
+                        getLogger('UserManager#connectionHandler').debug("Connection on "+socket.port+" failed to authenticate")
390 398
                         socket.destroy();
391 399
                     }
392 400
                 }).catch((e) => {
401
+                    getLogger('UserManager#connectionHandler').debug(String(e))
393 402
                     socket.destroy();
394 403
                 })
395 404
             },
396 405
             errorHandler: (socket, e, rpcName, args) => {
397
-                getLogger('UserManager').error(rpcName, args, e);
406
+                getLogger('UserManager#errorHandler').error(rpcName, args, e);
398 407
             },
399 408
             sesame: (sesame) => this.checkToken(sesame),
400 409
             visibility: '0.0.0.0'
@@ -403,25 +412,27 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
403 412
         return rpcServer
404 413
     }
405 414
 
406
-    checkToken = (token: string) : boolean => this.allowed.includes(token)
407
-                                            && Object.values(this.userLogins).find(login => login.auth.token.value === token)!.auth.token.created > Date.now() - ONE_WEEK
408
-
415
+    checkToken = (token: string): boolean => {
416
+        return this.allowed.includes(token)
417
+            && Object.values(this.userLogins).find(login => login.auth.token.value === token)!.auth.token.created > Date.now() - ONE_WEEK
418
+    }
419
+    
409 420
     checkTokenOwnedByUser = (username: string, tokenValue: string) => {
410 421
         username = username.toLowerCase()
411 422
         const maybeRecord = this.getUserRecordByToken(tokenValue)
412
-        if(!maybeRecord || maybeRecord.auth.user.username != username){
423
+        if (!maybeRecord || maybeRecord.auth.user.username != username) {
413 424
             return false
414
-        } 
425
+        }
415 426
         return true
416 427
     }
417
-                                                       
418
-    createToken = (user:User): Token => {
419
-        
420
-        if(this.userLogins[user.username]){
428
+
429
+    createToken = (user: User): Token => {
430
+
431
+        if (this.userLogins[user.username]) {
421 432
             return this.userLogins[user.username].auth.token
422 433
         }
423 434
 
424
-        const token:Token = {
435
+        const token: Token = {
425 436
             value: uuid(),
426 437
             user_id: user.id!,
427 438
             created: Date.now()
@@ -430,47 +441,47 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
430 441
         return token
431 442
     }
432 443
 
433
-    getCurrency = async(user:User, tier?: Tiers) : Promise<number> => { 
434
-        if(!tier) return 0
435
-        const usr : User = await this.admin
436
-        .knex('users')
437
-        .where('username', '=', user.username)
438
-        .select('*')
439
-        .first()
444
+    getCurrency = async (user: User, tier?: Tiers): Promise<number> => {
445
+        if (!tier) return 0
446
+        const usr: User = await this.admin
447
+            .knex('users')
448
+            .where('username', '=', user.username)
449
+            .select('*')
450
+            .first()
440 451
 
441 452
         return usr[tier]!
442 453
     }
443 454
 
444 455
     decrementCurrency = async (user: User, tier?: Tiers, value = 1) => {
445
-        if(!tier || value < 1) return
456
+        if (!tier || value < 1) return
446 457
 
447
-        const usr : User = await this.admin
448
-        .knex('users')
449
-        .where('id', '=', user.id)
450
-        .select('*')
451
-        .first()
458
+        const usr: User = await this.admin
459
+            .knex('users')
460
+            .where('id', '=', user.id)
461
+            .select('*')
462
+            .first()
452 463
 
453
-        if(!usr || usr[tier]! <= 0) return
464
+        if (!usr || usr[tier]! <= 0) return
454 465
 
455 466
         await this.admin
456
-        .knex('users')
457
-        .where('id', '=', user.id)
458
-        .decrement(tier, value)
467
+            .knex('users')
468
+            .where('id', '=', user.id)
469
+            .decrement(tier, value)
459 470
     }
460 471
 
461 472
     incrementCurrency = async (user: User, tier: Tiers, value = 1) => {
462
-        if(!tier || value < 1) return
473
+        if (!tier || value < 1) return
463 474
         await this.admin
464
-        .knex('users')
465
-        .where('id', '=', user.id)
466
-        .increment(tier, value)
475
+            .knex('users')
476
+            .where('id', '=', user.id)
477
+            .increment(tier, value)
467 478
     }
468 479
 
469
-    setCurrency = async (user: User, tier?:Tiers, value = 0) => {
470
-        if(!tier || value < 0) return
480
+    setCurrency = async (user: User, tier?: Tiers, value = 0) => {
481
+        if (!tier || value < 0) return
471 482
         await this.admin
472
-        .knex('users')
473
-        .where('id', '=', user.id)
474
-        .update(tier, value)
483
+            .knex('users')
484
+            .where('id', '=', user.id)
485
+            .update(tier, value)
475 486
     }
476 487
 }

+ 0
- 2
src/backend/main.server.ts 查看文件

@@ -1,2 +0,0 @@
1
-//import { enableProdMode } from '../frontend/node_modules/@angular/core';
2
-//enableProdMode();

+ 0
- 68
src/backend/webpack.prod.js 查看文件

@@ -1,68 +0,0 @@
1
-const path = require('path');
2
-
3
-module.exports = [{
4
-  mode: 'production',
5
-  target: "node",
6
-  node: {
7
-    global: true,
8
-    process: true,
9
-    __filename: false,
10
-    __dirname: false,
11
-    Buffer: true,
12
-  },
13
-  
14
-  resolve: {
15
-    // Add `.ts` and `.tsx` as a resolvable extension.
16
-
17
-    extensions: [".ts", ".tsx", ".js"]
18
-  },
19
-  module: {
20
-    rules: [
21
-      { test: /\.ts?$/, loader: "ts-loader" }
22
-    ]
23
-  },
24
-
25
-  externals: ['knex'],
26
-  optimization: {
27
-    minimize: false
28
-  },
29
-  entry: path.resolve(__dirname, 'Installer.ts'),
30
-  output: {
31
-      path: path.resolve(__dirname, '../../dist'),
32
-      filename: 'Installer.js',
33
-      libraryTarget: 'commonjs',
34
-  }
35
-},{
36
-  mode: 'production',
37
-  target: "node",
38
-  node: {
39
-    global: true,
40
-    process: true,
41
-    __filename: false,
42
-    __dirname: false,
43
-    Buffer: true,
44
-  },
45
-
46
-  
47
-  resolve: {
48
-    // Add `.ts` and `.tsx` as a resolvable extension.
49
-
50
-    extensions: [".ts", ".tsx", ".js"]
51
-  },
52
-  module: {
53
-    rules: [
54
-      { test: /\.ts?$/, loader: "ts-loader" }
55
-    ]
56
-  },
57
-
58
-  externals:["./Installer"],
59
-  optimization: {
60
-    minimize: false
61
-  },
62
-  entry: path.resolve(__dirname, 'Launcher.ts'),
63
-  output: {
64
-      path: path.resolve(__dirname, '../../dist'),
65
-      filename: 'FrontblockAdmin.js',
66
-      libraryTarget: 'commonjs',
67
-  }
68
-}]

+ 22
- 12
src/frontend/angular.json 查看文件

@@ -13,10 +13,10 @@
13 13
           "options": {
14 14
             "preserveSymlinks": true,
15 15
             "rebaseRootRelativeCssUrls": true,
16
-            "outputPath": "dist",
16
+            "outputPath": "dist/browser",
17 17
             "index": "src/index.html",
18 18
             "main": "src/main.ts",
19
-            "tsConfig": "src/tsconfig.app.json",
19
+            "tsConfig": "./tsconfig.app.json",
20 20
             "polyfills": "src/polyfills.ts",
21 21
             "assets": [
22 22
               "src/assets",
@@ -51,20 +51,13 @@
51 51
               "node_modules/echarts/dist/echarts.min.js",
52 52
               "node_modules/echarts/dist/extension/bmap.min.js",
53 53
               "node_modules/chart.js/dist/Chart.min.js",
54
-              "node_modules/rpclibrary/js/browser/rpclibrary.browser.js"
54
+              "node_modules/rpclibrary/js/browser/rpclibrary.browser.js",
55
+              "node_modules/js-cookie/src/js.cookie.js"
55 56
             ]
56 57
           },
57 58
           "configurations": {
58 59
             "production": {
59
-              "optimization": true,
60
-              "outputHashing": "all",
61
-              "sourceMap": false,
62
-              "extractCss": true,
63
-              "namedChunks": false,
64 60
               "aot": true,
65
-              "extractLicenses": true,
66
-              "vendorChunk": false,
67
-              "buildOptimizer": true,
68 61
               "fileReplacements": [
69 62
                 {
70 63
                   "replace": "src/environments/environment.ts",
@@ -136,7 +129,7 @@
136 129
           "builder": "@angular-devkit/build-angular:tslint",
137 130
           "options": {
138 131
             "tsConfig": [
139
-              "src/tsconfig.app.json",
132
+              "./tsconfig.app.json",
140 133
               "src/tsconfig.spec.json"
141 134
             ],
142 135
             "typeCheck": true,
@@ -167,6 +160,23 @@
167 160
           }
168 161
         }
169 162
       }
163
+    },
164
+    "frontcraft": {
165
+      "projectType": "application",
166
+      "schematics": {},
167
+      "root": "",
168
+      "sourceRoot": "",
169
+      "prefix": "app",
170
+      "architect": {
171
+        "server": {
172
+          "builder": "@angular-devkit/build-angular:server",
173
+          "options": {
174
+            "outputPath": "dist/server",
175
+            "main": "./src/main.server.ts",
176
+            "tsConfig": "./tsconfig.server.json"
177
+          }
178
+        }
179
+      }
170 180
     }
171 181
   },
172 182
   "defaultProject": "ngx-admin-demo",

+ 376
- 7
src/frontend/package-lock.json 查看文件

@@ -425,6 +425,7 @@
425 425
       "version": "8.2.14",
426 426
       "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-8.2.14.tgz",
427 427
       "integrity": "sha512-ABZO4E7eeFA1QyJ2trDezxeQM5ZFa1dXw1Mpl/+1vuXDKNjJgNyWYwKp/NwRkLmrsuV0yv4UDCDe4kJOGbPKnw==",
428
+      "dev": true,
428 429
       "requires": {
429 430
         "tslib": "^1.9.0"
430 431
       }
@@ -1350,6 +1351,16 @@
1350 1351
         "tslib": "^1.9.0"
1351 1352
       }
1352 1353
     },
1354
+    "@angular/platform-server": {
1355
+      "version": "8.2.14",
1356
+      "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-8.2.14.tgz",
1357
+      "integrity": "sha512-gGAgxMmac5CyLcwgB+qCD1o75An0NmpREh/lxPgz6n6Zs9JqdqpZROLSIHqGBaU6MWo1qiOfS6L08HwYPx7ipQ==",
1358
+      "requires": {
1359
+        "domino": "^2.1.2",
1360
+        "tslib": "^1.9.0",
1361
+        "xhr2": "^0.1.4"
1362
+      }
1363
+    },
1353 1364
     "@angular/router": {
1354 1365
       "version": "8.2.14",
1355 1366
       "resolved": "https://registry.npmjs.org/@angular/router/-/router-8.2.14.tgz",
@@ -2511,11 +2522,11 @@
2511 2522
       "integrity": "sha512-jX6R5lApSBtPHcZzgJ1+URxvJhmSodX+YcuDnuYsQJB1nkpC0Kjs6XL5OEONVg4NaoYcxMYmnxRe51lrlQdilg=="
2512 2523
     },
2513 2524
     "@nebular/theme": {
2514
-      "version": "4.4.0",
2515
-      "resolved": "https://registry.npmjs.org/@nebular/theme/-/theme-4.4.0.tgz",
2516
-      "integrity": "sha512-UcK1hwMvJXDROU9QiCfRq5LXRV9gB+K+AJtg1UYhvNJ+NzZkLyn+P+wFNX0StI91BjjNw3T699Xvz4B0grWhlA==",
2525
+      "version": "4.6.0",
2526
+      "resolved": "https://registry.npmjs.org/@nebular/theme/-/theme-4.6.0.tgz",
2527
+      "integrity": "sha512-S7topzx0Hf9D7YkQxKJ8UB1G2/sEN3o4eKjkRe8Xv5n7H3WqpKQ9Uef3oW2mTf75dmICBldhKXvopdr6TA5foA==",
2517 2528
       "requires": {
2518
-        "intersection-observer": "0.5.0"
2529
+        "intersection-observer": "0.7.0"
2519 2530
       }
2520 2531
     },
2521 2532
     "@ngtools/webpack": {
@@ -2542,6 +2553,24 @@
2542 2553
         }
2543 2554
       }
2544 2555
     },
2556
+    "@nguniversal/common": {
2557
+      "version": "9.0.1",
2558
+      "resolved": "https://registry.npmjs.org/@nguniversal/common/-/common-9.0.1.tgz",
2559
+      "integrity": "sha512-AprW7oREmywDudrBI1auy4lB6AQFKHLeebdY7vAXjviIEzBDm9Zd1Z59SqFtp+H4Pce8R7tQ3zoXY1n7azCigg=="
2560
+    },
2561
+    "@nguniversal/express-engine": {
2562
+      "version": "9.0.1",
2563
+      "resolved": "https://registry.npmjs.org/@nguniversal/express-engine/-/express-engine-9.0.1.tgz",
2564
+      "integrity": "sha512-uICu/CVrKuRYKUhpn91tRoERRhorDH038zyUsQt3yqsKV5BXyclr+H0lHh94dXyi+W0RKmksvzGNshwc4IWnUA==",
2565
+      "requires": {
2566
+        "@nguniversal/common": "9.0.1"
2567
+      }
2568
+    },
2569
+    "@nguniversal/module-map-ngfactory-loader": {
2570
+      "version": "8.2.6",
2571
+      "resolved": "https://registry.npmjs.org/@nguniversal/module-map-ngfactory-loader/-/module-map-ngfactory-loader-8.2.6.tgz",
2572
+      "integrity": "sha512-YcxXSrDZt6iDR+YbesJvprNpHd1nRLeThJwAFlcwvK/GVGSyKeWV6eqk3bRkBkgkw8OwaG/4lOQ4aofxQw+13w=="
2573
+    },
2545 2574
     "@nodelib/fs.stat": {
2546 2575
       "version": "1.1.3",
2547 2576
       "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz",
@@ -6490,6 +6519,12 @@
6490 6519
       "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
6491 6520
       "dev": true
6492 6521
     },
6522
+    "detect-file": {
6523
+      "version": "1.0.0",
6524
+      "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
6525
+      "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
6526
+      "dev": true
6527
+    },
6493 6528
     "detect-indent": {
6494 6529
       "version": "4.0.0",
6495 6530
       "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
@@ -6785,6 +6820,11 @@
6785 6820
         "domelementtype": "1"
6786 6821
       }
6787 6822
     },
6823
+    "domino": {
6824
+      "version": "2.1.4",
6825
+      "resolved": "https://registry.npmjs.org/domino/-/domino-2.1.4.tgz",
6826
+      "integrity": "sha512-l70mlQ7IjPKC8kT7GljQXJZmt5OqFL+RE91ik5y5WWQtsd9wP8R7gpFnNu96fK5MqAAZRXfLLsnzKtkty5fWGQ=="
6827
+    },
6788 6828
     "domutils": {
6789 6829
       "version": "1.5.1",
6790 6830
       "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
@@ -7547,6 +7587,15 @@
7547 7587
         }
7548 7588
       }
7549 7589
     },
7590
+    "expand-tilde": {
7591
+      "version": "2.0.2",
7592
+      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
7593
+      "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
7594
+      "dev": true,
7595
+      "requires": {
7596
+        "homedir-polyfill": "^1.0.1"
7597
+      }
7598
+    },
7550 7599
     "express": {
7551 7600
       "version": "4.17.1",
7552 7601
       "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
@@ -8011,6 +8060,18 @@
8011 8060
       "integrity": "sha1-WKRmaX34piBc39vzlVNri9d3pfY=",
8012 8061
       "dev": true
8013 8062
     },
8063
+    "findup-sync": {
8064
+      "version": "3.0.0",
8065
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
8066
+      "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==",
8067
+      "dev": true,
8068
+      "requires": {
8069
+        "detect-file": "^1.0.0",
8070
+        "is-glob": "^4.0.0",
8071
+        "micromatch": "^3.0.4",
8072
+        "resolve-dir": "^1.0.1"
8073
+      }
8074
+    },
8014 8075
     "flat-cache": {
8015 8076
       "version": "1.3.4",
8016 8077
       "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz",
@@ -8907,6 +8968,41 @@
8907 8968
       "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=",
8908 8969
       "dev": true
8909 8970
     },
8971
+    "global-modules": {
8972
+      "version": "2.0.0",
8973
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
8974
+      "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==",
8975
+      "dev": true,
8976
+      "requires": {
8977
+        "global-prefix": "^3.0.0"
8978
+      },
8979
+      "dependencies": {
8980
+        "global-prefix": {
8981
+          "version": "3.0.0",
8982
+          "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz",
8983
+          "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==",
8984
+          "dev": true,
8985
+          "requires": {
8986
+            "ini": "^1.3.5",
8987
+            "kind-of": "^6.0.2",
8988
+            "which": "^1.3.1"
8989
+          }
8990
+        }
8991
+      }
8992
+    },
8993
+    "global-prefix": {
8994
+      "version": "1.0.2",
8995
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
8996
+      "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
8997
+      "dev": true,
8998
+      "requires": {
8999
+        "expand-tilde": "^2.0.2",
9000
+        "homedir-polyfill": "^1.0.1",
9001
+        "ini": "^1.3.4",
9002
+        "is-windows": "^1.0.1",
9003
+        "which": "^1.2.14"
9004
+      }
9005
+    },
8910 9006
     "globals": {
8911 9007
       "version": "11.12.0",
8912 9008
       "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
@@ -9610,10 +9706,16 @@
9610 9706
         "ipaddr.js": "^1.9.0"
9611 9707
       }
9612 9708
     },
9709
+    "interpret": {
9710
+      "version": "1.2.0",
9711
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
9712
+      "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==",
9713
+      "dev": true
9714
+    },
9613 9715
     "intersection-observer": {
9614
-      "version": "0.5.0",
9615
-      "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.5.0.tgz",
9616
-      "integrity": "sha512-8Zgt4ijlyvIrQVTA7MPb2W9+KhoetrAbxlh0RmTGxpx0+ZsAXvy7IsbNnZIrqZ6TddAdWeQj49x7Ph7Ir6KRkA=="
9716
+      "version": "0.7.0",
9717
+      "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.7.0.tgz",
9718
+      "integrity": "sha512-Id0Fij0HsB/vKWGeBe9PxeY45ttRiBmhFyyt/geBdDHBYNctMRTE3dC1U3ujzz3lap+hVXlEcVaB56kZP/eEUg=="
9617 9719
     },
9618 9720
     "intl": {
9619 9721
       "version": "1.2.5",
@@ -10261,6 +10363,11 @@
10261 10363
       "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz",
10262 10364
       "integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ=="
10263 10365
     },
10366
+    "js-cookie": {
10367
+      "version": "2.2.1",
10368
+      "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
10369
+      "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
10370
+    },
10264 10371
     "js-tokens": {
10265 10372
       "version": "4.0.0",
10266 10373
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -15544,6 +15651,29 @@
15544 15651
         "resolve-from": "^3.0.0"
15545 15652
       }
15546 15653
     },
15654
+    "resolve-dir": {
15655
+      "version": "1.0.1",
15656
+      "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
15657
+      "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
15658
+      "dev": true,
15659
+      "requires": {
15660
+        "expand-tilde": "^2.0.0",
15661
+        "global-modules": "^1.0.0"
15662
+      },
15663
+      "dependencies": {
15664
+        "global-modules": {
15665
+          "version": "1.0.0",
15666
+          "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
15667
+          "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
15668
+          "dev": true,
15669
+          "requires": {
15670
+            "global-prefix": "^1.0.1",
15671
+            "is-windows": "^1.0.1",
15672
+            "resolve-dir": "^1.0.0"
15673
+          }
15674
+        }
15675
+      }
15676
+    },
15547 15677
     "resolve-from": {
15548 15678
       "version": "3.0.0",
15549 15679
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
@@ -18531,6 +18661,12 @@
18531 18661
       "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
18532 18662
       "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
18533 18663
     },
18664
+    "v8-compile-cache": {
18665
+      "version": "2.0.3",
18666
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz",
18667
+      "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==",
18668
+      "dev": true
18669
+    },
18534 18670
     "v8flags": {
18535 18671
       "version": "3.1.3",
18536 18672
       "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz",
@@ -19409,6 +19545,234 @@
19409 19545
         "webpack-sources": "^1.4.1"
19410 19546
       }
19411 19547
     },
19548
+    "webpack-cli": {
19549
+      "version": "3.3.11",
19550
+      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.11.tgz",
19551
+      "integrity": "sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g==",
19552
+      "dev": true,
19553
+      "requires": {
19554
+        "chalk": "2.4.2",
19555
+        "cross-spawn": "6.0.5",
19556
+        "enhanced-resolve": "4.1.0",
19557
+        "findup-sync": "3.0.0",
19558
+        "global-modules": "2.0.0",
19559
+        "import-local": "2.0.0",
19560
+        "interpret": "1.2.0",
19561
+        "loader-utils": "1.2.3",
19562
+        "supports-color": "6.1.0",
19563
+        "v8-compile-cache": "2.0.3",
19564
+        "yargs": "13.2.4"
19565
+      },
19566
+      "dependencies": {
19567
+        "ansi-regex": {
19568
+          "version": "4.1.0",
19569
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
19570
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
19571
+          "dev": true
19572
+        },
19573
+        "ansi-styles": {
19574
+          "version": "3.2.1",
19575
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
19576
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
19577
+          "dev": true,
19578
+          "requires": {
19579
+            "color-convert": "^1.9.0"
19580
+          }
19581
+        },
19582
+        "camelcase": {
19583
+          "version": "5.3.1",
19584
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
19585
+          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
19586
+          "dev": true
19587
+        },
19588
+        "chalk": {
19589
+          "version": "2.4.2",
19590
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
19591
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
19592
+          "dev": true,
19593
+          "requires": {
19594
+            "ansi-styles": "^3.2.1",
19595
+            "escape-string-regexp": "^1.0.5",
19596
+            "supports-color": "^5.3.0"
19597
+          },
19598
+          "dependencies": {
19599
+            "supports-color": {
19600
+              "version": "5.5.0",
19601
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
19602
+              "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
19603
+              "dev": true,
19604
+              "requires": {
19605
+                "has-flag": "^3.0.0"
19606
+              }
19607
+            }
19608
+          }
19609
+        },
19610
+        "cliui": {
19611
+          "version": "5.0.0",
19612
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
19613
+          "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
19614
+          "dev": true,
19615
+          "requires": {
19616
+            "string-width": "^3.1.0",
19617
+            "strip-ansi": "^5.2.0",
19618
+            "wrap-ansi": "^5.1.0"
19619
+          }
19620
+        },
19621
+        "cross-spawn": {
19622
+          "version": "6.0.5",
19623
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
19624
+          "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
19625
+          "dev": true,
19626
+          "requires": {
19627
+            "nice-try": "^1.0.4",
19628
+            "path-key": "^2.0.1",
19629
+            "semver": "^5.5.0",
19630
+            "shebang-command": "^1.2.0",
19631
+            "which": "^1.2.9"
19632
+          }
19633
+        },
19634
+        "emoji-regex": {
19635
+          "version": "7.0.3",
19636
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
19637
+          "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
19638
+          "dev": true
19639
+        },
19640
+        "find-up": {
19641
+          "version": "3.0.0",
19642
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
19643
+          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
19644
+          "dev": true,
19645
+          "requires": {
19646
+            "locate-path": "^3.0.0"
19647
+          }
19648
+        },
19649
+        "get-caller-file": {
19650
+          "version": "2.0.5",
19651
+          "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
19652
+          "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
19653
+          "dev": true
19654
+        },
19655
+        "invert-kv": {
19656
+          "version": "2.0.0",
19657
+          "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
19658
+          "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
19659
+          "dev": true
19660
+        },
19661
+        "is-fullwidth-code-point": {
19662
+          "version": "2.0.0",
19663
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
19664
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
19665
+          "dev": true
19666
+        },
19667
+        "lcid": {
19668
+          "version": "2.0.0",
19669
+          "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
19670
+          "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
19671
+          "dev": true,
19672
+          "requires": {
19673
+            "invert-kv": "^2.0.0"
19674
+          }
19675
+        },
19676
+        "os-locale": {
19677
+          "version": "3.1.0",
19678
+          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
19679
+          "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
19680
+          "dev": true,
19681
+          "requires": {
19682
+            "execa": "^1.0.0",
19683
+            "lcid": "^2.0.0",
19684
+            "mem": "^4.0.0"
19685
+          }
19686
+        },
19687
+        "require-main-filename": {
19688
+          "version": "2.0.0",
19689
+          "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
19690
+          "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
19691
+          "dev": true
19692
+        },
19693
+        "string-width": {
19694
+          "version": "3.1.0",
19695
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
19696
+          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
19697
+          "dev": true,
19698
+          "requires": {
19699
+            "emoji-regex": "^7.0.1",
19700
+            "is-fullwidth-code-point": "^2.0.0",
19701
+            "strip-ansi": "^5.1.0"
19702
+          }
19703
+        },
19704
+        "strip-ansi": {
19705
+          "version": "5.2.0",
19706
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
19707
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
19708
+          "dev": true,
19709
+          "requires": {
19710
+            "ansi-regex": "^4.1.0"
19711
+          }
19712
+        },
19713
+        "supports-color": {
19714
+          "version": "6.1.0",
19715
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
19716
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
19717
+          "dev": true,
19718
+          "requires": {
19719
+            "has-flag": "^3.0.0"
19720
+          }
19721
+        },
19722
+        "which-module": {
19723
+          "version": "2.0.0",
19724
+          "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
19725
+          "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
19726
+          "dev": true
19727
+        },
19728
+        "wrap-ansi": {
19729
+          "version": "5.1.0",
19730
+          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
19731
+          "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
19732
+          "dev": true,
19733
+          "requires": {
19734
+            "ansi-styles": "^3.2.0",
19735
+            "string-width": "^3.0.0",
19736
+            "strip-ansi": "^5.0.0"
19737
+          }
19738
+        },
19739
+        "y18n": {
19740
+          "version": "4.0.0",
19741
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
19742
+          "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
19743
+          "dev": true
19744
+        },
19745
+        "yargs": {
19746
+          "version": "13.2.4",
19747
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz",
19748
+          "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==",
19749
+          "dev": true,
19750
+          "requires": {
19751
+            "cliui": "^5.0.0",
19752
+            "find-up": "^3.0.0",
19753
+            "get-caller-file": "^2.0.1",
19754
+            "os-locale": "^3.1.0",
19755
+            "require-directory": "^2.1.1",
19756
+            "require-main-filename": "^2.0.0",
19757
+            "set-blocking": "^2.0.0",
19758
+            "string-width": "^3.0.0",
19759
+            "which-module": "^2.0.0",
19760
+            "y18n": "^4.0.0",
19761
+            "yargs-parser": "^13.1.0"
19762
+          }
19763
+        },
19764
+        "yargs-parser": {
19765
+          "version": "13.1.1",
19766
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
19767
+          "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
19768
+          "dev": true,
19769
+          "requires": {
19770
+            "camelcase": "^5.0.0",
19771
+            "decamelize": "^1.2.0"
19772
+          }
19773
+        }
19774
+      }
19775
+    },
19412 19776
     "webpack-core": {
19413 19777
       "version": "0.6.9",
19414 19778
       "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz",
@@ -20508,6 +20872,11 @@
20508 20872
       "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=",
20509 20873
       "dev": true
20510 20874
     },
20875
+    "xhr2": {
20876
+      "version": "0.1.4",
20877
+      "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.1.4.tgz",
20878
+      "integrity": "sha1-f4dliEdxbbUCYyOBL4GMras4el8="
20879
+    },
20511 20880
     "xml2js": {
20512 20881
       "version": "0.4.23",
20513 20882
       "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",

+ 22
- 14
src/frontend/package.json 查看文件

@@ -11,10 +11,11 @@
11 11
   },
12 12
   "scripts": {
13 13
     "ng": "ng",
14
+    "webpack:server": "webpack --config webpack.server.config.js",
14 15
     "conventional-changelog": "conventional-changelog",
15 16
     "start": "ng serve",
16
-    "build": "ng build",
17
-    "build:prod": "npm run build -- --prod --aot",
17
+    "build": "rm -rf dist serverBundle && npm run ngbuild && ng run frontcraft:server && webpack --config webpack.server.config",
18
+    "ngbuild": "ng build --prod",
18 19
     "test": "ng test",
19 20
     "test:coverage": "rimraf coverage && npm run test -- --code-coverage",
20 21
     "lint": "ng lint",
@@ -26,25 +27,29 @@
26 27
     "docs": "compodoc -p src/tsconfig.app.json -d docs",
27 28
     "docs:serve": "compodoc -p src/tsconfig.app.json -d docs -s",
28 29
     "prepush": "npm run lint:ci",
29
-    "release:changelog": "npm run conventional-changelog -- -p angular -i CHANGELOG.md -s"
30
+    "release:changelog": "npm run conventional-changelog -- -p angular -i CHANGELOG.md -s",
31
+    "add": "ng add @nguniversal/express-engine",
32
+    "tsc": "tsc --project src/tsconfig.server.json && webpack --config extra-webpack.config.js"
30 33
   },
31 34
   "dependencies": {
32 35
     "@agm/core": "^1.0.0-beta.5",
33
-    "@angular-builders/custom-webpack": "^8.2.0",
34
-    "@angular/animations": "^8.0.0",
35
-    "@angular/cdk": "^8.0.0",
36
-    "@angular/common": "^8.0.0",
37
-    "@angular/compiler": "^8.0.0",
38
-    "@angular/core": "^8.0.0",
36
+    "@angular-builders/custom-webpack": "^8.4.1",
37
+    "@angular/animations": "^8.2.14",
38
+    "@angular/cdk": "^8.2.3",
39
+    "@angular/common": "^8.2.14",
40
+    "@angular/core": "^8.2.14",
39 41
     "@angular/forms": "^8.0.0",
40 42
     "@angular/platform-browser": "^8.0.0",
41
-    "@angular/platform-browser-dynamic": "^8.0.0",
43
+    "@angular/platform-browser-dynamic": "^8.2.14",
44
+    "@angular/platform-server": "^8.2.14",
42 45
     "@angular/router": "^8.0.0",
43 46
     "@asymmetrik/ngx-leaflet": "3.0.1",
44 47
     "@nebular/auth": "4.4.0",
45 48
     "@nebular/eva-icons": "4.4.0",
46 49
     "@nebular/security": "4.4.0",
47
-    "@nebular/theme": "^4.4.0",
50
+    "@nebular/theme": "^4.6.0",
51
+    "@nguniversal/express-engine": "^9.0.1",
52
+    "@nguniversal/module-map-ngfactory-loader": "^8.2.6",
48 53
     "@swimlane/ngx-charts": "^10.0.0",
49 54
     "angular-tree-component": "7.2.0",
50 55
     "angular2-chartjs": "0.4.1",
@@ -58,6 +63,7 @@
58 63
     "eva-icons": "^1.1.0",
59 64
     "intl": "1.2.5",
60 65
     "ionicons": "2.0.1",
66
+    "js-cookie": "^2.2.1",
61 67
     "leaflet": "1.2.0",
62 68
     "nebular-icons": "1.1.0",
63 69
     "ng2-ckeditor": "^1.2.2",
@@ -81,8 +87,9 @@
81 87
   },
82 88
   "devDependencies": {
83 89
     "@angular-devkit/build-angular": "~0.803.24",
84
-    "@angular/cli": "^8.0.2",
85
-    "@angular/compiler-cli": "^8.0.0",
90
+    "@angular/cli": "^8.3.25",
91
+    "@angular/compiler": "^8.2.14",
92
+    "@angular/compiler-cli": "^8.2.14",
86 93
     "@angular/language-service": "8.0.0",
87 94
     "@compodoc/compodoc": "^1.1.11",
88 95
     "@fortawesome/fontawesome-free": "^5.2.0",
@@ -109,6 +116,7 @@
109 116
     "ts-node": "3.2.2",
110 117
     "tslint": "^5.7.0",
111 118
     "tslint-language-service": "^0.9.9",
112
-    "typescript": "^3.5.1"
119
+    "typescript": "^3.5.1",
120
+    "webpack-cli": "^3.3.11"
113 121
   }
114 122
 }

+ 47
- 0
src/frontend/server.ts 查看文件

@@ -0,0 +1,47 @@
1
+import 'zone.js/dist/zone-node';
2
+import 'reflect-metadata';
3
+
4
+import { ngExpressEngine } from '@nguniversal/express-engine';
5
+import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
6
+import { resolve } from 'path';
7
+import { enableProdMode } from '@angular/core';
8
+const domino = require('domino');
9
+const win = domino.createWindow('');
10
+
11
+global['window'] = win;
12
+global['document'] = win.document;
13
+global['alert'] = console.log
14
+global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest;
15
+
16
+export async function attachExpress(app, staticDir = "./dist") {
17
+  const STATIC_FOLDER = resolve(process.cwd(), staticDir);
18
+
19
+  enableProdMode();
20
+
21
+  const bundle = require(staticDir + '/server/main');
22
+
23
+  const ServerApiService = bundle.ServerApiService
24
+  const serviceObj = new ServerApiService()
25
+  await serviceObj.initialize()
26
+
27
+  app.set('view engine', 'html');
28
+  app.engine(
29
+    'html',
30
+    ngExpressEngine({
31
+      bootstrap: bundle.AppServerModuleNgFactory,
32
+      providers: [
33
+        provideModuleMap(bundle.LAZY_MODULE_MAP),
34
+        {
35
+          provide: bundle.IApiService,
36
+          useValue: serviceObj,
37
+          deps: []
38
+        }
39
+      ]
40
+    })
41
+  );
42
+
43
+  app.get('*', (req, res) => {
44
+    //console.log('*', req.path);
45
+    res.render(resolve(STATIC_FOLDER, 'browser/index'), { req, res })
46
+  });
47
+}

+ 1
- 10
src/frontend/src/app/@core/core.module.ts 查看文件

@@ -1,20 +1,11 @@
1
-import { ModuleWithProviders, NgModule, Optional, SkipSelf, APP_INITIALIZER } from '@angular/core';
1
+import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
2 2
 import { CommonModule } from '@angular/common';
3 3
 import { throwIfAlreadyLoaded } from './module-import-guard';
4 4
 
5
-import { ApiService, initializeLoginSvc } from '../frontcraft/services/login-api';
6 5
 import { CookieService } from 'ngx-cookie-service';
7 6
 import { LayoutService } from './utils';
8 7
 
9 8
 const DATA_SERVICES = [  
10
-  {provide: ApiService, useClass: ApiService},
11
-  {provide: CookieService, useClass: CookieService},
12
-  {
13
-    provide: APP_INITIALIZER,
14
-    useFactory: initializeLoginSvc,
15
-    deps: [ApiService, CookieService],
16
-    multi: true
17
-  }
18 9
 ];
19 10
 
20 11
 export const NB_CORE_PROVIDERS = [

+ 2
- 2
src/frontend/src/app/@theme/components/header/chat.component.ts 查看文件

@@ -1,6 +1,6 @@
1 1
 import { Component } from '@angular/core';
2
-import { ApiService } from '../../../frontcraft/services/login-api';
3 2
 import { ShoutMessage } from '../../../../../../backend/Components/Shoutbox/Interface';
3
+import { IApiService } from '../../../frontcraft/services/ApiService';
4 4
 
5 5
 @Component({
6 6
   selector: 'chat',
@@ -31,7 +31,7 @@ export class ChatComponent {
31 31
   history
32 32
 
33 33
   constructor(
34
-    private api: ApiService
34
+    private api: IApiService
35 35
   ) {}
36 36
 
37 37
   submit(event){

+ 3
- 4
src/frontend/src/app/@theme/components/header/header.component.ts 查看文件

@@ -1,14 +1,14 @@
1 1
 import { Component, OnDestroy, OnInit } from '@angular/core';
2
-import { NbMediaBreakpointsService, NbSidebarService, NbThemeService, NbMenuItem, NbDialogService } from '@nebular/theme';
2
+import { NbSidebarService, NbThemeService, NbMenuItem, NbDialogService } from '@nebular/theme';
3 3
 
4 4
 import { LayoutService } from '../../../@core/utils';
5 5
 import { map, takeUntil } from 'rxjs/operators';
6 6
 import { Subject } from 'rxjs';
7
-import { ApiService } from '../../../frontcraft/services/login-api';
8 7
 import { User } from '../../../../../../backend/Types/Types';
9 8
 import { Router } from '@angular/router';
10 9
 import { ChatComponent } from './chat.component';
11 10
 import { ShoutMessage } from '../../../../../../backend/Components/Shoutbox/Interface';
11
+import { IApiService } from '../../../frontcraft/services/ApiService';
12 12
 
13 13
 @Component({
14 14
   selector: 'ngx-header',
@@ -54,8 +54,7 @@ export class HeaderComponent implements OnInit, OnDestroy {
54 54
               private router: Router,
55 55
               private themeService: NbThemeService,
56 56
               private layoutService: LayoutService,
57
-              private breakpointService: NbMediaBreakpointsService,
58
-              private api: ApiService,
57
+              private api: IApiService,
59 58
               private dialogService : NbDialogService
60 59
              ) {}
61 60
 

+ 1
- 13
src/frontend/src/app/@theme/components/tiny-mce/tiny-mce.component.ts 查看文件

@@ -17,21 +17,9 @@ export class TinyMCEComponent implements OnDestroy, AfterViewInit {
17 17
   ) { }
18 18
 
19 19
   ngAfterViewInit() {
20
-    tinymce.init({
21
-      target: this.host.nativeElement,
22
-      plugins: ['link', 'paste', 'table'],
23
-      skin_url: `${this.locationStrategy.getBaseHref()}assets/skins/lightgray`,
24
-      setup: editor => {
25
-        this.editor = editor;
26
-        editor.on('keyup', () => {
27
-          this.editorKeyup.emit(editor.getContent());
28
-        });
29
-      },
30
-      height: '320',
31
-    });
20
+    
32 21
   }
33 22
 
34 23
   ngOnDestroy() {
35
-    tinymce.remove(this.editor);
36 24
   }
37 25
 }

+ 78
- 9
src/frontend/src/app/app-routing.module.ts 查看文件

@@ -1,25 +1,94 @@
1 1
 import { ExtraOptions, RouterModule, Routes } from '@angular/router';
2 2
 import { NgModule } from '@angular/core';
3
+import { PagesLayoutComponent } from './frontcraft/pages/pages-layout.component';
4
+import { FrontcraftUserComponent } from './frontcraft/pages/user/user.component';
5
+import { FrontcraftRaidComponent } from './frontcraft/pages/raid/raid.component';
6
+import { FrontcraftArchiveComponent } from './frontcraft/pages/raid/archive.component';
7
+import { FrontcraftRaidsComponent } from './frontcraft/pages/raids/raids.component';
8
+import { FrontcraftCharacterComponent } from './frontcraft/pages/character/character.component';
9
+import { FrontcraftCharactersComponent } from './frontcraft/pages/characters/characters.component';
10
+import { FrontcraftRulesComponent } from './frontcraft/pages/rules/rules.component';
11
+import { FrontcraftArmoryComponent } from './frontcraft/pages/armory/armory.component';
12
+import { RegisterComponent } from './frontcraft/auth/register/register.component';
13
+import { LogoutComponent } from './frontcraft/auth/logout/logout.component';
14
+import { MyLoginComponent } from './frontcraft/auth/login/login.component';
15
+import { AuthComponent } from './frontcraft/auth/auth-layout.component';
16
+import { ChangePermissionsComponent } from './frontcraft/permissions/changePermissions/changePermissions.component';
17
+import { PermissionsComponent } from './frontcraft/permissions/permissions-layout.component';
3 18
 
4 19
 const routes: Routes = [
5 20
   {
6 21
     path: 'permissions',
7
-    loadChildren: () => import('./frontcraft/permissions/permissions.module')
8
-      .then(m => m.PermissionsModule),
22
+    component: PermissionsComponent,
23
+    children: [
24
+      {
25
+          path: '**',
26
+          component: ChangePermissionsComponent,
27
+      },
28
+    ]
9 29
   },
10 30
   {
11 31
     path: 'auth',
12
-    loadChildren: () => import('./frontcraft/auth/auth.module')
13
-      .then(m => m.MyAuthModule),
32
+    component: AuthComponent,
33
+        children: [
34
+            {
35
+                path: 'register',
36
+                component: RegisterComponent
37
+            },
38
+            {
39
+                path: 'logout',
40
+                component: LogoutComponent,
41
+            },
42
+            {
43
+                path: '**',
44
+                component: MyLoginComponent,
45
+            },
46
+        ]
14 47
   },
15 48
   {
16 49
     path: 'frontcraft',
17
-    loadChildren: () => import('./frontcraft/pages/pages.module')
18
-      .then(m => m.FrontcraftPagesModule),
50
+    component: PagesLayoutComponent,
51
+    children: [
52
+        {
53
+            path: 'user/:name',
54
+            component: FrontcraftUserComponent
55
+        },
56
+        {
57
+            path: 'raid/:id',
58
+            component: FrontcraftRaidComponent
59
+        },
60
+        {
61
+            path: 'archive/:id',
62
+            component: FrontcraftArchiveComponent
63
+        },
64
+        {
65
+            path: 'raids',
66
+            component: FrontcraftRaidsComponent
67
+        },
68
+        {
69
+            path: 'character/:name',
70
+            component: FrontcraftCharacterComponent
71
+        },
72
+        {
73
+            path: 'characters',
74
+            component: FrontcraftCharactersComponent
75
+        },
76
+        {
77
+            path: 'rules',
78
+            component: FrontcraftRulesComponent
79
+        },
80
+        {
81
+            path: 'armory',
82
+            component: FrontcraftArmoryComponent
83
+        },
84
+        {
85
+            path: '**',
86
+            redirectTo: 'raids'
87
+        },
88
+    ]
19 89
   },
20
-  
21
-  { path: '', redirectTo: 'frontcraft', pathMatch: 'full' },
22
-  { path: '**', redirectTo: 'frontcraft' },
90
+  { path: '', redirectTo: 'frontcraft/raids', pathMatch: 'full' },
91
+  { path: '**', redirectTo: 'frontcraft/raids' },     
23 92
 ];
24 93
 
25 94
 const config: ExtraOptions = {

+ 3
- 15
src/frontend/src/app/app.component.ts 查看文件

@@ -3,9 +3,7 @@
3 3
  * Copyright Akveo. All Rights Reserved.
4 4
  * Licensed under the MIT License. See License.txt in the project root for license information.
5 5
  */
6
-import { Component, OnInit, Inject, PLATFORM_ID, APP_ID } from '@angular/core';
7
-import { ApiService } from './frontcraft/services/login-api';
8
-import { isPlatformBrowser } from '@angular/common';
6
+import { Component, OnInit } from '@angular/core';
9 7
 
10 8
 @Component({
11 9
   selector: 'ngx-app',
@@ -13,17 +11,7 @@ import { isPlatformBrowser } from '@angular/common';
13 11
 })
14 12
 export class AppComponent implements OnInit {
15 13
 
16
-  constructor(
17
-    private loginSvc: ApiService,
18
-    @Inject(PLATFORM_ID) private platformId: Object,
19
-    @Inject(APP_ID) private appId: string
20
-  ) {
21
-      if(!isPlatformBrowser(platformId)){
22
-        global['window'] = {}
23
-      }
24
-  }
14
+  constructor() {  }
25 15
 
26
-  ngOnInit(): void {
27
-
28
-  }
16
+  ngOnInit(): void { }
29 17
 }

+ 13
- 15
src/frontend/src/app/app.module.ts 查看文件

@@ -5,7 +5,7 @@
5 5
  */
6 6
 import { BrowserModule } from '@angular/platform-browser';
7 7
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
8
-import { NgModule, APP_INITIALIZER } from '@angular/core';
8
+import { NgModule, APP_INITIALIZER, NgZone, Injector } from '@angular/core';
9 9
 import { HttpClientModule } from '@angular/common/http';
10 10
 import { ThemeModule } from './@theme/theme.module';
11 11
 import { AppComponent } from './app.component';
@@ -19,14 +19,17 @@ import {
19 19
   NbToastrModule,
20 20
   NbWindowModule,
21 21
 } from '@nebular/theme';
22
-import { ApiService, initializeLoginSvc } from './frontcraft/services/login-api';
23
-import { CookieService } from 'ngx-cookie-service';
24 22
 import { CoreModule } from './@core/core.module';
23
+import { FrontcraftPagesModule } from './frontcraft/pages/pages.module';
24
+import { MyAuthModule } from './frontcraft/auth/auth.module';
25
+import { PermissionsModule } from './frontcraft/permissions/permissions.module';
25 26
 
26 27
 @NgModule({
27
-  declarations: [AppComponent],
28
+  declarations: [
29
+    AppComponent
30
+  ],
28 31
   imports: [
29
-    BrowserModule,
32
+    BrowserModule.withServerTransition({ appId: 'frontcraft' }),
30 33
     BrowserAnimationsModule,
31 34
     HttpClientModule,
32 35
     AppRoutingModule,
@@ -41,17 +44,12 @@ import { CoreModule } from './@core/core.module';
41 44
       messageGoogleMapKey: 'AIzaSyA_wNuCzia92MAmdLRzmqitRGvCF7wCZPY',
42 45
     }),
43 46
     CoreModule.forRoot(),
47
+    FrontcraftPagesModule,
48
+    MyAuthModule,
49
+    PermissionsModule
44 50
   ],
45 51
   bootstrap: [AppComponent],
46
-  providers: [
47
-    ApiService,
48
-    {
49
-        provide: APP_INITIALIZER,
50
-        deps: [CookieService],
51
-        multi: true,
52
-        useFactory: initializeLoginSvc
53
-    },
54
-  ]
52
+  providers: []
55 53
 })
56
-export class AppModule {
54
+export class FrontcraftAppModule {
57 55
 }

+ 18
- 0
src/frontend/src/app/app.server.module.ts 查看文件

@@ -0,0 +1,18 @@
1
+
2
+import { NgModule, APP_INITIALIZER } from '@angular/core';
3
+import { ServerModule } from '@angular/platform-server';
4
+import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';
5
+
6
+import { FrontcraftAppModule } from './app.module';
7
+import { AppComponent } from './app.component';
8
+
9
+@NgModule({
10
+  imports: [
11
+    FrontcraftAppModule,
12
+    ServerModule,
13
+    ModuleMapLoaderModule
14
+  ],
15
+  providers: [],
16
+  bootstrap: [ AppComponent ],
17
+})
18
+export class AppServerModule {}

+ 1
- 3
src/frontend/src/app/frontcraft/auth/auth-layout.component.ts 查看文件

@@ -1,5 +1,5 @@
1 1
 import { Component, OnInit } from '@angular/core';
2
-import { ApiService } from '../services/login-api';
2
+import { ClientApiService } from '../services/client-login-api';
3 3
 import { Router } from '@angular/router';
4 4
 
5 5
 @Component({
@@ -13,8 +13,6 @@ import { Router } from '@angular/router';
13 13
 
14 14
 export class AuthComponent implements OnInit{
15 15
   constructor(
16
-    private loginSvc : ApiService,
17
-    private router: Router  
18 16
   ){}
19 17
 
20 18
   ngOnInit(){

+ 0
- 34
src/frontend/src/app/frontcraft/auth/auth-routing.module.ts 查看文件

@@ -1,34 +0,0 @@
1
-import { NgModule } from '@angular/core';
2
-import { RouterModule, Routes } from '@angular/router';
3
-import { MyLoginComponent } from './login/login.component';
4
-import { AuthComponent } from './auth-layout.component';
5
-import { LogoutComponent } from './logout/logout.component';
6
-import { RegisterComponent } from './register/register.component';
7
-
8
-export const routes: Routes = [
9
-    {
10
-        path: '',
11
-        component: AuthComponent,
12
-        children: [
13
-            {
14
-                path: 'register',
15
-                component: RegisterComponent
16
-            },
17
-            {
18
-                path: 'logout',
19
-                component: LogoutComponent,
20
-            },
21
-            {
22
-                path: '**',
23
-                component: MyLoginComponent,
24
-            },
25
-        ]
26
-    }    
27
-];
28
-
29
-@NgModule({
30
-  imports: [RouterModule.forChild(routes)],
31
-  exports: [RouterModule],
32
-})
33
-export class MyAuthRoutingModule {
34
-}

+ 0
- 2
src/frontend/src/app/frontcraft/auth/auth.module.ts 查看文件

@@ -12,7 +12,6 @@ import {
12 12
   NbCardModule,
13 13
   NbSelectModule
14 14
 } from '@nebular/theme';
15
-import { MyAuthRoutingModule } from './auth-routing.module';
16 15
 import { MyLoginComponent } from './login/login.component';
17 16
 import { AuthComponent } from './auth-layout.component';
18 17
 import { ThemeModule } from '../../@theme/theme.module';
@@ -22,7 +21,6 @@ import { RegisterComponent } from './register/register.component';
22 21
 
23 22
 @NgModule({
24 23
   imports: [
25
-    MyAuthRoutingModule,
26 24
     CommonModule,
27 25
     FormsModule,
28 26
     RouterModule,

+ 1
- 1
src/frontend/src/app/frontcraft/auth/login/login.component.html 查看文件

@@ -29,7 +29,7 @@
29 29
            id="input-password"
30 30
            placeholder="Password"
31 31
            fieldSize="giant"
32
-           [status]="password.dirty ? (password.invalid  ? 'danger' : 'success') : ''"
32
+           [status]="password.dirty ? (password.invalid  ? 'danger' : 'success') : 'basic'"
33 33
            [required]="true"
34 34
            [minlength]="1"
35 35
            [maxlength]="15"

+ 15
- 5
src/frontend/src/app/frontcraft/auth/login/login.component.ts 查看文件

@@ -1,6 +1,8 @@
1 1
 import { Component, OnInit } from '@angular/core';
2
-import { ApiService } from '../../services/login-api';
2
+import { ClientApiService } from '../../services/client-login-api';
3 3
 import { Router } from '@angular/router';
4
+import { IApiService } from '../../services/ApiService';
5
+import { NbToastrService } from '@nebular/theme';
4 6
 
5 7
 @Component({
6 8
   selector: 'mylogin',
@@ -21,18 +23,26 @@ export class MyLoginComponent implements OnInit{
21 23
 
22 24
   constructor(
23 25
     private router : Router,  
24
-    private loginApi : ApiService
26
+    private api : IApiService,
27
+    private toastr: NbToastrService
25 28
   ){}
26 29
 
27 30
   ngOnInit(){
28
-    this.loginApi.checkLogin().then(loggedin => {
31
+    this.api.checkLogin().then(loggedin => {
29 32
       if(loggedin){
30 33
         this.router.navigateByUrl("/")
31 34
       }
32 35
     });
33 36
   }
34 37
 
35
-  login(){
36
-    this.loginApi.login(this.user.name, this.user.password)
38
+  async login(){
39
+    const login = await this.api.login(this.user.name, this.user.password)
40
+    if(!login){
41
+      this.toastr.danger("Login failed", "Error")
42
+      return
43
+    }else{
44
+      window['r'] = this.router
45
+      this.router.navigate(["/froncraft"])
46
+    }
37 47
   }
38 48
 }

+ 6
- 4
src/frontend/src/app/frontcraft/auth/logout/logout.component.ts 查看文件

@@ -1,5 +1,5 @@
1 1
 import { Component, OnInit } from '@angular/core';
2
-import { ApiService } from '../../services/login-api';
2
+import { IApiService } from '../../services/ApiService';
3 3
 import { Router } from '@angular/router';
4 4
 
5 5
 @Component({
@@ -9,11 +9,13 @@ import { Router } from '@angular/router';
9 9
 export class LogoutComponent implements OnInit{
10 10
 
11 11
   constructor(
12
-    private api : ApiService
12
+    private api : IApiService,
13
+    private router: Router
13 14
   ){}
14 15
 
15 16
   ngOnInit(){
16
-    this.api.logout()
17
+    this.api.logout().then(() => {
18
+      this.router.navigate(['/auth/login'])
19
+    })
17 20
   }
18
-
19 21
 }

+ 3
- 2
src/frontend/src/app/frontcraft/auth/register/register.component.ts 查看文件

@@ -1,9 +1,10 @@
1 1
 import { Component, OnInit } from '@angular/core';
2
-import { ApiService as ApiService, hash } from '../../services/login-api';
2
+import { ClientApiService as ClientApiService } from '../../services/client-login-api';
3 3
 import { Router } from '@angular/router';
4 4
 import { _Rank, _Class, Class, User, _Race  } from '../../../../../../backend/Types/Types'
5 5
 import { specs  } from '../../../../../../backend/Types/PlayerSpecs'
6 6
 import { race } from 'rxjs';
7
+import { hash, IApiService } from '../../services/ApiService';
7 8
 
8 9
 
9 10
 @Component({
@@ -33,7 +34,7 @@ export class RegisterComponent implements OnInit{
33 34
 
34 35
   constructor(
35 36
     private router : Router,  
36
-    private api : ApiService
37
+    private api : IApiService
37 38
   ){}
38 39
 
39 40
   ngOnInit(){

+ 1
- 2
src/frontend/src/app/frontcraft/pages/armory/armory.component.html 查看文件

@@ -1,6 +1,5 @@
1 1
 <nb-card 
2
-class = "col-12 col-xl-9"
3
-status="control">
2
+class = "col-12 col-xl-9">
4 3
     <nb-card-header style="text-transform: capitalize;">
5 4
         <h4>
6 5
             Armory

+ 3
- 2
src/frontend/src/app/frontcraft/pages/armory/armory.component.ts 查看文件

@@ -2,7 +2,8 @@ import { Component, OnInit } from '@angular/core';
2 2
 import { Item, Stats } from '../../../../../../backend/Types/Types';
3 3
 
4 4
 import { NbToastrService } from '@nebular/theme';
5
-import { ApiService } from '../../services/login-api';
5
+import { ClientApiService } from '../../services/client-login-api';
6
+import { IApiService } from '../../services/ApiService';
6 7
 
7 8
 @Component({
8 9
   selector: 'armory',
@@ -18,7 +19,7 @@ export class FrontcraftArmoryComponent implements OnInit {
18 19
   gear: Item[] = []
19 20
 
20 21
   constructor(
21
-    private api: ApiService,
22
+    private api: IApiService,
22 23
     private toastr: NbToastrService
23 24
   ) { }
24 25
 

+ 1
- 2
src/frontend/src/app/frontcraft/pages/character/character.component.html 查看文件

@@ -1,6 +1,5 @@
1 1
 <nb-card 
2
-class = "col-12 col-xl-9"
3
-status="control">
2
+class = "col-12 col-xl-9">
4 3
     <nb-card-header style="text-transform: capitalize;">
5 4
         <h4>
6 5
             <a *ngIf="link === 'character'" [ngStyle]="{'color': color}" [routerLink]="'/frontcraft/character/'+char.charactername">

+ 3
- 2
src/frontend/src/app/frontcraft/pages/character/character.component.ts 查看文件

@@ -1,9 +1,10 @@
1 1
 import { Component, OnInit, Input } from '@angular/core';
2 2
 import { ActivatedRoute, Router } from '@angular/router';
3
-import { ApiService as ApiService } from '../../services/login-api';
3
+import { ClientApiService as ClientApiService } from '../../services/client-login-api';
4 4
 import { Spec, User, Character, Item } from '../../../../../../backend/Types/Types';
5 5
 import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
6 6
 import { _Tiers } from '../../../../../../backend/Types/Items';
7
+import { IApiService } from '../../services/ApiService';
7 8
 
8 9
 @Component({
9 10
   selector: 'character',
@@ -28,7 +29,7 @@ export class FrontcraftCharacterComponent implements OnInit{
28 29
     gear2:string[] = []
29 30
 
30 31
     constructor(
31
-      private api: ApiService,
32
+      private api: IApiService,
32 33
       private route: ActivatedRoute,
33 34
     ){}
34 35
 

+ 2
- 2
src/frontend/src/app/frontcraft/pages/characters/characters.component.ts 查看文件

@@ -1,8 +1,8 @@
1 1
 import { Component, AfterViewInit, OnDestroy } from '@angular/core';
2 2
 import { NbThemeService } from '@nebular/theme';
3
-import { ApiService } from '../../services/login-api';
4 3
 import { _Class } from '../../../../../../backend/Types/Types';
5 4
 import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
5
+import { IApiService } from '../../services/ApiService';
6 6
 
7 7
 
8 8
 @Component({
@@ -17,7 +17,7 @@ export class FrontcraftCharactersComponent implements AfterViewInit, OnDestroy{
17 17
   allcharacters = []
18 18
   displayedcharacters = []
19 19
 
20
-  constructor(private theme: NbThemeService, private api:ApiService) {
20
+  constructor(private theme: NbThemeService, private api:IApiService) {
21 21
   }
22 22
 
23 23
   changeSearch(){

+ 16
- 10
src/frontend/src/app/frontcraft/pages/pages-layout.component.ts 查看文件

@@ -1,7 +1,10 @@
1
-import { Component, AfterContentChecked, OnInit, AfterContentInit } from '@angular/core';
1
+import { Component, AfterContentInit, OnInit } from '@angular/core';
2 2
 import { NbMenuItem } from '@nebular/theme';
3
-import { ApiService } from '../services/login-api';
3
+import { ClientApiService } from '../services/client-login-api';
4 4
 import { Router } from '@angular/router';
5
+import { IApiService } from '../services/ApiService';
6
+
7
+declare const Cookies
5 8
 
6 9
 @Component({
7 10
   selector: 'page-layout',
@@ -13,7 +16,8 @@ import { Router } from '@angular/router';
13 16
     </ngx-one-column-layout>
14 17
   `,
15 18
 })
16
-export class PagesLayoutComponent implements AfterContentInit{
19
+export class PagesLayoutComponent implements OnInit{
20
+
17 21
   menu:NbMenuItem[] = [{
18 22
     icon: 'image',
19 23
     title: 'Raids',
@@ -33,15 +37,17 @@ export class PagesLayoutComponent implements AfterContentInit{
33 37
   }]
34 38
   
35 39
   constructor(
36
-    private loginSvc : ApiService,
40
+    private api : IApiService,
37 41
     private router : Router
38 42
   ){}
39 43
 
40
-  ngAfterContentInit() : void {
41
-    this.loginSvc.checkLogin().then(loggedin => {
42
-      if(!loggedin){
43
-        this.router.navigateByUrl("/auth")
44
-      }
45
-    });
44
+  ngOnInit(): void {
45
+    /*
46
+    const u = this.api.getCurrentUser()
47
+    
48
+    if(!u){
49
+      this.router.navigate(['/auth/login'])
50
+    }
51
+    */
46 52
   }
47 53
 }

+ 0
- 63
src/frontend/src/app/frontcraft/pages/pages-routing.module.ts 查看文件

@@ -1,63 +0,0 @@
1
-import { NgModule } from '@angular/core';
2
-import { RouterModule, Routes } from '@angular/router';
3
-import { PagesLayoutComponent } from './pages-layout.component';
4
-import { FrontcraftCharacterComponent } from './character/character.component';
5
-import { FrontcraftUserComponent } from './user/user.component';
6
-import { FrontcraftRaidsComponent } from './raids/raids.component';
7
-import { FrontcraftRaidComponent } from './raid/raid.component';
8
-import { FrontcraftArchiveComponent } from './raid/archive.component';
9
-import { FrontcraftRulesComponent } from './rules/rules.component';
10
-import { FrontcraftCharactersComponent } from './characters/characters.component';
11
-import { FrontcraftArmoryComponent } from './armory/armory.component';
12
-
13
-export const routes: Routes = [
14
-    {
15
-        path: '',
16
-        component: PagesLayoutComponent,
17
-        children: [
18
-            {
19
-                path: 'user/:name',
20
-                component: FrontcraftUserComponent
21
-            },
22
-            {
23
-                path: 'raid/:id',
24
-                component: FrontcraftRaidComponent
25
-            },
26
-            {
27
-                path: 'archive/:id',
28
-                component: FrontcraftArchiveComponent
29
-            },
30
-            {
31
-                path: 'raids',
32
-                component: FrontcraftRaidsComponent
33
-            },
34
-            {
35
-                path: 'character/:name',
36
-                component: FrontcraftCharacterComponent
37
-            },
38
-            {
39
-                path: 'characters',
40
-                component: FrontcraftCharactersComponent,
41
-            },
42
-            {
43
-                path: 'rules',
44
-                component: FrontcraftRulesComponent
45
-            },
46
-            {
47
-                path: 'armory',
48
-                component: FrontcraftArmoryComponent
49
-            },
50
-            {
51
-                path: '**',
52
-                redirectTo: 'raids'
53
-            },
54
-        ]
55
-    }    
56
-];
57
-
58
-@NgModule({
59
-  imports: [RouterModule.forChild(routes)],
60
-  exports: [RouterModule],
61
-})
62
-export class FrontcraftRoutingModule {
63
-}

+ 0
- 2
src/frontend/src/app/frontcraft/pages/pages.module.ts 查看文件

@@ -18,7 +18,6 @@ import {
18 18
   NbDatepickerModule,
19 19
   NbSelectModule
20 20
 } from '@nebular/theme';
21
-import { FrontcraftRoutingModule } from './pages-routing.module';
22 21
 import { PagesLayoutComponent } from './pages-layout.component';
23 22
 import { ThemeModule } from '../../@theme/theme.module';
24 23
 import { FrontcraftCharacterComponent } from './character/character.component';
@@ -42,7 +41,6 @@ import { FrontcraftArmoryComponent } from './armory/armory.component';
42 41
 
43 42
 @NgModule({
44 43
   imports: [
45
-    FrontcraftRoutingModule,
46 44
     CommonModule,
47 45
     FormsModule,
48 46
     RouterModule,

+ 4
- 3
src/frontend/src/app/frontcraft/pages/raid/archive.component.ts 查看文件

@@ -1,8 +1,9 @@
1 1
 import { Component, OnInit } from '@angular/core';
2 2
 import { ActivatedRoute } from '@angular/router';
3
-import { ApiService as ApiService } from '../../services/login-api';
3
+import { ClientApiService as ClientApiService } from '../../services/client-login-api';
4 4
 import { RaidData } from '../../../../../../backend/Types/Types';
5 5
 import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
6
+import { IApiService } from '../../services/ApiService';
6 7
 
7 8
 @Component({
8 9
   selector: 'archive',
@@ -38,7 +39,7 @@ export class FrontcraftArchiveComponent implements OnInit{
38 39
     search = ""
39 40
     
40 41
     constructor(
41
-      private api: ApiService,
42
+      private api: IApiService,
42 43
       private route: ActivatedRoute,
43 44
     ){
44 45
     }
@@ -60,7 +61,7 @@ export class FrontcraftArchiveComponent implements OnInit{
60 61
       [
61 62
         ...raiddata.tanks, 
62 63
         ...raiddata.healers, 
63
-        ...Object.values(raiddata.participants).flat()
64
+        ...Object.values<any>(raiddata.participants).flat()
64 65
       ].forEach(p => {
65 66
         p['color'] = getClassColor(p.class)
66 67
       })

+ 3
- 2
src/frontend/src/app/frontcraft/pages/raid/characterpicker.component.ts 查看文件

@@ -1,8 +1,9 @@
1 1
 import { OnInit, Component } from '@angular/core';
2 2
 import { NbWindowRef, NbToastrService, NbDialogRef } from '@nebular/theme';
3 3
 import { RaidData, Character } from '../../../../../../backend/Types/Types';
4
-import { ApiService } from '../../services/login-api';
4
+import { ClientApiService } from '../../services/client-login-api';
5 5
 import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
6
+import { IApiService } from '../../services/ApiService';
6 7
 
7 8
 @Component({
8 9
     selector: 'characterpicker',
@@ -15,7 +16,7 @@ export class FrontcraftCharacerpickerComponent implements OnInit{
15 16
 
16 17
     constructor(
17 18
         protected dialogRef: NbDialogRef<FrontcraftCharacerpickerComponent>,
18
-        private api : ApiService,
19
+        private api : IApiService,
19 20
         private toast : NbToastrService
20 21
     ){}
21 22
 

+ 44
- 39
src/frontend/src/app/frontcraft/pages/raid/raid.component.html 查看文件

@@ -1,6 +1,6 @@
1 1
 <div class="row">
2 2
     <div class="col-12 col-xl-6">
3
-        <nb-card [size]="'giant'">
3
+        <nb-card>
4 4
             <nb-card-body>
5 5
                 <nb-tabset>
6 6
                     <nb-tab tabTitle="Info">
@@ -68,9 +68,7 @@
68 68
                                                 [src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
69 69
                                             {{ participant.charactername }}
70 70
                                         </a>
71
-                                        <span 
72
-                                            *ngIf="participant.rank=='Trial'" 
73
-                                            style="font-size: 9px;">
71
+                                        <span *ngIf="participant.rank=='Trial'" style="font-size: 9px;">
74 72
                                             Trial
75 73
                                         </span>
76 74
                                     </div>
@@ -97,9 +95,7 @@
97 95
                                                 [src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
98 96
                                             {{ participant.charactername }}
99 97
                                         </a>
100
-                                        <span 
101
-                                            *ngIf="participant.rank=='Trial'" 
102
-                                            style="font-size: 9px;">
98
+                                        <span *ngIf="participant.rank=='Trial'" style="font-size: 9px;">
103 99
                                             Trial
104 100
                                         </span>
105 101
                                     </div>
@@ -128,9 +124,7 @@
128 124
                                                     [src]="'../../../../assets/images/'+participant.class.toLowerCase()+'.png'" />
129 125
                                                 {{ participant.charactername }}
130 126
                                             </a>
131
-                                            <span 
132
-                                                *ngIf="participant.rank=='Trial'" 
133
-                                                style="font-size: 9px;">
127
+                                            <span *ngIf="participant.rank=='Trial'" style="font-size: 9px;">
134 128
                                                 Trial
135 129
                                             </span>
136 130
                                         </div>
@@ -149,41 +143,52 @@
149 143
         </nb-card>
150 144
     </div>
151 145
     <div class="col-12 col-xl-6">
152
-        <nb-card  *ngIf="isTier">
146
+        <nb-card *ngIf="isTier">
153 147
             <nb-card-body>
154 148
                 <nb-tabset>
155 149
                     <nb-tab tabTitle="Reserves" [active]="reservesShown">
156
-                        <input type="text" nbInput [(ngModel)]="search" (change)="changeSearch()" placeholder="Search"
157
-                            fullWidth="true">
150
+                        <input type="text" nbInput [(ngModel)]="search" (change)="changeSearch()" placeholder="Search" fullWidth="true">
158 151
 
159
-                        <nb-list>
152
+                        <nb-list class="">
160 153
                             <nb-list-item *ngFor="let item of displayedtokens | keyvalue">
161
-                                <wowhead [item]="item.value[0]"></wowhead><br />
162
-                                <div class="row">
163
-                                    <div *ngFor="let token of item.value" class="col-12 col-md-6 col-xl-4">
164
-                                        <span [ngStyle]="{'text-decoration': token.rank=='Trial'? 'line-through' : 'none currentcolor solid' }">
165
-                                            [ {{token.level}} ]
166
-                                            <span style="text-transform: capitalize;"
167
-                                                [ngStyle]="{'color':token.level>=10?'#ff8000':token.level>=8?'#a335ee':token.level>=6?'#0070dd':token.level>=4?'#1eff00':token.level>=2?'#ffffff':'#9d9d9d'}">
168
-                                                {{token.charactername}}
169
-                                            </span>
170
-                                        </span>
171
-                                        &nbsp;
172
-                                        <ng-template #tooltip>
173
-                                            <div style="color:white">
174
-                                                Becomes valid when promoted to Raider
154
+                                <table>
155
+                                    <tr>
156
+                                        <td>
157
+                                            <wowhead [item]="item.value[0]"></wowhead><br />
158
+
159
+                                        </td>
160
+                                    </tr>
161
+                                    <tr>
162
+                                        <td>
163
+                                            <div class="row">
164
+                                                <div 
165
+                                                *ngFor="let token of item.value" 
166
+                                                class="col-12 col-md-6 col-xl-4">
167
+                                                    <span
168
+                                                        [ngStyle]="{'text-decoration': token.rank=='Trial'? 'line-through' : 'none currentcolor solid' }">
169
+                                                        <span style="text-transform: capitalize;">
170
+                                                            [&nbsp;{{token.level}}&nbsp;]&nbsp;
171
+                                                            <a [routerLink]="'/frontcraft/character/'+token.charactername"
172
+                                                            [ngStyle]="{'color':token.level>=10?'#ff8000':token.level>=8?'#a335ee':token.level>=6?'#0070dd':token.level>=4?'#1eff00':token.level>=2?'#ffffff':'#9d9d9d'}">
173
+                                                                {{token.charactername}}
174
+                                                            </a>
175
+                                                        </span>
176
+                                                    </span>
177
+                                                    <ng-template #tooltip>
178
+                                                        <div style="color:white">
179
+                                                            Becomes valid when promoted to Raider
180
+                                                        </div>
181
+                                                    </ng-template>
182
+                                                    <span *ngIf="token.rank=='Trial'" style="font-size: 9px;" [nbPopover]="tooltip"
183
+                                                        nbPopoverTrigger="hover" nbPopoverPlacement="top">
184
+                                                        Trial
185
+                                                    </span><br />
186
+                                                </div>
175 187
                                             </div>
176
-                                        </ng-template>
177
-                                        <span 
178
-                                        *ngIf="token.rank=='Trial'" 
179
-                                        style="font-size: 9px;"
180
-                                        [nbPopover]="tooltip" 
181
-                                        nbPopoverTrigger="hover"
182
-                                        nbPopoverPlacement="top">
183
-                                            Trial
184
-                                        </span><br />
185
-                                    </div>
186
-                                </div>
188
+            
189
+                                        </td>
190
+                                    </tr>
191
+                                </table>
187 192
                             </nb-list-item>
188 193
                         </nb-list>
189 194
                     </nb-tab>

+ 3
- 2
src/frontend/src/app/frontcraft/pages/raid/raid.component.ts 查看文件

@@ -1,12 +1,13 @@
1 1
 import { Component, OnInit, OnDestroy } from '@angular/core';
2 2
 import { ActivatedRoute, Router, NavigationStart } from '@angular/router';
3
-import { ApiService as ApiService } from '../../services/login-api';
3
+import { ClientApiService as ClientApiService } from '../../services/client-login-api';
4 4
 import { RaidData, Raid, Signup, Character, Spec, Item, SRToken } from '../../../../../../backend/Types/Types';
5 5
 import { NbWindowService, NbToastrService, NbDialogService } from '@nebular/theme';
6 6
 import { FrontcraftCharacerpickerComponent } from './characterpicker.component';
7 7
 import { getClassColor, SpecT } from '../../../../../../backend/Types/PlayerSpecs';
8 8
 import { FrontcraftBuyTokenComponent } from '../shop/buytoken.component';
9 9
 import { allItems } from '../../../../../../backend/Types/Items';
10
+import { IApiService } from '../../services/ApiService';
10 11
 
11 12
 @Component({
12 13
   selector: 'raid',
@@ -45,7 +46,7 @@ export class FrontcraftRaidComponent implements OnInit, OnDestroy{
45 46
     uuid
46 47
 
47 48
     constructor(
48
-      private api: ApiService,
49
+      private api: IApiService,
49 50
       private route: ActivatedRoute,
50 51
       private router: Router,
51 52
       private dialogService : NbDialogService,

+ 3
- 2
src/frontend/src/app/frontcraft/pages/raids/createraid.compontent.ts 查看文件

@@ -1,8 +1,9 @@
1 1
 import { Component, OnInit } from '@angular/core';
2
-import { ApiService } from '../../services/login-api';
2
+import { ClientApiService } from '../../services/client-login-api';
3 3
 import { Raid, RaidData } from '../../../../../../backend/Types/Types';
4 4
 import { NbWindowRef, NbDialogRef } from '@nebular/theme';
5 5
 import { Tiers, _Tiers } from '../../../../../../backend/Types/Items';
6
+import { IApiService } from '../../services/ApiService';
6 7
 
7 8
 const ONE_MINUTE = 60000
8 9
 const ONE_HOUR = 60 * ONE_MINUTE
@@ -27,7 +28,7 @@ export class FrontcraftCreateRaidsComponent implements OnInit {
27 28
 
28 29
   constructor(
29 30
     protected dialogRef: NbDialogRef<FrontcraftCreateRaidsComponent>,
30
-    private api: ApiService
31
+    private api: IApiService
31 32
   ) {}
32 33
 
33 34
   loadNext(cardData) {

+ 3
- 2
src/frontend/src/app/frontcraft/pages/raids/raids.component.ts 查看文件

@@ -1,8 +1,9 @@
1 1
 import { Component, OnInit, OnDestroy } from '@angular/core';
2
-import { ApiService } from '../../services/login-api';
2
+import { ClientApiService } from '../../services/client-login-api';
3 3
 import { NbWindowService, NbDialogService } from '@nebular/theme';
4 4
 import { FrontcraftCreateRaidsComponent } from './createraid.compontent';
5 5
 import { Router, NavigationStart } from '@angular/router';
6
+import { IApiService } from '../../services/ApiService';
6 7
 
7 8
 @Component({
8 9
   selector: 'raids',
@@ -19,7 +20,7 @@ export class FrontcraftRaidsComponent implements OnInit, OnDestroy{
19 20
   uuid
20 21
 
21 22
   constructor(
22
-    private api: ApiService,
23
+    private api: IApiService,
23 24
     private router: Router,
24 25
     private dialogService: NbDialogService
25 26
   ) {

+ 15
- 8
src/frontend/src/app/frontcraft/pages/rules/rules.component.html 查看文件

@@ -60,14 +60,21 @@
60 60
             <nb-tab tabTitle="priorities">
61 61
                 <nb-list>
62 62
                     <nb-list-item *ngFor="let item of rules | keyvalue">
63
-                        <wowhead [item]="item.value[0]"></wowhead><br>
64
-                        <div class="row" *ngFor="let rule of item.value">
65
-                            <div class="col-4">
66
-                                <span *ngIf="rule.modifier>0">+</span>{{rule.modifier}} {{rule.race}} <span [ngStyle]="{'color':rule.color}">{{rule.specname}} {{rule.class}}</span> 
67
-                            </div>
68
-                            <div class="col-8" style="color:white"> ({{rule.description}})</div>
69
-                            <br />
70
-                        </div>
63
+                        <table >
64
+                            <tr>
65
+                                <td colspan="2">
66
+                                    <wowhead [item]="item.value[0]"></wowhead>
67
+                                </td>
68
+                            </tr>
69
+                            <tr *ngFor="let rule of item.value">
70
+                                <td style="width: 250px;">
71
+                                    <span *ngIf="rule.modifier>0">+</span>{{rule.modifier}} {{rule.race}} <span [ngStyle]="{'color':rule.color}">{{rule.specname}} {{rule.class}}</span> 
72
+                                </td>
73
+                                <td>
74
+                                    <div style="color:white"> ({{rule.description}})</div>
75
+                                </td>
76
+                            </tr>
77
+                        </table>
71 78
                     </nb-list-item>
72 79
                 </nb-list>
73 80
             </nb-tab>

+ 2
- 2
src/frontend/src/app/frontcraft/pages/rules/rules.component.ts 查看文件

@@ -1,6 +1,6 @@
1 1
 import { Component, OnInit } from '@angular/core';
2
-import { ApiService as ApiService } from '../../services/login-api';
3 2
 import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
3
+import { IApiService } from '../../services/ApiService';
4 4
 
5 5
 @Component({
6 6
   selector: 'rules',
@@ -12,7 +12,7 @@ export class FrontcraftRulesComponent implements OnInit{
12 12
     rules = {}
13 13
 
14 14
     constructor(
15
-      private api: ApiService,
15
+      private api: IApiService,
16 16
     ){
17 17
     }
18 18
 

+ 3
- 2
src/frontend/src/app/frontcraft/pages/shop/buytoken.component.ts 查看文件

@@ -1,10 +1,11 @@
1 1
 import { Component, OnInit, ContentChild, AfterContentInit, ViewChild, AfterViewInit, Input, Output, EventEmitter } from '@angular/core';
2
-import { ApiService as ApiService } from '../../services/login-api';
2
+import { ClientApiService as ClientApiService } from '../../services/client-login-api';
3 3
 import { FrontcraftItemSelectComponent } from './itemselector.component';
4 4
 import { NbWindowService, NbWindowRef, NbToastrService, NbDialogService, NbDialogRef } from '@nebular/theme';
5 5
 import { Item, Character, SRToken, Signup } from '../../../../../../backend/Types/Types';
6 6
 import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
7 7
 import { _Tiers, allItems, Tiers } from '../../../../../../backend/Types/Items';
8
+import { IApiService } from '../../services/ApiService';
8 9
 
9 10
 @Component({
10 11
     selector: 'buyToken',
@@ -88,7 +89,7 @@ import { _Tiers, allItems, Tiers } from '../../../../../../backend/Types/Items';
88 89
     constructor(
89 90
       private toastr: NbToastrService,
90 91
       protected dialogRef: NbDialogRef<FrontcraftBuyTokenComponent>,
91
-      private api : ApiService
92
+      private api : IApiService
92 93
     ){}
93 94
   
94 95
     async ngOnInit() {

+ 0
- 2
src/frontend/src/app/frontcraft/pages/shop/item.component.ts 查看文件

@@ -1,6 +1,4 @@
1 1
 import { Component, OnInit, Input, } from '@angular/core';
2
-import { ApiService as ApiService } from '../../services/login-api';
3
-import { NbToastrService, } from '@nebular/theme';
4 2
 import { Item, } from '../../../../../../backend/Types/Types';
5 3
 import { _Tiers, } from '../../../../../../backend/Types/Items';
6 4
 

+ 3
- 2
src/frontend/src/app/frontcraft/pages/shop/itemselector.component.ts 查看文件

@@ -1,6 +1,7 @@
1 1
 import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
2
-import { ApiService } from '../../services/login-api';
2
+import { ClientApiService } from '../../services/client-login-api';
3 3
 import { Item, Character } from '../../../../../../backend/Types/Types';
4
+import { IApiService } from '../../services/ApiService';
4 5
 
5 6
 @Component({
6 7
   selector: 'itemselect',
@@ -18,7 +19,7 @@ export class FrontcraftItemSelectComponent implements OnInit{
18 19
     @Output() onSelect = new EventEmitter<Item>();
19 20
 
20 21
     constructor(
21
-      private api: ApiService,
22
+      private api: IApiService,
22 23
     ){}
23 24
 
24 25
     async ngOnInit(){

+ 4
- 8
src/frontend/src/app/frontcraft/pages/shop/shop.component.ts 查看文件

@@ -1,9 +1,7 @@
1
-import { Component, OnInit, ContentChild, AfterContentInit, ViewChild, AfterViewInit, Input, Output, EventEmitter } from '@angular/core';
2
-import { ApiService as ApiService } from '../../services/login-api';
3
-import { FrontcraftItemSelectComponent } from './itemselector.component';
4
-import { NbWindowService, NbWindowRef, NbToastrService, NbDialogService, NbDialogRef } from '@nebular/theme';
5
-import { Item, Character, SRToken, Signup } from '../../../../../../backend/Types/Types';
6
-import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
1
+import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
2
+import { ClientApiService as ClientApiService } from '../../services/client-login-api';
3
+import { NbDialogService } from '@nebular/theme';
4
+import { Item, Character, Signup } from '../../../../../../backend/Types/Types';
7 5
 import { _Tiers, allItems } from '../../../../../../backend/Types/Items';
8 6
 
9 7
 @Component({
@@ -20,8 +18,6 @@ export class FrontcraftShopComponent implements OnInit{
20 18
     allItems = allItems
21 19
 
22 20
     constructor(
23
-      private api: ApiService,
24
-      private dialogService : NbDialogService
25 21
     ){
26 22
 
27 23
     }

+ 0
- 2
src/frontend/src/app/frontcraft/pages/shop/wowhead.component.ts 查看文件

@@ -1,6 +1,4 @@
1 1
 import { Component, OnInit, Input } from '@angular/core';
2
-import { ApiService as ApiService } from '../../services/login-api';
3
-import { NbToastrService } from '@nebular/theme';
4 2
 import { Item } from '../../../../../../backend/Types/Types';
5 3
 import { _Tiers } from '../../../../../../backend/Types/Items';
6 4
 import { DomSanitizer, SafeHtml } from '@angular/platform-browser';

+ 8
- 4
src/frontend/src/app/frontcraft/pages/user/user.component.ts 查看文件

@@ -1,11 +1,11 @@
1 1
 import { Component, OnInit } from '@angular/core';
2
-import { ApiService, hash } from '../../services/login-api';
3
-import { Router, ActivatedRoute } from '@angular/router';
2
+import { ActivatedRoute } from '@angular/router';
4 3
 import { User, Spec, Character } from '../../../../../../backend/Types/Types';
5 4
 import { getClassColor } from '../../../../../../backend/Types/PlayerSpecs';
6 5
 import { _Tiers } from '../../../../../../backend/Types/Items';
7 6
 import { _Rank } from '../../../../../../backend/Types/Types';
8 7
 import { NbToastrService } from '@nebular/theme';
8
+import { hash, IApiService } from '../../services/ApiService';
9 9
 
10 10
 @Component({
11 11
   selector: 'user-component',
@@ -19,12 +19,16 @@ export class FrontcraftUserComponent implements OnInit{
19 19
   ranks = _Rank
20 20
   myProfile = false
21 21
   manageUser
22
-  user:User = {} as any
22
+  user:User = {
23
+    rank: 'Guest',
24
+    username: 'Guest',
25
+    pwhash: ""
26
+  }
23 27
   characters : (Character & Spec)[] = []
24 28
 
25 29
   constructor(
26 30
     private route: ActivatedRoute,
27
-    private api : ApiService,
31
+    private api : IApiService,
28 32
     private toastr: NbToastrService
29 33
   ){}
30 34
 

+ 3
- 6
src/frontend/src/app/frontcraft/permissions/changePermissions/changePermissions.component.ts 查看文件

@@ -1,8 +1,9 @@
1 1
 import { Component, OnInit } from '@angular/core';
2
-import { ApiService as ApiService } from '../../services/login-api';
2
+import { ClientApiService as ClientApiService } from '../../services/client-login-api';
3 3
 import { Router } from '@angular/router';
4 4
 import { _Rank, _Class, _Race, RPCPermission  } from '../../../../../../backend/Types/Types'
5 5
 import { NbToastrService } from '@nebular/theme';
6
+import { IApiService } from '../../services/ApiService';
6 7
 
7 8
 
8 9
 @Component({
@@ -15,8 +16,7 @@ export class ChangePermissionsComponent implements OnInit{
15 16
   ranks = _Rank
16 17
 
17 18
   constructor(
18
-    private router : Router,  
19
-    private api : ApiService,
19
+    private api : IApiService,
20 20
     private toastr: NbToastrService
21 21
   ){}
22 22
 
@@ -32,9 +32,6 @@ export class ChangePermissionsComponent implements OnInit{
32 32
 
33 33
 
34 34
     perm[key] = value
35
-    console.log(perm);
36
-    
37
-
38 35
     await modify.setPermission(perm).catch(e => {
39 36
       
40 37
     })

+ 1
- 2
src/frontend/src/app/frontcraft/permissions/permissions-layout.component.ts 查看文件

@@ -1,5 +1,5 @@
1 1
 import { Component, OnInit } from '@angular/core';
2
-import { ApiService } from '../services/login-api';
2
+import { ClientApiService } from '../services/client-login-api';
3 3
 import { Router } from '@angular/router';
4 4
 
5 5
 @Component({
@@ -13,7 +13,6 @@ import { Router } from '@angular/router';
13 13
 
14 14
 export class PermissionsComponent implements OnInit{
15 15
   constructor(
16
-    private loginSvc : ApiService,
17 16
     private router: Router  
18 17
   ){}
19 18
 

+ 0
- 24
src/frontend/src/app/frontcraft/permissions/permissions-routing.module.ts 查看文件

@@ -1,24 +0,0 @@
1
-import { NgModule } from '@angular/core';
2
-import { RouterModule, Routes } from '@angular/router';
3
-import { PermissionsComponent } from './permissions-layout.component';
4
-import { ChangePermissionsComponent } from './changePermissions/changePermissions.component';
5
-
6
-export const routes: Routes = [
7
-    {
8
-        path: '',
9
-        component: PermissionsComponent,
10
-        children: [
11
-            {
12
-                path: '**',
13
-                component: ChangePermissionsComponent,
14
-            },
15
-        ]
16
-    }
17
-];
18
-
19
-@NgModule({
20
-  imports: [RouterModule.forChild(routes)],
21
-  exports: [RouterModule],
22
-})
23
-export class PermissionsRoutingModule {
24
-}

+ 0
- 2
src/frontend/src/app/frontcraft/permissions/permissions.module.ts 查看文件

@@ -15,13 +15,11 @@ import {
15 15
 } from '@nebular/theme';
16 16
 import { PermissionsComponent } from './permissions-layout.component';
17 17
 import { ThemeModule } from '../../@theme/theme.module';
18
-import { PermissionsRoutingModule } from './permissions-routing.module';
19 18
 import { ChangePermissionsComponent } from './changePermissions/changePermissions.component';
20 19
 
21 20
 @NgModule({
22 21
   imports: [
23 22
     NbToggleModule,
24
-    PermissionsRoutingModule,
25 23
     CommonModule,
26 24
     FormsModule,
27 25
     RouterModule,

+ 23
- 0
src/frontend/src/app/frontcraft/services/ApiService.ts 查看文件

@@ -0,0 +1,23 @@
1
+import { Auth, FrontcraftIfc, FrontcraftFeatureIfc, User, SomeOf } from '../../../../../backend/Types/Types';
2
+import { saltedHash } from '../../../../../backend/Util/hash';
3
+import { RPCSocket } from 'rpclibrary';
4
+
5
+export class IApiService{
6
+    getUnprivilegedSocket: () => RPCSocket & FrontcraftIfc
7
+    getAuth: () => Auth | undefined
8
+    checkLogin: () => Promise<boolean>
9
+    initialize: () => Promise<any>
10
+    getCurrentUser: () => User | undefined
11
+    login: (username: string, password: string) => Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>>
12
+    connectShoutbox: (callback:Function) => Promise<Function>
13
+    kick: () => Promise<void>
14
+    logout: () => Promise<void>
15
+    get: <K extends (keyof FrontcraftIfc | keyof FrontcraftFeatureIfc)>(feature : K) => K extends keyof FrontcraftIfc?FrontcraftIfc[K]:
16
+                                                                                        K extends keyof FrontcraftFeatureIfc?(FrontcraftFeatureIfc[K] | void): 
17
+                                                                                        never
18
+}
19
+
20
+export async function hash(value:string) : Promise<string>{
21
+    return saltedHash(value, "")
22
+}
23
+

src/frontend/src/app/frontcraft/services/login-api.ts → src/frontend/src/app/frontcraft/services/client-login-api.ts 查看文件

@@ -1,31 +1,29 @@
1
-import { Injectable, Injector, NgZone } from "@angular/core";
1
+import { Injectable } from "@angular/core";
2 2
 import {RPCSocket} from 'rpclibrary/js/src/Frontend'
3
-
4 3
 import { Auth, User, _Class, FrontcraftFeatureIfc, SomeOf, FrontcraftIfc, } from '../../../../../backend/Types/Types'
5
-import { CookieService } from 'ngx-cookie-service';
6
-import { Router } from '@angular/router';
7 4
 import { ShoutMessage } from '../../../../../backend/Components/Shoutbox/Interface';
8
-import { saltedHash } from '../../../../../backend/Util/hash';
9
-import { NbToastrService } from '@nebular/theme';
5
+import { hash, IApiService } from './ApiService';
6
+
7
+declare const Cookies
10 8
 
11 9
 @Injectable()
12
-export class ApiService{
10
+export class ClientApiService implements IApiService{
13 11
     private socket:RPCSocket & FrontcraftIfc;
14 12
     private auth:Auth
15 13
     private privSocket: RPCSocket & SomeOf<FrontcraftFeatureIfc>
16 14
 
17
-    constructor(
18
-        private injector: Injector,
19
-        private cookieSvc : CookieService,
20
-        private ngZone : NgZone,
21
-        private toastr: NbToastrService
22
-    ){}
15
+    constructor(){
16
+        window['s'] = this
17
+    }
23 18
 
24 19
     getUnprivilegedSocket = () : RPCSocket & FrontcraftIfc => this.socket
25 20
 
26 21
     private getPrivilegedSocket = async (auth:Auth) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
27
-        if(this.privSocket) return this.privSocket
28
-        if(auth == null) throw new Error("Bad Auth")
22
+        if(this.privSocket) {
23
+            return this.privSocket
24
+        }
25
+        if(auth == null) 
26
+            throw new Error("Bad Auth")
29 27
 
30 28
         try{
31 29
             const sock = new RPCSocket(
@@ -38,24 +36,24 @@ export class ApiService{
38 36
             })
39 37
 
40 38
             sock.hook('getUserData', () => auth)
41
-            sock.hook('navigate', (where:string) => {
42
-                this.ngZone.run( () => {
43
-                    this.injector.get(Router).navigateByUrl(where)
44
-                })
45
-            })
46 39
 
47 40
             sock.on('close', async () => {
41
+                console.log("priv#close");
42
+                
48 43
                 //handled via unprivileged socket
49 44
             })
50 45
 
51 46
             sock.on('error', async (e) => {
47
+                console.log("priv#error", e);
48
+
52 49
                 //handled via unprivileged socket
53 50
             })
54 51
             const authSock = await sock.connect<RPCSocket & SomeOf<FrontcraftFeatureIfc>>(auth.token.value)
55 52
             
56 53
             this.auth = auth
57 54
             this.privSocket = authSock
58
-            this.cookieSvc.set('token', JSON.stringify(auth))
55
+            Cookies.set('token', JSON.stringify(auth))
56
+//            document.cookie = JSON.stringify(auth)
59 57
             return authSock
60 58
         }catch(e){ 
61 59
             if(this.privSocket) this.privSocket.destroy()
@@ -86,13 +84,11 @@ export class ApiService{
86 84
         try{
87 85
             auth = await this.socket.UserManager.login(username, pwHash)
88 86
         }catch(e){
89
-            this.toastr.danger("Login failed", "Error")
90 87
             return
91 88
         }
92 89
 
93 90
         if(!auth){ 
94 91
             await this.logout()
95
-            this.toastr.danger("Login failed", "Error")
96 92
             throw new Error("Login failed")
97 93
         }
98 94
 
@@ -105,8 +101,8 @@ export class ApiService{
105 101
         return sock
106 102
     }
107 103
 
108
-    async connectShoutbox(handler) : Promise<Function>{
109
-        const res = await this.get('Shoutbox').subscribe(handler)
104
+    async connectShoutbox(callback:Function) : Promise<Function>{
105
+        const res = await this.get('Shoutbox').subscribe(callback)
110 106
         return async (msg: ShoutMessage) => await this.get('Shoutbox').shout(res.uuid, msg)
111 107
     }
112 108
 
@@ -116,25 +112,21 @@ export class ApiService{
116 112
     }
117 113
 
118 114
     logout = async () => {
119
-        this.cookieSvc.set('token', undefined)
115
+        Cookies.remove('token')
120 116
         if(this.auth){
121 117
             try{
122 118
                 await this.socket.UserManager.logout(this.auth.user.username, this.auth.token.value)
123 119
             }catch(e){
124
-                //socket is dead
120
+                console.warn(e);
125 121
             }
126 122
         } 
127 123
 
128 124
         if(this.privSocket) this.privSocket.destroy()
129 125
         this.privSocket = null
130 126
         this.auth  = null
131
-        
132
-        this.ngZone.run(() => {
133
-            this.injector.get(Router).navigate(['/auth']);
134
-        })
135 127
     }
136 128
 
137
-    initialize = async () : Promise<any> => {
129
+    initialize = async (force = false) : Promise<any> => {
138 130
         if(this.socket){
139 131
             this.socket.destroy()
140 132
             this.socket = null
@@ -143,9 +135,7 @@ export class ApiService{
143 135
         try{
144 136
             let conn = new RPCSocket(20000, window.location.hostname)
145 137
             conn.on('close', async () => {
146
-            })
147
-
148
-            
138
+            })                        
149 139
 
150 140
             this.socket = await conn.connect<FrontcraftIfc>()
151 141
         }catch(e){
@@ -155,9 +145,9 @@ export class ApiService{
155 145
         }
156 146
 
157 147
         try{
158
-            const cookie = JSON.parse(this.cookieSvc.get('token'))
148
+            const cookie = JSON.parse(Cookies.get('token'))
159 149
             
160
-            if(cookie != null) {
150
+            if(cookie != null && cookie != "") {
161 151
                 try{
162 152
                     const auth = await this.socket.UserManager.getAuth(cookie.token.value)
163 153
                     if(!auth) return this.socket
@@ -168,6 +158,7 @@ export class ApiService{
168 158
                 }
169 159
             }
170 160
         }catch(e){
161
+            Cookies.remove('token')
171 162
         }
172 163
     }
173 164
 
@@ -180,13 +171,4 @@ export class ApiService{
180 171
         await this.logout()
181 172
         return false
182 173
     }
183
-}
184
-
185
-export async function hash(value:string) : Promise<string>{
186
-    return saltedHash(value, "")
187
-}
188
-
189
-//angular depenency manager requires this
190
-export function initializeLoginSvc(svc: ApiService): () => Promise<any> {
191
-    return ()=>svc.initialize?svc.initialize():undefined
192 174
 }

+ 99
- 0
src/frontend/src/app/frontcraft/services/server-login-api.ts 查看文件

@@ -0,0 +1,99 @@
1
+import { Injectable } from "@angular/core";
2
+import {RPCSocket} from 'rpclibrary/js/src/Frontend'
3
+import { Auth, User, _Class, FrontcraftFeatureIfc, SomeOf, FrontcraftIfc, } from '../../../../../backend/Types/Types'
4
+import { hash, IApiService } from './ApiService';
5
+
6
+declare const Cookies
7
+
8
+@Injectable()
9
+export class ServerApiService implements IApiService{
10
+    private socket:RPCSocket & FrontcraftIfc;
11
+    private auth:Auth
12
+    private privSocket: RPCSocket & SomeOf<FrontcraftFeatureIfc>
13
+
14
+    constructor(){}
15
+
16
+    getUnprivilegedSocket = () : RPCSocket & FrontcraftIfc => this.socket
17
+
18
+    get = <K extends (keyof FrontcraftIfc | keyof FrontcraftFeatureIfc)>(feature : K) : K extends keyof FrontcraftIfc?FrontcraftIfc[K]:
19
+                                                                                        K extends keyof FrontcraftFeatureIfc?(FrontcraftFeatureIfc[K] | void): 
20
+                                                                                        never => {
21
+        //@ts-ignore
22
+        return this.socket[feature]
23
+    }
24
+
25
+    getCurrentUser = () : User | undefined => {
26
+        return this.auth?this.auth.user:undefined
27
+    }
28
+
29
+    login = async (username: string, password: string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
30
+        const pwHash = await hash(password)
31
+        let auth
32
+        try{
33
+            auth = await this.socket.UserManager.login(username, pwHash)
34
+        }catch(e){
35
+            return
36
+        }
37
+
38
+        if(!auth){ 
39
+            await this.logout()
40
+            throw new Error("Login failed")
41
+        }
42
+
43
+        //attach error handler now so failed logins dont trigger reloads
44
+        this.socket.on('error', async (err) => {
45
+            console.log(err);
46
+        })
47
+
48
+    }
49
+
50
+    async connectShoutbox(callback:Function) : Promise<Function>{
51
+        return console.log
52
+    }
53
+
54
+    kick = async () => {
55
+    }
56
+
57
+    logout = async () => {
58
+        Cookies.remove('token')
59
+        if(this.auth){
60
+            try{
61
+                await this.socket.UserManager.logout(this.auth.user.username, this.auth.token.value)
62
+            }catch(e){
63
+                console.warn(e);
64
+            }
65
+        } 
66
+
67
+        if(this.privSocket) this.privSocket.destroy()
68
+        this.privSocket = null
69
+        this.auth  = null
70
+    }
71
+
72
+    initialize = async () : Promise<any> => {
73
+        if(this.socket){
74
+            this.socket.destroy()
75
+            this.socket = null
76
+        }
77
+
78
+        try{
79
+            let conn = new RPCSocket(20000, window.location.hostname)
80
+            conn.on('close', async () => {
81
+            })                        
82
+
83
+            this.socket = await conn.connect<FrontcraftIfc>()
84
+        }catch(e){
85
+            console.log(e);
86
+            throw new Error("Websocket cannot connect")
87
+        }
88
+    }
89
+
90
+    getAuth = () => this.auth
91
+
92
+    async checkLogin() : Promise<boolean>{
93
+        if(!this.auth) return false
94
+        const valid = this.socket.UserManager.checkToken(this.auth.token.value, this.auth.user.rank)
95
+        if(valid) return true
96
+        await this.logout()
97
+        return false
98
+    }
99
+}

+ 9
- 0
src/frontend/src/main.server.ts 查看文件

@@ -0,0 +1,9 @@
1
+import { enableProdMode } from '@angular/core';
2
+
3
+enableProdMode()
4
+
5
+export { AppServerModule } from './app/app.server.module';
6
+import { IApiService } from './app/frontcraft/services/ApiService';
7
+export { IApiService }
8
+export { ServerApiService } from './app/frontcraft/services/server-login-api';
9
+

+ 14
- 3
src/frontend/src/main.ts 查看文件

@@ -6,12 +6,23 @@
6 6
 import { enableProdMode } from '@angular/core';
7 7
 import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
8 8
 
9
-import { AppModule } from './app/app.module';
9
+import { FrontcraftAppModule } from './app/app.module';
10 10
 import { environment } from './environments/environment';
11
+import { IApiService } from "./app/frontcraft/services/ApiService"
12
+import { ClientApiService } from './app/frontcraft/services/client-login-api';
11 13
 
12 14
 if (environment.production) {
13 15
   enableProdMode();
14 16
 }
15 17
 
16
-platformBrowserDynamic().bootstrapModule(AppModule)
17
-  .catch(err => console.error(err));
18
+const serviceObj = new ClientApiService()
19
+serviceObj.initialize().then(_ => {
20
+  platformBrowserDynamic([
21
+    {
22
+      provide: IApiService,
23
+      deps: [],
24
+      useValue: serviceObj
25
+    }
26
+  ]).bootstrapModule(FrontcraftAppModule)
27
+    .catch(err => console.error(err));
28
+})

+ 0
- 26
src/frontend/src/tsconfig.app.json 查看文件

@@ -1,26 +0,0 @@
1
-{
2
-  "extends": "../tsconfig.json",
3
-  "compilerOptions": {
4
-    "outDir": "../out-tsc/app",
5
-    "baseUrl": "./",
6
-    "paths": {
7
-      "@angular/*": [
8
-        "../node_modules/@angular/*"
9
-      ],
10
-      "@nebular/*": [
11
-        "../node_modules/@nebular/*"
12
-      ]
13
-    }
14
-  },
15
-  "exclude": [
16
-    "test.ts",
17
-    "**/*.spec.ts",
18
-    "../node_modules/@nebular/**/*.spec.ts",
19
-    "../node_modules/rpclibrary/js/**/*"
20
-  ],
21
-  "include": [
22
-    "../src/*.ts",
23
-    "../src/**/*.ts",
24
-    "../node_modules/@nebular/**/*.ts"
25
-  ]
26
-}

+ 24
- 0
src/frontend/tsconfig.app.json 查看文件

@@ -0,0 +1,24 @@
1
+{
2
+  "extends": "./tsconfig.json",
3
+  "compilerOptions": {
4
+    "outDir": "./out-tsc/app",
5
+    "paths": {
6
+      "@angular/*": [
7
+        "./node_modules/@angular/*"
8
+      ],
9
+      "@nebular/*": [
10
+        "./node_modules/@nebular/*"
11
+      ]
12
+    }
13
+  },
14
+  "exclude": [
15
+    "test.ts",
16
+    "**/*.spec.ts",
17
+    "./node_modules/@nebular/**/*.spec.ts",
18
+    "./node_modules/rpclibrary/js/**/*"
19
+  ],
20
+  "include": [
21
+    "./src/*.ts",
22
+    "./src/**/*.ts",
23
+  ]
24
+}

+ 9
- 7
src/frontend/tsconfig.json 查看文件

@@ -1,15 +1,14 @@
1 1
 {
2 2
   "compileOnSave": false,
3 3
   "compilerOptions": {
4
-    "importHelpers": true,
5
-    "module": "commonjs",
6
-    "outDir": "./dist/out-tsc",
7
-    "sourceMap": true,
8
-    "declaration": false,
4
+    "outDir": "./out-tsc",
5
+    "baseUrl": "./",
6
+    "declaration": true,
9 7
     "moduleResolution": "node",
10 8
     "emitDecoratorMetadata": true,
11 9
     "experimentalDecorators": true,
12
-    "target": "es5",
10
+    "importHelpers": true,
11
+    "target": "es2015",
13 12
     "typeRoots": [
14 13
       "node_modules/@types"
15 14
     ],
@@ -20,5 +19,8 @@
20 19
     "plugins": [
21 20
       { "name": "tslint-language-service"}
22 21
     ]
23
-  }
22
+  },
23
+  "angularCompilerOptions": {
24
+    "enableIvy": false,
25
+  },
24 26
 }

+ 15
- 0
src/frontend/tsconfig.server.json 查看文件

@@ -0,0 +1,15 @@
1
+{
2
+  "extends": "./tsconfig.app.json",
3
+  "compilerOptions": {
4
+    "outDir": "./out-tsc/app-server",
5
+    "module": "commonjs",
6
+    "types": ["node"]
7
+  },
8
+  "files": [
9
+    "src/main.server.ts",
10
+    "server.ts"
11
+  ],
12
+  "angularCompilerOptions": {
13
+    "entryModule": "./src/app/app.server.module#AppServerModule"
14
+  }
15
+}

+ 36
- 0
src/frontend/webpack.server.config.js 查看文件

@@ -0,0 +1,36 @@
1
+const path = require('path');
2
+const webpack = require('webpack');
3
+
4
+module.exports = {
5
+  entry: { server: './server.ts' },
6
+  resolve: { extensions: ['.js', '.ts'] },
7
+  mode: 'none',
8
+  target: 'node',
9
+  externals: [/(node_modules|main(\\|\/)..*(\\|\/).js)/],
10
+  output: {
11
+    path: path.join(__dirname, `dist`),
12
+    filename: '[name].js',
13
+    libraryTarget: 'commonjs'
14
+  },
15
+  module: {
16
+    rules: [
17
+      { test: /\.ts$/, loader: 'ts-loader', exclude: /^(?!.*\.spec\.ts$).*\.ts$/  },
18
+      {
19
+        test: /(\\|\/)@angular(\\|\/)core(\\|\/).+\.js$/,
20
+        parser: { system: true }
21
+      }
22
+    ]
23
+  },
24
+  plugins: [
25
+    new webpack.ContextReplacementPlugin(
26
+      /(.+)?angular(\\|\/)core(.+)?/,
27
+      path.join(__dirname, 'src'), // location of your src
28
+      {} // a map of your routes
29
+    ),
30
+    new webpack.ContextReplacementPlugin(
31
+      /(.+)?express(\\|\/)(.+)?/,
32
+      path.join(__dirname, 'src'),
33
+      {}
34
+    )
35
+  ]
36
+};

+ 3
- 9
tsconfig.json 查看文件

@@ -9,18 +9,12 @@
9 9
       "strict": true,
10 10
       "experimentalDecorators": true,
11 11
       "emitDecoratorMetadata": true,
12
-
12
+      "baseUrl": "./",
13 13
       "outDir": "./lib",
14
-      //"types": ["node"],
14
+      "types": ["node", "mocha"],
15 15
       "strictNullChecks": false
16 16
     },
17
-    "include": ["src/backend/**/*"],
18
-    "exclude": [
19
-      "./src/frontend/**/*",
20
-      "./node_modules/**/*", 
21
-      "./src/frontend/node_modules/**/*", 
22
-      "./test",
23
-    ],
17
+    "include": ["src", "test"],
24 18
     "angularCompilerOptions": {
25 19
       "enableIvy": false,
26 20
       "entryModule": "./src/backend/Admin/app.server.module#AppServerModule"

正在加载...
取消
保存