Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
David
mayan-document-ui
Commits
161e3295
Commit
161e3295
authored
Feb 09, 2020
by
David
Browse files
Can display a card of the staging document!
parent
4e5f4fa6
Changes
17
Hide whitespace changes
Inline
Side-by-side
frontend/angular.json
View file @
161e3295
...
...
@@ -127,5 +127,8 @@
}
}
},
"defaultProject"
:
"frontend"
"defaultProject"
:
"frontend"
,
"cli"
:
{
"analytics"
:
"b1071caa-ca8a-408c-8c60-405d1c88f3e1"
}
}
\ No newline at end of file
frontend/src/app/app-routing.module.ts
View file @
161e3295
import
{
NgModule
}
from
'
@angular/core
'
;
import
{
Routes
,
RouterModule
}
from
'
@angular/router
'
;
import
{
LoginComponent
}
from
"
./login/login.component
"
;
import
{
DocumentManagerComponent
}
from
"
./document-manager/document-manager.component
"
;
import
{
AuthenticatedGuard
}
from
"
./authenticated.guard
"
;
import
{
LoginComponent
}
from
'
./login/login.component
'
;
import
{
DocumentManagerComponent
}
from
'
./document-manager/document-manager.component
'
;
import
{
AuthenticatedGuard
}
from
'
./authenticated.guard
'
;
const
routes
:
Routes
=
[
...
...
frontend/src/app/app.module.ts
View file @
161e3295
...
...
@@ -5,20 +5,24 @@ import {AppRoutingModule} from './app-routing.module';
import
{
AppComponent
}
from
'
./app.component
'
;
import
{
BrowserAnimationsModule
}
from
'
@angular/platform-browser/animations
'
;
import
{
LoginComponent
}
from
'
./login/login.component
'
;
import
{
ReactiveFormsModule
}
from
"
@angular/forms
"
;
import
{
MatFormFieldModule
}
from
"
@angular/material/form-field
"
;
import
{
MatIconModule
}
from
"
@angular/material/icon
"
;
import
{
MatInputModule
}
from
"
@angular/material/input
"
;
import
{
MatButtonModule
}
from
"
@angular/material/button
"
;
import
{
HttpClientModule
}
from
"
@angular/common/http
"
;
import
{
StorageModule
}
from
'
@ngx-pwa/local-storage
'
;
import
{
DocumentManagerComponent
}
from
'
./document-manager/document-manager.component
'
;
import
{
ReactiveFormsModule
}
from
'
@angular/forms
'
;
import
{
MatFormFieldModule
}
from
'
@angular/material/form-field
'
;
import
{
MatIconModule
}
from
'
@angular/material/icon
'
;
import
{
MatInputModule
}
from
'
@angular/material/input
'
;
import
{
MatButtonModule
}
from
'
@angular/material/button
'
;
import
{
HTTP_INTERCEPTORS
,
HttpClientModule
}
from
'
@angular/common/http
'
;
import
{
StorageModule
}
from
'
@ngx-pwa/local-storage
'
;
import
{
DocumentManagerComponent
}
from
'
./document-manager/document-manager.component
'
;
import
{
TokenInterceptor
}
from
'
./token-interceptor
'
;
import
{
StagingDocumentComponent
}
from
'
./document-manager/staging-document/staging-document.component
'
;
import
{
MatCardModule
}
from
'
@angular/material/card
'
;
@
NgModule
({
declarations
:
[
AppComponent
,
LoginComponent
,
DocumentManagerComponent
DocumentManagerComponent
,
StagingDocumentComponent
],
imports
:
[
BrowserModule
,
...
...
@@ -30,9 +34,12 @@ import { DocumentManagerComponent } from './document-manager/document-manager.co
MatInputModule
,
MatButtonModule
,
HttpClientModule
,
StorageModule
.
forRoot
({
IDBNoWrap
:
true
})
StorageModule
.
forRoot
({
IDBNoWrap
:
true
}),
MatCardModule
],
providers
:
[
{
provide
:
HTTP_INTERCEPTORS
,
useClass
:
TokenInterceptor
,
multi
:
true
},
],
providers
:
[],
bootstrap
:
[
AppComponent
]
})
export
class
AppModule
{
...
...
frontend/src/app/authenticated.guard.ts
View file @
161e3295
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
CanActivate
,
CanActivateChild
,
ActivatedRouteSnapshot
,
RouterStateSnapshot
,
UrlTree
}
from
'
@angular/router
'
;
import
{
Observable
}
from
'
rxjs
'
;
import
{
StorageMap
}
from
"
@ngx-pwa/local-storage
"
;
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
CanActivate
,
CanActivateChild
,
ActivatedRouteSnapshot
,
RouterStateSnapshot
,
UrlTree
,
Router
}
from
'
@angular/router
'
;
import
{
Observable
}
from
'
rxjs
'
;
import
{
LoginService
}
from
'
./login/login.service
'
;
import
{
map
,
tap
}
from
'
rxjs/operators
'
;
@
Injectable
({
providedIn
:
'
root
'
})
export
class
AuthenticatedGuard
implements
CanActivate
,
CanActivateChild
{
constructor
(
private
readonly
storageMap
:
StorageMap
)
{}
constructor
(
private
readonly
loginService
:
LoginService
,
private
readonly
router
:
Router
)
{
}
canActivate
(
next
:
ActivatedRouteSnapshot
,
state
:
RouterStateSnapshot
):
Observable
<
boolean
|
UrlTree
>
|
Promise
<
boolean
|
UrlTree
>
|
boolean
|
UrlTree
{
//Check to see if we have an auth token in storage, and if it's valid somehow?
return
t
rue
;
return
t
his
.
validate
()
;
}
canActivateChild
(
next
:
ActivatedRouteSnapshot
,
state
:
RouterStateSnapshot
):
Observable
<
boolean
|
UrlTree
>
|
Promise
<
boolean
|
UrlTree
>
|
boolean
|
UrlTree
{
return
true
;
return
this
.
validate
();
}
private
validate
():
Observable
<
boolean
|
UrlTree
>
{
console
.
log
(
'
VALIDATING LOGIN
'
);
return
this
.
loginService
.
validateToken
().
pipe
(
tap
(
result
=>
console
.
log
(
'
result is
'
,
result
)),
map
(
result
=>
{
if
(
!
result
)
{
// return a URL tree to login
return
this
.
router
.
createUrlTree
([
'
login
'
]);
}
return
result
;
})
);
}
}
frontend/src/app/document-manager/document-manager.component.html
View file @
161e3295
<p>
document-manager works!
</p>
<p>
Staged Documents
</p>
<div
*ngIf=
"loading"
>
Loading...
</div>
<div
*ngIf=
"!loading"
class=
"staging-documents-list"
>
<div
*ngFor=
"let stagingFile of (stagingFiles | async)"
>
<app-staging-document
[stagingFolderFile]=
"stagingFile"
></app-staging-document>
</div>
</div>
frontend/src/app/document-manager/document-manager.component.scss
View file @
161e3295
.staging-documents-list
{
display
:
flex
;
justify-content
:
left
;
flex-direction
:
row
;
}
frontend/src/app/document-manager/document-manager.component.ts
View file @
161e3295
import
{
Component
,
OnInit
}
from
'
@angular/core
'
;
import
{
EMPTY
,
Observable
,
of
,
timer
}
from
'
rxjs
'
;
import
{
flatMap
,
tap
}
from
'
rxjs/operators
'
;
import
{
DocumentService
}
from
'
./document.service
'
;
import
{
StagingFolderFile
}
from
'
../mayan-api
'
;
@
Component
({
selector
:
'
app-document-manager
'
,
...
...
@@ -7,9 +11,22 @@ import { Component, OnInit } from '@angular/core';
})
export
class
DocumentManagerComponent
implements
OnInit
{
constructor
()
{
}
loading
=
false
;
stagingFiles
:
Observable
<
[
StagingFolderFile
]
>
=
EMPTY
;
constructor
(
private
readonly
documentService
:
DocumentService
)
{
}
ngOnInit
()
{
// load staging documents, display them create a timer to update the list
timer
(
0
,
5000
).
pipe
(
tap
(
m
=>
this
.
loading
=
true
),
flatMap
(
m
=>
this
.
documentService
.
loadStagingFiles
()),
tap
(
stagingFiles
=>
{
this
.
stagingFiles
=
of
(
stagingFiles
);
this
.
loading
=
false
;
})
).
subscribe
();
// todo, need the destroy, or do this differently
}
}
frontend/src/app/document-manager/document-service.service.spec.ts
0 → 100644
View file @
161e3295
import
{
TestBed
}
from
'
@angular/core/testing
'
;
import
{
DocumentService
}
from
'
./document.service
'
;
describe
(
'
DocumentServiceService
'
,
()
=>
{
let
service
:
DocumentService
;
beforeEach
(()
=>
{
TestBed
.
configureTestingModule
({});
service
=
TestBed
.
inject
(
DocumentService
);
});
it
(
'
should be created
'
,
()
=>
{
expect
(
service
).
toBeTruthy
();
});
});
frontend/src/app/document-manager/document.service.ts
0 → 100644
View file @
161e3295
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
Observable
,
of
}
from
'
rxjs
'
;
import
{
MayanResult
,
StagingFolder
,
StagingFolderFile
}
from
'
../mayan-api
'
;
import
{
HttpClient
}
from
'
@angular/common/http
'
;
import
{
environment
}
from
'
../../environments/environment
'
;
import
{
flatMap
,
map
}
from
'
rxjs/operators
'
;
@
Injectable
({
providedIn
:
'
root
'
})
export
class
DocumentService
{
constructor
(
private
readonly
httpClient
:
HttpClient
)
{
}
loadStagingFiles
(
page
?:
number
):
Observable
<
[
StagingFolderFile
]
>
{
return
this
.
httpClient
.
get
<
MayanResult
<
StagingFolder
>>
(
`
${
environment
.
mayan
}
/staging_folders/`
).
pipe
(
map
(
result
=>
{
return
result
.
results
[
0
];
}),
flatMap
(
stagingFolder
=>
of
(
stagingFolder
.
files
))
);
}
}
frontend/src/app/document-manager/staging-document/staging-document.component.html
0 → 100644
View file @
161e3295
<mat-card
class=
"example-card"
>
<mat-card-header>
<div
mat-card-avatar
class=
"example-header-image"
></div>
<mat-card-title>
{{stagingFolderFile.filename}}
</mat-card-title>
</mat-card-header>
<img
mat-card-image
src=
"{{stagingFolderFile.image_url}}"
alt=
"Staging Document Preview"
>
<mat-card-actions>
<button
mat-button
>
Import
</button>
<button
mat-button
>
Discard
</button>
</mat-card-actions>
</mat-card>
frontend/src/app/document-manager/staging-document/staging-document.component.scss
0 → 100644
View file @
161e3295
frontend/src/app/document-manager/staging-document/staging-document.component.spec.ts
0 → 100644
View file @
161e3295
import
{
async
,
ComponentFixture
,
TestBed
}
from
'
@angular/core/testing
'
;
import
{
StagingDocumentComponent
}
from
'
./staging-document.component
'
;
describe
(
'
StagingDocumentComponent
'
,
()
=>
{
let
component
:
StagingDocumentComponent
;
let
fixture
:
ComponentFixture
<
StagingDocumentComponent
>
;
beforeEach
(
async
(()
=>
{
TestBed
.
configureTestingModule
({
declarations
:
[
StagingDocumentComponent
]
})
.
compileComponents
();
}));
beforeEach
(()
=>
{
fixture
=
TestBed
.
createComponent
(
StagingDocumentComponent
);
component
=
fixture
.
componentInstance
;
fixture
.
detectChanges
();
});
it
(
'
should create
'
,
()
=>
{
expect
(
component
).
toBeTruthy
();
});
});
frontend/src/app/document-manager/staging-document/staging-document.component.ts
0 → 100644
View file @
161e3295
import
{
Component
,
Input
,
OnInit
}
from
'
@angular/core
'
;
import
{
StagingFolderFile
}
from
'
../../mayan-api
'
;
@
Component
({
selector
:
'
app-staging-document
'
,
templateUrl
:
'
./staging-document.component.html
'
,
styleUrls
:
[
'
./staging-document.component.scss
'
]
})
export
class
StagingDocumentComponent
implements
OnInit
{
@
Input
()
stagingFolderFile
:
StagingFolderFile
;
constructor
()
{
}
ngOnInit
():
void
{
}
}
frontend/src/app/login/login.component.ts
View file @
161e3295
import
{
Component
,
OnInit
}
from
'
@angular/core
'
;
import
{
FormControl
,
FormGroup
,
Validators
}
from
"
@angular/forms
"
;
import
{
environment
}
from
"
../../environments/environment
"
;
import
{
LoginService
}
from
"
./login.service
"
;
import
{
m
ap
}
from
"
rxjs/operators
"
;
import
{
FormControl
,
FormGroup
,
Validators
}
from
'
@angular/forms
'
;
import
{
LoginService
}
from
'
./login.service
'
;
import
{
Router
}
from
'
@angular/router
'
;
import
{
t
ap
}
from
'
rxjs/operators
'
;
@
Component
({
selector
:
'
app-login
'
,
...
...
@@ -17,18 +17,22 @@ export class LoginComponent implements OnInit {
password
:
new
FormControl
(
''
),
});
constructor
(
private
readonly
loginService
:
LoginService
)
{
constructor
(
private
readonly
loginService
:
LoginService
,
private
readonly
router
:
Router
)
{
}
ngOnInit
()
{
}
doLogin
()
{
console
.
log
(
"
would post to mayan to do the needful
"
,
environment
.
mayan
);
this
.
loginService
.
getAuthToken
(
this
.
loginForm
.
controls
.
username
.
value
,
this
.
loginForm
.
controls
.
password
.
value
)
.
subscribe
(
meh
=>
{
//when it's complete, we need to navigate to the other thing
})
.
pipe
(
tap
(
what
=>
console
.
log
(
'
login component
'
,
what
)),
)
.
subscribe
(
something
=>
{
// when it's complete, we need to navigate to the other thing
this
.
router
.
navigate
([
'
/
'
]);
});
}
}
frontend/src/app/login/login.service.ts
View file @
161e3295
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
HttpClient
}
from
"
@angular/common/http
"
;
import
{
environment
}
from
"
../../environments/environment
"
;
import
{
EMPTY
,
Observable
}
from
"
rxjs
"
;
import
{
StorageMap
}
from
"
@ngx-pwa/local-storage
"
;
import
{
flatMap
,
map
}
from
"
rxjs/operators
"
;
import
{
HttpClient
}
from
'
@angular/common/http
'
;
import
{
environment
}
from
'
../../environments/environment
'
;
import
{
Observable
}
from
'
rxjs
'
;
import
{
StorageMap
}
from
'
@ngx-pwa/local-storage
'
;
import
{
flatMap
,
map
}
from
'
rxjs/operators
'
;
import
{
User
}
from
'
../mayan-api
'
;
@
Injectable
({
providedIn
:
'
root
'
})
export
class
LoginService
{
p
rivate
AUTH_TOKEN
=
"
authToken
"
;
p
ublic
static
readonly
AUTH_TOKEN
=
'
authToken
'
;
constructor
(
private
readonly
httpClient
:
HttpClient
,
private
readonly
storageMap
:
StorageMap
)
{
}
getAuthToken
(
username
:
S
tring
,
password
:
S
tring
):
Observable
<
undefined
>
{
getAuthToken
(
username
:
s
tring
,
password
:
s
tring
):
Observable
<
undefined
>
{
const
request
=
{
username
:
username
,
password
:
password
username
,
password
}
as
LoginRequest
;
return
this
.
httpClient
.
post
<
TokenResponse
>
(
`
${
environment
.
mayan
}
/auth/token/obtain/`
,
request
).
pipe
(
flatMap
(
response
=>
{
return
this
.
storageMap
.
set
(
this
.
AUTH_TOKEN
,
response
.
token
);
})
return
this
.
storageMap
.
set
(
LoginService
.
AUTH_TOKEN
,
response
.
token
);
})
,
);
}
validateToken
():
Observable
<
Boolean
>
{
this
.
storageMap
.
get
(
this
.
AUTH_TOKEN
).
pipe
(
flatMap
(
//Make HTTP call to validate token
)
validateToken
():
Observable
<
boolean
>
{
return
this
.
httpClient
.
get
<
User
>
(
`
${
environment
.
mayan
}
/users/current/`
).
pipe
(
map
(
results
=>
results
.
id
!==
null
),
);
return
EMPTY
;
}
}
export
interface
LoginRequest
{
username
:
S
tring
;
password
:
S
tring
;
username
:
s
tring
;
password
:
s
tring
;
}
export
interface
TokenResponse
{
token
:
S
tring
;
token
:
s
tring
;
}
frontend/src/app/mayan-api.ts
0 → 100644
View file @
161e3295
export
interface
MayanResult
<
T
>
{
count
:
number
;
next
:
string
;
previous
:
string
;
results
:
[
T
];
}
export
interface
User
{
first_name
:
string
;
date_joined
:
string
;
email
:
string
;
groups
:
[
any
];
id
:
number
;
is_active
:
boolean
;
last_login
:
string
;
last_name
:
string
;
password
:
string
;
url
:
string
;
username
:
string
;
}
export
interface
StagingFolder
{
files
:
[
StagingFolderFile
];
}
export
interface
StagingFolderFile
{
filename
:
string
;
image_url
:
string
;
url
:
string
;
}
frontend/src/app/token-interceptor.ts
0 → 100644
View file @
161e3295
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
HttpEvent
,
HttpHandler
,
HttpInterceptor
,
HttpRequest
}
from
'
@angular/common/http
'
;
import
{
Observable
,
of
}
from
'
rxjs
'
;
import
{
StorageMap
}
from
'
@ngx-pwa/local-storage
'
;
import
{
LoginService
}
from
'
./login/login.service
'
;
import
{
environment
}
from
'
../environments/environment
'
;
import
{
flatMap
,
map
,
tap
}
from
'
rxjs/operators
'
;
@
Injectable
()
export
class
TokenInterceptor
implements
HttpInterceptor
{
constructor
(
private
readonly
storageMap
:
StorageMap
)
{
}
intercept
(
req
:
HttpRequest
<
any
>
,
next
:
HttpHandler
):
Observable
<
HttpEvent
<
any
>>
{
// do not intercept logins
if
(
req
.
url
===
`
${
environment
.
mayan
}
/auth/token/obtain/`
)
{
return
next
.
handle
(
req
);
}
// Oof, remember to do observables right, dingus
return
this
.
storageMap
.
has
(
LoginService
.
AUTH_TOKEN
).
pipe
(
flatMap
(
has
=>
{
if
(
has
)
{
return
this
.
storageMap
.
get
(
LoginService
.
AUTH_TOKEN
).
pipe
(
flatMap
(
authToken
=>
{
const
authReq
=
req
.
clone
({
setHeaders
:
{
Authorization
:
`Token
${
authToken
}
`
}
});
return
next
.
handle
(
authReq
);
}),
);
}
else
{
return
next
.
handle
(
req
);
}
})
);
}
}
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