Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
arsnova-click-v2-frontend
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
12
Merge Requests
12
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
ARSnova
arsnova-click-v2-frontend
Commits
f04fa781
Commit
f04fa781
authored
Jun 16, 2018
by
Christopher Mark Fullarton
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Secures the i18n-manager apis. Fixes style bugs in the theme switcher
parent
64355228
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
141 additions
and
46 deletions
+141
-46
server.ts
server.ts
+111
-27
src/app/root/login/login.component.spec.ts
src/app/root/login/login.component.spec.ts
+2
-2
src/app/root/login/login.component.ts
src/app/root/login/login.component.ts
+10
-5
src/app/root/theme-switcher/theme-switcher.component.ts
src/app/root/theme-switcher/theme-switcher.component.ts
+2
-3
src/app/service/api/themes/themes-api.service.ts
src/app/service/api/themes/themes-api.service.ts
+5
-3
src/app/themes/themes.component.ts
src/app/themes/themes.component.ts
+3
-1
src/assets/themes/themeSwitcher.scss
src/assets/themes/themeSwitcher.scss
+6
-4
src/index.html
src/index.html
+2
-1
No files found.
server.ts
View file @
f04fa781
...
...
@@ -7,14 +7,15 @@ import * as bodyParser from 'body-parser';
import
*
as
child_process
from
'
child_process
'
;
import
*
as
compress
from
'
compression
'
;
import
*
as
cors
from
'
cors
'
;
import
*
as
express
from
'
express
'
;
import
*
as
fs
from
'
fs
'
;
import
*
as
https
from
'
https
'
;
import
*
as
path
from
'
path
'
;
import
'
reflect-metadata
'
;
// These are important and needed before anything else
import
'
zone.js/dist/zone-node
'
;
import
{
DefaultSettings
}
from
'
./src/lib/default.settings
'
;
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode
();
...
...
@@ -42,12 +43,19 @@ const i18nFileBaseLocation = {
};
app
.
use
(
bodyParser
.
json
({
limit
:
'
50mb
'
}));
app
.
use
(
bodyParser
.
urlencoded
({
limit
:
'
50mb
'
,
extended
:
true
}));
app
.
use
(
bodyParser
.
urlencoded
({
limit
:
'
50mb
'
,
extended
:
true
,
}));
app
.
use
(
cors
(
corsOptions
));
app
.
use
(
compress
());
app
.
param
(
'
project
'
,
(
req
,
res
,
next
,
project
)
=>
{
if
(
!
project
||
!
i18nFileBaseLocation
[
project
])
{
res
.
status
(
500
).
send
({
status
:
'
STATUS:FAILED
'
,
data
:
'
Invalid Project specified
'
,
payload
:
{
project
}
});
res
.
status
(
500
).
send
({
status
:
'
STATUS:FAILED
'
,
data
:
'
Invalid Project specified
'
,
payload
:
{
project
},
});
}
else
{
req
.
i18nFileBaseLocation
=
i18nFileBaseLocation
[
project
];
req
.
projectBaseLocation
=
projectBaseLocation
[
project
];
...
...
@@ -121,13 +129,21 @@ const buildKeys = ({ root, dataNode, langRef, langData }) => {
}
else
{
const
value
=
{};
value
[
langRef
]
=
dataNode
;
langData
.
push
({
key
:
root
,
value
});
langData
.
push
({
key
:
root
,
value
,
});
}
}
else
{
Object
.
keys
(
dataNode
).
forEach
(
key
=>
{
const
rootKey
=
root
?
`
${
root
}
.`
:
''
;
buildKeys
({
root
:
`
${
rootKey
}${
key
}
`
,
dataNode
:
dataNode
[
key
],
langRef
,
langData
});
buildKeys
({
root
:
`
${
rootKey
}${
key
}
`
,
dataNode
:
dataNode
[
key
],
langRef
,
langData
,
});
});
}
};
...
...
@@ -194,7 +210,8 @@ const getBranch = (req) => {
};
app
.
engine
(
'
html
'
,
ngExpressEngine
({
bootstrap
:
RootServerModuleNgFactory
,
providers
:
[
bootstrap
:
RootServerModuleNgFactory
,
providers
:
[
provideModuleMap
(
LAZY_MODULE_MAP
),
],
}));
...
...
@@ -204,13 +221,20 @@ app.set('views', path.join(DIST_FOLDER, 'browser'));
// TODO: implement data requests securely
app
.
get
(
'
/api/v1/plugin/i18nator/:project/langFile
'
,
async
(
req
,
res
)
=>
{
const
payload
=
{
langData
:
{},
unused
:
{},
branch
:
{}
};
const
payload
=
{
langData
:
{},
unused
:
{},
branch
:
{},
};
if
(
!
cache
[
req
.
projectCache
].
langData
)
{
const
langData
=
[];
availableLangs
.
forEach
((
langRef
,
index
)
=>
{
buildKeys
({
root
:
''
,
dataNode
:
JSON
.
parse
(
fs
.
readFileSync
(
path
.
join
(
req
.
i18nFileBaseLocation
,
`
${
langRef
}
.json`
)).
toString
(
'
UTF-8
'
)),
langRef
,
langData
,
root
:
''
,
dataNode
:
JSON
.
parse
(
fs
.
readFileSync
(
path
.
join
(
req
.
i18nFileBaseLocation
,
`
${
langRef
}
.json`
)).
toString
(
'
UTF-8
'
)),
langRef
,
langData
,
});
});
cache
[
req
.
projectCache
].
langData
=
langData
;
...
...
@@ -227,32 +251,90 @@ app.get('/api/v1/plugin/i18nator/:project/langFile', async (req, res) => {
}
payload
.
branch
=
cache
[
req
.
projectCache
].
branch
;
res
.
send
({
status
:
'
STATUS:SUCCESSFUL
'
,
payload
});
res
.
send
({
status
:
'
STATUS:SUCCESSFUL
'
,
payload
,
});
});
app
.
post
(
'
/api/v1/plugin/i18nator/:project/updateLang
'
,
async
(
req
,
res
)
=>
{
const
username
=
req
.
body
.
username
;
const
token
=
req
.
body
.
token
;
if
(
!
username
||
!
token
)
{
res
.
send
({
status
:
'
STATUS:FAILED
'
,
step
:
'
AUTHENTICATE_STATIC
'
,
payload
:
{
reason
:
'
UNKOWN_LOGIN
'
},
});
return
;
}
if
(
!
req
.
body
.
data
)
{
res
.
status
(
500
).
send
({
status
:
'
STATUS:FAILED
'
,
data
:
'
Invalid Data
'
,
payload
:
{
body
:
req
.
body
}
});
res
.
status
(
500
).
send
({
status
:
'
STATUS:FAILED
'
,
data
:
'
Invalid Data
'
,
payload
:
{
body
:
req
.
body
},
});
return
;
}
const
result
=
{
en
:
{},
de
:
{},
es
:
{},
fr
:
{},
it
:
{}
};
const
langKeys
=
Object
.
keys
(
result
);
createObjectFromKeys
({
data
:
req
.
body
.
data
,
result
});
const
request
=
https
.
get
(
`
${
DefaultSettings
.
httpLibEndpoint
}
/authorize/validate/
${
username
}
/
${
token
}
`
,
(
response
)
=>
{
cache
[
req
.
projectCache
].
langData
=
req
.
body
.
data
;
let
data
=
''
;
langKeys
.
forEach
((
langRef
,
index
)
=>
{
const
fileContent
=
result
[
langRef
];
const
fileLocation
=
path
.
join
(
req
.
i18nFileBaseLocation
,
`
${
langRef
}
.json`
);
const
exists
=
fs
.
existsSync
(
fileLocation
);
if
(
!
exists
)
{
res
.
status
(
404
).
send
({
status
:
'
STATUS:FAILED
'
,
data
:
'
File not found
'
,
payload
:
{
fileLocation
}
});
return
;
}
fs
.
writeFileSync
(
fileLocation
,
JSON
.
stringify
(
fileContent
));
if
(
index
===
langKeys
.
length
-
1
)
{
res
.
send
({
status
:
'
STATUS:SUCCESSFUL
'
});
}
response
.
on
(
'
data
'
,
(
chunk
)
=>
{
data
+=
chunk
;
});
response
.
on
(
'
end
'
,
()
=>
{
data
=
JSON
.
parse
(
data
);
if
(
!
data
&&
data
.
status
!==
'
STATUS:SUCCESSFUL
'
)
{
return
;
}
const
result
=
{
en
:
{},
de
:
{},
es
:
{},
fr
:
{},
it
:
{},
};
const
langKeys
=
Object
.
keys
(
result
);
createObjectFromKeys
({
data
:
req
.
body
.
data
,
result
,
});
cache
[
req
.
projectCache
].
langData
=
req
.
body
.
data
;
langKeys
.
forEach
((
langRef
,
index
)
=>
{
const
fileContent
=
result
[
langRef
];
const
fileLocation
=
path
.
join
(
req
.
i18nFileBaseLocation
,
`
${
langRef
}
.json`
);
const
exists
=
fs
.
existsSync
(
fileLocation
);
if
(
!
exists
)
{
res
.
status
(
404
).
send
({
status
:
'
STATUS:FAILED
'
,
data
:
'
File not found
'
,
payload
:
{
fileLocation
},
});
return
;
}
fs
.
writeFileSync
(
fileLocation
,
JSON
.
stringify
(
fileContent
));
if
(
index
===
langKeys
.
length
-
1
)
{
res
.
send
({
status
:
'
STATUS:SUCCESSFUL
'
});
}
});
});
});
request
.
on
(
'
error
'
,
(
error
)
=>
{
console
.
log
(
'
error at validating login token
'
,
error
);
request
.
abort
();
res
.
send
({
status
:
'
STATUS:FAILED
'
,
step
:
'
UPDATE_LANG
'
,
payload
:
{
error
},
});
return
;
});
});
app
.
get
(
'
/api/*
'
,
(
req
,
res
)
=>
{
...
...
@@ -290,7 +372,9 @@ const buildCache = () => {
console
.
log
(
`* Fetching unused keys`
);
const
unusedKeysStart
=
new
Date
().
getTime
();
cache
[
projectName
].
unused
=
getUnusedKeys
({
params
:
{},
projectAppLocation
:
projectAppLocation
[
projectName
],
i18nFileBaseLocation
:
i18nFileBaseLocation
[
projectName
],
params
:
{},
projectAppLocation
:
projectAppLocation
[
projectName
],
i18nFileBaseLocation
:
i18nFileBaseLocation
[
projectName
],
});
const
unusedKeysEnd
=
new
Date
().
getTime
();
console
.
log
(
`-- Done. Took
${
unusedKeysEnd
-
unusedKeysStart
}
ms`
);
...
...
src/app/root/login/login.component.spec.ts
View file @
f04fa781
...
...
@@ -111,7 +111,7 @@ describe('LoginComponent', () => {
spyOn
(
router
,
'
navigateByUrl
'
).
and
.
callFake
(()
=>
{});
await
component
.
login
();
expect
(
component
[
'
authorizationFailed
'
]).
toBeFalsy
();
expect
(
component
[
'
_
authorizationFailed
'
]).
toBeFalsy
();
}));
...
...
@@ -127,7 +127,7 @@ describe('LoginComponent', () => {
spyOn
(
router
,
'
navigateByUrl
'
).
and
.
callFake
(()
=>
{});
await
component
.
login
();
expect
(
component
[
'
authorizationFailed
'
]).
toBeTruthy
();
expect
(
component
[
'
_
authorizationFailed
'
]).
toBeTruthy
();
}));
});
});
src/app/root/login/login.component.ts
View file @
f04fa781
...
...
@@ -11,11 +11,16 @@ import { UserService } from '../../service/user/user.service';
})
export
class
LoginComponent
implements
OnInit
{
public
static
readonly
TYPE
=
'
LoginComponent
'
;
public
username
=
''
;
public
password
=
''
;
private
_authorizationFailed
=
false
;
get
authorizationFailed
():
boolean
{
return
this
.
_authorizationFailed
;
}
private
username
=
''
;
private
password
=
''
;
private
return
=
''
;
private
authorizationFailed
=
false
;
constructor
(
private
userService
:
UserService
,
...
...
@@ -34,7 +39,7 @@ export class LoginComponent implements OnInit {
}
public
async
login
():
Promise
<
void
>
{
this
.
authorizationFailed
=
false
;
this
.
_
authorizationFailed
=
false
;
if
(
this
.
username
&&
this
.
password
)
{
const
passwordHash
=
this
.
userService
.
hashPassword
(
this
.
username
,
this
.
password
);
...
...
@@ -43,7 +48,7 @@ export class LoginComponent implements OnInit {
if
(
isAuthenticated
)
{
this
.
router
.
navigateByUrl
(
this
.
return
);
}
else
{
this
.
authorizationFailed
=
true
;
this
.
_
authorizationFailed
=
true
;
}
}
}
...
...
src/app/root/theme-switcher/theme-switcher.component.ts
View file @
f04fa781
...
...
@@ -54,12 +54,11 @@ export class ThemeSwitcherComponent {
if
(
isPlatformBrowser
(
this
.
platformId
))
{
const
themeDataset
=
document
.
getElementsByTagName
(
'
html
'
).
item
(
0
).
dataset
[
'
theme
'
];
if
(
themeDataset
=
==
this
.
previewThemeBackup
)
{
if
(
themeDataset
!
==
this
.
previewThemeBackup
)
{
document
.
getElementsByTagName
(
'
html
'
).
item
(
0
).
dataset
[
'
theme
'
]
=
this
.
previewThemeBackup
;
this
.
themesService
.
reloadLinkNodes
(
this
.
previewThemeBackup
);
return
;
}
this
.
themesService
.
reloadLinkNodes
(
this
.
previewThemeBackup
);
}
}
...
...
src/app/service/api/themes/themes-api.service.ts
View file @
f04fa781
...
...
@@ -9,9 +9,11 @@ import { DefaultSettings } from '../../../../lib/default.settings';
})
export
class
ThemesApiService
{
constructor
(
private
http
:
HttpClient
,
)
{
}
constructor
(
private
http
:
HttpClient
)
{
}
public
THEMES_PREVIEW_GET_URL
(
id
:
string
,
langRef
:
string
):
string
{
return
`/assets/images/theme/
${
id
}
/preview_
${
langRef
}
.jpeg`
;
}
public
THEMES_GET_URL
():
string
{
return
`
${
DefaultSettings
.
httpApiEndpoint
}
/themes`
;
...
...
src/app/themes/themes.component.ts
View file @
f04fa781
import
{
Component
,
EventEmitter
,
OnDestroy
,
Output
}
from
'
@angular/core
'
;
import
{
TranslateService
}
from
'
@ngx-translate/core
'
;
import
{
ThemesApiService
}
from
'
../service/api/themes/themes-api.service
'
;
import
{
ThemesService
}
from
'
../service/themes/themes.service
'
;
import
{
CategoryType
,
TrackingService
}
from
'
../service/tracking/tracking.service
'
;
...
...
@@ -19,6 +20,7 @@ export class ThemesComponent implements OnDestroy {
private
translateService
:
TranslateService
,
public
themesService
:
ThemesService
,
private
trackingService
:
TrackingService
,
private
themesApiService
:
ThemesApiService
,
)
{
this
.
_currentTheme
=
this
.
themesService
.
currentTheme
;
}
...
...
@@ -32,7 +34,7 @@ export class ThemesComponent implements OnDestroy {
}
public
getThemePreviewUrl
(
id
:
string
):
string
{
return
`/assets/images/theme/
${
id
}
/preview_
${
this
.
translateService
.
currentLang
}
.jpeg`
;
return
this
.
themesApiService
.
THEMES_PREVIEW_GET_URL
(
id
,
this
.
translateService
.
currentLang
)
;
}
public
change
(
id
:
string
):
void
{
...
...
src/assets/themes/themeSwitcher.scss
View file @
f04fa781
...
...
@@ -127,14 +127,12 @@
@each
$theme
,
$map
in
$themes
{
html
[
data-theme
=
#{
$theme
}
]
{
@include
transitionEffect
(
map-get
(
$map
,
"background-color"
));
*
:fullscreen
,
:-webkit-full-screen
,
*
:-webkit-full-screen
,
*
:-moz-full-screen
,
body
{
@include
transitionEffect
(
map-get
(
$map
,
"background-color"
));
}
@include
introjs
(
$map
);
...
...
@@ -162,7 +160,12 @@
}
}
#theme-wrapper
{
background-color
:
map-get
(
$map
,
"background-color"
);
@include
transitionEffect
(
map-get
(
$map
,
"background-color"
));
#content-container
{
@include
transitionEffect
(
map-get
(
$map
,
"background-color"
));
}
.text-light
,
a
.text-light
,
a
:hover
.text-light
,
a
:active
.text-light
,
a
:visited
.text-light
,
a
:focus
.text-light
{
color
:
map-get
(
$map
,
"fg-text-light"
);
}
...
...
@@ -208,7 +211,6 @@
@include
transitionEffect
(
map-get
(
$map
,
"bg-nav-row"
));
.nav-row
{
@include
transitionEffect
(
map-get
(
$map
,
"bg-nav-row"
));
background-color
:
map-get
(
$map
,
"bg-nav-row"
);
}
}
*
:
:-
webkit-input-placeholder
{
...
...
src/index.html
View file @
f04fa781
...
...
@@ -73,7 +73,8 @@
</head>
<body>
<div
id=
"theme-wrapper"
>
<div
id=
"theme-wrapper"
class=
"overflow-auto"
>
<div
id=
"content"
>
<app-root>
<div
id=
"loader-wrapper"
>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment