Merge branch 'dev' into celery-tasks

This commit is contained in:
Jonas Winkler
2020-11-10 00:16:59 +01:00
77 changed files with 1605 additions and 959 deletions

View File

@@ -1,16 +0,0 @@
import { TestBed } from '@angular/core/testing';
import { AuthGuardService } from './auth-guard.service';
describe('AuthGuardService', () => {
let service: AuthGuardService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AuthGuardService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@@ -1,20 +0,0 @@
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuardService {
constructor(public auth: AuthService, public router: Router) { }
canActivate(): boolean {
if (!this.auth.isAuthenticated()) {
this.router.navigate(['login']);
return false;
}
return true;
}
}

View File

@@ -1,16 +0,0 @@
import { TestBed } from '@angular/core/testing';
import { AuthInterceptor } from './auth.interceptor';
describe('AuthInterceptor', () => {
beforeEach(() => TestBed.configureTestingModule({
providers: [
AuthInterceptor
]
}));
it('should be created', () => {
const interceptor: AuthInterceptor = TestBed.inject(AuthInterceptor);
expect(interceptor).toBeTruthy();
});
});

View File

@@ -1,37 +0,0 @@
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { AuthService } from './auth.service';
import { catchError } from 'rxjs/operators';
import { Toast, ToastService } from './toast.service';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService, private toastService: ToastService) {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
if (this.authService.isAuthenticated()) {
request = request.clone({
setHeaders: {
Authorization: 'Token ' + this.authService.getToken()
}
});
}
return next.handle(request).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status == 401 && this.authService.isAuthenticated()) {
this.authService.logout()
this.toastService.showError("Your session has expired. Please log in again.")
}
return throwError(error)
})
);
}
}

View File

@@ -1,16 +0,0 @@
import { TestBed } from '@angular/core/testing';
import { AuthService } from './auth.service';
describe('AuthService', () => {
let service: AuthService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AuthService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@@ -1,72 +0,0 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { environment } from 'src/environments/environment';
interface TokenResponse {
token: string
}
@Injectable({
providedIn: 'root'
})
export class AuthService {
private currentUsername: string
private token: string
constructor(private http: HttpClient, private router: Router) {
this.token = localStorage.getItem('auth-service:token')
if (this.token == null) {
this.token = sessionStorage.getItem('auth-service:token')
}
this.currentUsername = localStorage.getItem('auth-service:currentUsername')
if (this.currentUsername == null) {
this.currentUsername = sessionStorage.getItem('auth-service:currentUsername')
}
}
private requestToken(username: string, password: string): Observable<TokenResponse> {
return this.http.post<TokenResponse>(`${environment.apiBaseUrl}token/`, {"username": username, "password": password})
}
isAuthenticated(): boolean {
return this.currentUsername != null
}
logout() {
this.currentUsername = null
this.token = null
localStorage.removeItem('auth-service:token')
localStorage.removeItem('auth-service:currentUsername')
sessionStorage.removeItem('auth-service:token')
sessionStorage.removeItem('auth-service:currentUsername')
this.router.navigate(['login'])
}
login(username: string, password: string, rememberMe: boolean): Observable<boolean> {
return this.requestToken(username,password).pipe(
map(tokenResponse => {
this.currentUsername = username
this.token = tokenResponse.token
let storage = rememberMe ? localStorage : sessionStorage
storage.setItem('auth-service:token', this.token)
storage.setItem('auth-service:currentUsername', this.currentUsername)
return true
})
)
}
getToken(): string {
return this.token
}
getCurrentUsername(): string {
return this.currentUsername
}
}

View File

@@ -3,8 +3,8 @@ import { Observable } from 'rxjs';
import { cloneFilterRules, FilterRule } from '../data/filter-rule';
import { PaperlessDocument } from '../data/paperless-document';
import { SavedViewConfig } from '../data/saved-view-config';
import { GENERAL_SETTINGS } from '../data/storage-keys';
import { DocumentService, SORT_DIRECTION_DESCENDING } from './rest/document.service';
import { DOCUMENT_LIST_SERVICE, GENERAL_SETTINGS } from '../data/storage-keys';
import { DocumentService } from './rest/document.service';
@Injectable({
@@ -18,33 +18,24 @@ export class DocumentListViewService {
currentPage = 1
currentPageSize: number = +localStorage.getItem(GENERAL_SETTINGS.DOCUMENT_LIST_SIZE) || GENERAL_SETTINGS.DOCUMENT_LIST_SIZE_DEFAULT
collectionSize: number
currentFilterRules: FilterRule[] = []
currentSortDirection = SORT_DIRECTION_DESCENDING
currentSortField = DocumentListViewService.DEFAULT_SORT_FIELD
viewConfig: SavedViewConfig
private currentViewConfig: SavedViewConfig
//TODO: make private
viewConfigOverride: SavedViewConfig
get viewId() {
return this.viewConfigOverride?.id
}
reload(onFinish?) {
let sortField: string
let sortDirection: string
let filterRules: FilterRule[]
if (this.viewConfig) {
sortField = this.viewConfig.sortField
sortDirection = this.viewConfig.sortDirection
filterRules = this.viewConfig.filterRules
} else {
sortField = this.currentSortField
sortDirection = this.currentSortDirection
filterRules = this.currentFilterRules
}
let viewConfig = this.viewConfigOverride || this.currentViewConfig
this.documentService.list(
this.currentPage,
this.currentPageSize,
sortField,
sortDirection,
filterRules).subscribe(
viewConfig.sortField,
viewConfig.sortDirection,
viewConfig.filterRules).subscribe(
result => {
this.collectionSize = result.count
this.documents = result.results
@@ -60,9 +51,43 @@ export class DocumentListViewService {
})
}
set filterRules(filterRules: FilterRule[]) {
this.currentViewConfig.filterRules = cloneFilterRules(filterRules)
this.saveCurrentViewConfig()
this.reload()
}
setFilterRules(filterRules: FilterRule[]) {
this.currentFilterRules = cloneFilterRules(filterRules)
get filterRules(): FilterRule[] {
return cloneFilterRules(this.currentViewConfig.filterRules)
}
set sortField(field: string) {
this.currentViewConfig.sortField = field
this.saveCurrentViewConfig()
this.reload()
}
get sortField(): string {
return this.currentViewConfig.sortField
}
set sortDirection(direction: string) {
this.currentViewConfig.sortDirection = direction
this.saveCurrentViewConfig()
this.reload()
}
get sortDirection(): string {
return this.currentViewConfig.sortDirection
}
loadViewConfig(config: SavedViewConfig) {
Object.assign(this.currentViewConfig, config)
this.reload()
}
private saveCurrentViewConfig() {
sessionStorage.setItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG, JSON.stringify(this.currentViewConfig))
}
getLastPage(): number {
@@ -108,5 +133,22 @@ export class DocumentListViewService {
}
}
constructor(private documentService: DocumentService) { }
constructor(private documentService: DocumentService) {
let currentViewConfigJson = sessionStorage.getItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG)
if (currentViewConfigJson) {
try {
this.currentViewConfig = JSON.parse(currentViewConfigJson)
} catch (e) {
sessionStorage.removeItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG)
this.currentViewConfig = null
}
}
if (!this.currentViewConfig) {
this.currentViewConfig = {
filterRules: [],
sortDirection: 'des',
sortField: 'created'
}
}
}
}

View File

@@ -21,7 +21,17 @@ export abstract class AbstractPaperlessService<T extends ObjectWithId> {
return url
}
list(page?: number, pageSize?: number, ordering?: string, extraParams?): Observable<Results<T>> {
private getOrderingQueryParam(sortField: string, sortDirection: string) {
if (sortField && sortDirection) {
return (sortDirection == 'des' ? '-' : '') + sortField
} else if (sortField) {
return sortField
} else {
return null
}
}
list(page?: number, pageSize?: number, sortField?: string, sortDirection?: string, extraParams?): Observable<Results<T>> {
let httpParams = new HttpParams()
if (page) {
httpParams = httpParams.set('page', page.toString())
@@ -29,6 +39,7 @@ export abstract class AbstractPaperlessService<T extends ObjectWithId> {
if (pageSize) {
httpParams = httpParams.set('page_size', pageSize.toString())
}
let ordering = this.getOrderingQueryParam(sortField, sortDirection)
if (ordering) {
httpParams = httpParams.set('ordering', ordering)
}

View File

@@ -2,7 +2,6 @@ import { Injectable } from '@angular/core';
import { PaperlessDocument } from 'src/app/data/paperless-document';
import { AbstractPaperlessService } from './abstract-paperless-service';
import { HttpClient } from '@angular/common/http';
import { AuthService } from '../auth.service';
import { Observable } from 'rxjs';
import { Results } from 'src/app/data/results';
import { FilterRule } from 'src/app/data/filter-rule';
@@ -10,6 +9,7 @@ import { FilterRule } from 'src/app/data/filter-rule';
export const DOCUMENT_SORT_FIELDS = [
{ field: "correspondent__name", name: "Correspondent" },
{ field: "document_type__name", name: "Document type" },
{ field: 'title', name: 'Title' },
{ field: 'archive_serial_number', name: 'ASN' },
{ field: 'created', name: 'Created' },
@@ -26,7 +26,7 @@ export const SORT_DIRECTION_DESCENDING = "des"
})
export class DocumentService extends AbstractPaperlessService<PaperlessDocument> {
constructor(http: HttpClient, private auth: AuthService) {
constructor(http: HttpClient) {
super(http, 'documents')
}
@@ -46,28 +46,20 @@ export class DocumentService extends AbstractPaperlessService<PaperlessDocument>
}
}
private getOrderingQueryParam(sortField: string, sortDirection: string) {
if (DOCUMENT_SORT_FIELDS.find(f => f.field == sortField)) {
return (sortDirection == SORT_DIRECTION_DESCENDING ? '-' : '') + sortField
} else {
return null
}
}
list(page?: number, pageSize?: number, sortField?: string, sortDirection?: string, filterRules?: FilterRule[]): Observable<Results<PaperlessDocument>> {
return super.list(page, pageSize, this.getOrderingQueryParam(sortField, sortDirection), this.filterRulesToQueryParams(filterRules))
return super.list(page, pageSize, sortField, sortDirection, this.filterRulesToQueryParams(filterRules))
}
getPreviewUrl(id: number): string {
return this.getResourceUrl(id, 'preview') + `?auth_token=${this.auth.getToken()}`
return this.getResourceUrl(id, 'preview')
}
getThumbUrl(id: number): string {
return this.getResourceUrl(id, 'thumb') + `?auth_token=${this.auth.getToken()}`
return this.getResourceUrl(id, 'thumb')
}
getDownloadUrl(id: number): string {
return this.getResourceUrl(id, 'download') + `?auth_token=${this.auth.getToken()}`
return this.getResourceUrl(id, 'download')
}
uploadDocument(formData) {

View File

@@ -10,7 +10,11 @@ export class SavedViewConfigService {
constructor() {
let savedConfigs = localStorage.getItem('saved-view-config-service:savedConfigs')
if (savedConfigs) {
this.configs = JSON.parse(savedConfigs)
try {
this.configs = JSON.parse(savedConfigs)
} catch (e) {
this.configs = []
}
}
}