Compare commits

...

110 Commits

Author SHA1 Message Date
Uwe Steinmann
ff4b3d7722 update release date 2025-02-27 13:47:53 +01:00
Uwe Steinmann
1c09c1ba4e fix getting uploaded files with PSR7 2025-01-02 17:15:12 +01:00
Uwe Steinmann
54d4d2c41a new version 1.4.0 2025-01-02 17:11:10 +01:00
Uwe Steinmann
6633e78ef8 lots of changes to be compatible with Slim 4 which was introduced 2025-01-02 17:10:52 +01:00
Uwe Steinmann
9ba5882aa9 works only till 5.1.36 and 6.0.29 2024-12-09 10:31:02 +01:00
Uwe Steinmann
feccb4ac65 add changes of 1.3.0 2024-12-09 10:27:00 +01:00
Uwe Steinmann
413877b537 update release date 2024-12-09 10:26:49 +01:00
Uwe Steinmann
4390b57036 slightly better phrasing 2024-12-09 10:17:09 +01:00
Uwe Steinmann
b7b3e20cf4 access container elements with get() add set them with set() 2024-12-09 10:16:33 +01:00
Uwe Steinmann
3fb56643ee add changes of 1.3.0 2024-11-27 17:19:25 +01:00
Uwe Steinmann
c8c5a789ae add method documentListRowExtraContent() for showing correspondent 2024-11-27 17:17:48 +01:00
Uwe Steinmann
7bc95887cb add search for rule 8 and 9 2024-11-11 14:58:13 +01:00
Uwe Steinmann
3a73820fee add translation for rule 8 and 9 2024-11-11 14:57:51 +01:00
Uwe Steinmann
caf2e49d3b add page with list of stored views 2024-11-11 14:42:18 +01:00
Uwe Steinmann
0ee9bfee6b start new version 1.3.0 2024-11-11 14:41:10 +01:00
Uwe Steinmann
eef4f46687 fix typos 2024-07-16 13:30:10 +02:00
Uwe Steinmann
a551ea2587 minor fixes and more information on token generation 2024-07-16 13:28:13 +02:00
Uwe Steinmann
38326621a1 need to get fulltext index first before searching 2024-07-16 09:37:14 +02:00
Uwe Steinmann
4aee2e9e3b new version 1.2.3 2024-07-16 08:42:14 +02:00
Uwe Steinmann
8b642f78b1 check if fulltext search is turned on 2024-07-16 08:41:57 +02:00
Uwe Steinmann
0eb85b8ebe one sentence what this extension is for 2024-04-23 08:54:18 +02:00
Uwe Steinmann
aafd65f26f add example for public demo 2024-04-23 08:51:55 +02:00
Uwe Steinmann
1ad48e50b5 example for credentials 2024-04-23 08:51:03 +02:00
Uwe Steinmann
75f4be229c update release date 2024-04-23 08:49:14 +02:00
Uwe Steinmann
afecdf2205 log folder name and id when uploading a document 2024-03-20 20:30:43 +01:00
Uwe Steinmann
8fa420114b new version 1.2.2, change in api 2024-03-15 10:45:19 +01:00
Uwe Steinmann
5df36d9487 fix typo in description 2023-12-21 17:26:55 +01:00
Uwe Steinmann
b18bedd004 new version 1.2.1 2023-11-03 16:43:55 +01:00
Uwe Steinmann
f68dd2e483 implement /api/documents/{id}/ 2023-11-03 16:42:28 +01:00
Uwe Steinmann
04cddbcee6 new version 1.2.0 2023-10-11 16:39:55 +02:00
Uwe Steinmann
1bf93e420c add more tests 2023-10-11 16:39:16 +02:00
Uwe Steinmann
e2b20688fe allow to set correspondent 2023-10-11 16:38:32 +02:00
Uwe Steinmann
8fd2a12ed8 fix line indenting 2023-10-11 16:37:56 +02:00
Uwe Steinmann
8ba45f3346 add saving views, get list of storage path from folder hierarchie 2023-10-11 16:37:23 +02:00
Uwe Steinmann
fa97180c55 fix searching for documents in inbox 2023-10-11 16:36:06 +02:00
Uwe Steinmann
3fe6f6df3c searching for documents can be restricted by storage path 2023-10-11 16:35:03 +02:00
Uwe Steinmann
5e0b31bf95 do not create facets when searching, because it takes very long and they are not needed 2023-10-11 16:34:17 +02:00
Uwe Steinmann
9dfd05247f support searching for any correspondent and no correspondent 2023-10-11 16:32:39 +02:00
Uwe Steinmann
6395de766b add class SeedDMS_ExtPaperless_Process_Folder 2023-10-11 16:29:38 +02:00
Uwe Steinmann
aefd3b8807 views can now be updated 2023-10-11 16:28:49 +02:00
Uwe Steinmann
d5b5a1cb49 more about searching and storage paths 2023-10-11 16:28:22 +02:00
Uwe Steinmann
b7e1ca4ed9 new version 1.1.5 2023-10-10 12:32:49 +02:00
Uwe Steinmann
434cce5d0d log end of middleware 2023-10-10 12:31:18 +02:00
Uwe Steinmann
5ccec6a942 report api version 1.13.0 2023-10-10 12:30:54 +02:00
Uwe Steinmann
24d1dfa17d evaluate param 'original' when downloading a document 2023-10-10 12:30:25 +02:00
Uwe Steinmann
16fe475136 return more settings in call of ui_settings 2023-10-10 12:29:34 +02:00
Uwe Steinmann
5bc93c25d5 add some fold marks 2023-10-10 12:28:57 +02:00
Uwe Steinmann
043ed11f8c method 'api' returns mail_accounts and mail_rule 2023-10-10 12:28:24 +02:00
Uwe Steinmann
2440fd4e65 new version 1.1.4 2023-09-30 17:23:49 +02:00
Uwe Steinmann
e3c545ef36 add some more logging but commented it out 2023-09-30 17:23:28 +02:00
Uwe Steinmann
e916e6afb9 fix regression in searching documents 2023-09-30 12:51:58 +02:00
Uwe Steinmann
e9bcdf0d09 update release date 2023-09-13 08:09:57 +02:00
Uwe Steinmann
a5fb29c683 add changes for 1.1.3 2023-09-06 15:12:44 +02:00
Uwe Steinmann
fb84b8d282 set DOCID 2023-09-06 15:11:56 +02:00
Uwe Steinmann
60bbc32f04 convert documents to pdf when downloading and configured to do so 2023-09-06 15:11:20 +02:00
Uwe Steinmann
ce540d3e24 start version 1.1.3 2023-05-30 10:08:10 +02:00
Uwe Steinmann
1205b32572 background color of label must be named 'color' not 'colour' 2023-05-30 10:04:37 +02:00
Uwe Steinmann
6116bbfa4d return same error as paperless-ngx when login fails 2023-05-13 17:06:01 +02:00
Uwe Steinmann
62d6ab86c5 login and password can be passed as command line parameters 2023-05-13 17:05:31 +02:00
Uwe Steinmann
45af226bca update date release date 2023-05-11 16:32:47 +02:00
Uwe Steinmann
5c2ce7b0ac add changes for 1.1.2 2023-05-11 09:54:11 +02:00
Uwe Steinmann
1d9adf9b26 add phrase paperless_jwtsecret_not_set 2023-05-11 09:29:59 +02:00
Uwe Steinmann
ee6b5eb7c6 add filter by 'modified' 2023-05-11 09:29:40 +02:00
Uwe Steinmann
a13b19bf34 check if jwt secret is set and issue a warning if not 2023-05-11 09:28:48 +02:00
Uwe Steinmann
d07399d8b0 depend on seeddms 5.1.31 or 6.0.24 2023-05-02 17:50:10 +02:00
Uwe Steinmann
d5416f895a allow sorting by field 'modified' 2023-05-02 11:43:44 +02:00
Uwe Steinmann
5db8a70515 start new version 1.1.2 2023-05-02 10:15:20 +02:00
Uwe Steinmann
4f939feb68 support sorting by correspondent 2023-05-02 10:13:43 +02:00
Uwe Steinmann
6f3c87bf08 some minor corrections in comments 2023-05-02 08:23:59 +02:00
Uwe Steinmann
c4abcf98c0 set date of modification to date of latest version 2023-05-02 08:23:24 +02:00
Uwe Steinmann
10dddd8e7e new version 1.1.1 2023-04-20 12:05:00 +02:00
Uwe Steinmann
f50d74f710 add changes for 1.1.1 2023-04-20 10:44:12 +02:00
Uwe Steinmann
a74ec650af rename class.Paperless.php to class.PaperlessView.php
git diff
2023-04-20 10:43:19 +02:00
Uwe Steinmann
16ee0a8c49 log error when folder cannot be written 2023-04-15 16:56:53 +02:00
Uwe Steinmann
b50ddcdbb4 add note about how to test the extension 2023-03-30 08:38:54 +02:00
Uwe Steinmann
76d6be2a08 update release date, fix typo 2023-03-30 08:33:03 +02:00
Uwe Steinmann
9840153ff8 fix typo 2023-03-30 08:29:07 +02:00
Uwe Steinmann
72cc22e474 better documentation 2023-03-30 08:28:23 +02:00
Uwe Steinmann
210e8a04a9 add subsection for each app 2023-03-30 08:19:26 +02:00
Uwe Steinmann
687bb2e2b2 add links to f-droid and google play 2023-03-30 08:17:50 +02:00
Uwe Steinmann
fe4f527daa add example how the credentials look like 2023-03-30 07:16:14 +02:00
Uwe Steinmann
76399068dc adjust copyright and file header info 2023-03-30 07:13:29 +02:00
Uwe Steinmann
7b85496041 about section on how to install 2023-03-30 07:12:49 +02:00
Uwe Steinmann
48c474a815 next version is 1.1.0 because of so many changes 2023-03-15 18:21:15 +01:00
Uwe Steinmann
84742f6ab6 add more tests 2023-03-15 18:14:57 +01:00
Uwe Steinmann
2580c56a09 improve search for similar documents (extend or reduce the list of search terms) 2023-03-15 18:05:28 +01:00
Uwe Steinmann
16a3083f33 more documentation on similar document search 2023-03-15 18:05:01 +01:00
Uwe Steinmann
72471b96e3 add short note about seaching for similar documents 2023-03-15 14:25:30 +01:00
Uwe Steinmann
8011d515f9 add change for 1.0.1 2023-03-15 14:23:18 +01:00
Uwe Steinmann
6a84abb6ce search for similar docs 2023-03-15 14:23:03 +01:00
Uwe Steinmann
28d2e4dc4b add changes for 1.0.1 2023-03-09 17:32:44 +01:00
Uwe Steinmann
63539d9e07 return only released documents 2023-03-09 17:19:36 +01:00
Uwe Steinmann
19b5a670d7 fix passing attributes to search() of fulltext 2023-03-09 07:55:27 +01:00
Uwe Steinmann
b4199beed8 add info on document types and correspondents 2023-02-22 10:10:35 +01:00
Uwe Steinmann
ce5873027d add changes of 1.0.1 2023-02-21 13:10:50 +01:00
Uwe Steinmann
b1693b24c0 depend on 5.1.30 or 6.0.23 2023-02-21 13:10:23 +01:00
Uwe Steinmann
d578a7bc99 fix typo in 'documenttypesattr' 2023-02-21 13:09:19 +01:00
Uwe Steinmann
3f871b3b77 search for document types and correspondents 2023-02-21 13:08:46 +01:00
Uwe Steinmann
691bbcd689 fixed getting list of document types 2023-02-21 13:08:09 +01:00
Uwe Steinmann
2a19650419 set correspondent and document type in document data 2023-02-21 13:07:33 +01:00
Uwe Steinmann
af39f6fdf2 add changes for 1.0.1 2023-02-18 15:42:41 +01:00
Uwe Steinmann
9c3114634b add search for more_like_id and correpondent (not used yet) 2023-02-18 15:42:15 +01:00
Uwe Steinmann
26df6830c0 add config of attribute for document type, start version 1.0.1 2023-02-18 15:41:00 +01:00
Uwe Steinmann
68c706b6e6 get document types like correspondents from attribute 2023-02-18 15:39:37 +01:00
Uwe Steinmann
32aed7f3eb get correspondents from ->getStatistics() 2023-02-18 15:38:52 +01:00
Uwe Steinmann
1121532204 add route /api/statistics/ 2023-02-18 09:43:25 +01:00
Uwe Steinmann
ae0d06f1ef ordering by asn uses document id 2023-02-18 09:42:59 +01:00
Uwe Steinmann
59084a1ddd distinguish between rootfolder and startfolder 2023-02-18 09:37:23 +01:00
Uwe Steinmann
111e842645 archive serial number must be an int 2023-02-18 09:33:55 +01:00
Uwe Steinmann
959b8bea7d add initila support for correspondents 2023-02-08 20:47:58 +01:00
20 changed files with 1670 additions and 385 deletions

104
README.md
View File

@ -1,24 +1,32 @@
# SeedDMS paperless extension
This extension makes SeedDMS behave like a Paperless ngx server.
Paperless (and Paperless ngx) is another free document management system.
It has a different focus than SeedDMS and misses many of the features
of SeedDMS but there are three Android apps for uploading and browsing,
which can be used for SeedDMS as well, if this extension is installed.
All apps are available at google play and/or f-droid.
All apps are available at
[Google Play](https://play.google.com/store/apps) and/or [f-droid](https://f-droid.org/).
paperless-mobile
This is the youngest but most feature complete app. It has all
the features of both apps paperless and paperless-share.
### paperless-mobile
paperless
This one is already a couple of years around but development has
slowed down a bit. It supports listing and uploading documents.
This is the youngest but most feature complete app. It has all
the features of both apps paperless and paperless-share.
[Google Play](https://play.google.com/store/apps/details?id=eu.bauerj.paperless_app),
[f-droid](https://f-droid.org/packages/eu.bauerj.paperless_app/).
paperless-share
This app just adds a share button. Any shared document will
be uploaded to the server. Once the app was started it is mostly
invisible.
### paperless
This one is already a couple of years around but development has
slowed down a bit. It supports listing and uploading documents.
### paperless-share
This app just adds a share button. Any shared document will
be uploaded to the server. Once the app was started it is mostly
invisible.
## How it works
@ -28,6 +36,23 @@ and basic authentication of paperless. Because this middleware applies
to all routes of the rest api, even the existing routes may use
the new authentication methods.
## Installation
Install this extension like any other extension by uploading the
zip file in the extension manager or copy the content of this
repository into a directory `paperless` in SeedDMS' extension
directory `www/ext`.
Afterwards import one of the database files
* paperless.sql (MySQL)
* paperless-sqlite3.sql (SQLite3)
into your database.
You can test the extension by accessing `http://<your-seeddms>/restapi/index.php/api/`
with your browser. It should return a json object containing various links.
## Restrictions
The concept of paperless is quite different from SeedDMS. Fortunately,
@ -42,11 +67,13 @@ to setup fulltext search before using it.
### Authentication
Paperless uses a token based or http basic authentication. Both are
implemented by another slim middleware. There is no session, but the
token is encrypted and stores all the required data to identify the user.
The password to encrypt the token can be set in the configuration, just
like the expiration date of the token. Once the password changes all
token will become invalid and users will have to relogin.
implemented in SeedDMS by an additional slim middleware. There is no
session, but the token is encrypted and stores all the required data
to identify the user, including a lifetime which can be set in the
configuration. Once that lifetime has ended the token becomes invalid
and the user has to relogin. The password to encrypt the token can
also be set in the configuration. Once the password changes all token
will become invalid and users will have to relogin.
### Archive
@ -66,6 +93,20 @@ A category in SeedDMS does not have a color and cannot be marked as inbox tags.
SeedDMS deriveѕ the color from the category name and keeps a list of
categories, which are treated as inbox tags, in the configuration.
### Document Types
There is no direct equivalent to Document Types in SeedDMS, but they can
be easily simulated with a custom attribute. Since version 1.0.1 of this
extension the configuration contains a parameter for an attribute which
must be a value set containing the different document types. Do *not* make
it a multi value attribute, because a document in Paperless may have only
one type. Adding more types when you need it or changing the order is possible.
### Correspondents
Just like Document Types, there is a second attribute for correspondents.
It's implemented in SeedDMS just like document types.
## Folder hierachy
Paperless does not have folders. Consequently, SeedDMS disolves its folder
@ -75,4 +116,35 @@ upload folder. Moving documents at its right place must be done within SeedDMS.
Which documents are actually visible also depends on which root folder is used.
The root folder can be set in the configuration or can be the user's home folder.
Well, paperless seems to have a different concept called 'storage path'. Though
that's not like folder paths in SeedDMS but it's worth a try to map the both.
Since version 1.2.0 of this extension, there storage paths will resolve on folder
paths in SeedDMS.
## Searching for documents
The extension enforces any search to be limited to released documents.
## Searching for similar documents
There is some experimental support for searching for similar documents. This
is done by extracting the most frequent words from the content and using them
to issue a second query with this list of words. Since this list of most frequent
words can be very long it will be reduced. For a word to qualify for the
query
* it must be longer than 4 characters
* have a frequency greater 2
If less than five words meet these conditions, the list will be filled up with
subsequent words from the most frequent word list. If the than executed query
doesn't yield a result the list will be diminished again word by word until the
search succeeds or the query is empty.
## Changing meta data
The app paperless-mobile has support for editing meta data and even the content
of a document. Currently, this extension only supports editing the correspondent
and the tags of a document. All other changes made in paperless mobile we be
disregarded.

View File

@ -1,3 +1,85 @@
Changes in version 1.4.0
==========================
- lots of changes to be compatible with Slim 4 which was introduced
in SeedDMS 5.1.37 and 6.0.30
Changes in version 1.3.0
==========================
- use get() and set() to access elements of container
(in preparation for Slim4)
- add page for listing stored views
- show correspondent as badge in document list view
Changes in version 1.2.3
==========================
- better check for fulltext index, issue warning in settings if fulltext
search is turned off
Changes in version 1.2.2
==========================
- requires SeedDMS 5.1.34 or 6.0.27
Changes in version 1.2.1
==========================
- implement /api/documents/{id}/
Changes in version 1.2.0
==========================
- add filtering 'not set' or 'any value' for correspondent
- editing meta data can set correspondent
- create list of storage paths from path of folders
- turn off facets in route 'statistics'
- saved views can be changed
- fix getting number of documents in inbox
Changes in version 1.1.5
==========================
- make it work with paperless mobile >=3.0.2
- fix downloading of original document
Changes in version 1.1.4
==========================
- fix regression in searching documents
Changes in version 1.1.3
==========================
- fix color of labels
- return json array with element `non_field_errors` when login with
token failed
- convert none pdf documents to pdf when downloading them (must be
configured)
Changes in version 1.1.2
==========================
- date of modification is taken from upload date of version
- add filtering by modification date
- support sorting by correspondent
- show warning on settings page if jwt secret is not set
Changes in version 1.1.1
==========================
- some more logging
- rename class.Paperless.php to class.PaperlessView.php
Changes in version 1.1.0
==========================
- add support for correspondents and document types
- use document id as archive serial number
- return only released documents
- add experimental support for searching for similar docs
Changes in version 1.0.0
==========================

View File

@ -2,22 +2,16 @@
/**
* Implementation of a paperless view
*
* @category DMS
* @package SeedDMS
* @license GPL2
* @subpackage paperless
* @license GPL3
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2023 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class to represent a paperless view
*
* @category DMS
* @package SeedDMS
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2022 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_PaperlessView { /* {{{ */
/**
@ -115,6 +109,10 @@ class SeedDMS_PaperlessView { /* {{{ */
return $this->_view;
} /* }}} */
public function setView($view) { /* {{{ */
$this->_view = $view;
} /* }}} */
/*
* Add a new to the database.
*
@ -128,6 +126,11 @@ class SeedDMS_PaperlessView { /* {{{ */
return false;
}
$this->_id = $db->getInsertID();
} else {
$queryStr = "UPDATE `tblPaperlessView` SET `view`=".$db->qstr(json_encode($this->_view))." WHERE `id`=".$this->_id;
if (!$db->getResult($queryStr)) {
return false;
}
}
return self::getInstance($this->_id, $this->_dms);

File diff suppressed because it is too large Load Diff

View File

@ -3,13 +3,13 @@ $EXT_CONF['paperless'] = array(
'title' => 'Paperless RestAPI',
'description' => 'This extension adds additional rest api routes to make it behave like a paperless server. Just use the regular paperless apps, .e.g paperless mobile to access SeedDMS.',
'disable' => false,
'version' => '1.0.0',
'releasedate' => '2023-02-05',
'version' => '1.4.0',
'releasedate' => '2025-02-27',
'author' => array('name'=>'Uwe Steinmann', 'email'=>'uwe@steinmann.cx', 'company'=>'MMK GmbH'),
'config' => array(
'rootfolder' => array(
'title'=>'Folder used as root folder',
'help'=>'This is the folder used as the base folder. Documens not below this folder will be not shown by the papeerless mobile app. Uploaded documents will be saved into this folder, unless the dedicated upload folder is set.',
'help'=>'This is the folder used as the base folder. Documens not below this folder will not be shown by the paperless mobile app. Uploaded documents will be saved into this folder, unless the dedicated upload folder is set.',
'type'=>'select',
'internal'=>'folders',
),
@ -26,7 +26,7 @@ $EXT_CONF['paperless'] = array(
),
'jwtsecret' => array(
'title'=>'Secret for JSON Web Token',
'help'=>'This is used for creating a token which is needed to authenticate by token',
'help'=>'This is used for creating a secret which is needed to authenticate by token',
'type'=>'password',
),
'tokenlivetime' => array(
@ -50,9 +50,30 @@ $EXT_CONF['paperless'] = array(
'options'=>['title'=>'Title', 'content'=>'Content'],
'allow_empty'=>true,
),
'correspondentsattr' => array(
'title'=>'Attribute for storing the correspondent',
'help'=>'This attribute stores the correspondent of a document and must have a list of correspondents.',
'type'=>'select',
'internal'=>'attributedefinitions',
'objtype'=>'2',
'allow_empty'=>true,
),
'documenttypesattr' => array(
'title'=>'Attribute for storing the document type',
'help'=>'This attribute stores the document type of a document and must have a list of types.',
'type'=>'select',
'internal'=>'attributedefinitions',
'objtype'=>'2',
'allow_empty'=>true,
),
'converttopdf' => array(
'title'=>'Convert to PDF',
'type'=>'checkbox',
'help'=>"Enable, if you want non pdf documents to be converted to PDF if they are downloaded. Usually, this is only done for preview.",
),
),
'constraints' => array(
'depends' => array('php' => '7.4.0-', 'seeddms' => array('5.1.29-5.1.99', '6.0.22-6.0.99')),
'depends' => array('php' => '7.4.0-', 'seeddms' => array('5.1.34-5.1.37', '6.0.30-6.0.99', '6.1.0-6.1.99')),
),
'icon' => 'icon.svg',
'changelog' => 'changelog.md',

View File

@ -1,18 +1,52 @@
<?php
$__lang['en_GB'] = array(
'paperless'=>'Paperless',
'paperless_upload_succeded'=>'Upload succeded',
'paperless_upload_failed'=>'Upload failed',
'paperless_missing_target_folder'=>'Missing target folder',
'paperless_no_files_uploaded'=>'No files uploaded',
'paperless_upload_maxsize'=>'Max file size exceeded',
'paperless_token_has_expired'=>'Token has expired. Login again before you proceed.',
'paperless_jwtsecret_not_set'=>'The secret for the JSON Web Token is not set. This is required for successful login.',
'paperless_needs_fulltextsearch'=>'The extension needs fulltext search to be on.',
'paperless_views'=>'Paperless',
'paperless_view_name'=>'Name',
'paperless_view_rules'=>'Rules',
'paperless_view_sort_by'=>'Sort by',
'paperless_view_dashboard'=>'Dashboard',
'paperless_view_sidebar'=>'Sidebar',
'paperless_view_rule_13'=>'Added until',
'paperless_view_rule_14'=>'Added from',
'paperless_view_rule_8'=>'Created until',
'paperless_view_rule_9'=>'Created from',
'paperless_view_rule_6'=>'Category',
'paperless_view_rule_3'=>'Correspondent',
'paperless_view_rule_19'=>'Title & Content',
'paperless_view_rule_20'=>'Advanced Search',
);
$__lang['de_DE'] = array(
'paperless'=>'Paperless',
'paperless_upload_succeded'=>'Erfolgreich hochgeladen',
'paperless_upload_failed'=>'Hochladen fehlgeschlagen',
'paperless_missing_target_folder'=>'Zielordner nicht vorhanden',
'paperless_no_files_uploaded'=>'Keine Dateien hochgeladen',
'paperless_upload_maxsize'=>'Maximale Dateigröße überschritten',
'paperless_token_has_expired'=>'Token abgelaufen. Melden Sie sich bitte neu an.',
'paperless_jwtsecret_not_set'=>'Das Geheimnis des JSON Web Token ist nicht gesetzt. Dies ist für eine erfolgreiche Anmeldung erforderlich.',
'paperless_needs_fulltextsearch'=>'Die Erweiterung erfordert eine konfigurierte Volltextsuche .',
'paperless_views'=>'Paperless',
'paperless_view_name'=>'Name',
'paperless_view_rules'=>'Regeln',
'paperless_view_sort_by'=>'Sortiere nach',
'paperless_view_dashboard'=>'Dashboard',
'paperless_view_sidebar'=>'Sidebar',
'paperless_view_rule_13'=>'Hinzugefügt bis',
'paperless_view_rule_14'=>'Hinzugefügt von',
'paperless_view_rule_8'=>'Ausgestellt bis',
'paperless_view_rule_9'=>'Ausgestellt von',
'paperless_view_rule_6'=>'Kategorie',
'paperless_view_rule_3'=>'Korrepondent',
'paperless_view_rule_19'=>'Titel & Inhalt',
'paperless_view_rule_20'=>'Erweiterte Suche',
);

View File

@ -0,0 +1,69 @@
<?php
/**
* MyDMS. Document Management System
* Copyright (C) 2002-2005 Markus Westphal
* Copyright (C) 2006-2008 Malcolm Cowe
* Copyright (C) 2010-2011 Matteo Lucarelli
* Copyright (C) 2010-2024 Uwe Steinmann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
if(!empty($_SERVER['SEEDDMS_HOME']))
require_once($_SERVER['SEEDDMS_HOME'].'/inc/inc.Settings.php');
else
require_once("../../../inc/inc.Settings.php");
require_once("inc/inc.Utils.php");
require_once("inc/inc.LogInit.php");
require_once("inc/inc.Language.php");
require_once("inc/inc.Init.php");
require_once("inc/inc.Extension.php");
require_once("inc/inc.DBInit.php");
require_once("inc/inc.ClassUI.php");
require_once("inc/inc.Authentication.php");
require_once('ext/paperless/class.PaperlessView.php');
$tmp = explode('.', basename($_SERVER['SCRIPT_FILENAME']));
$view = UI::factory($theme, $tmp[1], array('dms' => $dms, 'user' => $user));
$v = new SeedDMS_Version();
if($v->majorVersion() > 5) {
$accessop = new SeedDMS_AccessOperation($dms, $user, $settings);
if (!$accessop->check_view_access($view, $_GET)) {
UI::exitError(getMLText("admin_tools"), getMLText("access_denied"));
}
} else
$accessop = new SeedDMS_AccessOperation($dms, null, $user, $settings);
$pview = null;
if (isset($_GET["view"])) {
$pview = SeedDMS_PaperlessView::getInstance($_GET['view'], $dms);
}
if($view) {
$view->setParam('accessobject', $accessop);
$view->setParam('showtree', showtree());
$view->setParam('pview', $pview);
$view->setParam('fulltextservice', $fulltextservice);
$view->setParam('logger', $logger);
$view->setParam('conversionmgr', $conversionmgr);
$view->setParam('previewWidthList', $settings->_previewWidthList);
$view->setParam('previewconverters', $settings->_converters['preview']);
$view->setParam('timeout', $settings->_cmdTimeout);
$view($_GET);
exit;
}

View File

@ -1,5 +1,17 @@
Create a file credentials and define AUTH and URL in it.
URL is the base url of the restapi service. AUTH are the credentials
as pass in http header Authorization. It can be ab basic authentication,
a papeerless or a regular SeedDMS token.
# Testing the API
These scripts can be used to test almost all endpoints of the
paperless-ngx API.
In order to use them, create a file `credentials` and define `AUTH` and
`URL` in it. `URL` is the base url of the restapi service. `AUTH` contains
the credentials passed in the http header `Authorization`. It can be a basic
authentication, a paperless token or a regular SeedDMS key.
Example:
URL="http://my.seeddms.org/restapi/index.php"
AUTH="my seeddms api key"
#AUTH="Token <paperless token>"
#AUTH="Basic <credentials>"

14
tests/credentials.example Normal file
View File

@ -0,0 +1,14 @@
# Create a token by running `./test-token.sh login password`
URL="http://192.168.178.25:8000"
AUTH="Token fe34a1f210f561c3599641035c1bbcd2c2bbc8b3"
#URL="https://your-server/restapi/index.php"
#AUTH="your api key"
# Credentials for local seeddms uses Basic auth with admin:admin
URL="https://seeddms.steinmann.cx/restapi/index.php"
AUTH="Basic YWRtaW46YWRtaW4="
# Credentials for demo6 seeddms uses Basic auth with admin:admin
#URL="https://demo6.seeddms.org/restapi/index.php"
#AUTH="Basic YWRtaW46YWRtaW4="

7
tests/test-correspondents.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
. ./credentials
curl --silent "${URL}/api/correspondents/" -H "Authorization: ${AUTH}"
#| jq '.'

View File

@ -2,4 +2,6 @@
. ./credentials
curl -L --silent "${URL}/fetch/doc/23311" -H "Authorization: ${AUTH}" --output 23311.pdf
DOCID=22833
curl -L --silent "${URL}/fetch/doc/${DOCID}" -H "Authorization: ${AUTH}" --output ${DOCID}.pdf

View File

@ -0,0 +1,6 @@
#!/bin/sh
. ./credentials
curl --silent "${URL}/api/documents/?format=json&page=1&correspondent__isnull=0&page_size=15&ordering=-added" -H "Authorization: ${AUTH}"
#| jq '.'

6
tests/test-documents-like.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
. ./credentials
curl --silent "${URL}/api/documents/?format=json&more_like_id=19245&page=1&page_size=5&ordering=-added" -H "Authorization: ${AUTH}"
#| jq '.'

View File

@ -2,5 +2,6 @@
. ./credentials
curl --silent "${URL}/api/documents/?format=json&query=added:%5B-70%20day%20to%20now%5D&is_tagged=0&page=3&page_size=5&ordering=-added" -H "Authorization: ${AUTH}" | jq '.'
curl --silent "${URL}/api/documents/?format=json&_query=added:%5B-70%20day%20to%20now%5D&is_tagged=0&document_type__id=1&page=1&page_size=5&ordering=-added" -H "Authorization: ${AUTH}"
#| jq '.'
#curl --silent "${URL}/api/documents/?format=json&query=barbaradio&page=3&page_size=5&ordering=-added" -H "Authorization: ${AUTH}" | jq '.'

7
tests/test-documenttypes.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
. ./credentials
curl --silent "${URL}/api/document_types/" -H "Authorization: ${AUTH}"
#| jq '.'

10
tests/test-patch-saved-view.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
. ./credentials
curl --silent -X PATCH "${URL}/api/saved_views/" \
-H 'Content-Type: application/json' \
-H "Authorization: ${AUTH}" \
-d '{"id":0,"name":"autoview","username":"admin","password":"admin"}'
# | jq '.'

7
tests/test-storagepaths.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
. ./credentials
curl --silent "${URL}/api/storage_paths/" -H "Authorization: ${AUTH}"
#| jq '.'

View File

@ -2,7 +2,16 @@
. ./credentials
USERNAME="admin"
if [ -n "$1" ]; then
USERNAME=$1
fi
PASSWORD="admin"
if [ -n "$2" ]; then
PASSWORD=$2
fi
JSON="{\"username\":\"$USERNAME\",\"password\":\"$PASSWORD\"}"
curl --silent -X POST "${URL}/api/token/" \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"admin"}' | jq '.'
-d $JSON | jq '.'

6
tests/test-ui-settings.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
. ./credentials
curl --silent "${URL}/api/ui_settings/" -H "Authorization: ${AUTH}" | jq '.'

View File

@ -0,0 +1,363 @@
<?php
/**
* Implementation of PaperlessViews view
*
* @category DMS
* @package SeedDMS
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2017 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class which outputs the html page for PaperlessViews view
*
* @category DMS
* @package SeedDMS
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2017 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_View_PaperlessViews extends SeedDMS_Bootstrap_Style {
function js() { /* {{{ */
$dms = $this->params['dms'];
$user = $this->params['user'];
$onepage = $this->params['onepage'];
header('Content-Type: application/javascript');
parent::jsTranslations(array('cancel', 'splash_move_document', 'confirm_move_document', 'move_document', 'confirm_transfer_link_document', 'transfer_content', 'link_document', 'splash_move_folder', 'confirm_move_folder', 'move_folder'));
?>
$(document).ready(function() {
$('body').on('click', '.view', function(ev){
ev.preventDefault();
$('#paperless_view.ajax').trigger('update', {view: $(this).data('view')});
});
});
<?php
if($onepage) {
$this->printClickDocumentJs();
}
$this->printDeleteDocumentButtonJs();
} /* }}} */
protected function printListHeader($previewer, $order=false) { /* {{{ */
print "<table class=\"table table-condensed table-sm\">";
print "<thead>\n<tr>\n";
print "<th></th>\n";
if($order) {
$orderby = ''; //$this->params['orderby'];
$orderdir = ''; //$this->params['orderdir'];
print "<th><a data-action=\"".$order."\" data-orderby=\"n\" data-orderdir=\"".($orderdir == 'desc' ? '' : 'desc')."\">".getMLText("name")."</a> ".($orderby == 'n' || $orderby == '' ? ($orderdir == 'desc' ? '<i class="icon-arrow-up"></i>' : '<i class="icon-arrow-down"></i>') : '')." &middot; <a data-action=\"".$order."\" data-orderby=\"u\" data-orderdir=\"".($orderdir == 'desc' ? '' : 'desc')."\">".getMLText("last_update")."</a> ".($orderby == 'u' ? ($orderdir == 'desc' ? '<i class="icon-arrow-up"></i>' : '<i class="icon-arrow-down"></i>') : '')." &middot; <a data-action=\"".$order."\" data-orderby=\"e\" data-orderdir=\"".($orderdir == 'desc' ? '' : 'desc')."\">".getMLText("expires")."</a> ".($orderby == 'e' ? ($orderdir == 'desc' ? '<i class="icon-arrow-up"></i>' : '<i class="icon-arrow-down"></i>') : '')."</th>\n";
} else
print "<th>".getMLText("name")."</th>\n";
if($order)
print "<th><a data-action=\"".$order."\" data-orderby=\"s\" data-orderdir=\"".($orderdir == 'desc' ? '' : 'desc')."\">".getMLText("status")."</a>".($orderby == 's' ? " ".($orderdir == 'desc' ? '<i class="icon-arrow-up"></i>' : '<i class="icon-arrow-down"></i>') : '')."</th>\n";
else
print "<th>".getMLText("status")."</th>\n";
print "<th>".getMLText("action")."</th>\n";
print "</tr>\n</thead>\n<tbody>\n";
} /* }}} */
protected function printListFooter() { /* {{{ */
echo "</tbody>\n</table>";
} /* }}} */
private function getSearchParameter($data) { /* {{{ */
$dms = $this->params['dms'];
$user = $this->params['user'];
$settings = $this->params['settings'];
$categories = array();
$categorynames = array();
$astart = null;
$aend = null;
$mstart = null;
$mend = null;
$startfolder = $dms->getRootFolder();
$rootfolder = $dms->getRootFolder();
$cattrs = [];
$query = '';
foreach ($data['filter_rules'] as $rule) {
switch ($rule['rule_type']) {
case 3:
$correspondent = null;
if(!empty($settings->_extensions['paperless']['correspondentsattr']) && $attrdef = $dms->getAttributeDefinition($settings->_extensions['paperless']['correspondentsattr'])) {
$valueset = $attrdef->getValueSetAsArray();
if(isset($valueset[$rule['value']-1])) {
$correspondent = $valueset[$rule['value']-1];
$cattrs['attr_'.$attrdef->getId()] = $correspondent;
}
}
break;
case 6:
$catid = (int) $rule['value'];
if($catid) {
if($cat = $dms->getDocumentCategory($catid)) {
$categories[] = $cat;
$categorynames[] = $cat->getName();
}
}
break;
case 8:
$aend = makeTsFromDate($rule['value']);
break;
case 9:
$astart = makeTsFromDate($rule['value']);
break;
case 13:
$aend = makeTsFromDate($rule['value']);
break;
case 14:
$astart = makeTsFromDate($rule['value']);
break;
case 19:
$query = $rule['value'];
break;
case 20:
$tmp = explode(',', $rule['value']);
foreach ($tmp as $t) {
if (substr($t, 0, 9) == 'created:[') {
$q = substr($t, 9, -1);
if($x = explode(' to ', $q, 2)) {
$astart = strtotime($x[0]);
$aend = strtotime($x[1])+86400;
}
} elseif (substr($t, 0, 7) == 'added:[') {
$q = substr($t, 7, -1);
if($x = explode(' to ', $q, 2)) {
$astart = strtotime($x[0]);
$aend = strtotime($x[1])+86400;
}
} else {
$query = $t;
}
}
break;
}
}
return [$query, array('record_type'=>['document'], 'status'=>[2], 'user'=>[$user->getLogin()], 'category'=>$categorynames, 'created_start'=>$astart, 'created_end'=>$aend, 'modified_start'=>$mstart, 'modified_end'=>$mend, 'startFolder'=>$startfolder, 'rootFolder'=>$rootfolder, 'attributes'=>$cattrs)];
} /* }}} */
private function printList($data, $previewer) { /* {{{ */
$dms = $this->params['dms'];
$user = $this->params['user'];
$settings = $this->params['settings'];
$fulltextservice = $this->params['fulltextservice'];
$logger = $this->params['logger'];
$order = [];
$order['dir'] = $data['sort_reverse'] ? 'desc' : 'asc';
$orderfield = $data["sort_field"];
if(in_array($orderfield, ['modified', 'created', 'title']))
$order['by'] = $orderfield;
elseif($orderfield == 'added')
$order['by'] = 'created';
elseif($orderfield == 'archive_serial_number')
$order['by'] = 'id';
elseif($orderfield == 'correspondent__name') {
if(!empty($settings->_extensions['paperless']['correspondentsattr']) && $attrdef = $dms->getAttributeDefinition($settings->_extensions['paperless']['correspondentsattr'])) {
$order['by'] = 'attr_'.$attrdef->getId();
}
}
list($query, $searchparams) = $this->getSearchParameter($data);
if($fulltextservice && $index = $fulltextservice->Indexer()) {
$lucenesearch = $fulltextservice->Search();
$limit = 10;
$offset = 0;
$logger->log('Query is '.$query, PEAR_LOG_DEBUG);
/*
$logger->log('User is '.$userobj->getLogin(), PEAR_LOG_DEBUG);
$logger->log('limit is '.$limit, PEAR_LOG_DEBUG);
$logger->log('offset is '.$offset, PEAR_LOG_DEBUG);
*/
$searchresult = $lucenesearch->search($query, $searchparams, array('limit'=>$limit, 'offset'=>$offset), $order, array('no_facets'=>true));
if($searchresult) {
$recs = array();
$facets = $searchresult['facets'];
$dcount = 0;
$fcount = 0;
if($searchresult['hits']) {
$allids = '';
$this->printListHeader($previewer);
foreach($searchresult['hits'] as $hit) {
if($hit['document_id'][0] == 'D') {
if($document = $dms->getDocument((int) substr($hit['document_id'], 1))) {
$document->verifyLastestContentExpriry();
$v = new SeedDMS_Version();
if($v->majorVersion() > 5) {
$document->checkForDueRevisionWorkflow($user);
}
$lc = $document->getLatestContent();
if($document->getAccessMode($user) >= M_READ && $lc) {
$txt = $this->callHook('documentListItem', $document, $previewer, false, 'opentasks');
if(is_string($txt))
echo $txt;
else {
/*
$errormsg = '';
$errorcls = '';
if(!$doc['error']) {
} else {
$errorcls = $doc['error'] < 0 ? " error" : ($doc['error'] === 0 ? " success" : "");
$errormsg = $doc['error'];
}
*/
$extracontent = array();
$extracontent['below_title'] = $this->getListRowPath($document);
echo $this->documentListRowStart($document);
echo $this->documentListRow($document, $previewer, true, 0, $extracontent);
echo $this->documentListRowEnd($document);
}
}
}
}
}
$this->printListFooter();
$logger->log('Result is '.$allids, PEAR_LOG_DEBUG);
}
}
}
} /* }}} */
private function count($data) { /* {{{ */
$dms = $this->params['dms'];
$user = $this->params['user'];
$settings = $this->params['settings'];
$fulltextservice = $this->params['fulltextservice'];
$logger = $this->params['logger'];
list($query, $searchparams) = $this->getSearchParameter($data);
if($fulltextservice && $index = $fulltextservice->Indexer()) {
$lucenesearch = $fulltextservice->Search();
$limit = 10;
$offset = 0;
$logger->log('Query is '.$query, PEAR_LOG_DEBUG);
/*
$logger->log('User is '.$userobj->getLogin(), PEAR_LOG_DEBUG);
$logger->log('limit is '.$limit, PEAR_LOG_DEBUG);
$logger->log('offset is '.$offset, PEAR_LOG_DEBUG);
*/
$searchresult = $lucenesearch->search($query, $searchparams, array('limit'=>0, 'offset'=>0), [], array('no_facets'=>true));
if($searchresult) {
return $searchresult['count'];
}
}
return false;
} /* }}} */
public function list() { /* {{{ */
$dms = $this->params['dms'];
$user = $this->params['user'];
$settings = $this->params['settings'];
$pview = $this->params['pview'];
$cachedir = $this->params['cachedir'];
$conversionmgr = $this->params['conversionmgr'];
$previewwidth = $this->params['previewWidthList'];
$previewconverters = $this->params['previewconverters'];
$timeout = $this->params['timeout'];
$previewer = new SeedDMS_Preview_Previewer($cachedir, $previewwidth, $timeout);
if($conversionmgr)
$previewer->setConversionMgr($conversionmgr);
else
$previewer->setConverters($previewconverters);
if ($pview) {
$data = $pview->getView();
$this->printList($data, $previewer);
}
} /* }}} */
private function getFilterValue($rule) { /* {{{ */
$dms = $this->params['dms'];
$settings = $this->params['settings'];
switch($rule['rule_type']) {
case 13: // Added until
case 14: // Added from
return getReadableDate($rule['value']);
case 3: // Correspondent
if(!empty($settings->_extensions['paperless']['correspondentsattr']) && $attrdef = $dms->getAttributeDefinition($settings->_extensions['paperless']['correspondentsattr'])) {
$valueset = $attrdef->getValueSetAsArray();
if(isset($valueset[$rule['value']-1])) {
return $valueset[$rule['value']-1];
}
}
return '???';
break;
case 6: // Category
return $dms->getDocumentCategory($rule['value'])->getName();
break;
default:
return $rule['value'];
}
} /* }}} */
public function show() { /* {{{ */
$dms = $this->params['dms'];
$user = $this->params['user'];
$settings = $this->params['settings'];
$session = $this->params['session'];
$area = 'my_account';
$this->htmlStartPage(getMLText("paperless_views"), '', '../../');
$this->globalNavigation();
$this->contentStart();
$this->pageNavigation(getMLText($area), $area);
$this->contentHeading(getMLText("paperless_views"));
$this->rowStart();
$this->columnStart(4);
$views = SeedDMS_PaperlessView::getAllInstances($user, $dms);
if($views) {
print "<table id=\"paperlessviews-table\" class=\"table table-condensed table-sm table-hover\">";
print "<thead>\n<tr>\n";
print "<th>".getMLText("paperless_view_name")."</th>\n";
print "<th>".getMLText("paperless_view_rules")."</th>\n";
print "</tr>\n</thead>\n<tbody>\n";
foreach($views as $view) {
$data = $view->getView();
$c = $this->count($data);
echo "<tr class=\"view\" data-view=\"".$data['id']."\"><td><strong>".$data['name']." (".$c.")</strong>";
echo "<br>".getMLText('paperless_view_sort_by').": ".$data['sort_field'];
if ($data['show_on_dashboard']) {
echo "<br>".getMLText('paperless_view_dashboard').': <i class="fa fa-check"></i>';
}
if ($data['show_in_sidebar']) {
echo "<br>".getMLText('paperless_view_sidebar').': <i class="fa fa-check"></i>';
}
echo "</td>";
echo "<td>";
foreach ($data['filter_rules'] as $rule) {
echo getMLText('paperless_view_rule_'.$rule['rule_type']).": ".$this->getFilterValue($rule)."<br>";
}
// echo "<pre>";
// print_r($data);
// echo "</pre>";
echo "</td>";
echo "</tr>";
}
echo "</tbody>\n</table>\n";
} else {
$this->infoMsg(getMLText('upload_area_no_secret_info'));
}
$this->columnEnd();
$this->columnStart(8);
echo '<div id="paperless_view" class="ajax" data-base="ext/paperless/" data-view="PaperlessViews" data-action="list"></div>';
$this->columnEnd();
$this->rowEnd();
$this->contentEnd();
$this->htmlEndPage();
} /* }}} */
}