Compare commits

..

No commits in common. "master" and "6.0.15" have entirely different histories.

629 changed files with 46960 additions and 65007 deletions

View File

@ -3,6 +3,6 @@ root = true
[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
trim_trailing_whitespaces = true
indent_style = tab
indent_size = 2

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
*.tar.gz
SeedDMS_*/*.tgz
ext/*
webapp/*

View File

@ -6,10 +6,7 @@ Header set X-Content-Type-Options: "nosniff"
</IfModule>
RewriteEngine On
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
#RewriteRule "^favicon\.ico$" "-" [L]
#RewriteRule "^(favicon\.ico)$" %{HTTP_HOST}/views/bootstrap/images/favicon.svg [L,NC]
RewriteRule "^(favicon\.ico)" /views/bootstrap/images/favicon.svg [L,NC]
RewriteRule ^favicon.ico$ styles/bootstrap/favicon.ico [L]
# Store the current location in an environment variable CWD to use
# mod_rewrite in .htaccess files without knowing the RewriteBase
@ -26,16 +23,10 @@ RewriteRule "^views/.*/images.*$" "-" [L]
RewriteRule "^out/images.*$" "-" [L]
RewriteRule "^styles/.*$" "-" [L]
# Accessing a file in an extension is only possible in one
# of the directories op, out. res
# Accessing a file in an extension is always possible
# Added for old extensions which do not use routes
RewriteRule ^ext/[^/]+/icon.(?:png|svg)$ - [L]
RewriteCond %{REQUEST_URI} "ext/[^/]+/"
RewriteRule !^ext/[^/]+/.*(?:op|out|res|node_modules) - [F]
RewriteCond %{REQUEST_URI} "ext/[^/]+/res/.*$" [NC]
RewriteRule !^ext/[^/]+/res/.*\.(?:css|js|png|gif|svg|ico|html|woff|ttf) - [F]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ext/.*$ - [L]
RewriteRule "^ext/.*$" "-" [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

454
CHANGELOG
View File

@ -1,132 +1,3 @@
--------------------------------------------------------------------------------
Changes in version 6.0.33
--------------------------------------------------------------------------------
- merge changes up to 5.1.40
--------------------------------------------------------------------------------
Changes in version 6.0.32
--------------------------------------------------------------------------------
- merge changes up to 5.1.39
- fix setting attributes (user, group, document, folder) when checking in
a new document version
- validate setting revision date
--------------------------------------------------------------------------------
Changes in version 6.0.31
--------------------------------------------------------------------------------
- merge changes up to 5.1.38
- fix various restapi endpoints which hadn't been updated to slim4
--------------------------------------------------------------------------------
Changes in version 6.0.30
--------------------------------------------------------------------------------
- merge changes up to 5.1.37
- receipt comment can be disabled
- send request receipt notification only when document is released
--------------------------------------------------------------------------------
Changes in version 6.0.29
--------------------------------------------------------------------------------
- merge changes up to 5.1.36
- fix regression in FolderNotify
--------------------------------------------------------------------------------
Changes in version 6.0.28
--------------------------------------------------------------------------------
- merge changes up to 5.1.35
--------------------------------------------------------------------------------
Changes in version 6.0.27
--------------------------------------------------------------------------------
- merge changes up to 5.1.34
- Document/folder check distinguishes between documents which cannot be
receiped/revised because of access rights or the recipient/revisor being
disabled.
- fix creating user via rest api
- checkout info does not depend on whether the logged in user was substituted
- add new endpoints for managing roles by rest api
- add transmittals in menu
- add legacy access check for controllers
--------------------------------------------------------------------------------
Changes in version 6.0.26
--------------------------------------------------------------------------------
- merge changes up to 5.1.33
- add task to import files from drop folder
- add substitution of users in bootstrap4 theme
--------------------------------------------------------------------------------
Changes in version 6.0.25
--------------------------------------------------------------------------------
- merge changes up to 5.1.32
- status log can be turned on with advanced access control
- scheduler has more condensed layout
--------------------------------------------------------------------------------
Changes in version 6.0.24
--------------------------------------------------------------------------------
- add task to send list of recent changes by email
- merge changes up to 5.1.31
--------------------------------------------------------------------------------
Changes in version 6.0.23
--------------------------------------------------------------------------------
- fix setting recipients and revisors
- check in of a document is allowed for the user having done the check out
or those users with unlimited access rights on the document
- merge changes up to 5.1.30
--------------------------------------------------------------------------------
Changes in version 6.0.22
--------------------------------------------------------------------------------
- merge changes up to 5.1.29
--------------------------------------------------------------------------------
Changes in version 6.0.21
--------------------------------------------------------------------------------
- merge changes up to 5.1.28
- add new check for documents with identical sequence numbers in a folder
--------------------------------------------------------------------------------
Changes in version 6.0.20
--------------------------------------------------------------------------------
- merge changes up to 5.1.27
- fix triggering workflow (Closes: #542)
- create original file name from new document name when uploading document
from the library folder. Used to be the original file name
--------------------------------------------------------------------------------
Changes in version 6.0.19
--------------------------------------------------------------------------------
- merge changes up to 5.1.26
- fix deletion of tasks when using bootstrap4 theme
- fix deletion of documents when clicking on icon in document list (my documents)
--------------------------------------------------------------------------------
Changes in version 6.0.18
--------------------------------------------------------------------------------
- finish op/op.Cron.php, returns json
- merge changes up to 5.1.25
- fix sending trigger workflow notification (Closes: #522)
- fix updating und deleting items in document lists
- call hook 'filenameDownloadItem' in search export and transmittal download
- fix possible xss attack in UsrMgr (CVE-2022-28479)
--------------------------------------------------------------------------------
Changes in version 6.0.17
--------------------------------------------------------------------------------
- merge changes up to 5.1.24
- send notification when a receiption of a document was submitted
--------------------------------------------------------------------------------
Changes in version 6.0.16
--------------------------------------------------------------------------------
- cancel checkout needs confirmation
- add input field to filter list of recipients if more then 10
- add task for creating missing preview images
- no longer use old PHPExcel classes, use PhpOffice\PhpSpreadsheet\Spreadsheet
instead
--------------------------------------------------------------------------------
Changes in version 6.0.15
--------------------------------------------------------------------------------
@ -321,330 +192,6 @@
- add document list which can be exported as an archive
- search results can be exported
--------------------------------------------------------------------------------
Changes in version 5.1.40
--------------------------------------------------------------------------------
- fix saving user data when language selection is turned of (Closes: #568)
- add much better support for new storage drivers
- fix possible xss attacks
- saver way to collect plugin configuration
- fix update of postgres database
- add hook displayPreviewThumb
- add searching for mimetype in database
- list of expired documents can be filtered by user
- use quoted printable encoding instead of base64 for email subjects
--------------------------------------------------------------------------------
Changes in version 5.1.39
--------------------------------------------------------------------------------
- show quota on chart page when listing total document size per user
- turn off legend for chart sizepermonth
- do not add group manager as mandatory approver/reviewer if logged in
user is the manager itself
- fixed setting group approvers from previous document version
- very experimental support of memcached for accelerating some database
operations (do not use in production)
- prevent malicious manipulation of referer when setting language
- fix setting attributes of type user, group, document, folder when updating
a document
- objects can be removed from clipboard
- call hooks for document/folder list in attribute manager
--------------------------------------------------------------------------------
Changes in version 5.1.38
--------------------------------------------------------------------------------
- require php 8.2
- fix php error in out/out.ReviewSummary.php
--------------------------------------------------------------------------------
Changes in version 5.1.37
--------------------------------------------------------------------------------
- do not show chart by category if there are no categories
- documents in certain folders can be excluded from dashboard, could be useful
for folders containing archived documents
- migrate from Slim 3 to Slim 4 (check for extension updates)
- fix reloading more entries in list of folders/documents at end of page if
maxItemsPerPage is set
- prevent xss attack
- log level for rest api can be set separately
--------------------------------------------------------------------------------
Changes in version 5.1.36
--------------------------------------------------------------------------------
- add new page for send test notification
- remove deprecated function formatted_size()
- fix bugs when importing files from filesystem with metadata, better logging
- fix potential xss attack when showing log file
- support for different storage of documents (not yet used)
- do not treat repository url like a directory name (will no longer add a
directory seperator)
- use rename() on windows when moving an extension to its final destination
- fixed bug in AddDocument, approver group wasn't checked properly against
mandatory approvers
- email From-address in settings can be forced for all outgoing mail
- checking of ssl certificate for smtp can be turned off
- add chart for disk space per month
- clearing cache of js files works for a large number of files
- WebDAV returns `quota-used-bytes` and `quota-available-bytes`
- fix settings SeedDMS attributes in WebDAV server
- propperly check for duplicate folder names in op/op.Ajax.php
- add searching for file size (fulltext search)
--------------------------------------------------------------------------------
Changes in version 5.1.35
--------------------------------------------------------------------------------
- check access rights on EditDocumentFile and RemoveDocumentFile
- allow to set expiration dates in the past again
- fix authentication with ldap if AD is used
- fix progress bar in list of users if quota is active
- field storing email in ldap can be configured
--------------------------------------------------------------------------------
Changes in version 5.1.34
--------------------------------------------------------------------------------
- introduce global reviewer/approver
- group managers can be used as mandatory reviewers/approvers for all
users of that group
- update sabre/dav to 4.*
- show parent folder of document in lists of documents (calendar, dashboard)
- documents can be updated by dragging a file on a document list item
- dragging a folder on a folder list item oder the drag and drop area will
recursively upload the folder hierarchy including all files
- fix checking if user is owner when sending notifications
- do not show fast upload area if access on folder is insufficient
- do not send notification mail 'submitted review/approval' to owner of
document, still send it to uploader of version
- set default language in login form if language selector is turned off
- do not show full list of notifiers to none admins
- do not list document/folders in sequence selector if its number exceeds 50
- typeahead menu works with arrow keys again, wait 1 sec. before searching
- fix sending notification mails when document/folder was moved
- tasks and clipboard can be shown in main menu, even if there are no tasks
due or the clipboard is empty
- add conversion service from text/html to text/plain
--------------------------------------------------------------------------------
Changes in version 5.1.33
--------------------------------------------------------------------------------
- use SeedDMS_Core_File::mimetype() to determine mime type when uploading a
file with drag&drop
- user images may be 300px height, do not scale them up
- do not show unreadable documents on Dashboard
- fix creating preview image of file in drop folder if it contains
special chars
- show fileѕ and folders in dropfolder dir recursively
- fix 'Add to clipboard' menu item in bootstrap theme
- open confirm box when changing category in batch operation
- hidden users can excluded when setting list of reviewers/approvers
- extension can add a legacy access right
- check if document version may be removed
- set max file size for indexing when updating a document
- nicer output on info page
- do not show filter for categories in database search if they don't exist
- show logs of finished worflows
- show preview of documents on clipboard
- minor improvements in restapi
- update layout of tab for attachments
- remove session when calling logout of restapi
- fix some potential security issues
--------------------------------------------------------------------------------
Changes in version 5.1.32
--------------------------------------------------------------------------------
- check error msg after calling AddDocument and UpdateDocument controller
in webdav module
- more verbose log messages
- show errors of none activated extensions and do not allow to activate it,
if there are errors (e.g. missing php extensions)
- move Approve/ReviewDocument in a controller
- setting password by user can be disabled
- groups from ldap can be synced with seeddms groups
- fix error when sending notification to group of reviewers
- seperate some notification messages for folders and documents
- fix various drag&drop operations
- do not sent notifidation mail to uploader if owner has received on already
--------------------------------------------------------------------------------
Changes in version 5.1.31
--------------------------------------------------------------------------------
- rest api returns error msg and not just http status
- comment of document, documentcontent and folder can be rendered as
markdown
- fix preview for file in drop folder
- fix export of search result
- use openssl instead of mcrypt
- search form shows 'from' and 'to' field for integers and floats
- show preview of document in EditAttributes page
- major overhaul of fulltext search, add new search tab for a more
facetted based search
- add initial version of Dashboard
- default public status of attachments can be configured
--------------------------------------------------------------------------------
Changes in version 5.1.30
--------------------------------------------------------------------------------
- conversion from pdf to png replaces alpha channel with white
- add list of conversion services in debug menu of admin tool
- use chosen select for custom attributes
- color category (use first 6 chars of md5(category name) as hex color)
- create missing preview images in category or attribute manager
- support README of extension in different languages
- do not force password change if in substitute user mode
--------------------------------------------------------------------------------
Changes in version 5.1.29
--------------------------------------------------------------------------------
- fix php errors in restapi
- fix 'maximum size' error when uploading a file with drag&drop
- update jquery to 3.6.1 (only bootstrap4 theme)
- introduce authentication service
- new hook in restapi to add middleware
- previews for png, txt, pdf in different directories. This will
enforce a recreation of all cached preview images, pdf and text files!
- various improvements of fulltext service
- show number of documents per category in category manager
- show number of keywords per category in keyword manager
- improve drag&drop with clipboard
- old pear packages SeedDMS/Core, SeedDMS/Lucene, SeedDMS/Preview
are now based on composer and has moved into vendor dir
--------------------------------------------------------------------------------
Changes in version 5.1.28
--------------------------------------------------------------------------------
- user information in user manager failed to load when a document content
with 0 bytes was created by the user
- fix repair of wrong file extension
- fix regression in password forgotten function
- fix security issue when creating hash in password forgotten operation
- add initial support for logging and notifications in rest api
- add rest api calls to get attributes of a document version and to set
attributes of folders, documents, and document versions
- fixed various errors in swagger.yaml
- use methods in inc/inc.ClassNotificationService.php for webdav
- clear login failures when login by webdav succeeds
- output log of restapi in LogManagement
- new hook to add more tabs for sections in LogManagement
- rest api returns version attributes as 'version_attributes' (was
'version-attributes'), each attribute also contains the name
- new hook in rest api to add more routes in extensions
- uploaded several documents at once by fast upload will assign random
sequence number to allow manually sorting the documents afterwards
- fix counting of login failures if both ldap and db authentication is done
--------------------------------------------------------------------------------
Changes in version 5.1.27
--------------------------------------------------------------------------------
- fix adding new attribute definition if object type is 'all'
- EmptyFolder runs callbacks to remove objects from index and remove preview images
- skip internal conversion service for images if imagick extension is missing
- running the controller will always call the hooks preRun and postRun
- add tabs on ViewFolder page
- link behind logo in header can be set in extension
- move attributes for documents and folders on search page into own accordion
- search page uses conversion mgr for preview images
- backport export of search result from seeddms 6.0.x
- ldap authentication used 'uid' instead 'cn' in distinguished name if
the initial bind failed and a second bind with the user's credentials
is done
- fix sorting in search result
- import of users can handle hidden and disabled flag
- image conversion falls back to gd library if imagick extension is not loaded
--------------------------------------------------------------------------------
Changes in version 5.1.26
--------------------------------------------------------------------------------
- add hook additionalDocumentContentInfo
- add restapi function 'statstotal'
- custom attributes of type 'date' regard the date format
- check extension dependency on shell commands
- log reason for notification
- add list of notification services
- clicking on the file selection button no longer submits the form in firefox
- fix clear clipboard link in menu
- add conversion service from tiff, gif to png
- do not use logger in notification service if it was not initialized
- fix editing of custom date fields
- fix listing files/folders with umlauts when using webdav
- fix upload with fine-uploader
--------------------------------------------------------------------------------
Changes in version 5.1.25
--------------------------------------------------------------------------------
- certain fields in configuration can be disabled for editing, also works for
configuration fields of extensions
- send notification mail to owner of document and uploader of a version
- new mail body for changing a version comment
- add hook documentListPreview
- various improvements for workflows
- output splash message when removing, editing, adding a category or keyword
- extensions cannot be disabled/enabled if configuration file is not writeable
- prevent cross site scripting in views/bootstrap/class.DefaultKeywords.php (CVE-2022-28051)
- fix possible DoS in op/op.RemoveLog.php (CVE-2022-28478)
- show only calendar events of logged in user
- show expired documents in calendar
- call new hook 'cleanUpDocument' after uploading or updating a document
- pass 'add' or 'update' to hook 'addDocumentContentFile'
- more access restrictions on files in extensions
- fix check of extensions available in repository
--------------------------------------------------------------------------------
Changes in version 5.1.24
--------------------------------------------------------------------------------
- fix sending of some notification mails to groups
- major overhaul of notifications
- check view access for FolderAccess and DocumentAccess
- more settings to disable import and download of extensions
- add new configuration for excluding sequence and comment when creating
a folder
- get zendframework from pkgist
- auto generate path if not set in settings.xml
- add document conversion service
- send request email for next workflow step only if that step is actually reached
- send mails to owner of document/folder only if not logged in or already
in list of notifiers
- improve fulltext search
- improve validation of change password form
- better error checking if uploading or adding a document failed due to
size limits
--------------------------------------------------------------------------------
Changes in version 5.1.23
--------------------------------------------------------------------------------
- output path of parent folder in many document/folder lists
- list affected documents when transfering processes to another user
- check for quota and duplicate content in restapi
- remove preview images before removing document
- fixed error due to multiple declared function when controller method
RemoveFolder::run was called more than once
- fix php error setting mandatory workflow when uploading documents via webdav
- typeahead search for folders can search in subfolders
- new theme based on bootstrap 4, including many improvements on small displays
- propperly check for translation of html email body (Closes: #510)
- set mandatory group reviewer/approver when adding a new document or version
- fix sending notification mails to group when uploading document via drag&drop
- guest login can use any user account
- issue warning if document cannot be approved/reviewed anymore, because it has
expired
- much better form validation based on jquery validation
- secure unlocking/locking of a documents with form token to prevent CSRF attacks
- append referuri to base url to prevent redirects to arbitraty sites in op.Login.php
- theme can be set in user manager
- fields in configuration can be omitted from display and saving
- comment of document version may not be modified when document has expired
- attributes of document version may be edited if enableVersionModification is true
even if the document has been released, obsoleted or has been expired
- reviews and approvals can be removed by admin
- links are all created absolute based on _httpRoot instead of relative to
the current page. This fixes a potential security hole cased by malformed
links.
- add chart with number of folders per document
- add number of links, attachments, versions of a selected user in the user
manager
- add support for drag and drop of attachments
- show all folders in tree when selecting a target folder for move operations
even if they are not writable, otherwise sub folders may not appear in the
tree, because parent folders are not writable
--------------------------------------------------------------------------------
Changes in version 5.1.22
--------------------------------------------------------------------------------
@ -798,7 +345,6 @@
- pass configuration to init() of extension (backport from 6.0.x)
- place comment of version below version data (remove extra column, backport from 6.0.x)
- fix creating folders via restapi (Closes: #469)
- custom attributes of type date show up in the calendar
--------------------------------------------------------------------------------
Changes in version 5.1.15

View File

@ -1,10 +1,7 @@
module.exports = function (grunt) {
'use strict';
// if you set bootstrapDir to views/bootstrap/vendors then make sure
// bootbox is not installed, because version 5 of bootbox will not work
// with bootstrap 2
var bootstrapDir = 'views/bootstrap4/vendors',
var bootstrapDir = 'views/bootstrap/vendors',
tdkDir = 'views/tdk/vendors',
nodeDir = 'node_modules';
@ -74,13 +71,6 @@ module.exports = function (grunt) {
],
dest: bootstrapDir + '/select2/js',
flatten: true
},{
expand: true,
src: [
nodeDir + '/select2/dist/js/i18n/*'
],
dest: bootstrapDir + '/select2/js/i18n',
flatten: true
},{
expand: true,
src: [
@ -88,20 +78,6 @@ module.exports = function (grunt) {
],
dest: bootstrapDir + '/select2/css',
flatten: true
},{
expand: true,
src: [
nodeDir + '/@ttskch/select2-bootstrap4-theme/dist/*'
],
dest: bootstrapDir + '/select2-bootstrap4-theme',
flatten: true
},{
expand: true,
src: [
nodeDir + '/vis-timeline/dist/*'
],
dest: bootstrapDir + '/vis-timeline',
flatten: true
},{
expand: true,
src: [
@ -116,20 +92,6 @@ module.exports = function (grunt) {
],
dest: bootstrapDir + '/jquery-validation',
flatten: true
},{
expand: true,
src: [
nodeDir + '/jquery-typeahead/dist/*'
],
dest: bootstrapDir + '/jquery-typeahead',
flatten: true
},{
expand: true,
src: [
nodeDir + '/bootbox/dist/*'
],
dest: bootstrapDir + '/bootbox',
flatten: true
},{
expand: true,
src: [
@ -183,13 +145,6 @@ module.exports = function (grunt) {
],
dest: bootstrapDir + '/moment/locale',
flatten: true
},{
expand: true,
src: [
nodeDir + '/popper.js/dist/umd/*'
],
dest: bootstrapDir + '/popper',
flatten: true
},{
expand: true,
src: [
@ -197,30 +152,6 @@ module.exports = function (grunt) {
],
dest: bootstrapDir + '/perfect-scrollbar',
flatten: true
},{
expand: true,
src: [
nodeDir + '/bootstrap/dist/js/bootstrap.min.js',
nodeDir + '/bootstrap/dist/css/bootstrap.min.css'
],
dest: bootstrapDir + '/bootstrap',
flatten: true
},{
expand: true,
src: [
nodeDir + '/spectrum-colorpicker2/dist/spectrum.min.js',
nodeDir + '/spectrum-colorpicker2/dist/spectrum.min.css'
],
dest: bootstrapDir + '/spectrum-colorpicker2',
flatten: true
},{
expand: true,
src: [
nodeDir + '/jquery-lazy/jquery.lazy.min.js',
nodeDir + '/jquery-lazy/jquery.lazy.plugins.js'
],
dest: bootstrapDir + '/jquery-lazy',
flatten: true
},{
expand: true,
src: [

View File

@ -1,8 +1,8 @@
VERSION=$(shell php -r 'include("inc/inc.Version.php"); $$v=new SeedDMS_Version(); echo $$v->version();')
SRC=CHANGELOG inc conf utils index.php .htaccess languages op out controllers doc TODO LICENSE webdav install restapi pdfviewer
VIEWS ?= bootstrap bootstrap4
VIEWS ?= bootstrap
NODISTFILES=utils/importmail.php utils/seedddms-importmail utils/remote-email-upload utils/remote-upload utils/da-bv-reminder.php utils/seeddms-da-bv-reminder utils/relodge.php utils/seeddms-relodge .svn .gitignore
NODISTFILES=utils/importmail.php utils/seedddms-importmail utils/remote-email-upload utils/remote-upload utils/da-bv-reminder.php utils/seeddms-da-bv-reminder .svn .gitignore
PHPDOC=~/Downloads/phpDocumentor.phar
@ -23,12 +23,6 @@ dist:
(cd tmp; tar --exclude=.svn --exclude=.gitignore -czvf ../seeddms-$(VERSION).tar.gz seeddms-$(VERSION))
rm -rf tmp
quickstart:
php7.4 vendor/bin/phing -Dversion=$(VERSION) package
unittest:
vendor/bin/phing -Dversion=$(VERSION) phpunitfast
pear:
(cd SeedDMS_Core/; pear package)
(cd SeedDMS_Lucene/; pear package)
@ -62,37 +56,7 @@ repository:
doc:
$(PHPDOC) -d SeedDMS_Core --ignore 'getusers.php,getfoldertree.php,config.php,reverselookup.php' --force -t html
# Download apigen with
# composer create-project --no-dev apigen/apigen:^7.0@alpha tools/apigen
apidoc:
tools/apigen/bin/apigen SeedDMS_Core/Core --exclude "tests/*" --output html
apigen generate -s SeedDMS_Core --exclude tests -d html
# Turn the package.xml file into CHANGELOG.md
#
# The idea is to form blocks of lines separated by an empty line.
# Echo block consists of the version number, release date und notes.
# This blocks are turned into single lines which are than sorted.
# Afterwards the single lines are turned back into blocks.
#
# It first uses sgrep to extract the version, date und notes. This is
# feed to sed to isolated the date and version and put them on separate
# lines. Each version
# forms a block of n lines with the first two being the version and date.
# All remaining lines are notes. Blocks are separated by an empty line.
# It's important to form blocks without ane empty lines because the following
# awk will create a single line from each block which can then be sorted
# (or simply reversed in order).
# Because the blocks are listed in the wrong order (last version first and
# previous version last, e.g. 5.1.29, 3.3.0, 3.3.1, ...., 5.1.27, 5.1.28) they
# need to be reversed in order. This is done by turning each block into line
# with the former new lines replaced by a '|'. So it's basically a '|' separated
# csv file which is then reversed in order by 'sort -r'. In order to separate
# blocks by a newline, each line of that output is appended by another
# line break. Result is put back
# into the original format by replacing all '|' by newline.
#
PKGFILE=SeedDMS_Core/package.xml
changelog:
@sgrep 'stag("DATE") .. etag("DATE") or ((stag("RELEASE") .. etag("RELEASE")) in (stag("VERSION") .. etag("VERSION"))) or inner(stag("NOTES") __ etag("NOTES"))' ${PKGFILE} | sed -e 's#^ *<date>\([-0-9]*\)</date><release>\([0-9.preRC]*\)</release>#\n\n\2 (\1)\n---------------------#' | awk -F'\n' -vRS='' -vOFS='|' '{$$1=$$1}1' | sort -V -r | sed 's/$$/\n/' | tr '|' '\n'
.PHONY: doc webdav webapp repository changelog
.PHONY: doc webdav webapp repository

108
SeedDMS_Core/Core.php Normal file
View File

@ -0,0 +1,108 @@
<?php
/**
* Implementation of a document in the document management system
*
* @category DMS
* @package SeedDMS_Core
* @license GPL2
* @author Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
* Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
* 2010 Matteo Lucarelli, 2010-2012 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* @uses SeedDMS_DatabaseAccess
*/
define('USE_PDO', 1);
if(defined('USE_PDO'))
require_once('Core/inc.DBAccessPDO.php');
else
require_once('Core/inc.DBAccess.php');
/**
* @uses SeedDMS_DMS
*/
require_once('Core/inc.ClassDMS.php');
/**
* @uses SeedDMS_Decorator
*/
require_once('Core/inc.ClassDecorator.php');
/**
* @uses SeedDMS_Object
*/
require_once('Core/inc.ClassObject.php');
/**
* @uses SeedDMS_Folder
*/
require_once('Core/inc.ClassFolder.php');
/**
* @uses SeedDMS_Document
*/
require_once('Core/inc.ClassDocument.php');
/**
* @uses SeedDMS_Attribute
*/
require_once('Core/inc.ClassAttribute.php');
/**
* @uses SeedDMS_Group
*/
require_once('Core/inc.ClassGroup.php');
/**
* @uses SeedDMS_User
*/
require_once('Core/inc.ClassUser.php');
/**
* @uses SeedDMS_KeywordCategory
*/
require_once('Core/inc.ClassKeywords.php');
/**
* @uses SeedDMS_DocumentCategory
*/
require_once('Core/inc.ClassDocumentCategory.php');
/**
* @uses SeedDMS_Notification
*/
require_once('Core/inc.ClassNotification.php');
/**
* @uses SeedDMS_UserAccess
* @uses SeedDMS_GroupAccess
*/
require_once('Core/inc.ClassAccess.php');
/**
* @uses SeedDMS_Workflow
*/
require_once('Core/inc.ClassWorkflow.php');
/**
*/
require_once('Core/inc.AccessUtils.php');
/**
* @uses SeedDMS_File
*/
require_once('Core/inc.FileUtils.php');
/**
* @uses SeedDMS_Transmittal
*/
require_once('Core/inc.ClassTransmittal.php');
/**
* @uses SeedDMS_File
*/
require_once('Core/inc.ClassIterator.php');
?>

View File

@ -0,0 +1,88 @@
<?php
/**
* Some definitions for access control
*
* @category DMS
* @package SeedDMS_Core
* @license GPL 2
* @version @version@
* @author Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal,
* 2006-2008 Malcolm Cowe, 2010 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Used to indicate that a search should return all
* results in the ACL table. See {@link SeedDMS_Core_Folder::getAccessList()}
*/
define("M_ANY", -1);
/**
* No rights at all
*/
define("M_NONE", 1);
/**
* Read access only
*/
define("M_READ", 2);
/**
* Read and write access only
*/
define("M_READWRITE", 3);
/**
* Unrestricted access
*/
define("M_ALL", 4);
define ("O_GTEQ", ">=");
define ("O_LTEQ", "<=");
define ("O_EQ", "=");
/**
* Folder notification
*/
define("T_FOLDER", 1); //TargetType = Folder
/**
* Document notification
*/
define("T_DOCUMENT", 2); // " = Document
/**
* Notify on all actions on the folder/document
*/
define("N_ALL", 0);
/**
* Notify when object has been deleted
*/
define("N_DELETE", 1);
/**
* Notify when object has been moved
*/
define("N_MOVE", 2);
/**
* Notify when object has been updated (no new version)
*/
define("N_UPDATE", 3);
/**
* Notify when document has new version
*/
define("N_NEW_VERSION", 4);
/**
* Notify when version of document was deleted
*/
define("N_DELETE_VERSION", 5);
/**
* Notify when version of document was deleted
*/
define("N_ADD_DOCUMENT", 6);

View File

@ -0,0 +1,122 @@
<?php
/**
* Implementation of user and group access object
*
* @category DMS
* @package SeedDMS_Core
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
* 2010 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class to represent a user access right.
* This class cannot be used to modify access rights.
*
* @category DMS
* @package SeedDMS_Core
* @author Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
* 2010 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Core_UserAccess { /* {{{ */
/**
* @var SeedDMS_Core_User
*/
var $_user;
/**
* @var
*/
var $_mode;
/**
* SeedDMS_Core_UserAccess constructor.
* @param $user
* @param $mode
*/
function __construct($user, $mode) {
$this->_user = $user;
$this->_mode = $mode;
}
/**
* @return int
*/
function getUserID() { return $this->_user->getID(); }
/**
* @return mixed
*/
function getMode() { return $this->_mode; }
/**
* @return bool
*/
function isAdmin() {
return ($this->_mode == SeedDMS_Core_User::role_admin);
}
/**
* @return SeedDMS_Core_User
*/
function getUser() {
return $this->_user;
}
} /* }}} */
/**
* Class to represent a group access right.
* This class cannot be used to modify access rights.
*
* @category DMS
* @package SeedDMS_Core
* @author Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe, 2010 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Core_GroupAccess { /* {{{ */
/**
* @var SeedDMS_Core_Group
*/
var $_group;
/**
* @var
*/
var $_mode;
/**
* SeedDMS_Core_GroupAccess constructor.
* @param $group
* @param $mode
*/
function __construct($group, $mode) {
$this->_group = $group;
$this->_mode = $mode;
}
/**
* @return int
*/
function getGroupID() { return $this->_group->getID(); }
/**
* @return mixed
*/
function getMode() { return $this->_mode; }
/**
* @return SeedDMS_Core_Group
*/
function getGroup() {
return $this->_group;
}
} /* }}} */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
<?php
/**
* Implementation of the decorator pattern
*
* @category DMS
* @package SeedDMS_Core
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class which implements a simple decorator pattern
*
* @category DMS
* @package SeedDMS_Core
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Core_Decorator {
protected $o;
public function __construct($object) {
$this->o = $object;
}
public function __call($method, $args)
{
if (!method_exists($this->o, $method)) {
throw new Exception("Undefined method $method attempt.");
}
/* In case the called method returns the object itself, then return this object */
$result = call_user_func_array(array($this->o, $method), $args);
return $result === $this->o ? $this : $result;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,120 @@
<?php
/**
* Implementation of document categories in the document management system
*
* @category DMS
* @package SeedDMS_Core
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class to represent a document category in the document management system
*
* @category DMS
* @package SeedDMS_Core
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C)2011 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Core_DocumentCategory {
/**
* @var integer $_id id of document category
* @access protected
*/
protected $_id;
/**
* @var string $_name name of category
* @access protected
*/
protected $_name;
/**
* @var object $_dms reference to dms this category belongs to
* @access protected
*/
protected $_dms;
function __construct($id, $name) { /* {{{ */
$this->_id = $id;
$this->_name = $name;
$this->_dms = null;
} /* }}} */
function setDMS($dms) { /* {{{ */
$this->_dms = $dms;
} /* }}} */
function getID() { return $this->_id; }
function getName() { return $this->_name; }
function setName($newName) { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "UPDATE `tblCategory` SET `name` = ".$db->qstr($newName)." WHERE `id` = ". $this->_id;
if (!$db->getResult($queryStr))
return false;
$this->_name = $newName;
return true;
} /* }}} */
function isUsed() { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "SELECT * FROM `tblDocumentCategory` WHERE `categoryID`=".$this->_id;
$resArr = $db->getResultArray($queryStr);
if (is_array($resArr) && count($resArr) == 0)
return false;
return true;
} /* }}} */
function remove() { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "DELETE FROM `tblCategory` WHERE `id` = " . $this->_id;
if (!$db->getResult($queryStr))
return false;
return true;
} /* }}} */
function getDocumentsByCategory($limit=0, $offset=0) { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "SELECT * FROM `tblDocumentCategory` where `categoryID`=".$this->_id;
if($limit && is_numeric($limit))
$queryStr .= " LIMIT ".(int) $limit;
if($offset && is_numeric($offset))
$queryStr .= " OFFSET ".(int) $offset;
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && !$resArr)
return false;
$documents = array();
foreach ($resArr as $row) {
if($doc = $this->_dms->getDocument($row["documentID"]))
array_push($documents, $doc);
}
return $documents;
} /* }}} */
function countDocumentsByCategory() { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "SELECT COUNT(*) as `c` FROM `tblDocumentCategory` where `categoryID`=".$this->_id;
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && !$resArr)
return false;
return $resArr[0]['c'];
} /* }}} */
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,624 @@
<?php
/**
* Implementation of the group object in the document management system
*
* @category DMS
* @package SeedDMS_Core
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
* 2010 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class to represent a user group in the document management system
*
* @category DMS
* @package SeedDMS_Core
* @author Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe, 2010 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Core_Group { /* {{{ */
/**
* The id of the user group
*
* @var integer
*/
protected $_id;
/**
* The name of the user group
*
* @var string
*/
protected $_name;
/**
* @var SeedDMS_Core_User[]
*/
protected $_users;
/**
* The comment of the user group
*
* @var string
*/
protected $_comment;
/**
* Back reference to DMS this user group belongs to
*
* @var SeedDMS_Core_DMS
*/
protected $_dms;
function __construct($id, $name, $comment) { /* {{{ */
$this->_id = $id;
$this->_name = $name;
$this->_comment = $comment;
$this->_dms = null;
} /* }}} */
/**
* Return an instance of a group object
*
* @param string|integer $id Id, name of group, depending
* on the 3rd parameter.
* @param SeedDMS_Core_DMS $dms instance of dms
* @param string $by search by group name if set to 'name'.
* Search by Id of group if left empty.
* @return SeedDMS_Core_Group|bool instance of class SeedDMS_Core_Group if group was
* found, null if group was not found, false in case of error
*/
public static function getInstance($id, $dms, $by='') { /* {{{ */
$db = $dms->getDB();
switch($by) {
case 'name':
$queryStr = "SELECT * FROM `tblGroups` WHERE `name` = ".$db->qstr($id);
break;
default:
$queryStr = "SELECT * FROM `tblGroups` WHERE `id` = " . (int) $id;
}
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false)
return false;
else if (count($resArr) != 1) //wenn, dann wohl eher 0 als > 1 ;-)
return null;
$resArr = $resArr[0];
$group = new self($resArr["id"], $resArr["name"], $resArr["comment"]);
$group->setDMS($dms);
return $group;
} /* }}} */
/**
* @param $orderby
* @param SeedDMS_Core_DMS $dms
* @return array|bool
*/
public static function getAllInstances($orderby, $dms) { /* {{{ */
$db = $dms->getDB();
switch($orderby) {
default:
$queryStr = "SELECT * FROM `tblGroups` ORDER BY `name`";
}
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false)
return false;
$groups = array();
for ($i = 0; $i < count($resArr); $i++) {
$group = new self($resArr[$i]["id"], $resArr[$i]["name"], $resArr[$i]["comment"]);
$group->setDMS($dms);
$groups[$i] = $group;
}
return $groups;
} /* }}} */
/**
* Check if this object is of type 'group'.
*
* @param string $type type of object
*/
public function isType($type) { /* {{{ */
return $type == 'group';
} /* }}} */
/**
* @param SeedDMS_Core_DMS $dms
*/
function setDMS($dms) { /* {{{ */
$this->_dms = $dms;
} /* }}} */
/**
* @return SeedDMS_Core_DMS $dms
*/
function getDMS() {
return $this->_dms;
}
/**
* @return int
*/
function getID() { return $this->_id; }
/**
* @return string
*/
function getName() { return $this->_name; }
/**
* @param $newName
* @return bool
*/
function setName($newName) { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "UPDATE `tblGroups` SET `name` = ".$db->qstr($newName)." WHERE `id` = " . $this->_id;
if (!$db->getResult($queryStr))
return false;
$this->_name = $newName;
return true;
} /* }}} */
/**
* @return string
*/
function getComment() { return $this->_comment; }
/**
* @param $newComment
* @return bool
*/
function setComment($newComment) { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "UPDATE `tblGroups` SET `comment` = ".$db->qstr($newComment)." WHERE `id` = " . $this->_id;
if (!$db->getResult($queryStr))
return false;
$this->_comment = $newComment;
return true;
} /* }}} */
/**
* @return SeedDMS_Core_User[]|bool
*/
function getUsers() { /* {{{ */
$db = $this->_dms->getDB();
if (!isset($this->_users)) {
$queryStr = "SELECT `tblUsers`.* FROM `tblUsers` ".
"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
"WHERE `tblGroupMembers`.`groupID` = '". $this->_id ."'";
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false)
return false;
$this->_users = array();
$classnamerole = $this->_dms->getClassname('role');
$classname = $this->_dms->getClassname('user');
foreach ($resArr as $row) {
/** @var SeedDMS_Core_User $user */
$role = $classnamerole::getInstance($row['role'], $this->_dms);
$user = new $classname($row["id"], $row["login"], $row["pwd"], $row["fullName"], $row["email"], $row["language"], $row["theme"], $row["comment"], $role, $row['hidden']);
$user->setDMS($this->_dms);
array_push($this->_users, $user);
}
}
return $this->_users;
} /* }}} */
/**
* @return SeedDMS_Core_User[]|bool
*/
function getManagers() { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "SELECT `tblUsers`.* FROM `tblUsers` ".
"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
"WHERE `tblGroupMembers`.`groupID` = '". $this->_id ."' AND `tblGroupMembers`.`manager` = 1";
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false)
return false;
$managers = array();
$classnamerole = $this->_dms->getClassname('role');
$classname = $this->_dms->getClassname('user');
foreach ($resArr as $row) {
/** @var SeedDMS_Core_User $user */
$role = $classnamerole::getInstance($row['role'], $this->_dms);
$user = new $classname($row["id"], $row["login"], $row["pwd"], $row["fullName"], $row["email"], $row["language"], $row["theme"], $row["comment"], $role, $row['hidden']);
$user->setDMS($this->_dms);
array_push($managers, $user);
}
return $managers;
} /* }}} */
/**
* @param SeedDMS_Core_User $user
* @param bool $asManager
* @return bool
*/
function addUser($user,$asManager=false) { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "INSERT INTO `tblGroupMembers` (`groupID`, `userID`, `manager`) VALUES (".$this->_id.", ".$user->getID(). ", " . ($asManager?"1":"0") ." )";
$res = $db->getResult($queryStr);
if (!$res) return false;
unset($this->_users);
return true;
} /* }}} */
/**
* @param SeedDMS_Core_User $user
* @return bool
*/
function removeUser($user) { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "DELETE FROM `tblGroupMembers` WHERE `groupID` = ".$this->_id." AND `userID` = ".$user->getID();
$res = $db->getResult($queryStr);
if (!$res) return false;
unset($this->_users);
return true;
} /* }}} */
/**
* Check if user is member of group
*
* @param SeedDMS_Core_User $user user to be checked
* @param boolean $asManager also check whether user is manager of group if
* set to true, otherwise does not care about manager status
* @return boolean true if user is member, otherwise false
*/
function isMember($user,$asManager=false) { /* {{{ */
if (isset($this->_users)&&!$asManager) {
foreach ($this->_users as $usr)
if ($usr->getID() == $user->getID())
return true;
return false;
}
$db = $this->_dms->getDB();
if ($asManager) $queryStr = "SELECT * FROM `tblGroupMembers` WHERE `groupID` = " . $this->_id . " AND `userID` = " . $user->getID() . " AND `manager` = 1";
else $queryStr = "SELECT * FROM `tblGroupMembers` WHERE `groupID` = " . $this->_id . " AND `userID` = " . $user->getID();
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false) return false;
if (count($resArr) != 1) return false;
return true;
} /* }}} */
/**
* Toggle manager status of user
*
* @param SeedDMS_Core_User $user
* @return boolean true if operation was successful, otherwise false
*/
function toggleManager($user) { /* {{{ */
$db = $this->_dms->getDB();
if (!$this->isMember($user)) return false;
if ($this->isMember($user,true)) $queryStr = "UPDATE `tblGroupMembers` SET `manager` = 0 WHERE `groupID` = ".$this->_id." AND `userID` = ".$user->getID();
else $queryStr = "UPDATE `tblGroupMembers` SET `manager` = 1 WHERE `groupID` = ".$this->_id." AND `userID` = ".$user->getID();
if (!$db->getResult($queryStr)) return false;
return true;
} /* }}} */
/**
* Delete user group
* This function deletes the user group and all it references, like access
* control lists, notifications, as a child of other groups, etc.
*
* @param SeedDMS_Core_User $user the user doing the removal (needed for entry in
* review log.
* @return boolean true on success or false in case of an error
*/
function remove($user) { /* {{{ */
$db = $this->_dms->getDB();
$db->startTransaction();
$queryStr = "DELETE FROM `tblGroupMembers` WHERE `groupID` = " . $this->_id;
if (!$db->getResult($queryStr)) {
$db->rollbackTransaction();
return false;
}
$queryStr = "DELETE FROM `tblACLs` WHERE `groupID` = " . $this->_id;
if (!$db->getResult($queryStr)) {
$db->rollbackTransaction();
return false;
}
$queryStr = "DELETE FROM `tblNotify` WHERE `groupID` = " . $this->_id;
if (!$db->getResult($queryStr)) {
$db->rollbackTransaction();
return false;
}
$queryStr = "DELETE FROM `tblMandatoryReviewers` WHERE `reviewerGroupID` = " . $this->_id;
if (!$db->getResult($queryStr)) {
$db->rollbackTransaction();
return false;
}
$queryStr = "DELETE FROM `tblMandatoryApprovers` WHERE `approverGroupID` = " . $this->_id;
if (!$db->getResult($queryStr)) {
$db->rollbackTransaction();
return false;
}
$queryStr = "DELETE FROM `tblWorkflowTransitionGroups` WHERE `groupid` = " . $this->_id;
if (!$db->getResult($queryStr)) {
$db->rollbackTransaction();
return false;
}
$queryStr = "DELETE FROM `tblGroups` WHERE `id` = " . $this->_id;
if (!$db->getResult($queryStr)) {
$db->rollbackTransaction();
return false;
}
// TODO : update document status if reviewer/approver has been deleted
$reviewStatus = $this->getReviewStatus();
foreach ($reviewStatus as $r) {
$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
"VALUES ('". $r["reviewID"] ."', '-2', 'Review group removed from process', ".$db->getCurrentDatetime().", '". $user->getID() ."')";
$res=$db->getResult($queryStr);
if(!$res) {
$db->rollbackTransaction();
return false;
}
}
$approvalStatus = $this->getApprovalStatus();
foreach ($approvalStatus as $a) {
$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
"VALUES ('". $a["approveID"] ."', '-2', 'Approval group removed from process', ".$db->getCurrentDatetime().", '". $user->getID() ."')";
$res=$db->getResult($queryStr);
if(!$res) {
$db->rollbackTransaction();
return false;
}
}
$receiptStatus = $this->getReceiptStatus();
foreach ($receiptStatus as $r) {
$queryStr = "INSERT INTO `tblDocumentReceiptLog` (`receiptID`, `status`, `comment`, `date`, `userID`) ".
"VALUES ('". $r["receiptID"] ."', '-2', 'Recipients group removed from process', ".$db->getCurrentDatetime().", '". $user->getID() ."')";
$res=$db->getResult($queryStr);
if(!$res) {
$db->rollbackTransaction();
return false;
}
}
$revisionStatus = $this->getRevisionStatus();
foreach ($revisionStatus as $r) {
$queryStr = "INSERT INTO `tblDocumentRevisionLog` (`revisionID`, `status`, `comment`, `date`, `userID`) ".
"VALUES ('". $r["revisionID"] ."', '-2', 'Revisors group removed from process', ".$db->getCurrentDatetime().", '". $user->getID() ."')";
$res=$db->getResult($queryStr);
if(!$res) {
$db->rollbackTransaction();
return false;
}
}
$db->commitTransaction();
return true;
} /* }}} */
function getReviewStatus($documentID=null, $version=null) { /* {{{ */
$db = $this->_dms->getDB();
if (!$db->createTemporaryTable("ttreviewid")) {
return false;
}
$status = array();
// See if the group is assigned as a reviewer.
$queryStr = "SELECT `tblDocumentReviewers`.*, `tblDocumentReviewLog`.`status`, ".
"`tblDocumentReviewLog`.`comment`, `tblDocumentReviewLog`.`date`, ".
"`tblDocumentReviewLog`.`userID` ".
"FROM `tblDocumentReviewers` ".
"LEFT JOIN `tblDocumentReviewLog` USING (`reviewID`) ".
"LEFT JOIN `ttreviewid` on `ttreviewid`.`maxLogID` = `tblDocumentReviewLog`.`reviewLogID` ".
"WHERE `ttreviewid`.`maxLogID`=`tblDocumentReviewLog`.`reviewLogID` ".
($documentID==null ? "" : "AND `tblDocumentReviewers`.`documentID` = '". (int) $documentID ."' ").
($version==null ? "" : "AND `tblDocumentReviewers`.`version` = '". (int) $version ."' ").
"AND `tblDocumentReviewers`.`type`='1' ".
"AND `tblDocumentReviewers`.`required`='". $this->_id ."' ";
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false)
return false;
if (count($resArr)>0) {
foreach ($resArr as $res)
$status[] = $res;
}
return $status;
} /* }}} */
function getApprovalStatus($documentID=null, $version=null) { /* {{{ */
$db = $this->_dms->getDB();
if (!$db->createTemporaryTable("ttapproveid")) {
return false;
}
$status = array();
// See if the group is assigned as an approver.
$queryStr = "SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
"`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
"`tblDocumentApproveLog`.`userID` ".
"FROM `tblDocumentApprovers` ".
"LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
"LEFT JOIN `ttapproveid` on `ttapproveid`.`maxLogID` = `tblDocumentApproveLog`.`approveLogID` ".
"WHERE `ttapproveid`.`maxLogID`=`tblDocumentApproveLog`.`approveLogID` ".
($documentID==null ? "" : "AND `tblDocumentApprovers`.`documentID` = '". (int) $documentID ."' ").
($version==null ? "" : "AND `tblDocumentApprovers`.`version` = '". (int) $version ."' ").
"AND `tblDocumentApprovers`.`type`='1' ".
"AND `tblDocumentApprovers`.`required`='". $this->_id ."' ";
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false)
return false;
if (count($resArr)>0) {
foreach ($resArr as $res)
$status[] = $res;
}
return $status;
} /* }}} */
function getReceiptStatus($documentID=null, $version=null) { /* {{{ */
$db = $this->_dms->getDB();
$status = array();
// See if the group is assigned as a recipient.
$queryStr = "SELECT `tblDocumentRecipients`.*, `tblDocumentReceiptLog`.`status`, ".
"`tblDocumentReceiptLog`.`comment`, `tblDocumentReceiptLog`.`date`, ".
"`tblDocumentReceiptLog`.`userID` ".
"FROM `tblDocumentRecipients` ".
"LEFT JOIN `tblDocumentReceiptLog` USING (`receiptID`) ".
"WHERE `tblDocumentRecipients`.`type`='1' ".
($documentID==null ? "" : "AND `tblDocumentRecipients`.`documentID` = '". (int) $documentID ."' ").
($version==null ? "" : "AND `tblDocumentRecipients`.`version` = '". (int) $version ."' ").
"AND `tblDocumentRecipients`.`required`='". $this->_id ."' ";
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false)
return false;
if (count($resArr)>0) {
foreach ($resArr as $res) {
if(isset($status["status"][$res['documentID']])) {
if($status["status"][$res['documentID']]['date'] < $res['date']) {
$status["status"][$res['documentID']] = $res;
}
} else {
$status["status"][$res['documentID']] = $res;
}
}
}
return $status;
} /* }}} */
function getRevisionStatus($documentID=null, $version=null) { /* {{{ */
$db = $this->_dms->getDB();
$status = array();
if (!$db->createTemporaryTable("ttcontentid")) {
return false;
}
// See if the group is assigned as a revisor.
$queryStr = "SELECT `tblDocumentRevisors`.*, `tblDocumentRevisionLog`.`status`, ".
"`tblDocumentRevisionLog`.`comment`, `tblDocumentRevisionLog`.`date`, ".
"`tblDocumentRevisionLog`.`userID` ".
"FROM `tblDocumentRevisors` ".
"LEFT JOIN `tblDocumentRevisionLog` USING (`revisionID`) ".
"LEFT JOIN `ttcontentid` ON `ttcontentid`.`maxVersion` = `tblDocumentRevisors`.`version` AND `ttcontentid`.`document` = `tblDocumentRevisors`.`documentID` ".
"WHERE `tblDocumentRevisors`.`type`='1' ".
($documentID==null ? "" : "AND `tblDocumentRevisors`.`documentID` = '". (int) $documentID ."' ").
($version==null ? "" : "AND `tblDocumentRevisors`.`version` = '". (int) $version ."' ").
($documentID==null && $version==null ? "AND `ttcontentid`.`maxVersion` = `tblDocumentRevisors`.`version` " : "").
"AND `tblDocumentRevisors`.`required`='". $this->_id ."' ".
"ORDER BY `tblDocumentRevisionLog`.`revisionLogID` DESC";
$resArr = $db->getResultArray($queryStr);
if ($resArr === false)
return false;
if (count($resArr)>0) {
$status['status'] = array();
foreach ($resArr as $res) {
if($res['date']) {
if(isset($status["status"][$res['documentID']])) {
if($status["status"][$res['documentID']]['date'] < $res['date']) {
$status["status"][$res['documentID']] = $res;
}
} else {
$status["status"][$res['documentID']] = $res;
}
}
}
}
return $status;
} /* }}} */
/**
* Get a list of documents with a workflow
*
* @param int $documentID optional document id for which to retrieve the
* reviews
* @param int $version optional version of the document
* @return bool|array list of all workflows
*/
function getWorkflowStatus($documentID=null, $version=null) { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = 'select distinct d.*, c.`groupid` from `tblWorkflowTransitions` a left join `tblWorkflows` b on a.`workflow`=b.`id` left join `tblWorkflowTransitionGroups` c on a.`id`=c.`transition` left join `tblWorkflowDocumentContent` d on b.`id`=d.`workflow` where d.`document` is not null and a.`state`=d.`state` and c.`groupid`='.$this->_id;
if($documentID) {
$queryStr .= ' AND d.`document`='.(int) $documentID;
if($version)
$queryStr .= ' AND d.`version`='.(int) $version;
}
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false)
return false;
$result = array();
if (count($resArr)>0) {
foreach ($resArr as $res) {
$result[] = $res;
}
}
return $result;
} /* }}} */
/**
* Get all notifications of group
*
* @param integer $type type of item (T_DOCUMENT or T_FOLDER)
* @return SeedDMS_Core_Notification[]|bool array of notifications
*/
function getNotifications($type=0) { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "SELECT `tblNotify`.* FROM `tblNotify` ".
"WHERE `tblNotify`.`groupID` = ". $this->_id;
if($type) {
$queryStr .= " AND `tblNotify`.`targetType` = ". (int) $type;
}
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && !$resArr)
return false;
$notifications = array();
foreach ($resArr as $row) {
$not = new SeedDMS_Core_Notification($row["target"], $row["targetType"], $row["userID"], $row["groupID"]);
$not->setDMS($this->_dms);
array_push($notifications, $not);
}
return $notifications;
} /* }}} */
} /* }}} */

View File

@ -0,0 +1,231 @@
<?php
namespace SeedDMS;
/**
* Implementation of the document iterartor
*
* @category DMS
* @package SeedDMS_Core
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
class DocumentIterator implements \Iterator {
/**
* @var object folder
*/
protected $_folder;
/**
* @var object dms
*/
protected $_dms;
/**
* @var array documents
*/
protected $_documents;
public function __construct($folder) {
$this->_folder = $folder;
$this->_dms = $folder->getDMS();
$this->_documents = array();
$this->_pointer = 0;
$this->_cache = array();
$this->populate();
}
public function rewind() {
$this->_pointer = 0;
}
public function valid() {
return isset($this->_documents[$this->_pointer]);
}
public function next() {
$this->_pointer++;
}
public function key() {
return $this->_folders[$this->_pointer];
}
public function current() {
if($this->_documents[$this->_pointer]) {
$documentid = $this->_documents[$this->_pointer]['id'];
if(!isset($this->_cache[$documentid])) {
// echo $documentid." not cached<br />";
$this->_cache[$documentid] = $this->_dms->getdocument($documentid);
}
return $this->_cache[$documentid];
}
return null;
}
private function populate($orderby="", $dir="asc", $limit=0, $offset=0) { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "SELECT `id` FROM `tblDocuments` WHERE `folder` = " . $this->_folder->getID();
if ($orderby && $orderby[0]=="n") $queryStr .= " ORDER BY `name`";
elseif ($orderby && $orderby[0]=="s") $queryStr .= " ORDER BY `sequence`";
elseif ($orderby && $orderby[0]=="d") $queryStr .= " ORDER BY `date`";
if($dir == 'desc')
$queryStr .= " DESC";
if(is_int($limit) && $limit > 0) {
$queryStr .= " LIMIT ".$limit;
if(is_int($offset) && $offset > 0)
$queryStr .= " OFFSET ".$offset;
}
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false)
return false;
$this->_documents = $resArr;
} /* }}} */
}
class FolderIterator implements \Iterator { /* {{{ */
/**
* @var object folder
*/
protected $_folder;
/**
* @var object dms
*/
protected $_dms;
/**
* @var array documents
*/
protected $_folders;
public function __construct($folder) { /* {{{ */
$this->_folder = $folder;
$this->_dms = $folder->getDMS();
$this->_folders = array();
$this->_pointer = 0;
$this->_cache = array();
$this->populate();
} /* }}} */
public function rewind() { /* {{{ */
$this->_pointer = 0;
} /* }}} */
public function valid() { /* {{{ */
return isset($this->_folders[$this->_pointer]);
} /* }}} */
public function next() { /* {{{ */
$this->_pointer++;
} /* }}} */
public function key() { /* {{{ */
return $this->_folders[$this->_pointer];
} /* }}} */
public function current() { /* {{{ */
if($this->_folders[$this->_pointer]) {
$folderid = $this->_folders[$this->_pointer]['id'];
if(!isset($this->_cache[$folderid])) {
// echo $folderid." not cached<br />";
$this->_cache[$folderid] = $this->_dms->getFolder($folderid);
}
return $this->_cache[$folderid];
}
return null;
} /* }}} */
private function populate($orderby="", $dir="asc", $limit=0, $offset=0) { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "SELECT `id` FROM `tblFolders` WHERE `parent` = " . $this->_folder->getID();
if ($orderby && $orderby[0]=="n") $queryStr .= " ORDER BY `name`";
elseif ($orderby && $orderby[0]=="s") $queryStr .= " ORDER BY `sequence`";
elseif ($orderby && $orderby[0]=="d") $queryStr .= " ORDER BY `date`";
if($dir == 'desc')
$queryStr .= " DESC";
if(is_int($limit) && $limit > 0) {
$queryStr .= " LIMIT ".$limit;
if(is_int($offset) && $offset > 0)
$queryStr .= " OFFSET ".$offset;
}
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false)
return false;
$this->_folders = $resArr;
} /* }}} */
} /* }}} */
/**
* The FolderFilterIterator checks if the given user has access on
* the current folder.
* FilterIterator uses an inner iterator passed to the constructor
* to iterate over the sub folders of a folder.
*
$iter = new FolderIterator($folder);
$iter2 = new FolderFilterIterator($iter, $user);
foreach($iter2 as $ff) {
echo $ff->getName()."<br />";
}
*/
class FolderFilterIterator extends \FilterIterator { /* {{{ */
public function __construct(Iterator $iterator , $filter ) {
parent::__construct($iterator);
$this->userFilter = $filter;
}
public function accept() { /* {{{ */
$folder = $this->getInnerIterator()->current();
echo "accept() for ".$folder->getName()."<br />";
return true;
} /* }}} */
} /* }}} */
/**
$iter = new RecursiveFolderIterator($folder);
$iter2 = new RecursiveIteratorIterator($iter, RecursiveIteratorIterator::SELF_FIRST);
foreach($iter2 as $ff) {
echo $ff->getID().': '.$ff->getName()."<br />";
}
*/
class RecursiveFolderIterator extends FolderIterator implements \RecursiveIterator { /* {{{ */
public function hasChildren() { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "SELECT id FROM `tblFolders` WHERE `parent` = ".(int) $this->current()->getID();
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && !$resArr)
return false;
return true;
} /* }}} */
public function getChildren() { /* {{{ */
return new RecursiveFolderIterator($this->current());
} /* }}} */
} /* }}} */
class RecursiveFolderFilterIterator extends FolderFilterIterator { /* {{{ */
public function hasChildren() { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "SELECT id FROM `tblFolders` WHERE `parent` = ".(int) $this->current()->getID();
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && !$resArr)
return false;
return true;
} /* }}} */
public function getChildren() { /* {{{ */
return new RecursiveFolderIterator($this->current());
} /* }}} */
} /* }}} */

View File

@ -0,0 +1,186 @@
<?php
/**
* Implementation of keyword categories in the document management system
*
* @category DMS
* @package SeedDMS_Core
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
* 2010 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class to represent a keyword category in the document management system
*
* @category DMS
* @package SeedDMS_Core
* @author Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
* 2010 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Core_KeywordCategory {
/**
* @var integer $_id id of keyword category
* @access protected
*/
protected $_id;
/**
* @var integer $_ownerID id of user who is the owner
* @access protected
*/
protected $_ownerID;
/**
* @var string $_name name of category
* @access protected
*/
protected $_name;
/**
* @var SeedDMS_Core_DMS $_dms reference to dms this category belongs to
* @access protected
*/
protected $_dms;
/**
* SeedDMS_Core_KeywordCategory constructor.
* @param $id
* @param $ownerID
* @param $name
*/
function __construct($id, $ownerID, $name) {
$this->_id = $id;
$this->_name = $name;
$this->_ownerID = $ownerID;
$this->_dms = null;
}
/**
* @param SeedDMS_Core_DMS $dms
*/
function setDMS($dms) {
$this->_dms = $dms;
}
/**
* @return int
*/
function getID() { return $this->_id; }
/**
* @return string
*/
function getName() { return $this->_name; }
/**
* @return bool|SeedDMS_Core_User
*/
function getOwner() {
if (!isset($this->_owner))
$this->_owner = $this->_dms->getUser($this->_ownerID);
return $this->_owner;
}
/**
* @param $newName
* @return bool
*/
function setName($newName) {
$db = $this->_dms->getDB();
$queryStr = "UPDATE `tblKeywordCategories` SET `name` = ".$db->qstr($newName)." WHERE `id` = ". $this->_id;
if (!$db->getResult($queryStr))
return false;
$this->_name = $newName;
return true;
}
/**
* @param SeedDMS_Core_User $user
* @return bool
*/
function setOwner($user) {
$db = $this->_dms->getDB();
$queryStr = "UPDATE `tblKeywordCategories` SET `owner` = " . $user->getID() . " WHERE = `id` = " . $this->_id;
if (!$db->getResult($queryStr))
return false;
$this->_ownerID = $user->getID();
$this->_owner = $user;
return true;
}
/**
* @return array
*/
function getKeywordLists() {
$db = $this->_dms->getDB();
$queryStr = "SELECT * FROM `tblKeywords` WHERE `category` = " . $this->_id . " order by `keywords`";
return $db->getResultArray($queryStr);
}
/**
* @param $listID
* @param $keywords
* @return bool
*/
function editKeywordList($listID, $keywords) {
$db = $this->_dms->getDB();
$queryStr = "UPDATE `tblKeywords` SET `keywords` = ".$db->qstr($keywords)." WHERE `id` = $listID";
return $db->getResult($queryStr);
}
/**
* @param $keywords
* @return bool
*/
function addKeywordList($keywords) {
$db = $this->_dms->getDB();
$queryStr = "INSERT INTO `tblKeywords` (`category`, `keywords`) VALUES (" . $this->_id . ", ".$db->qstr($keywords).")";
return $db->getResult($queryStr);
}
/**
* @param $listID
* @return bool
*/
function removeKeywordList($listID) {
$db = $this->_dms->getDB();
$queryStr = "DELETE FROM `tblKeywords` WHERE `id` = $listID";
return $db->getResult($queryStr);
}
/**
* @return bool
*/
function remove() {
$db = $this->_dms->getDB();
$db->startTransaction();
$queryStr = "DELETE FROM `tblKeywords` WHERE `category` = " . $this->_id;
if (!$db->getResult($queryStr)) {
$db->rollbackTransaction();
return false;
}
$queryStr = "DELETE FROM `tblKeywordCategories` WHERE `id` = " . $this->_id;
if (!$db->getResult($queryStr)) {
$db->rollbackTransaction();
return false;
}
$db->commitTransaction();
return true;
}
}

View File

@ -0,0 +1,116 @@
<?php
/**
* Implementation of a notification object
*
* @category DMS
* @package SeedDMS_Core
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class to represent a notification
*
* @category DMS
* @package SeedDMS_Core
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Core_Notification { /* {{{ */
/**
* @var integer id of target (document or folder)
*
* @access protected
*/
protected $_target;
/**
* @var integer document or folder
*
* @access protected
*/
protected $_targettype;
/**
* @var integer id of user to notify
*
* @access protected
*/
protected $_userid;
/**
* @var integer id of group to notify
*
* @access protected
*/
protected $_groupid;
/**
* @var object reference to the dms instance this user belongs to
*
* @access protected
*/
protected $_dms;
/**
* Constructor
*
* @param integer $target id of document/folder this notification is
* attached to.
* @param integer $targettype 1 = target is document, 2 = target is a folder
* @param integer $userid id of user. The id is -1 if the notification is
* for a group.
* @param integer $groupid id of group. The id is -1 if the notification is
* for a user.
*/
function __construct($target, $targettype, $userid, $groupid) { /* {{{ */
$this->_target = $target;
$this->_targettype = $targettype;
$this->_userid = $userid;
$this->_groupid = $groupid;
} /* }}} */
/**
* Set instance of dms this object belongs to
*
* @param object $dms instance of dms
*/
function setDMS($dms) { /* {{{ */
$this->_dms = $dms;
} /* }}} */
/**
* Get id of target (document/object) this notification is attachted to
*
* @return integer id of target
*/
function getTarget() { return $this->_target; }
/**
* Get type of target
*
* @return integer type of target (1=document/2=object)
*/
function getTargetType() { return $this->_targettype; }
/**
* Get user for this notification
*
* @return integer id of user or -1 if this notification does not belong
* to a user
*/
function getUser() { return $this->_dms->getUser($this->_userid); }
/**
* Get group for this notification
*
* @return integer id of group or -1 if this notification does not belong
* to a group
*/
function getGroup() { return $this->_dms->getGroup($this->_groupid); }
} /* }}} */
?>

View File

@ -0,0 +1,313 @@
<?php
/**
* Implementation of an generic object in the document management system
*
* @category DMS
* @package SeedDMS_Core
* @license GPL2
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010-2012 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class to represent a generic object in the document management system
*
* This is the base class for generic objects in SeedDMS.
*
* @category DMS
* @package SeedDMS_Core
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010-2012 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Core_Object { /* {{{ */
/**
* @var integer unique id of object
*/
protected $_id;
/**
* @var array list of attributes
*/
protected $_attributes;
/**
* @var SeedDMS_Core_DMS back reference to document management system
*/
public $_dms;
/**
* SeedDMS_Core_Object constructor.
* @param $id
*/
function __construct($id) { /* {{{ */
$this->_id = $id;
$this->_dms = null;
} /* }}} */
/**
* Check if this object is of a given type.
*
* This method must be implemened in the child class
*
* @param string $type type of object
*/
public function isType($type) {return false;}
/**
* Set dms this object belongs to.
*
* Each object needs a reference to the dms it belongs to. It will be
* set when the object is created.
* The dms has a references to the currently logged in user
* and the database connection.
*
* @param SeedDMS_Core_DMS $dms reference to dms
*/
public function setDMS($dms) { /* {{{ */
$this->_dms = $dms;
} /* }}} */
public function getDMS() { /* {{{ */
return $this->_dms;
} /* }}} */
/**
* Return the internal id of the document
*
* @return integer id of document
*/
public function getID() { return $this->_id; }
/**
* Returns all attributes set for the object
*
* @return array|bool
*/
public function getAttributes() { /* {{{ */
if (!$this->_attributes) {
$db = $this->_dms->getDB();
switch(get_class($this)) {
case $this->_dms->getClassname('document'):
$queryStr = "SELECT a.* FROM `tblDocumentAttributes` a LEFT JOIN `tblAttributeDefinitions` b ON a.`attrdef`=b.`id` WHERE a.`document` = " . $this->_id." ORDER BY b.`name`";
break;
case $this->_dms->getClassname('documentcontent'):
$queryStr = "SELECT a.* FROM `tblDocumentContentAttributes` a LEFT JOIN `tblAttributeDefinitions` b ON a.`attrdef`=b.`id` WHERE a.`content` = " . $this->_id." ORDER BY b.`name`";
break;
case $this->_dms->getClassname('folder'):
$queryStr = "SELECT a.* FROM `tblFolderAttributes` a LEFT JOIN `tblAttributeDefinitions` b ON a.`attrdef`=b.`id` WHERE a.`folder` = " . $this->_id." ORDER BY b.`name`";
break;
default:
return false;
}
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && !$resArr) return false;
$this->_attributes = array();
foreach ($resArr as $row) {
$attrdef = $this->_dms->getAttributeDefinition($row['attrdef']);
$attr = new SeedDMS_Core_Attribute($row["id"], $this, $attrdef, $row["value"]);
$attr->setDMS($this->_dms);
$this->_attributes[$attrdef->getId()] = $attr;
}
}
return $this->_attributes;
} /* }}} */
/**
* Returns an attribute of the object for the given attribute definition
*
* @param SeedDMS_Core_AttributeDefinition $attrdef
* @return array|string value of attritbute or false. The value is an array
* if the attribute is defined as multi value
*/
public function getAttribute($attrdef) { /* {{{ */
if (!$this->_attributes) {
$this->getAttributes();
}
if (isset($this->_attributes[$attrdef->getId()])) {
return $this->_attributes[$attrdef->getId()];
} else {
return false;
}
} /* }}} */
/**
* Returns an attribute value of the object for the given attribute definition
*
* @param SeedDMS_Core_AttributeDefinition $attrdef
* @return array|string value of attritbute or false. The value is an array
* if the attribute is defined as multi value
*/
public function getAttributeValue($attrdef) { /* {{{ */
if (!$this->_attributes) {
$this->getAttributes();
}
if (isset($this->_attributes[$attrdef->getId()])) {
$value = $this->_attributes[$attrdef->getId()]->getValue();
if($attrdef->getMultipleValues()) {
$sep = substr($value, 0, 1);
$vsep = $attrdef->getValueSetSeparator();
/* If the value doesn't start with the separator used in the value set,
* then assume that the value was not saved with a leading separator.
* This can happen, if the value was previously a single value from
* the value set and later turned into a multi value attribute.
*/
if($sep == $vsep)
return(explode($sep, substr($value, 1)));
else
return(array($value));
} else {
return $value;
}
} else
return false;
} /* }}} */
/**
* Returns an attribute value of the object for the given attribute definition
*
* This is a short cut for getAttribute($attrdef)->getValueAsArray() but
* first checks if the object has an attribute for the given attribute
* definition.
*
* @param SeedDMS_Core_AttributeDefinition $attrdef
* @return array|bool
* even if the attribute is not defined as multi value
*/
public function getAttributeValueAsArray($attrdef) { /* {{{ */
if (!$this->_attributes) {
$this->getAttributes();
}
if (isset($this->_attributes[$attrdef->getId()])) {
return $this->_attributes[$attrdef->getId()]->getValueAsArray();
} else
return false;
} /* }}} */
/**
* Returns an attribute value of the object for the given attribute definition
*
* This is a short cut for getAttribute($attrdef)->getValueAsString() but
* first checks if the object has an attribute for the given attribute
* definition.
*
* @param SeedDMS_Core_AttributeDefinition $attrdef
* @return string value of attritbute or false. The value is always a string
* even if the attribute is defined as multi value
*/
public function getAttributeValueAsString($attrdef) { /* {{{ */
if (!$this->_attributes) {
$this->getAttributes();
}
if (isset($this->_attributes[$attrdef->getId()])) {
return $this->_attributes[$attrdef->getId()]->getValue();
} else
return false;
} /* }}} */
/**
* Set an attribute of the object for the given attribute definition
*
* @param SeedDMS_Core_AttributeDefinition $attrdef definition of attribute
* @param array|string $value value of attribute, for multiple values this
* must be an array
* @return boolean true if operation was successful, otherwise false
*/
public function setAttributeValue($attrdef, $value) { /* {{{ */
$db = $this->_dms->getDB();
if (!$this->_attributes) {
$this->getAttributes();
}
switch($attrdef->getType()) {
case SeedDMS_Core_AttributeDefinition::type_boolean:
$value = ($value === true || $value != '' || $value == 1) ? 1 : 0;
break;
}
if($attrdef->getMultipleValues() && is_array($value)) {
if(in_array($attrdef->getType(), array(SeedDMS_Core_AttributeDefinition::type_user, SeedDMS_Core_AttributeDefinition::type_group)))
$sep = ',';
else
$sep = substr($attrdef->getValueSet(), 0, 1);
$value = $sep.implode($sep, $value);
}
/* Handle the case if an attribute is not set already */
if(!isset($this->_attributes[$attrdef->getId()])) {
switch(get_class($this)) {
case $this->_dms->getClassname('document'):
$tablename = 'tblDocumentAttributes';
$queryStr = "INSERT INTO `tblDocumentAttributes` (`document`, `attrdef`, `value`) VALUES (".$this->_id.", ".$attrdef->getId().", ".$db->qstr($value).")";
break;
case $this->_dms->getClassname('documentcontent'):
$tablename = 'tblDocumentContentAttributes';
$queryStr = "INSERT INTO `tblDocumentContentAttributes` (`content`, `attrdef`, `value`) VALUES (".$this->_id.", ".$attrdef->getId().", ".$db->qstr($value).")";
break;
case $this->_dms->getClassname('folder'):
$tablename = 'tblFolderAttributes';
$queryStr = "INSERT INTO `tblFolderAttributes` (`folder`, `attrdef`, `value`) VALUES (".$this->_id.", ".$attrdef->getId().", ".$db->qstr($value).")";
break;
default:
return false;
}
$res = $db->getResult($queryStr);
if (!$res)
return false;
$attr = new SeedDMS_Core_Attribute($db->getInsertID($tablename), $this, $attrdef, $value);
$attr->setDMS($this->_dms);
$this->_attributes[$attrdef->getId()] = $attr;
return true;
}
/* The attribute already exists. setValue() will either update or delete it. */
$this->_attributes[$attrdef->getId()]->setValue($value);
return true;
} /* }}} */
/**
* Remove an attribute of the object for the given attribute definition
* @param SeedDMS_Core_AttributeDefinition $attrdef
* @return boolean true if operation was successful, otherwise false
*/
public function removeAttribute($attrdef) { /* {{{ */
$db = $this->_dms->getDB();
if (!$this->_attributes) {
$this->getAttributes();
}
if(isset($this->_attributes[$attrdef->getId()])) {
switch(get_class($this)) {
case $this->_dms->getClassname('document'):
$queryStr = "DELETE FROM `tblDocumentAttributes` WHERE `document`=".$this->_id." AND `attrdef`=".$attrdef->getId();
break;
case $this->_dms->getClassname('documentcontent'):
$queryStr = "DELETE FROM `tblDocumentContentAttributes` WHERE `content`=".$this->_id." AND `attrdef`=".$attrdef->getId();
break;
case $this->_dms->getClassname('folder'):
$queryStr = "DELETE FROM `tblFolderAttributes` WHERE `folder`=".$this->_id." AND `attrdef`=".$attrdef->getId();
break;
default:
return false;
}
$res = $db->getResult($queryStr);
if (!$res)
return false;
unset($this->_attributes[$attrdef->getId()]);
}
return true;
} /* }}} */
} /* }}} */

View File

@ -0,0 +1,398 @@
<?php
/**
* Implementation of the transmittal object in the document management system
*
* @category DMS
* @package SeedDMS_Core
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
* 2010 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class to represent a transmittal in the document management system
*
* @category DMS
* @package SeedDMS_Core
* @author Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
* 2010 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Core_Transmittal {
/**
* @var integer id of transmittal
*
* @access protected
*/
var $_id;
/**
* @var string name of transmittal
*
* @access protected
*/
var $_name;
/**
* @var string comment of transmittal
*
* @access protected
*/
var $_comment;
/**
* @var boolean true if transmittal is public
*
* @access protected
*/
var $_isPublic;
/**
* @var object user this transmittal belongs to
*
* @access protected
*/
var $_user;
/**
* @var object date of creation
*
* @access protected
*/
var $_date;
/**
* @var object items
*
* @access protected
*/
var $_items;
/**
* @var object reference to the dms instance this user belongs to
*
* @access protected
*/
var $_dms;
function __construct($id, $user, $name, $comment, $isPublic=0, $date='') {
$this->_id = $id;
$this->_name = $name;
$this->_comment = $comment;
$this->_user = $user;
$this->_isPublic = $isPublic;
$this->_date = $date;
$this->_items = array();
$this->_dms = null;
}
/**
* Get an instance of a transmittal object
*
* @param string|integer $id id or name of transmittal, depending
* on the 3rd parameter.
* @param object $dms instance of dms
* @param string $by search by [id|name]. If this
* parameter is left empty, the user will be search by its Id.
* @return object instance of class SeedDMS_Core_Transmittal
*/
public static function getInstance($id, $dms, $by='') { /* {{{ */
if(!$dms || get_class($dms) != 'SeedDMS_Core_DMS')
return false;
$db = $dms->getDB();
switch($by) {
case 'name':
$queryStr = "SELECT * FROM `tblTransmittals` WHERE `name` = ".$db->qstr($id);
break;
default:
$queryStr = "SELECT * FROM `tblTransmittals` WHERE id = " . (int) $id;
}
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false) return false;
if (count($resArr) != 1) return false;
$resArr = $resArr[0];
$uclassname = $dms->getClassname('user');
$user = $uclassname::getInstance($resArr['userID'], $dms);
$transmittal = new self($resArr["id"], $user, $resArr["name"], $resArr["comment"], $resArr["public"], $resArr["date"]);
$transmittal->setDMS($dms);
return $transmittal;
} /* }}} */
/**
* Get all instances of a transmittal object
*
* @param string|integer $id id or name of transmittal, depending
* on the 3rd parameter.
* @param object $dms instance of dms
* @param string $by search by [id|name]. If this
* parameter is left empty, the user will be search by its Id.
* @return object instance of class SeedDMS_Core_Transmittal
*/
public static function getAllInstances($user, $orderby, $dms) { /* {{{ */
$db = $dms->getDB();
$queryStr = "SELECT * FROM `tblTransmittals`";
if($user)
$queryStr .= " WHERE `userID` = " . $user->getID();
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false) return false;
$uclassname = $dms->getClassname('user');
$transmittals = array();
foreach ($resArr as $res) {
$user = $uclassname::getInstance($res['userID'], $dms);
$transmittal = new self($res["id"], $user, $res["name"], $res["comment"], $res["public"], $res["date"]);
$transmittal->setDMS($dms);
$transmittals[] = $transmittal;
}
return $transmittals;
} /* }}} */
function setDMS($dms) {
$this->_dms = $dms;
}
function getID() { return $this->_id; }
function getName() { return $this->_name; }
function setName($newName) { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "UPDATE `tblTransmittals` SET `name` =".$db->qstr($newName)." WHERE `id` = " . $this->_id;
$res = $db->getResult($queryStr);
if (!$res)
return false;
$this->_name = $newName;
return true;
} /* }}} */
function getComment() { return $this->_comment; }
function setComment($newComment) { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "UPDATE `tblTransmittals` SET `comment` =".$db->qstr($newComment)." WHERE `id` = " . $this->_id;
$res = $db->getResult($queryStr);
if (!$res)
return false;
$this->_comment = $newComment;
return true;
} /* }}} */
function getUser() { return $this->_user; }
function getItems() { /* {{{ */
$db = $this->_dms->getDB();
if (!$this->_items) {
$queryStr = "SELECT `tblTransmittalItems`.* FROM `tblTransmittalItems` ".
"LEFT JOIN `tblDocuments` ON `tblTransmittalItems`.`document`=`tblDocuments`.`id` ".
"WHERE `tblTransmittalItems`.`transmittal` = '". $this->_id ."'";
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false)
return false;
$this->_users = array();
$classname = $this->_dms->getClassname('transmittalitem');
foreach ($resArr as $row) {
$document = $this->_dms->getDocument($row['document']);
$content = $document->getContentByVersion($row['version']);
$item = new $classname($row["id"], $this, $content, $row["date"]);
array_push($this->_items, $item);
}
}
return $this->_items;
} /* }}} */
function getSize() { /* {{{ */
$db = $this->_dms->getDB();
if (!$this->_items) {
self::getItems();
}
$size = 0;
foreach ($this->_items as $item) {
if($content = $item->getContent()) {
$size += $content->getFileSize();
}
}
return $size;
} /* }}} */
/**
* Add an item to the transmittal
*
* @param object $item instance of SeedDMS_Core_DocumentContent
* @return boolean true if item could be added, otherwise false
*/
function addContent($item) { /* {{{ */
$db = $this->_dms->getDB();
if(get_class($item) != $this->_dms->getClassname('documentcontent'))
return false;
$document = $item->getDocument();
$queryStr = "INSERT INTO `tblTransmittalItems` (`transmittal`, `document`, `version`, `date`) ".
"VALUES ('". $this->_id ."', ".$document->getID().", ".$item->getVersion().", ".$db->getCurrentDatetime().")";
$res=$db->getResult($queryStr);
if(!$res) {
return false;
}
$itemID = $db->getInsertID('tblTransmittalItems');
return SeedDMS_Core_TransmittalItem::getInstance($itemID, $this->_dms);
} /* }}} */
function remove() { /* {{{ */
$db = $this->_dms->getDB();
$queryStr = "DELETE FROM `tblTransmittals` WHERE `id` = " . $this->_id;
if (!$db->getResult($queryStr)) {
return false;
}
return true;
} /* }}} */
}
/**
* Class to represent a transmittal in the document management system
*
* @category DMS
* @package SeedDMS_Core
* @author Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
* 2010 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Core_TransmittalItem {
/**
* @var integer id of transmittal item
*
* @access protected
*/
var $_id;
/**
* @var object document content
*
* @access protected
*/
var $_content;
/**
* @var object transmittal
*
* @access protected
*/
var $_transmittal;
/**
* @var object date of creation
*
* @access protected
*/
var $_date;
function __construct($id, $transmittal, $content, $date='') {
$this->_id = $id;
$this->_transmittal = $transmittal;
$this->_content = $content;
$this->_date = $date;
$this->_dms = null;
}
public static function getInstance($id, $dms) { /* {{{ */
if(!$dms || get_class($dms) != 'SeedDMS_Core_DMS')
return false;
$db = $dms->getDB();
$queryStr = "SELECT * FROM `tblTransmittalItems` WHERE `id` = " . (int) $id;
$resArr = $db->getResultArray($queryStr);
if (is_bool($resArr) && $resArr == false)
return false;
if (count($resArr) != 1)
return false;
$resArr = $resArr[0];
$transmittal = SeedDMS_Core_Transmittal::getInstance($resArr['transmittal'], $dms);
$dclassname = $dms->getClassname('document');
$document = $dclassname::getInstance($resArr['document'], $dms);
$content = $document->getContentByVersion((int) $resArr['version']);
$item = new self($resArr["id"], $transmittal, $content, $resArr["date"]);
$item->setDMS($dms);
return $item;
} /* }}} */
function setDMS($dms) {
$this->_dms = $dms;
}
function getID() { return $this->_id; }
function getTransmittal() { return $this->_transmittal; }
function getContent() { return $this->_content; }
function getDate() { return $this->_date; }
function remove() { /* {{{ */
$db = $this->_dms->getDB();
$transmittal = $this->_transmittal;
$queryStr = "DELETE FROM `tblTransmittalItems` WHERE `id` = " . $this->_id;
if (!$db->getResult($queryStr)) {
return false;
}
return true;
} /* }}} */
/**
* Check if the content referenzed by the transmittal item is unequal
* to the latest content of the document.
*
* This function updateѕ always to the latest version of the document,
* even if the version in the item is higher. This can happen if a
* version has been removed.
*
* @return boolean/integer false in case of an error, otherwise the new
* version.
*/
function updateContent() { /* {{{ */
$db = $this->_dms->getDB();
$transmittal = $this->_transmittal;
$document = $this->_content->getDocument();
$latestcontent = $document->getLatestContent();
if($latestcontent->getVersion() != $this->_content->getVersion()) {
$queryStr = "UPDATE `tblTransmittalItems` set `version` = ".$latestcontent->getVersion()." WHERE `id` = " . $this->_id;
if (!$db->getResult($queryStr)) {
return false;
}
}
return $latestcontent->getVersion();
} /* }}} */
}
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,317 @@
<?php
/**
* Implementation of database access
*
* @category DMS
* @package SeedDMS_Core
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
* 2010 Matteo Lucarelli, 2010 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Include the adodb database abstraction
*/
require_once "adodb/adodb.inc.php";
/** @noinspection PhpUndefinedClassInspection */
/**
* Class to represent the database access for the document management
*
* @category DMS
* @package SeedDMS_Core
* @author Markus Westphal, Malcolm Cowe, Matteo Lucarelli, Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli, 2010 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Core_DatabaseAccess {
var $_debug;
var $_driver;
var $_hostname;
var $_database;
var $_user;
var $_passw;
var $_conn;
var $_connected;
var $_ttreviewid;
var $_ttapproveid;
var $_ttstatid;
var $_ttcontentid;
var $_intransaction;
/*
Backup functions
*/
/**
* Return list of all database tables
*
* This function is used to retrieve a list of database tables for backup
*
* @return array list of table names
*/
function TableList() {
return $this->_conn->MetaTables("TABLES");
}
/**
* Constructor of SeedDMS_Core_DatabaseAccess
*
* Sets all database parameters but does not connect.
*
* @param string $driver the database type e.g. mysql, sqlite
* @param string $hostname host of database server
* @param string $user name of user having access to database
* @param string $passw password of user
* @param bool|string $database name of database
*/
function __construct($driver, $hostname, $user, $passw, $database = false) {
$this->_driver = $driver;
$this->_hostname = $hostname;
$this->_database = $database;
$this->_user = $user;
$this->_passw = $passw;
$this->_connected = false;
$this->_intransaction = 0;
// $tt*****id is a hack to ensure that we do not try to create the
// temporary table twice during a single connection. Can be fixed by
// using Views (MySQL 5.0 onward) instead of temporary tables.
// CREATE ... IF NOT EXISTS cannot be used because it has the
// unpleasant side-effect of performing the insert again even if the
// table already exists.
//
// See createTemporaryTable() method for implementation.
$this->_ttreviewid = false;
$this->_ttapproveid = false;
$this->_ttstatid = false;
$this->_ttcontentid = false;
$this->_debug = false;
}
/**
* Connect to database
*
* @return boolean true if connection could be established, otherwise false
*/
function connect() { /* {{{ */
$this->_conn = ADONewConnection($this->_driver);
if ($this->_database)
$this->_conn->Connect($this->_hostname, $this->_user, $this->_passw, $this->_database);
else
$this->_conn->Connect($this->_hostname, $this->_user, $this->_passw);
if (!$this->_conn)
return false;
$this->_conn->SetFetchMode(ADODB_FETCH_ASSOC);
$this->_conn->Execute('SET NAMES utf8');
$this->_connected = true;
return true;
} /* }}} */
/**
* Make sure a database connection exisits
*
* This function checks for a database connection. If it does not exists
* it will reconnect.
*
* @return boolean true if connection is established, otherwise false
*/
function ensureConnected() { /* {{{ */
if (!$this->_connected) return $this->connect();
else return true;
} /* }}} */
/**
* Sanitize String used in database operations
*
* @param string $text
* @return string sanitized string
*/
function qstr($text) { /* {{{ */
return $this->_conn->qstr($text);
} /* }}} */
/**
* Execute SQL query and return result
*
* Call this function only with sql query which return data records.
*
* @param string $queryStr sql query
* @return array|boolean data if query could be executed otherwise false
*/
function getResultArray($queryStr) { /* {{{ */
/** @noinspection PhpUnusedLocalVariableInspection */
$resArr = array();
$res = $this->_conn->Execute($queryStr);
if (!$res) {
if($this->_debug)
echo "error: ".$queryStr."<br />";
return false;
}
$resArr = $res->GetArray();
$res->Close();
return $resArr;
} /* }}} */
/**
* Execute SQL query
*
* Call this function only with sql query which do not return data records.
*
* @param string $queryStr sql query
* @return bool true if query could be executed otherwise false
* @internal param bool $silent not used anymore. This was used when this method
* still issued an error message
*/
function getResult($queryStr) { /* {{{ */
$res = $this->_conn->Execute($queryStr);
if(!$res) {
if($this->_debug)
echo "error: ".$queryStr."<br />";
}
return $res;
} /* }}} */
/**
* Return the id of the last instert record
*
* @return integer id used in last autoincrement
*/
function getInsertID() { /* {{{ */
return $this->_conn->Insert_ID();
} /* }}} */
function startTransaction() { /* {{{ */
if(!$this->_intransaction) {
$this->_conn->BeginTrans();
}
$this->_intransaction++;
} /* }}} */
function rollbackTransaction() { /* {{{ */
if($this->_intransaction == 1) {
$this->_conn->RollbackTrans();
}
$this->_intransaction--;
} /* }}} */
function commitTransaction() { /* {{{ */
if($this->_intransaction == 1) {
$this->_conn->CommitTrans();
}
$this->_intransaction--;
} /* }}} */
function getErrorMsg() { /* {{{ */
return $this->_conn->ErrorMsg();
} /* }}} */
function getErrorNo() { /* {{{ */
return $this->_conn->ErrorNo();
} /* }}} */
/**
* Create various temporary tables to speed up and simplify sql queries
* @param $tableName
* @param bool $override
* @return bool
*/
function createTemporaryTable($tableName, $override=false) { /* {{{ */
if (!strcasecmp($tableName, "ttreviewid")) {
$queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttreviewid` (PRIMARY KEY (`reviewID`), INDEX (`maxLogID`)) ".
"SELECT `tblDocumentReviewLog`.`reviewID`, ".
"MAX(`tblDocumentReviewLog`.`reviewLogID`) AS `maxLogID` ".
"FROM `tblDocumentReviewLog` ".
"GROUP BY `tblDocumentReviewLog`.`reviewID` ".
"ORDER BY `tblDocumentReviewLog`.`reviewLogID`";
if (!$this->_ttreviewid) {
if (!$this->getResult($queryStr))
return false;
$this->_ttreviewid=true;
}
else {
if (is_bool($override) && $override) {
if (!$this->getResult("DELETE FROM `ttreviewid`"))
return false;
if (!$this->getResult($queryStr))
return false;
}
}
return $this->_ttreviewid;
}
else if (!strcasecmp($tableName, "ttapproveid")) {
$queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttapproveid` (PRIMARY KEY (`approveID`), INDEX (`maxLogID`)) ".
"SELECT `tblDocumentApproveLog`.`approveID`, ".
"MAX(`tblDocumentApproveLog`.`approveLogID`) AS `maxLogID` ".
"FROM `tblDocumentApproveLog` ".
"GROUP BY `tblDocumentApproveLog`.`approveID` ".
"ORDER BY `tblDocumentApproveLog`.`approveLogID`";
if (!$this->_ttapproveid) {
if (!$this->getResult($queryStr))
return false;
$this->_ttapproveid=true;
}
else {
if (is_bool($override) && $override) {
if (!$this->getResult("DELETE FROM `ttapproveid`"))
return false;
if (!$this->getResult($queryStr))
return false;
}
}
return $this->_ttapproveid;
}
else if (!strcasecmp($tableName, "ttstatid")) {
$queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttstatid` (PRIMARY KEY (`statusID`), INDEX (`maxLogID`)) ".
"SELECT `tblDocumentStatusLog`.`statusID`, ".
"MAX(`tblDocumentStatusLog`.`statusLogID`) AS `maxLogID` ".
"FROM `tblDocumentStatusLog` ".
"GROUP BY `tblDocumentStatusLog`.`statusID` ".
"ORDER BY `tblDocumentStatusLog`.`statusLogID`";
if (!$this->_ttstatid) {
if (!$this->getResult($queryStr))
return false;
$this->_ttstatid=true;
}
else {
if (is_bool($override) && $override) {
if (!$this->getResult("DELETE FROM `ttstatid`"))
return false;
if (!$this->getResult($queryStr))
return false;
}
}
return $this->_ttstatid;
}
else if (!strcasecmp($tableName, "ttcontentid")) {
$queryStr = "CREATE TEMPORARY TABLE `ttcontentid` (PRIMARY KEY (`document`), INDEX (`maxVersion`)) ".
"SELECT `tblDocumentContent`.`document`, ".
"MAX(`tblDocumentContent`.`version`) AS `maxVersion` ".
"FROM `tblDocumentContent` ".
"GROUP BY `tblDocumentContent`.`document` ".
"ORDER BY `tblDocumentContent`.`document`";
if (!$this->_ttcontentid) {
if (!$this->getResult($queryStr))
return false;
$this->_ttcontentid=true;
}
else {
if (is_bool($override) && $override) {
if (!$this->getResult("DELETE FROM `ttcontentid`"))
return false;
if (!$this->getResult($queryStr))
return false;
}
}
return $this->_ttcontentid;
}
return false;
} /* }}} */
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,286 @@
<?php
/**
* Implementation of various file system operations
*
* @category DMS
* @package SeedDMS_Core
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal,
* 2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
* 2010 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class to represent a user in the document management system
*
* @category DMS
* @package SeedDMS_Core
* @author Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal,
* 2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
* 2010 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Core_File {
/**
* @param $old
* @param $new
* @return bool
*/
static function renameFile($old, $new) { /* {{{ */
return @rename($old, $new);
} /* }}} */
/**
* @param $file
* @return bool
*/
static function removeFile($file) { /* {{{ */
return @unlink($file);
} /* }}} */
/**
* @param $source
* @param $target
* @return bool
*/
static function copyFile($source, $target) { /* {{{ */
return @copy($source, $target);
} /* }}} */
/**
* @param $source
* @param $target
* @return bool
*/
static function moveFile($source, $target) { /* {{{ */
/** @noinspection PhpUndefinedFunctionInspection */
if (!@copyFile($source, $target))
return false;
/** @noinspection PhpUndefinedFunctionInspection */
return @removeFile($source);
} /* }}} */
/**
* @param $file
* @return bool|int
*/
static function fileSize($file) { /* {{{ */
if(!$a = fopen($file, 'r'))
return false;
fseek($a, 0, SEEK_END);
$filesize = ftell($a);
fclose($a);
return $filesize;
} /* }}} */
/**
* @param $size
* @param array $sizes
* @return string
*/
static function format_filesize($size, $sizes = array('Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB')) { /* {{{ */
if ($size == 0) return('0 Bytes');
/** @noinspection PhpIllegalArrayKeyTypeInspection */
return (round($size/pow(1024, ($i = floor(log($size, 1024)))), 2) . ' ' . $sizes[$i]);
} /* }}} */
/**
* @param $str
* @return bool|int
*/
static function parse_filesize($str) { /* {{{ */
preg_replace('/\s\s+/', '', $str);
if(in_array(strtoupper(substr($str, -1)), array('B','K','M','G'))) {
$value = (int) substr($str, 0, -1);
$unit = substr($str, -1, 1);
} else {
return (int) $str;
}
switch(strtoupper($unit)) {
case 'G':
return $value * 1024 * 1024 * 1024;
break;
case 'M':
return $value * 1024 * 1024;
break;
case 'K':
return $value * 1024;
break;
default;
return $value;
break;
}
/** @noinspection PhpUnreachableStatementInspection */
return false;
} /* }}} */
/**
* @param $file
* @return string
*/
static function checksum($file) { /* {{{ */
return md5_file($file);
} /* }}} */
/**
* @param $old
* @param $new
* @return bool
*/
static function renameDir($old, $new) { /* {{{ */
return @rename($old, $new);
} /* }}} */
/**
* @param $path
* @return bool
*/
static function makeDir($path) { /* {{{ */
if( !is_dir( $path ) ){
$res=@mkdir( $path , 0777, true);
if (!$res) return false;
}
return true;
/* some old code
if (strncmp($path, DIRECTORY_SEPARATOR, 1) == 0) {
$mkfolder = DIRECTORY_SEPARATOR;
}
else {
$mkfolder = "";
}
$path = preg_split( "/[\\\\\/]/" , $path );
for( $i=0 ; isset( $path[$i] ) ; $i++ )
{
if(!strlen(trim($path[$i])))continue;
$mkfolder .= $path[$i];
if( !is_dir( $mkfolder ) ){
$res=@mkdir( "$mkfolder" , 0777);
if (!$res) return false;
}
$mkfolder .= DIRECTORY_SEPARATOR;
}
return true;
// patch from alekseynfor safe_mod or open_basedir
global $settings;
$path = substr_replace ($path, "/", 0, strlen($settings->_contentDir));
$mkfolder = $settings->_contentDir;
$path = preg_split( "/[\\\\\/]/" , $path );
for( $i=0 ; isset( $path[$i] ) ; $i++ )
{
if(!strlen(trim($path[$i])))continue;
$mkfolder .= $path[$i];
if( !is_dir( $mkfolder ) ){
$res= @mkdir( "$mkfolder" , 0777);
if (!$res) return false;
}
$mkfolder .= DIRECTORY_SEPARATOR;
}
return true;
*/
} /* }}} */
/**
* @param $path
* @return bool
*/
static function removeDir($path) { /* {{{ */
$handle = @opendir($path);
while ($entry = @readdir($handle) )
{
if ($entry == ".." || $entry == ".")
continue;
else if (is_dir($path . $entry))
{
if (!self::removeDir($path . $entry . "/"))
return false;
}
else
{
if (!@unlink($path . $entry))
return false;
}
}
@closedir($handle);
return @rmdir($path);
} /* }}} */
/**
* @param $sourcePath
* @param $targetPath
* @return bool
*/
static function copyDir($sourcePath, $targetPath) { /* {{{ */
if (mkdir($targetPath, 0777)) {
$handle = @opendir($sourcePath);
while ($entry = @readdir($handle) ) {
if ($entry == ".." || $entry == ".")
continue;
else if (is_dir($sourcePath . $entry)) {
if (!self::copyDir($sourcePath . $entry . "/", $targetPath . $entry . "/"))
return false;
} else {
if (!@copy($sourcePath . $entry, $targetPath . $entry))
return false;
}
}
@closedir($handle);
}
else
return false;
return true;
} /* }}} */
/**
* @param $sourcePath
* @param $targetPath
* @return bool
*/
static function moveDir($sourcePath, $targetPath) { /* {{{ */
/** @noinspection PhpUndefinedFunctionInspection */
if (!copyDir($sourcePath, $targetPath))
return false;
/** @noinspection PhpUndefinedFunctionInspection */
return removeDir($sourcePath);
} /* }}} */
// code by Kioob (php.net manual)
/**
* @param $source
* @param bool $level
* @return bool|string
*/
static function gzcompressfile($source, $level=false) { /* {{{ */
$dest=$source.'.gz';
$mode='wb'.$level;
$error=false;
if($fp_out=@gzopen($dest,$mode)) {
if($fp_in=@fopen($source,'rb')) {
while(!feof($fp_in))
@gzwrite($fp_out,fread($fp_in,1024*512));
@fclose($fp_in);
}
else $error=true;
@gzclose($fp_out);
}
else $error=true;
if($error) return false;
else return $dest;
} /* }}} */
}

2176
SeedDMS_Core/package.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
<?php
$g_config['type'] = 'mysql';
$g_config['hostname'] = 'localhost';
$g_config['user'] = 'letodms';
$g_config['passwd'] = 'letodms';
$g_config['name'] = 'letodms';
$g_config['contentDir'] = '/tmp/content';
$g_config['contentOffsetDir'] = '/tmp/content';
?>

View File

@ -0,0 +1,25 @@
<?php
include("config.php");
include("SeedDMS/SeedDMS_Core.php");
$db = new SeedDMS_Core_DatabaseAccess($g_config['type'], $g_config['hostname'], $g_config['user'], $g_config['passwd'], $g_config['name']);
$db->connect() or die ("Could not connect to db-server \"" . $g_config['hostname'] . "\"");
$dms = new SeedDMS_Core_DMS($db, $g_config['contentDir'], $g_config['contentOffsetDir']);
function tree($folder, $indent='') {
echo $indent."D ".$folder->getName()."\n";
$subfolders = $folder->getSubFolders();
foreach($subfolders as $subfolder) {
tree($subfolder, $indent.' ');
}
$documents = $folder->getDocuments();
foreach($documents as $document) {
echo $indent." ".$document->getName()."\n";
}
}
$folder = $dms->getFolder(1);
tree($folder);
?>

View File

@ -0,0 +1,14 @@
<?php
include("config.php");
include("SeedDMS/SeedDMS_Core.php");
$db = new SeedDMS_Core_DatabaseAccess($g_config['type'], $g_config['hostname'], $g_config['user'], $g_config['passwd'], $g_config['name']);
$db->connect() or die ("Could not connect to db-server \"" . $g_config['hostname'] . "\"");
$dms = new SeedDMS_Core_DMS($db, $g_config['contentDir'], $g_config['contentOffsetDir']);
$users = $dms->getAllUsers();
foreach($users as $user)
echo $user->getId()." ".$user->getLogin()." ".$user->getFullname()."\n";
?>

View File

@ -0,0 +1,44 @@
<?php
include("config.php");
include("SeedDMS/SeedDMS_Core.php");
$db = new SeedDMS_Core_DatabaseAccess($g_config['type'], $g_config['hostname'], $g_config['user'], $g_config['passwd'], $g_config['name']);
$db->connect() or die ("Could not connect to db-server \"" . $g_config['hostname'] . "\"");
$dms = new SeedDMS_Core_DMS($db, $g_config['contentDir'], $g_config['contentOffsetDir']);
$path = '/Test 1/';
echo "Searching for folder or document with path '".$path."'\n";
$root = $dms->getRootFolder();
if($path[0] == '/') {
$path = substr($path, 1);
}
$patharr = explode('/', $path);
/* The last entry is always the document, though if the path ends in '/' the
* document name will be empty.
*/
$docname = array_pop($patharr);
$parentfolder = $root;
foreach($patharr as $pathseg) {
if($folder = $dms->getFolderByName($pathseg, $parentfolder)) {
$parentfolder = $folder;
}
}
if($folder) {
if($docname) {
if($document = $dms->getDocumentByName($docname, $folder)) {
echo "Given path is document '".$document->getName()."'\n";
} else {
echo "No object found\n";
}
} else {
echo "Given path is a folder '".$folder->getName()."'\n";
}
} else {
echo "No object found\n";
}
?>

44
SeedDMS_Lucene/Lucene.php Normal file
View File

@ -0,0 +1,44 @@
<?php
// SeedDMS. Document Management System
// Copyright (C) 2011-2013 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.
/**
* @uses Zend_Search_Lucene
*/
require_once('Zend/Search/Lucene.php');
/**
* @uses Zend_Search_Lucene_Analysis_TokenFilter_Stopwords
*/
require_once("Zend/Search/Lucene/Analysis/TokenFilter/StopWords.php");
/**
* @uses SeedDMS_Lucene_Indexer
*/
require_once('Lucene/Indexer.php');
/**
* @uses SeedDMS_Lucene_Search
*/
require_once('Lucene/Search.php');
/**
* @uses SeedDMS_Lucene_IndexedDocument
*/
require_once('Lucene/IndexedDocument.php');
?>

View File

@ -0,0 +1,217 @@
<?php
/**
* Implementation of an indexed document
*
* @category DMS
* @package SeedDMS_Lucene
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class for managing an indexed document.
*
* @category DMS
* @package SeedDMS_Lucene
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2011, Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Lucene_IndexedDocument extends Zend_Search_Lucene_Document {
/**
* @var string
*/
protected $errormsg;
/**
* @var string
*/
protected $mimetype;
/**
* @var string
*/
protected $cmd;
/**
* @param $cmd
* @param int $timeout
* @return string
* @throws Exception
*/
static function execWithTimeout($cmd, $timeout=2) { /* {{{ */
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
$pipes = array();
$timeout += time();
$process = proc_open($cmd, $descriptorspec, $pipes);
if (!is_resource($process)) {
throw new Exception("proc_open failed on: " . $cmd);
}
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
$output = $error = '';
$timeleft = $timeout - time();
$read = array($pipes[1], $pipes[2]);
$write = NULL;
$exeptions = NULL;
do {
$num_changed_streams = stream_select($read, $write, $exeptions, $timeleft, 200000);
if ($num_changed_streams === false) {
proc_terminate($process);
throw new Exception("stream select failed on: " . $cmd);
} elseif ($num_changed_streams > 0) {
$output .= fread($pipes[1], 8192);
$error .= fread($pipes[2], 8192);
}
$timeleft = $timeout - time();
} while (!feof($pipes[1]) && $timeleft > 0);
if ($timeleft <= 0) {
proc_terminate($process);
throw new Exception("command timeout on: " . $cmd);
} else {
return array('stdout'=>$output, 'stderr'=>$error);
}
} /* }}} */
/**
* Constructor. Creates our indexable document and adds all
* necessary fields to it using the passed in document
* @param SeedDMS_Core_DMS $dms
* @param SeedDMS_Core_Document|Folder $document
* @param null $convcmd
* @param bool $nocontent
* @param int $timeout
*/
public function __construct($dms, $document, $convcmd=null, $nocontent=false, $timeout=5) { /* {{{ */
$this->errormsg = '';
$this->cmd = '';
$this->mimetype = '';
$this->addField(Zend_Search_Lucene_Field::Text('title', $document->getName(), 'utf-8'));
if($acllist = $document->getReadAccessList(1, 1, 1)) {
$allu = [];
foreach($acllist['users'] as $u)
$allu[] = $u->getLogin();
$this->addField(Zend_Search_Lucene_Field::Text('users', implode(' ', $allu), 'utf-8'));
/*
$allg = [];
foreach($acllist['groups'] as $g)
$allg[] = $g->getName();
$this->addField(Zend_Search_Lucene_Field::Text('groups', implode(' ', $allg), 'utf-8'));
*/
}
if($attributes = $document->getAttributes()) {
foreach($attributes as $attribute) {
$attrdef = $attribute->getAttributeDefinition();
if($attrdef->getValueSet() != '')
$this->addField(Zend_Search_Lucene_Field::Keyword('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue(), 'utf-8'));
else
$this->addField(Zend_Search_Lucene_Field::Text('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue(), 'utf-8'));
}
}
$owner = $document->getOwner();
$this->addField(Zend_Search_Lucene_Field::Text('owner', $owner->getLogin(), 'utf-8'));
if($comment = $document->getComment()) {
$this->addField(Zend_Search_Lucene_Field::Text('comment', $comment, 'utf-8'));
}
$tmp = explode(':', substr($document->getFolderList(), 1, -1));
foreach($tmp as $t)
$this->addField(Zend_Search_Lucene_Field::Keyword('path', $t));
// $this->addField(Zend_Search_Lucene_Field::Keyword('path', str_replace(':', 'x', $document->getFolderList())));
if($document->isType('document')) {
$this->addField(Zend_Search_Lucene_Field::Keyword('document_id', 'D'.$document->getID()));
$version = $document->getLatestContent();
if($version) {
$this->addField(Zend_Search_Lucene_Field::Keyword('mimetype', $version->getMimeType()));
$this->addField(Zend_Search_Lucene_Field::Keyword('origfilename', $version->getOriginalFileName(), 'utf-8'));
if(!$nocontent)
$this->addField(Zend_Search_Lucene_Field::UnIndexed('created', $version->getDate()));
if($attributes = $version->getAttributes()) {
foreach($attributes as $attribute) {
$attrdef = $attribute->getAttributeDefinition();
if($attrdef->getValueSet() != '')
$this->addField(Zend_Search_Lucene_Field::Keyword('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue(), 'utf-8'));
else
$this->addField(Zend_Search_Lucene_Field::Text('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue(), 'utf-8'));
}
}
}
if($categories = $document->getCategories()) {
$names = array();
foreach($categories as $cat) {
$names[] = $cat->getName();
}
$this->addField(Zend_Search_Lucene_Field::Text('category', implode(' ', $names), 'utf-8'));
}
if($keywords = $document->getKeywords()) {
$this->addField(Zend_Search_Lucene_Field::Text('keywords', $keywords, 'utf-8'));
}
if($version) {
$status = $version->getStatus();
$this->addField(Zend_Search_Lucene_Field::Keyword('status', $status['status'], 'utf-8'));
}
if($version && !$nocontent) {
$path = $dms->contentDir . $version->getPath();
if(file_exists($path)) {
$content = '';
$mimetype = $version->getMimeType();
$this->mimetype = $mimetype;
$cmd = '';
$mimeparts = explode('/', $mimetype, 2);
if(isset($convcmd[$mimetype])) {
$cmd = sprintf($convcmd[$mimetype], $path);
} elseif(isset($convcmd[$mimeparts[0].'/*'])) {
$cmd = sprintf($convcmd[$mimetype], $path);
} elseif(isset($convcmd['*'])) {
$cmd = sprintf($convcmd[$mimetype], $path);
}
if($cmd) {
$this->cmd = $cmd;
try {
$content = self::execWithTimeout($cmd, $timeout);
if($content['stdout']) {
$this->addField(Zend_Search_Lucene_Field::UnStored('content', $content['stdout'], 'utf-8'));
}
if($content['stderr']) {
$this->errormsg = $content['stderr'];
}
} catch (Exception $e) {
}
}
}
}
} elseif($document->isType('folder')) {
$this->addField(Zend_Search_Lucene_Field::Keyword('document_id', 'F'.$document->getID()));
$this->addField(Zend_Search_Lucene_Field::UnIndexed('created', $document->getDate()));
}
} /* }}} */
public function getErrorMsg() { /* {{{ */
return $this->errormsg;
} /* }}} */
public function getMimeType() { /* {{{ */
return $this->mimetype;
} /* }}} */
public function getCmd() { /* {{{ */
return $this->cmd;
} /* }}} */
}
?>

View File

@ -0,0 +1,67 @@
<?php
/**
* Implementation of lucene index
*
* @category DMS
* @package SeedDMS_Lucene
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class for managing a lucene index.
*
* @category DMS
* @package SeedDMS_Lucene
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2011, Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Lucene_Indexer {
/**
* @var string $indexname name of lucene index
* @access protected
*/
protected $indexname;
static function open($conf) { /* {{{ */
try {
$index = Zend_Search_Lucene::open($conf['indexdir']);
return($index);
} catch (Exception $e) {
return null;
}
} /* }}} */
static function create($conf) { /* {{{ */
try {
$index = Zend_Search_Lucene::create($conf['indexdir']);
return($index);
} catch (Exception $e) {
return null;
}
} /* }}} */
/**
* Do some initialization
*
*/
static function init($stopWordsFile='') { /* {{{ */
$analyzer = new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive();
if($stopWordsFile && file_exists($stopWordsFile)) {
$stopWordsFilter = new Zend_Search_Lucene_Analysis_TokenFilter_StopWords();
$stopWordsFilter->loadFromFile($stopWordsFile);
$analyzer->addFilter($stopWordsFilter);
}
Zend_Search_Lucene_Analysis_Analyzer::setDefault($analyzer);
} /* }}} */
}
?>

View File

@ -0,0 +1,153 @@
<?php
/**
* Implementation of search in lucene index
*
* @category DMS
* @package SeedDMS_Lucene
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class for searching in a lucene index.
*
* @category DMS
* @package SeedDMS_Lucene
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2011, Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Lucene_Search {
/**
* @var object $index lucene index
* @access protected
*/
protected $index;
/**
* Create a new instance of the search
*
* @param object $index lucene index
* @return object instance of SeedDMS_Lucene_Search
*/
function __construct($index) { /* {{{ */
$this->index = $index;
$this->version = '@package_version@';
if($this->version[0] == '@')
$this->version = '3.0.0';
} /* }}} */
/**
* Get document from index
*
* @param object $index lucene index
* @return object instance of SeedDMS_Lucene_Document of false
*/
function getDocument($id) { /* {{{ */
$hits = $this->index->find('document_id:D'.$id);
return $hits ? $hits[0] : false;
} /* }}} */
/**
* Get folder from index
*
* @param object $index lucene index
* @return object instance of SeedDMS_Lucene_Document of false
*/
function getFolder($id) { /* {{{ */
$hits = $this->index->find('document_id:F'.$id);
return $hits ? $hits[0] : false;
} /* }}} */
/**
* Search in index
*
* @param object $index lucene index
* @return object instance of SeedDMS_Lucene_Search
*/
function search($term, $fields=array(), $limit=array()) { /* {{{ */
$querystr = '';
$term = trim($term);
if($term) {
$querystr = substr($term, -1) != '*' ? $term.'*' : $term;
}
if(!empty($fields['owner'])) {
if(is_string($owner)) {
if($querystr)
$querystr .= ' && ';
$querystr .= 'owner:'.$owner;
} elseif(is_array($fields['owner'])) {
if($querystr)
$querystr .= ' && ';
$querystr .= '(owner:"';
$querystr .= implode('" || owner:"', $fields['owner']);
$querystr .= '")';
}
}
if(!empty($fields['category'])) {
if($querystr)
$querystr .= ' && ';
$querystr .= '(category:"';
$querystr .= implode('" || category:"', $fields['category']);
$querystr .= '")';
}
if(!empty($fields['status'])) {
if($querystr)
$querystr .= ' && ';
$querystr .= '(status:"';
$querystr .= implode('" || status:"', $fields['status']);
$querystr .= '")';
}
if(!empty($fields['user'])) {
if($querystr)
$querystr .= ' && ';
$querystr .= '(users:"';
$querystr .= implode('" || users:"', $fields['user']);
$querystr .= '")';
}
if(!empty($fields['rootFolder']) && $fields['rootFolder']->getFolderList()) {
if($querystr)
$querystr .= ' && ';
$querystr .= '(path:"';
$tmp[] = $fields['rootFolder']->getID();
$querystr .= implode('" && path:"', $tmp);
//$querystr .= $fields['rootFolder']->getFolderList().$fields['rootFolder']->getID().':';
$querystr .= '")';
}
if(!empty($fields['startFolder']) && $fields['startFolder']->getFolderList()) {
if($querystr)
$querystr .= ' && ';
$querystr .= '(path:"';
// $querystr .= str_replace(':', 'x', $fields['startFolder']->getFolderList().$fields['startFolder']->getID().':');
$tmp = array();//explode(':', substr($fields['startFolder']->getFolderList(), 1, -1));
$tmp[] = $fields['startFolder']->getID();
$querystr .= implode('" && path:"', $tmp);
// $querystr .= str_replace(':', ' ', $fields['startFolder']->getFolderList().$fields['startFolder']->getID());
$querystr .= '")';
}
try {
$query = Zend_Search_Lucene_Search_QueryParser::parse($querystr);
try {
$hits = $this->index->find($query);
$recs = array();
$c = 0;
foreach($hits as $hit) {
if($c >= $limit['offset'] && ($c-$limit['offset'] < $limit))
$recs[] = array('id'=>$hit->id, 'document_id'=>$hit->document_id);
$c++;
}
return array('count'=>count($hits), 'hits'=>$recs, 'facets'=>array());
} catch (Zend_Search_Lucene_Exception $e) {
return false;
}
} catch (Zend_Search_Lucene_Search_QueryParserException $e) {
return false;
}
} /* }}} */
}
?>

356
SeedDMS_Lucene/package.xml Normal file
View File

@ -0,0 +1,356 @@
<?xml version="1.0" encoding="UTF-8"?>
<package packagerversion="1.8.1" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
<name>SeedDMS_Lucene</name>
<channel>pear.php.net</channel>
<summary>Fulltext search for SeedDMS</summary>
<description>SeedDMS is a web based document management system (DMS). This is
the fulltext search engine for it, based on Lucene.</description>
<lead>
<name>Uwe Steinmann</name>
<user>steinm</user>
<email>uwe@steinmann.cx</email>
<active>yes</active>
</lead>
<date>2020-12-12</date>
<time>08:55:43</time>
<version>
<release>1.1.16</release>
<api>1.1.16</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
- add indexing of folders
</notes>
<contents>
<dir baseinstalldir="SeedDMS" name="/">
<dir name="Lucene">
<file name="Indexer.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
<file name="Search.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
<file name="IndexedDocument.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
</dir> <!-- /Lucene -->
<dir name="tests">
</dir> <!-- /tests -->
<file name="Lucene.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
</dir> <!-- / -->
</contents>
<dependencies>
<required>
<php>
<min>4.3.0</min>
</php>
<pearinstaller>
<min>1.5.4</min>
</pearinstaller>
</required>
</dependencies>
<phprelease />
<changelog>
<release>
<version>
<release>0.0.1</release>
<api>0.0.1</api>
</version>
<stability>
<release>alpha</release>
<api>alpha</api>
</stability>
<date>2009-04-27</date>
<license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
<notes>
</notes>
</release>
<release>
<date>2011-11-06</date>
<time>08:05:38</time>
<version>
<release>1.0.1</release>
<api>1.0.0</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
- New Release
</notes>
</release>
<release>
<date>2012-11-06</date>
<time>08:05:38</time>
<version>
<release>1.1.0</release>
<api>1.1.0</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
use a configurable list of mime type converters, fixed indexing and searching
of special chars like german umlaute.
</notes>
</release>
<release>
<date>2012-12-03</date>
<time>10:31:23</time>
<version>
<release>1.1.1</release>
<api>1.1.1</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
catch exception if index is opened but not available
</notes>
</release>
<release>
<date>2013-06-17</date>
<time>10:31:23</time>
<version>
<release>1.1.2</release>
<api>1.1.1</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
parse query term and catch errors before using it
</notes>
</release>
<release>
<date>2013-06-27</date>
<time>15:12:50</time>
<version>
<release>1.1.3</release>
<api>1.1.1</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
explicitly set encoding to utf-8 when adding fields
do not check if deleting document from index fails, update it in any case
</notes>
</release>
<release>
<date>2013-08-13</date>
<time>21:56:55</time>
<version>
<release>1.1.4</release>
<api>1.1.4</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
class SeedDMS_Lucene_Search::search returns false if query is invalid instead of an empty result record
</notes>
</release>
<release>
<date>2014-07-30</date>
<time>09:00:34</time>
<version>
<release>1.1.5</release>
<api>1.1.5</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
field for original filename is treated as utf-8
declare SeeDMS_Lucene_Indexer::open() static
</notes>
</release>
<release>
<date>2015-08-05</date>
<time>21:13:13</time>
<version>
<release>1.1.6</release>
<api>1.1.6</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
run external commands with a timeout
</notes>
</release>
<release>
<date>2016-02-01</date>
<time>09:14:07</time>
<version>
<release>1.1.7</release>
<api>1.1.7</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
add command for indexing postѕcript files
</notes>
</release>
<release>
<date>2016-03-29</date>
<time>08:11:19</time>
<version>
<release>1.1.8</release>
<api>1.1.7</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
set last parameter of stream_select() to 200000 micro sec. in case the timeout in sec. is set to 0
</notes>
</release>
<release>
<date>2016-04-28</date>
<time>08:11:19</time>
<version>
<release>1.1.9</release>
<api>1.1.7</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
pass variables to stream_select() to fullfill strict standards.
make all functions in Indexer.php static
</notes>
</release>
<release>
<date>2017-03-01</date>
<time>15:55:32</time>
<version>
<release>1.1.10</release>
<api>1.1.10</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
catch exception in execWithTimeout()
</notes>
</release>
<release>
<date>2017-12-04</date>
<time>10:58:13</time>
<version>
<release>1.1.11</release>
<api>1.1.11</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
allow conversion commands for mimetypes with wildcards
</notes>
</release>
<release>
<date>2018-01-30</date>
<time>10:58:13</time>
<version>
<release>1.1.12</release>
<api>1.1.12</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
execWithTimeout() reads data from stderr and saves it into error msg
</notes>
</release>
<release>
<date>2018-04-11</date>
<time>10:58:13</time>
<version>
<release>1.1.13</release>
<api>1.1.13</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
IndexedDocument() remembers cmd and mimetype
</notes>
</release>
<release>
<date>2020-09-02</date>
<time>08:55:43</time>
<version>
<release>1.1.14</release>
<api>1.1.14</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
Index users with at least read access on the document
</notes>
</release>
<release>
<date>2020-09-10</date>
<time>08:55:43</time>
<version>
<release>1.1.15</release>
<api>1.1.15</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
- add searching for document status
- better error handling if opening index fails
- parameters for SeedDMS_Lucene_Search::search() has changed
- SeedDMS_Lucene_Search::search() returns array of hits, count and facets
- pass config array instead of index directory to SeedDMS_Lucene_Indexer::create()
and SeedDMS_Lucene_Indexer::open()
</notes>
</release>
</changelog>
</package>

View File

@ -0,0 +1,34 @@
<?php
// SeedDMS. Document Management System
// Copyright (C) 2011-2013 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.
/**
* @uses Preview/Base.php
*/
require_once('Preview/Base.php');
/**
* @uses Preview/Previewer.php
*/
require_once('Preview/Previewer.php');
/**
* @uses Preview/PdfPreviewer.php
*/
require_once('Preview/PdfPreviewer.php');
?>

View File

@ -0,0 +1,202 @@
<?php
/**
* Implementation of preview base
*
* @category DMS
* @package SeedDMS_Preview
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class for managing creation of preview images for documents.
*
* @category DMS
* @package SeedDMS_Preview
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2011, Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Preview_Base {
/**
* @var string $cacheDir location in the file system where all the
* cached data like thumbnails are located. This should be an
* absolute path.
* @access public
*/
public $previewDir;
/**
* @var array $converters list of mimetypes and commands for converting
* file into preview image
* @access protected
*/
protected $converters;
/**
* @var integer $timeout maximum time for execution of external commands
* @access protected
*/
protected $timeout;
/**
* @var boolean $xsendfile set to true if mod_xѕendfile is to be used
* @access protected
*/
protected $xsendfile;
/**
* @var string $lastpreviewfile will be set to the file name of the last preview
* @access protected
*/
protected $lastpreviewfile;
function __construct($previewDir, $timeout=5, $xsendfile=true) { /* {{{ */
if(!is_dir($previewDir)) {
if (!SeedDMS_Core_File::makeDir($previewDir)) {
$this->previewDir = '';
} else {
$this->previewDir = $previewDir;
}
} else {
$this->previewDir = $previewDir;
}
$this->timeout = intval($timeout);
$this->converters = array();
$this->xsendfile = $xsendfile;
} /* }}} */
static function execWithTimeout($cmd, $timeout=5) { /* {{{ */
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
$pipes = array();
$timeout += time();
// Putting an 'exec' before the command will not fork the command
// and therefore not create any child process. proc_terminate will
// then reliably terminate the cmd and not just shell. See notes of
// https://www.php.net/manual/de/function.proc-terminate.php
$process = proc_open('exec '.$cmd, $descriptorspec, $pipes);
if (!is_resource($process)) {
throw new Exception("proc_open failed on: " . $cmd);
}
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
$output = $error = '';
$timeleft = $timeout - time();
$read = array($pipes[1], $pipes[2]);
$write = NULL;
$exeptions = NULL;
do {
$num_changed_streams = stream_select($read, $write, $exeptions, $timeleft, 200000);
if ($num_changed_streams === false) {
proc_terminate($process);
throw new Exception("stream select failed on: " . $cmd);
} elseif ($num_changed_streams > 0) {
$output .= fread($pipes[1], 8192);
$error .= fread($pipes[2], 8192);
}
$timeleft = $timeout - time();
} while (!feof($pipes[1]) && $timeleft > 0);
if ($timeleft <= 0) {
proc_terminate($process);
throw new Exception("command timeout on: " . $cmd);
} else {
return array('stdout'=>$output, 'stderr'=>$error);
}
} /* }}} */
/**
* Set a list of converters
*
* Merges the list of passed converters with the already existing ones.
* Existing converters will be overwritten.
*
* @param array list of converters. The key of the array contains the mimetype
* and the value is the command to be called for creating the preview
*/
function setConverters($arr) { /* {{{ */
if(is_array($arr))
$this->converters = $arr;
else
$this->converters = array();
} /* }}} */
/**
* Enable/Disable xsendfile extension
*
* Merges the list of passed converters with the already existing ones.
* Existing converters will be overwritten.
*
* @param boolean $xsendfile turn on/off use of xsendfile module in apache
*/
function setXsendfile($xsendfile) { /* {{{ */
$this->xsendfile = $xsendfile;
} /* }}} */
/**
* Add a list of converters
*
* Merges the list of passed converters with the already existing ones.
* Existing converters will be overwritten.
*
* @param array list of converters. The key of the array contains the mimetype
* and the value is the command to be called for creating the preview
*/
function addConverters($arr) { /* {{{ */
$this->converters = array_merge($this->converters, $arr);
} /* }}} */
/**
* Check if converter for a given mimetype is set
*
* @param string $mimetype
* @return boolean true if converter exists, otherwise false
*/
function hasConverter($mimetype) { /* {{{ */
return array_key_exists($mimetype, $this->converters) && $this->converters[$mimetype];
} /* }}} */
/**
* Send a file from disk to the browser
*
* This function uses either readfile() or the xѕendfile apache module if
* it is installed.
*
* @param string $filename
*/
protected function sendFile($filename) { /* {{{ */
if($this->xsendfile && function_exists('apache_get_modules') && in_array('mod_xsendfile',apache_get_modules())) {
header("X-Sendfile: ".$filename);
} else {
$size = filesize($filename);
header("Content-Length: " . $size);
/* Make sure output buffering is off */
if (ob_get_level()) {
ob_end_clean();
}
readfile($filename);
}
} /* }}} */
/**
* Return path of last created preview file
*
* @return string
*/
public function getPreviewFile() { /* {{{ */
return $this->lastpreviewfile;
} /* }}} */
}

View File

@ -0,0 +1,295 @@
<?php
/**
* Implementation of pdf preview documents
*
* @category DMS
* @package SeedDMS_Preview
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class for managing creation of pdf preview for documents.
*
* @category DMS
* @package SeedDMS_Preview
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2011, Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Preview_PdfPreviewer extends SeedDMS_Preview_Base {
function __construct($previewDir, $timeout=5, $xsendfile=true) { /* {{{ */
parent::__construct($previewDir, $timeout, $xsendfile);
$this->converters = array(
'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => "unoconv -d document -f pdf --stdout -v '%f' > '%o'",
'application/vnd.oasis.opendocument.text' => "unoconv -d document -f pdf --stdout -v '%f' > '%o'",
'text/rtf' => "unoconv -d document -f pdf --stdout -v '%f' > '%o'",
'application/msword' => "unoconv -d document -f pdf --stdout -v '%f' > '%o'",
'application/vnd.ms-excel' => "unoconv -d document -f pdf --stdout -v '%f' > '%o'",
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => "unoconv -d document -f pdf --stdout -v '%f' > '%o'",
'text/plain' => "unoconv -d document -f pdf --stdout -v '%f' > '%o'",
'application/postscript' => "ps2pdf '%f' - > '%o'",
'image/jpeg' => "convert '%f' pdf:- > '%o'",
'image/png' => "convert '%f' pdf:- > '%o'",
'image/gif' => "convert '%f' pdf:- > '%o'",
'video/mp4' => "convert '%f[1-20]' pdf:- > '%o'",
);
} /* }}} */
/**
* Return the physical filename of the preview image on disk
*
* @param object $object document content or document file
* @return string file name of preview image
*/
protected function getFileName($object) { /* {{{ */
if(!$object)
return false;
$document = $object->getDocument();
$dms = $document->_dms;
$dir = $this->previewDir.'/'.$document->getDir();
switch(get_class($object)) {
case $dms->getClassname('documentcontent'):
$target = $dir.'p'.$object->getVersion();
break;
case "SeedDMS_Core_DocumentFile":
$target = $dir.'f'.$object->getID();
break;
default:
return false;
}
return $target;
} /* }}} */
/**
* Create a pdf preview for a given file
*
* This method creates a preview in pdf format for a regular file
* in the file system and stores the result in the directory $dir relative
* to the configured preview directory. The filename of the resulting preview
* image is either $target.pdf (if set) or md5($infile).pdf.
* The $mimetype is used to select the propper conversion programm.
* An already existing pdf preview is replaced.
*
* @param string $infile name of input file including full path
* @param string $dir directory relative to $this->previewDir
* @param string $mimetype MimeType of input file
* @param string $target optional name of preview image (without extension)
* @return boolean true on success, false on failure
*/
public function createRawPreview($infile, $dir, $mimetype, $target='') { /* {{{ */
if(!$this->previewDir)
return false;
if(!is_dir($this->previewDir.'/'.$dir)) {
if (!SeedDMS_Core_File::makeDir($this->previewDir.'/'.$dir)) {
return false;
}
}
if(!file_exists($infile))
return false;
if(!$target)
$target = $this->previewDir.$dir.md5($infile);
$this->lastpreviewfile = $target.'.pdf';
if($target != '' && (!file_exists($target.'.pdf') || filectime($target.'.pdf') < filectime($infile))) {
$cmd = '';
$mimeparts = explode('/', $mimetype, 2);
if(isset($this->converters[$mimetype])) {
$cmd = str_replace(array('%f', '%o', '%m'), array($infile, $target.'.pdf', $mimetype), $this->converters[$mimetype]);
} elseif(isset($this->converters[$mimeparts[0].'/*'])) {
$cmd = str_replace(array('%f', '%o', '%m'), array($infile, $target.'.pdf', $mimetype), $this->converters[$mimeparts[0].'/*']);
} elseif(isset($this->converters['*'])) {
$cmd = str_replace(array('%f', '%o', '%m'), array($infile, $target.'.pdf', $mimetype), $this->converters['*']);
}
if($cmd) {
try {
self::execWithTimeout($cmd, $this->timeout);
} catch(Exception $e) {
$this->lastpreviewfile = '';
return false;
}
}
return true;
}
return true;
} /* }}} */
/**
* Create preview image
*
* This function creates a preview image for the given document
* content or document file. It internally uses
* {@link SeedDMS_Preview::createRawPreview()}. The filename of the
* preview image is created by {@link SeedDMS_Preview_Previewer::getFileName()}
*
* @param object $object instance of SeedDMS_Core_DocumentContent
* or SeedDMS_Core_DocumentFile
* @return boolean true on success, false on failure
*/
public function createPreview($object) { /* {{{ */
if(!$object)
return false;
$document = $object->getDocument();
$file = $document->_dms->contentDir.$object->getPath();
$target = $this->getFileName($object);
return $this->createRawPreview($file, $document->getDir(), $object->getMimeType(), $target);
} /* }}} */
/**
* Check if a preview image already exists.
*
* This function is a companion to {@link SeedDMS_Preview_Previewer::createRawPreview()}.
*
* @param string $infile name of input file including full path
* @param string $dir directory relative to $this->previewDir
* @return boolean true if preview exists, otherwise false
*/
public function hasRawPreview($infile, $dir, $target='') { /* {{{ */
if(!$this->previewDir)
return false;
if(!$target)
$target = $this->previewDir.$dir.md5($infile);
if($target !== false && file_exists($target.'.pdf') && filectime($target.'.pdf') >= filectime($infile)) {
return true;
}
return false;
} /* }}} */
/**
* Check if a preview image already exists.
*
* This function is a companion to {@link SeedDMS_Preview_Previewer::createPreview()}.
*
* @param object $object instance of SeedDMS_Core_DocumentContent
* or SeedDMS_Core_DocumentFile
* @return boolean true if preview exists, otherwise false
*/
public function hasPreview($object) { /* {{{ */
if(!$object)
return false;
if(!$this->previewDir)
return false;
$target = $this->getFileName($object);
if($target !== false && file_exists($target.'.pdf') && filectime($target.'.pdf') >= $object->getDate()) {
return true;
}
return false;
} /* }}} */
/**
* Return a preview image.
*
* This function returns the content of a preview image if it exists..
*
* @param string $infile name of input file including full path
* @param string $dir directory relative to $this->previewDir
* @return boolean/string image content if preview exists, otherwise false
*/
public function getRawPreview($infile, $dir, $target='') { /* {{{ */
if(!$this->previewDir)
return false;
if(!$target)
$target = $this->previewDir.$dir.md5($infile);
if($target && file_exists($target.'.pdf')) {
$this->sendFile($target.'.pdf');
}
} /* }}} */
/**
* Return a preview image.
*
* This function returns the content of a preview image if it exists..
*
* @param object $object instance of SeedDMS_Core_DocumentContent
* or SeedDMS_Core_DocumentFile
* @return boolean/string image content if preview exists, otherwise false
*/
public function getPreview($object) { /* {{{ */
if(!$this->previewDir)
return false;
$target = $this->getFileName($object);
if($target && file_exists($target.'.pdf')) {
$this->sendFile($target.'.pdf');
}
} /* }}} */
/**
* Return file size preview image.
*
* @param object $object instance of SeedDMS_Core_DocumentContent
* or SeedDMS_Core_DocumentFile
* @return boolean/integer size of preview image or false if image
* does not exist
*/
public function getFilesize($object) { /* {{{ */
$target = $this->getFileName($object);
if($target && file_exists($target.'.pdf')) {
return(filesize($target.'.pdf'));
} else {
return false;
}
} /* }}} */
/**
* Delete preview image.
*
* @param object $object instance of SeedDMS_Core_DocumentContent
* or SeedDMS_Core_DocumentFile
* @return boolean true if deletion succeded or false if file does not exist
*/
public function deletePreview($object) { /* {{{ */
if(!$this->previewDir)
return false;
$target = $this->getFileName($object);
if($target && file_exists($target.'.pdf')) {
return(unlink($target.'.pdf'));
} else {
return false;
}
} /* }}} */
static function recurseRmdir($dir) {
$files = array_diff(scandir($dir), array('.','..'));
foreach ($files as $file) {
(is_dir("$dir/$file")) ? SeedDMS_Preview_Previewer::recurseRmdir("$dir/$file") : unlink("$dir/$file");
}
return rmdir($dir);
}
/**
* Delete all preview images belonging to a document
*
* This function removes the preview images of all versions and
* files of a document including the directory. It actually just
* removes the directory for the document in the cache.
*
* @param object $document instance of SeedDMS_Core_Document
* @return boolean true if deletion succeded or false if file does not exist
*/
public function deleteDocumentPreviews($document) { /* {{{ */
if(!$this->previewDir)
return false;
$dir = $this->previewDir.'/'.$document->getDir();
if(file_exists($dir) && is_dir($dir)) {
return SeedDMS_Preview_Previewer::recurseRmdir($dir);
} else {
return false;
}
} /* }}} */
}
?>

View File

@ -0,0 +1,338 @@
<?php
/**
* Implementation of preview documents
*
* @category DMS
* @package SeedDMS_Preview
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class for managing creation of preview images for documents.
*
* @category DMS
* @package SeedDMS_Preview
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2011, Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Preview_Previewer extends SeedDMS_Preview_Base {
/**
* @var integer $width maximum width/height of resized image
* @access protected
*/
protected $width;
function __construct($previewDir, $width=40, $timeout=5, $xsendfile=true) { /* {{{ */
parent::__construct($previewDir, $timeout, $xsendfile);
$this->converters = array(
'image/png' => "convert -resize %wx '%f' '%o'",
'image/gif' => "convert -resize %wx '%f' '%o'",
'image/jpg' => "convert -resize %wx '%f' '%o'",
'image/jpeg' => "convert -resize %wx '%f' '%o'",
'image/svg+xml' => "convert -resize %wx '%f' '%o'",
'text/plain' => "convert -resize %wx '%f' '%o'",
'application/pdf' => "convert -density 100 -resize %wx '%f[0]' '%o'",
'application/postscript' => "convert -density 100 -resize %wx '%f[0]' '%o'",
'application/x-compressed-tar' => "tar tzvf '%f' | convert -density 100 -resize %wx text:-[0] '%o'",
);
$this->width = intval($width);
} /* }}} */
/**
* Return the physical filename of the preview image on disk
*
* @param object $object document content or document file
* @param integer $width width of preview image
* @return string file name of preview image
*/
public function getFileName($object, $width) { /* {{{ */
if(!$object)
return false;
$document = $object->getDocument();
$dms = $document->_dms;
$dir = $this->previewDir.'/'.$document->getDir();
switch(get_class($object)) {
case $dms->getClassname('documentcontent'):
$target = $dir.'p'.$object->getVersion().'-'.$width;
break;
case "SeedDMS_Core_DocumentFile":
$target = $dir.'f'.$object->getID().'-'.$width;
break;
default:
return false;
}
return $target;
} /* }}} */
/**
* Create a preview image for a given file
*
* This method creates a preview image in png format for a regular file
* in the file system and stores the result in the directory $dir relative
* to the configured preview directory. The filename of the resulting preview
* image is either $target.png (if set) or md5($infile)-$width.png.
* The $mimetype is used to select the propper conversion programm.
* An already existing preview image is replaced.
*
* @param string $infile name of input file including full path
* @param string $dir directory relative to $this->previewDir
* @param string $mimetype MimeType of input file
* @param integer $width width of generated preview image
* @param string $target optional name of preview image (without extension)
* @return boolean true on success, false on failure
*/
public function createRawPreview($infile, $dir, $mimetype, $width=0, $target='') { /* {{{ */
if($width == 0)
$width = $this->width;
else
$width = intval($width);
if(!$this->previewDir)
return false;
if(!is_dir($this->previewDir.'/'.$dir)) {
if (!SeedDMS_Core_File::makeDir($this->previewDir.'/'.$dir)) {
return false;
}
}
if(!file_exists($infile))
return false;
if(!$target)
$target = $this->previewDir.$dir.md5($infile).'-'.$width;
$this->lastpreviewfile = $target.'.png';
if($target != '' && (!file_exists($target.'.png') || filectime($target.'.png') < filectime($infile))) {
$cmd = '';
$mimeparts = explode('/', $mimetype, 2);
if(isset($this->converters[$mimetype])) {
$cmd = str_replace(array('%w', '%f', '%o', '%m'), array($width, $infile, $target.'.png', $mimetype), $this->converters[$mimetype]);
} elseif(isset($this->converters[$mimeparts[0].'/*'])) {
$cmd = str_replace(array('%w', '%f', '%o', '%m'), array($width, $infile, $target.'.png', $mimetype), $this->converters[$mimeparts[0].'/*']);
} elseif(isset($this->converters['*'])) {
$cmd = str_replace(array('%w', '%f', '%o', '%m'), array($width, $infile, $target.'.png', $mimetype), $this->converters['*']);
}
if($cmd) {
try {
self::execWithTimeout($cmd, $this->timeout);
} catch(Exception $e) {
$this->lastpreviewfile = '';
return false;
}
}
return true;
}
return true;
} /* }}} */
/**
* Create preview image
*
* This function creates a preview image for the given document
* content or document file. It internally uses
* {@link SeedDMS_Preview::createRawPreview()}. The filename of the
* preview image is created by {@link SeedDMS_Preview_Previewer::getFileName()}
*
* @param object $object instance of SeedDMS_Core_DocumentContent
* or SeedDMS_Core_DocumentFile
* @param integer $width desired width of preview image
* @return boolean true on success, false on failure
*/
public function createPreview($object, $width=0) { /* {{{ */
if(!$object)
return false;
if($width == 0)
$width = $this->width;
else
$width = intval($width);
$document = $object->getDocument();
$file = $document->_dms->contentDir.$object->getPath();
$target = $this->getFileName($object, $width);
return $this->createRawPreview($file, $document->getDir(), $object->getMimeType(), $width, $target);
} /* }}} */
/**
* Check if a preview image already exists.
*
* This function is a companion to {@link SeedDMS_Preview_Previewer::createRawPreview()}.
*
* @param string $infile name of input file including full path
* @param string $dir directory relative to $this->previewDir
* @param integer $width desired width of preview image
* @return boolean true if preview exists, otherwise false
*/
public function hasRawPreview($infile, $dir, $width=0) { /* {{{ */
if($width == 0)
$width = $this->width;
else
$width = intval($width);
if(!$this->previewDir)
return false;
$target = $this->previewDir.$dir.md5($infile).'-'.$width;
if($target !== false && file_exists($target.'.png') && filectime($target.'.png') >= filectime($infile)) {
return true;
}
return false;
} /* }}} */
/**
* Check if a preview image already exists.
*
* This function is a companion to {@link SeedDMS_Preview_Previewer::createPreview()}.
*
* @param object $object instance of SeedDMS_Core_DocumentContent
* or SeedDMS_Core_DocumentFile
* @param integer $width desired width of preview image
* @return boolean true if preview exists, otherwise false
*/
public function hasPreview($object, $width=0) { /* {{{ */
if(!$object)
return false;
if($width == 0)
$width = $this->width;
else
$width = intval($width);
if(!$this->previewDir)
return false;
$target = $this->getFileName($object, $width);
if($target !== false && file_exists($target.'.png') && filectime($target.'.png') >= $object->getDate()) {
return true;
}
return false;
} /* }}} */
/**
* Return a preview image.
*
* This function returns the content of a preview image if it exists..
*
* @param string $infile name of input file including full path
* @param string $dir directory relative to $this->previewDir
* @param integer $width desired width of preview image
* @return boolean/string image content if preview exists, otherwise false
*/
public function getRawPreview($infile, $dir, $width=0) { /* {{{ */
if($width == 0)
$width = $this->width;
else
$width = intval($width);
if(!$this->previewDir)
return false;
$target = $this->previewDir.$dir.md5($infile).'-'.$width;
if($target && file_exists($target.'.png')) {
$this->sendFile($target.'.png');
}
} /* }}} */
/**
* Return a preview image.
*
* This function returns the content of a preview image if it exists..
*
* @param object $object instance of SeedDMS_Core_DocumentContent
* or SeedDMS_Core_DocumentFile
* @param integer $width desired width of preview image
* @return boolean/string image content if preview exists, otherwise false
*/
public function getPreview($object, $width=0) { /* {{{ */
if($width == 0)
$width = $this->width;
else
$width = intval($width);
if(!$this->previewDir)
return false;
$target = $this->getFileName($object, $width);
if($target && file_exists($target.'.png')) {
$this->sendFile($target.'.png');
}
} /* }}} */
/**
* Return file size preview image.
*
* @param object $object instance of SeedDMS_Core_DocumentContent
* or SeedDMS_Core_DocumentFile
* @param integer $width desired width of preview image
* @return boolean/integer size of preview image or false if image
* does not exist
*/
public function getFilesize($object, $width=0) { /* {{{ */
if($width == 0)
$width = $this->width;
else
$width = intval($width);
$target = $this->getFileName($object, $width);
if($target && file_exists($target.'.png')) {
return(filesize($target.'.png'));
} else {
return false;
}
} /* }}} */
/**
* Delete preview image.
*
* @param object $object instance of SeedDMS_Core_DocumentContent
* or SeedDMS_Core_DocumentFile
* @param integer $width desired width of preview image
* @return boolean true if deletion succeded or false if file does not exist
*/
public function deletePreview($object, $width=0) { /* {{{ */
if($width == 0)
$width = $this->width;
else
$width = intval($width);
if(!$this->previewDir)
return false;
$target = $this->getFileName($object, $width);
if($target && file_exists($target.'.png')) {
return(unlink($target.'.png'));
} else {
return false;
}
} /* }}} */
static function recurseRmdir($dir) {
$files = array_diff(scandir($dir), array('.','..'));
foreach ($files as $file) {
(is_dir("$dir/$file")) ? SeedDMS_Preview_Previewer::recurseRmdir("$dir/$file") : unlink("$dir/$file");
}
return rmdir($dir);
}
/**
* Delete all preview images belonging to a document
*
* This function removes the preview images of all versions and
* files of a document including the directory. It actually just
* removes the directory for the document in the cache.
*
* @param object $document instance of SeedDMS_Core_Document
* @return boolean true if deletion succeded or false if file does not exist
*/
public function deleteDocumentPreviews($document) { /* {{{ */
if(!$this->previewDir)
return false;
$dir = $this->previewDir.'/'.$document->getDir();
if(file_exists($dir) && is_dir($dir)) {
return SeedDMS_Preview_Previewer::recurseRmdir($dir);
} else {
return false;
}
} /* }}} */
}
?>

457
SeedDMS_Preview/package.xml Normal file
View File

@ -0,0 +1,457 @@
<?xml version="1.0" encoding="UTF-8"?>
<package packagerversion="1.8.1" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
<name>SeedDMS_Preview</name>
<channel>pear.php.net</channel>
<summary>Create thumbnails from document content for SeedDMS</summary>
<description>SeedDMS is a web based document management system (DMS). These
are the classes to create preview images and pdf file from the document content.</description>
<lead>
<name>Uwe Steinmann</name>
<user>steinm</user>
<email>uwe@steinmann.cx</email>
<active>yes</active>
</lead>
<date>2020-12-23</date>
<time>09:49:39</time>
<version>
<release>1.3.2</release>
<api>1.3.1</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
set header Content-Length
update package description
</notes>
<contents>
<dir baseinstalldir="SeedDMS" name="/">
<dir name="Preview">
<file name="Base.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
<file name="Previewer.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
<file name="PdfPreviewer.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
</dir> <!-- /Lucene -->
<dir name="tests">
</dir> <!-- /tests -->
<file name="Preview.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
</dir> <!-- / -->
</contents>
<dependencies>
<required>
<php>
<min>4.3.0</min>
</php>
<pearinstaller>
<min>1.5.4</min>
</pearinstaller>
</required>
</dependencies>
<phprelease />
<changelog>
<release>
<date>2012-11-20</date>
<time>08:05:38</time>
<version>
<release>1.0.0</release>
<api>1.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
initial version
</notes>
</release>
<release>
<date>2013-04-29</date>
<time>19:34:07</time>
<version>
<release>1.1.0</release>
<api>1.1.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
preview image can also be created from a document file (SeedDMS_Core_DocumentFile)
</notes>
</release>
<release>
<date>2014-03-18</date>
<time>16:34:59</time>
<version>
<release>1.1.1</release>
<api>1.1.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
add converters for .tar.gz, .ps, .txt
</notes>
</release>
<release>
<date>2014-04-10</date>
<time>20:29:39</time>
<version>
<release>1.1.2</release>
<api>1.1.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
create fixed width image with proportional height
</notes>
</release>
<release>
<date>2015-02-13</date>
<time>20:29:39</time>
<version>
<release>1.1.3</release>
<api>1.1.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
preview images will also be recreated if the object this image belongs is of newer date than the image itself. This happens if versions are being deleted and than a new version is uploaded. Because the new version will get the version number of the old version, it will also take over the old preview image.Comparing the creation date of the image with the object detects this case.
</notes>
</release>
<release>
<date>2015-08-08</date>
<time>09:36:57</time>
<version>
<release>1.1.4</release>
<api>1.1.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
command for creating the preview will be called with a given timeout
</notes>
</release>
<release>
<date>2016-02-11</date>
<time>09:36:57</time>
<version>
<release>1.1.5</release>
<api>1.1.5</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
add method getFilesize()
timeout for external commands can be passed to contructor of SeedDMS_Preview_Previewer
</notes>
</release>
<release>
<date>2016-03-08</date>
<time>09:36:57</time>
<version>
<release>1.1.6</release>
<api>1.1.6</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
check if object passed to createPreview(), hasPreview() is not null
</notes>
</release>
<release>
<date>2016-03-29</date>
<time>08:07:14</time>
<version>
<release>1.1.7</release>
<api>1.1.7</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
set last parameter of stream_select() to 200000 micro sec. in case the timeout in sec. is set to 0
</notes>
</release>
<release>
<date>2016-04-05</date>
<time>15:17:11</time>
<version>
<release>1.1.8</release>
<api>1.1.8</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
pass variables to stream_select (required by php7)
</notes>
</release>
<release>
<date>2016-04-26</date>
<time>15:17:11</time>
<version>
<release>1.1.9</release>
<api>1.1.9</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
add more documentation
finish deletePreview()
add new method deleteDocumentPreviews()
fix calculation of timeout (Bug #269)
check if cache dir exists before deleting it in deleteDocumentPreviews()
</notes>
</release>
<release>
<date>2016-11-07</date>
<time>15:17:11</time>
<version>
<release>1.2.0</release>
<api>1.2.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
add new previewer which converts document to pdf instead of png
</notes>
</release>
<release>
<date>2016-11-15</date>
<time>21:00:26</time>
<version>
<release>1.2.1</release>
<api>1.2.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
setConverters() overrides exiting converters
</notes>
</release>
<release>
<date>2017-03-02</date>
<time>07:14:59</time>
<version>
<release>1.2.2</release>
<api>1.2.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
commands can be set for mimetypes 'xxxx/*' and '*'
pass mimetype as parameter '%m' to converter
</notes>
</release>
<release>
<date>2017-09-18</date>
<time>07:14:32</time>
<version>
<release>1.2.3</release>
<api>1.2.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
createPreview() returns false if running the converter command fails
</notes>
</release>
<release>
<date>2017-10-11</date>
<time>07:14:32</time>
<version>
<release>1.2.4</release>
<api>1.2.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
fix typo in converter for tar.gz files
</notes>
</release>
<release>
<date>2017-10-11</date>
<time>07:14:32</time>
<version>
<release>1.2.5</release>
<api>1.2.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
SeedDMS_Preview_Base::hasConverter() returns only try if command is set
</notes>
</release>
<release>
<date>2017-12-04</date>
<time>10:59:39</time>
<version>
<release>1.2.6</release>
<api>1.2.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
SeedDMS_Preview_Base::setConverters() overrides existing converters.
New method SeedDMS_Preview_Base::addConverters() merges new converters with old ones.
</notes>
</release>
<release>
<date>2018-01-18</date>
<time>10:59:39</time>
<version>
<release>1.2.7</release>
<api>1.2.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
add SeedDMS_Preview_Base::sendFile() as a replacement for readfile() which uses
mod_xsendfile if available
execWithTimeout() reads data from stderr and returns it together with stdout in array
</notes>
</release>
<release>
<date>2018-03-08</date>
<time>10:59:39</time>
<version>
<release>1.2.8</release>
<api>1.2.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
preview is also created if SeedDMS_Core_DocumentContent has a child class
</notes>
</release>
<release>
<date>2018-07-13</date>
<time>10:59:39</time>
<version>
<release>1.2.9</release>
<api>1.2.9</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
make sure list of converters is always an array
usage of mod_sendfile can be configured
</notes>
</release>
<release>
<date>2019-02-11</date>
<time>10:59:39</time>
<version>
<release>1.2.10</release>
<api>1.2.10</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
new parameter for enabling/disabling xsendfile
fix creation of pdf preview if document content class is not SeedDMS_Core_DocumentContent
</notes>
</release>
<release>
<date>2020-02-17</date>
<time>09:49:39</time>
<version>
<release>1.3.0</release>
<api>1.3.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
add new methode getPreviewFile()
</notes>
</release>
<release>
<date>2020-03-21</date>
<time>09:49:39</time>
<version>
<release>1.3.1</release>
<api>1.3.1</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
add parameter $target to SeedDMS_Preview_pdfPreviewer::hasRawPreview() and SeedDMS_Preview_pdfPreviewer::getRawPreview()
</notes>
</release>
</changelog>
</package>

View File

View File

@ -0,0 +1,44 @@
<?php
// SeedDMS. Document Management System
// Copyright (C) 2011-2015 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.
/**
* @uses SeedDMS_SQLiteFTS_Indexer
*/
require_once('SQLiteFTS/Indexer.php');
/**
* @uses SeedDMS_SQLiteFTS_Search
*/
require_once('SQLiteFTS/Search.php');
/**
* @uses SeedDMS_SQLiteFTS_Term
*/
require_once('SQLiteFTS/Term.php');
/**
* @uses SeedDMS_SQLiteFTS_QueryHit
*/
require_once('SQLiteFTS/QueryHit.php');
/**
* @uses SeedDMS_SQLiteFTS_IndexedDocument
*/
require_once('SQLiteFTS/IndexedDocument.php');
?>

View File

@ -0,0 +1,66 @@
<?php
/**
* Implementation of a document
*
* @category DMS
* @package SeedDMS_SQLiteFTS
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class for managing a document.
*
* @category DMS
* @package SeedDMS_SQLiteFTS
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2011, Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_SQLiteFTS_Document {
/**
* @var integer $id id of document
* @access protected
*/
public $id;
/**
* @var array $fields fields
* @access protected
*/
protected $fields;
public function __get($key) { /* {{{ */
if(isset($this->fields[$key]))
return $this->fields[$key];
else
return false;
} /* }}} */
public function addField($key, $value) { /* {{{ */
//if($key == 'document_id') {
if($key == 'docid') {
$this->id = $this->fields[$key] = (int) $value;
} else {
if(isset($this->fields[$key]))
$this->fields[$key] .= ' '.$value;
else
$this->fields[$key] = $value;
}
} /* }}} */
public function getFieldValue($key) { /* {{{ */
if(isset($this->fields[$key]))
return $this->fields[$key];
else
return false;
} /* }}} */
}
?>

View File

@ -0,0 +1,206 @@
<?php
/**
* Implementation of an indexed document
*
* @category DMS
* @package SeedDMS_SQLiteFTS
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
/**
* @uses SeedDMS_SQLiteFTS_Document
*/
require_once('Document.php');
/**
* Class for managing an indexed document.
*
* @category DMS
* @package SeedDMS_SQLiteFTS
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2011, Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_SQLiteFTS_IndexedDocument extends SeedDMS_SQLiteFTS_Document {
/**
* @var string
*/
protected $errormsg;
/**
* @var string
*/
protected $mimetype;
/**
* @var string
*/
protected $cmd;
static function execWithTimeout($cmd, $timeout=2) { /* {{{ */
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
$pipes = array();
$timeout += time();
$process = proc_open($cmd, $descriptorspec, $pipes);
if (!is_resource($process)) {
throw new Exception("proc_open failed on: " . $cmd);
}
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
$output = $error = '';
$timeleft = $timeout - time();
$read = array($pipes[1], $pipes[2]);
$write = NULL;
$exeptions = NULL;
do {
$num_changed_streams = stream_select($read, $write, $exeptions, $timeleft, 200000);
if ($num_changed_streams === false) {
proc_terminate($process);
throw new Exception("stream select failed on: " . $cmd);
} elseif ($num_changed_streams > 0) {
$output .= fread($pipes[1], 8192);
$error .= fread($pipes[2], 8192);
}
$timeleft = $timeout - time();
} while (!feof($pipes[1]) && $timeleft > 0);
if ($timeleft <= 0) {
proc_terminate($process);
throw new Exception("command timeout on: " . $cmd);
} else {
return array('stdout'=>$output, 'stderr'=>$error);
}
} /* }}} */
/**
* Constructor. Creates our indexable document and adds all
* necessary fields to it using the passed in document
*/
public function __construct($dms, $document, $convcmd=null, $nocontent=false, $timeout=5) { /* {{{ */
$this->errormsg = '';
$this->cmd = '';
$this->mimetype = '';
$this->addField('title', $document->getName());
if($acllist = $document->getReadAccessList(1, 1, 1)) {
$allu = [];
foreach($acllist['users'] as $u)
$allu[] = $u->getLogin();
$this->addField('users', implode(' ', $allu));
/*
$allg = [];
foreach($acllist['groups'] as $g)
$allg[] = $g->getName();
$this->addField('groups', implode(' ', $allg));
*/
}
if($attributes = $document->getAttributes()) {
foreach($attributes as $attribute) {
$attrdef = $attribute->getAttributeDefinition();
if($attrdef->getValueSet() != '')
$this->addField('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue());
else
$this->addField('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue());
}
}
$owner = $document->getOwner();
$this->addField('owner', $owner->getLogin());
$this->addField('path', str_replace(':', 'x', $document->getFolderList()));
if($comment = $document->getComment()) {
$this->addField('comment', $comment);
}
if($document->isType('document')) {
$this->addField('document_id', 'D'.$document->getID());
$version = $document->getLatestContent();
if($version) {
$this->addField('mimetype', $version->getMimeType());
$this->addField('origfilename', $version->getOriginalFileName());
if(!$nocontent)
$this->addField('created', $version->getDate(), 'unindexed');
if($attributes = $version->getAttributes()) {
foreach($attributes as $attribute) {
$attrdef = $attribute->getAttributeDefinition();
if($attrdef->getValueSet() != '')
$this->addField('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue());
else
$this->addField('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue());
}
}
}
if($categories = $document->getCategories()) {
$names = array();
foreach($categories as $cat) {
$names[] = $cat->getName();
}
$this->addField('category', implode(' ', $names));
}
if($keywords = $document->getKeywords()) {
$this->addField('keywords', $keywords);
}
if($version) {
$status = $version->getStatus();
$this->addField('status', $status['status']+10);
}
if($version && !$nocontent) {
$path = $dms->contentDir . $version->getPath();
if(file_exists($path)) {
$content = '';
$mimetype = $version->getMimeType();
$this->mimetype = $mimetype;
$cmd = '';
$mimeparts = explode('/', $mimetype, 2);
if(isset($convcmd[$mimetype])) {
$cmd = sprintf($convcmd[$mimetype], $path);
} elseif(isset($convcmd[$mimeparts[0].'/*'])) {
$cmd = sprintf($convcmd[$mimetype], $path);
} elseif(isset($convcmd['*'])) {
$cmd = sprintf($convcmd[$mimetype], $path);
}
if($cmd) {
$this->cmd = $cmd;
try {
$content = self::execWithTimeout($cmd, $timeout);
if($content['stdout']) {
$this->addField('content', $content['stdout'], 'unstored');
}
if($content['stderr']) {
$this->errormsg = $content['stderr'];
}
} catch (Exception $e) {
}
}
}
}
} elseif($document->isType('folder')) {
$this->addField('document_id', 'F'.$document->getID());
}
} /* }}} */
public function getErrorMsg() { /* {{{ */
return $this->errormsg;
} /* }}} */
public function getMimeType() { /* {{{ */
return $this->mimetype;
} /* }}} */
public function getCmd() { /* {{{ */
return $this->cmd;
} /* }}} */
}
?>

View File

@ -0,0 +1,309 @@
<?php
/**
* Implementation of SQLiteFTS index
*
* @category DMS
* @package SeedDMS_Lucene
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class for managing a SQLiteFTS index.
*
* @category DMS
* @package SeedDMS_Lucene
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2011, Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_SQLiteFTS_Indexer {
/**
* @var object $index sqlite index
* @access protected
*/
protected $_conn;
/**
* Constructor
*
*/
function __construct($indexerDir) { /* {{{ */
$this->_conn = new PDO('sqlite:'.$indexerDir.'/index.db');
} /* }}} */
/**
* Open an existing index
*
* @param string $indexerDir directory on disk containing the index
*/
static function open($conf) { /* {{{ */
if(file_exists($conf['indexdir'].'/index.db')) {
return new SeedDMS_SQLiteFTS_Indexer($conf['indexdir']);
} else
return self::create($conf);
} /* }}} */
/**
* Create a new index
*
* @param array $conf $conf['indexdir'] is the directory on disk containing the index
*/
static function create($conf) { /* {{{ */
if(file_exists($conf['indexdir'].'/index.db'))
unlink($conf['indexdir'].'/index.db');
$index = new SeedDMS_SQLiteFTS_Indexer($conf['indexdir']);
/* Make sure the sequence of fields is identical to the field list
* in SeedDMS_SQLiteFTS_Term
*/
$version = SQLite3::version();
if($version['versionNumber'] >= 3008000)
$sql = 'CREATE VIRTUAL TABLE docs USING fts4(documentid, title, comment, keywords, category, mimetype, origfilename, owner, content, created, users, status, path, notindexed=created, matchinfo=fts3)';
else
$sql = 'CREATE VIRTUAL TABLE docs USING fts4(documentid, title, comment, keywords, category, mimetype, origfilename, owner, content, created, users, status, path, matchinfo=fts3)';
$res = $index->_conn->exec($sql);
if($res === false) {
return null;
}
$sql = 'CREATE VIRTUAL TABLE docs_terms USING fts4aux(docs);';
$res = $index->_conn->exec($sql);
if($res === false) {
return null;
}
return($index);
} /* }}} */
/**
* Do some initialization
*
*/
static function init($stopWordsFile='') { /* {{{ */
} /* }}} */
/**
* Add document to index
*
* @param object $doc indexed document of class
* SeedDMS_SQLiteFTS_IndexedDocument
* @return boolean false in case of an error, otherwise true
*/
function addDocument($doc) { /* {{{ */
if(!$this->_conn)
return false;
$sql = "INSERT INTO docs (documentid, title, comment, keywords, category, owner, content, mimetype, origfilename, created, users, status, path) VALUES (".$this->_conn->quote($doc->getFieldValue('document_id')).", ".$this->_conn->quote($doc->getFieldValue('title')).", ".$this->_conn->quote($doc->getFieldValue('comment')).", ".$this->_conn->quote($doc->getFieldValue('keywords')).", ".$this->_conn->quote($doc->getFieldValue('category')).", ".$this->_conn->quote($doc->getFieldValue('owner')).", ".$this->_conn->quote($doc->getFieldValue('content')).", ".$this->_conn->quote($doc->getFieldValue('mimetype')).", ".$this->_conn->quote($doc->getFieldValue('origfilename')).", ".(int)$doc->getFieldValue('created').", ".$this->_conn->quote($doc->getFieldValue('users')).", ".$this->_conn->quote($doc->getFieldValue('status')).", ".$this->_conn->quote($doc->getFieldValue('path'))/*time()*/.")";
$res = $this->_conn->exec($sql);
if($res === false) {
return false;
var_dump($this->_conn->errorInfo());
}
return $res;
} /* }}} */
/**
* Remove document from index
*
* @param object $doc indexed document of class
* SeedDMS_SQLiteFTS_IndexedDocument
* @return boolean false in case of an error, otherwise true
*/
public function delete($id) { /* {{{ */
if(!$this->_conn)
return false;
$sql = "DELETE FROM docs WHERE docid=".(int) $id;
$res = $this->_conn->exec($sql);
return $res;
} /* }}} */
/**
* Check if document was deleted
*
* Just for compatibility with lucene.
*
* @return boolean always false
*/
public function isDeleted($id) { /* {{{ */
return false;
} /* }}} */
/**
* Find documents in index
*
* @param string $query
* @param array $limit array with elements 'limit' and 'offset'
* @return boolean false in case of an error, otherwise array with elements
* 'count', 'hits', 'facets'
*/
public function find($query, $limit=array()) { /* {{{ */
if(!$this->_conn)
return false;
$sql = "SELECT count(*) AS `c` FROM `docs`";
if($query)
$sql .= " WHERE docs MATCH ".$this->_conn->quote($query);
$res = $this->_conn->query($sql);
$row = $res->fetch();
$sql = "SELECT docid, documentid FROM docs";
if($query)
$sql .= " WHERE docs MATCH ".$this->_conn->quote($query);
$res = $this->_conn->query($sql);
if(!empty($limit['limit']))
$sql .= " LIMIT ".(int) $limit['limit'];
if(!empty($limit['offset']))
$sql .= " OFFSET ".(int) $limit['offset'];
$res = $this->_conn->query($sql);
$hits = array();
if($res) {
foreach($res as $rec) {
$hit = new SeedDMS_SQLiteFTS_QueryHit($this);
$hit->id = $rec['docid'];
$hit->documentid = $rec['documentid'];
$hits[] = $hit;
}
}
return array('count'=>$row['c'], 'hits'=>$hits);
} /* }}} */
/**
* Get a single document from index
*
* @param integer $id id of document
* @return boolean false in case of an error, otherwise true
*/
public function findById($id) { /* {{{ */
if(!$this->_conn)
return false;
$sql = "SELECT docid FROM docs WHERE docid=".(int) $id;
$res = $this->_conn->query($sql);
$hits = array();
if($res) {
while($rec = $res->fetch(PDO::FETCH_ASSOC)) {
$hit = new SeedDMS_SQLiteFTS_QueryHit($this);
$hit->id = $rec['docid'];
$hits[] = $hit;
}
}
return $hits;
} /* }}} */
/**
* Get a single document from index
*
* @param integer $id id of index record
* @return boolean false in case of an error, otherwise true
*/
public function getDocument($id) { /* {{{ */
if(!$this->_conn)
return false;
$sql = "SELECT docid, documentid, title, comment, owner, keywords, category, mimetype, origfilename, created, users, status, path FROM docs WHERE docid=".$id;
$res = $this->_conn->query($sql);
$doc = false;
if($res) {
$rec = $res->fetch(PDO::FETCH_ASSOC);
$doc = new SeedDMS_SQLiteFTS_Document();
$doc->addField('docid', $rec['docid']);
$doc->addField('document_id', $rec['documentid']);
$doc->addField('title', $rec['title']);
$doc->addField('comment', $rec['comment']);
$doc->addField('keywords', $rec['keywords']);
$doc->addField('category', $rec['category']);
$doc->addField('mimetype', $rec['mimetype']);
$doc->addField('origfilename', $rec['origfilename']);
$doc->addField('owner', $rec['owner']);
$doc->addField('created', $rec['created']);
$doc->addField('users', $rec['users']);
$doc->addField('status', $rec['status']);
$doc->addField('path', $rec['path']);
}
return $doc;
} /* }}} */
/**
* Get a single folder from index
*
* @param integer $id id of folder
* @return boolean false in case of an error, otherwise true
*/
public function getFolder($id) { /* {{{ */
if(!$this->_conn)
return false;
$sql = "SELECT docid, documentid, title, comment, owner, keywords, category, mimetype, origfilename, created, users, status, path FROM docs WHERE documentid='F".$id."'";
$res = $this->_conn->query($sql);
$doc = false;
if($res) {
$rec = $res->fetch(PDO::FETCH_ASSOC);
$doc = new SeedDMS_SQLiteFTS_Document();
$doc->addField('docid', $rec['docid']);
$doc->addField('document_id', $rec['documentid']);
$doc->addField('title', $rec['title']);
$doc->addField('comment', $rec['comment']);
$doc->addField('owner', $rec['owner']);
$doc->addField('created', $rec['created']);
$doc->addField('users', $rec['users']);
$doc->addField('path', $rec['path']);
}
return $doc;
} /* }}} */
/**
* Return list of terms in index
*
* This function does nothing!
*/
public function terms() { /* {{{ */
if(!$this->_conn)
return false;
$sql = "SELECT term, col, occurrences FROM docs_terms WHERE col!='*' ORDER BY col";
$res = $this->_conn->query($sql);
$terms = array();
if($res) {
while($rec = $res->fetch(PDO::FETCH_ASSOC)) {
$term = new SeedDMS_SQLiteFTS_Term($rec['term'], $rec['col'], $rec['occurrences']);
$terms[] = $term;
}
}
return $terms;
} /* }}} */
/**
* Return list of documents in index
*
*/
public function count() { /* {{{ */
$sql = "SELECT count(*) c FROM docs";
$res = $this->_conn->query($sql);
if($res) {
$rec = $res->fetch(PDO::FETCH_ASSOC);
return $rec['c'];
}
return 0;
} /* }}} */
/**
* Commit changes
*
* This function does nothing!
*/
function commit() { /* {{{ */
} /* }}} */
/**
* Optimize index
*
* This function does nothing!
*/
function optimize() { /* {{{ */
} /* }}} */
}
?>

View File

@ -0,0 +1,71 @@
<?php
/**
* Implementation of a query hit
*
* @category DMS
* @package SeedDMS_SQLiteFTS
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class for managing a query hit.
*
* @category DMS
* @package SeedDMS_SQLiteFTS
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2011, Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_SQLiteFTS_QueryHit {
/**
* @var SeedDMS_SQliteFTS_Indexer $index
* @access protected
*/
protected $_index;
/**
* @var SeedDMS_SQliteFTS_Document $document
* @access protected
*/
protected $_document;
/**
* @var integer $id id of index document
* @access public
*/
public $id;
/**
* @var integer $id id of real document
* @access public
*/
public $documentid;
/**
*
*/
public function __construct(SeedDMS_SQLiteFTS_Indexer $index) { /* {{{ */
$this->_index = $index;
} /* }}} */
/**
* Return the document associated with this hit
*
* @return SeedDMS_SQLiteFTS_Document
*/
public function getDocument() { /* {{{ */
if (!$this->_document instanceof SeedDMS_SQLiteFTS_Document) {
$this->_document = $this->_index->getDocument($this->id);
}
return $this->_document;
} /* }}} */
}
?>

View File

@ -0,0 +1,140 @@
<?php
/**
* Implementation of search in SQlite FTS index
*
* @category DMS
* @package SeedDMS_Lucene
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class for searching in a SQlite FTS index.
*
* @category DMS
* @package SeedDMS_Lucene
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2011, Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_SQliteFTS_Search {
/**
* @var object $index SQlite FTS index
* @access protected
*/
protected $index;
/**
* Create a new instance of the search
*
* @param object $index SQlite FTS index
* @return object instance of SeedDMS_SQliteFTS_Search
*/
function __construct($index) { /* {{{ */
$this->index = $index;
$this->version = '@package_version@';
if($this->version[0] == '@')
$this->version = '3.0.0';
} /* }}} */
/**
* Get document from index
*
* @param int $id real document id
* @return object instance of SeedDMS_SQliteFTS_QueryHit or false
*/
function getDocument($id) { /* {{{ */
$hits = $this->index->find('D'.$id);
return $hits['hits'] ? $hits['hits'][0] : false;
} /* }}} */
/**
* Get folder from index
*
* @param int $id real folder id
* @return object instance of SeedDMS_SQliteFTS_QueryHit or false
*/
function getFolder($id) { /* {{{ */
$hits = $this->index->find('F'.$id);
return $hits['hits'] ? $hits['hits'][0] : false;
} /* }}} */
/**
* Search in index
*
* @param object $index SQlite FTS index
* @return object instance of SeedDMS_Lucene_Search
*/
function search($term, $fields=array(), $limit=array()) { /* {{{ */
$querystr = '';
$term = trim($term);
if($term) {
$querystr = substr($term, -1) != '*' ? $term.'*' : $term;
}
if(!empty($fields['owner'])) {
if(is_string($fields['owner'])) {
if($querystr)
$querystr .= ' ';
$querystr .= 'owner:'.$fields['owner'];
} elseif(is_array($fields['owner'])) {
if($querystr)
$querystr .= ' ';
$querystr .= '(owner:';
$querystr .= implode(' OR owner:', $fields['owner']);
$querystr .= ')';
}
}
if(!empty($fields['category'])) {
if($querystr)
$querystr .= ' ';
$querystr .= '(category:';
$querystr .= implode(' OR category:', $fields['category']);
$querystr .= ')';
}
if(!empty($fields['status'])) {
if($querystr)
$querystr .= ' ';
$status = array_map(function($v){return $v+10;}, $fields['status']);
$querystr .= '(status:';
$querystr .= implode(' OR status:', $status);
$querystr .= ')';
}
if(!empty($fields['user'])) {
if($querystr)
$querystr .= ' ';
$querystr .= '(users:';
$querystr .= implode(' OR users:', $fields['user']);
$querystr .= ')';
}
if(!empty($fields['rootFolder']) && $fields['rootFolder']->getFolderList()) {
if($querystr)
$querystr .= ' ';
$querystr .= '(path:';
$querystr .= str_replace(':', 'x', $fields['rootFolder']->getFolderList().$fields['rootFolder']->getID().':');
$querystr .= ')';
}
if(!empty($fields['startFolder']) && $fields['startFolder']->getFolderList()) {
if($querystr)
$querystr .= ' ';
$querystr .= '(path:';
$querystr .= str_replace(':', 'x', $fields['startFolder']->getFolderList().$fields['startFolder']->getID().':');
$querystr .= ')';
}
try {
$result = $this->index->find($querystr, $limit);
$recs = array();
foreach($result["hits"] as $hit) {
$recs[] = array('id'=>$hit->id, 'document_id'=>$hit->documentid);
}
return array('count'=>$result['count'], 'hits'=>$recs, 'facets'=>array());
} catch (Exception $e) {
return false;
}
} /* }}} */
}
?>

View File

@ -0,0 +1,70 @@
<?php
/**
* Implementation of a term
*
* @category DMS
* @package SeedDMS_SQLiteFTS
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010, Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class for managing a term.
*
* @category DMS
* @package SeedDMS_SQLiteFTS
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2011, Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_SQLiteFTS_Term {
/**
* @var string $text
* @access public
*/
public $text;
/**
* @var string $field
* @access public
*/
public $field;
/**
* @var integer $occurrence
* @access public
*/
public $_occurrence;
/**
*
*/
public function __construct($term, $col, $occurrence) { /* {{{ */
$this->text = $term;
$fields = array(
0 => 'documentid',
1 => 'title',
2 => 'comment',
3 => 'keywords',
4 => 'category',
5 => 'mimetype',
6 => 'origfilename',
7 => 'owner',
8 => 'content',
9 => 'created',
10 => 'user',
11 => 'status',
12 => 'path'
);
$this->field = $fields[$col];
$this->_occurrence = $occurrence;
} /* }}} */
}
?>

View File

@ -0,0 +1,316 @@
<?xml version="1.0" encoding="UTF-8"?>
<package packagerversion="1.8.1" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
<name>SeedDMS_SQLiteFTS</name>
<channel>pear.php.net</channel>
<summary>Fulltext search based on sqlite for SeedDMS</summary>
<description>SeedDMS is a web based document management system (DMS). This is
the fulltext search engine for it, based on SQLite FTS.</description>
<lead>
<name>Uwe Steinmann</name>
<user>steinm</user>
<email>uwe@steinmann.cx</email>
<active>yes</active>
</lead>
<date>2020-12-12</date>
<time>08:57:44</time>
<version>
<release>1.0.15</release>
<api>1.0.15</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
- add indexing folders
</notes>
<contents>
<dir baseinstalldir="SeedDMS" name="/">
<dir name="SQLiteFTS">
<file name="Indexer.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
<file name="IndexedDocument.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
<file name="Document.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
<file name="QueryHit.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
<file name="Search.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
<file name="Term.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
</dir> <!-- /SQLiteFTS -->
<dir name="tests">
</dir> <!-- /tests -->
<file name="SQLiteFTS.php" role="php">
<tasks:replace from="@package_version@" to="version" type="package-info" />
</file>
</dir> <!-- / -->
</contents>
<dependencies>
<required>
<php>
<min>4.3.0</min>
</php>
<pearinstaller>
<min>1.5.4</min>
</pearinstaller>
</required>
</dependencies>
<phprelease />
<changelog>
<release>
<date>2015-08-10</date>
<time>21:13:13</time>
<version>
<release>1.0.0</release>
<api>1.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
initial release
</notes>
</release>
<release>
<date>2015-11-16</date>
<time>09:07:07</time>
<version>
<release>1.0.1</release>
<api>1.0.1</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
add __get() to SQLiteFTS_Document because class.IndexInfo.php access class variable title which doesn't exists
</notes>
</release>
<release>
<date>2016-01-10</date>
<time>09:07:07</time>
<version>
<release>1.0.2</release>
<api>1.0.1</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
check if index exists before removing it when creating a new one
</notes>
</release>
<release>
<date>2016-02-01</date>
<time>09:15:01</time>
<version>
<release>1.0.3</release>
<api>1.0.1</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
add command for indexing postѕcript files
</notes>
</release>
<release>
<date>2016-03-15</date>
<time>15:59:07</time>
<version>
<release>1.0.4</release>
<api>1.0.1</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
make it work with sqlite3 &lt; 3.8.0
</notes>
</release>
<release>
<date>2016-03-29</date>
<time>08:09:48</time>
<version>
<release>1.0.5</release>
<api>1.0.1</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
set last parameter of stream_select() to 200000 micro sec. in case the timeout in sec. is set to 0
</notes>
</release>
<release>
<date>2016-03-29</date>
<time>08:09:48</time>
<version>
<release>1.0.6</release>
<api>1.0.1</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
fix calculation of timeout (see bug #269)
</notes>
</release>
<release>
<date>2017-03-01</date>
<time>15:53:24</time>
<version>
<release>1.0.7</release>
<api>1.0.7</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
catch exception in execWithTimeout()
</notes>
</release>
<release>
<date>2017-12-04</date>
<time>11:00:40</time>
<version>
<release>1.0.8</release>
<api>1.0.8</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
allow conversion commands for mimetypes with wildcards
</notes>
</release>
<release>
<date>2018-01-30</date>
<time>11:00:40</time>
<version>
<release>1.0.9</release>
<api>1.0.9</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
execWithTimeout() reads data from stderr and saves it into error msg
</notes>
</release>
<release>
<date>2018-04-11</date>
<time>11:00:40</time>
<version>
<release>1.0.10</release>
<api>1.0.10</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
IndexedDocument() remembers cmd and mimetype
</notes>
</release>
<release>
<date>2019-11-28</date>
<time>11:00:40</time>
<version>
<release>1.0.11</release>
<api>1.0.11</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
Set 'created' in index to creation date of indexed content (was set to current
timestamp)
</notes>
</release>
<release>
<date>2020-09-02</date>
<time>08:57:44</time>
<version>
<release>1.0.12</release>
<api>1.0.12</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
Index users with at least read access on a document
</notes>
</release>
<release>
<date>2020-09-02</date>
<time>08:57:44</time>
<version>
<release>1.0.13</release>
<api>1.0.13</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
add user to list of terms
</notes>
</release>
<release>
<date>2020-09-11</date>
<time>08:57:44</time>
<version>
<release>1.0.14</release>
<api>1.0.14</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
- add searching for document status
- search even if query is empty (will find all documents)
- parameters for SeedDMS_SQLiteFTS_Search::search() has changed
- SeedDMS_Lucene_Search::search() returns array of hits, count and facets
- pass config array instead of index directory to SeedDMS_Lucene_Indexer::create()
and SeedDMS_Lucene_Indexer::open()
</notes>
</release>
</changelog>
</package>

View File

5
TODO
View File

@ -1,6 +1,3 @@
This list is hopelessly outdated, but some of the issues are
still worth to be implemented!
Update comment and date of a review/approval, if the same status is set
again. Currently setting the same status is turned of, because it didn't
have any effect, which is quite confusing if the user can do an operation
@ -28,6 +25,8 @@ approaches to get the configuration directory.
Show expiration status of documents in document list
Copy folders recursivly
Allow operations like delete, move, approve, etc. on a list of documents
installation script:

216
build.xml
View File

@ -1,216 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="seeddms" basedir="." default="main">
<property name="tmp" value="/tmp" />
<property name="package" value="${phing.project.name}" override="true" />
<property name="seeddmsurl" value="http://localhost/seeddms51x" />
<property name="builddir" value="${tmp}/build/${phing.project.name}" override="true" />
<property name="srcdir" value="${project.basedir}" override="true" />
<property name="datadir" value="" override="true" />
<property name="dbtype" value="sqlite" override="true" />
<property name="dbhost" value="" override="true" />
<property name="dbuser" value="" override="true" />
<property name="dbpass" value="" override="true" />
<property name="dbname" value="" override="true" />
<property name="version" value="-" />
<property name="shortversion" value="${version}" />
<propertyregex property="shortversion" subject="${version} kk" pattern="([56])\.([0-9]).*" replace="seeddms$1$2x" override="true"/>
<property name="majorversion" value="${version}" />
<propertyregex property="majorversion" subject="${version}" pattern="([56])\..*" replace="$1" override="true"/>
<property name="composer_version" value="2.8.5" />
<property name="composer_extra_params" value="" />
<property name="composer_env" value="" />
<property name="mink_driver" value="chrome" />
<property name="snooze_multiplier" value="1" />
<fileset id="distfiles" dir=".">
<include name="languages/**" />
<include name="op/**" />
<include name="out/**" />
<include name="inc/**" />
<include name="controllers/**" />
<include name="styles/**" />
<include name="views/bootstrap*/**" />
<include name="utils/**" />
<include name="doc/**" />
<include name="webdav/**" />
<include name="install/**" />
<include name="restapi/**" />
<include name="pdfviewer/**" />
<include name="index.php" />
<include name="CHANGELOG" />
<include name=".htaccess" />
<include name="LICENSE" />
</fileset>
<target name="main">
<echo>Hello</echo>
</target>
<!-- PHP CodeSniffer -->
<target name="phpcbf">
<exec command="${srcdir}/vendor/bin/phpcbf --standard=${srcdir}/phpcs.xml" escape="false" passthru="true" checkreturn="true" />
</target>
<target name="phpcs">
<exec command="${srcdir}/vendor/bin/phpcs --standard=${srcdir}/phpcs.xml --report=checkstyle &gt; ${builddir}/reports/checkstyle.xml" escape="false" />
</target>
<target name="phpcs-console">
<exec command="${srcdir}/vendor/bin/phpcs --standard=${srcdir}/phpcs.xml" escape="false" passthru="true" checkreturn="true" />
</target>
<target name="php-cs-fixer-dryrun">
<exec command="${srcdir}/vendor/bin/php-cs-fixer fix --dry-run -vvv --diff ${srcdir}/inc" passthru="true" escape="false" checkreturn="true" />
</target>
<!-- PHPUnit -->
<target name="phpunitfast" description="Run tests">
<exec dir="${srcdir}/SeedDMS_Core" command="XDEBUG_MODE=coverage SEEDDMS_CORE_SQL=../install/create_tables-sqlite3.sql ${srcdir}/vendor/bin/phpunit --bootstrap ${srcdir}/SeedDMS_Core/bootstrap-${majorversion}.php --coverage-html ${srcdir}/coverage/" passthru="true" checkreturn="true" />
<!-- exec dir="${srcdir}/tests" command="SEEDDMS_URL=${seeddmsurl} SEEDDMS_MINK_DRIVER=${mink_driver} SEEDDMS_SNOOZE_MULTIPLIER=${snooze_multiplier} ${srcdir}/vendor/bin/phpunit" passthru="true" checkreturn="true" / -->
</target>
<target name="composer" description="Install dependencies with Composer">
<if>
<equals arg1="${composer_version}" arg2="latest-2.x" />
<then>
<httpget url="https://getcomposer.org/composer-2.phar" sslVerifyPeer="false" dir="${srcdir}" filename="composer.phar" />
</then>
<else>
<if>
<not><available file="composer.phar" /></not>
<then>
<httpget url="https://getcomposer.org/download/${composer_version}/composer.phar" sslVerifyPeer="false" dir="${srcdir}" />
</then>
</if>
</else>
</if>
<echo message="Installing dependencies..." />
<exec command="${composer_env} php ${srcdir}/composer.phar install ${composer_extra_params}" passthru="true" checkreturn="true" />
</target>
<target name="dist" description="build SeedDMS tar archive">
<if>
<equals arg1="-" arg2="${version}" />
<then><fail msg="Pass version as property 'version'" /></then>
</if>
<echo msg="This is ${shortversion}" />
<delete file="./seeddms-${version}.tar.gz" failonerror="false" />
<tar destfile="./seeddms-${version}.tar.gz" prefix="seeddms-${version}" compression="gzip">
<fileset refid="distfiles" />
</tar>
</target>
<target name="package" description="build SeedDMS quickstart packages for distribution">
<if>
<equals arg1="-" arg2="${version}" />
<then><fail msg="Pass version as property 'version'" /></then>
</if>
<echo msg="This is ${shortversion}" />
<if>
<matches string="${version}" pattern="^6\.0\..*" />
<then><echo msg="This is version 6" /></then>
<else><echo msg="This is version 5" /></else>
</if>
<!-- make sure the work area is empty, then rebuild it -->
<delete dir="${builddir}/packages" includeemptydirs="true" failonerror="false" />
<mkdir dir="${builddir}/packages" />
<delete dir="${builddir}/export" includeemptydirs="true" failonerror="false" />
<mkdir dir="${builddir}/export/${shortversion}" />
<mkdir dir="${builddir}/export/${shortversion}/conf" />
<mkdir dir="${builddir}/export/${shortversion}/data" />
<mkdir dir="${builddir}/export/${shortversion}/data/1048576" />
<mkdir dir="${builddir}/export/${shortversion}/data/log" />
<mkdir dir="${builddir}/export/${shortversion}/data/cache" />
<exec command="echo 'Signature: 8a477f597d28d172789f06886806bc55' &gt; ${builddir}/export/${shortversion}/data/cache/CACHEDIR.TAG" />
<exec command="echo '# This file is a cache directory tag created by seeddms.' &gt;&gt; ${builddir}/export/${shortversion}/data/cache/CACHEDIR.TAG" />
<exec command="echo '# For information about cache directory tags, see: http://www.brynosaurus.com/cachedir/' &gt;&gt; ${builddir}/export/${shortversion}/data/cache/CACHEDIR.TAG" />
<mkdir dir="${builddir}/export/${shortversion}/data/backup" />
<mkdir dir="${builddir}/export/${shortversion}/data/lucene" />
<mkdir dir="${builddir}/export/${shortversion}/data/staging" />
<mkdir dir="${builddir}/export/${shortversion}/pear" />
<mkdir dir="${builddir}/export/${shortversion}/www" />
<mkdir dir="${builddir}/export/${shortversion}/www/ext" />
<mkdir dir="${builddir}/export/${shortversion}/seeddms-${version}" />
<copy file="${srcdir}/conf/settings.xml.template" tofile="${builddir}/export/${shortversion}/conf/settings.xml">
<filterchain>
<replaceregexp>
<regexp pattern="_DBC_DBTYPE_" replace="${dbtype}"/>
<regexp pattern="_DBC_DBSERVER_" replace="${dbhost}"/>
<regexp pattern="_DBC_DBNAME_" replace="${dbname}"/>
<regexp pattern="_DBC_DBUSER_" replace="${dbuser}"/>
<regexp pattern="_DBC_DBPASS_" replace="${dbpass}"/>
<regexp pattern="_SHORT_VERSION_" replace="${shortversion}"/>
</replaceregexp>
</filterchain>
</copy>
<copy file="${srcdir}/conf/.htaccess" tofile="${builddir}/export/${shortversion}/conf/.htaccess" />
<copy todir="${builddir}/export/${shortversion}/seeddms-${version}">
<fileset refid="distfiles" />
</copy>
<copy todir="${builddir}/export/${shortversion}/pear/vendor">
<fileset dir="${srcdir}/vendor" defaultexcludes="false" />
</copy>
<copy todir="${builddir}/export/${shortversion}/www/ext/example">
<fileset dir="${srcdir}/ext/example" defaultexcludes="false" />
</copy>
<!-- copy todir="${builddir}/export/${shortversion}/pear/SeedDMS">
<fileset dir="SeedDMS_Core">
<include name="Core/**" />
<include name="Core.php" />
</fileset>
<fileset dir="SeedDMS_Preview">
<include name="Preview/**" />
<include name="Preview.php" />
</fileset>
<fileset dir="SeedDMS_Lucene">
<include name="Lucene/**" />
<include name="Lucene.php" />
</fileset -->
<!-- fileset dir="SeedDMS_SQLiteFTS">
<include name="SQLiteFTS/**" />
<include name="SQLiteFTS.php" />
</fileset>
</copy -->
<!-- copy todir="${builddir}/export/${shortversion}/pear">
<fileset dir="../seeddms-ext/http_webdav_server">
<include name="HTTP/WebDAV/Server/**" />
<include name="HTTP/WebDAV/Server.php" />
</fileset>
</copy>
<copy todir="${builddir}/export/${shortversion}/pear/HTTP/WebDAV">
<fileset dir="../seeddms-ext/http_webdav_server">
<include name="Tools/**" />
</fileset>
</copy -->
<copy tofile="${builddir}/export/${shortversion}/pear/composer.json" file="composer-dist.json">
</copy>
<phingcall target="composer">
<property name="composer_extra_params" value="--working-dir=${builddir}/export/${shortversion}/pear/" />
<property name="composer_envv" value="COMPOSER=${srcdir}/composer-dist.json" />
</phingcall>
<exec command="cd ${builddir}/export/${shortversion} &amp;&amp; ln -s seeddms-${version} seeddms" />
<exec command="cd ${builddir}/export/${shortversion}/www &amp;&amp; ln -s ../seeddms/op" />
<exec command="cd ${builddir}/export/${shortversion}/www &amp;&amp; ln -s ../seeddms/out" />
<exec command="cd ${builddir}/export/${shortversion}/www &amp;&amp; ln -s ../seeddms/inc" />
<exec command="cd ${builddir}/export/${shortversion}/www &amp;&amp; ln -s ../seeddms/controllers" />
<exec command="cd ${builddir}/export/${shortversion}/www &amp;&amp; ln -s ../seeddms/languages" />
<exec command="cd ${builddir}/export/${shortversion}/www &amp;&amp; ln -s ../seeddms/views" />
<exec command="cd ${builddir}/export/${shortversion}/www &amp;&amp; ln -s ../seeddms/restapi" />
<exec command="cd ${builddir}/export/${shortversion}/www &amp;&amp; ln -s ../seeddms/styles" />
<exec command="cd ${builddir}/export/${shortversion}/www &amp;&amp; ln -s ../seeddms/pdfviewer" />
<exec command="cd ${builddir}/export/${shortversion}/www &amp;&amp; ln -s ../seeddms/install" />
<exec command="cd ${builddir}/export/${shortversion}/www &amp;&amp; ln -s ../seeddms/webdav" />
<exec command="cd ${builddir}/export/${shortversion}/www &amp;&amp; ln -s ../seeddms/index.php" />
<exec command="cd ${builddir}/export/${shortversion}/www &amp;&amp; ln -s ../seeddms/.htaccess" />
<exec command="cat ${srcdir}/install/create_tables-sqlite3.sql | sqlite3 ${builddir}/export/${shortversion}/data/content.db" />
<!-- build the standard tar.gz archive -->
<echo message="Building .tar.gz...." />
<exec command="cd ${builddir}/export ; tar czf ${builddir}/packages/seeddms-quickstart-${version}.tar.gz ${shortversion}" checkreturn="true" />
<echo message="Built in ${builddir}/packages/seeddms-quickstart-${version}.tar.gz" />
</target>
</project>

View File

@ -1,76 +0,0 @@
{
"config": {
"platform": {
"php": "8.2"
}
},
"require": {
"robthree/twofactorauth": "^1.5",
"slim/slim": "^4.0",
"guzzlehttp/psr7": "*",
"erusev/parsedown": "*",
"erusev/parsedown-extra": "*",
"mibe/feedwriter": "^1.1",
"phpoffice/phpspreadsheet": "*",
"sabre/xml": "*",
"sabre/dav": "^4.",
"pear/log": "*",
"pear/mail": "*",
"pear/mail_mime": "*",
"pear/net_smtp": "*",
"pear/auth_sasl": "*",
"pear/db": "*",
"dragonmantank/cron-expression": "^3.1",
"alecrabbit/php-console-colour": "*",
"dragonmantank/cron-expression": "^3",
"zf1/zend-search-lucene": "*",
"symfony/http-foundation": "^5.4",
"php-di/php-di": "^6.4",
"slim/psr7": "^1.7",
"seeddms/core": "dev-master",
"seeddms/lucene": "dev-master",
"seeddms/preview": "dev-master",
"seeddms/sqlitefts": "dev-master",
"seeddms/http_webdav_server": "dev-master"
},
"require-dev": {
"composer/composer": "dev-main"
},
"repositories": [
{
"type": "path",
"url": "/home/cvs/seeddms-ext/core",
"options": {
"symlink": false
}
},
{
"type": "path",
"url": "/home/cvs/seeddms-ext/lucene",
"options": {
"symlink": false
}
},
{
"type": "path",
"url": "/home/cvs/seeddms-ext/preview",
"options": {
"symlink": false
}
},
{
"type": "path",
"url": "/home/cvs/seeddms-ext/sqlitefts",
"options": {
"symlink": false
}
},
{
"type": "path",
"url": "/home/cvs/seeddms-ext/http_webdav_server",
"options": {
"symlink": false
}
}
]
}

View File

@ -15,15 +15,14 @@
footNote = "SeedDMS free document management system - www.seeddms.org"
printDisclaimer = "true"
language = "en_GB"
theme = "bootstrap4"
theme = "bootstrap"
previewWidthList = "40"
previewWidthDetail = "100"
onePageMode="true"
/>
<!--
- strictFormCheck: Strict form checking. If set to true, then all fields in the form will be checked for a value. If set to false, then (most) comments and keyword fields become optional. Comments are always required when submitting a review or overriding document status.
- viewOnlineFileTypes: files with one of the following endings can be viewed online (USE ONLY LOWER CASE CHARACTERS)
- enableConverting: enable/disable converting of files (deprecated)
- enableConverting: enable/disable converting of files XXX
- enableEmail: enable/disable automatic email notification
- enableUsersView: enable/disable group and user view for all users
- enableFullSearch: false to don't use fulltext search
@ -35,14 +34,12 @@
- 2 to start with tree shown fully expanded
- stopWordsFile: path to stop word file for indexer
- sortUsersInList: how to sort users in lists ('fullname' or '' (default))
- enableDropUpload: enable/disable uploading files by drag&drop
- enableRecursiveCount: enable/disable counting docs and folder recursively
- maxRecursiveCount: after this number of docs/folders precise counting will stop
- enableThemeSelector: enable/disable the theme selector on the login page
- enableDropUpload: XXX
- enableRecursiveCount: XXX
- maxRecursiveCount: XXX
- enableThemeSelector: XXX
- fullSearchEngine: Either "lucene" or "sqlitefts"
- sortFoldersDefault: how to sort forders by default. u=unsorted, s=sequence, n=name
- defaultDocPosition: Default position for a new document. 'start', 'end', or ''
- defaultFolderPosition: Default position for a new folder. 'start', 'end', or ''
- sortFoldersDefault: XXX
-->
<edition
strictFormCheck = "false"
@ -57,14 +54,12 @@
enableLanguageSelector = "true"
stopWordsFile = ""
sortUsersInList = ""
enableDropUpload = "true"
enableDropUpload = "false"
enableRecursiveCount = "false"
maxRecursiveCount = "0"
enableThemeSelector = "true"
fullSearchEngine = "sqlitefts"
enableThemeSelector = "false"
fullSearchEngine = "lucene"
sortFoldersDefault = "u"
defaultDocPosition = "end"
defaultFolderPosition = "end"
/>
<!--
- enableCalendar: enable/disable calendar
@ -101,18 +96,17 @@
-->
<server
rootDir = ""
httpRoot = "/_SHORT_VERSION_/"
httpRoot = "/seeddms/"
contentDir = ""
stagingDir = ""
luceneDir = ""
logFileEnable = "true"
logFileRotation = "d"
enableLargeFileUpload = "false"
enableLargeFileUpload = "true"
partitionSize = "2000000"
dropFolderDir = ""
cacheDir = ""
backupDir = ""
logFileMaxLevel="6"
/>
<!--
- enableGuestLogin: If you want anybody to login as guest, set the following line to true
@ -121,17 +115,16 @@
- restricted: Restricted access: only allow users to log in if they have an entry in the local database (irrespective of successful authentication with LDAP).
- enableUserImage: enable users images
- disableSelfEdit: if true user cannot edit his own profile
- disableChangePassword: if true user cannot change the password
- passwordStrength: minimum strength of password, set to 0 to disable
- passwordStrengthAlgorithm: algorithm used to calculate password strenght (simple or advanced)
- passwordExpiration: number of days after password expires
- passwordHistory: number of remembered passwords
- loginFailure: maximum allowed login failures before an account is disabled
- autoLoginUser: id of user used if auto login is turned on
- quota: maximum allowed space on disc for each user
- undelUserIds: ids of users which cannot be deleted
- encryptionKey: arbitrary string used for creating form tokens
- cookieLifetime: lifetime of cookie in seconds, set to 0 for session cookies
- passwordStrength: XXX
- passwordStrengthAlgorithm: XXX
- passwordExpiration: XXX
- passwordHistory: XXX
- loginFailure: XXX
- autoLoginUser: XXX
- quota: XXX
- undelUserIds: XXX
- encryptionKey: XXX
- cookieLifetime: XXX
-->
<authentication
enableGuestLogin = "false"
@ -139,7 +132,6 @@
restricted = "true"
enableUserImage = "false"
disableSelfEdit = "false"
disableChangePassword = "false"
passwordStrength = "0"
passwordStrengthAlgorithm = "simple"
passwordExpiration = "0"
@ -171,7 +163,6 @@
bindDN = ""
bindPw = ""
filter = ""
groupField = ""
/>
<!-- ***** CONNECTOR Microsoft Active Directory *****
- enable: enable/disable connector
@ -193,12 +184,11 @@
accountDomainName = "example.com"
bindDN = ""
bindPw = ""
filter = ""
groupField = ""
/>
</connectors>
</authentication>
<!--
- ADOdbPath: Path to adodb. This is the directory containing the adodb directory
- dbDriver: DB-Driver used by adodb (see adodb-readme)
- dbHostname: DB-Server
- dbDatabase: database where the tables for seeddms are stored (optional - see adodb-readme)
@ -207,6 +197,7 @@
- doNotCheckVersion: Whether or not to check the database schema for its correct version.
-->
<database
ADOdbPath = ""
dbDriver = "_DBC_DBTYPE_"
dbHostname = "_DBC_DBSERVER_"
dbDatabase = "_DBC_DBNAME_"
@ -218,8 +209,8 @@
- smtpServer: SMTP Server hostname
- smtpPort: SMTP Server port
- smtpSendFrom: Send from
- smtpUser: user name used for authenticating against smtp server
- smtpPassword: password used for authenticating against smtp server
- smtpUser: XXX
- smtpPassword: XXX
-->
<smtp
smtpServer = "localhost"
@ -233,11 +224,13 @@
<!--
-siteDefaultPage: Default page on login. Defaults to out/out.ViewFolder.php
- rootFolderID: ID of root-folder (mostly no need to change)
- showMissingTranslations: set true if missing translation shall be listed at end of page
- titleDisplayHack: Workaround for page titles that go over more than 2 lines.
- showMissingTranslations: XXX
-->
<display
siteDefaultPage = ""
rootFolderID = "1"
titleDisplayHack = "true"
showMissingTranslations = "false"
/>
<!--
@ -256,15 +249,15 @@
- enableVersionModification: allow to modify versions after approval
- enableDuplicateDocNames: allow duplicate names in a folder
- enableDuplicateSubFolderNames: allow duplicate names in a folder
- enableOwnerRevApp: allow owner of a document to review and approve
- enableSelfRevApp: allow the user current logged in to add herself as a reviewer or approver
- presetExpirationDate: set to time period if each document shall expire
- overrideMimeType: set to true if the mimetype of a document version is determined by the server
- enableOwnerRevApp: XXX
- enableSelfRevApp: XXX
- presetExpirationDate: XXX
- overrideMimeType: XXX
-->
<edition
enableAdminRevApp = "false"
versioningFileName = "versioning_info.txt"
workflowMode = "traditional"
workflowMode = "advanced"
enableVersionDeletion = "true"
enableVersionModification = "true"
enableDuplicateDocNames = "true"
@ -284,9 +277,9 @@
- be any number or string that does not already exist within $_contentDir.
- maxDirID: Maximum number of sub-directories per parent directory. Default: 0.
- updateNotifyTime: users are notified about document-changes that took place within the last "updateNotifyTime" seconds
- extraPath: additional path which is added to php's include path
- maxExecutionTime: maximum script execution time, this cannot be larger than the value set in php.ini
- cmdTimeout: timeout in sec. for external commands
- extraPath: XXX
- maxExecutionTime: XXX
- cmdTimeout: XXX
-->
<server
coreDir = ""
@ -299,9 +292,9 @@
cmdTimeout = "10"
/>
<!--
- enableNotificationAppRev: set to true if reviewers and approvers shall be informed about a pending review/approval
- enableNotificationAppRev: XXX
- enableOwnerNotification: XXX
- enableNotificationWorkflow: set to true if the users in the workflow shall be informed
- enableNotificationWorkflow: XXX
-->
<notification
enableNotificationAppRev = "true"
@ -309,20 +302,22 @@
enableNotificationWorkflow = "false"
/>
<converters target="fulltext">
<converter mimeType="application/pdf">pdftotext -nopgbrk %s -</converter>
<converter mimeType="application/pdf">pdftotext -nopgbrk %s - | sed -e 's/ [a-zA-Z0-9.]\{1\} / /g' -e 's/[0-9.]//g'</converter>
<converter mimeType="application/msword">catdoc %s</converter>
<converter mimeType="application/vnd.ms-excel">ssconvert -T Gnumeric_stf:stf_csv -S %s fd://1</converter>
<converter mimeType="audio/mp3">id3 -l -R %s | egrep '(Title|Artist|Album)' | sed 's/^[^:]*: //g'</converter>
<converter mimeType="audio/mpeg">id3 -l -R %s | egrep '(Title|Artist|Album)' | sed 's/^[^:]*: //g'</converter>
<converter mimeType="text/plain">cat %s</converter>
<converter mimeType="text/html">html2text %s</converter>
<converter mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document">docx2txt %s -</converter>
</converters>
<converters target="preview">
<converter mimeType="application/msword">unoconv -d document -e PageRange=1 -f pdf --stdout -v '%f'|gs -dBATCH -dNOPAUSE -sDEVICE=pngalpha -dPDFFitPage -r72x72 -sOutputFile=- -dFirstPage=1 -dLastPage=1 -q - | convert -resize %wx png:- '%o'</converter>
<converter mimeType="image/png">convert -resize %wx '%f' '%o'</converter>
<converter mimeType="image/jpg">convert -resize %wx '%f' '%o'</converter>
<converter mimeType="image/gif">convert -resize %wx '%f' '%o'</converter>
<converter mimeType="text/plain">a2ps -1 -a1 -R -B -o - '%f' | gs -dBATCH -dNOPAUSE -sDEVICE=pngalpha -dFirstPage=1 -dLastPage=1 -dPDFFitPage -r72x72 -sOutputFile=- -q - | convert -resize %wx png:- '%o'</converter>
</converters>
</advanced>
<extensions>
<extension name="example" disable="true">
<parameter name="__disable__">1</parameter>
</extension>
</extensions>
<extensions/>
</configuration>

View File

@ -56,43 +56,16 @@ class SeedDMS_Controller_AddDocument extends SeedDMS_Controller_Common {
$reqversion = $this->getParam('reqversion');
$version_comment = $this->getParam('versioncomment');
$attributes = $this->getParam('attributes');
foreach($attributes as $attrdefid=>&$attribute) {
foreach($attributes as $attrdefid=>$attribute) {
if($attrdef = $dms->getAttributeDefinition($attrdefid)) {
if(null === ($ret = $this->callHook('validateAttribute', $attrdef, $attribute))) {
if($attribute) {
switch($attrdef->getType()) {
case SeedDMS_Core_AttributeDefinition::type_date:
if(is_array($attribute))
$attribute = array_map(fn($value): string => date('Y-m-d', makeTsFromDate($value)), $attribute);
else
$attribute = date('Y-m-d', makeTsFromDate($attribute));
break;
case SeedDMS_Core_AttributeDefinition::type_folder:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getFolder((int) $value), $attribute);
else
$attribute = $dms->getFolder((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_document:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getDocument((int) $value), $attribute);
else
$attribute = $dms->getDocument((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_user:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getUser((int) $value), $attribute);
else
$attribute = $dms->getUser((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_group:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getGroup((int) $value), $attribute);
else
$attribute = $dms->getGroup((int) $attribute);
break;
}
if(!$attrdef->validate($attribute, null, true)) {
if(!$attrdef->validate($attribute)) {
$this->errormsg = getAttributeValidationError($attrdef->getValidationError(), $attrdef->getName(), $attribute);
return false;
}
@ -107,49 +80,19 @@ class SeedDMS_Controller_AddDocument extends SeedDMS_Controller_Common {
}
}
if($attributes_version = $this->getParam('attributesversion')) {
foreach($attributes_version as $attrdefid=>&$attribute) {
foreach($attributes_version as $attrdefid=>$attribute) {
if($attrdef = $dms->getAttributeDefinition($attrdefid)) {
if(null === ($ret = $this->callHook('validateAttribute', $attrdef, $attribute))) {
if($attribute) {
switch($attrdef->getType()) {
case SeedDMS_Core_AttributeDefinition::type_date:
if(is_array($attribute))
$attribute = array_map(fn($value): string => date('Y-m-d', makeTsFromDate($value)), $attribute);
else
$attribute = date('Y-m-d', makeTsFromDate($attribute));
break;
case SeedDMS_Core_AttributeDefinition::type_folder:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getFolder((int) $value), $attribute);
else
$attribute = $dms->getFolder((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_document:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getDocument((int) $value), $attribute);
else
$attribute = $dms->getDocument((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_user:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getUser((int) $value), $attribute);
else
$attribute = $dms->getUser((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_group:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getGroup((int) $value), $attribute);
else
$attribute = $dms->getGroup((int) $attribute);
break;
}
if(!$attrdef->validate($attribute, null, true)) {
if(!$attrdef->validate($attribute)) {
$this->errormsg = getAttributeValidationError($attrdef->getValidationError(), $attrdef->getName(), $attribute);
return false;
}
} elseif($attrdef->getMinValues() > 0) {
$this->errormsg = array("attr_min_values", array("attrname"=>$attrdef->getName()));
return false;
}
} else {
if($ret === false)

View File

@ -41,43 +41,11 @@ class SeedDMS_Controller_AddSubFolder extends SeedDMS_Controller_Common {
$comment = $this->getParam('comment');
$sequence = $this->getParam('sequence');
$attributes = $this->getParam('attributes');
foreach($attributes as $attrdefid=>&$attribute) {
foreach($attributes as $attrdefid=>$attribute) {
if($attrdef = $dms->getAttributeDefinition($attrdefid)) {
if(null === ($ret = $this->callHook('validateAttribute', $attrdef, $attribute))) {
if($attribute) {
switch($attrdef->getType()) {
case SeedDMS_Core_AttributeDefinition::type_date:
if(is_array($attribute))
$attribute = array_map(fn($value): string => date('Y-m-d', makeTsFromDate($value)), $attribute);
else
$attribute = date('Y-m-d', makeTsFromDate($attribute));
break;
case SeedDMS_Core_AttributeDefinition::type_folder:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getFolder((int) $value), $attribute);
else
$attribute = $dms->getFolder((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_document:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getDocument((int) $value), $attribute);
else
$attribute = $dms->getDocument((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_user:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getUser((int) $value), $attribute);
else
$attribute = $dms->getUser((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_group:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getGroup((int) $value), $attribute);
else
$attribute = $dms->getGroup((int) $attribute);
break;
}
if(!$attrdef->validate($attribute, null, true)) {
if(!$attrdef->validate($attribute)) {
$this->errormsg = getAttributeValidationError($attrdef->getValidationError(), $attrdef->getName(), $attribute);
return false;
}

View File

@ -7,38 +7,36 @@
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010-2023 Uwe Steinmann
* @copyright Copyright (C) 2010-2013 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class which does the busines logic for approving a document
* Class which does the busines logic for downloading a document
*
* @category DMS
* @package SeedDMS
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010-2023 Uwe Steinmann
* @copyright Copyright (C) 2010-2013 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Controller_ApproveDocument extends SeedDMS_Controller_Common {
public $oldstatus;
public $newstatus;
public function run() { /* {{{ */
public function run() {
$dms = $this->params['dms'];
$user = $this->params['user'];
$settings = $this->params['settings'];
$document = $this->params['document'];
$content = $this->params['content'];
$approvaltype = $this->params['type'];
$approvalstatus = $this->params['status'];
$approvalcomment = $this->params['comment'];
$approvalfile = $this->params['file'];
$approvalgroup = $this->params['group'];
$overallStatus = $content->getStatus();
$this->oldstatus = $overallStatus['status'];
$this->newstatus = $this->oldstatus;
$approvalstatus = $this->params['approvalstatus'];
$approvaltype = $this->params['approvaltype'];
$group = $this->params['group'];
$comment = $this->params['comment'];
$file = $this->params['file'];
/* Get the document id and name before removing the document */
$docname = $document->getName();
$documentid = $document->getID();
if(!$this->callHook('preApproveDocument', $content)) {
}
@ -46,35 +44,34 @@ class SeedDMS_Controller_ApproveDocument extends SeedDMS_Controller_Common {
$result = $this->callHook('approveDocument', $content);
if($result === null) {
if ($approvaltype == "ind") {
$approvalLogID = $content->setApprovalByInd($user, $user, $approvalstatus, $approvalcomment, $approvalfile);
} elseif ($approvaltype == "grp") {
$approvalLogID = $content->setApprovalByGrp($approvalgroup, $user, $approvalstatus, $approvalcomment, $approvalfile);
} else {
$this->errormsg = "approval_wrong_type";
if(0 > $content->setApprovalByInd($user, $user, $approvalstatus, $comment, $file)) {
$this->error = 1;
$this->errormsg = "approval_update_failed";
return false;
}
if($approvalLogID === false || 0 > $approvalLogID) {
} elseif ($approvaltype == "grp") {
if(0 > $content->setApprovalByGrp($group, $user, $approvalstatus, $comment, $file)) {
$this->error = 1;
$this->errormsg = "approval_update_failed";
return false;
}
}
}
/* Check to see if the overall status for the document version needs to be
* updated.
*/
$result = $this->callHook('approveUpdateDocumentStatus', $content);
if($result === null) {
/* If document was rejected, set the document status to S_REJECTED right away */
if ($approvalstatus == -1){
$this->newstatus = S_REJECTED;
if($content->setStatus(S_REJECTED, $approvalcomment, $user)) {
if(isset($GLOBALS['SEEDDMS_HOOKS']['approveDocument'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['approveDocument'] as $hookObj) {
if (method_exists($hookObj, 'postApproveDocument')) {
$hookObj->postApproveDocument(null, $content, S_REJECTED);
}
}
}
if($content->setStatus(S_REJECTED,$comment,$user)) {
$this->callHook('postApproveDocument', $content, S_REJECTED);
}
} else {
$docApprovalStatus = $content->getApprovalStatus();
if (is_bool($docApprovalStatus) && !$docApprovalStatus) {
$this->error = 1;
$this->errormsg = "cannot_retrieve_approval_snapshot";
return false;
}
@ -92,15 +89,8 @@ class SeedDMS_Controller_ApproveDocument extends SeedDMS_Controller_Common {
// count of the approvals required for this document.
if ($approvalCT == $approvalTotal) {
// Change the status to released.
$this->newstatus=S_RELEASED;
if($content->setStatus($this->newstatus, getMLText("automatic_status_update"), $user)) {
if(isset($GLOBALS['SEEDDMS_HOOKS']['approveDocument'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['approveDocument'] as $hookObj) {
if (method_exists($hookObj, 'postApproveDocument')) {
$hookObj->postApproveDocument(null, $content, S_RELEASED);
}
}
}
if($content->setStatus(S_RELEASED, getMLText("automatic_status_update"), $user)) {
$this->callHook('postApproveDocument', $content, S_RELEASED);
}
}
}
@ -110,6 +100,6 @@ class SeedDMS_Controller_ApproveDocument extends SeedDMS_Controller_Common {
}
return true;
} /* }}} */
}
}

View File

@ -78,7 +78,6 @@ class SeedDMS_Controller_AttributeMgr extends SeedDMS_Controller_Common {
return false;
}
if (!$attrdef->setRegex($regex)) {
$this->errormsg = 'attrdef_invalid_regex';
return false;
}

View File

@ -1,114 +0,0 @@
<?php
/**
* Implementation of CheckInDocument controller
*
* @category DMS
* @package SeedDMS
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010-2024 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class which does the busines logic for downloading a document
*
* @category DMS
* @package SeedDMS
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010-2024 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Controller_CheckInDocument extends SeedDMS_Controller_Common {
public function run() { /* {{{ */
$name = $this->getParam('name');
$comment = $this->getParam('comment');
/* Call preCheckInDocument early, because it might need to modify some
* of the parameters.
*/
if(false === $this->callHook('preCheckInDocument', $this->params['document'])) {
if(empty($this->errormsg))
$this->errormsg = 'hook_preCheckInDocument_failed';
return null;
}
$comment = $this->getParam('comment');
$dms = $this->params['dms'];
$user = $this->params['user'];
$document = $this->params['document'];
$settings = $this->params['settings'];
$fulltextservice = $this->params['fulltextservice'];
$folder = $this->params['folder'];
$userfiletmp = $this->getParam('userfiletmp');
$userfilename = $this->getParam('userfilename');
$filetype = $this->getParam('filetype');
$userfiletype = $this->getParam('userfiletype');
$reviewers = $this->getParam('reviewers');
$approvers = $this->getParam('approvers');
$recipients = $this->getParam('recipients');
$reqversion = $this->getParam('reqversion');
$comment = $this->getParam('comment');
$attributes = $this->getParam('attributes');
$workflow = $this->getParam('workflow');
$maxsizeforfulltext = $this->getParam('maxsizeforfulltext');
$initialdocumentstatus = $this->getParam('initialdocumentstatus');
$content = $this->callHook('checkinDocument');
if($content === null) {
if($contentResult=$document->checkIn($comment, $user, $reviewers, $approvers, $version=0, $attributes, $workflow, $initialdocumentstatus)) {
if ($this->hasParam('expires')) {
if($document->setExpires($this->getParam('expires'))) {
} else {
}
}
if(!empty($recipients['i'])) {
foreach($recipients['i'] as $uid) {
if($u = $dms->getUser($uid)) {
$res = $contentResult->getContent()->addIndRecipient($u, $user);
}
}
}
if(!empty($recipients['g'])) {
foreach($recipients['g'] as $gid) {
if($g = $dms->getGroup($gid)) {
$res = $contentResult->getContent()->addGrpRecipient($g, $user);
}
}
}
$content = $contentResult->getContent();
} else {
$this->errormsg = 'error_checkin_document';
$result = false;
}
} elseif($result === false) {
if(empty($this->errormsg))
$this->errormsg = 'hook_checkinDocument_failed';
return false;
}
if($fulltextservice && ($index = $fulltextservice->Indexer()) && $content) {
$idoc = $fulltextservice->IndexedDocument($document);
if(false !== $this->callHook('preIndexDocument', $document, $idoc)) {
$lucenesearch = $fulltextservice->Search();
if($hit = $lucenesearch->getDocument((int) $document->getId())) {
$index->delete($hit->id);
}
$index->addDocument($idoc);
$index->commit();
}
}
if(false === $this->callHook('postCheckInDocument', $document, $content)) {
}
return $content;
} /* }}} */
}

View File

@ -29,24 +29,14 @@ class SeedDMS_Controller_ClearCache extends SeedDMS_Controller_Common {
$post = $this->params['post'];
$ret = '';
if(!empty($post['previewpng'])) {
$cmd = 'rm -rf '.addDirSep($settings->_cacheDir).'png'.DIRECTORY_SEPARATOR.'[1-9]*';
system($cmd, $ret);
}
if(!empty($post['previewpdf'])) {
$cmd = 'rm -rf '.addDirSep($settings->_cacheDir).'pdf'.DIRECTORY_SEPARATOR.'[1-9]*';
system($cmd, $ret);
}
if(!empty($post['previewtxt'])) {
$cmd = 'rm -rf '.addDirSep($settings->_cacheDir).'txt'.DIRECTORY_SEPARATOR.'[1-9]*';
if(!empty($post['preview'])) {
$cmd = 'rm -rf '.$settings->_cacheDir.'/[1-9]*';
system($cmd, $ret);
}
if(!empty($post['js'])) {
/* system('rm ...') does not work anymore if the number of files is too large */
array_map('unlink', array_filter((array) glob(addDirSep($settings->_cacheDir).'js'.DIRECTORY_SEPARATOR.'*')));
$cmd = 'rm -rf '.$settings->_cacheDir.'/js/*';
system($cmd, $ret);
}
if(false === $this->callHook('clear', $post)) {

View File

@ -24,83 +24,37 @@ class SeedDMS_Controller_Cron extends SeedDMS_Controller_Common {
public function run() { /* {{{ */
$dms = $this->params['dms'];
$user = $this->params['user'];
$settings = $this->params['settings'];
$logger = $this->params['logger'];
$mode = $this->params['mode'];
$seltask = $this->params['task'];
$mode = 'run'; //$this->params['mode'];
$db = $dms->getDb();
$scheduler = new SeedDMS_Scheduler($db);
$tasks = $scheduler->getTasks();
$jsonarr = [];
foreach($tasks as $task) {
if($seltask && $seltask != $task->getExtension()."::".$task->getTask())
continue;
if(isset($GLOBALS['SEEDDMS_SCHEDULER']['tasks'][$task->getExtension()]) && is_object($taskobj = resolveTask($GLOBALS['SEEDDMS_SCHEDULER']['tasks'][$task->getExtension()][$task->getTask()]))) {
$arr = array(
'extension'=>$task->getExtension(),
'name'=>$task->getTask(),
'mode'=>$mode,
'disabled' => (bool) $task->getDisabled(),
'isdue' => $task->isDue(),
);
switch($mode) {
case "run":
case "dryrun":
if(method_exists($taskobj, 'execute')) {
if(!$task->getDisabled() && $task->isDue()) {
if($mode == 'run') {
/* Schedule the next run right away to prevent a second execution
* of the task when the cron job of the scheduler is called before
* the last run was finished. The task itself can still be scheduled
* to fast, but this is up to the admin of seeddms.
*/
$task->updateLastNextRun();
if($user = $dms->getUserByLogin('cli_scheduler')) {
if($taskobj->execute($task)) {
add_log_line("Execution of task ".$task->getExtension()."::".$task->getTask()." successful.");
$arr['success'] = true;
$task->updateLastNextRun();
} else {
add_log_line("Execution of task ".$task->getExtension()."::".$task->getTask()." failed, task has been disabled.", PEAR_LOG_ERR);
$arr['success'] = false;
$task->setDisabled(1);
}
} elseif($mode == 'dryrun') {
$arr['success'] = true;
} else {
add_log_line("Execution of task ".$task->getExtension()."::".$task->getTask()." failed because of missing user 'cli_scheduler'. Task has been disabled.", PEAR_LOG_ERR);
$task->setDisabled(1);
}
}
}
break;
case "check":
$arr['error'] = false;
if(!method_exists($taskobj, 'execute')) {
$arr['error'] = true;
$arr['messages'][] = 'Missing method execute()';
}
if(get_parent_class($taskobj) != 'SeedDMS_SchedulerTaskBase') {
$arr['error'] = true;
$arr['error'][] = "Wrong parent class";
}
break;
case "list":
default:
header("Content-Type: application/json");
$arr['nextrun']=$task->getNextRun();
$arr['frequency']=$task->getFrequency();
$arr['params']=array();
if($params = $task->getParameter()) {
foreach($params as $key=>$value) {
$p = $taskobj->getAdditionalParamByName($key);
$arr['params'][$key] = ($p['type'] == 'password') ? '*******' : $value;
}
}
break;
}
$jsonarr[] = $arr;
}
}
echo json_encode($jsonarr);
return true;
} /* }}} */

View File

@ -30,17 +30,8 @@ class SeedDMS_Controller_DocumentAccess extends SeedDMS_Controller_Common {
$settings = $this->params['settings'];
$action = $this->params['action'];
return null;
}
// Change owner -----------------------------------------------------------
public function setowner() {
$dms = $this->params['dms'];
$user = $this->params['user'];
$folder = $this->params['folder'];
$document = $this->params['document'];
$settings = $this->params['settings'];
if ($action == "setowner") {
if(false === $this->callHook('preSetOwner', $document)) {
if(empty($this->errormsg))
$this->errormsg = 'hook_preSetOwner_failed';
@ -55,16 +46,7 @@ class SeedDMS_Controller_DocumentAccess extends SeedDMS_Controller_Common {
return null;
}
}
return true;
}
public function notinherit() {
$dms = $this->params['dms'];
$user = $this->params['user'];
$folder = $this->params['folder'];
$document = $this->params['document'];
$settings = $this->params['settings'];
} elseif ($action == "notinherit") {
if(false === $this->callHook('preSetNotInherit', $document)) {
if(empty($this->errormsg))
$this->errormsg = 'hook_preSetNotInherit_failed';
@ -98,16 +80,7 @@ class SeedDMS_Controller_DocumentAccess extends SeedDMS_Controller_Common {
$this->errormsg = 'hook_postSetNotInherit_failed';
return null;
}
return true;
}
public function inherit() {
$dms = $this->params['dms'];
$user = $this->params['user'];
$folder = $this->params['folder'];
$document = $this->params['document'];
$settings = $this->params['settings'];
} elseif ($action == "inherit") {
if(false === $this->callHook('preSetInherit', $document)) {
if(empty($this->errormsg))
$this->errormsg = 'hook_preSetInherit_failed';
@ -122,16 +95,7 @@ class SeedDMS_Controller_DocumentAccess extends SeedDMS_Controller_Common {
$this->errormsg = 'hook_postSetInherit_failed';
return null;
}
return true;
}
public function setdefault() {
$dms = $this->params['dms'];
$user = $this->params['user'];
$folder = $this->params['folder'];
$document = $this->params['document'];
$settings = $this->params['settings'];
} elseif ($action == "setdefault") {
if(false === $this->callHook('preSetDefault', $document)) {
if(empty($this->errormsg))
$this->errormsg = 'hook_preSetDefault_failed';
@ -148,16 +112,7 @@ class SeedDMS_Controller_DocumentAccess extends SeedDMS_Controller_Common {
$this->errormsg = 'hook_postSetDefault_failed';
return null;
}
return true;
}
public function editaccess() {
$dms = $this->params['dms'];
$user = $this->params['user'];
$folder = $this->params['folder'];
$document = $this->params['document'];
$settings = $this->params['settings'];
} elseif ($action == "editaccess") {
$mode = $this->params['mode'];
$userid = $this->params['userid'];
$groupid = $this->params['groupid'];
@ -167,16 +122,7 @@ class SeedDMS_Controller_DocumentAccess extends SeedDMS_Controller_Common {
elseif ($groupid) {
$document->changeAccess($mode, $groupid, false);
}
return true;
}
public function delaccess() {
$dms = $this->params['dms'];
$user = $this->params['user'];
$folder = $this->params['folder'];
$document = $this->params['document'];
$settings = $this->params['settings'];
} elseif ($action == "delaccess") {
$userid = $this->params['userid'];
$groupid = $this->params['groupid'];
if ($userid) {
@ -185,16 +131,7 @@ class SeedDMS_Controller_DocumentAccess extends SeedDMS_Controller_Common {
elseif ($groupid) {
$document->removeAccess($groupid, false);
}
return true;
}
public function addaccess() {
$dms = $this->params['dms'];
$user = $this->params['user'];
$folder = $this->params['folder'];
$document = $this->params['document'];
$settings = $this->params['settings'];
} elseif ($action == "addaccess") {
$mode = $this->params['mode'];
$userid = $this->params['userid'];
$groupid = $this->params['groupid'];
@ -204,6 +141,8 @@ class SeedDMS_Controller_DocumentAccess extends SeedDMS_Controller_Common {
elseif ($groupid && $groupid != -1) {
$document->addAccess($mode, $groupid, false);
}
}
return true;
}
}

View File

@ -50,7 +50,6 @@ class SeedDMS_Controller_Download extends SeedDMS_Controller_Common {
header("Content-Disposition: attachment; filename=\"" . $efilename . "\"; filename*=UTF-8''".$efilename);
header("Content-Type: " . $content->getMimeType());
header("Cache-Control: must-revalidate");
header("ETag: ".$content->getChecksum());
sendFile($dms->contentDir . $content->getPath());
}

View File

@ -52,7 +52,7 @@ class SeedDMS_Controller_EditDocument extends SeedDMS_Controller_Common {
$expires = $this->params['expires'];
$oldexpires = $document->getExpires();
if ($expires != $oldexpires) {
if(false === $this->callHook('preSetExpires', $document, $expires)) {
if(!$this->callHook('preSetExpires', $document, $expires)) {
}
if(!$document->setExpires($expires)) {
@ -61,21 +61,21 @@ class SeedDMS_Controller_EditDocument extends SeedDMS_Controller_Common {
$document->verifyLastestContentExpriry();
if(false === $this->callHook('postSetExpires', $document, $expires)) {
if(!$this->callHook('postSetExpires', $document, $expires)) {
}
}
$keywords = $this->params['keywords'];
$oldkeywords = $document->getKeywords();
if ($oldkeywords != $keywords) {
if(false === $this->callHook('preSetKeywords', $document, $keywords, $oldkeywords)) {
if(!$this->callHook('preSetKeywords', $document, $keywords, $oldkeywords)) {
}
if(!$document->setKeywords($keywords)) {
return false;
}
if(false === $this->callHook('postSetKeywords', $document, $keywords, $oldkeywords)) {
if(!$this->callHook('postSetKeywords', $document, $keywords, $oldkeywords)) {
}
}
@ -95,21 +95,21 @@ class SeedDMS_Controller_EditDocument extends SeedDMS_Controller_Common {
if (count($categoriesarr) != count($oldcategories) ||
array_diff($categories, $oldcatsids)) {
if(false === $this->callHook('preSetCategories', $document, $categoriesarr, $oldcategories)) {
if(!$this->callHook('preSetCategories', $document, $categoriesarr, $oldcategories)) {
}
if(!$document->setCategories($categoriesarr)) {
return false;
}
if(false === $this->callHook('postSetCategories', $document, $categoriesarr, $oldcategories)) {
if(!$this->callHook('postSetCategories', $document, $categoriesarr, $oldcategories)) {
}
}
} elseif($oldcategories) {
if(false === $this->callHook('preSetCategories', $document, array(), $oldcategories)) {
if(!$this->callHook('preSetCategories', $document, array(), $oldcategories)) {
}
if(!$document->setCategories(array())) {
return false;
}
if(false === $this->callHook('postSetCategories', $document, array(), $oldcategories)) {
if(!$this->callHook('postSetCategories', $document, array(), $oldcategories)) {
}
}
@ -122,37 +122,10 @@ class SeedDMS_Controller_EditDocument extends SeedDMS_Controller_Common {
if($attribute) {
switch($attrdef->getType()) {
case SeedDMS_Core_AttributeDefinition::type_date:
if(is_array($attribute))
$attribute = array_map(fn($value): string => date('Y-m-d', makeTsFromDate($value)), $attribute);
else
$attribute = date('Y-m-d', makeTsFromDate($attribute));
break;
case SeedDMS_Core_AttributeDefinition::type_folder:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getFolder((int) $value), $attribute);
else
$attribute = $dms->getFolder((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_document:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getDocument((int) $value), $attribute);
else
$attribute = $dms->getDocument((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_user:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getUser((int) $value), $attribute);
else
$attribute = $dms->getUser((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_group:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getGroup((int) $value), $attribute);
else
$attribute = $dms->getGroup((int) $attribute);
break;
}
if(!$attrdef->validate($attribute, $document, false)) {
if(!$attrdef->validate($attribute, $document, true)) {
$this->errormsg = getAttributeValidationError($attrdef->getValidationError(), $attrdef->getName(), $attribute);
return false;
}
@ -189,10 +162,6 @@ class SeedDMS_Controller_EditDocument extends SeedDMS_Controller_Common {
}
}
/* There are various hooks in inc/inc.FulltextInit.php which will take
* care of reindexing it. They just delete the indexing date which is
* faster then indexing the folder completely
*
if($fulltextservice && ($index = $fulltextservice->Indexer()) && $document) {
$idoc = $fulltextservice->IndexedDocument($document);
if(false !== $this->callHook('preIndexDocument', $document, $idoc)) {
@ -204,7 +173,6 @@ class SeedDMS_Controller_EditDocument extends SeedDMS_Controller_Common {
$index->commit();
}
}
*/
} elseif($result === false) {
if(empty($this->errormsg))
@ -212,7 +180,7 @@ class SeedDMS_Controller_EditDocument extends SeedDMS_Controller_Common {
return false;
}
if(false === $this->callHook('postEditDocument')) {
if(!$this->callHook('postEditDocument')) {
}
return true;

View File

@ -51,42 +51,10 @@ class SeedDMS_Controller_EditFolder extends SeedDMS_Controller_Common {
$oldattributes = $folder->getAttributes();
if($attributes) {
foreach($attributes as $attrdefid=>$attribute) {
if($attrdef = $dms->getAttributeDefinition($attrdefid)) {
$attrdef = $dms->getAttributeDefinition($attrdefid);
if(null === ($ret = $this->callHook('validateAttribute', $attrdef, $attribute))) {
if($attribute) {
switch($attrdef->getType()) {
case SeedDMS_Core_AttributeDefinition::type_date:
if(is_array($attribute))
$attribute = array_map(fn($value): string => date('Y-m-d', makeTsFromDate($value)), $attribute);
else
$attribute = date('Y-m-d', makeTsFromDate($attribute));
break;
case SeedDMS_Core_AttributeDefinition::type_folder:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getFolder((int) $value), $attribute);
else
$attribute = $dms->getFolder((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_document:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getDocument((int) $value), $attribute);
else
$attribute = $dms->getDocument((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_user:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getUser((int) $value), $attribute);
else
$attribute = $dms->getUser((int) $attribute);
break;
case SeedDMS_Core_AttributeDefinition::type_group:
if(is_array($attribute))
$attribute = array_map(fn($value): object => $dms->getGroup((int) $value), $attribute);
else
$attribute = $dms->getGroup((int) $attribute);
break;
}
if(!$attrdef->validate($attribute, $folder, false)) {
if(!$attrdef->validate($attribute, $folder, true)) {
$this->errormsg = getAttributeValidationText($attrdef->getValidationError(), $attrdef->getName(), $attribute);
return false;
}
@ -97,7 +65,6 @@ class SeedDMS_Controller_EditFolder extends SeedDMS_Controller_Common {
}
} elseif($attrdef->getMinValues() > 0) {
$this->errormsg = getMLText("attr_min_values", array("attrname"=>$attrdef->getName()));
return false;
} elseif(isset($oldattributes[$attrdefid])) {
if(!$folder->removeAttribute($dms->getAttributeDefinition($attrdefid)))
return false;
@ -108,7 +75,6 @@ class SeedDMS_Controller_EditFolder extends SeedDMS_Controller_Common {
}
}
}
}
foreach($oldattributes as $attrdefid=>$oldattribute) {
if(!isset($attributes[$attrdefid])) {
if(!$folder->removeAttribute($dms->getAttributeDefinition($attrdefid)))
@ -124,10 +90,6 @@ class SeedDMS_Controller_EditFolder extends SeedDMS_Controller_Common {
}
}
/* There are various hooks in inc/inc.FulltextInit.php which will take
* care of reindexing it. They just delete the indexing date which is
* faster then indexing the folder completely
*
if($fulltextservice && ($index = $fulltextservice->Indexer()) && $folder) {
$idoc = $fulltextservice->IndexedDocument($folder);
if(false !== $this->callHook('preIndexFolder', $folder, $idoc)) {
@ -139,7 +101,6 @@ class SeedDMS_Controller_EditFolder extends SeedDMS_Controller_Common {
$index->commit();
}
}
*/
} elseif($result === false) {
if(empty($this->errormsg))
@ -147,7 +108,7 @@ class SeedDMS_Controller_EditFolder extends SeedDMS_Controller_Common {
return false;
}
if(false === $this->callHook('postEditFolder')) {
if(!$this->callHook('postEditFolder')) {
}
return true;

View File

@ -22,63 +22,41 @@
*/
class SeedDMS_Controller_EmptyFolder extends SeedDMS_Controller_Common {
/* Register a callback which removes each document/folder from the fulltext index
* The callback must return null otherwise the removal will be canceled.
*/
static function removeFromIndex($arr, $object) { /* {{{ */
$fulltextservice = $arr[0];
$lucenesearch = $fulltextservice->Search();
$hit = null;
if($object->isType('document'))
$hit = $lucenesearch->getDocument($object->getID());
elseif($object->isType('folder'))
$hit = $lucenesearch->getFolder($object->getID());
if($hit) {
$index = $fulltextservice->Indexer();
$index->delete($hit->id);
$index->commit();
}
return null;
} /* }}} */
static function removePreviews($arr, $document) { /* {{{ */
$previewer = $arr[0];
$previewer->deleteDocumentPreviews($document);
return null;
} /* }}} */
public function run() { /* {{{ */
public function run() {
$dms = $this->params['dms'];
$user = $this->params['user'];
$settings = $this->params['settings'];
$folder = $this->params['folder'];
$fulltextservice = $this->params['fulltextservice'];
$index = $this->params['index'];
$indexconf = $this->params['indexconf'];
/* Get the folder id and name before removing the folder */
/* Get the document id and name before removing the document */
$foldername = $folder->getName();
$folderid = $folder->getID();
if(false === $this->callHook('preEmptyFolder')) {
if(empty($this->errormsg))
$this->errormsg = 'hook_preEmptyFolder_failed';
return false;
return null;
}
$result = $this->callHook('emptyFolder', $folder);
if($result === null) {
if($fulltextservice && ($index = $fulltextservice->Indexer())) {
/* Register a callback which is called by SeedDMS_Core when a folder
* or document is removed. The second parameter passed to this callback
* is the document or folder to be removed.
/* Register a callback which removes each document from the fulltext index
* The callback must return null other the removal will be canceled.
*/
$dms->addCallback('onPreRemoveDocument', 'SeedDMS_Controller_EmptyFolder::removeFromIndex', array($fulltextservice));
$dms->addCallback('onPreRemoveFolder', 'SeedDMS_Controller_EmptyFolder::removeFromIndex', array($fulltextservice));
function removeFromIndex($arr, $document) {
$index = $arr[0];
$indexconf = $arr[1];
$lucenesearch = new $indexconf['Search']($index);
if($hit = $lucenesearch->getDocument($document->getID())) {
$index->delete($hit->id);
$index->commit();
}
/* Register another callback which removes the preview images of the document */
$previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir);
$dms->addCallback('onPreRemoveDocument', 'SeedDMS_Controller_EmptyFolder::removePreviews', array($previewer));
return null;
}
if($index)
$dms->setCallback('onPreEmptyDocument', 'removeFromIndex', array($index, $indexconf));
if (!$folder->emptyFolder()) {
$this->errormsg = 'error_occured';
@ -90,9 +68,9 @@ class SeedDMS_Controller_EmptyFolder extends SeedDMS_Controller_Common {
return false;
}
if(false === $this->callHook('postEmptyFolder')) {
if(!$this->callHook('postEmptyFolder')) {
}
return true;
} /* }}} */
}
}

View File

@ -31,12 +31,97 @@ class SeedDMS_Controller_Login extends SeedDMS_Controller_Common {
return self::$user;
} /* }}} */
public function _finalize($user) { /* {{{ */
public function run() { /* {{{ */
$dms = $this->params['dms'];
$settings = $this->params['settings'];
$session = $this->params['session'];
$sesstheme = $this->params['sesstheme'];
$source = isset($this->params['source']) ? $this->params['source'] : '';
$referuri = $this->params['referuri'];
$lang = $this->params['lang'];
$login = $this->params['login'];
$pwd = $this->params['pwd'];
self::$user = null;
/* The preLogin hook may set self::$user which will prevent any further
* authentication process.
*/
if($this->callHook('preLogin')) {
}
$user = self::$user;
/* The password may only be empty if the guest user tries to log in.
* There is just one guest account with id $settings->_guestID which
* is allowed to log in without a password. All other guest accounts
* are treated like regular logins
*/
if(!$user && $settings->_enableGuestLogin && (int) $settings->_guestID) {
$guestUser = $dms->getUser((int) $settings->_guestID);
if(!$guestUser) {
$this->setErrorMsg("login_error_text");
return false;
}
if(($login != $guestUser->getLogin())) {
if ((!isset($pwd) || strlen($pwd)==0)) {
$this->setErrorMsg("login_error_text");
return false;
}
} else {
$user = $guestUser;
}
}
/* Run any additional authentication method. The hook must return a
* valid user, if the authentication succeeded. If it fails, it must
* return false and if the hook doesn't care at all, if must return null.
*/
if(!$user) {
$user = $this->callHook('authenticate');
if(false === $user) {
if(empty($this->errormsg))
$this->setErrorMsg("authentication_failed");
return false;
}
}
/* Deprecated: Run any additional authentication implemented in a hook */
if(!is_object($user) && isset($GLOBALS['SEEDDMS_HOOKS']['authentication'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['authentication'] as $authObj) {
if(!$user && method_exists($authObj, 'authenticate')) {
$user = $authObj->authenticate($dms, $settings, $login, $pwd);
if(false === $user) {
if(empty($this->errormsg))
$this->setErrorMsg("authentication_failed");
return false;
}
}
}
}
/* Authenticate against LDAP server {{{ */
if (!is_object($user) && isset($settings->_ldapHost) && strlen($settings->_ldapHost)>0) {
require_once("../inc/inc.ClassLdapAuthentication.php");
$authobj = new SeedDMS_LdapAuthentication($dms, $settings);
$user = $authobj->authenticate($login, $pwd);
if(!$user) {
add_log_line('Authentication against LDAP failed for user '.$login);
}
} /* }}} */
/* Authenticate against SeedDMS database {{{ */
if(!is_object($user)) {
require_once("../inc/inc.ClassDbAuthentication.php");
$authobj = new SeedDMS_DbAuthentication($dms, $settings);
$user = $authobj->authenticate($login, $pwd);
} /* }}} */
/* If the user is still not authenticated, then exit with an error */
if(!is_object($user)) {
$this->callHook('loginFailed');
$this->setErrorMsg("login_error_text");
return false;
}
self::$user = $user;
@ -84,10 +169,6 @@ class SeedDMS_Controller_Login extends SeedDMS_Controller_Common {
/* Clear login failures if login was successful */
$user->clearLoginFailures();
/* Setting the theme and language and all the cookie handling is
* only done when authentication was requested from a weg page.
*/
if($source == 'web') {
// Capture the user's language and theme settings.
if ($lang) {
$user->setLanguage($lang);
@ -156,121 +237,10 @@ class SeedDMS_Controller_Login extends SeedDMS_Controller_Common {
$lifetime = 0;
setcookie("mydms_session", $id, $lifetime, $settings->_httpRoot, null, false, true);
}
}
if($this->callHook('postLogin', $user)) {
}
return true;
} /* }}} */
public function run() { /* {{{ */
$dms = $this->params['dms'];
$settings = $this->params['settings'];
$session = $this->params['session'];
$authenticator = $this->params['authenticator'];
$source = isset($this->params['source']) ? $this->params['source'] : '';
$sesstheme = $this->getParam('sesstheme');
$referuri = $this->getParam('referuri');
$lang = $this->getParam('lang');
$login = $this->params['login'];
$pwd = $this->params['pwd'];
self::$user = null;
/* The preLogin hook may set self::$user which will prevent any further
* authentication process.
*/
if($this->callHook('preLogin')) {
}
$user = self::$user;
/* The password may only be empty if the guest user tries to log in.
* There is just one guest account with id $settings->_guestID which
* is allowed to log in without a password. All other guest accounts
* are treated like regular logins
*/
if(!$user && $settings->_enableGuestLogin && (int) $settings->_guestID) {
$guestUser = $dms->getUser((int) $settings->_guestID);
if($guestUser) {
if(($login != $guestUser->getLogin())) {
if ((!isset($pwd) || strlen($pwd)==0)) {
$this->setErrorMsg("login_error_text");
return false;
}
} else {
$user = $guestUser;
}
}
}
/* Run any additional authentication method. The hook must return a
* valid user, if the authentication succeeded. If it fails, it must
* return false and if the hook doesn't care at all, if must return null.
*/
if(!$user) {
$user = $this->callHook('authenticate', $source);
if(false === $user) {
if(empty($this->errormsg))
$this->setErrorMsg("authentication_failed");
return false;
}
}
/* Deprecated: Run any additional authentication implemented in a hook */
if(!is_object($user) && isset($GLOBALS['SEEDDMS_HOOKS']['authentication'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['authentication'] as $authObj) {
if(!$user && method_exists($authObj, 'authenticate')) {
$user = $authObj->authenticate($dms, $settings, $login, $pwd);
if(false === $user) {
if(empty($this->errormsg))
$this->setErrorMsg("authentication_failed");
return false;
}
}
}
}
if(!is_object($user))
$user = $authenticator->authenticate($login, $pwd);
if(0) {
/* Authenticate against LDAP server {{{ */
if (!is_object($user) && isset($settings->_ldapHost) && strlen($settings->_ldapHost)>0) {
require_once("../inc/inc.ClassLdapAuthentication.php");
$authobj = new SeedDMS_LdapAuthentication($dms, $settings);
$user = $authobj->authenticate($login, $pwd);
if(!$user) {
add_log_line('Authentication against LDAP failed for user '.$login);
}
} /* }}} */
/* Authenticate against SeedDMS database {{{ */
if(!is_object($user)) {
require_once("../inc/inc.ClassDbAuthentication.php");
$authobj = new SeedDMS_DbAuthentication($dms, $settings);
$user = $authobj->authenticate($login, $pwd);
} /* }}} */
}
/* If the user is still not authenticated, then exit with an error */
if(!is_object($user)) {
/* if counting of login failures is turned on, then increment its value */
if($settings->_loginFailure) {
$user = $dms->getUserByLogin($login);
if($user) {
$failures = $user->addLoginFailure();
if($failures >= $settings->_loginFailure)
$user->setDisabled(true);
}
}
$this->callHook('loginFailed');
$this->setErrorMsg("login_error_text");
return false;
}
return self::_finalize($user);
} /* }}} */
}

View File

@ -27,7 +27,6 @@ class SeedDMS_Controller_PdfPreview extends SeedDMS_Controller_Common {
$dms = $this->params['dms'];
$type = $this->params['type'];
$settings = $this->params['settings'];
$conversionmgr = $this->params['conversionmgr'];
switch($type) {
case "version":
@ -52,9 +51,6 @@ class SeedDMS_Controller_PdfPreview extends SeedDMS_Controller_Common {
$this->params['content'] = $content;
if(null === $this->callHook('version')) {
$previewer = new SeedDMS_Preview_PdfPreviewer($settings->_cacheDir, $settings->_cmdTimeout);
if($conversionmgr)
$previewer->setConversionMgr($conversionmgr);
else
$previewer->setConverters(isset($settings->_converters['pdf']) ? $settings->_converters['pdf'] : array());
$previewer->setXsendfile($settings->_enableXsendfile);
if(!$previewer->hasPreview($content)) {

View File

@ -22,11 +22,14 @@
*/
class SeedDMS_Controller_Preview extends SeedDMS_Controller_Common {
public function version() { /* {{{ */
public function run() {
global $theme;
$dms = $this->params['dms'];
$type = $this->params['type'];
$settings = $this->params['settings'];
$conversionmgr = $this->params['conversionmgr'];
switch($type) {
case "version":
$version = $this->params['version'];
$document = $this->params['document'];
$width = $this->params['width'];
@ -52,9 +55,6 @@ class SeedDMS_Controller_Preview extends SeedDMS_Controller_Common {
$previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir, $width, $settings->_cmdTimeout);
else
$previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir);
if($conversionmgr)
$previewer->setConversionMgr($conversionmgr);
else
$previewer->setConverters($settings->_converters['preview']);
$previewer->setXsendfile($settings->_enableXsendfile);
if(!$previewer->hasPreview($content)) {
@ -64,19 +64,15 @@ class SeedDMS_Controller_Preview extends SeedDMS_Controller_Common {
}
}
if(!$previewer->hasPreview($content)) {
return false;
header('Content-Type: image/svg+xml');
readfile('../views/'.$theme.'/images/empty.svg');
exit;
}
header('Content-Type: image/png');
$previewer->getPreview($content);
return true;
}
} /* }}} */
public function file() { /* {{{ */
$dms = $this->params['dms'];
$settings = $this->params['settings'];
$conversionmgr = $this->params['conversionmgr'];
break;
case "file":
$object = $this->params['object'];
$document = $this->params['document'];
$width = $this->params['width'];
@ -90,9 +86,6 @@ class SeedDMS_Controller_Preview extends SeedDMS_Controller_Common {
$previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir, $width, $settings->_cmdTimeout);
else
$previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir);
if($conversionmgr)
$previewer->setConversionMgr($conversionmgr);
else
$previewer->setConverters($settings->_converters['preview']);
$previewer->setXsendfile($settings->_enableXsendfile);
@ -103,12 +96,15 @@ class SeedDMS_Controller_Preview extends SeedDMS_Controller_Common {
}
}
if(!$previewer->hasPreview($object)) {
return false;
header('Content-Type: image/svg+xml');
readfile('../views/'.$theme.'/images/empty.svg');
exit;
}
header('Content-Type: image/png');
$previewer->getPreview($object);
}
break;
}
return true;
}
} /* }}} */
}

View File

@ -43,8 +43,6 @@ class SeedDMS_Controller_RemoveDocument extends SeedDMS_Controller_Common {
$result = $this->callHook('removeDocument', $document);
if($result === null) {
$previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir);
$previewer->deleteDocumentPreviews($document);
if (!$document->remove()) {
if($dms->lasterror)
$this->errormsg = $dms->lasterror;
@ -67,7 +65,7 @@ class SeedDMS_Controller_RemoveDocument extends SeedDMS_Controller_Common {
}
}
if(false === $this->callHook('postRemoveDocument')) {
if(!$this->callHook('postRemoveDocument')) {
}
return true;

View File

@ -22,40 +22,14 @@
*/
class SeedDMS_Controller_RemoveFolder extends SeedDMS_Controller_Common {
/* Register a callback which removes each document/folder from the fulltext index
* The callback must return null otherwise the removal will be canceled.
*/
static function removeFromIndex($arr, $object) { /* {{{ */
$fulltextservice = $arr[0];
$lucenesearch = $fulltextservice->Search();
$hit = null;
if($object->isType('document'))
$hit = $lucenesearch->getDocument($object->getID());
elseif($object->isType('folder'))
$hit = $lucenesearch->getFolder($object->getID());
if($hit) {
$index = $fulltextservice->Indexer();
$index->delete($hit->id);
$index->commit();
}
return null;
} /* }}} */
static function removePreviews($arr, $document) { /* {{{ */
$previewer = $arr[0];
$previewer->deleteDocumentPreviews($document);
return null;
} /* }}} */
public function run() { /* {{{ */
public function run() {
$dms = $this->params['dms'];
$user = $this->params['user'];
$settings = $this->params['settings'];
$folder = $this->params['folder'];
$fulltextservice = $this->params['fulltextservice'];
/* Get the folder id and name before removing the folder */
/* Get the document id and name before removing the document */
$foldername = $folder->getName();
$folderid = $folder->getID();
@ -67,18 +41,38 @@ class SeedDMS_Controller_RemoveFolder extends SeedDMS_Controller_Common {
$result = $this->callHook('removeFolder', $folder);
if($result === null) {
if($fulltextservice && ($index = $fulltextservice->Indexer())) {
/* Register a callback which is called by SeedDMS_Core when a folder
* or document is removed. The second parameter passed to this callback
* is the document or folder to be removed.
/* Register a callback which removes each document from the fulltext index
* The callback must return null other the removal will be canceled.
*/
$dms->addCallback('onPreRemoveDocument', 'SeedDMS_Controller_RemoveFolder::removeFromIndex', array($fulltextservice));
$dms->addCallback('onPreRemoveFolder', 'SeedDMS_Controller_RemoveFolder::removeFromIndex', array($fulltextservice));
function removeFromIndex($arr, $document) {
$fulltextservice = $arr[0];
$lucenesearch = $fulltextservice->Search();
$hit = null;
if($document->isType('document'))
$hit = $lucenesearch->getDocument($document->getID());
elseif($document->isType('folder'))
$hit = $lucenesearch->getFolder($document->getID());
if($hit) {
$index = $fulltextservice->Indexer();
$index->delete($hit->id);
$index->commit();
}
return null;
}
if($fulltextservice && ($index = $fulltextservice->Indexer())) {
$dms->addCallback('onPreRemoveDocument', 'removeFromIndex', array($fulltextservice));
$dms->addCallback('onPreRemoveFolder', 'removeFromIndex', array($fulltextservice));
}
/* Register another callback which removes the preview images of the document */
function removePreviews($arr, $document) {
$previewer = $arr[0];
$previewer->deleteDocumentPreviews($document);
return null;
}
require_once("SeedDMS/Preview.php");
$previewer = new SeedDMS_Preview_Previewer($settings->_cacheDir);
$dms->addCallback('onPreRemoveDocument', 'SeedDMS_Controller_RemoveFolder::removePreviews', array($previewer));
$dms->addCallback('onPreRemoveDocument', 'removePreviews', array($previewer));
if (!$folder->remove()) {
$this->errormsg = 'error_occured';
@ -90,9 +84,9 @@ class SeedDMS_Controller_RemoveFolder extends SeedDMS_Controller_Common {
return false;
}
if(false === $this->callHook('postRemoveFolder')) {
if(!$this->callHook('postRemoveFolder')) {
}
return true;
} /* }}} */
}
}

View File

@ -7,70 +7,70 @@
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010-2023 Uwe Steinmann
* @copyright Copyright (C) 2010-2013 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Class which does the busines logic for reviewing a document
* Class which does the busines logic for downloading a document
*
* @category DMS
* @package SeedDMS
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010-2023 Uwe Steinmann
* @copyright Copyright (C) 2010-2013 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_Controller_ReviewDocument extends SeedDMS_Controller_Common {
public function run() { /* {{{ */
public function run() {
$dms = $this->params['dms'];
$user = $this->params['user'];
$settings = $this->params['settings'];
$document = $this->params['document'];
$content = $this->params['content'];
$reviewtype = $this->params['type'];
$reviewstatus = $this->params['status'];
$reviewcomment = $this->params['comment'];
$reviewfile = $this->params['file'];
$reviewgroup = $this->params['group'];
$overallStatus = $content->getStatus();
$this->oldstatus = $overallStatus['status'];
$this->newstatus = $this->oldstatus;
$reviewstatus = $this->params['reviewstatus'];
$reviewtype = $this->params['reviewtype'];
$group = $this->params['group'];
$comment = $this->params['comment'];
$file = $this->params['file'];
/* Get the document id and name before removing the document */
$docname = $document->getName();
$documentid = $document->getID();
if(!$this->callHook('preReviewDocument', $content)) {
}
$result = $this->callHook('reviewDocument', $content);
if($result === null) {
if ($reviewtype == "ind") {
$reviewLogID = $content->setReviewByInd($user, $user, $reviewstatus, $reviewcomment, $reviewfile);
} elseif($reviewtype == "grp") {
$reviewLogID = $content->setReviewByGrp($reviewgroup, $user, $reviewstatus, $reviewcomment, $reviewfile);
} else {
$this->errormsg = "review_wrong_type";
if(0 > $content->setReviewByInd($user, $user, $reviewstatus, $comment, $file)) {
$this->error = 1;
$this->errormsg = "review_update_failed";
return false;
}
if($reviewLogID === false || 0 > $reviewLogID) {
} elseif ($reviewtype == "grp") {
if(0 > $content->setReviewByGrp($group, $user, $reviewstatus, $comment, $file)) {
$this->error = 1;
$this->errormsg = "review_update_failed";
return false;
}
}
}
/* Check to see if the overall status for the document version needs to be
* updated.
*/
$result = $this->callHook('reviewUpdateDocumentStatus', $content);
if($result === null) {
if ($reviewstatus == -1){
$this->newstatus = S_REJECTED;
if($content->setStatus(S_REJECTED, $reviewcomment, $user)) {
if(isset($GLOBALS['SEEDDMS_HOOKS']['reviewDocument'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['reviewDocument'] as $hookObj) {
if (method_exists($hookObj, 'postReviewDocument')) {
$hookObj->postReviewDocument(null, $content, S_REJECTED);
}
}
}
if($content->setStatus(S_REJECTED,$comment,$user)) {
}
} else {
$docReviewStatus = $content->getReviewStatus();
if (is_bool($docReviewStatus) && !$docReviewStatus) {
$this->error = 1;
$this->errormsg = "cannot_retrieve_review_snapshot";
return false;
}
@ -89,6 +89,7 @@ class SeedDMS_Controller_ReviewDocument extends SeedDMS_Controller_Common {
if ($reviewCT == $reviewTotal) {
$docApprovalStatus = $content->getApprovalStatus();
if (is_bool($docApprovalStatus) && !$docApprovalStatus) {
$this->error = 1;
$this->errormsg = "cannot_retrieve_approval_snapshot";
return false;
}
@ -105,19 +106,15 @@ class SeedDMS_Controller_ReviewDocument extends SeedDMS_Controller_Common {
// If the approvals received is less than the approvals total, then
// change status to pending approval.
if ($approvalCT<$approvalTotal) {
$this->newstatus = S_DRAFT_APP;
} else {
$newStatus=S_DRAFT_APP;
}
else {
// Otherwise, change the status to released.
$this->newstatus = S_RELEASED;
}
if($content->setStatus($this->newstatus, getMLText("automatic_status_update"), $user)) {
if(isset($GLOBALS['SEEDDMS_HOOKS']['reviewDocument'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['reviewDocument'] as $hookObj) {
if (method_exists($hookObj, 'postReviewDocument')) {
$hookObj->postReviewDocument(null, $content, $this->newstatus);
}
}
$newStatus=S_RELEASED;
}
if ($content->setStatus($newStatus, getMLText("automatic_status_update"), $user)) {
// Send notification to subscribers.
}
}
}
@ -127,5 +124,6 @@ class SeedDMS_Controller_ReviewDocument extends SeedDMS_Controller_Common {
}
return true;
} /* }}} */
}
}

View File

@ -22,10 +22,6 @@
*/
class SeedDMS_Controller_ReviseDocument extends SeedDMS_Controller_Common {
public $oldstatus;
public $newstatus;
public function run() {
$dms = $this->params['dms'];
$user = $this->params['user'];
@ -36,9 +32,6 @@ class SeedDMS_Controller_ReviseDocument extends SeedDMS_Controller_Common {
$revisiontype = $this->params['revisiontype'];
$group = $this->params['group'];
$comment = $this->params['comment'];
$overallStatus = $content->getStatus();
$this->oldstatus = $overallStatus['status'];
$this->newstatus = $this->oldstatus;
/* if set to true, a single reject will reject the doc. If set to false
* all revisions will be collected first and afterwards the doc is rejected
@ -78,7 +71,6 @@ class SeedDMS_Controller_ReviseDocument extends SeedDMS_Controller_Common {
$result = $this->callHook('reviseUpdateDocumentStatus', $content);
if($result === null) {
if ($onevotereject && $revisionstatus == -1){
$this->newstatus = S_NEEDS_CORRECTION;
if(!$content->setStatus(S_NEEDS_CORRECTION,$comment,$user)) {
$this->error = 1;
$this->errormsg = "revision_update_failed";
@ -110,22 +102,22 @@ class SeedDMS_Controller_ReviseDocument extends SeedDMS_Controller_Common {
// of them were rejections then documents needs correction.
// Otherwise put it back into revision workflow
if ($revisionok == $revisionTotal) {
$this->newstatus=S_RELEASED;
if ($content->finishRevision($user, $this->newstatus, 'Finished revision workflow', getMLText("automatic_status_update"))) {
$newStatus=S_RELEASED;
if ($content->finishRevision($user, $newStatus, 'Finished revision workflow', getMLText("automatic_status_update"))) {
if(!$this->callHook('finishReviseDocument', $content)) {
}
}
} elseif (($revisionok + $revisionnotok) == $revisionTotal) {
$this->newstatus=S_NEEDS_CORRECTION;
// if ($content->finishRevision($user, $this->newstatus, 'Finished revision workflow', getMLText("automatic_status_update"))) {
if(!$content->setStatus($this->newstatus,$comment,$user)) {
$newStatus=S_NEEDS_CORRECTION;
// if ($content->finishRevision($user, $newStatus, 'Finished revision workflow', getMLText("automatic_status_update"))) {
if(!$content->setStatus($newStatus,$comment,$user)) {
$this->error = 1;
$this->errormsg = "revision_update_failed";
return false;
}
} else {
$this->newstatus=S_IN_REVISION;
if(!$content->setStatus($this->newstatus,$comment,$user)) {
$newStatus=S_IN_REVISION;
if(!$content->setStatus($newStatus,$comment,$user)) {
$this->error = 1;
$this->errormsg = "revision_update_failed";
return false;

View File

@ -42,7 +42,7 @@ class SeedDMS_Controller_TransferDocument extends SeedDMS_Controller_Common {
if (!$document->transferToUser($newuser)) {
return false;
} else {
if(false === $this->callHook('postTransferDocument')) {
if(!$this->callHook('postTransferDocument')) {
}
}
}

View File

@ -39,11 +39,10 @@ class SeedDMS_Controller_TransmittalDownload extends SeedDMS_Controller_Common {
$document = $content->getDocument();
if ($document->getAccessMode($user) >= M_READ) {
$extracols = $this->callHook('extraDownloadColumns', $document);
$filename = $this->callHook('filenameDownloadItem', $content);
if($rawcontent = $this->callHook('rawcontent', $content)) {
$downmgr->addItem($content, $extracols, $rawcontent, $filename);
$downmgr->addItem($content, $extracols, $rawcontent);
} else
$downmgr->addItem($content, $extracols, null, $filename);
$downmgr->addItem($content, $extracols);
}
}

View File

@ -59,7 +59,7 @@ class SeedDMS_Controller_UpdateDocument extends SeedDMS_Controller_Common {
$content = $this->callHook('updateDocument');
if($content === null) {
$filesize = SeedDMS_Core_File::fileSize($userfiletmp);
if($contentResult=$document->addContent($comment, $user, $userfiletmp, utf8_basename($userfilename), $filetype, $userfiletype, $reviewers, $approvers, 0, $attributes, $workflow, $initialdocumentstatus)) {
if($contentResult=$document->addContent($comment, $user, $userfiletmp, utf8_basename($userfilename), $filetype, $userfiletype, $reviewers, $approvers, $version=0, $attributes, $workflow, $initialdocumentstatus)) {
if ($this->hasParam('expires')) {
if($document->setExpires($this->getParam('expires'))) {
@ -105,7 +105,7 @@ class SeedDMS_Controller_UpdateDocument extends SeedDMS_Controller_Common {
}
}
if(false === $this->callHook('postUpdateDocument', $document, $content)) {
if(!$this->callHook('postUpdateDocument', $document, $content)) {
}
return $content;

View File

@ -49,7 +49,6 @@ class SeedDMS_Controller_ViewOnline extends SeedDMS_Controller_Common {
*/
$this->params['content'] = $content;
if(null === $this->callHook('version')) {
if(file_exists($dms->contentDir . $content->getPath())) {
header("Content-Type: " . $content->getMimeType());
$efilename = rawurlencode($content->getOriginalFileName());
if (!isset($settings->_viewOnlineFileTypes) || !is_array($settings->_viewOnlineFileTypes) || !in_array(strtolower($content->getFileType()), $settings->_viewOnlineFileTypes)) {
@ -58,11 +57,9 @@ class SeedDMS_Controller_ViewOnline extends SeedDMS_Controller_Common {
header("Content-Disposition: filename=\"" . $efilename . "\"; filename*=UTF-8''".$efilename);
}
header("Cache-Control: must-revalidate");
header("ETag: ".$content->getChecksum());
sendFile($dms->contentDir.$content->getPath());
}
}
break;
}
return true;

View File

@ -1,31 +1,3 @@
Commands for converting documents
----------------------------------
This file contains commands for converting different document types
into
* text (for fulltext search)
* png (for preview images)
* pdf (for pdf documents)
Such conversions may not necessarily output an excact equivalent of
the input file, but outputs a suitable representation, e.g.
converting an mp3 file into text may output the metadata or even the
lyrics of the song. Converting it into a preview image may result
in a picture of the album cover.
Please note, that when ever a command outputs anything to stderr,
this will considered as a failure of the command. Most command line
programs have a parameter (.e.g. `-q`) to suppress such an output.
If you run php-fpm you may encounter problems with charsets based on
UTF-8. Programms like `catdoc` read LANG from the environment to
set the correct encoding of the output. php-fpm often clears the
environment and programms like `catdoc` will not longer output any
UTF-8 chars. In such a case you may want to set `clear_env=no` in
php-fpm's configuration. On Debian this is done in the file
`/etc/php/<php version>/fpm/pool.d/www.conf`. Search for `clear_env`.
Conversion to text for fulltext search
=======================================
@ -35,13 +7,7 @@ application/csv
cat '%s'
application/pdf
pdftotext -q -nopgbrk %s - | sed -e 's/ [a-zA-Z0-9.]\{1\} / /g' -e 's/[0-9.]//g'
If pdftotext takes too long on large document you may want to pass parameter
-l to specify the last page to be converted. -q is for suppressing error/warnings
send to stderr
mutool draw -F txt -q -N -o - %s
pdftotext -nopgbrk %s - | sed -e 's/ [a-zA-Z0-9.]\{1\} / /g' -e 's/[0-9.]//g'
application/vnd.openxmlformats-officedocument.wordprocessingml.document
docx2txt '%s' -
@ -49,14 +15,11 @@ application/vnd.openxmlformats-officedocument.wordprocessingml.document
application/msword
catdoc %s
application/vnd.oasis.opendocument.text
odt2txt %s
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
xlsx2csv -d tab %s
xlsx2csv %s
application/vnd.ms-excel
xls2csv -d tab %s
xls2csv %s
text/html
html2text %s
@ -64,12 +27,6 @@ text/html
Many office formats
unoconv -d document -f txt --stdout '%s'
Apache Tika is another option for creating plain text from various document
types. Just use curl to send the document to your tika server and get the
plain text in return.
curl -s -T '%s' http://localhost:9998/tika --header 'Accept: text/plain'
Conversion to pdf for pdf preview
==================================
@ -85,10 +42,7 @@ text/rtf
image/png
image/jpg
image/jpeg
convert -density 300 '%f' 'pdf:%o'
image/svg+xml
cairosvg -f pdf -o '%o' '%f'
convert -f pdf -density 300 '%f' '%o'
application/vnd.ms-powerpoint
application/vnd.openxmlformats-officedocument.presentationml.presentation
@ -100,26 +54,6 @@ application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
application/vnd.oasis.opendocument.spreadsheet
unoconv -d spreadsheet -f pdf --stdout -v '%f' > '%o'
message/rfc822
java -jar emailconverter-2.5.3-all.jar '%f' -o '%o'
The emailconverter can be obtained from https://github.com/nickrussler/email-to-pdf-converter
It requires wkhtmltopdf which is part of debian.
text/plain
iconv -c -f utf-8 -t latin1 '%f' | a2ps -1 -q -a1 -R -B -o - - | ps2pdf - -
The parameter `-q` is important because a2ps sends some statistical
data to stderr, which makes SeedDMS believe the command has failed.
application/x-xopp
xournalpp -p "%o" "%f"
Converting from application/x-xopp to pdf only works if the xopp file
does not use a pdf document as a background, because this pdf is not
stored in the xopp fіle.
Conversion to png for preview images
=====================================
@ -131,44 +65,16 @@ It basically instructs you to comment out the line
in /etc/ImageMagick-6/policy.xml
convert determines the format of the converted image from the extension of
the output filename. SeedDMS usually sets a propper extension when running
the command, but nevertheless it is good practice to explicitly set the output
format by prefixing the output filename with 'png:'. This is of course always
needed if the output goes to stdout.
image/jpg
image/jpeg
image/png
convert -resize %wx '%f' 'png:%o'
image/svg+xml
cairosvg -f png --output-width %w -o '%o' '%f'
text/plain
convert -density 100 -resize %wx 'text:%f[0]' 'png:%o'
convert -resize %wx '%f' '%o'
application/pdf
gs -dBATCH -dNOPAUSE -sDEVICE=png16m -dPDFFitPage -r72x72 -sOutputFile=- -dFirstPage=1 -dLastPage=1 -q '%f' | convert -resize %wx png:- '%o'
convert -density 100 -resize %wx '%f[0]' 'png:%o'
mutool draw -F png -w %w -q -N -o '%o' '%f' 1
pdftocairo '%f' -png -singlefile -scale-to-x %w -scale-to-y -1 - > '%o'
pdftocairo needs to output to stdout because the output file name passed
to pdftocairo will be suffixed with png
application/postscript
convert -density 100 -resize %wx '%f[0]' 'png:%o'
text/plain
iconv -c -f utf-8 -t latin1 '%f' | a2ps -1 -q -a1 -R -B -o - - | gs -dBATCH -dNOPAUSE -sDEVICE=png16m -dFirstPage=1 -dLastPage=1 -dPDFFitPage -r72x72 -sOutputFile=- -q - | convert -resize %wx png:- 'png:%o'
On Linux systems you will have to set the desired value in /etc/papersize for a2ps
e.g. a4, or letter. Unfortunately, a2ps cannot process utf-8 encoded files. That's
why the input needs to be recoded with iconv or recode.
a2ps -1 -a1 -R -B -o - '%f' | gs -dBATCH -dNOPAUSE -sDEVICE=png16m -dFirstPage=1 -dLastPage=1 -dPDFFitPage -r72x72 -sOutputFile=- -q - | convert -resize %wx png:- '%o'
application/msword
application/vnd.oasis.opendocument.spreadsheet
@ -181,26 +87,5 @@ application/vnd.ms-powerpoint
text/csv
application/csv
application/vnd.wordperfect
unoconv -d document -e PageRange=1 -f pdf --stdout -v '%f' | gs -dBATCH -dNOPAUSE -sDEVICE=pngalpha -dPDFFitPage -r72x72 -sOutputFile=- -dFirstPage=1 -dLastPage=1 -q - | convert -resize %wx png:- 'png:%o'
unoconv -d document -e PageRange=1 -f pdf --stdout -v '%f' | gs -dBATCH -dNOPAUSE -sDEVICE=pngalpha -dPDFFitPage -r72x72 -sOutputFile=- -dFirstPage=1 -dLastPage=1 -q - | convert -resize %wx png:- '%o'
video/webm
video/mp4
This will take 12th frame of a video and converts into a png. It requires
ffmpeg to be installed.
convert -resize %wx "%f[12]" "png:%o"
You may as well use ffmpeg right away
ffmpeg -i "%f" -ss 00:00:02 -frames:v 1 -loglevel quiet -vf scale=%w:-1 -f apng "%o"
audio/mpeg
sox "%f" -n spectrogram -x 600 -Y 550 -r -l -o - | convert -resize %wx png:- "png:%o"
application/x-xopp
xournalpp -i "%o" --export-png-width=%w "%f"
Converting from application/x-xopp to png only works if the xopp file
does not use a pdf document as a background, because this pdf is not
stored in the xopp fіle.

View File

@ -5,23 +5,23 @@ REQUIREMENTS
============
SeedDMS is a web-based application written in PHP. It uses MySQL,
SQLite3 or PostgreSQL to manage the documents that were uploaded into
the application. Be aware that PostgreSQL is not very well tested.
sqlite3 or postgresql to manage the documents that were uploaded into
the application. Be aware that postgresql is not very well tested.
Make sure you have PHP >= 8.2 and MySQL 5 or higher installed. SeedDMS
Make sure you have PHP 7.x and MySQL 5 or higher installed. SeedDMS
will work with PHP running in CGI-mode as well as running as a module under
apache.
Here is a detailed list of requirements:
1. A web server with at least php 8.2
2. A mysql database, unless you use SQLite
1. A web server with at least php 7.0
2. A mysql database, unless you use sqlite
3. The php installation must have support for `pdo_mysql`, `pdo_pgsql` or `pdo_sqlite`,
`php_gd2`, `php_mbstring`, `php_xml`
4. Depending on the configuration the extensions `php_ldap`, `php_mycrypt`,
`php_gmp`, `php_libsodium`, `php_imagick` must be installed
`php_gmp`, `php_libsodium`must be installed
5. Various command line programms to convert files into text for indexing
pdftotext, catdoc, xls2csv or scconvert, cat, id3 (all optional, only needed
pdftotext, catdoc, xls2csv or scconvert, cat, id3 (optional, only needed
for fulltext search)
6. ImageMagic (the convert program) is needed for creating preview images
7. A bunch of packages from Packagist which all ship with the seeddms-quickstart
@ -29,32 +29,20 @@ Here is a detailed list of requirements:
It is highly recommended to use the quickstart archive
(seeddms-quickstart-x.y.z.tar.gz) because it includes all software packages
(excluding those listed above in item 1. to 6.) for running SeedDMS. Hence,
you still need a working web server with PHP and in addition a mysql or
PostgreSQL database unless you intend to use SQLite.
(excluding those listing above in item 1. to 6.) for running SeedDMS. Hence,
you still need a working web server with PHP and a mysql or postgres database
unless you intend to use sqlite.
QUICKSTART
===========
The fastes way to get SeedDMS running is by unpacking the archive
`seeddms-quickstart-x.y.z.tar.gz` on your webserver.
Let's assume you use seeddms-quickstart-5.1.x.tar.gz.
Let's assume you use seeddms-quickstart-5.1.10.tar.gz.
It will create a new directory `seeddms51x` containing everything you
need to run SeedDMS with SQLite3. Even if you intend to use mysql in the
long run it is advisable to first set up SeedDMS with SQLite3 and than
just switch the database.
Setting up the web server
--------------------------
First of all you will need to set up your web server. Here, we will only focus
on apache running on Debian/GNU Linux.
need to run SeedDMS with sqlite3.
Either let the document root of your web server point to the directory `www`
below `seeddms51x`
DocumentRoot /var/www/seeddms51x/www
or add an alias. For apache this could be like
below `seeddms51x` or add an alias. For apache this could be like
Alias /seeddms51x /<some directory>/seeddms51x/www
@ -64,16 +52,11 @@ Alias /mydms /<some directory>/seeddms51x/www
Do not set the DocumentRoot or Alias to
the `seeddms51x` directory, because this will allow anybody to access
your `data` and `conf` directory if it is not secured by a .htaccess file.
This is a major security risk.
your `data` and `conf` directory. This is a major security risk.
Make sure that the subdirectory `seeddms51x/data` and the configuration file
`seeddms51/conf/settings.xml` is writeable by your web server. All other
directories can be just readable by your web server, though it is advisable
to even protect them from writing.
Adjusting the configuration of SeedDMS
---------------------------------------
directories must just be readable by your web server.
In the next step you need to adjust the configuration file in
`seeddms51x/conf/settings.xml`. Open the file in your favorite text editor
@ -86,9 +69,9 @@ set an alias like described above).
It will first ask to unlock the installer by creating a file
`ENABLE_INSTALL_TOOL` in the diretory `seeddms51x/conf/`. Change all paths by
replacing `/home/www-data` with your base directory where you put seeddms51x.
Set httpRoot to `/` (if the document root points to `seeddms51x/www`) or
`/seeddms51x` (if you have set an alias `seeddms51x` like described above).
replacing `/home/wwww-data` with your base directory where you put seeddms51x.
Set httpRoot to '/' (if the document root points to`seeddms51x/www`) or
'/seeddms51x' (if you have set an alias like described above).
Once your configuration is done,
save it, remove the file `ENABLE_INSTALL_TOOL` and point your browser to
@ -97,11 +80,11 @@ http://your-domain/ or http://your-domain/seeddms51x.
SECURITY CONSIDERATIONS
=======================
You should always access your SeedDMS installation through
a secured https connection, unless you precisly know what you are doing.
SeedDMS ships an `.htaccess` file which already has some common security
First of all you should always access your SeedDMS installation through
a secured https connection, unless you know precisly what are you doing.
SeedDMS ships an .htaccess file which already has some common security
http headers set. In order for them to apply you need to activate the
headers module. On Debian/GNU Linux this can be done with
headers module. On Debian this can be done with
```
a2enmod headers
@ -111,13 +94,17 @@ Protect directories with data or configuration
---------------------------------------------
A crucial point when setting up SeedDMS is the propper placement of the
data directory. Do not place it below your document root of your web server!
If you do so, there is a potential way that
attackers can easily access your documents with a regular web browser.
If you cannot place the data directory outside of document root, then either
restrict access to it with an appropriate `.htaccess` file like the following.
The SeedDMS quickstart archive already includes this `.htaccess` file.
data directory. Do not place it below your document root as
configured in your web server! If you do so, there is good change that
attackers can easily access your documents with a regular browser.
If you can't place the data directory outside of document root, that either
restrict access to it with an appropriate .htaccess file or/and change
the `contentOffsetDir` in `settings.xml` to something random, but ensure it
is still a valid directory name. If you change contentOffsetDir then
do not forget to move `data/1048576` to `data/<your random name>`.
Example for .htaccess file in data directory
----------------------------------------------
```
# line below if for Apache 2.4
<ifModule mod_authz_core.c>
@ -136,14 +123,6 @@ IndexIgnore *
</ifModule>
```
Alternatively or in addition you can change
the `contentOffsetDir` in `settings.xml` to something random, but ensure it
is still a valid directory name. If you change contentOffsetDir, then
do not forget to move `data/1048576` to `data/<your random name>`.
Also turn off directory listings in your apache configuration for the
`data` directory.
Securing the configuration file
---------------------------------
@ -152,43 +131,29 @@ can be crucial for those configuration options where external commands are
being configured, e.g. for the full text engine or creating preview images.
As a hoster you may not want this configuration options being set by a SeedDMS
administrator. For now you need to make the configuration file `settings.xml`
unwritable for the web server. In that case the SeedDMS administrator can
still see the configuration but will not be able to change it.
Since version 5.1.23 and 6.0.16 of SeedDMS there is some preliminary way to
hide parts of the configuration which makes them unchangeable for the
SeedDMS administrator.
unwritable for the web server.
Setting a new encryption key
------------------------------
Though this is not related to setting up the web server environment, it is
important to recreated the encryption key in SeedDMS once SeedDMS is running.
Just open the settings in the admin tools and empty the currently set
encryption key on the tab 'System'. Save the settings and check the key again.
It should be a new one. Save the settings again. The encryption key is
mainly used for creating tokens in HTML forms to prevent CSRF attacks.
It should be new one. Save the settings again
UPGRADING FROM A PREVIOUS VERSION OF SEEDDMS
UPGRATING FROM A PREVIOUS VERSION OR SEEDDMS
=============================================
As SeedDMS is a smooth continuation of LetoDMS there is no difference
in updating from LetoDMS or SeedDMS.
in updating from LetoDMS or SeedDMS
You have basically two choices to update SeedDMS:
You have basically two choices to update SeedDMS
- you install a fresh version of SeedDMS and copy over your data and configuration
- you replace the software in your current installation with a new version
The first option is less interuptive but requires to be able to set up a second
temporary SeedDMS installation, which may not be possible, e.g. because of storage
limitations. It can be the only option if you change servers.
The first update procedure is only needed if the version changes on the minor
or major version number. Changes in the subminor version number will never
include database changes and consequently it is sufficient to use the existing
data directory and database with the new version. Choose the second update
option in this case.
temporary SeedDMS installation.
In both cases make sure to have a backup of your data directory, configuration
and database.
@ -196,30 +161,22 @@ and database.
Fresh installation and take over of data
-----------------------------------------
The first update option is to set up a new instance of SeedDMS and once
that is running take over the data from your current (old) instance.
1. just do a fresh installation somewhere on your web server and make sure it
- just do a fresh installation somewhere on your web server and make sure it
works. It is fine to use
SQLite for it, even if your final installation uses MySQL.
2. replace the data directory in your new installation with the data directory
from your current installation. Depending on the size of that directory (and
whether the new installation is on a new server or the old server) you
sqlite for it, even if your final installation uses mysql.
- replace the data directory in your new installation with the data directory
from your current installation. Depending on the size of that directory you
may either copy, move or place a symbolic link. The content of the data directory
will not be changed during the update. Its even perfectly save to
browse through your documents and download them after finishing the
update. The data directory will not be modified until you actually modify
documents.
3. copy over the configuration `settings.xml` into your new installation. This will
effectively make your new installation use the data from your old installation,
because all paths are still pointing to the old installation.
4. if you use mysql you could as well make a copy of the database to make sure
your current database remains unchanged.
5. modify the `settings.xml` to fit the environment of the new installation.
This will mostly be the
will not be changed unless you modify your documents. Its perfectly save to
browse through your documents and download them.
- copy over the configuration settings.xml into your new installation
- if you use mysql you could as well make a copy of the database to make sure
your current database remains unchanged. As long as you do not do any modification,
you could even use your current database.
- modify the settings.xml to fit the fresh install. This will mostly be the
httpRoot, the paths to the installation directory and possibly the database
connection.
6. create a file `ENABLE_INSTALL_TOOL` in the `conf` directory and point
- create a file `ENABLE_INSTALL_TOOL` in the conf directory and point
your browser at http://hostname/seeddms/install
The install tool will detect the version of your current SeedDMS installation
and run the required database updates.
@ -227,24 +184,21 @@ that is running take over the data from your current (old) instance.
this step
will not be required because such a subminor version update will never
contain database updates.
- test your new installation.
Upgrading your current installation
-----------------------------------
Instead of setting up a new installation, you may as well replace the php files
in your current installation with new versions from the quickstart archive.
1. get the SeedDMS quickstart archive `seeddms-quickstart-x.y.z.tar.gz` and
unpack it somewhere on your disc.
2. copy the directory `seeddms-x.y.z` from the unpacked archive into your
current installation and make the link `seeddms` point to this new directory.
3. copy the directory `pear` from the unpacked archive into your current
installation, replacing the existing directory. Make a backup of `pear` before
the replacement if you want to ensure to be able to go back to your old version.
4. you may compare your `conf/settings.xml` file with the shipped version
`conf/settings.xml.template` for new parameters. If you don't do it, the next
- make a backup of your data folder and the configuration file settings.xml
- in case you use mysql then dump your current database
- get the SeedDMS archive seeddms-x.y.z.tar.gz and all pear packages
SeedDMS_Core, SeedDMS_Lucene, SeedDMS_Preview and extract them over your
current instalation. As they do not contain a data directory nor a settings.xml
file, you will not overwrite your existing data and configuration.
- you may compare your conf/settings.xml file with the shipped version
conf/settings.xml.template for new parameters. If you don't do it, the next
time you save the configuration the default values will be used.
5. create a file `ENABLE_INSTALL_TOOL` in the `conf` directory and point
- create a file `ENABLE_INSTALL_TOOL` in the conf directory and point
your browser at http://hostname/seeddms/install
The install tool will detect the version of your current SeedDMS installation
and run the required database updates.
@ -257,9 +211,6 @@ in your current installation with new versions from the quickstart archive.
THE LONG STORY
================
This section is mostly outdated but may still contain some valueable
information for those trying to understand the installation process.
If you intend to run a single instance of SeedDMS, you are most likely
better off by using the quickstart archive as described above. This
section is mostly for users who wants to know more about the internals
@ -345,7 +296,7 @@ http://localhost/seeddms/
* Point you web browser towards http://hostname/seeddms/install/
* Follow the instructions on the page and create a file `ENABLE_INSTALL_TOOL`
in the `conf` directory.
in the conf directory.
* Create a data directory with the thre sub directories staging, cache
and lucene.
@ -454,7 +405,7 @@ If you install SeedDMS for the first time continue with the database setup.
e.g. for mysql:
> cat create_tables-innodb.sql | mysql -useeddms -p seeddms
This step can also be done by the install tool.
* create a file `ENABLE_INSTALL_TOOL` in the `conf` directory and point
* create a file `ENABLE_INSTALL_TOOL` in the conf directory and point
your browser at http://hostname/seeddms/install
@ -598,4 +549,16 @@ LICENSING
SeedDMS is licensed unter GPLv2
Jumploader is licensed as stated by the author on th web site
<http://jumploader.com/>
-- Taken from web site of jumploader ---
You may use this software for free, however, you should not:
- Decompile binaries.
- Alter or replace class and/or resource files.
- Redistribute this software under different name or authority.
If you would like a customized version, I can do this for a fee. Don't hesitate to contact me with questions or comments.
Uwe Steinmann <info@seeddms.org>

View File

@ -1,66 +0,0 @@
Ldap configuration
===================
The configuration for authentication against an ldap server needs to be done
in the `settings.xml` file using a text editor. It cannot be edited from within the
web gui.
SeedDMS supports ldap authentication using an Active Directory (AD) or a
regular ldap server, e.g. openldap
The location of the ldap server is specified in two parameters: `host` and
`port`. `host` can be either a plain hostname or an ldap URI, including the
protocol, the host and optionally the port, e.g. ldap://localhost:389. In case
of an URI the port in the configuration must remain empty.
The authentication itself is a two step process which differs, depending on how
to bind to the server. If the configuration sets 'bindDN' and 'bindPW', those
values will be used for a initial non anonymous bind to the ldap server
otherwise an anonymous bind is executed.
After the initial bind, a ldap search for either 'uid=<username>' (ldap) or
'sAMAccountName=<username>' (AD) below basedn is done. The purpose of this
search is to retrieve a working bindDN which is then used to actually
authenticate the user. In case of an anonymous first bind the search will
likely fail and the bindDN for the second bind will be either
'uid=<username>,<basedn>' (ldap) or '<username>@<accountDomainName>' (AD). If
the search succeeds the bindDN will be taken from the user's data in the ldap
server. This bindDN will be used for a second bind using the users password.
If the second bind succeeds the user could be successfully authenticated.
The data from the ldap server can be used to create an account in SeedDMS
if the user trying to login does not exist yet, but was able to authenticate.
This will only be done if 'authentication->restricted' in the configuration
is set to false. In that case the common name (cn) and email address is taken
from ldap. An already existing account in SeedDMS will be updated with data from
ldap.
Since version 5.1.35 and 6.0.28 the field name of the email address in ldap
can be set with the attribute `mailField`. If it is not set it defaults to `mail`.
Since version 5.1.34 and 6.0.27 the groups of a user stored in the ldap directory
can be synchronised with the groups in SeedDMS. The ldap field storing
the groups can be configured with the attribute `mailField`. This will add
new groups in SeedDMS and aѕsign them to the user.
Examples
---------
Anonymous bind to openldap on localhost, port 389
- type = "ldap"
- baseDN = "ou=users,dc=mycompany,dc=de"
- host = "ldap://localhost"
During authentication as user 'admin' the following steps are executed
1. connect to ldap server at localhost:389
2. do an anonymous bind
3. search for 'uid=admin' below basedn
4.1. if search succeeds use the dn from the user
4.2. if search fails use 'uid=admin,<basedn>' as dn
5. do a non anonymous bind with dn and password entered by user
6. if step 5. succeeds the use is authenticated
If bindDN and bindPW are specified in the configuration, the second step
will be a non anonymous bind.

View File

@ -1,29 +0,0 @@
Mail configuration
===================
SeedDMS uses email to
* notify users about changes of documents and folders
* send instructions during the password forgotten process
Configuring email in SeedDMS is simple on systems running a
local mail server, because this is the default in SeedDMS and
no additional configuration is needed. On Linux you should
consider running a local mail server, which relais the mails
to your outgoing mail server. If you cannot run a local mail
server, you can still configure SeedDMS to use an outgoing
SMTP server. Below are some examples on how to configure
SeedDMS for different hosters.
1&1
---------
smtp server: ssl://smtp.1und1.de
smtp port: 465
Gmail
---------
smtp server: ssl://smtp.gmail.com
smtp port: 465
note: since June, 2022 you will no longer be able to turn on 'Less secure app access' in your google account. Instead you need to turn on 2-Step Verification first and than
create an App Password (https://support.google.com/accounts/answer/185833)

View File

@ -106,11 +106,6 @@ op/op.ReviewDocument.php
* document was reviewed
subscribers of the document
op/op.SetReviewersApprovers.php
* Reviewers/approvers were added/deleted
subscribers of the document
uploader of version
op/op.RewindWorkflow.php
* Workflow was rewind to beginning
subscribers of the document
@ -126,28 +121,3 @@ op/op.TriggerWorkflow.php
op/op.UpdateDocument.php
* document was updated
subscribers of the document
op/op.ReceiptDocument.php
* document was received
subscribers of the document
op/op.ReviseDocument.php
* document was revised
subscribers of the document
op/op.SetRevisors.php
* Revisors were added/deleted
subscribers of the document
uploader of version
revisor
op/op.ReceiptDocument.php
* document was receipt
subscribers of the document
op/op.SetRecipients.php
* Recipients were added/deleted
subscribers of the document
uploader of version
recipient

View File

@ -1,55 +0,0 @@
# How to access the Rest API
Below are various examples on how to access the Rest API. Some of them
start by calling the `login` endpoint which creates a cookie based
session which is stored in a local file named `cookies.txt`.
The authentication is done with the user `admin`. You may use any other
user as well.
You may as well pass `-H Authorization: <api key>` instead of `-b cookies.txt`
to `curl` after setting the api key in the configuration of your SeedDMS.
Of course, in that case you will not need the initial call of the `login`
endpoint.
The examples often use the `jq` programm for formating the returned
json data.
## Initial test
The `echo` endpoint does not require any authentication.
```
#!/bin/sh
BASEURL="https://your-domain/"
curl --silent -X GET ${BASEURL}restapi/index.php/echo/test | jq '.'
```
## Getting list of users
```
#!/bin/sh
BASEURL="https://your-domain/"
curl --silent -F "user=admin" -F "pass=admin" -b cookies.txt -c cookies.txt ${BASEURL}restapi/index.php/login | jq
curl --silent -b cookies.txt -X GET "${BASEURL}restapi/index.php/users" | jq '.'
```
## Getting meta data of a folder
```
#!/bin/sh
BASEURL="https://your-domain/"
curl --silent -H "Authorization: <api key>" -X GET "${BASEURL}restapi/index.php/folder/1" | jq '.'
```
## Notes
Make sure to encode the data properly when using restapi functions which uses
put. If you use curl with PHP, then encode the data as the following
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));

View File

@ -1,26 +0,0 @@
Scheduler
==========
The scheduler in SeedDMS manages frequently run tasks. It is very similar
to regular unix cron jobs. A task in SeedDMS is an instanciation of a task
class which itself is defined by an extension or SeedDMS itself.
SeedDMS has some predefined classes e.g. core::expireddocs.
In order for tasks to be runnalbe, a user `cli_scheduler` must exists in
SeedDMS.
All tasks are executed by a single cronjob in the directory `utils`
> */5 * * * * /home/www-data/seeddms60x/seeddms/utils/seeddms-schedulercli --mode=run
Please keep in mind, that the php interpreter used for the cronjob may be
different from the php interpreter used für the web application. Hence, two
different php.ini files might be used. php and the php extensions may differ as
well. This can cause some extensions to be disabled and consequently some task
classes are not defined.
`utils/seeddms-schedulercli` can also be run on the command line. If you
do that, run it with the same system user used for the web server. On Debian
this is www-data. Hence run it like
sudo -u www-data utils/seeddms-schedulercli --mode=list

View File

@ -1,23 +0,0 @@
Swagger
========
Swagger is used to describe a rest api. SeedDMS ships a swagger.yaml file
in the restapi directory. You can load this file into a swagger editor, e.g.
http://petstore.swagger.io/ or http://editor.swagger.io/
You may as well set up your own swagger-ui installation as described at
https://medium.com/@tatianaensslin/how-to-add-swagger-ui-to-php-server-code-f1610c01dc03
Your apache needs to have the module `header` enabled, because some HTTP headers
are set when the file `swagger.yaml` is accessed by the editor.
Currently, the swagger.yaml shipped with SeedDMS uses still swagger 2.0
If you are using php-fpm you will have to ensure that files with
extension .yaml are allowed to be parsed. Extend the
`security.limit_extensions` in the pool configuration by `.yaml`. Also
check the contents of the file `.htaccess` in directory `restapi`. It
by default sets the handler for php to `application/x-httpd-php` which
uses the apache module of php. If you would like to use php-fpm
instead, then set it to
SetHandler "proxy:unix:/var/run/php/php8.2-fpm.sock|fcgi://localhost/"

View File

@ -1,5 +1,5 @@
WebDAV
========
-----------------------------------------------
SeedDMS has support for WebDAV which allows to easily add, delete,
move, copy and modify documents. All operating systems have support
@ -29,7 +29,7 @@ the content of document or creating a new
version if a document is saved.
Configuring davfs2
-------------------
===================
On Linux it is quite simple to mount the SeedDMS WebDAV server with
davfs2. Just place a line like the following in your /etc/fstab
@ -51,14 +51,15 @@ and possibly add your login data to /etc/davfs2/secrets
/media/webdav admin secret
Making applications work with WebDAV
-------------------------------------
=====================================
Various programms have differnt strategies to save files to disc and
prevent data lost under all circumstances. Those strategies often don't
work very well an a WebDAV-Server. The following will list some of those
strategies.
### VIM
VIM
=========================
vim does a lot more than just reading and writing the file you want
to edit. It creates swap and backup files for data recovery if vim crashes
@ -68,7 +69,7 @@ swap file at all or create it outside the WebDAV server. A second problem
arises from how vim modifіes the file you are editing. Before a file
is saved a backup is created by renaming the file to the same name with a
'~' at the end and writing the file content into a new
file with the name of the original file. Afterwards vim deletes the backup
file with the name of the original file. Afterwards vim deleteѕ the backup
file. On a regular file system you
won't see a difference between the file before and after saving, though
it is actually a new one. In SeedDMS you won't notice a difference either
@ -87,17 +88,12 @@ set nobackup
set nowritebackup
set noswapfile
If you want to restrict the settings to the directory where the dms
is mounted by webdav, e.g. /media/webdav, you can set an auto command
in .vimrc
autocmd BufNewFile,BufRead /media/webdav/* set nobackup nowritebackup noswapfile
Creating the backup file in a directory outside of WebDAV doesn't help in
this case, because it still does the file renaming which is turned off by
this case, because it still does the file renaming which is turned of by
'nowritebackup'.
### cdaver
cdaver
========
cadaver is a webdav client similar to classical command line based ftp clients.
It can be used to browse through the folders, downloads and uploads files, and

View File

@ -1,59 +0,0 @@
OCR
====
SeedDMS itself has no support for optical character recognition (OCR)
because it does not care about the content of file. Though, external
OCR software can be used to convert an image into text and index it
by the full text search engine.
The following script can be use to convert a scanned image into pdf
with a text layer added. The script actually takes this file to
ran it through pdftotext. It was published in the seeddms forum
https://sourceforge.net/p/seeddms/discussion/general/thread/4ec5973d/
#!/bin/bash
inputpdf=$1
temp_folder=/tmp/seedinput/$(date +"%Y_%m_%d_%H%M%S")/
lockfile=/tmp/seed
protokolldatei=./tesser_syslog
cores=2
mkdir -p $lockfile
while [ -e "$lockfile"/"`basename $0`" ];
do
sleep 5
done
if ( set -o noclobber; echo "locked" > "$lockfile"/"`basename $0`"); then
trap 'rm -f "$lockfile"/"`basename $0`"; echo $(date) " Lockdatei wird geloescht: " $lockfile"/"`basename $0` Aufrufparameter: $* >> $protokolldatei ;rm -r $temp_folder; exit $?' INT TERM KILL EXIT
#das Datum mit dem Scriptnamen in die Protokolldatei schreiben
echo $(date) " Lockdatei erstellt: " $lockfile"/"`basename $0` >> $protokolldatei
else
#Script beenden falls Lockdatei nicht erstellt werden konnte
echo $(date) " Programm wird beendet, Lockdatei konnte nicht erstellt werden: $lockfile"/"`basename $0` Aufrufparameter: $* " >> $protokolldatei
exit 1
fi
mkdir -p $temp_folder
$(pdftotext -raw $1 - 1> $temp_folder''tmp.txt )
pdf_contents=`cat $temp_folder''tmp.txt`
pdf_contents=`echo "$pdf_contents" | tr -dc '[:print:]'`
if [ -z "$pdf_contents" ]; then
convert -density 300 -quality 95 $inputpdf +adjoin $temp_folder''image%03d.jpg
find $temp_folder -name '*.jpg'| parallel --gnu -j $cores tesseract -l deu --psm 6 {} {} pdf
num=`find $temp_folder -name '*.pdf'| wc -l`
if [ "$num" -gt "1" ]; then
pdfunite $temp_folder*.pdf $temp_folder''tmp.pdf
else
mv $temp_folder*.pdf $temp_folder''tmp.pdf
fi
pdftotext $temp_folder''tmp.pdf $temp_folder''tmp.txt
mv $temp_folder''tmp.pdf $1
fi
cat $temp_folder''tmp.txt

View File

@ -183,13 +183,10 @@ class SeedDMS_ExtExample_Task extends SeedDMS_SchedulerTaskBase {
* Run the task
*
* @param $task task to be executed
* @param $dms dms
* @return boolean true if task was executed succesfully, otherwise false
*/
public function execute($task) {
$dms = $this->dms;
$user = $this->user;
$settings = $this->settings;
$logger = $this->logger;
public function execute($task, $dms, $user) {
$taskparams = $task->getParameter();
return true;
}

View File

@ -2,7 +2,7 @@
$EXT_CONF['example'] = array(
'title' => 'Example Extension',
'description' => 'This sample extension demonstrates the use of various hooks',
'disable' => true,
'disable' => false,
'version' => '1.0.1',
'releasedate' => '2018-03-21',
'author' => array('name'=>'Uwe Steinmann', 'email'=>'uwe@steinmann.cx', 'company'=>'MMK GmbH'),

View File

@ -12,6 +12,9 @@
* @version Release: @package_version@
*/
require_once("inc.Utils.php");
require_once("inc.ClassNotificationService.php");
require_once("inc.ClassEmailNotify.php");
require_once("inc.ClassSession.php");
require_once("inc.ClassAccessOperation.php");
@ -107,6 +110,8 @@ if($settings->_useHomeAsRootFolder && !$user->isAdmin() && $user->getHomeFolder(
$role = $user->getRole();
$dms->noReadForStatus = $role->getNoAccess();
require_once('inc/inc.Notification.php');
/* Include additional language file for view
* This file must set $LANG[xx][]
*/
@ -122,7 +127,7 @@ if($isajax)
* to be changed redirect to out/out.ForcePasswordChange.php. Do this
* check only if password expiration is turned on, we are not on the
* page to change the password or the page that changes the password, the
* current user is not admin, and no user substitution has occured. */
* current user is not admin, and no user substiation has occured. */
if (!$user->isAdmin() && $origuser == null) {
if($settings->_passwordExpiration > 0) {
@ -153,5 +158,6 @@ if($settings->_enable2FactorAuthentication && $settings->_guestID != $user->getI
/* Update cookie lifetime */
if($settings->_cookieLifetime) {
$lifetime = time() + intval($settings->_cookieLifetime);
setcookie("mydms_session", $dms_session, $lifetime, $settings->_httpRoot, null, false, true);
/* Turn off http only cookies if jumploader is enabled */
setcookie("mydms_session", $dms_session, $lifetime, $settings->_httpRoot, null, null, !$settings->_enableLargeFileUpload);
}

View File

@ -1,42 +0,0 @@
<?php
/**
* Create authentication service
*
* @category DMS
* @package SeedDMS
* @license GPL 2
* @version @version@
* @author Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2002-2005 Markus Westphal,
* 2006-2008 Malcolm Cowe, 2010-2022 Uwe Steinmann
* @version Release: @package_version@
*/
require_once('inc.ClassAuthenticationService.php');
require_once('inc.ClassDbAuthentication.php');
require_once('inc.ClassLdapAuthentication.php');
global $logger;
$authenticator = new SeedDMS_AuthenticationService($logger, $settings);
if(isset($GLOBALS['SEEDDMS_HOOKS']['authentication'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['authentication'] as $authenticationObj) {
if(method_exists($authenticationObj, 'preAddService')) {
$authenticationObj->preAddService($dms, $authenticator);
}
}
}
$authenticator->addService(new SeedDMS_DbAuthentication($dms, $settings), 'db');
if(isset($settings->_ldapHost) && strlen($settings->_ldapHost)>0) {
$authenticator->addService(new SeedDMS_LdapAuthentication($dms, $settings), 'ldap');
}
if(isset($GLOBALS['SEEDDMS_HOOKS']['authentication'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['authentication'] as $authenticationObj) {
if(method_exists($authenticationObj, 'postAddService')) {
$authenticationObj->postAddService($dms, $authenticator);
}
}
}

View File

@ -18,13 +18,53 @@ require_once("inc.ClassEmailNotify.php");
require_once("inc.ClassSession.php");
require_once("inc.ClassAccessOperation.php");
function __authenticate($username, $password) { /* {{{ */
global $dms, $settings;
$user = false;
/* Authenticate against LDAP server {{{ */
if (!$user && isset($settings->_ldapHost) && strlen($settings->_ldapHost)>0) {
require_once("../inc/inc.ClassLdapAuthentication.php");
$authobj = new SeedDMS_LdapAuthentication($dms, $settings);
$user = $authobj->authenticate($username, $password);
} /* }}} */
/* Authenticate against SeedDMS database {{{ */
else {
require_once("../inc/inc.ClassDbAuthentication.php");
$authobj = new SeedDMS_DbAuthentication($dms, $settings);
$user = $authobj->authenticate($username, $password);
} /* }}} */
if (!$user) {
return false;
}
if (($user->getID() == $settings->_guestID) && (!$settings->_enableGuestLogin)) {
return false;
}
// Check if account is disabled
if($user->isDisabled()) {
return false;
}
// control admin IP address if required
if ($user->isAdmin() && ($_SERVER['REMOTE_ADDR'] != $settings->_adminIP ) && ( $settings->_adminIP != "") ){
return false;
}
return $user;
} /* }}} */
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="'.$settings->_siteName.'"');
header('HTTP/1.0 401 Unauthorized');
echo getMLText('cancel_basic_authentication');
exit;
} else {
if(!($user = $authenticator->authenticate($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']))) {
if(!($user = __authenticate($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']))) {
header('WWW-Authenticate: Basic realm="'.$settings->_siteName.'"');
header('HTTP/1.0 401 Unauthorized');
echo getMLText('cancel_basic_authentication');
@ -36,6 +76,8 @@ if (!isset($_SERVER['PHP_AUTH_USER'])) {
$user->clearLoginFailures();
$dms->setUser($user);
require_once('inc/inc.Notification.php');
$notifier = new SeedDMS_NotificationService();
if($settings->_enableEmail) {
$notifier->addService(new SeedDMS_EmailNotify($dms));
}

View File

@ -47,113 +47,10 @@ class SeedDMS_AccessOperation {
*/
private $_aro;
/**
* @var array $legacy_access list of objects with access use for view and controller
* @access protected
*/
private $legacy_access;
function __construct($dms, $user, $settings) { /* {{{ */
$this->dms = $dms;
$this->user = $user;
$this->settings = $settings;
$this->legacy_access['guest'] = array(
'Calendar',
'Download',
'ErrorDlg',
'Help',
'Login',
'Search',
'ViewDocument',
'ViewFolder',
'ViewOnline',
);
$this->legacy_access['user'] = array(
'AddDocument',
'AddDocumentLink',
'AddEvent',
'AddFile',
'AddSubFolder',
'AddToTransmittal',
'ApprovalSummary',
'ApproveDocument',
'Calendar',
'CategoryChooser',
'ChangePassword',
'CheckInDocument',
'CheckOutDocument',
'Clipboard',
'Dashboard',
'DocumentAccess',
'DocumentChooser',
'DocumentNotify',
'DocumentVersionDetail',
'Download',
'DropFolderChooser',
'EditAttributes',
'EditComment',
'EditDocumentFile',
'EditDocument',
'EditEvent',
'EditFolder',
'EditOnline',
'EditUserData',
'ErrorDlg',
'FolderAccess',
'FolderChooser',
'FolderNotify',
'ForcePasswordChange',
'GroupView',
'Help',
'KeywordChooser',
'Login',
'ManageNotify',
'MoveDocument',
'MoveFolder',
'MyAccount',
'MyDocuments',
'OpensearchDesc',
'OverrideContentStatus',
'PasswordForgotten',
'PasswordSend',
'ReceiptDocument',
'ReceiptSummary',
'RemoveDocumentFile',
'RemoveDocument',
'RemoveEvent',
'RemoveFolderFiles',
'RemoveFolder',
'RemoveTransmittal',
'RemoveVersion',
'RemoveWorkflowFromDocument',
'ReturnFromSubWorkflow',
'ReviewDocument',
'ReviewSummary',
'ReviseDocument',
'RevisionSummary',
'RewindWorkflow',
'RunSubWorkflow',
'Search',
'Session',
'SetExpires',
'SetRecipients',
'SetReviewersApprovers',
'SetRevisors',
'SetWorkflow',
'SubstituteUser',
'Tasks',
'TransmittalMgr',
'TriggerWorkflow',
'UpdateDocument',
'UserDefaultKeywords',
'UserImage',
'UsrView',
'ViewDocument',
'ViewEvent',
'ViewFolder',
'ViewOnline',
'WorkflowGraph',
'WorkflowSummary');
} /* }}} */
/**
@ -192,7 +89,7 @@ class SeedDMS_AccessOperation {
function mayRemoveVersion($document) { /* {{{ */
if($document->isType('document')) {
$versions = $document->getContent();
if ((($this->settings->_enableVersionDeletion && ($document->getAccessMode($this->user, 'removeVersion') == M_ALL)) || $this->user->isAdmin() ) && (count($versions) > 1)) {
if ((($this->settings->_enableVersionDeletion && ($document->getAccessMode($this->user) == M_ALL)) || $this->user->isAdmin() ) && (count($versions) > 1)) {
return true;
}
}
@ -311,8 +208,7 @@ class SeedDMS_AccessOperation {
if($document->isType('document')) {
if($latestContent = $document->getLatestContent()) {
$workflow = $latestContent->getWorkflow();
$workflowstate = $latestContent->getWorkflowState();
if ((($this->settings->_enableVersionModification && ($document->getAccessMode($this->user) == M_ALL)) || $this->user->isAdmin()) && (!$workflow || ($workflowstate && ($workflow->getInitState()->getID() == $workflowstate->getID())))) {
if ((($this->settings->_enableVersionModification && ($document->getAccessMode($this->user) == M_ALL)) || $this->user->isAdmin()) && (!$workflow || ($workflow->getInitState()->getID() == $latestContent->getWorkflowState()->getID()))) {
return true;
}
}
@ -343,14 +239,12 @@ class SeedDMS_AccessOperation {
*
* This check can only be done for documents. Setting the documents
* comment date is only allowed if version modification is turned on in
* the settings and the document has not been obsoleted or expired.
* the settings and the document has not been obsoleted.
* The admin may set the comment even if is
* disallowed in the settings.
*/
function mayEditComment($document) { /* {{{ */
if($document->isType('document')) {
if($document->getAccessMode($this->user) < M_READWRITE)
return false;
if($document->isLocked()) {
$lockingUser = $document->getLockingUser();
if (($lockingUser->getID() != $this->user->getID()) && ($document->getAccessMode($this->user) != M_ALL)) {
@ -359,7 +253,7 @@ class SeedDMS_AccessOperation {
}
if($latestContent = $document->getLatestContent()) {
$status = $latestContent->getStatus();
if (($this->settings->_enableVersionModification || $this->user->isAdmin()) && !in_array($status["status"], array(S_OBSOLETE, S_EXPIRED))) {
if ((($this->settings->_enableVersionModification && ($document->getAccessMode($this->user) >= M_READWRITE)) || $this->user->isAdmin()) && ($status["status"]!=S_OBSOLETE)) {
return true;
}
}
@ -372,18 +266,16 @@ class SeedDMS_AccessOperation {
*
* Setting the object attributes
* is only allowed if version modification is turned on in
* the settings or the document is still in an approval/review
* or intial workflow step.
* the settings and the document has not been obsoleted.
* The admin may set the comment even if is
* disallowed in the settings.
*/
function mayEditAttributes($document) { /* {{{ */
if($document->isType('document')) {
if($latestContent = $document->getLatestContent()) {
$status = $latestContent->getStatus();
$workflow = $latestContent->getWorkflow();
$workflowstate = $latestContent->getWorkflowState();
if($document->getAccessMode($this->user) < M_READWRITE)
return false;
if ($this->settings->_enableVersionModification || in_array($status["status"], array(S_DRAFT_REV, S_DRAFT_APP, S_IN_REVISION)) || ($workflow && $workflowstate && $workflow->getInitState()->getID() == $workflowstate->getID())) {
if ((($this->settings->_enableVersionModification && ($document->getAccessMode($this->user) >= M_READWRITE)) || $this->user->isAdmin()) && (in_array($status["status"], array(S_DRAFT_REV, S_DRAFT_APP, S_IN_REVISION)) || ($workflow && $workflow->getInitState()->getID() == $latestContent->getWorkflowState()->getID()))) {
return true;
}
}
@ -514,30 +406,6 @@ class SeedDMS_AccessOperation {
return false;
} /* }}} */
/**
* Check if document content may be checked in
*
*
*/
function mayCheckIn($document) { /* {{{ */
if($document->isType('document')) {
$checkoutinfo = $document->getCheckOutInfo();
if(!$checkoutinfo)
return false;
$info = $checkoutinfo[0];
if($this->user->getID() == $info['userID'] || $document->getAccessMode($this->user) == M_ALL) {
return true;
}
}
return false;
} /* }}} */
public function allowLegacyAccess($access, $role) { /* {{{ */
if($role == 'user' || $role == 'guest') {
$this->legacy_access[$role][] = $access;
}
} /* }}} */
protected function check_view_legacy_access($view, $get=array()) { /* {{{ */
if($this->user->isAdmin())
return true;
@ -553,35 +421,98 @@ class SeedDMS_AccessOperation {
}
if($this->user->isGuest()) {
$user_allowed = $this->legacy_access['guest'];
$user_allowed = array(
'Calendar',
'ErrorDlg',
'Help',
'Login',
'Search',
'ViewDocument',
'ViewFolder',
);
} else {
$user_allowed = $this->legacy_access['user'];
}
if(array_intersect($scripts, $user_allowed))
return true;
return false;
} /* }}} */
protected function check_controller_legacy_access($controller, $get=array()) { /* {{{ */
if($this->user->isAdmin())
return true;
if(is_string($controller)) {
$scripts = array($controller);
} elseif(is_array($controller)) {
$scripts = $controller;
} elseif(is_subclass_of($controller, 'SeedDMS_Controller_Common')) {
$scripts = array($controller->getParam('class'));
} else {
return false;
}
if($this->user->isGuest()) {
$user_allowed = $this->legacy_access['guest'];
} else {
$user_allowed = $this->legacy_access['user'];
$user_allowed = array(
'AddDocument',
'AddDocumentLink',
'AddEvent',
'AddFile',
'AddSubFolder',
'AddToTransmittal',
'ApprovalSummary',
'ApproveDocument',
'Calendar',
'CategoryChooser',
'ChangePassword',
'CheckInDocument',
'Clipboard',
'DocumentAccess',
'DocumentChooser',
'DocumentNotify',
'DocumentVersionDetail',
'DropFolderChooser',
'EditAttributes',
'EditComment',
'EditDocumentFile',
'EditDocument',
'EditEvent',
'EditFolder',
'EditOnline',
'EditUserData',
'ErrorDlg',
'FolderAccess',
'FolderChooser',
'FolderNotify',
'ForcePasswordChange',
'GroupView',
'Help',
'KeywordChooser',
'Login',
'ManageNotify',
'MoveDocument',
'MoveFolder',
'MyAccount',
'MyDocuments',
'OpensearchDesc',
'OverrideContentStatus',
'PasswordForgotten',
'PasswordSend',
'ReceiptDocument',
'ReceiptSummary',
'RemoveDocumentFile',
'RemoveDocument',
'RemoveEvent',
'RemoveFolderFiles',
'RemoveFolder',
'RemoveTransmittal',
'RemoveVersion',
'RemoveWorkflowFromDocument',
'ReturnFromSubWorkflow',
'ReviewDocument',
'ReviewSummary',
'ReviseDocument',
'RevisionSummary',
'RewindWorkflow',
'RunSubWorkflow',
'Search',
'Session',
'SetExpires',
'SetRecipients',
'SetReviewersApprovers',
'SetRevisors',
'SetWorkflow',
'SubstituteUser',
'Tasks',
'TransmittalMgr',
'TriggerWorkflow',
'UpdateDocument',
'UserDefaultKeywords',
'UserImage',
'UsrView',
'ViewDocument',
'ViewEvent',
'ViewFolder',
'WorkflowGraph',
'WorkflowSummary');
}
if(array_intersect($scripts, $user_allowed))
@ -649,8 +580,6 @@ class SeedDMS_AccessOperation {
*/
function check_controller_access($controller, $get=array()) { /* {{{ */
if(!$this->settings->_advancedAcl) {
return $this->check_controller_legacy_access($controller, $get);
/*
if($this->user->isGuest())
return false;
elseif($this->user->isAdmin())
@ -660,7 +589,6 @@ class SeedDMS_AccessOperation {
return false;
return true;
}
*/
}
if(is_string($controller)) {
$scripts = array($controller);

View File

@ -163,7 +163,7 @@ class SeedDMS_AroAco { /* {{{ */
* @return object instance of SeedDMS_Aco
*/
function __construct($dms, $id, $parent, $object, $alias) { /* {{{ */
$this->_dms = $dms;
$this->_dmѕ = $dms;
$this->_id = $id;
$this->_parent = $parent;
$this->_object = $object;

View File

@ -4,11 +4,11 @@
*
* @category DMS
* @package SeedDMS
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright 2010-2016 Uwe Steinmann
* @license GPL 2
* @version @package_version@
* @link https://www.seeddms.org
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2010-2016 Uwe Steinmann
* @version Release: @package_version@
*/
/**
@ -17,13 +17,27 @@
* @category DMS
* @package SeedDMS
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright 2010-2016 Uwe Steinmann
* @license GPL 2
* @copyright Copyright (C) 2010-2016 Uwe Steinmann
* @version Release: @package_version@
* @link https://www.seeddms.org
*/
abstract class SeedDMS_Authentication
{
abstract class SeedDMS_Authentication {
/**
* @var object $dms object of dms
* @access protected
*/
private $dms;
/**
* @var object $settings SeedDMS Settings
* @access protected
*/
private $settings;
function __construct($dms, $settings) { /* {{{ */
$this->dms = $dms;
$this->settings = $settings;
} /* }}} */
/**
* Do Authentication
*
@ -31,11 +45,9 @@ abstract class SeedDMS_Authentication
* the user object otherwise false must be returned. If authentication fails
* the number of failed logins should be incremented and account disabled.
*
* @param string $username name of user to authenticate
* @param string $password password of user to authenticate
*
* @return object|false user object if authentication was successful
* otherwise false
* @param string $username
* @param string $password
* @return object|boolean user object if authentication was successful otherwise false
*/
abstract function authenticate($username, $password);
}

View File

@ -1,108 +0,0 @@
<?php
/**
* MyDMS. Document Management System
* Copyright (C) 2002-2005 Markus Westphal
* Copyright (C) 2006-2008 Malcolm Cowe
* Copyright (C) 2010 Matteo Lucarelli
* Copyright (C) 2010-2024 Uwe Steinmann
*
* PHP version 8
*
* 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.
*
* @category SeedDMS
* @package SeedDMS
* @author Uwe Steinmann <info@seeddms.org>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://www.seeddms.org Main Site
*/
/* Middleware for authentication based on session */
class SeedDMS_Auth_Middleware_Session { /* {{{ */
private $container;
public function __construct($container) {
$this->container = $container;
}
/**
* Example middleware invokable class
*
* @param \Psr\Http\Message\ServerRequestInterface $request PSR7 request
* @param \Psr\Http\Message\ResponseInterface $response PSR7 response
* @param callable $next Next middleware
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function __invoke($request, $handler) {
// $this->container has the DI
$dms = $this->container->get('dms');
$settings = $this->container->get('config');
$logger = $this->container->get('logger');
$userobj = null;
if ($this->container->has('userobj')) {
$userobj = $this->container->get('userobj');
}
if ($userobj) {
$response = $handler->handle($request);
return $response;
}
$logger->log("Invoke middleware for method " . $request->getMethod() . " on '" . $request->getUri()->getPath() . "'", PEAR_LOG_INFO);
require_once("inc/inc.ClassSession.php");
$session = new SeedDMS_Session($dms->getDb());
if (isset($_COOKIE["mydms_session"])) {
$dms_session = $_COOKIE["mydms_session"];
$logger->log("Session key: " . $dms_session, PEAR_LOG_DEBUG);
if (!$resArr = $session->load($dms_session)) {
/* Delete Cookie */
setcookie("mydms_session", $dms_session, time() - 3600, $settings->_httpRoot);
$logger->log("Session for id '" . $dms_session . "' has gone", PEAR_LOG_ERR);
return $response->withStatus(403);
}
/* Load user data */
$userobj = $dms->getUser($resArr["userID"]);
if (!is_object($userobj)) {
/* Delete Cookie */
setcookie("mydms_session", $dms_session, time() - 3600, $settings->_httpRoot);
if ($settings->_enableGuestLogin) {
if (!($userobj = $dms->getUser($settings->_guestID))) {
return $response->withStatus(403);
}
} else {
return $response->withStatus(403);
}
}
if ($userobj->isAdmin()) {
if ($resArr["su"]) {
if (!($userobj = $dms->getUser($resArr["su"]))) {
return $response->withStatus(403);
}
}
}
$dms->setUser($userobj);
} else {
return $response->withStatus(403);
}
$this->container->set('userobj', $userobj);
$response = $handler->handle($request);
return $response;
}
} /* }}} */

View File

@ -1,102 +0,0 @@
<?php
/**
* Implementation of authentication service
*
* @category DMS
* @package SeedDMS
* @license GPL 2
* @version @version@
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2016 Uwe Steinmann
* @version Release: @package_version@
*/
/**
* Implementation of authentication service
*
* @category DMS
* @package SeedDMS
* @author Uwe Steinmann <uwe@steinmann.cx>
* @copyright Copyright (C) 2016 Uwe Steinmann
* @version Release: @package_version@
*/
class SeedDMS_AuthenticationService {
/**
* List of services for authenticating user
*/
protected $services;
/*
* List of servives with errors
*/
protected $errors;
/*
* Service for logging
*/
protected $logger;
/*
* Configuration
*/
protected $settings;
public function __construct($logger = null, $settings = null) { /* {{{ */
$this->services = array();
$this->errors = array();
$this->logger = $logger;
$this->settings = $settings;
} /* }}} */
public function addService($service, $name='') { /* {{{ */
if(!$name)
$name = md5(uniqid());
$this->services[$name] = $service;
$this->errors[$name] = true;
} /* }}} */
public function getServices() { /* {{{ */
return $this->services;
} /* }}} */
public function getErrors() { /* {{{ */
return $this->errors;
} /* }}} */
/**
* Run each authentication service
*
* This method calls authenticate() of each authentication service and
* evaluates the returned value.
* If the authentication method returns false (some internal error which
* prevented to check authentication at all), this method will return
* false imediately, in case of null (no valid authentication) the next
* service will be tried and in all other cases the value will be returned.
*
* @param string $username name of user
* @param string $password password of user
*/
public function authenticate($username, $password) { /* {{{ */
$user = null;
foreach($this->services as $name => $service) {
if($this->logger)
$this->logger->log('Authentication service \''.$name.'\'', PEAR_LOG_INFO);
$user = $service->authenticate($username, $password);
if($user === false) {
$this->errors[$name] = false;
if($this->logger)
$this->logger->log('Authentication service \''.$name.'\': Authentication of user \''.$username.'\' failed.', PEAR_LOG_ERR);
return false;
} elseif($user === null) {
if($this->logger)
$this->logger->log('Authentication service \''.$name.'\': Authentication of user \''.$username.'\' disregarded.', PEAR_LOG_ERR);
} else {
if($this->logger)
$this->logger->log('Authentication service \''.$name.'\': Authentication of user \''.$username.'\' successful.', PEAR_LOG_INFO);
$this->errors[$name] = true;
return $user;
}
}
return $user;
} /* }}} */
}

View File

@ -33,60 +33,36 @@ class SeedDMS_Calendar {
*/
protected $db;
/**
* Instanz of user
*/
protected $user;
public function __construct($db, $user) { /* {{{ */
function __construct($db, $user) {
$this->db = $db;
$this->user = $user;
} /* }}} */
}
public function setUser($user) { /* {{{ */
$this->user = $user;
} /* }}} */
public function getUser() { /* {{{ */
return $this->user;
} /* }}} */
public function getEvents($day, $month, $year) { /* {{{ */
function getEvents($day, $month, $year) { /* {{{ */
$date = mktime(12,0,0, $month, $day, $year);
$queryStr = "SELECT * FROM `tblEvents` WHERE `start` <= " . $date . " AND `stop` >= " . $date;
if(!$this->user->isAdmin()) {
$queryStr .= " AND `userID`=".$this->user->getID();
}
$ret = $this->db->getResultArray($queryStr);
return $ret;
} /* }}} */
public function getEventsInInterval($start, $stop) { /* {{{ */
$queryStr = "SELECT * FROM `tblEvents` WHERE (( `start` <= " . (int) $start . " AND `stop` >= " . (int) $start . " ) ".
function getEventsInInterval($start, $stop) { /* {{{ */
$queryStr = "SELECT * FROM `tblEvents` WHERE ( `start` <= " . (int) $start . " AND `stop` >= " . (int) $start . " ) ".
"OR ( `start` <= " . (int) $stop . " AND `stop` >= " . (int) $stop . " ) ".
"OR ( `start` >= " . (int) $start . " AND `stop` <= " . (int) $stop . " ))";
if(!$this->user->isAdmin()) {
$queryStr .= " AND `userID`=".$this->user->getID();
}
"OR ( `start` >= " . (int) $start . " AND `stop` <= " . (int) $stop . " )";
$ret = $this->db->getResultArray($queryStr);
return $ret;
} /* }}} */
public function addEvent($from, $to, $name, $comment ) { /* {{{ */
function addEvent($from, $to, $name, $comment ) { /* {{{ */
$queryStr = "INSERT INTO `tblEvents` (`name`, `comment`, `start`, `stop`, `date`, `userID`) VALUES ".
"(".$this->db->qstr($name).", ".$this->db->qstr($comment).", ".(int) $from.", ".(int) $to.", ".$this->db->getCurrentTimestamp().", ".$this->user->getID().")";
$ret = $this->db->getResult($queryStr);
if (!$ret)
return false;
$event = $this->getEvent((int) $this->db->getInsertID('tblEvents'));
return $event;
return $ret;
} /* }}} */
public function getEvent($id) { /* {{{ */
function getEvent($id) { /* {{{ */
if (!is_numeric($id)) return false;
$queryStr = "SELECT * FROM `tblEvents` WHERE `id` = " . (int) $id;
@ -98,7 +74,7 @@ class SeedDMS_Calendar {
return $ret[0];
} /* }}} */
public function editEvent($id, $from, $to=null, $name=null, $comment=null) { /* {{{ */
function editEvent($id, $from, $to=null, $name=null, $comment=null) { /* {{{ */
if (!is_numeric($id)) return false;
$queryStr = "UPDATE `tblEvents` SET `start` = " . (int) $from . ($to !== null ? ", `stop` = " . (int) $to : '') . ($name !== null ? ", `name` = " . $this->db->qstr($name) : '') . ($comment !== null ? ", `comment` = " . $this->db->qstr($comment) : '') . ", `date` = " . $this->db->getCurrentTimestamp() . " WHERE `id` = ". (int) $id;
@ -106,7 +82,7 @@ class SeedDMS_Calendar {
return $ret;
} /* }}} */
public function delEvent($id) { /* {{{ */
function delEvent($id) { /* {{{ */
if (!is_numeric($id)) return false;
$queryStr = "DELETE FROM `tblEvents` WHERE `id` = " . (int) $id;

Some files were not shown because too many files have changed in this diff Show More