mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-09 09:58:20 -05:00
add comment function
This commit is contained in:
parent
d1e8299010
commit
817882ff6f
@ -67,6 +67,7 @@ import { ApiVersionInterceptor } from './interceptors/api-version.interceptor'
|
|||||||
import { ColorSliderModule } from 'ngx-color/slider'
|
import { ColorSliderModule } from 'ngx-color/slider'
|
||||||
import { ColorComponent } from './components/common/input/color/color.component'
|
import { ColorComponent } from './components/common/input/color/color.component'
|
||||||
import { DocumentAsnComponent } from './components/document-asn/document-asn.component'
|
import { DocumentAsnComponent } from './components/document-asn/document-asn.component'
|
||||||
|
import { DocumentCommentComponent } from './components/document-comment/document-comment.component';
|
||||||
import { DirtyDocGuard } from './guards/dirty-doc.guard'
|
import { DirtyDocGuard } from './guards/dirty-doc.guard'
|
||||||
|
|
||||||
import localeBe from '@angular/common/locales/be'
|
import localeBe from '@angular/common/locales/be'
|
||||||
@ -173,6 +174,7 @@ function initializeApp(settings: SettingsService) {
|
|||||||
DateComponent,
|
DateComponent,
|
||||||
ColorComponent,
|
ColorComponent,
|
||||||
DocumentAsnComponent,
|
DocumentAsnComponent,
|
||||||
|
DocumentCommentComponent,
|
||||||
TasksComponent,
|
TasksComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
<div *ngIf="comments">
|
||||||
|
<form [formGroup]='commentForm'>
|
||||||
|
<div class="form-group">
|
||||||
|
<textarea class="form-control" id="newcomment" rows="5" formControlName='newcomment'></textarea>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-primary" i18n [disabled]="networkActive" (click)="addComment()">add comment</button>
|
||||||
|
</form>
|
||||||
|
<hr>
|
||||||
|
<div *ngFor="let comment of comments; trackBy: byId" [disableRipple]="true" class="card border-bg-primary bg-primary mb-3 comment-card" [attr.comment-id]="comment.id">
|
||||||
|
<div class="d-flex card-header comment-card-header text-white justify-content-between">
|
||||||
|
<span>{{comment?.user?.firstname}} {{comment?.user?.lastname}} ({{comment?.user?.username}}) - {{ comment?.created | customDate}}</span>
|
||||||
|
<span>
|
||||||
|
<a class="text-white" (click)="deleteComment($event)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">
|
||||||
|
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
|
||||||
|
<path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4L4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body bg-white text-dark comment-card-body card-text">
|
||||||
|
{{comment.comment}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,22 @@
|
|||||||
|
.comment-card-body {
|
||||||
|
padding-top: .8rem !important;
|
||||||
|
padding-bottom: .8rem !important;
|
||||||
|
max-height: 10rem;
|
||||||
|
overflow: scroll;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-card-header a {
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-card-header a:hover {
|
||||||
|
background: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-card-header a:hover svg {
|
||||||
|
fill: var(--primary);
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { DocumentCommentComponent } from './document-comment.component';
|
||||||
|
|
||||||
|
describe('DocumentCommentComponent', () => {
|
||||||
|
let component: DocumentCommentComponent;
|
||||||
|
let fixture: ComponentFixture<DocumentCommentComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ DocumentCommentComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(DocumentCommentComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,63 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { DocumentDetailComponent } from 'src/app/components/document-detail/document-detail.component';
|
||||||
|
import { DocumentCommentService } from 'src/app/services/rest/document-comment.service';
|
||||||
|
import { PaperlessDocumentComment } from 'src/app/data/paperless-document-comment';
|
||||||
|
|
||||||
|
import { take } from 'rxjs/operators';
|
||||||
|
import { FormControl, FormGroup } from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-document-comment',
|
||||||
|
templateUrl: './document-comment.component.html',
|
||||||
|
styleUrls: ['./document-comment.component.scss']
|
||||||
|
})
|
||||||
|
export class DocumentCommentComponent implements OnInit {
|
||||||
|
|
||||||
|
comments:PaperlessDocumentComment[];
|
||||||
|
networkActive = false;
|
||||||
|
documentId: number;
|
||||||
|
commentForm: FormGroup = new FormGroup({
|
||||||
|
newcomment: new FormControl('')
|
||||||
|
})
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private documentDetailComponent: DocumentDetailComponent,
|
||||||
|
private documentCommentService: DocumentCommentService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
byId(index, item: PaperlessDocumentComment) {
|
||||||
|
return item.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
async ngOnInit(): Promise<any> {
|
||||||
|
try {
|
||||||
|
this.documentId = this.documentDetailComponent.documentId;
|
||||||
|
this.comments= await this.documentCommentService.getComments(this.documentId).pipe(take(1)).toPromise();
|
||||||
|
} catch(err){
|
||||||
|
this.comments = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addComment(){
|
||||||
|
this.networkActive = true
|
||||||
|
this.documentCommentService.addComment(this.documentId, this.commentForm.get("newcomment").value).subscribe(result => {
|
||||||
|
this.comments = result;
|
||||||
|
this.commentForm.get("newcomment").reset();
|
||||||
|
this.networkActive = false;
|
||||||
|
}, error => {
|
||||||
|
this.networkActive = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteComment(event){
|
||||||
|
let parent = event.target.parentElement.closest('div[comment-id]');
|
||||||
|
if(parent){
|
||||||
|
this.documentCommentService.deleteComment(this.documentId, parseInt(parent.getAttribute("comment-id"))).subscribe(result => {
|
||||||
|
this.comments = result;
|
||||||
|
this.networkActive = false;
|
||||||
|
}, error => {
|
||||||
|
this.networkActive = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -169,6 +169,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</li>
|
</li>
|
||||||
|
<li [ngbNavItem]="5" *ngIf="isCommentsEnabled">
|
||||||
|
<a ngbNavLink i18n>Comments</a>
|
||||||
|
<ng-template ngbNavContent>
|
||||||
|
<app-document-comment #commentComponent></app-document-comment>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||||
|
@ -35,6 +35,7 @@ import { StoragePathService } from 'src/app/services/rest/storage-path.service'
|
|||||||
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
|
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
|
||||||
import { StoragePathEditDialogComponent } from '../common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component'
|
import { StoragePathEditDialogComponent } from '../common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component'
|
||||||
import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
|
import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
|
||||||
|
import { EnvironmentService } from 'src/app/services/rest/environment.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-document-detail',
|
selector: 'app-document-detail',
|
||||||
@ -83,6 +84,8 @@ export class DocumentDetailComponent
|
|||||||
previewCurrentPage: number = 1
|
previewCurrentPage: number = 1
|
||||||
previewNumPages: number = 1
|
previewNumPages: number = 1
|
||||||
|
|
||||||
|
isCommentsEnabled:boolean = false
|
||||||
|
|
||||||
store: BehaviorSubject<any>
|
store: BehaviorSubject<any>
|
||||||
isDirty$: Observable<boolean>
|
isDirty$: Observable<boolean>
|
||||||
unsubscribeNotifier: Subject<any> = new Subject()
|
unsubscribeNotifier: Subject<any> = new Subject()
|
||||||
@ -118,7 +121,8 @@ export class DocumentDetailComponent
|
|||||||
private documentTitlePipe: DocumentTitlePipe,
|
private documentTitlePipe: DocumentTitlePipe,
|
||||||
private toastService: ToastService,
|
private toastService: ToastService,
|
||||||
private settings: SettingsService,
|
private settings: SettingsService,
|
||||||
private storagePathService: StoragePathService
|
private storagePathService: StoragePathService,
|
||||||
|
private environment: EnvironmentService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
titleKeyUp(event) {
|
titleKeyUp(event) {
|
||||||
@ -274,6 +278,13 @@ export class DocumentDetailComponent
|
|||||||
this.suggestions = null
|
this.suggestions = null
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.environment.get("PAPERLESS_COMMENTS_ENABLED").subscribe(result => {
|
||||||
|
this.isCommentsEnabled = (result.value.toString().toLowerCase() === "true"?true:false);
|
||||||
|
}, error => {
|
||||||
|
this.isCommentsEnabled = false;
|
||||||
|
})
|
||||||
|
|
||||||
this.title = this.documentTitlePipe.transform(doc.title)
|
this.title = this.documentTitlePipe.transform(doc.title)
|
||||||
this.documentForm.patchValue(doc)
|
this.documentForm.patchValue(doc)
|
||||||
}
|
}
|
||||||
|
8
src-ui/src/app/data/paperless-document-comment.ts
Normal file
8
src-ui/src/app/data/paperless-document-comment.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { ObjectWithId } from './object-with-id'
|
||||||
|
import { CommentUser } from './user-type'
|
||||||
|
|
||||||
|
export interface PaperlessDocumentComment extends ObjectWithId {
|
||||||
|
created?: Date
|
||||||
|
comment?: string
|
||||||
|
user?: CommentUser
|
||||||
|
}
|
3
src-ui/src/app/data/paperless-environment.ts
Normal file
3
src-ui/src/app/data/paperless-environment.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export interface PaperlessEnvironment {
|
||||||
|
value?: string;
|
||||||
|
}
|
7
src-ui/src/app/data/user-type.ts
Normal file
7
src-ui/src/app/data/user-type.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { ObjectWithId } from './object-with-id'
|
||||||
|
|
||||||
|
export interface CommentUser extends ObjectWithId {
|
||||||
|
username: string
|
||||||
|
firstname: string
|
||||||
|
lastname: string
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { DocumentCommentService } from './document-comment.service';
|
||||||
|
|
||||||
|
describe('DocumentCommentService', () => {
|
||||||
|
let service: DocumentCommentService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(DocumentCommentService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
31
src-ui/src/app/services/rest/document-comment.service.ts
Normal file
31
src-ui/src/app/services/rest/document-comment.service.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
|
import { PaperlessDocumentComment } from 'src/app/data/paperless-document-comment';
|
||||||
|
import { AbstractPaperlessService } from './abstract-paperless-service';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { PaperlessDocumentCommentFrame } from 'src/app/data/paperless-document-comment-frame';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class DocumentCommentService extends AbstractPaperlessService<PaperlessDocumentComment> {
|
||||||
|
|
||||||
|
constructor(http: HttpClient) {
|
||||||
|
super(http, 'documents')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getComments(id: number): Observable<PaperlessDocumentComment> {
|
||||||
|
return this.http.get<PaperlessDocumentComment[]>(this.getResourceUrl(id, "comments"))
|
||||||
|
}
|
||||||
|
|
||||||
|
addComment(id: number, comment): Observable<PaperlessDocumentComment[]>{
|
||||||
|
return this.http.post<PaperlessDocumentComment[]>(this.getResourceUrl(id, 'comments'), {"payload": comment})
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteComment(documentId: number, commentId: number): Observable<PaperlessDocumentComment[]>{
|
||||||
|
let httpParams = new HttpParams();
|
||||||
|
httpParams = httpParams.set("commentId", commentId.toString());
|
||||||
|
return this.http.delete<PaperlessDocumentComment[]>(this.getResourceUrl(documentId, 'comments'), {params: httpParams});
|
||||||
|
}
|
||||||
|
}
|
16
src-ui/src/app/services/rest/environment.service.spec.ts
Normal file
16
src-ui/src/app/services/rest/environment.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { EnvironmentService } from './environment.service';
|
||||||
|
|
||||||
|
describe('EnvironmentService', () => {
|
||||||
|
let service: EnvironmentService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(EnvironmentService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
22
src-ui/src/app/services/rest/environment.service.ts
Normal file
22
src-ui/src/app/services/rest/environment.service.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { PaperlessEnvironment } from 'src/app/data/paperless-environment';
|
||||||
|
import { environment } from 'src/environments/environment'
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class EnvironmentService {
|
||||||
|
|
||||||
|
protected baseUrl: string = environment.apiBaseUrl
|
||||||
|
|
||||||
|
constructor(protected http: HttpClient) { }
|
||||||
|
|
||||||
|
get(environment: string): Observable<PaperlessEnvironment> {
|
||||||
|
let httpParams = new HttpParams();
|
||||||
|
httpParams = httpParams.set('name', environment);
|
||||||
|
|
||||||
|
return this.http.get<PaperlessEnvironment>(`${this.baseUrl}environment/`, {params: httpParams})
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ from django.core import serializers
|
|||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django.core.management.base import CommandError
|
from django.core.management.base import CommandError
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
from documents.models import Comment
|
||||||
from documents.models import Correspondent
|
from documents.models import Correspondent
|
||||||
from documents.models import Document
|
from documents.models import Document
|
||||||
from documents.models import DocumentType
|
from documents.models import DocumentType
|
||||||
@ -126,6 +127,9 @@ class Command(BaseCommand):
|
|||||||
serializers.serialize("json", DocumentType.objects.all()),
|
serializers.serialize("json", DocumentType.objects.all()),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
manifest += json.loads(
|
||||||
|
serializers.serialize("json", Comment.objects.all())),
|
||||||
|
|
||||||
documents = Document.objects.order_by("id")
|
documents = Document.objects.order_by("id")
|
||||||
document_map = {d.pk: d for d in documents}
|
document_map = {d.pk: d for d in documents}
|
||||||
document_manifest = json.loads(serializers.serialize("json", documents))
|
document_manifest = json.loads(serializers.serialize("json", documents))
|
||||||
|
19
src/documents/migrations/1023_add_comments.py
Normal file
19
src/documents/migrations/1023_add_comments.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('documents', '1016_auto_20210317_1351'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Comment',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('comment', models.TextField()),
|
||||||
|
('created', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('document_id', models.PositiveIntegerField()),
|
||||||
|
('user_id', models.PositiveIntegerField())
|
||||||
|
],
|
||||||
|
)
|
||||||
|
]
|
@ -537,3 +537,40 @@ class PaperlessTask(models.Model):
|
|||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
acknowledged = models.BooleanField(default=False)
|
acknowledged = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
class Comment(models.Model):
|
||||||
|
comment = models.TextField(
|
||||||
|
_("content"),
|
||||||
|
blank=True,
|
||||||
|
help_text=_("Comment for the document")
|
||||||
|
)
|
||||||
|
|
||||||
|
created = models.DateTimeField(
|
||||||
|
_("created"),
|
||||||
|
default=timezone.now, db_index=True)
|
||||||
|
|
||||||
|
document = models.ForeignKey(
|
||||||
|
Document,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
related_name="documents",
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
verbose_name=_("document")
|
||||||
|
)
|
||||||
|
|
||||||
|
user = models.ForeignKey(
|
||||||
|
User,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
related_name="users",
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
verbose_name=_("user")
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ("created",)
|
||||||
|
verbose_name = _("comment")
|
||||||
|
verbose_name_plural = _("comments")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.content
|
@ -21,6 +21,8 @@ from django.db.models.functions import Lower
|
|||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.http import HttpResponseBadRequest
|
from django.http import HttpResponseBadRequest
|
||||||
|
from django.http import HttpResponseNotAllowed
|
||||||
|
from django.http import HttpResponseNotFound
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.translation import get_language
|
from django.utils.translation import get_language
|
||||||
from django.views.decorators.cache import cache_control
|
from django.views.decorators.cache import cache_control
|
||||||
@ -62,6 +64,7 @@ from .matching import match_correspondents
|
|||||||
from .matching import match_document_types
|
from .matching import match_document_types
|
||||||
from .matching import match_storage_paths
|
from .matching import match_storage_paths
|
||||||
from .matching import match_tags
|
from .matching import match_tags
|
||||||
|
from .models import Comment
|
||||||
from .models import Correspondent
|
from .models import Correspondent
|
||||||
from .models import Document
|
from .models import Document
|
||||||
from .models import DocumentType
|
from .models import DocumentType
|
||||||
@ -379,6 +382,61 @@ class DocumentViewSet(
|
|||||||
except (FileNotFoundError, Document.DoesNotExist):
|
except (FileNotFoundError, Document.DoesNotExist):
|
||||||
raise Http404()
|
raise Http404()
|
||||||
|
|
||||||
|
def getComments(self, doc):
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id":c.id,
|
||||||
|
"comment":c.comment,
|
||||||
|
"created":c.created,
|
||||||
|
"user":{
|
||||||
|
"id":c.user.id,
|
||||||
|
"username": c.user.username,
|
||||||
|
"firstname":c.user.first_name,
|
||||||
|
"lastname":c.user.last_name
|
||||||
|
}
|
||||||
|
} for c in Comment.objects.filter(document=doc).order_by('-created')
|
||||||
|
];
|
||||||
|
|
||||||
|
@action(methods=['get', 'post', 'delete'], detail=True)
|
||||||
|
def comments(self, request, pk=None):
|
||||||
|
if settings.PAPERLESS_COMMENTS_ENABLED != True:
|
||||||
|
return HttpResponseNotAllowed("comment function is disabled")
|
||||||
|
|
||||||
|
try:
|
||||||
|
doc = Document.objects.get(pk=pk)
|
||||||
|
except Document.DoesNotExist:
|
||||||
|
raise Http404()
|
||||||
|
|
||||||
|
currentUser = request.user;
|
||||||
|
|
||||||
|
if request.method == 'GET':
|
||||||
|
try:
|
||||||
|
return Response(self.getComments(doc));
|
||||||
|
except Exception as e:
|
||||||
|
return Response({"error": str(e)});
|
||||||
|
elif request.method == 'POST':
|
||||||
|
try:
|
||||||
|
c = Comment.objects.create(
|
||||||
|
document = doc,
|
||||||
|
comment=request.data["payload"],
|
||||||
|
user=currentUser
|
||||||
|
);
|
||||||
|
c.save();
|
||||||
|
|
||||||
|
return Response(self.getComments(doc));
|
||||||
|
except Exception as e:
|
||||||
|
return Response({
|
||||||
|
"error": str(e)
|
||||||
|
});
|
||||||
|
elif request.method == 'DELETE':
|
||||||
|
comment = Comment.objects.get(id=int(request.GET.get("commentId")));
|
||||||
|
comment.delete();
|
||||||
|
return Response(self.getComments(doc));
|
||||||
|
|
||||||
|
return Response({
|
||||||
|
"error": "error"
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
class SearchResultSerializer(DocumentSerializer):
|
class SearchResultSerializer(DocumentSerializer):
|
||||||
def to_representation(self, instance):
|
def to_representation(self, instance):
|
||||||
@ -835,3 +893,32 @@ class AcknowledgeTasksView(GenericAPIView):
|
|||||||
return Response({"result": result})
|
return Response({"result": result})
|
||||||
except Exception:
|
except Exception:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
class EnvironmentView(APIView):
|
||||||
|
|
||||||
|
permission_classes = (IsAuthenticated,)
|
||||||
|
|
||||||
|
def get(self, request, format=None):
|
||||||
|
if 'name' in request.query_params:
|
||||||
|
name = request.query_params['name']
|
||||||
|
else:
|
||||||
|
return HttpResponseBadRequest("name required")
|
||||||
|
|
||||||
|
if(name not in settings.PAPERLESS_FRONTEND_ALLOWED_ENVIRONMENTS and settings.PAPERLESS_DISABLED_FRONTEND_ENVIRONMENT_CHECK == False):
|
||||||
|
return HttpResponseNotAllowed("environment not allowed to request")
|
||||||
|
|
||||||
|
value = None
|
||||||
|
try:
|
||||||
|
value = getattr(settings, name)
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
value = os.getenv(name)
|
||||||
|
except:
|
||||||
|
value = None
|
||||||
|
|
||||||
|
if value == None:
|
||||||
|
return HttpResponseNotFound("environment not found")
|
||||||
|
|
||||||
|
return Response({
|
||||||
|
"value": str(value)
|
||||||
|
});
|
||||||
|
@ -566,6 +566,14 @@ CONVERT_MEMORY_LIMIT = os.getenv("PAPERLESS_CONVERT_MEMORY_LIMIT")
|
|||||||
|
|
||||||
GS_BINARY = os.getenv("PAPERLESS_GS_BINARY", "gs")
|
GS_BINARY = os.getenv("PAPERLESS_GS_BINARY", "gs")
|
||||||
|
|
||||||
|
# Comment settings
|
||||||
|
PAPERLESS_COMMENTS_ENABLED = __get_boolean("PAPERLESS_COMMENTS_ENABLED", "NO")
|
||||||
|
|
||||||
|
# allowed environments for frontend
|
||||||
|
PAPERLESS_DISABLED_FRONTEND_ENVIRONMENT_CHECK = __get_boolean("PAPERLESS_DISABLED_FRONTEND_ENVIRONMENT_CHECK", "NO")
|
||||||
|
PAPERLESS_FRONTEND_ALLOWED_ENVIRONMENTS = [
|
||||||
|
"PAPERLESS_COMMENTS_ENABLED"
|
||||||
|
]
|
||||||
|
|
||||||
# Pre-2.x versions of Paperless stored your documents locally with GPG
|
# Pre-2.x versions of Paperless stored your documents locally with GPG
|
||||||
# encryption, but that is no longer the default. This behaviour is still
|
# encryption, but that is no longer the default. This behaviour is still
|
||||||
|
@ -8,6 +8,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
from documents.views import AcknowledgeTasksView
|
from documents.views import AcknowledgeTasksView
|
||||||
|
from documents.views import EnvironmentView
|
||||||
from documents.views import BulkDownloadView
|
from documents.views import BulkDownloadView
|
||||||
from documents.views import BulkEditView
|
from documents.views import BulkEditView
|
||||||
from documents.views import CorrespondentViewSet
|
from documents.views import CorrespondentViewSet
|
||||||
@ -94,6 +95,7 @@ urlpatterns = [
|
|||||||
AcknowledgeTasksView.as_view(),
|
AcknowledgeTasksView.as_view(),
|
||||||
name="acknowledge_tasks",
|
name="acknowledge_tasks",
|
||||||
),
|
),
|
||||||
|
re_path(r"^environment/", EnvironmentView.as_view()),
|
||||||
path("token/", views.obtain_auth_token),
|
path("token/", views.obtain_auth_token),
|
||||||
]
|
]
|
||||||
+ api_router.urls,
|
+ api_router.urls,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user