]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Rename comments --> notes 2904/head
authorshamoon <4887959+shamoon@users.noreply.github.com>
Fri, 17 Mar 2023 23:36:08 +0000 (16:36 -0700)
committershamoon <4887959+shamoon@users.noreply.github.com>
Sat, 18 Mar 2023 20:59:17 +0000 (13:59 -0700)
45 files changed:
docker/docker-prepare.sh
src-ui/cypress/e2e/documents/document-detail.cy.ts
src-ui/cypress/fixtures/documents/1/comments.json [deleted file]
src-ui/cypress/fixtures/documents/1/notes.json [new file with mode: 0644]
src-ui/cypress/fixtures/documents/documents.json
src-ui/cypress/fixtures/groups/groups.json
src-ui/cypress/fixtures/ui_settings/settings.json
src-ui/cypress/fixtures/ui_settings/settings_restricted.json
src-ui/cypress/fixtures/users/users.json
src-ui/messages.xlf
src-ui/src/app/app.module.ts
src-ui/src/app/components/document-comments/document-comments.component.ts [deleted file]
src-ui/src/app/components/document-detail/document-detail.component.html
src-ui/src/app/components/document-detail/document-detail.component.ts
src-ui/src/app/components/document-list/document-card-large/document-card-large.component.html
src-ui/src/app/components/document-list/document-card-large/document-card-large.component.ts
src-ui/src/app/components/document-list/document-card-small/document-card-small.component.html
src-ui/src/app/components/document-list/document-card-small/document-card-small.component.scss
src-ui/src/app/components/document-list/document-card-small/document-card-small.component.ts
src-ui/src/app/components/document-list/document-list.component.html
src-ui/src/app/components/document-list/document-list.component.ts
src-ui/src/app/components/document-notes/document-notes.component.html [moved from src-ui/src/app/components/document-comments/document-comments.component.html with 50% similarity]
src-ui/src/app/components/document-notes/document-notes.component.scss [moved from src-ui/src/app/components/document-comments/document-comments.component.scss with 100% similarity]
src-ui/src/app/components/document-notes/document-notes.component.ts [new file with mode: 0644]
src-ui/src/app/components/manage/settings/settings.component.html
src-ui/src/app/components/manage/settings/settings.component.ts
src-ui/src/app/data/paperless-document-comment.ts [deleted file]
src-ui/src/app/data/paperless-document-note.ts [new file with mode: 0644]
src-ui/src/app/data/paperless-document.ts
src-ui/src/app/data/paperless-uisettings.ts
src-ui/src/app/services/permissions.service.ts
src-ui/src/app/services/rest/document-comments.service.ts [deleted file]
src-ui/src/app/services/rest/document-notes.service.ts [new file with mode: 0644]
src-ui/src/app/services/rest/document.service.ts
src-ui/src/theme.scss
src/documents/admin.py
src/documents/index.py
src/documents/management/commands/document_exporter.py
src/documents/migrations/1034_alter_comment_document_alter_comment_user.py [deleted file]
src/documents/migrations/1035_rename_comment_note.py [new file with mode: 0644]
src/documents/models.py
src/documents/serialisers.py
src/documents/tests/test_api.py
src/documents/tests/test_management_exporter.py
src/documents/views.py

index b088cef4055111f013fec195281947454e4a21a4..d6eab42815c3eec5a00b11f479f9b2730f491581 100755 (executable)
@@ -80,7 +80,7 @@ django_checks() {
 
 search_index() {
 
-       local -r index_version=3
+       local -r index_version=4
        local -r index_version_file=${DATA_DIR}/.index_version
 
        if [[ (! -f "${index_version_file}") || $(<"${index_version_file}") != "$index_version" ]]; then
index 8f6d8bde971a0c1c7878c1f5cd6097f1d0da53f4..dd5f8fac851b19ab602327c5c1a0b02cfbc490e9 100644 (file)
@@ -17,28 +17,28 @@ describe('document-detail', () => {
       req.reply({ result: 'OK' })
     }).as('saveDoc')
 
-    cy.fixture('documents/1/comments.json').then((commentsJson) => {
+    cy.fixture('documents/1/notes.json').then((notesJson) => {
       cy.intercept(
         'GET',
-        'http://localhost:8000/api/documents/1/comments/',
+        'http://localhost:8000/api/documents/1/notes/',
         (req) => {
-          req.reply(commentsJson.filter((c) => c.id != 10)) // 3
+          req.reply(notesJson.filter((c) => c.id != 10)) // 3
         }
       )
 
       cy.intercept(
         'DELETE',
-        'http://localhost:8000/api/documents/1/comments/?id=9',
+        'http://localhost:8000/api/documents/1/notes/?id=9',
         (req) => {
-          req.reply(commentsJson.filter((c) => c.id != 9 && c.id != 10)) // 2
+          req.reply(notesJson.filter((c) => c.id != 9 && c.id != 10)) // 2
         }
       )
 
       cy.intercept(
         'POST',
-        'http://localhost:8000/api/documents/1/comments/',
+        'http://localhost:8000/api/documents/1/notes/',
         (req) => {
-          req.reply(commentsJson) // 4
+          req.reply(notesJson) // 4
         }
       )
     })
@@ -75,48 +75,40 @@ describe('document-detail', () => {
     cy.get('pdf-viewer').should('be.visible')
   })
 
-  it('should show a list of comments', () => {
-    cy.wait(1000)
-      .get('a')
-      .contains('Comments')
-      .click({ force: true })
-      .wait(1000)
-    cy.get('app-document-comments').find('.card').its('length').should('eq', 3)
+  it('should show a list of notes', () => {
+    cy.wait(1000).get('a').contains('Notes').click({ force: true }).wait(1000)
+    cy.get('app-document-notes').find('.card').its('length').should('eq', 3)
   })
 
-  it('should support comment deletion', () => {
-    cy.wait(1000).get('a').contains('Comments').click().wait(1000)
-    cy.get('app-document-comments')
+  it('should support note deletion', () => {
+    cy.wait(1000).get('a').contains('Notes').click().wait(1000)
+    cy.get('app-document-notes')
       .find('.card')
       .first()
       .find('button')
       .click({ force: true })
       .wait(500)
-    cy.get('app-document-comments').find('.card').its('length').should('eq', 2)
+    cy.get('app-document-notes').find('.card').its('length').should('eq', 2)
   })
 
-  it('should support comment insertion', () => {
-    cy.wait(1000).get('a').contains('Comments').click().wait(1000)
-    cy.get('app-document-comments')
+  it('should support note insertion', () => {
+    cy.wait(1000).get('a').contains('Notes').click().wait(1000)
+    cy.get('app-document-notes')
       .find('form textarea')
-      .type('Testing new comment')
+      .type('Testing new note')
       .wait(500)
-    cy.get('app-document-comments').find('form button').click().wait(1500)
-    cy.get('app-document-comments').find('.card').its('length').should('eq', 4)
+    cy.get('app-document-notes').find('form button').click().wait(1500)
+    cy.get('app-document-notes').find('.card').its('length').should('eq', 4)
   })
 
-  it('should support navigation to comments tab by url', () => {
-    cy.visit('/documents/1/comments')
-    cy.get('app-document-comments').should('exist')
+  it('should support navigation to notes tab by url', () => {
+    cy.visit('/documents/1/notes')
+    cy.get('app-document-notes').should('exist')
   })
 
-  it('should dynamically update comment counts', () => {
-    cy.visit('/documents/1/comments')
-    cy.get('app-document-comments').within(() => cy.contains('Delete').click())
-    cy.get('ul.nav')
-      .find('li')
-      .contains('Comments')
-      .find('.badge')
-      .contains('2')
+  it('should dynamically update note counts', () => {
+    cy.visit('/documents/1/notes')
+    cy.get('app-document-notes').within(() => cy.contains('Delete').click())
+    cy.get('ul.nav').find('li').contains('Notes').find('.badge').contains('2')
   })
 })
diff --git a/src-ui/cypress/fixtures/documents/1/comments.json b/src-ui/cypress/fixtures/documents/1/comments.json
deleted file mode 100644 (file)
index a6013b5..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-[
-    {
-        "id": 10,
-        "comment": "Testing new comment",
-        "created": "2022-08-08T04:24:55.176008Z",
-        "user": {
-            "id": 1,
-            "username": "user2",
-            "first_name": "",
-            "last_name": ""
-        }
-    },
-    {
-        "id": 9,
-        "comment": "Testing one more time",
-        "created": "2022-02-18T04:24:55.176008Z",
-        "user": {
-            "id": 2,
-            "username": "user1",
-            "first_name": "",
-            "last_name": ""
-        }
-    },
-    {
-        "id": 8,
-        "comment": "Another comment",
-        "created": "2021-11-08T04:24:47.925042Z",
-        "user": {
-            "id": 2,
-            "username": "user33",
-            "first_name": "",
-            "last_name": ""
-        }
-    },
-    {
-        "id": 7,
-        "comment": "Cupcake ipsum dolor sit amet cheesecake candy cookie tiramisu. Donut chocolate chupa chups macaroon brownie halvah pie cheesecake gummies. Sweet chocolate bar candy donut gummi bears bear claw liquorice bonbon shortbread.\n\nDonut chocolate bar candy wafer wafer tiramisu. Gummies chocolate cake muffin toffee carrot cake macaroon. Toffee toffee jelly beans danish lollipop cake.",
-        "created": "2021-02-08T02:37:49.724132Z",
-        "user": {
-            "id": 3,
-            "username": "admin",
-            "first_name": "",
-            "last_name": ""
-        }
-    }
-]
diff --git a/src-ui/cypress/fixtures/documents/1/notes.json b/src-ui/cypress/fixtures/documents/1/notes.json
new file mode 100644 (file)
index 0000000..97c8e5a
--- /dev/null
@@ -0,0 +1,26 @@
+[
+    {
+        "id": 10,
+        "note": "Testing new note",
+        "created": "2022-08-08T04:24:55.176008Z",
+        "user": 3
+    },
+    {
+        "id": 9,
+        "note": "Testing one more time",
+        "created": "2022-02-18T04:24:55.176008Z",
+        "user": 15
+    },
+    {
+        "id": 8,
+        "note": "Another note",
+        "created": "2021-11-08T04:24:47.925042Z",
+        "user": 3
+    },
+    {
+        "id": 7,
+        "note": "Cupcake ipsum dolor sit amet cheesecake candy cookie tiramisu. Donut chocolate chupa chups macaroon brownie halvah pie cheesecake gummies. Sweet chocolate bar candy donut gummi bears bear claw liquorice bonbon shortbread.\n\nDonut chocolate bar candy wafer wafer tiramisu. Gummies chocolate cake muffin toffee carrot cake macaroon. Toffee toffee jelly beans danish lollipop cake.",
+        "created": "2021-02-08T02:37:49.724132Z",
+        "user": 3
+    }
+]
index b67cfa4df774ed66e917ea6e43ebf90117f5f5e5..be7640c8f3538e4b27fa44a345006b5d21fbc8a5 100644 (file)
             "archived_file_name": "2022-03-22 no latin title.pdf",
             "owner": null,
             "permissions": [],
-            "comments": [
+            "notes": [
                 {
-                    "id": 30,
-                    "comment": "One more time",
-                    "created": "2023-03-17T22:02:14.357575Z",
-                    "user": {
-                        "id": 2,
-                        "username": "username",
-                        "first_name": "",
-                        "last_name": ""
-                    }
+                    "id": 9,
+                    "note": "Testing one more time",
+                    "created": "2022-02-18T04:24:55.176008Z",
+                    "user": 15
                 },
                 {
-                    "id": 6,
-                    "comment": "Lets keep going",
-                    "created": "2023-03-16T06:57:32.014027Z",
-                    "user": {
-                        "id": 2,
-                        "username": "username",
-                        "first_name": "",
-                        "last_name": ""
-                    }
+                    "id": 8,
+                    "note": "Another note",
+                    "created": "2021-11-08T04:24:47.925042Z",
+                    "user": 3
                 },
                 {
-                    "id": 5,
-                    "comment": "And just one more",
-                    "created": "2023-03-16T06:57:27.022729Z",
-                    "user": {
-                        "id": 2,
-                        "username": "username",
-                        "first_name": "",
-                        "last_name": ""
-                    }
+                    "id": 7,
+                    "note": "Cupcake ipsum dolor sit amet cheesecake candy cookie tiramisu. Donut chocolate chupa chups macaroon brownie halvah pie cheesecake gummies. Sweet chocolate bar candy donut gummi bears bear claw liquorice bonbon shortbread.\n\nDonut chocolate bar candy wafer wafer tiramisu. Gummies chocolate cake muffin toffee carrot cake macaroon. Toffee toffee jelly beans danish lollipop cake.",
+                    "created": "2021-02-08T02:37:49.724132Z",
+                    "user": 3
                 }
             ]
         },
@@ -75,7 +60,7 @@
             "archived_file_name": "2022-03-23 llorem ipsum dolor sit amet.pdf",
             "owner": null,
             "permissions": [],
-            "comments": []
+            "notes": []
         },
         {
             "id": 3,
@@ -96,7 +81,7 @@
             "archived_file_name": "2022-03-24 dolor.pdf",
             "owner": null,
             "permissions": [],
-            "comments": []
+            "notes": []
         },
         {
             "id": 4,
             "archived_file_name": "2022-06-01 sit amet.pdf",
             "owner": null,
             "permissions": [],
-            "comments": []
+            "notes": []
         }
     ]
 }
index 0bf2655d91b412139e15a409feb985c408890d7a..f6051be90a3fef00060a2df9f925da1d99fefe2b 100644 (file)
                 "change_user",
                 "delete_user",
                 "view_user",
-                "add_comment",
-                "change_comment",
-                "delete_comment",
-                "view_comment"
+                "add_note",
+                "change_note",
+                "delete_note",
+                "view_note"
             ]
         },
         {
                 "change_task",
                 "delete_task",
                 "view_task",
-                "add_comment",
-                "change_comment",
-                "delete_comment",
-                "view_comment",
+                "add_note",
+                "change_note",
+                "delete_note",
+                "view_note",
                 "add_correspondent",
                 "change_correspondent",
                 "delete_correspondent",
index f552054df4d66704b5bb1711f715a0377b52d902..3183943fe61f7a6624777ed213dcb677f89e22cb 100644 (file)
         "change_task",
         "delete_task",
         "view_task",
-        "add_comment",
-        "change_comment",
-        "delete_comment",
-        "view_comment",
+        "add_note",
+        "change_note",
+        "delete_note",
+        "view_note",
         "add_correspondent",
         "change_correspondent",
         "delete_correspondent",
index 921d4274d6ee787a1da7c825020a12a0deca9583..72ebe51b1a108b2e16908c18e371cd4d348bc61d 100644 (file)
@@ -74,7 +74,7 @@
         "change_task",
         "delete_task",
         "view_task",
-        "add_comment",
+        "add_note",
         "add_frontendsettings",
         "change_frontendsettings",
         "delete_frontendsettings",
index ca477667a39e4a80665515ff87ecd5d389e2b5ea..a69a86b92cba4dc56953927ce8e5e7c5ae0c80c8 100644 (file)
@@ -30,7 +30,7 @@
                 "django_celery_results.delete_taskresult",
                 "paperless_mail.add_mailaccount",
                 "auth.change_group",
-                "documents.add_comment",
+                "documents.add_note",
                 "paperless_mail.delete_mailaccount",
                 "authtoken.delete_tokenproxy",
                 "guardian.delete_groupobjectpermission",
@@ -44,7 +44,7 @@
                 "documents.add_documenttype",
                 "django_q.change_success",
                 "documents.delete_tag",
-                "documents.change_comment",
+                "documents.change_note",
                 "django_q.delete_task",
                 "documents.add_savedviewfilterrule",
                 "django_q.view_task",
@@ -59,7 +59,7 @@
                 "documents.add_savedview",
                 "auth.delete_user",
                 "documents.view_log",
-                "documents.view_comment",
+                "documents.view_note",
                 "guardian.change_groupobjectpermission",
                 "sessions.delete_session",
                 "django_q.change_failure",
                 "django_celery_results.view_taskresult",
                 "contenttypes.add_contenttype",
                 "django_q.delete_success",
-                "documents.delete_comment",
+                "documents.delete_note",
                 "django_q.add_failure",
                 "guardian.add_userobjectpermission",
                 "sessions.view_session",
                 "change_task",
                 "delete_task",
                 "view_task",
-                "add_comment",
-                "change_comment",
-                "delete_comment",
-                "view_comment",
+                "add_note",
+                "change_note",
+                "delete_note",
+                "view_note",
                 "add_frontendsettings",
                 "change_frontendsettings",
                 "delete_frontendsettings",
                 "django_celery_results.delete_taskresult",
                 "authtoken.change_token",
                 "auth.change_group",
-                "documents.add_comment",
+                "documents.add_note",
                 "authtoken.delete_tokenproxy",
                 "documents.view_documenttype",
                 "contenttypes.delete_contenttype",
                 "django_q.change_task",
                 "sessions.add_session",
                 "documents.change_taskattributes",
-                "documents.change_comment",
+                "documents.change_note",
                 "django_q.delete_task",
                 "django_q.delete_ormq",
                 "auth.change_permission",
                 "documents.view_document",
                 "documents.add_savedview",
                 "django_q.view_failure",
-                "documents.view_comment",
+                "documents.view_note",
                 "documents.view_log",
                 "documents.add_log",
                 "documents.change_savedview",
                 "django_celery_results.view_taskresult",
                 "contenttypes.add_contenttype",
                 "django_q.delete_success",
-                "documents.delete_comment",
+                "documents.delete_note",
                 "django_q.add_failure",
                 "sessions.view_session",
                 "contenttypes.view_contenttype",
                 "django_celery_results.delete_taskresult",
                 "authtoken.change_token",
                 "auth.change_group",
-                "documents.add_comment",
+                "documents.add_note",
                 "authtoken.delete_tokenproxy",
                 "documents.view_documenttype",
                 "contenttypes.delete_contenttype",
                 "django_q.change_task",
                 "sessions.add_session",
                 "documents.change_taskattributes",
-                "documents.change_comment",
+                "documents.change_note",
                 "django_q.delete_task",
                 "django_q.delete_ormq",
                 "auth.change_permission",
                 "documents.view_document",
                 "documents.add_savedview",
                 "django_q.view_failure",
-                "documents.view_comment",
+                "documents.view_note",
                 "documents.view_log",
                 "auth.delete_user",
                 "documents.add_log",
                 "django_celery_results.view_taskresult",
                 "contenttypes.add_contenttype",
                 "django_q.delete_success",
-                "documents.delete_comment",
+                "documents.delete_note",
                 "django_q.add_failure",
                 "sessions.view_session",
                 "contenttypes.view_contenttype",
index c10758158d178ab2789a803e0c9a113a9f60a228..ce470a9a43a86af136b6a3359878d2545787687b 100644 (file)
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.ts</context>
-          <context context-type="linenumber">94</context>
+          <context context-type="linenumber">97</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
         <source>Not assigned</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts</context>
-          <context context-type="linenumber">321</context>
+          <context context-type="linenumber">335</context>
         </context-group>
         <note priority="1" from="description">Filter drop down element to filter for documents with no correspondent/type/tag assigned</note>
       </trans-unit>
           <context context-type="linenumber">1</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="2122666445936087317" datatype="html">
-        <source>Enter comment</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-comments/document-comments.component.html</context>
-          <context context-type="linenumber">4</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="4025397324401332794" datatype="html">
-        <source> Please enter a comment. </source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-comments/document-comments.component.html</context>
-          <context context-type="linenumber">5,7</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="2337485514607640701" datatype="html">
-        <source>Add comment</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-comments/document-comments.component.html</context>
-          <context context-type="linenumber">11</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="7978668497183230348" datatype="html">
-        <source>Delete comment</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-comments/document-comments.component.html</context>
-          <context context-type="linenumber">21</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-comments/document-comments.component.html</context>
-          <context context-type="linenumber">25</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="5438997040668245251" datatype="html">
-        <source>Error saving comment: <x id="PH" equiv-text="e.toString()"/></source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-comments/document-comments.component.ts</context>
-          <context context-type="linenumber">59</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="7593210124183303626" datatype="html">
-        <source>Error deleting comment: <x id="PH" equiv-text="e.toString()"/></source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/document-comments/document-comments.component.ts</context>
-          <context context-type="linenumber">75</context>
-        </context-group>
-      </trans-unit>
       <trans-unit id="1407560924967345762" datatype="html">
         <source>Page</source>
         <context-group purpose="location">
           <context context-type="linenumber">215</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="8403302283555274795" datatype="html">
-        <source>Comments <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span *ngIf=&quot;document?.comments.length&quot; class=&quot;badge text-bg-secondary ms-1&quot;&gt;"/><x id="INTERPOLATION" equiv-text=".length}}"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/a&gt;"/></source>
+      <trans-unit id="8460995830263484763" datatype="html">
+        <source>Notes <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span *ngIf=&quot;document?.notes.length&quot; class=&quot;badge text-bg-secondary ms-1&quot;&gt;"/><x id="INTERPOLATION" equiv-text="ngth}}"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/a&gt;"/></source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
           <context context-type="linenumber">175,176</context>
           <context context-type="linenumber">191</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="3758078190163790058" datatype="html">
-        <source>View comments</source>
+      <trans-unit id="106713086593101376" datatype="html">
+        <source>View notes</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-card-large/document-card-large.component.html</context>
           <context context-type="linenumber">70</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="6326693689225506833" datatype="html">
-        <source><x id="INTERPOLATION" equiv-text="omments.length}}"/> Comments</source>
+      <trans-unit id="8778002102373462277" datatype="html">
+        <source><x id="INTERPOLATION" equiv-text="otes.length}}"/> Notes</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-card-large/document-card-large.component.html</context>
           <context context-type="linenumber">74</context>
           <context context-type="linenumber">18</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="3807699453257291879" datatype="html">
-        <source>Comments</source>
+      <trans-unit id="8104421162933956065" datatype="html">
+        <source>Notes</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
           <context context-type="linenumber">147</context>
           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
           <context context-type="linenumber">159</context>
         </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
+          <context context-type="linenumber">25</context>
+        </context-group>
       </trans-unit>
       <trans-unit id="231679111972850796" datatype="html">
         <source>Added</source>
         <source>View &quot;<x id="PH" equiv-text="this.list.activeSavedViewTitle"/>&quot; saved successfully.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.ts</context>
-          <context context-type="linenumber">202</context>
+          <context context-type="linenumber">205</context>
         </context-group>
       </trans-unit>
       <trans-unit id="6837554170707123455" datatype="html">
         <source>View &quot;<x id="PH" equiv-text="savedView.name"/>&quot; created successfully.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-list/document-list.component.ts</context>
-          <context context-type="linenumber">243</context>
+          <context context-type="linenumber">246</context>
         </context-group>
       </trans-unit>
       <trans-unit id="6849725902312323996" datatype="html">
           <context context-type="linenumber">13</context>
         </context-group>
       </trans-unit>
+      <trans-unit id="1044349881182559852" datatype="html">
+        <source>Enter note</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-notes/document-notes.component.html</context>
+          <context context-type="linenumber">4</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="7770536883443596194" datatype="html">
+        <source> Please enter a note. </source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-notes/document-notes.component.html</context>
+          <context context-type="linenumber">5,7</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="8433732438274024544" datatype="html">
+        <source>Add note</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-notes/document-notes.component.html</context>
+          <context context-type="linenumber">11</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="8428006099054244235" datatype="html">
+        <source>Delete note</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-notes/document-notes.component.html</context>
+          <context context-type="linenumber">21</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-notes/document-notes.component.html</context>
+          <context context-type="linenumber">25</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="207390237682956115" datatype="html">
+        <source>Error saving note: <x id="PH" equiv-text="e.toString()"/></source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-notes/document-notes.component.ts</context>
+          <context context-type="linenumber">65</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="5682285129543775369" datatype="html">
+        <source>Error deleting note: <x id="PH" equiv-text="e.toString()"/></source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/document-notes/document-notes.component.ts</context>
+          <context context-type="linenumber">81</context>
+        </context-group>
+      </trans-unit>
       <trans-unit id="6316128875819022658" datatype="html">
         <source>correspondent</source>
         <context-group purpose="location">
           <context context-type="linenumber">155</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="4666858503087488647" datatype="html">
-        <source>Enable comments</source>
+      <trans-unit id="293524471897878391" datatype="html">
+        <source>Enable notes</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
           <context context-type="linenumber">163</context>
         <source>Search score</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
-          <context context-type="linenumber">31</context>
+          <context context-type="linenumber">32</context>
         </context-group>
         <note priority="1" from="description">Score is a value returned by the full text search engine and specifies how well a result matches the given query</note>
       </trans-unit>
index beb3b0935970576522eeaa28452ae61ec0a9e3d1..446f63254e934b42db6904599a02267b03107b0a 100644 (file)
@@ -70,7 +70,7 @@ import { ApiVersionInterceptor } from './interceptors/api-version.interceptor'
 import { ColorSliderModule } from 'ngx-color/slider'
 import { ColorComponent } from './components/common/input/color/color.component'
 import { DocumentAsnComponent } from './components/document-asn/document-asn.component'
-import { DocumentCommentsComponent } from './components/document-comments/document-comments.component'
+import { DocumentNotesComponent } from './components/document-notes/document-notes.component'
 import { PermissionsGuard } from './guards/permissions.guard'
 import { DirtyDocGuard } from './guards/dirty-doc.guard'
 import { DirtySavedViewGuard } from './guards/dirty-saved-view.guard'
@@ -196,7 +196,7 @@ function initializeApp(settings: SettingsService) {
     DateComponent,
     ColorComponent,
     DocumentAsnComponent,
-    DocumentCommentsComponent,
+    DocumentNotesComponent,
     TasksComponent,
     UserEditDialogComponent,
     GroupEditDialogComponent,
diff --git a/src-ui/src/app/components/document-comments/document-comments.component.ts b/src-ui/src/app/components/document-comments/document-comments.component.ts
deleted file mode 100644 (file)
index 405ddd2..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-import { Component, Input, Output, EventEmitter } from '@angular/core'
-import { DocumentCommentsService } from 'src/app/services/rest/document-comments.service'
-import { PaperlessDocumentComment } from 'src/app/data/paperless-document-comment'
-import { FormControl, FormGroup } from '@angular/forms'
-import { first } from 'rxjs/operators'
-import { ToastService } from 'src/app/services/toast.service'
-import { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
-
-@Component({
-  selector: 'app-document-comments',
-  templateUrl: './document-comments.component.html',
-  styleUrls: ['./document-comments.component.scss'],
-})
-export class DocumentCommentsComponent extends ComponentWithPermissions {
-  commentForm: FormGroup = new FormGroup({
-    newComment: new FormControl(''),
-  })
-
-  networkActive = false
-  newCommentError: boolean = false
-
-  @Input()
-  documentId: number
-
-  @Input()
-  comments: PaperlessDocumentComment[] = []
-
-  @Output()
-  updated: EventEmitter<PaperlessDocumentComment[]> = new EventEmitter()
-
-  constructor(
-    private commentsService: DocumentCommentsService,
-    private toastService: ToastService
-  ) {
-    super()
-  }
-
-  addComment() {
-    const comment: string = this.commentForm
-      .get('newComment')
-      .value.toString()
-      .trim()
-    if (comment.length == 0) {
-      this.newCommentError = true
-      return
-    }
-    this.newCommentError = false
-    this.networkActive = true
-    this.commentsService.addComment(this.documentId, comment).subscribe({
-      next: (result) => {
-        this.comments = result
-        this.commentForm.get('newComment').reset()
-        this.networkActive = false
-        this.updated.emit(this.comments)
-      },
-      error: (e) => {
-        this.networkActive = false
-        this.toastService.showError(
-          $localize`Error saving comment: ${e.toString()}`
-        )
-      },
-    })
-  }
-
-  deleteComment(commentId: number) {
-    this.commentsService.deleteComment(this.documentId, commentId).subscribe({
-      next: (result) => {
-        this.comments = result
-        this.networkActive = false
-        this.updated.emit(this.comments)
-      },
-      error: (e) => {
-        this.networkActive = false
-        this.toastService.showError(
-          $localize`Error deleting comment: ${e.toString()}`
-        )
-      },
-    })
-  }
-
-  displayName(comment: PaperlessDocumentComment): string {
-    if (!comment.user) return ''
-    let nameComponents = []
-    if (comment.user.first_name) nameComponents.unshift(comment.user.first_name)
-    if (comment.user.last_name) nameComponents.unshift(comment.user.last_name)
-    if (comment.user.username) {
-      if (nameComponents.length > 0)
-        nameComponents.push(`(${comment.user.username})`)
-      else nameComponents.push(comment.user.username)
-    }
-    return nameComponents.join(' ')
-  }
-
-  commentFormKeydown(event: KeyboardEvent) {
-    if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {
-      this.addComment()
-    }
-  }
-}
index ee1c1591388b3f80fb55da1d947afd5e534a6ecd..3cd4c9a17e39b9399f6b74c9a782aaaa0ffc353d 100644 (file)
                     </ng-template>
                 </li>
 
-                <li [ngbNavItem]="DocumentDetailNavIDs.Comments" *ngIf="commentsEnabled">
-                    <a ngbNavLink i18n>Comments <span *ngIf="document?.comments.length" class="badge text-bg-secondary ms-1">{{document.comments.length}}</span></a>
+                <li [ngbNavItem]="DocumentDetailNavIDs.Notes" *ngIf="notesEnabled">
+                    <a ngbNavLink i18n>Notes <span *ngIf="document?.notes.length" class="badge text-bg-secondary ms-1">{{document.notes.length}}</span></a>
                     <ng-template ngbNavContent>
-                        <app-document-comments [documentId]="documentId" [comments]="document?.comments" (updated)="commentsUpdated($event)"></app-document-comments>
+                        <app-document-notes [documentId]="documentId" [notes]="document?.notes" (updated)="notesUpdated($event)"></app-document-notes>
                     </ng-template>
                 </li>
 
index 3ca7755e286f8362d5002ec50794d7698633c8cd..e154cd03bfc948827d44a6d1cbc54e3f1a84e7df 100644 (file)
@@ -42,14 +42,14 @@ import {
 } from 'src/app/services/permissions.service'
 import { PaperlessUser } from 'src/app/data/paperless-user'
 import { UserService } from 'src/app/services/rest/user.service'
-import { PaperlessDocumentComment } from 'src/app/data/paperless-document-comment'
+import { PaperlessDocumentNote } from 'src/app/data/paperless-document-note'
 
 enum DocumentDetailNavIDs {
   Details = 1,
   Content = 2,
   Metadata = 3,
   Preview = 4,
-  Comments = 5,
+  Notes = 5,
   Permissions = 6,
 }
 
@@ -658,9 +658,9 @@ export class DocumentDetailComponent
     }
   }
 
-  get commentsEnabled(): boolean {
+  get notesEnabled(): boolean {
     return (
-      this.settings.get(SETTINGS_KEYS.COMMENTS_ENABLED) &&
+      this.settings.get(SETTINGS_KEYS.NOTES_ENABLED) &&
       this.permissionsService.currentUserCan(
         PermissionAction.View,
         PermissionType.Document
@@ -668,8 +668,8 @@ export class DocumentDetailComponent
     )
   }
 
-  commentsUpdated(comments: PaperlessDocumentComment[]) {
-    this.document.comments = comments
+  notesUpdated(notes: PaperlessDocumentNote[]) {
+    this.document.notes = notes
     this.openDocumentService.refreshDocument(this.documentId)
   }
 
index 01ea1e8b61b4317c9770b9737df5bcff7c983283..6f4e36b733c92666392e81f4e2eae269ed819aee 100644 (file)
@@ -26,7 +26,7 @@
         </div>
         <p class="card-text">
           <span *ngIf="document.__search_hit__ && document.__search_hit__.highlights" [innerHtml]="document.__search_hit__.highlights"></span>
-          <span *ngFor="let highlight of searchCommentHighlights" class="d-block">
+          <span *ngFor="let highlight of searchNoteHighlights" class="d-block">
             <svg width="1em" height="1em" fill="currentColor" class="me-2">
               <use xlink:href="assets/bootstrap-icons.svg#chat-left-text"/>
             </svg>
 
 
           <div class="list-group list-group-horizontal border-0 card-info ms-md-auto mt-2 mt-md-0">
-            <button routerLink="/documents/{{document.id}}/comments" *ngIf="document.comments.length" class="list-group-item btn btn-sm bg-light text-dark p-1 border-0 me-2" title="View comments" i18n-title>
+            <button *ngIf="notesEnabled && document.notes.length" routerLink="/documents/{{document.id}}/notes" class="list-group-item btn btn-sm bg-light text-dark p-1 border-0 me-2" title="View notes" i18n-title>
               <svg class="metadata-icon me-2 text-muted" fill="currentColor">
                 <use xlink:href="assets/bootstrap-icons.svg#chat-left-text"/>
               </svg>
-              <small i18n>{{document.comments.length}} Comments</small>
+              <small i18n>{{document.notes.length}} Notes</small>
             </button>
             <button *ngIf="document.document_type" type="button" class="list-group-item btn btn-sm bg-light text-dark p-1 border-0 me-2" title="Filter by document type" i18n-title
              (click)="clickDocumentType.emit(document.document_type);$event.stopPropagation()">
index c01759be3dc21c9d6c6461a3eddd1ede933fda7e..b73606d78961dddde0b6252e1b85b5d86a72d8d7 100644 (file)
@@ -73,16 +73,14 @@ export class DocumentCardLargeComponent extends ComponentWithPermissions {
     }
   }
 
-  get searchCommentHighlights() {
+  get searchNoteHighlights() {
     let highlights = []
     if (
       this.document['__search_hit__'] &&
-      this.document['__search_hit__'].comment_highlights
+      this.document['__search_hit__'].note_highlights
     ) {
-      // only show comments with a match
-      highlights = (
-        this.document['__search_hit__'].comment_highlights as string
-      )
+      // only show notes with a match
+      highlights = (this.document['__search_hit__'].note_highlights as string)
         .split(',')
         .filter((higlight) => higlight.includes('<span'))
     }
@@ -136,4 +134,8 @@ export class DocumentCardLargeComponent extends ComponentWithPermissions {
       (this.document.content.length > 500 ? '...' : '')
     )
   }
+
+  get notesEnabled(): boolean {
+    return this.settingsService.get(SETTINGS_KEYS.NOTES_ENABLED)
+  }
 }
index c3debc7398f02b2e6351fb7ee271c126c1c504a0..d9836cc9cd547a4ddbe7576f662b2144493019ef 100644 (file)
       <div class="tags d-flex flex-column text-end position-absolute me-1 fs-6">
         <app-tag *ngFor="let t of getTagsLimited$() | async" [tag]="t" (click)="clickTag.emit(t.id);$event.stopPropagation()" [clickable]="true" linkTitle="Toggle tag filter" i18n-linkTitle></app-tag>
         <div *ngIf="moreTags">
-          <span class="badge badge-secondary">+ {{moreTags}}</span>
+          <span class="badge text-dark">+ {{moreTags}}</span>
         </div>
       </div>
     </div>
 
-    <a routerLink="/documents/{{document.id}}/comments" *ngIf="document.comments.length" class="document-card-comments py-2 px-1">
+    <a *ngIf="notesEnabled && document.notes.length" routerLink="/documents/{{document.id}}/notes" class="document-card-notes py-2 px-1">
       <span class="badge rounded-pill bg-light border text-primary">
       <svg class="metadata-icon ms-1 me-1" fill="currentColor">
         <use xlink:href="assets/bootstrap-icons.svg#chat-left-text"/>
       </svg>
-      {{document.comments.length}}</span>
+      {{document.notes.length}}</span>
     </a>
 
-    <div class="card-body p-2">
+    <div class="card-body bg-light p-2">
       <p class="card-text">
         <ng-container *ngIf="document.correspondent">
           <a title="Toggle correspondent filter" i18n-title (click)="clickCorrespondent.emit(document.correspondent);$event.stopPropagation()" class="fw-bold btn-link">{{(document.correspondent$ | async)?.name}}</a>:
index 95c66d7d6953c16b2f772f52ca00dd92fb9e56ae..9affa52ec4b1b649de5f3e177e7a9bdb9c5b7756 100644 (file)
   display: block;
 }
 
-.document-card-comments {
+.document-card-notes {
   position: absolute;
   right: 0;
-  bottom: 170px;
+  top: 142px;
 }
 
 .card-selected {
index 745f2b3e44b0b7637b050c2d2591e5f7ee3a4d56..28b3541542960a1c80af6e7bb2d744b15c27ad02 100644 (file)
@@ -74,7 +74,7 @@ export class DocumentCardSmallComponent extends ComponentWithPermissions {
   }
 
   getTagsLimited$() {
-    const limit = this.document.comments.length > 0 ? 6 : 7
+    const limit = this.document.notes.length > 0 ? 6 : 7
     return this.document.tags$.pipe(
       map((tags) => {
         if (tags.length > limit) {
@@ -111,4 +111,8 @@ export class DocumentCardSmallComponent extends ComponentWithPermissions {
   mouseLeaveCard() {
     this.popover.close()
   }
+
+  get notesEnabled(): boolean {
+    return this.settingsService.get(SETTINGS_KEYS.NOTES_ENABLED)
+  }
 }
index 02015380e8c591e4cdd2f9ee2a1693678ad416be..70ff168f6b67f14ec5072ec134ca4d664d3e4c97 100644 (file)
         [currentSortReverse]="list.sortReverse"
         (sort)="onSort($event)"
         i18n>Title</th>
-      <th class="d-none d-xl-table-cell"
-        appSortable="num_comments"
+      <th *ngIf="notesEnabled" class="d-none d-xl-table-cell"
+        appSortable="num_notes"
         [currentSortField]="list.sortField"
         [currentSortReverse]="list.sortReverse"
         (sort)="onSort($event)"
-        i18n>Comments</th>
+        i18n>Notes</th>
       <th class="d-none d-xl-table-cell"
         appSortable="document_type__name"
         [currentSortField]="list.sortField"
           <a routerLink="/documents/{{d.id}}" title="Edit document" i18n-title style="overflow-wrap: anywhere;">{{d.title | documentTitle}}</a>
           <app-tag [tag]="t" *ngFor="let t of d.tags$ | async" class="ms-1" clickable="true" linkTitle="Filter by tag" i18n-linkTitle (click)="clickTag(t.id);$event.stopPropagation()"></app-tag>
         </td>
-        <td class="d-none d-xl-table-cell">
-          <a routerLink="/documents/{{d.id}}/comments" *ngIf="d.comments.length" class="btn btn-sm p-0">
+        <td *ngIf="notesEnabled" class="d-none d-xl-table-cell">
+          <a *ngIf="d.notes.length" routerLink="/documents/{{d.id}}/notes" class="btn btn-sm p-0">
             <span class="badge rounded-pill bg-light border text-primary">
             <svg class="metadata-icon ms-1 me-1" fill="currentColor">
               <use xlink:href="assets/bootstrap-icons.svg#chat-left-text"/>
             </svg>
-            {{d.comments.length}}</span>
+            {{d.notes.length}}</span>
           </a>
         </td>
         <td class="d-none d-xl-table-cell">
index d4a6544443f95bc9dce3c282db8ea3812cca7939..7847097bc2a9c10b32ebb7fc60278fb06d0b8ff0 100644 (file)
@@ -17,6 +17,7 @@ import {
 import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type'
 import { PaperlessDocument } from 'src/app/data/paperless-document'
 import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'
+import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
 import {
   SortableDirective,
   SortEvent,
@@ -29,6 +30,7 @@ import {
   DOCUMENT_SORT_FIELDS_FULLTEXT,
 } from 'src/app/services/rest/document.service'
 import { SavedViewService } from 'src/app/services/rest/saved-view.service'
+import { SettingsService } from 'src/app/services/settings.service'
 import { ToastService } from 'src/app/services/toast.service'
 import { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
 import { FilterEditorComponent } from './filter-editor/filter-editor.component'
@@ -51,7 +53,8 @@ export class DocumentListComponent
     private toastService: ToastService,
     private modalService: NgbModal,
     private consumerStatusService: ConsumerStatusService,
-    public openDocumentsService: OpenDocumentsService
+    public openDocumentsService: OpenDocumentsService,
+    private settingsService: SettingsService
   ) {
     super()
   }
@@ -289,4 +292,8 @@ export class DocumentListComponent
   trackByDocumentId(index, item: PaperlessDocument) {
     return item.id
   }
+
+  get notesEnabled(): boolean {
+    return this.settingsService.get(SETTINGS_KEYS.NOTES_ENABLED)
+  }
 }
similarity index 50%
rename from src-ui/src/app/components/document-comments/document-comments.component.html
rename to src-ui/src/app/components/document-notes/document-notes.component.html
index b303524147c395adfaeadf4f773d03aab724c49e..f6c46cd47ae6067ddbc02e0291e23258c2366829 100644 (file)
@@ -1,28 +1,28 @@
-<div *ngIf="comments">
-    <form [formGroup]="commentForm" class="needs-validation mt-3" *appIfPermissions="{ action: PermissionAction.Add, type: PermissionType.Comment }" novalidate>
+<div *ngIf="notes">
+    <form [formGroup]="noteForm" class="needs-validation mt-3" *appIfPermissions="{ action: PermissionAction.Add, type: PermissionType.Note }" novalidate>
         <div class="form-group">
-            <textarea class="form-control form-control-sm" [class.is-invalid]="newCommentError" rows="3" formControlName="newComment" placeholder="Enter comment" i18n-placeholder (keydown)="commentFormKeydown($event)" required></textarea>
+            <textarea class="form-control form-control-sm" [class.is-invalid]="newNoteError" rows="3" formControlName="newNote" placeholder="Enter note" i18n-placeholder (keydown)="noteFormKeydown($event)" required></textarea>
             <div class="invalid-feedback" i18n>
-                Please enter a comment.
+                Please enter a note.
             </div>
         </div>
         <div class="form-group mt-2 d-flex justify-content-end align-items-center">
             <div *ngIf="networkActive" class="spinner-border spinner-border-sm fw-normal me-auto" role="status"></div>
-            <button type="button" class="btn btn-primary btn-sm" [disabled]="networkActive" (click)="addComment()" i18n>Add comment</button>
+            <button type="button" class="btn btn-primary btn-sm" [disabled]="networkActive" (click)="addNote()" i18n>Add note</button>
         </div>
     </form>
     <hr>
-    <div *ngFor="let comment of comments" class="card border mb-3">
+    <div *ngFor="let note of notes" class="card border mb-3">
         <div class="card-body text-dark">
-            <p class="card-text">{{comment.comment}}</p>
+            <p class="card-text">{{note.note}}</p>
         </div>
         <div class="d-flex card-footer small bg-light text-primary justify-content-between align-items-center">
-            <span>{{displayName(comment)}} - {{ comment.created | customDate}}</span>
-            <button type="button" class="btn btn-link btn-sm p-0 fade" title="Delete comment" i18n-title (click)="deleteComment(comment.id)" *appIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.Comment }">
+            <span>{{displayName(note)}} - {{ note.created | customDate}}</span>
+            <button type="button" class="btn btn-link btn-sm p-0 fade" title="Delete note" i18n-title (click)="deleteNote(note.id)" *appIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.Note }">
                 <svg width="13" height="13" fill="currentColor">
                     <use xlink:href="assets/bootstrap-icons.svg#trash" />
                 </svg>
-                <span class="visually-hidden" i18n>Delete comment</span>
+                <span class="visually-hidden" i18n>Delete note</span>
             </button>
         </div>
     </div>
diff --git a/src-ui/src/app/components/document-notes/document-notes.component.ts b/src-ui/src/app/components/document-notes/document-notes.component.ts
new file mode 100644 (file)
index 0000000..c8bb3cc
--- /dev/null
@@ -0,0 +1,106 @@
+import { Component, Input, Output, EventEmitter } from '@angular/core'
+import { DocumentNotesService } from 'src/app/services/rest/document-notes.service'
+import { PaperlessDocumentNote } from 'src/app/data/paperless-document-note'
+import { FormControl, FormGroup } from '@angular/forms'
+import { first } from 'rxjs/operators'
+import { ToastService } from 'src/app/services/toast.service'
+import { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
+import { UserService } from 'src/app/services/rest/user.service'
+import { PaperlessUser } from 'src/app/data/paperless-user'
+
+@Component({
+  selector: 'app-document-notes',
+  templateUrl: './document-notes.component.html',
+  styleUrls: ['./document-notes.component.scss'],
+})
+export class DocumentNotesComponent extends ComponentWithPermissions {
+  noteForm: FormGroup = new FormGroup({
+    newNote: new FormControl(''),
+  })
+
+  networkActive = false
+  newNoteError: boolean = false
+
+  @Input()
+  documentId: number
+
+  @Input()
+  notes: PaperlessDocumentNote[] = []
+
+  @Output()
+  updated: EventEmitter<PaperlessDocumentNote[]> = new EventEmitter()
+  users: PaperlessUser[]
+
+  constructor(
+    private notesService: DocumentNotesService,
+    private toastService: ToastService,
+    private usersService: UserService
+  ) {
+    super()
+    this.usersService.listAll().subscribe({
+      next: (users) => {
+        this.users = users.results
+      },
+    })
+  }
+
+  addNote() {
+    const note: string = this.noteForm.get('newNote').value.toString().trim()
+    if (note.length == 0) {
+      this.newNoteError = true
+      return
+    }
+    this.newNoteError = false
+    this.networkActive = true
+    this.notesService.addNote(this.documentId, note).subscribe({
+      next: (result) => {
+        this.notes = result
+        this.noteForm.get('newNote').reset()
+        this.networkActive = false
+        this.updated.emit(this.notes)
+      },
+      error: (e) => {
+        this.networkActive = false
+        this.toastService.showError(
+          $localize`Error saving note: ${e.toString()}`
+        )
+      },
+    })
+  }
+
+  deleteNote(noteId: number) {
+    this.notesService.deleteNote(this.documentId, noteId).subscribe({
+      next: (result) => {
+        this.notes = result
+        this.networkActive = false
+        this.updated.emit(this.notes)
+      },
+      error: (e) => {
+        this.networkActive = false
+        this.toastService.showError(
+          $localize`Error deleting note: ${e.toString()}`
+        )
+      },
+    })
+  }
+
+  displayName(note: PaperlessDocumentNote): string {
+    if (!note.user) return ''
+    const user = this.users.find((u) => u.id === note.user)
+    if (!user) return ''
+    const nameComponents = []
+    if (user.first_name) nameComponents.unshift(user.first_name)
+    if (user.last_name) nameComponents.unshift(user.last_name)
+    if (user.username) {
+      if (nameComponents.length > 0) nameComponents.push(`(${user.username})`)
+      else nameComponents.push(user.username)
+    }
+    return nameComponents.join(' ')
+  }
+
+  noteFormKeydown(event: KeyboardEvent) {
+    if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {
+      this.addNote()
+    }
+  }
+}
index b7e7d64b4531b19481f890326dd220948da8160d..3357aff78910d4efc9bec53856ccf9ebce9fdfd0 100644 (file)
           </div>
         </div>
 
-        <h4 class="mt-4" i18n>Comments</h4>
+        <h4 class="mt-4" i18n>Notes</h4>
 
         <div class="row mb-3">
           <div class="offset-md-3 col">
-            <app-input-check i18n-title title="Enable comments" formControlName="commentsEnabled"></app-input-check>
+            <app-input-check i18n-title title="Enable notes" formControlName="notesEnabled"></app-input-check>
           </div>
         </div>
 
index 39aaaae2833c9fcb79c082b9bedfdbd69f1d14b7..d795d7f0e7a512bdcbf4b0d70b4c935b5f6847a7 100644 (file)
@@ -85,7 +85,7 @@ export class SettingsComponent
     displayLanguage: new FormControl(null),
     dateLocale: new FormControl(null),
     dateFormat: new FormControl(null),
-    commentsEnabled: new FormControl(null),
+    notesEnabled: new FormControl(null),
     updateCheckingEnabled: new FormControl(null),
 
     notificationsConsumerNewDocument: new FormControl(null),
@@ -196,7 +196,7 @@ export class SettingsComponent
       displayLanguage: this.settings.getLanguage(),
       dateLocale: this.settings.get(SETTINGS_KEYS.DATE_LOCALE),
       dateFormat: this.settings.get(SETTINGS_KEYS.DATE_FORMAT),
-      commentsEnabled: this.settings.get(SETTINGS_KEYS.COMMENTS_ENABLED),
+      notesEnabled: this.settings.get(SETTINGS_KEYS.NOTES_ENABLED),
       updateCheckingEnabled: this.settings.get(
         SETTINGS_KEYS.UPDATE_CHECKING_ENABLED
       ),
@@ -552,8 +552,8 @@ export class SettingsComponent
       this.settingsForm.value.notificationsConsumerSuppressOnDashboard
     )
     this.settings.set(
-      SETTINGS_KEYS.COMMENTS_ENABLED,
-      this.settingsForm.value.commentsEnabled
+      SETTINGS_KEYS.NOTES_ENABLED,
+      this.settingsForm.value.notesEnabled
     )
     this.settings.set(
       SETTINGS_KEYS.UPDATE_CHECKING_ENABLED,
diff --git a/src-ui/src/app/data/paperless-document-comment.ts b/src-ui/src/app/data/paperless-document-comment.ts
deleted file mode 100644 (file)
index 884e590..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-import { ObjectWithId } from './object-with-id'
-import { PaperlessUser } from './paperless-user'
-
-export interface PaperlessDocumentComment extends ObjectWithId {
-  created?: Date
-  comment?: string
-  user?: PaperlessUser
-}
diff --git a/src-ui/src/app/data/paperless-document-note.ts b/src-ui/src/app/data/paperless-document-note.ts
new file mode 100644 (file)
index 0000000..569b494
--- /dev/null
@@ -0,0 +1,7 @@
+import { ObjectWithId } from './object-with-id'
+
+export interface PaperlessDocumentNote extends ObjectWithId {
+  created?: Date
+  note?: string
+  user?: number // PaperlessUser
+}
index be15efb01d6291dc262b82fcf2e5b9a43dd50cfd..755d44f6aea4f780242a317e83e239eef5f06a62 100644 (file)
@@ -4,14 +4,14 @@ import { PaperlessDocumentType } from './paperless-document-type'
 import { Observable } from 'rxjs'
 import { PaperlessStoragePath } from './paperless-storage-path'
 import { ObjectWithPermissions } from './object-with-permissions'
-import { PaperlessDocumentComment } from './paperless-document-comment'
+import { PaperlessDocumentNote } from './paperless-document-note'
 
 export interface SearchHit {
   score?: number
   rank?: number
 
   highlights?: string
-  comment_highlights?: string
+  note_highlights?: string
 }
 
 export interface PaperlessDocument extends ObjectWithPermissions {
@@ -55,7 +55,7 @@ export interface PaperlessDocument extends ObjectWithPermissions {
 
   archive_serial_number?: number
 
-  comments?: PaperlessDocumentComment[]
+  notes?: PaperlessDocumentNote[]
 
   __search_hit__?: SearchHit
 }
index d2b4c583d5cec1e8eb005d89a4b461579f9050f0..4701a430080bba2c4671a912e1e327ee22a22bc1 100644 (file)
@@ -34,7 +34,7 @@ export const SETTINGS_KEYS = {
     'general-settings:notifications:consumer-failed',
   NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD:
     'general-settings:notifications:consumer-suppress-on-dashboard',
-  COMMENTS_ENABLED: 'general-settings:comments-enabled',
+  NOTES_ENABLED: 'general-settings:notes-enabled',
   SLIM_SIDEBAR: 'general-settings:slim-sidebar',
   UPDATE_CHECKING_ENABLED: 'general-settings:update-checking:enabled',
   UPDATE_CHECKING_BACKEND_SETTING:
@@ -125,7 +125,7 @@ export const SETTINGS: PaperlessUiSetting[] = [
     default: true,
   },
   {
-    key: SETTINGS_KEYS.COMMENTS_ENABLED,
+    key: SETTINGS_KEYS.NOTES_ENABLED,
     type: 'boolean',
     default: true,
   },
index a7ba7638d93c096d4997d4a10df51ba6d4e27e89..e1ce9497736e1357784395d5be6fd78b6257a293 100644 (file)
@@ -18,7 +18,7 @@ export enum PermissionType {
   SavedView = '%s_savedview',
   PaperlessTask = '%s_paperlesstask',
   UISettings = '%s_uisettings',
-  Comment = '%s_comment',
+  Note = '%s_note',
   MailAccount = '%s_mailaccount',
   MailRule = '%s_mailrule',
   User = '%s_user',
diff --git a/src-ui/src/app/services/rest/document-comments.service.ts b/src-ui/src/app/services/rest/document-comments.service.ts
deleted file mode 100644 (file)
index a697c0e..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-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'
-
-@Injectable({
-  providedIn: 'root',
-})
-export class DocumentCommentsService extends AbstractPaperlessService<PaperlessDocumentComment> {
-  constructor(http: HttpClient) {
-    super(http, 'documents')
-  }
-
-  getComments(documentId: number): Observable<PaperlessDocumentComment[]> {
-    return this.http.get<PaperlessDocumentComment[]>(
-      this.getResourceUrl(documentId, 'comments')
-    )
-  }
-
-  addComment(id: number, comment): Observable<PaperlessDocumentComment[]> {
-    return this.http.post<PaperlessDocumentComment[]>(
-      this.getResourceUrl(id, 'comments'),
-      { comment: comment }
-    )
-  }
-
-  deleteComment(
-    documentId: number,
-    commentId: number
-  ): Observable<PaperlessDocumentComment[]> {
-    return this.http.delete<PaperlessDocumentComment[]>(
-      this.getResourceUrl(documentId, 'comments'),
-      { params: new HttpParams({ fromString: `id=${commentId}` }) }
-    )
-  }
-}
diff --git a/src-ui/src/app/services/rest/document-notes.service.ts b/src-ui/src/app/services/rest/document-notes.service.ts
new file mode 100644 (file)
index 0000000..11bbde4
--- /dev/null
@@ -0,0 +1,37 @@
+import { Injectable } from '@angular/core'
+import { HttpClient, HttpParams } from '@angular/common/http'
+import { PaperlessDocumentNote } from 'src/app/data/paperless-document-note'
+import { AbstractPaperlessService } from './abstract-paperless-service'
+import { Observable } from 'rxjs'
+
+@Injectable({
+  providedIn: 'root',
+})
+export class DocumentNotesService extends AbstractPaperlessService<PaperlessDocumentNote> {
+  constructor(http: HttpClient) {
+    super(http, 'documents')
+  }
+
+  getNotes(documentId: number): Observable<PaperlessDocumentNote[]> {
+    return this.http.get<PaperlessDocumentNote[]>(
+      this.getResourceUrl(documentId, 'notes')
+    )
+  }
+
+  addNote(id: number, note: string): Observable<PaperlessDocumentNote[]> {
+    return this.http.post<PaperlessDocumentNote[]>(
+      this.getResourceUrl(id, 'notes'),
+      { note: note }
+    )
+  }
+
+  deleteNote(
+    documentId: number,
+    noteId: number
+  ): Observable<PaperlessDocumentNote[]> {
+    return this.http.delete<PaperlessDocumentNote[]>(
+      this.getResourceUrl(documentId, 'notes'),
+      { params: new HttpParams({ fromString: `id=${noteId}` }) }
+    )
+  }
+}
index 4e7e97110fec081352e5c14144036dd2dfca7be4..63b447b9af7e292a622896344e40f2c27db1623d 100644 (file)
@@ -22,6 +22,7 @@ export const DOCUMENT_SORT_FIELDS = [
   { field: 'created', name: $localize`Created` },
   { field: 'added', name: $localize`Added` },
   { field: 'modified', name: $localize`Modified` },
+  { field: 'num_notes', name: $localize`Notes` },
 ]
 
 export const DOCUMENT_SORT_FIELDS_FULLTEXT = [
index 7090d8d40f7a4bec6b593f0b39c03ce39924d4ad..92b078994e7be2d8c528d21b46fe5b5caee9a1a6 100644 (file)
@@ -137,6 +137,10 @@ $form-check-radio-checked-bg-image-dark: url("data:image/svg+xml,<svg xmlns='htt
     border-color: rgba(0,0,0,0) !important;
   }
 
+  .document-card .card-body.bg-light {
+    background-color: var(--bs-body-bg);
+  }
+
   .doc-img {
     mix-blend-mode: normal;
     border-radius: 0;
index 0e7daafc4abeb615752eacc2fca15195a90df2a1..072e69e6e787b3482d5554920171d33eb52f12ac 100644 (file)
@@ -4,6 +4,7 @@ from guardian.admin import GuardedModelAdmin
 from .models import Correspondent
 from .models import Document
 from .models import DocumentType
+from .models import Note
 from .models import PaperlessTask
 from .models import SavedView
 from .models import SavedViewFilterRule
@@ -131,6 +132,13 @@ class TaskAdmin(admin.ModelAdmin):
     )
 
 
+class NotesAdmin(GuardedModelAdmin):
+
+    list_display = ("user", "created", "note", "document")
+    list_filter = ("created", "user")
+    list_display_links = ("created",)
+
+
 admin.site.register(Correspondent, CorrespondentAdmin)
 admin.site.register(Tag, TagAdmin)
 admin.site.register(DocumentType, DocumentTypeAdmin)
@@ -138,3 +146,4 @@ admin.site.register(Document, DocumentAdmin)
 admin.site.register(SavedView, SavedViewAdmin)
 admin.site.register(StoragePath, StoragePathAdmin)
 admin.site.register(PaperlessTask, TaskAdmin)
+admin.site.register(Note, NotesAdmin)
index c0b3f5465998e314ad7e2a6543c6ad960a23161d..05d4d5d17912548c2102bdb1e976ea5ec525aac7 100644 (file)
@@ -6,8 +6,8 @@ from contextlib import contextmanager
 from dateutil.parser import isoparse
 from django.conf import settings
 from django.utils import timezone
-from documents.models import Comment
 from documents.models import Document
+from documents.models import Note
 from guardian.shortcuts import get_users_with_perms
 from whoosh import classify
 from whoosh import highlight
@@ -52,7 +52,7 @@ def get_schema():
         path=TEXT(sortable=True),
         path_id=NUMERIC(),
         has_path=BOOLEAN(),
-        comments=TEXT(),
+        notes=TEXT(),
         owner=TEXT(),
         owner_id=NUMERIC(),
         has_owner=BOOLEAN(),
@@ -98,7 +98,7 @@ def open_index_searcher():
 def update_document(writer: AsyncWriter, doc: Document):
     tags = ",".join([t.name for t in doc.tags.all()])
     tags_ids = ",".join([str(t.id) for t in doc.tags.all()])
-    comments = ",".join([str(c.comment) for c in Comment.objects.filter(document=doc)])
+    notes = ",".join([str(c.note) for c in Note.objects.filter(document=doc)])
     asn = doc.archive_serial_number
     if asn is not None and (
         asn < Document.ARCHIVE_SERIAL_NUMBER_MIN
@@ -136,7 +136,7 @@ def update_document(writer: AsyncWriter, doc: Document):
         path=doc.storage_path.name if doc.storage_path else None,
         path_id=doc.storage_path.id if doc.storage_path else None,
         has_path=doc.storage_path is not None,
-        comments=comments,
+        notes=notes,
         owner=doc.owner.username if doc.owner else None,
         owner_id=doc.owner.id if doc.owner else None,
         has_owner=doc.owner is not None,
@@ -293,7 +293,7 @@ class DelayedFullTextQuery(DelayedQuery):
     def _get_query(self):
         q_str = self.query_params["query"]
         qp = MultifieldParser(
-            ["content", "title", "correspondent", "tag", "type", "comments"],
+            ["content", "title", "correspondent", "tag", "type", "notes"],
             self.searcher.ixreader.schema,
         )
         qp.add_plugin(DateParserPlugin(basedate=timezone.now()))
index 427cd4ef2d7ccb61232d3d9f8a0c8fe100ac46a0..e92e09966b8a0d39696bf7ed206cc839b7ad685e 100644 (file)
@@ -17,10 +17,10 @@ from django.core.management.base import BaseCommand
 from django.core.management.base import CommandError
 from django.db import transaction
 from django.utils import timezone
-from documents.models import Comment
 from documents.models import Correspondent
 from documents.models import Document
 from documents.models import DocumentType
+from documents.models import Note
 from documents.models import SavedView
 from documents.models import SavedViewFilterRule
 from documents.models import StoragePath
@@ -206,7 +206,7 @@ class Command(BaseCommand):
                 self.files_in_export_dir.add(x.resolve())
 
         # 2. Create manifest, containing all correspondents, types, tags, storage paths
-        # comments, documents and ui_settings
+        # note, documents and ui_settings
         with transaction.atomic():
             manifest = json.loads(
                 serializers.serialize("json", Correspondent.objects.all()),
@@ -222,11 +222,11 @@ class Command(BaseCommand):
                 serializers.serialize("json", StoragePath.objects.all()),
             )
 
-            comments = json.loads(
-                serializers.serialize("json", Comment.objects.all()),
+            notes = json.loads(
+                serializers.serialize("json", Note.objects.all()),
             )
             if not self.split_manifest:
-                manifest += comments
+                manifest += notes
 
             documents = Document.objects.order_by("id")
             document_map = {d.pk: d for d in documents}
@@ -359,7 +359,7 @@ class Command(BaseCommand):
                 content += list(
                     filter(
                         lambda d: d["fields"]["document"] == document_dict["pk"],
-                        comments,
+                        notes,
                     ),
                 )
                 manifest_name.write_text(json.dumps(content, indent=2))
diff --git a/src/documents/migrations/1034_alter_comment_document_alter_comment_user.py b/src/documents/migrations/1034_alter_comment_document_alter_comment_user.py
deleted file mode 100644 (file)
index 1583e76..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-# Generated by Django 4.1.5 on 2023-03-17 21:23
-
-from django.conf import settings
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
-        ("documents", "1033_alter_documenttype_options_alter_tag_options_and_more"),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name="comment",
-            name="document",
-            field=models.ForeignKey(
-                blank=True,
-                null=True,
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="comments",
-                to="documents.document",
-                verbose_name="document",
-            ),
-        ),
-        migrations.AlterField(
-            model_name="comment",
-            name="user",
-            field=models.ForeignKey(
-                blank=True,
-                null=True,
-                on_delete=django.db.models.deletion.SET_NULL,
-                related_name="comments",
-                to=settings.AUTH_USER_MODEL,
-                verbose_name="user",
-            ),
-        ),
-    ]
diff --git a/src/documents/migrations/1035_rename_comment_note.py b/src/documents/migrations/1035_rename_comment_note.py
new file mode 100644 (file)
index 0000000..5cd05b8
--- /dev/null
@@ -0,0 +1,61 @@
+# Generated by Django 4.1.5 on 2023-03-17 22:15
+
+from django.conf import settings
+from django.db import migrations
+from django.db import models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ("documents", "1034_alter_savedviewfilterrule_rule_type"),
+    ]
+
+    operations = [
+        migrations.RenameModel(
+            old_name="Comment",
+            new_name="Note",
+        ),
+        migrations.RenameField(model_name="note", old_name="comment", new_name="note"),
+        migrations.AlterModelOptions(
+            name="note",
+            options={
+                "ordering": ("created",),
+                "verbose_name": "note",
+                "verbose_name_plural": "notes",
+            },
+        ),
+        migrations.AlterField(
+            model_name="note",
+            name="document",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="notes",
+                to="documents.document",
+                verbose_name="document",
+            ),
+        ),
+        migrations.AlterField(
+            model_name="note",
+            name="note",
+            field=models.TextField(
+                blank=True, help_text="Note for the document", verbose_name="content"
+            ),
+        ),
+        migrations.AlterField(
+            model_name="note",
+            name="user",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.SET_NULL,
+                related_name="notes",
+                to=settings.AUTH_USER_MODEL,
+                verbose_name="user",
+            ),
+        ),
+    ]
index d820f32d27046c64fc6526a70c6cc3616914c20a..deaa2c28adadde78b734080c089774030335c2ab 100644 (file)
@@ -635,11 +635,11 @@ class PaperlessTask(models.Model):
     )
 
 
-class Comment(models.Model):
-    comment = models.TextField(
+class Note(models.Model):
+    note = models.TextField(
         _("content"),
         blank=True,
-        help_text=_("Comment for the document"),
+        help_text=_("Note for the document"),
     )
 
     created = models.DateTimeField(
@@ -652,7 +652,7 @@ class Comment(models.Model):
         Document,
         blank=True,
         null=True,
-        related_name="comments",
+        related_name="notes",
         on_delete=models.CASCADE,
         verbose_name=_("document"),
     )
@@ -661,15 +661,15 @@ class Comment(models.Model):
         User,
         blank=True,
         null=True,
-        related_name="comments",
+        related_name="notes",
         on_delete=models.SET_NULL,
         verbose_name=_("user"),
     )
 
     class Meta:
         ordering = ("created",)
-        verbose_name = _("comment")
-        verbose_name_plural = _("comments")
+        verbose_name = _("note")
+        verbose_name_plural = _("notes")
 
     def __str__(self):
-        return self.content
+        return self.note
index 9746dea409075286b449dfc31b28cc2073449f96..4e2fafe3443a619580ab6883646cd6e306b91d57 100644 (file)
@@ -382,8 +382,6 @@ class DocumentSerializer(OwnedObjectSerializer, DynamicFieldsModelSerializer):
     archived_file_name = SerializerMethodField()
     created_date = serializers.DateField(required=False)
 
-    num_comments = serializers.IntegerField(read_only=True)
-
     owner = serializers.PrimaryKeyRelatedField(
         queryset=User.objects.all(),
         required=False,
@@ -444,8 +442,7 @@ class DocumentSerializer(OwnedObjectSerializer, DynamicFieldsModelSerializer):
             "owner",
             "permissions",
             "set_permissions",
-            "comments",
-            "num_comments",
+            "notes",
         )
 
 
index f56d0344ccc924ee59f24ebdc50723b4b594e60d..d6da83d5149a8639edfdfae73e10c0ec93a0f36a 100644 (file)
@@ -38,7 +38,7 @@ from documents.models import PaperlessTask
 from documents.models import SavedView
 from documents.models import StoragePath
 from documents.models import Tag
-from documents.models import Comment
+from documents.models import Note
 from documents.tests.utils import DirectoriesMixin
 from paperless import version
 from rest_framework.test import APITestCase
@@ -1717,28 +1717,28 @@ class TestDocumentApi(DirectoriesMixin, APITestCase):
             1,
         )
 
-    def test_get_existing_comments(self):
+    def test_get_existing_notes(self):
         """
         GIVEN:
-            - A document with a single comment
+            - A document with a single note
         WHEN:
-            - API reuqest for document comments is made
+            - API reuqest for document notes is made
         THEN:
-            - The associated comment is returned
+            - The associated note is returned
         """
         doc = Document.objects.create(
             title="test",
             mime_type="application/pdf",
-            content="this is a document which will have comments!",
+            content="this is a document which will have notes!",
         )
-        comment = Comment.objects.create(
-            comment="This is a comment.",
+        note = Note.objects.create(
+            note="This is a note.",
             document=doc,
             user=self.user,
         )
 
         response = self.client.get(
-            f"/api/documents/{doc.pk}/comments/",
+            f"/api/documents/{doc.pk}/notes/",
             format="json",
         )
 
@@ -1754,39 +1754,39 @@ class TestDocumentApi(DirectoriesMixin, APITestCase):
         self.assertDictEqual(
             resp_data,
             {
-                "id": comment.id,
-                "comment": comment.comment,
+                "id": note.id,
+                "note": note.note,
                 "user": {
-                    "id": comment.user.id,
-                    "username": comment.user.username,
-                    "first_name": comment.user.first_name,
-                    "last_name": comment.user.last_name,
+                    "id": note.user.id,
+                    "username": note.user.username,
+                    "first_name": note.user.first_name,
+                    "last_name": note.user.last_name,
                 },
             },
         )
 
-    def test_create_comment(self):
+    def test_create_note(self):
         """
         GIVEN:
             - Existing document
         WHEN:
-            - API request is made to add a comment
+            - API request is made to add a note
         THEN:
-            - Comment is created and associated with document
+            - note is created and associated with document
         """
         doc = Document.objects.create(
             title="test",
             mime_type="application/pdf",
-            content="this is a document which will have comments added",
+            content="this is a document which will have notes added",
         )
         resp = self.client.post(
-            f"/api/documents/{doc.pk}/comments/",
-            data={"comment": "this is a posted comment"},
+            f"/api/documents/{doc.pk}/notes/",
+            data={"note": "this is a posted note"},
         )
         self.assertEqual(resp.status_code, status.HTTP_200_OK)
 
         response = self.client.get(
-            f"/api/documents/{doc.pk}/comments/",
+            f"/api/documents/{doc.pk}/notes/",
             format="json",
         )
 
@@ -1798,48 +1798,48 @@ class TestDocumentApi(DirectoriesMixin, APITestCase):
 
         resp_data = resp_data[0]
 
-        self.assertEqual(resp_data["comment"], "this is a posted comment")
+        self.assertEqual(resp_data["note"], "this is a posted note")
 
-    def test_delete_comment(self):
+    def test_delete_note(self):
         """
         GIVEN:
             - Existing document
         WHEN:
-            - API request is made to add a comment
+            - API request is made to add a note
         THEN:
-            - Comment is created and associated with document
+            - note is created and associated with document
         """
         doc = Document.objects.create(
             title="test",
             mime_type="application/pdf",
-            content="this is a document which will have comments!",
+            content="this is a document which will have notes!",
         )
-        comment = Comment.objects.create(
-            comment="This is a comment.",
+        note = Note.objects.create(
+            note="This is a note.",
             document=doc,
             user=self.user,
         )
 
         response = self.client.delete(
-            f"/api/documents/{doc.pk}/comments/?id={comment.pk}",
+            f"/api/documents/{doc.pk}/notes/?id={note.pk}",
             format="json",
         )
 
         self.assertEqual(response.status_code, status.HTTP_200_OK)
 
-        self.assertEqual(len(Comment.objects.all()), 0)
+        self.assertEqual(len(Note.objects.all()), 0)
 
-    def test_get_comments_no_doc(self):
+    def test_get_notes_no_doc(self):
         """
         GIVEN:
-            - A request to get comments from a non-existent document
+            - A request to get notes from a non-existent document
         WHEN:
-            - API request for document comments is made
+            - API request for document notes is made
         THEN:
             - HTTP status.HTTP_404_NOT_FOUND is returned
         """
         response = self.client.get(
-            "/api/documents/500/comments/",
+            "/api/documents/500/notes/",
             format="json",
         )
         self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
index 18fb6d6622dec0b7450a053e0ad50f891933c68b..284151ffc16ca9c8c1ac74f0569472e02f77389a 100644 (file)
@@ -13,10 +13,10 @@ from django.test import override_settings
 from django.test import TestCase
 from django.utils import timezone
 from documents.management.commands import document_exporter
-from documents.models import Comment
 from documents.models import Correspondent
 from documents.models import Document
 from documents.models import DocumentType
+from documents.models import Note
 from documents.models import StoragePath
 from documents.models import Tag
 from documents.models import User
@@ -66,8 +66,8 @@ class TestExportImport(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
             storage_type=Document.STORAGE_TYPE_GPG,
         )
 
-        self.comment = Comment.objects.create(
-            comment="This is a comment. amaze.",
+        self.note = Note.objects.create(
+            note="This is a note. amaze.",
             document=self.d1,
             user=self.user,
         )
@@ -199,8 +199,8 @@ class TestExportImport(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
                         checksum = hashlib.md5(f.read()).hexdigest()
                     self.assertEqual(checksum, element["fields"]["archive_checksum"])
 
-            elif element["model"] == "documents.comment":
-                self.assertEqual(element["fields"]["comment"], self.comment.comment)
+            elif element["model"] == "documents.note":
+                self.assertEqual(element["fields"]["note"], self.note.note)
                 self.assertEqual(element["fields"]["document"], self.d1.id)
                 self.assertEqual(element["fields"]["user"], self.user.id)
 
index 6226d99cd69a4baa505405660a6cdebaaef82c83..47c4a7ec61adf59f8e79560529aafe8c30f41311 100644 (file)
@@ -72,10 +72,10 @@ from .matching import match_correspondents
 from .matching import match_document_types
 from .matching import match_storage_paths
 from .matching import match_tags
-from .models import Comment
 from .models import Correspondent
 from .models import Document
 from .models import DocumentType
+from .models import Note
 from .models import PaperlessTask
 from .models import SavedView
 from .models import StoragePath
@@ -230,7 +230,7 @@ class DocumentViewSet(
     GenericViewSet,
 ):
     model = Document
-    queryset = Document.objects.annotate(num_comments=Count("comments"))
+    queryset = Document.objects.annotate(num_notes=Count("notes"))
     serializer_class = DocumentSerializer
     pagination_class = StandardPagination
     permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
@@ -251,11 +251,11 @@ class DocumentViewSet(
         "modified",
         "added",
         "archive_serial_number",
-        "num_comments",
+        "num_notes",
     )
 
     def get_queryset(self):
-        return Document.objects.distinct()
+        return Document.objects.distinct().annotate(num_notes=Count("notes"))
 
     def get_serializer(self, *args, **kwargs):
         super().get_serializer(*args, **kwargs)
@@ -442,11 +442,11 @@ class DocumentViewSet(
         except (FileNotFoundError, Document.DoesNotExist):
             raise Http404()
 
-    def getComments(self, doc):
+    def getNotes(self, doc):
         return [
             {
                 "id": c.id,
-                "comment": c.comment,
+                "note": c.note,
                 "created": c.created,
                 "user": {
                     "id": c.user.id,
@@ -455,11 +455,11 @@ class DocumentViewSet(
                     "last_name": c.user.last_name,
                 },
             }
-            for c in Comment.objects.filter(document=doc).order_by("-created")
+            for c in Note.objects.filter(document=doc).order_by("-created")
         ]
 
     @action(methods=["get", "post", "delete"], detail=True)
-    def comments(self, request, pk=None):
+    def notes(self, request, pk=None):
         try:
             doc = Document.objects.get(pk=pk)
         except Document.DoesNotExist:
@@ -469,17 +469,17 @@ class DocumentViewSet(
 
         if request.method == "GET":
             try:
-                return Response(self.getComments(doc))
+                return Response(self.getNotes(doc))
             except Exception as e:
-                logger.warning(f"An error occurred retrieving comments: {str(e)}")
+                logger.warning(f"An error occurred retrieving notes: {str(e)}")
                 return Response(
-                    {"error": "Error retreiving comments, check logs for more detail."},
+                    {"error": "Error retreiving notes, check logs for more detail."},
                 )
         elif request.method == "POST":
             try:
-                c = Comment.objects.create(
+                c = Note.objects.create(
                     document=doc,
-                    comment=request.data["comment"],
+                    note=request.data["note"],
                     user=currentUser,
                 )
                 c.save()
@@ -488,23 +488,23 @@ class DocumentViewSet(
 
                 index.add_or_update_document(self.get_object())
 
-                return Response(self.getComments(doc))
+                return Response(self.getNotes(doc))
             except Exception as e:
-                logger.warning(f"An error occurred saving comment: {str(e)}")
+                logger.warning(f"An error occurred saving note: {str(e)}")
                 return Response(
                     {
-                        "error": "Error saving comment, check logs for more detail.",
+                        "error": "Error saving note, check logs for more detail.",
                     },
                 )
         elif request.method == "DELETE":
-            comment = Comment.objects.get(id=int(request.GET.get("id")))
-            comment.delete()
+            note = Note.objects.get(id=int(request.GET.get("id")))
+            note.delete()
 
             from documents import index
 
             index.add_or_update_document(self.get_object())
 
-            return Response(self.getComments(doc))
+            return Response(self.getNotes(doc))
 
         return Response(
             {
@@ -516,14 +516,14 @@ class DocumentViewSet(
 class SearchResultSerializer(DocumentSerializer, PassUserMixin):
     def to_representation(self, instance):
         doc = Document.objects.get(id=instance["id"])
-        comments = ",".join(
-            [str(c.comment) for c in Comment.objects.filter(document=instance["id"])],
+        notes = ",".join(
+            [str(c.note) for c in Note.objects.filter(document=instance["id"])],
         )
         r = super().to_representation(doc)
         r["__search_hit__"] = {
             "score": instance.score,
             "highlights": instance.highlights("content", text=doc.content),
-            "comment_highlights": instance.highlights("comments", text=comments)
+            "note_highlights": instance.highlights("notes", text=notes)
             if doc
             else None,
             "rank": instance.rank,