diff --git a/ccm-docrepo/CHANGELOG b/ccm-docrepo/CHANGELOG new file mode 100644 index 000000000..89ba7cf3c --- /dev/null +++ b/ccm-docrepo/CHANGELOG @@ -0,0 +1,10 @@ +April 14, 2011 + +Package ccm-docmgr from Byline repository copied and integrated in ccm/aplaws +as an test environment. +This "old" docmgr worked nearly out of the box (in contrast to "new" docmgr. + +Plan: Integrate "old" docmgr as a simple doc repository for files. To distinguish +it from the advanced version provided by Magpie (which is based on the old code +but heavily extended) it should be renamed to ccm-docrepo or +ccm-filerepository / ccm-documentrepository \ No newline at end of file diff --git a/ccm-docrepo/application.xml b/ccm-docrepo/application.xml new file mode 100644 index 000000000..3ae958a09 --- /dev/null +++ b/ccm-docrepo/application.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + diff --git a/ccm-docrepo/doc/package.html b/ccm-docrepo/doc/package.html new file mode 100644 index 000000000..6b6a107e0 --- /dev/null +++ b/ccm-docrepo/doc/package.html @@ -0,0 +1,17 @@ + + + +com.arsdigita.docrepo + + + +

+The document repository is an online file storage system for collaborative +file sharing within groups. + +

+ + + + + diff --git a/ccm-docrepo/etc/enterprise.init.in b/ccm-docrepo/etc/enterprise.init.in new file mode 100644 index 000000000..89eb21c1a --- /dev/null +++ b/ccm-docrepo/etc/enterprise.init.in @@ -0,0 +1 @@ +init com.arsdigita.docrepo.installer.Initializer { } diff --git a/ccm-docrepo/pdl/com/arsdigita/docrepo/DocBlobject.pdl b/ccm-docrepo/pdl/com/arsdigita/docrepo/DocBlobject.pdl new file mode 100644 index 000000000..bfb87b12d --- /dev/null +++ b/ccm-docrepo/pdl/com/arsdigita/docrepo/DocBlobject.pdl @@ -0,0 +1,29 @@ +// +// Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// $Id: docrepo/DocBlobject.pdl $ +// $DateTime: 2004/08/17 23:26:27 $ +model com.arsdigita.docrepo; + + +object type DocBlobject { + BigDecimal id = dr_blobjects.content_id; + Blob content = dr_blobjects.content BLOB; + + object key (id); +} + diff --git a/ccm-docrepo/pdl/com/arsdigita/docrepo/File.pdl b/ccm-docrepo/pdl/com/arsdigita/docrepo/File.pdl new file mode 100644 index 000000000..8d5179697 --- /dev/null +++ b/ccm-docrepo/pdl/com/arsdigita/docrepo/File.pdl @@ -0,0 +1,57 @@ +// +// Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// $Id: docrepo/File.pdl $ +model com.arsdigita.docrepo; + +import com.arsdigita.kernel.*; + +// Note that content retrieval and insert are factored out as separate +// events to speed up loading the meta-data only. + +object type File extends ResourceImpl { + // Doesn't need anything that isn't already in ResourceImpl +} + +query getFileRevisionBlob { + Blob content; + do { + select + value + from + vcx_txns tx, + vcx_tags tg, + vcx_obj_changes ch, + vcx_operations op, + vcx_blob_operations bo + where + tx.id = ch.txn_id + and tg.txn_id = tx.id + and ch.id = op.change_id + and op.id = bo.id + and tx.id = (select min(tx2.id) + from vcx_txns tx2 + where tx2.id > :transactionID + and exists (select 1 + from vcx_tags tg2 + where tg2.txn_id = tx2.id + and tg2.tagged_oid = tg.tagged_oid)) + and op.attribute = 'content' + } map { + content = value; + } +} diff --git a/ccm-docrepo/pdl/com/arsdigita/docrepo/Folder.pdl b/ccm-docrepo/pdl/com/arsdigita/docrepo/Folder.pdl new file mode 100644 index 000000000..5691ec59b --- /dev/null +++ b/ccm-docrepo/pdl/com/arsdigita/docrepo/Folder.pdl @@ -0,0 +1,27 @@ +// +// Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// $Id: docrepo/Folder.pdl $ +model com.arsdigita.docrepo; + +object type Folder extends ResourceImpl { + + // Current implementation does not require any extensions to + // ResourceImpl + +} + diff --git a/ccm-docrepo/pdl/com/arsdigita/docrepo/RecentUpdatedDocsPortlet.pdl b/ccm-docrepo/pdl/com/arsdigita/docrepo/RecentUpdatedDocsPortlet.pdl new file mode 100644 index 000000000..5cf439c04 --- /dev/null +++ b/ccm-docrepo/pdl/com/arsdigita/docrepo/RecentUpdatedDocsPortlet.pdl @@ -0,0 +1,25 @@ +// +// Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// $Id: docrepo/RecentUpdatedDocsPortlet.pdl#5 $ +model com.arsdigita.docrepo.ui; + +import com.arsdigita.portal.Portlet; + +object type RecentUpdatedDocsPortlet extends Portlet { + // Empty +} diff --git a/ccm-docrepo/pdl/com/arsdigita/docrepo/Repository.pdl b/ccm-docrepo/pdl/com/arsdigita/docrepo/Repository.pdl new file mode 100644 index 000000000..75befc841 --- /dev/null +++ b/ccm-docrepo/pdl/com/arsdigita/docrepo/Repository.pdl @@ -0,0 +1,68 @@ +// +// Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// $Id: docrepo/Repository.pdl pboy $ +model com.arsdigita.docrepo; + +import com.arsdigita.kernel.*; +import com.arsdigita.web.Application; + +object type Repository extends Application { + + BigDecimal rootID = dr_repositories.root_id INTEGER; + BigDecimal ownerID = dr_repositories.owner_id INTEGER; + + + reference key (dr_repositories.repository_id); +} + +data operation addUserRepositoriesMapping { + do { + insert into docs_mounted + (party_id, repository_id) + select :userID, repository_id from dr_repositories + where repository_id in :repositoryIDs + and not exists (select 1 from docs_mounted + where docs_mounted.repository_id = docs_repositories.repository_id + and docs_mounted.party_id = :userID) + } +} + +data operation removeUserRepositoriesMapping { + do { + delete from docs_mounted + where party_id = :userID + and repository_id in :repositoryIDs + } +} + + +query getRepositoryRoots { + BigDecimal id; + do { + select + d.resource_id, + from docs_resources d + where resource_id in (select docs_repositories.root_id + from docs_repositories, docs_mounted + where docs_mounted.repository_id = docs_repositories.repository_id + and docs_mounted.party_id = :userID) + } map { + id = d.resource_id; + } +} + diff --git a/ccm-docrepo/pdl/com/arsdigita/docrepo/ResourceImpl.pdl b/ccm-docrepo/pdl/com/arsdigita/docrepo/ResourceImpl.pdl new file mode 100644 index 000000000..a98d10a00 --- /dev/null +++ b/ccm-docrepo/pdl/com/arsdigita/docrepo/ResourceImpl.pdl @@ -0,0 +1,113 @@ +// +// Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// $Id: docrepo/ResourceImpl.pdl pboy $ +model com.arsdigita.docrepo; + +import com.arsdigita.versioning.*; +import com.arsdigita.kernel.*; + +object type ResourceImpl extends VersionedACSObject { + String[1..1] name = dr_resources.name VARCHAR(200); + String[0..1] description = dr_resources.description VARCHAR(4000); + Boolean[1..1] isFolder = dr_resources.is_folder CHAR(1); + String[1..1] path = dr_resources.path VARCHAR(3000); + String mimeType = dr_resources.mime_type VARCHAR(200); + BigDecimal size = dr_resources.length INTEGER; + Date[1..1] creationDate = dr_resources.creation_date TIMESTAMP; + String[0..1] creationIP = dr_resources.creation_ip VARCHAR(50); + Date[1..1] lastModifiedDate = dr_resources.last_modified TIMESTAMP; + String[0..1] lastModifiedIP = dr_resources.modifying_ip VARCHAR(50); + + reference key (dr_resources.resource_id); +} + +association { + ResourceImpl[1..1] contentResource = + join dr_blobjects.resource_id to dr_resources.resource_id; + component DocBlobject[0..1] content = + join dr_resources.resource_id to dr_blobjects.resource_id; +} + +association { + ResourceImpl[0..n] createdResources = + join users.user_id to dr_resources.creation_user; + User[0..1] creationUser = join dr_resources.creation_user to users.user_id; +} + +association { + ResourceImpl[0..n] modifiedResources = + join users.user_id to dr_resources.last_user; + User[0..1] lastModifiedUser = join dr_resources.last_user to users.user_id; +} + +association { + ResourceImpl[0..1] parent = join dr_resources.parent_id + to dr_resources.resource_id; + component ResourceImpl[0..n] immediateChildren = + join dr_resources.resource_id to dr_resources.parent_id; +} + +// Returns the direct children of a given resource + +query getDirectChildren { + BigDecimal id; + Boolean isFolder; + do { + select resource_id, + is_folder + from dr_resources + where parent_id = :parentID + } map { + id = resource_id; + isFolder = is_folder; + } +} + +// Returns a set of resources by path + +query getResourceByPath { + BigDecimal id; + Boolean isFolder; + String name; + String path; + do { + select resource_id, + name, + is_folder, + path + from dr_resources + where path = :targetPath + } map { + id = resource_id; + isFolder = is_folder; + name = name; + path = path; + } +} + + +// Update the denormalized path for every child of a given resource +data operation updateChildren { + do { + update dr_resources + set path = :rootPath || substr(path, :oldRootPathLength) + where path like :oldPath || '%' + and not resource_id = :parentResource + } +} + diff --git a/ccm-docrepo/pdl/com/arsdigita/docrepo/query-getChildren.ora.pdl b/ccm-docrepo/pdl/com/arsdigita/docrepo/query-getChildren.ora.pdl new file mode 100644 index 000000000..5b427fa8a --- /dev/null +++ b/ccm-docrepo/pdl/com/arsdigita/docrepo/query-getChildren.ora.pdl @@ -0,0 +1,69 @@ +// +// Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// $Id: docrepo/query-getChildren.ora.pdl pboy $ +model com.arsdigita.docrepo; + +// retrieve listing of resources that have a given parent + +query getChildren { + BigDecimal parentID; + String name; + String description; + Boolean isFolder; + String mimeType; + String mimeTypeDescription; + BigDecimal modifyingUser; + String modifyingIP; + Date lastModified; + BigDecimal id; + String objectType; + do { + select CASE WHEN d.parent_id is null then -1 + else d.parent_id end parent_id, + d.name, + d.description, + d.is_folder, + d.mime_type, + d.last_user, + d.modifying_ip, + d.last_modified, + m.label, + a.object_id, + a.object_type + from dr_resources d, + acs_objects a, + cms_mime_types m + where d.resource_id = a.object_id + and m.mime_type(+) = d.mime_type + and parent_id = :folderID + order by d.is_folder, d.name + } map { + parentID = parent_id; + name = d.name; + description = d.description; + isFolder = d.is_folder; + mimeType = d.mime_type; + mimeTypeDescription = m.label; + modifyingUser = d.last_user; + modifyingIP = d.modifying_ip; + lastModified = d.last_modified; + id = a.object_id; + objectType = a.object_type; + } +} + diff --git a/ccm-docrepo/pdl/com/arsdigita/docrepo/query-getChildren.pg.pdl b/ccm-docrepo/pdl/com/arsdigita/docrepo/query-getChildren.pg.pdl new file mode 100644 index 000000000..20cc4747b --- /dev/null +++ b/ccm-docrepo/pdl/com/arsdigita/docrepo/query-getChildren.pg.pdl @@ -0,0 +1,69 @@ +// +// Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// $Id: docrepo/query-getChildren.pg.pdl pboy $ +// $DateTime: 2004/08/17 23:26:27 $ +model com.arsdigita.docrepo; + +// retrieve listing of resources that have a given parent + +query getChildren { + BigDecimal parentID; + String name; + String description; + Boolean isFolder; + String mimeType; + String mimeTypeDescription; + BigDecimal modifyingUser; + String modifyingIP; + Date lastModified; + BigDecimal id; + String objectType; + do { + select CASE WHEN d.parent_id is null then -1 + else d.parent_id end as parent_id, + d.name, + d.description, + d.is_folder, + d.mime_type, + m.label, + d.last_user, + d.modifying_ip, + d.last_modified, + a.object_id, + a.object_type + from dr_resources d + left join cms_mime_types m on (d.mime_type = m.mime_type), + acs_objects a + where d.resource_id = a.object_id + and parent_id = :folderID + order by d.is_folder, d.name + } map { + parentID = parent_id; + name = d.name; + description = d.description; + isFolder = d.is_folder; + mimeType = d.mime_type; + mimeTypeDescription = m.label; + modifyingUser = d.last_user; + modifyingIP = d.modifying_ip; + lastModified = d.last_modified; + id = a.object_id; + objectType = a.object_type; + } +} + diff --git a/ccm-docrepo/pdl/com/arsdigita/docrepo/query-getRepositoriesView.ora.pdl b/ccm-docrepo/pdl/com/arsdigita/docrepo/query-getRepositoriesView.ora.pdl new file mode 100644 index 000000000..781782d3c --- /dev/null +++ b/ccm-docrepo/pdl/com/arsdigita/docrepo/query-getRepositoriesView.ora.pdl @@ -0,0 +1,46 @@ +// +// Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// $Id: docrepo/query-getRepositoriesView.ora.pdl pboy $ +model com.arsdigita.docrepo; + +query getRepositoriesView { + BigDecimal repositoryID; + BigDecimal isMounted; + BigDecimal numFiles; + do { + select distinct + dr_repositories.repository_id, + decode(dm.repository_id, null, 0, 1) mounted, + dr_repository_num_files(dr_repositories.root_id) num_files + from (select repository_id from docs_mounted where party_id = :userID) dm, + dr_repositories, + users, + group_member_map + where dm.repository_id(+) = docs_repositories.repository_id + and dr_repositories.owner_id = users.user_id + and users.user_id = group_member_map.member_id + and group_member_map.group_id in (select + group_id + from group_member_map + where member_id = :userID) + } map { + repositoryID = dr_repositories.repository_id; + isMounted = mounted; + numFiles = num_files; + } +} diff --git a/ccm-docrepo/pdl/com/arsdigita/docrepo/query-getRepositoriesView.pg.pdl b/ccm-docrepo/pdl/com/arsdigita/docrepo/query-getRepositoriesView.pg.pdl new file mode 100644 index 000000000..3a72b69ad --- /dev/null +++ b/ccm-docrepo/pdl/com/arsdigita/docrepo/query-getRepositoriesView.pg.pdl @@ -0,0 +1,47 @@ +// +// Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// $Id: docrepo/query-getRepositoriesView.pg.pdl pboy $ +model com.arsdigita.docrepo; + +query getRepositoriesView { + BigDecimal repositoryID; + BigDecimal isMounted; + BigDecimal numFiles; + do { + select distinct + dr_repositories.repository_id, + coalesce(dm.repository_id, null, 0, 1) as mounted, + dr_repository_num_files(docs_repositories.root_id) as num_files + from dr_repositories + left join (select repository_id from docs_mounted + where party_id = :userID) dm + on (dr_repositories.repository_id = dm.repository_id), + users, + group_member_map + where users.user_id = group_member_map.member_id + and dr_repositories.owner_id = users.user_id + and group_member_map.group_id in (select + group_id + from group_member_map + where member_id = :userID) + } map { + repositoryID = dr_repositories.repository_id; + isMounted = mounted; + numFiles = num_files; + } +} diff --git a/ccm-docrepo/pdl/com/arsdigita/docrepo/query-listDestinationFolders.ora.pdl b/ccm-docrepo/pdl/com/arsdigita/docrepo/query-listDestinationFolders.ora.pdl new file mode 100644 index 000000000..c499fa3ca --- /dev/null +++ b/ccm-docrepo/pdl/com/arsdigita/docrepo/query-listDestinationFolders.ora.pdl @@ -0,0 +1,49 @@ +// +// Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// $Id: docrepo/query-listDestinationFolders.ora.pdl pboy $ +model com.arsdigita.docrepo; + +// Retrieve a list of all folders in a certain repository for Copy +// or Move operations. +// This query excludes subfolders of source folders. It excludes +// all(!) children folder(s) of the selected resources (specified +// by the bind variable srcResources). +query listDestinationFolders { + String name; + String path; + BigDecimal parentID; + BigDecimal resourceID; + do { + select name, + resource_id, + path, + CASE WHEN parent_id is null then -1 + else parent_id END as parent_id + from dr_resources + where is_folder='1' + and resource_id in (select object_id from vc_objects + where is_deleted = '0') + and path like :rootPath || '%' + } map { + name = dr_resources.name; + path = dr_resources.path; + resourceID = dr_resources.resource_id; + parentID = dr_resources.parent_id; + } +} + diff --git a/ccm-docrepo/pdl/com/arsdigita/docrepo/query-listDestinationFolders.pg.pdl b/ccm-docrepo/pdl/com/arsdigita/docrepo/query-listDestinationFolders.pg.pdl new file mode 100644 index 000000000..138ab45b5 --- /dev/null +++ b/ccm-docrepo/pdl/com/arsdigita/docrepo/query-listDestinationFolders.pg.pdl @@ -0,0 +1,49 @@ +// +// Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// $Id: docrepo/query-listDestinationFolders.pg.pdl pboy $ +model com.arsdigita.docrepo; + +// Retrieve a list of all folders in a certain repository for Copy +// or Move operations. +// This query excludes subfolders of source folders. It excludes +// all(!) children folder(s) of the selected resources (specified +// by the bind variable srcResources). +query listDestinationFolders { + String name; + String path; + BigDecimal parentID; + BigDecimal resourceID; + do { + select name, + resource_id, + path, + CASE WHEN parent_id is null then (-1)::integer + else parent_id END as parent_id + from dr_resources + where is_folder='1' + and resource_id in (select object_id from vc_objects + where is_deleted = '0') + and path like :rootPath || '%' + } map { + name = dr_resources.name; + path = dr_resources.path; + resourceID = dr_resources.resource_id; + parentID = dr_resources.parent_id; + } +} + diff --git a/ccm-docrepo/sql/ccm-docrepo/default/index-dr_blobjects_resource_id_idx.sql b/ccm-docrepo/sql/ccm-docrepo/default/index-dr_blobjects_resource_id_idx.sql new file mode 100644 index 000000000..f8159f57a --- /dev/null +++ b/ccm-docrepo/sql/ccm-docrepo/default/index-dr_blobjects_resource_id_idx.sql @@ -0,0 +1,20 @@ +-- +-- Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. +-- +-- This library is free software; you can redistribute it and/or +-- modify it under the terms of the GNU Lesser General Public License +-- as published by the Free Software Foundation; either version 2.1 of +-- the License, or (at your option) any later version. +-- +-- This library 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 +-- Lesser General Public License for more details. +-- +-- You should have received a copy of the GNU Lesser General Public +-- License along with this library; if not, write to the Free Software +-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-- +-- $Id: index-dr_blobjects_resource_id_idx.sql pboy $ + +create index dr_blobjects_resource_id_idx on dr_blobjects(resource_id); diff --git a/ccm-docrepo/sql/ccm-docrepo/default/index-dr_resources_creatin_usr_idx.sql b/ccm-docrepo/sql/ccm-docrepo/default/index-dr_resources_creatin_usr_idx.sql new file mode 100644 index 000000000..9c739826e --- /dev/null +++ b/ccm-docrepo/sql/ccm-docrepo/default/index-dr_resources_creatin_usr_idx.sql @@ -0,0 +1,20 @@ +-- +-- Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. +-- +-- This library is free software; you can redistribute it and/or +-- modify it under the terms of the GNU Lesser General Public License +-- as published by the Free Software Foundation; either version 2.1 of +-- the License, or (at your option) any later version. +-- +-- This library 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 +-- Lesser General Public License for more details. +-- +-- You should have received a copy of the GNU Lesser General Public +-- License along with this library; if not, write to the Free Software +-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-- +-- $Id: index-dr_resources_creatin_usr_idx.sql pboy $ + +create index dr_resources_creatin_usr_idx on dr_resources(creation_user); diff --git a/ccm-docrepo/sql/ccm-docrepo/default/index-dr_resources_last_user_idx.sql b/ccm-docrepo/sql/ccm-docrepo/default/index-dr_resources_last_user_idx.sql new file mode 100644 index 000000000..4b14fff46 --- /dev/null +++ b/ccm-docrepo/sql/ccm-docrepo/default/index-dr_resources_last_user_idx.sql @@ -0,0 +1,20 @@ +-- +-- Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. +-- +-- This library is free software; you can redistribute it and/or +-- modify it under the terms of the GNU Lesser General Public License +-- as published by the Free Software Foundation; either version 2.1 of +-- the License, or (at your option) any later version. +-- +-- This library 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 +-- Lesser General Public License for more details. +-- +-- You should have received a copy of the GNU Lesser General Public +-- License along with this library; if not, write to the Free Software +-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-- +-- $Id: index-dr_resources_last_user_idx.sql pboy $ + +create index dr_resources_last_user_idx on dr_resources(last_user); diff --git a/ccm-docrepo/sql/ccm-docrepo/default/index-dr_resources_parent_id_idx.sql b/ccm-docrepo/sql/ccm-docrepo/default/index-dr_resources_parent_id_idx.sql new file mode 100644 index 000000000..a29b397bc --- /dev/null +++ b/ccm-docrepo/sql/ccm-docrepo/default/index-dr_resources_parent_id_idx.sql @@ -0,0 +1,20 @@ +-- +-- Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. +-- +-- This library is free software; you can redistribute it and/or +-- modify it under the terms of the GNU Lesser General Public License +-- as published by the Free Software Foundation; either version 2.1 of +-- the License, or (at your option) any later version. +-- +-- This library 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 +-- Lesser General Public License for more details. +-- +-- You should have received a copy of the GNU Lesser General Public +-- License along with this library; if not, write to the Free Software +-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-- +-- $Id: index-dr_resources_parent_id_idx.sql pboy $ + +create index dr_resources_parent_id_idx on dr_resources(parent_id); diff --git a/ccm-docrepo/sql/ccm-docrepo/oracle-se-create.sql b/ccm-docrepo/sql/ccm-docrepo/oracle-se-create.sql new file mode 100644 index 000000000..6a4cc6bc9 --- /dev/null +++ b/ccm-docrepo/sql/ccm-docrepo/oracle-se-create.sql @@ -0,0 +1,28 @@ +-- +-- Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. +-- +-- This library is free software; you can redistribute it and/or +-- modify it under the terms of the GNU Lesser General Public License +-- as published by the Free Software Foundation; either version 2.1 of +-- the License, or (at your option) any later version. +-- +-- This library 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 +-- Lesser General Public License for more details. +-- +-- You should have received a copy of the GNU Lesser General Public +-- License along with this library; if not, write to the Free Software +-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-- +-- $Id: oracle-se-create.sql pboy $ + + +@@ ddl/oracle-se/create.sql + +@@ default/index-dr_blobjects_resource_id_idx.sql +@@ default/index-dr_resources_creatin_usr_idx.sql +@@ default/index-dr_resources_last_user_idx.sql +@@ default/index-dr_resources_parent_id_idx.sql + +@@ ddl/oracle-se/deferred.sql diff --git a/ccm-docrepo/sql/ccm-docrepo/postgres-create.sql b/ccm-docrepo/sql/ccm-docrepo/postgres-create.sql new file mode 100644 index 000000000..833d5cb3c --- /dev/null +++ b/ccm-docrepo/sql/ccm-docrepo/postgres-create.sql @@ -0,0 +1,29 @@ +-- +-- Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. +-- +-- This library is free software; you can redistribute it and/or +-- modify it under the terms of the GNU Lesser General Public License +-- as published by the Free Software Foundation; either version 2.1 of +-- the License, or (at your option) any later version. +-- +-- This library 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 +-- Lesser General Public License for more details. +-- +-- You should have received a copy of the GNU Lesser General Public +-- License along with this library; if not, write to the Free Software +-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-- +-- $Id: postgres-create.sql#4 pboy $ + +begin; + +\i ddl/postgres/create.sql +\i default/index-dr_blobjects_resource_id_idx.sql +\i default/index-dr_resources_creatin_usr_idx.sql +\i default/index-dr_resources_last_user_idx.sql +\i default/index-dr_resources_parent_id_idx.sql +\i ddl/postgres/deferred.sql + +commit; diff --git a/ccm-docrepo/sql/ccm-docrepo/upgrade/move-out-blob-column.sql b/ccm-docrepo/sql/ccm-docrepo/upgrade/move-out-blob-column.sql new file mode 100644 index 000000000..1dd2be8a9 --- /dev/null +++ b/ccm-docrepo/sql/ccm-docrepo/upgrade/move-out-blob-column.sql @@ -0,0 +1,53 @@ +-- +-- Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. +-- +-- This library is free software; you can redistribute it and/or +-- modify it under the terms of the GNU Lesser General Public License +-- as published by the Free Software Foundation; either version 2.1 of +-- the License, or (at your option) any later version. +-- +-- This library 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 +-- Lesser General Public License for more details. +-- +-- You should have received a copy of the GNU Lesser General Public +-- License along with this library; if not, write to the Free Software +-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-- +-- $Id: //apps/docmgr/dev/sql/upgrade/move-out-blob-column.sql#4 $ +-- $DateTime: 2004/08/17 23:26:27 $ + + +------------------------------------------ +-- 1. Create new docs_blobjects table +------------------------------------------ +create table docs_blobjects ( + content_id INTEGER not null + constraint docs_blobjec_conten_id_p_7c9oS + primary key, + -- referential constraint for content_id deferred due to circular dependencies + resource_id INTEGER not null, + -- referential constraint for resource_id deferred due to circular dependencies + content BLOB +); + +------------------------------------------ +-- 2. Add constraints +----------------------------------------- +alter table docs_blobjects add + constraint docs_blobjec_resour_id_f__xiNa foreign key (resource_id) + references docs_resources(resource_id); + +------------------------------------------ +-- 3. Insert data from docs_resources into +-- docs_blobjects +------------------------------------------ +insert into docs_blobjects (content_id, content,resource_id) + select acs_object_id_seq.nextval, content, resource_id from docs_resources; + +------------------------------------------ +-- 4. Drop content column from docs_resources +------------------------------------------ +alter table docs_resources +drop (content); diff --git a/ccm-docrepo/src/ccm-docrepo.config b/ccm-docrepo/src/ccm-docrepo.config new file mode 100644 index 000000000..adfdba100 --- /dev/null +++ b/ccm-docrepo/src/ccm-docrepo.config @@ -0,0 +1,4 @@ + + + + diff --git a/ccm-docrepo/src/ccm-docrepo.load b/ccm-docrepo/src/ccm-docrepo.load new file mode 100644 index 000000000..6001c1548 --- /dev/null +++ b/ccm-docrepo/src/ccm-docrepo.load @@ -0,0 +1,14 @@ + + + +
+ + + + + + + + + + diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ApplicationAuthenticationListener.java b/ccm-docrepo/src/com/arsdigita/docrepo/ApplicationAuthenticationListener.java new file mode 100644 index 000000000..5e111ff40 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ApplicationAuthenticationListener.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.event.RequestEvent; +import com.arsdigita.bebop.event.RequestListener; +import com.arsdigita.dispatcher.AccessDeniedException; +import com.arsdigita.kernel.Kernel; +import com.arsdigita.kernel.permissions.PermissionDescriptor; +import com.arsdigita.kernel.permissions.PermissionService; +import com.arsdigita.kernel.permissions.PrivilegeDescriptor; +import com.arsdigita.ui.login.UserAuthenticationListener; +import com.arsdigita.web.Web; +import org.apache.log4j.Logger; + +/** + * A RequestListener that verifies the user + * has a given privilege on the current Application. + * + * The user is redirected to ACCESS_DENIED if their is + * insufficient permission. + * + * XXX Permissions will be incorporated in December. This is + * temporary for use in our engineering production server until. + * that time. + * + * @version $Id: ApplicationAuthenticationListener.java pboy $ + */ +public class ApplicationAuthenticationListener + extends UserAuthenticationListener implements RequestListener { + + private static final Logger s_log = Logger.getLogger + (ApplicationAuthenticationListener.class); + + private String m_privilegeName; + + /** + * Constructs listener + * + * @param privilegeName a String that represents the privlege name for the + * privilege a user must have to see the page. + * + */ + public ApplicationAuthenticationListener(String privilegeName) { + super(); + m_privilegeName = privilegeName; + } + + public void setRequiredPrivilege(String privilegeName) { + m_privilegeName = privilegeName; + } + + public String getRequiredPrivilege() { + return m_privilegeName; + } + + /** + * Checks whether the user is logged in. If not, redirects the client + * to the login page. + **/ + @Override + public void pageRequested(RequestEvent event) { + PageState state = event.getPageState(); + + PrivilegeDescriptor privDescriptor = + PrivilegeDescriptor.get(m_privilegeName); + + PermissionDescriptor permDescriptor = new PermissionDescriptor + (privDescriptor, + Web.getContext().getApplication(), + Kernel.getContext().getParty()); + + if (!PermissionService.checkPermission(permDescriptor)) { + denyRequest(state); + } + + } + + /** + * Action performed if authentication failed. Override this to perform + * a specific action after the authentication check. + */ + public void denyRequest(PageState state) { + + if (Kernel.getContext().getParty() == null) { + Util.redirectToLoginPage(state); + return; + } + + throw new AccessDeniedException(); + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/Constants.java b/ccm-docrepo/src/com/arsdigita/docrepo/Constants.java new file mode 100644 index 000000000..79d06f571 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/Constants.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + + +/** + * Constants used throughout the document manager application. + * + * @version $Id: Constants.java pboy $ + */ + +public interface Constants { + + // PDL constants + String ACTION = "action"; + String CONTENT = "content"; + String DESCRIPTION = "description"; + String DURATION = "duration"; + String FOLDER_ID = "folderID"; + String IS_FOLDER = "isFolder"; + String LAST_MODIFIED_DATE = "lastModifiedDate"; + String MIME_TYPE_LABEL = "mimeTypeDescription"; + String NAME = "name"; + String OBJECT_ID = "objectID"; + String PARENT = "parent"; + String PARTY_ID = "partyID"; + String PATH = "path"; + String SIZE = "size"; + String TYPE = "mimeType"; + String USER_ID = "userID"; + + String REPOSITORIES_MOUNTED = "subscribedRepositories"; + + // MIME type constants + + String TEXT_PLAIN = com.arsdigita.mail.Mail.TEXT_PLAIN; + String TEXT_HTML = com.arsdigita.mail.Mail.TEXT_HTML; +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ContentTypeException.java b/ccm-docrepo/src/com/arsdigita/docrepo/ContentTypeException.java new file mode 100644 index 000000000..76845cbf1 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ContentTypeException.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +/** + * Base class for content type exceptions. + * + * @author Ron Henderson (ron@arsdigita.com) + * @author Gavin Doughtie (gavin@arsdigita.com) + * @version $Id: ContentTypeException.java pboy $ + */ + +public class ContentTypeException extends Exception { + + /** + * Creates a new exception with a given error message. + * @param message the error message + */ + public ContentTypeException(String message) { + super(message); + } + + /** + * Creates a new exception by wrapping an existing one. + * @param e the exception to wrap + */ + public ContentTypeException(Exception e) { + this(e.getMessage()); + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/DRResources.properties b/ccm-docrepo/src/com/arsdigita/docrepo/DRResources.properties new file mode 100644 index 000000000..d4c92439e --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/DRResources.properties @@ -0,0 +1,71 @@ +ui.action.edit.copy=Copy +ui.action.edit.cut=Cut +ui.action.edit.delete=Delete +ui.action.error=The following error(s) occured: +ui.action.error.continue=Continue +ui.action.delete.submit=Delete +ui.action.delete.confirm='Do you really want to delete the selected files and folders?' +ui.action.copy.submit=Copy to ... +ui.action.move.submit=Move to ... +ui.action.newfile=New Document +ui.action.newfolder=New Folder +ui.cancel=Cancel +ui.email.formatinvalid=Did not send document to following e-mail addresses because of invalid format +ui.error.parentnotfound=Could not find parent folder. The parent folder may have just been deleted. +ui.error.resourceexists=Resource already exists +ui.error.mimetype=The new version cannot have a different MIME type than the original file! +ui.file.description=Description: (opt.) +ui.file.keywords=Keywords: +ui.file.upload=Upload File: (*) +ui.file.name=Name: (opt.) +ui.file.name.required=Name: (*) +ui.file.save=Save +ui.file.submit=Upload +ui.file.source=Source: +ui.file.version.description=Version Description: (*) +ui.file.upload.header=Upload File into Folder +ui.filedelete.confirm=Do you really want to delete this file? +ui.fileinfo.goback.label=Return to +ui.fileinfo.actions.header=Actions +ui.fileinfo.comments.title=Feedback +ui.fileinfo.delete.header=Delete Document +ui.fileinfo.delete.link=Delete +ui.fileinfo.download.header=Download Document +ui.fileinfo.download.link=Download +ui.fileinfo.edit.action.description=Changed name/description +ui.fileinfo.edit.header=Document Properties +ui.fileinfo.edit.link=Edit +ui.fileinfo.feedback.header=Comments and Ratings +ui.fileinfo.history.header=Revision History +ui.fileinfo.history.title=History +ui.fileinfo.links.title=Links +ui.fileinfo.newversion.link=Upload new revision +ui.fileinfo.properties.header=Document Properties +ui.fileinfo.properties.title=Properties +ui.fileinfo.sendcolleague.header=E-mail Document +ui.fileinfo.sendcolleague.link=Send to a Colleague +ui.fileinfo.title=File Info +ui.fileinfo.upload.header=Upload New Version +ui.folder.empty=This folder is empty +ui.folder.name=Name: (*) +ui.folder.description=Description: (opt.) +ui.folder.save=Create +ui.folder.content.header=Contents of +ui.folder.create.header=Create New Folder in +ui.folder.destination.list.header=Destination folder +ui.nav.help=Help +ui.nav.signout=Sign Out +ui.repositories.content.header=Available Document Repositories +ui.repositories.mounted.save=Update +ui.repositories.recentDocs.empty=There are no recently edited documents. +ui.send.friend.description=Personal Message: +ui.send.friend.email.list=Send to: +ui.send.friend.email.subject=Subject +ui.send.friend.submit=Send +ui.title=Document Manager +ui.workspace.browse.title=Browse +ui.workspace.repositories.title=Repositories +ui.workspace.search.title=Search +ui.workspace.title=Workspace +ui.fileinfo.upload.initialversion.description=Initial version +ui.portlet.action.newresource=New Document diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/DRResources_de.properties b/ccm-docrepo/src/com/arsdigita/docrepo/DRResources_de.properties new file mode 100644 index 000000000..6308a6757 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/DRResources_de.properties @@ -0,0 +1,71 @@ +ui.action.edit.copy=Kopieren +ui.action.edit.cut=Ausschneiden +ui.action.edit.delete=L\u00f6schen +ui.action.error=Folgende(r) Fehler trat(en) auf: +ui.action.error.continue=Fortfahren +ui.action.delete.submit=L\u00f6schen +ui.action.delete.confirm='Sollen die ausgew\u00e4hlten Dateien und Ordner tats\u00e4chlich gel\u00f6scht werden?' +ui.action.copy.submit=Kopieren nach ... +ui.action.move.submit=Verschieben nach ... +ui.action.newfile=Neues Dokument +ui.action.newfolder=Neuer Ordner +ui.cancel=Abbrechen +ui.email.formatinvalid=Das Dokument konte aufgrund eines ung\u00fcltigen Formates nicht an die folgende E-Mail Adresse versandt werden +ui.error.parentnotfound=Could not find parent folder. The parent folder may have just been deleted. +ui.error.resourceexists=Resource already exists +ui.error.mimetype=The new version cannot have a different MIME type than the original file! +ui.file.description=Beschreibung: (opt.) +ui.file.keywords=Keywords: +ui.file.upload=Datgei hochladen: (*) +ui.file.name=Name: (opt.) +ui.file.name.required=Name: (*) +ui.file.save=Sichern +ui.file.submit=Upload +ui.file.source=Quelle: +ui.file.version.description=Version Description: (*) +ui.file.upload.header=Upload File into Folder +ui.filedelete.confirm=Do you really want to delete this file? +ui.fileinfo.goback.label=Return to +ui.fileinfo.actions.header=Actions +ui.fileinfo.comments.title=Feedback +ui.fileinfo.delete.header=Delete Document +ui.fileinfo.delete.link=Delete +ui.fileinfo.download.header=Download Document +ui.fileinfo.download.link=Download +ui.fileinfo.edit.action.description=Changed name/description +ui.fileinfo.edit.header=Document Properties +ui.fileinfo.edit.link=Edit +ui.fileinfo.feedback.header=Comments and Ratings +ui.fileinfo.history.header=Revision History +ui.fileinfo.history.title=History +ui.fileinfo.links.title=Links +ui.fileinfo.newversion.link=Upload new revision +ui.fileinfo.properties.header=Document Properties +ui.fileinfo.properties.title=Properties +ui.fileinfo.sendcolleague.header=E-mail Document +ui.fileinfo.sendcolleague.link=Send to a Colleague +ui.fileinfo.title=File Info +ui.fileinfo.upload.header=Upload New Version +ui.folder.empty=This folder is empty +ui.folder.name=Name: (*) +ui.folder.description=Description: (opt.) +ui.folder.save=Create +ui.folder.content.header=Contents of +ui.folder.create.header=Create New Folder in +ui.folder.destination.list.header=Destination folder +ui.nav.help=Help +ui.nav.signout=Sign Out +ui.repositories.content.header=Available Document Repositories +ui.repositories.mounted.save=Update +ui.repositories.recentDocs.empty=There are no recently edited documents. +ui.send.friend.description=Personal Message: +ui.send.friend.email.list=Send to: +ui.send.friend.email.subject=Subject +ui.send.friend.submit=Send +ui.title=Document Manager +ui.workspace.browse.title=Browse +ui.workspace.repositories.title=Repositories +ui.workspace.search.title=Search +ui.workspace.title=Workspace +ui.fileinfo.upload.initialversion.description=Initial version +ui.portlet.action.newresource=New Document diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/DRResources_en.properties b/ccm-docrepo/src/com/arsdigita/docrepo/DRResources_en.properties new file mode 100644 index 000000000..d4c92439e --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/DRResources_en.properties @@ -0,0 +1,71 @@ +ui.action.edit.copy=Copy +ui.action.edit.cut=Cut +ui.action.edit.delete=Delete +ui.action.error=The following error(s) occured: +ui.action.error.continue=Continue +ui.action.delete.submit=Delete +ui.action.delete.confirm='Do you really want to delete the selected files and folders?' +ui.action.copy.submit=Copy to ... +ui.action.move.submit=Move to ... +ui.action.newfile=New Document +ui.action.newfolder=New Folder +ui.cancel=Cancel +ui.email.formatinvalid=Did not send document to following e-mail addresses because of invalid format +ui.error.parentnotfound=Could not find parent folder. The parent folder may have just been deleted. +ui.error.resourceexists=Resource already exists +ui.error.mimetype=The new version cannot have a different MIME type than the original file! +ui.file.description=Description: (opt.) +ui.file.keywords=Keywords: +ui.file.upload=Upload File: (*) +ui.file.name=Name: (opt.) +ui.file.name.required=Name: (*) +ui.file.save=Save +ui.file.submit=Upload +ui.file.source=Source: +ui.file.version.description=Version Description: (*) +ui.file.upload.header=Upload File into Folder +ui.filedelete.confirm=Do you really want to delete this file? +ui.fileinfo.goback.label=Return to +ui.fileinfo.actions.header=Actions +ui.fileinfo.comments.title=Feedback +ui.fileinfo.delete.header=Delete Document +ui.fileinfo.delete.link=Delete +ui.fileinfo.download.header=Download Document +ui.fileinfo.download.link=Download +ui.fileinfo.edit.action.description=Changed name/description +ui.fileinfo.edit.header=Document Properties +ui.fileinfo.edit.link=Edit +ui.fileinfo.feedback.header=Comments and Ratings +ui.fileinfo.history.header=Revision History +ui.fileinfo.history.title=History +ui.fileinfo.links.title=Links +ui.fileinfo.newversion.link=Upload new revision +ui.fileinfo.properties.header=Document Properties +ui.fileinfo.properties.title=Properties +ui.fileinfo.sendcolleague.header=E-mail Document +ui.fileinfo.sendcolleague.link=Send to a Colleague +ui.fileinfo.title=File Info +ui.fileinfo.upload.header=Upload New Version +ui.folder.empty=This folder is empty +ui.folder.name=Name: (*) +ui.folder.description=Description: (opt.) +ui.folder.save=Create +ui.folder.content.header=Contents of +ui.folder.create.header=Create New Folder in +ui.folder.destination.list.header=Destination folder +ui.nav.help=Help +ui.nav.signout=Sign Out +ui.repositories.content.header=Available Document Repositories +ui.repositories.mounted.save=Update +ui.repositories.recentDocs.empty=There are no recently edited documents. +ui.send.friend.description=Personal Message: +ui.send.friend.email.list=Send to: +ui.send.friend.email.subject=Subject +ui.send.friend.submit=Send +ui.title=Document Manager +ui.workspace.browse.title=Browse +ui.workspace.repositories.title=Repositories +ui.workspace.search.title=Search +ui.workspace.title=Workspace +ui.fileinfo.upload.initialversion.description=Initial version +ui.portlet.action.newresource=New Document diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/DocBlobject.java b/ccm-docrepo/src/com/arsdigita/docrepo/DocBlobject.java new file mode 100644 index 000000000..c42010563 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/DocBlobject.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + + +//import com.arsdigita.web.Web; +import com.arsdigita.domain.DataObjectNotFoundException; +//import com.arsdigita.domain.DomainObjectFactory; +import com.arsdigita.domain.DomainObject; +//import com.arsdigita.kernel.Kernel; +import com.arsdigita.db.Sequences; +//import com.arsdigita.kernel.KernelExcursion; +//import com.arsdigita.persistence.DataCollection; +import com.arsdigita.persistence.DataObject; +//import com.arsdigita.persistence.DataOperation; +//import com.arsdigita.persistence.DataQuery; +//import com.arsdigita.persistence.Filter; +import com.arsdigita.persistence.OID; +//import com.arsdigita.persistence.PersistenceException; +//import com.arsdigita.persistence.Session; +//import com.arsdigita.persistence.SessionManager; +//import com.arsdigita.persistence.metadata.ObjectType; + +import java.math.BigDecimal; + + +/** + * + * + */ +public class DocBlobject extends DomainObject { + + public static final String BASE_DATA_OBJECT_TYPE = + "com.arsdigita.docrepo.DocBlobject"; + + @Override + public String getBaseDataObjectType() { + return BASE_DATA_OBJECT_TYPE; + } + + public DocBlobject() { + super(BASE_DATA_OBJECT_TYPE); + } + + @Override + protected void initialize() { + + super.initialize(); + try { + if(isNew()) { + set("id",Sequences.getNextValue()); + } + } catch (java.sql.SQLException e) { + //s_log.error here + } + } + + /** + * Creates a new Doc Blob by retrieving it from the underlying data + * object. + * + * @param dataObject the dataObject corresponding to this file + */ + public DocBlobject(DataObject dataObject) { + super(dataObject); + } + + /** + * Creates a new File by retrieving it based on ID. + * + * @param id - the ID of this file in the database + */ + public DocBlobject(BigDecimal id) throws DataObjectNotFoundException { + this(new OID(BASE_DATA_OBJECT_TYPE, id)); + } + + /** + * Creates a new DocBlobject by retrieving it based on OID. + * + * @param oid - the OID of this file + */ + public DocBlobject(OID oid) throws DataObjectNotFoundException { + super(oid); + } + + public byte[] getContent() { + return (byte[])get("content"); + } + + public void setContent(byte[] content) { + + set("content",content); + + } + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/File.java b/ccm-docrepo/src/com/arsdigita/docrepo/File.java new file mode 100644 index 000000000..3380e1b3f --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/File.java @@ -0,0 +1,455 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + + +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.domain.DomainObjectFactory; +import com.arsdigita.mimetypes.MimeType; +import com.arsdigita.persistence.DataObject; +import com.arsdigita.persistence.OID; +import com.arsdigita.persistence.metadata.Property; +import com.arsdigita.util.Assert; +import org.apache.oro.text.perl.Perl5Util; + +import javax.activation.DataHandler; +import javax.activation.FileDataSource; +import javax.activation.DataSource; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.util.Iterator; +import java.util.Vector; + +/** + * Represents a File in the document manager application. + * + * @author Stefan Deusch (stefan@arsdigita.com) + * @author Ron Henderson (ron@arsdigita.com) + * @version $Id: File.java pboy $ + */ +public class File extends ResourceImpl implements Constants { + + /** Logger instance for debugging support. */ + protected static org.apache.log4j.Logger s_log = + org.apache.log4j.Logger.getLogger(File.class); + + public static final String BASE_DATA_OBJECT_TYPE = + "com.arsdigita.docrepo.File"; + + public static final String DEFAULT_MIME_TYPE = + "application/octet-stream"; + + private static Perl5Util s_re = new Perl5Util(); + + private static final String PATTERN ="/^([^\\.].*)(\\.\\w+)$/"; + + private static final byte[] EMPTY_BYTES = new byte[0]; + + /** + * Creates a new file by retrieving it from the underlying data + * object. + * + * @param dataObject the dataObject corresponding to this file + */ + public File(DataObject dataObject) { + super(dataObject); + } + + /** + * Creates a new File by retrieving it based on ID. + * + * @param id - the ID of this file in the database + */ + public File(BigDecimal id) throws DataObjectNotFoundException { + this(new OID(BASE_DATA_OBJECT_TYPE, id)); + } + + /** + * Creates a new File by retrieving it based on OID. + * + * @param oid - the OID of this file + */ + public File(OID oid) throws DataObjectNotFoundException { + super(oid); + } + + /** + * Creates a file inside a given parent folder. + * + * @param name the name of the File + * @param description the description of the file contents (may + * be null) + */ + public File(String name, String description, Folder parent) { + this(BASE_DATA_OBJECT_TYPE, name, description, parent); + } + + + /** + * Creates a file inside a given parent folder. + * + * @param name the name of the File + * @param description the description of the file contents (may + * be null) + */ + public File(String baseDataObjectType, String name, String description, + Folder parent) { + super(baseDataObjectType, name, description, parent); + } + + /** + * Creates an empty file inside a given parent folder. + * + * @param parent The parent folder + */ + public File(Folder parent) { + super(BASE_DATA_OBJECT_TYPE, parent); + } + + /** + * Creates a file + * + * @param objectType the type of the object + * + */ + public File(String objectType) { + super(objectType); + } + + /** + * + * @param dataObject + * @return + */ + public static File retrieveFile(DataObject dataObject) { + Assert.exists(dataObject, DataObject.class); + + return new File(dataObject); + } + + + /** + * + */ + @Override + protected void beforeSave() { + set(IS_FOLDER, Boolean.FALSE); + super.beforeSave(); + } + + /** + * Returns the pdl object type required for this object. + * + */ + public String getBaseDataObjectType() { + return BASE_DATA_OBJECT_TYPE; + } + + /** + * @return the MIME type of this file as a string, or null if the + * content type cannot be determined. + */ + public String getContentType() { + return (String) get(TYPE); + } + + /** + * @return the pretty name for the MIME type of the file or null + * if no content type can be set. For instance, getContentType + * will return something like "application/msexcel" where this will + * return "Microsoft Excel document". If the mime type is not + * registered in the database this this will just return the same + * value as getContentType() + */ + public String getPrettyContentType() { + String type = getContentType(); + if (type != null) { + MimeType mimeType = MimeType.loadMimeType(type); + if (mimeType != null) { + type = mimeType.getLabel(); + } + } + return type; + } + + /** + * Sets the MIME type of this file. + * + * @param type the content type of this file. + */ + private void setContentType(String type) { + if (isNew()) { + set(TYPE, type); + } else { + if (!type.equals(getContentType())) { + throw new TypeChangeException(getContentType(), type); + } + } + } + + /** + * Sets the content of this resource to a file with a given name and + * description. + * + * @param file the file to read content from + * @param name the name of the file + * @param description the description of the file + */ + public void setContent(java.io.File file, + String name, + String description, + String mimeType) + throws ResourceException + { + + DataSource source = new FileDataSource(file); + setContent(source, name, description, mimeType); + setName(name); + setDescription(description); + setContentType(mimeType); + } + + /** + * Sets the content of this resource to a file with a given name and + * description. + * + * @param source the data source to read content from + * @param name the name of the file + * @param description the description of the file + */ + public void setContent(DataSource source, + String name, + String description, + String mimeType) + throws ResourceException + { + DataHandler dh = new DataHandler(source); + setDataHandler(dh); + setName(name); + setDescription(description); + setContentType(mimeType); + } + + /** + * Convenience method for use with plain text files. Sets the + * content of the file to a String and sets its MIME type to + * "text/plain". + */ + final public void setText(String text) { + final byte[] content = text.getBytes(); + DocBlobject dblob = new DocBlobject(); + dblob.setContent(content); + set(CONTENT, dblob); + set(SIZE, BigDecimal.valueOf(content.length)); + setContentType(TEXT_PLAIN); + } + + /** + * Returns an InputStream suitable for reading the raw content of + * the file. + * + * @return an InputStream + */ + public InputStream getInputStream() { + DataObject data = (DataObject)get("content"); + if(data == null) { + throw new DataObjectNotFoundException("Doc Blob not found"); + } + DocBlobject dobj = (DocBlobject)DomainObjectFactory.newInstance(data); + return new ByteArrayInputStream((byte[]) dobj.getContent()); + } + + /** + * Returns the raw content of the file as a byte array. Do not + * use this method for very large files. Use the {link + * getInputStream} method instead. + */ + public byte[] getRawContent() { + DataObject data = (DataObject)get("content"); + if(data == null) { + return EMPTY_BYTES; + } + DocBlobject dobj = (DocBlobject)DomainObjectFactory.newInstance(data); + return (byte[]) dobj.getContent(); + } + + /** + * Provides the mechanism to set this file's content. + * + * @param dh the DataHandler for this part's content + */ + private void setDataHandler(DataHandler dh) + throws ResourceException + { + // Copy the data to an internal byte[] array and transfer this + // to the persistence layer. + + try { + InputStream is = dh.getInputStream(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + int ch; + + while ((ch = is.read()) != -1) { + os.write(ch); + } + + // Convert to a byte array and store the data and size as + // properties of the file + + byte[] content = os.toByteArray(); + DocBlobject dblob = new DocBlobject(); + dblob.setContent(content); + set(CONTENT, dblob); + set(SIZE, BigDecimal.valueOf(content.length)); + + } catch (IOException e) { + throw new ResourceException("error reading content: " + e.getMessage()); + } + } + + /** + * Returns the size of the file in bytes. + * + * @return the size of the file in bytes, or -1 if the size + * cannot be computed. + */ + public BigDecimal getSize() { + BigDecimal size = (BigDecimal) get(SIZE); + if (size != null) { + return size; + } else { + return BigDecimal.valueOf(0); + } + } + + + public boolean isFile() { + return true; + } + + public boolean isFolder() { + return false; + } + + public Resource copyTo(String name, Resource parent) { + File dest = new File((Folder) parent); + copy(this,dest); + dest.setName(name); + dest.setContentType(getContentType()); + byte[] content = getRawContent(); + DocBlobject dblob = new DocBlobject(); + dblob.setContent(content); + dest.set(CONTENT,dblob); + dest.set(SIZE, BigDecimal.valueOf(content.length)); + dest.save(); + return dest; + } + + /** + * @return the list of directory property names for a File, + * including those inherited from ResourceImpl. + */ + @Override + protected Vector getPropertyNames() { + Vector names = super.getPropertyNames(); + Iterator props = getObjectType().getDeclaredProperties(); + while (props.hasNext()) { + names.addElement(((Property) props.next()).getName()); + } + return names; + } + + + /** + * Returns the display name of a file, that is the file name minus + * any extension if present. An extension is defined as the '.' + * character followed by one or more non-whitespace characters at + * the end of the file name. Any file name that begins with '.' + * will always be returned intact. */ + @Override + public String getDisplayName() { + String name = getName(); + if (s_re.match(PATTERN,name)) { + return s_re.group(1); + } + return name; + } + + + + /** + * Checks for valid characters in a file name and also checks that + * the name corresponds to a compatible MIME type. If no extension + * is supplied and the current file name includes an extension, + * add that extension to the name before guessing its MIME type. + */ + public boolean isValidNewName(String name) { + + boolean isValid = isValidName(name) == 0; + if (isValid && !isNew()) { + + String contentType = Util.guessContentType + (appendExtension(name),null); + isValid = contentType.equals(getContentType()); + } + + return isValid; + } + + /** + * Append the extension of this file to a given file name. If the + * given file name already has an extension it will be returned + * without modification. + */ + public String appendExtension(String name) { + String ext = getExtension(name); + if (ext.equals("")) { + name += getExtension(getName()); + } + return name; + } + + /** + * Return the extension of a file name, if present. Otherwise + * return an empty string. + */ + public static String getExtension(String name) { + if (s_re.match(PATTERN,name)) { + return s_re.group(2); + } + return ""; + } + + /** + * Saves a new revision of this file. + * + * @param src The source file to upload to the database. + * @param originalName The original name of the file. The servlet container may not return the same file extension. For example, tomcat will return some random .tmp file, which will cause mime type checking to fail. + * @param versionDesc The description of this version of the file. + */ + public void saveNewRevision(java.io.File src, String originalName, String versionDesc) { + setContent(src, getName(), getDescription(), getContentType()); + applyTag(versionDesc); + save(); + + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/Folder.java b/ccm-docrepo/src/com/arsdigita/docrepo/Folder.java new file mode 100644 index 000000000..9b77c19b2 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/Folder.java @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + + +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.domain.DomainObjectFactory; +import com.arsdigita.domain.DomainCollection; +import com.arsdigita.persistence.DataObject; +import com.arsdigita.persistence.DataQuery; +import com.arsdigita.persistence.OID; +import com.arsdigita.persistence.Session; +import com.arsdigita.persistence.SessionManager; +import com.arsdigita.persistence.DataAssociation; +import com.arsdigita.persistence.metadata.ObjectType; + +import java.math.BigDecimal; +import java.util.StringTokenizer; + +/** + * Represents a Folder in the document repository application. + * + * @author Stefan Deusch (stefan@arsdigita.com) + * @author Ron Henderson (ron@arsdigita.com) + * @version $Id: Folder.java pboy $ + */ +public class Folder extends ResourceImpl implements Constants { + + public static final String BASE_DATA_OBJECT_TYPE = + "com.arsdigita.docrepo.Folder"; + + /** + * Constructor. + */ + public Folder() { + this(BASE_DATA_OBJECT_TYPE); + } + + /** + * Creates a new folder object. + */ + public Folder(DataObject dataObject) { + super(dataObject); + } + + /** + * Creates a new folder by retrieving it based on ID. + * + * @param id - the BigDecimal ID + */ + public Folder(BigDecimal id) throws DataObjectNotFoundException { + this(new OID(BASE_DATA_OBJECT_TYPE, id)); + } + + /** + * Creates a new folder by retrieving it based on OID. + * + * @param oid - the Object oID + */ + public Folder(OID oid) throws DataObjectNotFoundException { + super(oid); + } + + public Folder(String objectTypeString) { + super(objectTypeString); + } + + /** + * Constructor. The contained DataObject is + * initialized with a new DataObject with an + * ObjectType specified by type. + * + * @param type The ObjectType of the contained + * DataObject. + * + * @see com.arsdigita.domain.DomainObject#DomainObject(ObjectType) + * @see com.arsdigita.persistence.DataObject + * @see com.arsdigita.persistence.metadata.ObjectType + */ + protected Folder(ObjectType type) { + super(type); + } + + + /** + * Creates a named folder with a description. + * + * @param name the name of the folder + * @param description the description of the folder contents (may + * be null) + */ + public Folder(String name, String description) { + super(BASE_DATA_OBJECT_TYPE, name, description); + } + + + /** + * Creates a sub folder inside a given parent folder. + * + * @param name the name of the folder + * @param description the description of the folder contents (may + * be null) + */ + public Folder(String name, String description, Folder parent) { + super(BASE_DATA_OBJECT_TYPE); + if (parent.hasResource(name)) { + throw new ResourceExistsException("A resource named " + + name + + " exists in the parent folder " + + parent.getName()); + } + setParent(parent); + setName(name); + setDescription(description); + } + + @Override + protected void beforeSave() { + if (s_log.isDebugEnabled()) { + s_log.debug("folder before save"); + } + set(IS_FOLDER, Boolean.TRUE); + super.beforeSave(); + } + + @Override + protected String getBaseDataObjectType() { + return BASE_DATA_OBJECT_TYPE; + } + + @Override + public void setParent(Resource parent) { + if (parent instanceof Folder) { + final String parentPath = parent.getPath(); + final String path = getPath(); + if (s_log.isDebugEnabled()) { + s_log.debug("folder set parent Parent path: " + + parentPath + + " folder path: " + + path); + } + if (path != null && parentPath.startsWith(path)) { + throw new ResourceException( + "The parent is a child of this folder. " + + "Parent path: " + parentPath + + " folder path: " + path); + } + + } + + super.setParent(parent); + } + + /** + * Retrieves the named sub folder by searching from the current folder + * along the given path. Returns the child folder or throws a + * DataObjectNotFoundException if the subfolder does not exist. + * + * @return child folder if and only if it exists as a sub folder + * with the correct path + */ + public Folder retrieveFolder(String path) throws DataObjectNotFoundException, + InvalidNameException { + return new Folder(getResourceID(path)); + } + + /** + * + * @param path + * @return + * @throws DataObjectNotFoundException + * @throws InvalidNameException + */ + public File retrieveFile(String path) throws DataObjectNotFoundException, + InvalidNameException { + return new File(getResourceID(path)); + } + + /** + * + * @param name + * @return + */ + public boolean hasResource(String name) { + DataAssociation da = (DataAssociation) get("immediateChildren"); + DomainCollection resources = new DomainCollection(da); + resources.addEqualsFilter(NAME, name); + try { + return resources.next(); + } finally { + resources.close(); + } + } + + + /** + * Creates the sub folder named by path, including any necessary + * but nonexistent parent folders. + */ + public Folder createFolders(final String path) + throws InvalidNameException, + ResourceExistsException + { + int pec; + if ( (pec = isValidPath(path)) != 0 ) { + throw new InvalidNameException(pec); + } + + // Build up the array of sub folders to search for. First we + // just extract the set of path elements from the path + // string. If the path is "a/b/c", this will produce: + // + // name[0] = a + // name[1] = b + // name[2] = c + + StringTokenizer st = new StringTokenizer(path,SEPARATOR); + int pathElementCount = st.countTokens(); + + String name[] = new String[pathElementCount]; + for (int i = 0; i < pathElementCount; i++) { + name[i] = st.nextToken(); + } + + // Build the array of sub paths. If the original path is + // "a/b/c", this will produce: + // + // subPath[0] = /a + // subPath[1] = /a/b + // subPath[2] = /a/b/c + + String subPath[] = new String[pathElementCount]; + for (int i = 0; i < pathElementCount; i++) { + StringBuffer buf = new StringBuffer(); + for (int j = 0; j <= i; j++) { + buf.append(SEPARATOR); + buf.append(name[j]); + } + subPath[i] = buf.toString(); + } + + // Now we check for the existence of each Folder starting from + // the end until we find one that exists. + + Folder folder[] = new Folder[pathElementCount]; + int lastPathElementIndex = pathElementCount - 1; + int retrievedFolderIndex = -1; + for (retrievedFolderIndex = lastPathElementIndex; + retrievedFolderIndex >= 0; + retrievedFolderIndex--) { + try { + folder[retrievedFolderIndex] = + retrieveFolder(subPath[retrievedFolderIndex].substring(1)); + break; + } catch (DataObjectNotFoundException ex) { + // continue retrieving + } + } + + // Verify that we did NOT retrieve the first folder. + + if (retrievedFolderIndex == lastPathElementIndex) { + throw new ResourceExistsException + ("createFolders: folder exists:" + path); + } + + // We now loop back and create each parent folder. + + Folder parent = (retrievedFolderIndex < 0) ? + this : folder[retrievedFolderIndex]; + + for (int i = retrievedFolderIndex + 1; i < pathElementCount; i++) { + folder[i] = new Folder(name[i], null, parent); + folder[i].save(); + parent = folder[i]; + } + + return folder[lastPathElementIndex]; + } + + /** + * + * @return + */ + public boolean isFolder() { + return true; + } + + /** + * + * @return + */ + public boolean isFile() { + return false; + } + + /** + * Returns the display name for a folder, which is equivalent to + * calling getName(). + */ + public String getDisplayName() { + return getName(); + } + + /** + * Copy this folder to a new location. Recursively copies all + * children from the original resource location to the new + * resource location. + */ + public Resource copyTo(String name, Resource parent) { + Folder dest = new Folder(); + + copy(this,dest); + + dest.setName(name); + dest.setParent(parent); + dest.save(); + + Session session = SessionManager.getSession(); + DataQuery query = session.retrieveQuery + ("com.arsdigita.docs.getDirectChildren"); + query.setParameter("parentID", getID()); + + while (query.next()) { + + OID oid = new OID(ResourceImpl.BASE_DATA_OBJECT_TYPE, + query.get("id")); + + try { + ResourceImpl orig = (ResourceImpl) + DomainObjectFactory.newInstance(oid); + orig.copyTo(dest); + } catch (DataObjectNotFoundException ex) { + throw new ResourceException(ex); + } + } + + return dest; + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/Initializer.java b/ccm-docrepo/src/com/arsdigita/docrepo/Initializer.java new file mode 100644 index 000000000..171296e2e --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/Initializer.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +import com.arsdigita.db.*; +import com.arsdigita.docrepo.ui.RecentUpdatedDocsPortlet; +import com.arsdigita.domain.*; +import com.arsdigita.kernel.ACSObjectInstantiator; +import com.arsdigita.persistence.*; +import com.arsdigita.persistence.pdl.*; +// import com.arsdigita.web.*; +import com.arsdigita.runtime.*; + +/** + * Document Repository Initializer + * + * @author Jim Parsons <jparsons@redhat.com> + * @author Peter Boy <pboy@barkhof.uni-bremen.de> + * @version $Revision: #19 $ $Date: 2004/08/17 $ + **/ + +public class Initializer extends CompoundInitializer { + + + public Initializer() { + final String url = RuntimeConfig.getConfig().getJDBCURL(); + final int database = DbHelper.getDatabaseFromURL(url); + + add(new PDLInitializer + (new ManifestSource + ("ccm-docrepo.pdl.mf", + new NameFilter(DbHelper.getDatabaseSuffix(database), "pdl")))); + + } + + /** + * + * @param evt + */ + @Override + public void init(DomainInitEvent evt) { + super.init(evt); + + // Prerequisite to access a repository instance + DomainObjectFactory.registerInstantiator( + Repository.BASE_DATA_OBJECT_TYPE, new ACSObjectInstantiator() { + @Override + public DomainObject doNewInstance(DataObject dataObject) { + return new Repository(dataObject); + } + } + ); + + DomainObjectFactory.registerInstantiator + (ResourceImpl.BASE_DATA_OBJECT_TYPE, + new ACSObjectInstantiator() { + @Override + public DomainObject doNewInstance(DataObject obj) { + Boolean isFolder = (Boolean) obj.get(Constants.IS_FOLDER); + if (isFolder != null && isFolder.booleanValue()) { + return new Folder(obj); + } else { + return new File(obj); + } + } + }); + // File + DomainObjectFactory.registerInstantiator( + File.BASE_DATA_OBJECT_TYPE, new ACSObjectInstantiator() { + @Override + public DomainObject doNewInstance(DataObject dataObject) { + return new File(dataObject); + } + } + ); + + // Folder + DomainObjectFactory.registerInstantiator( + Folder.BASE_DATA_OBJECT_TYPE, new ACSObjectInstantiator() { + @Override + public DomainObject doNewInstance(DataObject dataObject) { + return new Folder(dataObject); + } + } + ); + + DomainObjectFactory.registerInstantiator( + DocBlobject.BASE_DATA_OBJECT_TYPE, new DomainObjectInstantiator() { + public DomainObject doNewInstance(DataObject dataObject) { + return new DocBlobject(dataObject); + } + } + ); + + // Registering internal portlets + + // Prerequisite to access RecentUpdatedDocsPortlet + DomainObjectFactory.registerInstantiator( + RecentUpdatedDocsPortlet.BASE_DATA_OBJECT_TYPE, + new ACSObjectInstantiator() { + @Override + public DomainObject doNewInstance(DataObject dataObject) { + return new RecentUpdatedDocsPortlet(dataObject); + } + } + ); + } + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/InvalidMimeTypeFormatException.java b/ccm-docrepo/src/com/arsdigita/docrepo/InvalidMimeTypeFormatException.java new file mode 100644 index 000000000..2776aa75d --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/InvalidMimeTypeFormatException.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +/** + * + */ +public class InvalidMimeTypeFormatException extends Exception { + + + /** + * Constructs a InvalidMimeTypeFormatException with the specified detail message. + */ + public InvalidMimeTypeFormatException(String s) { + super(s); + } + + + /** + * Constructs a InvalidMimeTypeFormatException with the specified cause. + * Pass in an Exception or an Error (both subclasses of Throwable) + * to indicate the cause of failure. + */ + public InvalidMimeTypeFormatException(Throwable cause) { + super(cause.getMessage()); + } + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/InvalidNameException.java b/ccm-docrepo/src/com/arsdigita/docrepo/InvalidNameException.java new file mode 100644 index 000000000..6cb9419dc --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/InvalidNameException.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +import java.text.ChoiceFormat; + +/** + * Exception thrown to indicate that a resource name (or path) + * is in an invalid state. + * + * @author stefan@arsdigita.com + * @version $Id: InvalidNameException.java pboy $ + */ +public class InvalidNameException extends ResourceException { + + /** + * Error messages for path validation methods + * @see ResourceImpl.isValidPath + */ + public static final int ZERO_CHARACTERS_ERROR = 1; + public static final int LEADING_FILE_SEPARATOR_ERROR = 2; + public static final int TRAILING_FILE_SEPARATOR_ERROR = 3; + public static final int INVALID_CHARACTER_ERROR = 4; + public static final int LEADING_CHARACTER_ERROR = 5; + + /* + TODO: Error messages eventually internationalized + read from a resource file. + */ + protected static ChoiceFormat s_validPathErrorMessages = + new ChoiceFormat( + new double[] {ZERO_CHARACTERS_ERROR, + LEADING_FILE_SEPARATOR_ERROR, + TRAILING_FILE_SEPARATOR_ERROR, + INVALID_CHARACTER_ERROR, + LEADING_CHARACTER_ERROR}, + new String[] {"Empty string is no valid pathname.", + "Path name cannot begin with a file separation character.", + "Path name cannot end with a file separation character.", + "Path name contains invalid characters, " + + "only [a-z][A-Z][0-9][-., ] are allowed.", + "Resource names cannot begin with a \".\"."}); + + /** + * Creates a new exception with a given error message. + * @param message the error message + */ + + public InvalidNameException(String message) { + super(message); + } + + /** + * Creates a new exception with the error message + * corresponding to the error message codes above. + * @param error code + */ + + public InvalidNameException(int messageCode) { + super(s_validPathErrorMessages.format(messageCode)); + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/Loader.java b/ccm-docrepo/src/com/arsdigita/docrepo/Loader.java new file mode 100644 index 000000000..f2c0e05c9 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/Loader.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +import com.arsdigita.docrepo.ui.RecentUpdatedDocsPortlet; +// import com.arsdigita.mimetypes.*; +import com.arsdigita.domain.DomainObject; +import com.arsdigita.kernel.ACSObjectInstantiator; +import com.arsdigita.kernel.Kernel; +import com.arsdigita.kernel.KernelExcursion; +import com.arsdigita.loader.PackageLoader; +import com.arsdigita.persistence.DataObject; +import com.arsdigita.portal.PortletType; +import com.arsdigita.portal.apportlet.AppPortletSetup; +import com.arsdigita.runtime.ScriptContext; +import com.arsdigita.web.ApplicationType; + +import org.apache.log4j.Logger; + +/** + * Document RFepository Loader + * + * @author pboy <pboy@barkhof.uni-bremen.de> + * @version $Id: Loader.java $ + **/ + +public class Loader extends PackageLoader { + + + /** Logger instance for debugging */ + private static final Logger s_log = Logger.getLogger(Loader.class); + + /** + * Run script invoked by com.arsdigita.packing loader script. + * + * @param ctx + */ + public void run(final ScriptContext ctx) { + + new KernelExcursion() { + public void excurse() { + setEffectiveParty(Kernel.getSystemParty()); + + loadDocRepositoryApplicationType(); + setupDocRepositoryPortlet(null); + + setupDefaultDocRepository(); + + } + }.run(); + + s_log.info("Done"); + } + + // //////////////////////////////////////////////////////////////////////// + // + // S e t u p o f a p p l i c a t i o n t y p e s + // + // //////////////////////////////////////////////////////////////////////// + + /** + * Creates a document repository application type, the domain class of the + * document repository (docrepo) package, as a legacy-compatible type of + * application. + * + * Creates an entry in table application_types and a corresponding entry in + * apm_package_types + * + * TODO: migrate to a new style, legacy free application type. + */ + private void loadDocRepositoryApplicationType() { + + ApplicationType type = ApplicationType.createApplicationType( + "docrepo", + "Document Repository", + Repository.BASE_DATA_OBJECT_TYPE); + type.setDescription + ("The document repository empowers users to share documents."); + // Current code requires an apps specific dispatcher class. Has to be + // modified to be able to create a legacy free app type. + type.setDispatcherClass + ("com.arsdigita.docrepo.ui.DRDispatcher"); + + } + + + + // //////////////////////////////////////////////////////////////////////// + // + // S e t u p a D O C R E P O a p p l i c a t i o n + // + // //////////////////////////////////////////////////////////////////////// + private void setupDefaultDocRepository() { + + // try { + // SiteNode sn = SiteNode.getSiteNode("/administration", false); + // if (!"administration".equals(sn.getName())) { + Repository repo = Repository.create( + "repository", "Default Document Repository", null); + repo.save(); + // } + // } catch (DataObjectNotFoundException e) { + // Assert.fail(e.getMessage()); + // } + } + + + // //////////////////////////////////////////////////////////////////////// + // + // S e t u p o f i n t e r n a l p o r t l e t s + // + // //////////////////////////////////////////////////////////////////////// + + + /** + * Creates a PortletType (persistent object) for the RecentUpdatedDocs + * Portlet. + * + * Instances (Portlets) are created by user interface or programmatically + * by configuration. + */ + private void setupDocRepositoryPortlet(ApplicationType provider) { + + // Create the document repository portlet + AppPortletSetup setup = new AppPortletSetup(s_log); + + setup.setPortletObjectType(RecentUpdatedDocsPortlet.BASE_DATA_OBJECT_TYPE); + setup.setTitle("Recently Updated Documents"); + setup.setDescription( + "Displays the most recent documents in the document repository."); + setup.setProfile(PortletType.WIDE_PROFILE); + // setup.setProviderApplicationType(provider); + setup.setProviderApplicationType(Repository.BASE_DATA_OBJECT_TYPE); + setup.setInstantiator(new ACSObjectInstantiator() { + @Override + protected DomainObject doNewInstance(DataObject dataObject) { + return new RecentUpdatedDocsPortlet(dataObject); + } + }); + + setup.run(); + + } + + + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/Lockable.java b/ccm-docrepo/src/com/arsdigita/docrepo/Lockable.java new file mode 100644 index 000000000..1706220dd --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/Lockable.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +import com.arsdigita.kernel.Party; + +/** + * This interface specifies functionality to lock a + * an object by a user. + * + * + *

+ * Stability: Experimental + *

+ * @author Stefan Deusch (stefan@arsdigita.com) + */ +public interface Lockable { + + /** + * Applies a lock to an object + * owned by the user + */ + public void lock(Party user); + + /** + * Party who previously locked + * object, unlocks it now. + */ + public void unlock(Party user); + + /** + * Checks whether the task is locked by a user. + * @return true if the task is locked + * by a user; false otherwise. + */ + public boolean isLocked(); + + /** + * Retrieves the user who locked the process. + * @return the user who locked the process. + * + */ + public Party getLockedParty(); + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/MimeTypeXMLLoader.java b/ccm-docrepo/src/com/arsdigita/docrepo/MimeTypeXMLLoader.java new file mode 100644 index 000000000..cc777fb67 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/MimeTypeXMLLoader.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +//import com.arsdigita.mimetypes.ImageMimeType; +import com.arsdigita.mimetypes.MimeType; +import com.arsdigita.mimetypes.MimeTypeExtension; +//import com.arsdigita.mimetypes.TextMimeType; +//import com.arsdigita.mimetypes.MimeTypeInitializer; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.persistence.OID; +import com.arsdigita.util.StringUtils; +import java.io.IOException; +import java.io.InputStream; +import org.apache.xerces.parsers.DOMParser; +//import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +//import org.xml.sax.InputSource; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import java.util.ArrayList; + +/** + * Initializer helper class which loades more Mime types into the + * database from an xml file. + * + * @author Stefan Deusch + */ + +public final class MimeTypeXMLLoader { + + // XML constants here + + private static final String XML_MIME_ROOT = "mimetypes"; + private static final String XML_MIME_NODE = "mimetype"; + private static final String XML_MIME_NAME = "name"; + private static final String XML_MIME_EXTENSION = "extension"; + private static final String XML_MIME_LABEL = "label"; + private static final String XML_MIME_CLASS = "class"; + + + /** + * Parse the input stream and load the extracted XML source. + * + * @param is InputStream to read the document from + */ + + public static void parse(InputStream is) + throws IOException, + InvalidMimeTypeFormatException + { + InputSource inputSrc = new InputSource(is); + DOMParser parser = new DOMParser(); + + try { + parser.parse(inputSrc); + } catch (SAXException e) { + throw new InvalidMimeTypeFormatException(e); + } + + loadMimeTypes(parser.getDocument()); + } + + /** + * Load MIME types from an XML configuration document into the + * database. + * + * @param doc XML MimeType configuration document + */ + + private static void loadMimeTypes(org.w3c.dom.Document doc) + throws InvalidMimeTypeFormatException + { + Element root = doc.getDocumentElement(); + if (root.getTagName().compareTo(XML_MIME_ROOT) != 0) { + throw new InvalidMimeTypeFormatException + ("Invalid MIME type document"); + } + + NodeList nodeList = root.getElementsByTagName(XML_MIME_NODE); + for (int j=0; j < nodeList.getLength(); j++) { + assertMimeType((Element)nodeList.item(j)); + } + } + + /** + * Checks whether the MIME type defined by element + * is available in the database. If not, it is created. + * + * @param element DOM element decribing a MIME type + */ + + private static void assertMimeType(Element element) { + + // Get inline attributes + + String name = element.getAttribute(XML_MIME_NAME); + String extensions = element.getAttribute(XML_MIME_EXTENSION); + String label = element.getAttribute(XML_MIME_LABEL); + String objectType = element.getAttribute(XML_MIME_CLASS); + + // If MIME class was not specified, set up the correct + // default. + + if (null == objectType || "".equals(objectType) ) { + objectType = "MimeType"; + } + String javaClass = "com.arsdigita.mimetypes." + objectType; + + String objType = "com.arsdigita.cms." + objectType; + + // Set up an array of property values + + ArrayList props = new ArrayList(5); + props.add(name); + props.add(label); + props.add(extensions); + props.add(objectType); + props.add("0"); + + // Try to load the type. If it doesn't exist in the database + // we will create it. If it does exist we update its + // properties so that the database is in sync with the loaded + // configuration file. + + MimeType type = MimeType.loadMimeType(name); + + if (null == type) { + type = MimeType.createMimeType(name, javaClass, objType); + } else { + type.setLabel(label); + type.setJavaClass(javaClass); + type.setSpecificObjectType(objType); + } + + updateMimeProperties(type, props); + updateFileExtensions(type, extensions); + } + + /** + * Update MIME type properties. + */ + + private static void updateMimeProperties(MimeType type, + ArrayList props) + { + // XXX Has to be adopted to the curent CCM version! +/* if (type instanceof TextMimeType) + MimeTypeInitializer.setTextMimeProperties + ((TextMimeType)type, props); + else if (type instanceof ImageMimeType) + MimeTypeInitializer.setImageMimeProperties + ((ImageMimeType)type, props); + else + MimeTypeInitializer.setMimeProperties + (type, props); + + type.save(); */ + } + + /** + * Update MIME type extensions list. + */ + + private static void updateFileExtensions(MimeType type, + String extensions) + { + String [] ext = StringUtils.split(extensions, ','); + + for (int j = 0; j < ext.length; j++) { + MimeTypeExtension me; + try { + me = new MimeTypeExtension + (new OID(MimeTypeExtension.MIME_TYPE, ext[j])); + } catch(DataObjectNotFoundException e) { + // me = new MimeTypeExtension(); + // me.setFileExtension(ext[j]); + me = MimeTypeExtension.create(ext[j],MimeTypeExtension.MIME_TYPE); + } + // me.setMimeType(type.getMimeType()); + me.save(); + } + } + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/Repository.java b/ccm-docrepo/src/com/arsdigita/docrepo/Repository.java new file mode 100644 index 000000000..31e71a4c2 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/Repository.java @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + + +// import com.arsdigita.docrepo.util.GlobalizationUtil; + +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.kernel.Group; +import com.arsdigita.kernel.Kernel; +import com.arsdigita.kernel.KernelExcursion; +import com.arsdigita.kernel.Party; +//import com.arsdigita.kernel.SiteNode; +import com.arsdigita.kernel.User; +// import com.arsdigita.kernel.permissions.PermissionDescriptor; +import com.arsdigita.kernel.permissions.PermissionService; +//import com.arsdigita.kernel.permissions.PrivilegeDescriptor; +//import com.arsdigita.persistence.DataObject; +import com.arsdigita.persistence.OID; +import com.arsdigita.persistence.SessionManager; +//import com.arsdigita.persistence.Session; +import com.arsdigita.persistence.DataCollection; +import com.arsdigita.persistence.DataObject; +import com.arsdigita.util.UncheckedWrapperException; + +import com.arsdigita.web.Application; +import com.arsdigita.web.Web; +//import com.arsdigita.web.ApplicationCollection; +import com.arsdigita.util.Assert; + +import java.math.BigDecimal; +import javax.servlet.http.HttpServletRequest; + +import org.apache.log4j.Logger; + +/** + * A repository is the application that provides access to files and + * folders. + * + * @author Stefan Deusch (stefan@arsdigita.com) + * @author Ron Henderson (ron@arsdigita.com) + */ + +public class Repository extends Application implements Constants { + + /** Logger instance for debugging purpose. */ + private static Logger s_log = Logger.getLogger(Repository.class); + + public static final String BASE_DATA_OBJECT_TYPE = + "com.arsdigita.docrepo.Repository"; + + /** + * + * @return + */ + protected String getBaseDataObjectType() { + return BASE_DATA_OBJECT_TYPE; + } + + // pdl constants + private static final String OWNER = "ownerID"; + private static final String ROOT = "rootID"; + + private Folder m_root = null; + + /** + * Retreives a repository from the database usings its OID. + * + * @param oid the OID of the repository + */ + public Repository(OID oid) throws DataObjectNotFoundException { + super(oid); + } + + /** + * Constructor. The contained DataObject is retrieved + * from the persistent storage mechanism with an OID + * specified by id. + * + * @param id The id for the retrieved + * DataObject. + */ + public Repository(BigDecimal id) throws DataObjectNotFoundException { + this(new OID(BASE_DATA_OBJECT_TYPE, id)); + } + + /** + * Constructs a repository from the underlying data object. + */ + public Repository(DataObject obj) { + super(obj); + + if (obj.isNew()) { + s_log.info("Create root folder for repository"); + + // Generate a unique name for the root folder based on the + // primary key of the repository. + + m_root = new Folder(getID().toString(), null); + m_root.save(); + obj.set(ROOT, m_root.getID()); + + s_log.info("Created root folder for repository " + getID()); + } + } + + private boolean m_wasNew; + + /** + * + */ + @Override + protected void beforeSave() { + if (isNew()) { + m_wasNew = true; + } + + super.beforeSave(); + } + + /** + * Grant write permission to the Portal participants. + */ + protected void afterSave() { + super.afterSave(); + + if (m_wasNew) { + KernelExcursion excursion = new KernelExcursion() { + protected void excurse() { + setParty(Kernel.getSystemParty()); + + // Assert.assertNotNull(m_root, "Folder m_root"); + Assert.exists(m_root, "Folder m_root"); + + PermissionService.setContext(m_root, Repository.this); + } + }; + excursion.run(); + } + } + + /** + * This is called when the application is created. + */ + public static Repository create(String urlName, + String title, + Application parent) { + Repository repository = (Repository) Application.createApplication + (BASE_DATA_OBJECT_TYPE, urlName, title, parent); + + repository.save(); + + return repository; + } + + /** + * Sets the display name of the repository. + */ + private void setName(String name) { + set(NAME, name); + } + + /** + * Sets the owner id of this repository. + */ + private void setOwner(BigDecimal ownerID) { + set(OWNER, ownerID); + } + + + + + /** + * Convenience method to retrieve a resource (file or folder) by + * absolute path name. + * + * @returns a Resource or null of no resource exists with the + * specified absolute path. + */ + public static Resource retrieveResource(String absPath) { + throw new UnsupportedOperationException(); + } + + /** + * + * @param party + */ + private static void assertParty(Party party) { + BigDecimal id = party.getID(); + + if (id == null) { + throw new RuntimeException("User not peristent"); + } + } + + /** + * Returns the party owning the repository. + * @return the party owning the repository. + */ + public Party getOwner() { + BigDecimal id = (BigDecimal)get(OWNER); + Party party = null; + + if (id != null) { + try { + party = User.retrieve(id); + } catch (DataObjectNotFoundException e1) { + // try to load a group + try { + party = new Group(id); + } catch (DataObjectNotFoundException e2) { + throw new RuntimeException("No User or Group found."); + } + } + } + + return party; + } + + /** + * @return the root file folder for this repository + */ + public Folder getRoot() { + BigDecimal id = (BigDecimal)get(ROOT); + Folder root = null; + + try { + root = new Folder(id); + } catch (DataObjectNotFoundException e) { + throw new UncheckedWrapperException + ("Repository root folder does not exist"); + } + + return root; + } + + /** + * + * @return + */ + public static ResourceImplCollection getRecentlyModifiedDocuments() { + + HttpServletRequest req = Web.getRequest(); + Repository rep = getCurrentRepository(req); + DataCollection dataCollection = SessionManager + .getSession().retrieve(ResourceImpl.BASE_DATA_OBJECT_TYPE); + + dataCollection.addFilter(dataCollection.getFilterFactory().startsWith + ("path", rep.getRoot().getPath(), true)); + dataCollection.addEqualsFilter("isFolder", Boolean.FALSE); + + ResourceImplCollection rCollection = + new ResourceImplCollection(dataCollection); + return rCollection; + } + + /** + * + * @param rep + * @return + */ + public static ResourceImplCollection getRecentlyModifiedDocuments(Repository rep) { + DataCollection dataCollection = + SessionManager.getSession().retrieve(ResourceImpl.BASE_DATA_OBJECT_TYPE); + dataCollection.addFilter(dataCollection.getFilterFactory().startsWith + ("path", rep.getRoot().getPath(), true)); + dataCollection.addEqualsFilter("isFolder", Boolean.FALSE); + + ResourceImplCollection rCollection = + new ResourceImplCollection(dataCollection); + return rCollection; + } + + /** + * + * @param req + * @return + */ + public static Repository getCurrentRepository(HttpServletRequest req) { + Application app = Application.getCurrentApplication(req); + if(app instanceof Repository) { + return (Repository) app; + } + return null; + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/Resource.java b/ccm-docrepo/src/com/arsdigita/docrepo/Resource.java new file mode 100644 index 000000000..8945302fc --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/Resource.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +import java.math.BigDecimal; +import java.net.URL; + +/** + * This interface describes the functionality common to operations + * on files and folders in the document repository application. + * + * Concrete implementations of this interface may vary in the + * implementation of the data store. For example, persistent data for + * resource might be stored in a file system or a database. + * + * @author Stefan Deusch (stefan@arsdigita.com) + * @version $Id: Resource.java pboy $ + */ + +public interface Resource { + + /** + * The path-separator character, represented as a string for convenience. + */ + final static String SEPARATOR = "/"; + + /** + * The path-separator character. + */ + final static char SEPARATOR_CHAR = SEPARATOR.charAt(0); + + + /** + * Returns the name of the file or folder corresponding to this + * resource. + */ + String getName(); + + /** + * Returns a description of the resource, or null if no + * description has been provided. + */ + String getDescription(); + + /** + * Returns the path name of this resource's parent, or null if + * this resource does not have a parent. + */ + Resource getParent(); + + /** + * Converts this resource into a pathname string. + */ + String getPath(); + + /** + * Tests whether this resource is a folder. + */ + boolean isFolder(); + + /** + * Tests whether this resource is a file. + */ + boolean isFile(); + + /** + * Copies the resource into another location. Preserves the + * original name of the resource but places the copy inside a new + * parent resource. + * + * @param parent the parent of the copy + * @return a copy of the original resource + */ + Resource copyTo(Resource parent) throws ResourceExistsException; + + /** + * Copies the resource into another location with a new name. + * + * @param name the name of the copy + * @param parent the parent of the copy + * @return a copy of the original resource. + */ + Resource copyTo(String name, Resource parent) throws ResourceExistsException; + + /** + * Copies the resource into the same location (same parent) with a + * new name. + * + * @param name the name of the copy + * @return a copy of the original resource. + */ + Resource copyTo(String name) throws ResourceExistsException; + + /** + * Returns the pathname string of this resource. + */ + String toString(); + + /** + * Returns the URL corresponding to this resource. + */ + URL toURL(); + + /** + * Returns a unique identifier for this resource. + */ + BigDecimal getID(); +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ResourceException.java b/ccm-docrepo/src/com/arsdigita/docrepo/ResourceException.java new file mode 100644 index 000000000..9eb4c5789 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ResourceException.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +import com.arsdigita.util.UncheckedWrapperException; + +/** + * Base class for resource exceptions. + * + * @author Ron Henderson (ron@arsdigita.com) + * @version $Id: ResourceException.java pboy $ + */ + +public class ResourceException extends UncheckedWrapperException { + + /** + * Creates a new exception with a given error message. + * @param message the error message + */ + public ResourceException (String message) { + super(message); + } + + /** + * Creates a new exception by wrapping an existing one. + * @param e the exception to wrap + */ + public ResourceException (Exception e) { + super(e); + } + + public ResourceException(String message, Exception e) { + super(message, e); + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ResourceExistsException.java b/ccm-docrepo/src/com/arsdigita/docrepo/ResourceExistsException.java new file mode 100644 index 000000000..69222c3d8 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ResourceExistsException.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +// import com.arsdigita.persistence.UniqueConstraintException; + +/** + * Exception thrown to indicate that another resource exists with the + * same parent and name. + * + * @version $Id: ResourceExistsException.java pboy $ + */ + +public class ResourceExistsException extends RuntimeException { + + /** + * Creates a new exception with a given error message. + * @param message the error message + */ + public ResourceExistsException(String message) { + super(message); + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ResourceImpl.java b/ccm-docrepo/src/com/arsdigita/docrepo/ResourceImpl.java new file mode 100644 index 000000000..da6314d67 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ResourceImpl.java @@ -0,0 +1,708 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + + +import com.arsdigita.db.Sequences; +import com.arsdigita.web.Web; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.domain.DomainObjectFactory; +import com.arsdigita.kernel.ACSObject; +import com.arsdigita.kernel.Kernel; +import com.arsdigita.kernel.KernelExcursion; +import com.arsdigita.kernel.Party; +import com.arsdigita.kernel.User; +import com.arsdigita.kernel.permissions.PermissionDescriptor; +import com.arsdigita.kernel.permissions.PermissionService; +import com.arsdigita.kernel.permissions.PrivilegeDescriptor; +import com.arsdigita.persistence.DataCollection; +import com.arsdigita.persistence.DataObject; +import com.arsdigita.persistence.DataOperation; +import com.arsdigita.persistence.DataQuery; +import com.arsdigita.persistence.Filter; +import com.arsdigita.persistence.OID; +import com.arsdigita.persistence.PersistenceException; +import com.arsdigita.persistence.Session; +import com.arsdigita.persistence.SessionManager; +import com.arsdigita.persistence.metadata.ObjectType; +import com.arsdigita.versioning.VersionedACSObject; + +import org.apache.oro.text.perl.Perl5Util; +import org.apache.log4j.Logger; + +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.StringTokenizer; +import java.util.Vector; +import javax.servlet.http.HttpServletRequest; + +/** + * This class is the abstract parent class of {@link File} and {@link + * Folder}. It provides an implementation of the {@link Resource} + * interface for a database-backed virtual filesystem. + * + * This implementation stores file in Oracle exclusively. + * All versioning API is by inheritance from VersionedACSObject + * (which will eventually + * also include access logging - so wait for VersionedACSObject) + * + * @author Stefan Deusch (stefan@arsdigita.com) + * @author Ron Henderson (ron@arsdigita.com) + * @version $Revision: #18 $ $Date: 2004/08/17 $ $Author: dennis $ + * @version $Id: ResourceImpl.java pboy $ + */ +public abstract class ResourceImpl extends VersionedACSObject + implements Resource, Constants { + + /** Logger instance for debugging support. */ + protected static Logger s_log = Logger.getLogger(ResourceImpl.class); + + public static final String BASE_DATA_OBJECT_TYPE = + "com.arsdigita.docrepo.ResourceImpl"; + public static final String PARENT = "parent"; + + /** + * + * @return + */ + @Override + protected String getBaseDataObjectType() { + return BASE_DATA_OBJECT_TYPE; + } + + + /** + * Default constructor. The contained DataObject is + * initialized with a new DataObject with an + * ObjectType of BASE_DATA_OBJECT_TYPE. + * + * @see com.arsdigita.domain.DomainObject#DomainObject(String) + * @see com.arsdigita.persistence.metadata.ObjectType + */ + protected ResourceImpl() { + this(BASE_DATA_OBJECT_TYPE); + } + + /** + * Constructor. The contained DataObject is + * initialized with a new DataObject with an + * ObjectType specified by the string + * typeName. + * + * @param typeName The name of the ObjectType of the + * contained DataObject. + * + * @see com.arsdigita.domain.DomainObject#DomainObject(String) + * @see com.arsdigita.persistence.DataObject + * @see com.arsdigita.persistence.metadata.ObjectType + */ + protected ResourceImpl(String typeName) { + super(typeName); + } + + /** + * Constructor. The contained DataObject is + * initialized with a new DataObject with an + * ObjectType specified by type. + * + * @param type The ObjectType of the contained + * DataObject. + * + * @see com.arsdigita.domain.DomainObject#DomainObject(ObjectType) + * @see com.arsdigita.persistence.DataObject + * @see com.arsdigita.persistence.metadata.ObjectType + */ + protected ResourceImpl(ObjectType type) { + super(type); + } + + /** + * Creates a new resource. Properties of this object are not made + * persistent until the save() method is called. + */ + protected ResourceImpl(DataObject dataObject) { + super(dataObject); + } + + /** + * Creates a resource given the ID + * + * @param id the BigDecimal ID + */ + protected ResourceImpl(BigDecimal id) throws DataObjectNotFoundException { + this(new OID(BASE_DATA_OBJECT_TYPE, id)); + } + + /** + * Creates a resource given the OID + * + * @param oid the Object OID + * + */ + protected ResourceImpl(OID oid) throws DataObjectNotFoundException { + super(oid); + } + + /** + * Creates a named resource of the specified type. + */ + protected ResourceImpl(String type, + String name, + String description) { + this(type); + setName(name); + setDescription(description); + } + + /** + * Creates a named resource of the specified type with a given parent. + */ + protected ResourceImpl(String type, + String name, + String description, + ResourceImpl parent) { + this(type,name,description); + setParent(parent); + } + + /** + * Creates an empty resource with the given parent. + */ + protected ResourceImpl(String type, + ResourceImpl parent) { + this(type); + setParent(parent); + } + + private boolean m_wasNew; + + protected void beforeSave() { + m_wasNew = isNew(); + /** + * Update the path for this resource before saving. It should be + * sufficient to update the path only when the name changes, but + * the current implementation is conservative about path updates. + */ + final boolean pathChanged = + isPropertyModified(PARENT) || isPropertyModified(NAME); + + if (pathChanged) { + String oldPath = null; + if (!isNew()) { + oldPath = getPath(); + } + final Resource parent = getParent(); + if (parent != null) { + final String parentPath = parent.getPath(); + setPath(parentPath + SEPARATOR + getName()); + } else { + setPath(SEPARATOR + getName()); + } + if (oldPath != null) { + updateChildren(oldPath); + } + } + if(isNew()) { + User user = Web.getContext().getUser(); + if (user != null) { + setCreationUser(user); + setLastModifiedUser(user); + } + java.util.Date date = new java.util.Date(); + setCreationDate(date); + setLastModifiedDate(date); + setCreationIP(); + } else { + User user = Web.getContext().getUser(); + if (user != null){ + setLastModifiedUser(user); + } + + setLastModifiedDate(new java.util.Date()); + setLastModifiedIP(); + + } + + super.beforeSave(); + } + + protected void afterSave() { + super.afterSave(); + + if (m_wasNew && !isRoot()) { + Object obj = getParent(); + + if (obj instanceof ACSObject) { + PermissionService.setContext(this, (ACSObject) obj); + } + new KernelExcursion() { + protected void excurse() { + Party currentParty = Kernel.getContext().getParty(); + setParty(Kernel.getSystemParty()); + PermissionService.grantPermission + (new PermissionDescriptor(PrivilegeDescriptor.ADMIN, + ResourceImpl.this, + currentParty)); + } + }.run(); + + } + + } + + /** + * Deletes a resource. Throws a {@link ResourceNotEmptyException} + * if the resource still contains children. + */ + public void delete() throws ResourceNotEmptyException { + // We mangle names here so that a deleted "foo" doesn't stop + // the user from adding a new "foo". + // + // XXX: This is not a pleasing way to fix this, but the truly + // right thing to do is fix versioning, not doc repos's use of + // versioning. + + String name = getName(); + String suffix = ""; + + try { + suffix = "-" + Sequences.getNextValue(); + } catch (SQLException se) { + throw new PersistenceException(se.getMessage()); + } + + int suffixLength = suffix.length(); + int nameLength = name.length(); + + if (nameLength > suffixLength) { + setName(name.substring(0, nameLength - suffixLength) + suffix); + } else { + setName(name + suffix); + } + + save(); + + try { + super.delete(); + } catch (PersistenceException ex) { + throw new ResourceNotEmptyException(ex.getMessage()); + } + } + + /** + * Update the denormalized path for each child of this resource. + */ + + private void updateChildren(String oldPath) { + String path = getPath(); + s_log.debug("Running updateChildren for ID " + getID() + " on path " + path); + // Execute the data operation to update all children + Session session = SessionManager.getSession(); + DataOperation op = session.retrieveDataOperation + ("com.arsdigita.docs.updateChildren"); + op.setParameter("rootPath", path); + op.setParameter("oldPath", oldPath); + op.setParameter("oldRootPathLength", new Integer(oldPath.length()+1)); + op.setParameter("parentResource", getID()); + op.execute(); + op.close(); + } + + + public String getName() { + return (String) get(NAME); + } + + public void setName(String name) { + set(NAME, name); + } + + public String getDescription() { + return (String) get(DESCRIPTION); + } + + public void setDescription(String description) { + set(DESCRIPTION, description); + } + + public Resource getParent() { + DataObject parent = (DataObject)get(PARENT); + if (parent != null) { + return (Resource)DomainObjectFactory.newInstance(parent); + } else { + return null; + } + } + + /** + * Set the parent of this resource. + * + * @param parent the parent of this resource + */ + public void setParent(Resource parent) { + set(PARENT, parent); + } + + + protected BigDecimal getParentResourceID() { + Resource parent = getParent(); + if (parent != null) { + return parent.getID(); + } else { + return null; + } + } + + public boolean isRoot() { + return getParent() == null; + } + + public String getPath() { + String path = (String) get(PATH); + return path; + } + + private void setPath(String path) { + set(PATH, path); + } + + public abstract boolean isFolder(); + + public abstract boolean isFile(); + + public URL toURL() { + throw new UnsupportedOperationException(); + } + + /** + * Retrieves the path corresponding to a given resource. + */ + protected static String retrievePath(BigDecimal id) { + DataCollection collection = SessionManager.getSession().retrieve + (BASE_DATA_OBJECT_TYPE); + collection.addEqualsFilter(ID, id); + + String ids = null; + if (collection.next()) { + ids = (String)collection.get(PATH); + collection.close(); + } else { + // this means that the id is not valid so there is no path + return ""; + } + + StringBuffer ancestors = new StringBuffer(); + if (ids == null) { + // this should not happen + return ancestors.toString(); + } + + collection = SessionManager.getSession().retrieve + (BASE_DATA_OBJECT_TYPE); + Filter filter = collection.addFilter(PATH + " <= :ancestors"); + filter.set("ancestors", ids); + filter = collection.addFilter + (PATH + " = substr(:path, 1, length(" + PATH +"))"); + filter.set("path", ids); + + collection.addOrder(PATH); + + while (collection.next()) { + ancestors.append(SEPARATOR + collection.get(NAME)); + } + + return ancestors.toString(); + } + + /** + * Verifies that the given string corresponds to a valid relative + * path name. + * @return 0 for a system-valid parthname, otherwise error codes + * defined in InvalidNameException. + * @see InvalidNameException + */ + protected static int isValidPath(String path) { + if (path.length() == 0) { + return InvalidNameException.ZERO_CHARACTERS_ERROR; + } + + // check for leading slash + if (path.charAt(0) == SEPARATOR_CHAR) { + return InvalidNameException.LEADING_FILE_SEPARATOR_ERROR; + } + + // check for trailing separator + if (path.charAt(path.length()-1) == SEPARATOR_CHAR) { + return InvalidNameException.TRAILING_FILE_SEPARATOR_ERROR; + } + + // tokenize and validate each token + StringTokenizer st = new StringTokenizer(path, SEPARATOR); + while (st.hasMoreTokens()) { + String name = st.nextToken().trim(); + if (name.length() == 0) { + return InvalidNameException.ZERO_CHARACTERS_ERROR; + } + int nec; + if ((nec = isValidName(name)) != 0 ) { + return nec; + } + } + + return 0; + } + + /** + * Verifies that the given string corresponds to a valid absolute + * path name. + */ + protected static boolean isAbsolutePath(String path) { + if (path.length() == 0) { + return false; + } + + return (path.trim().charAt(0) == SEPARATOR_CHAR && + 0 == isValidPath(path.substring(1))); + } + + /** + * Verifies that the string only contains valid characters for + * resource names. The following are allowed: + * + * [a-z][A-Z][0-9][-., ] + * + * In addition, names cannot begin with ".", i.e. we do NOT + * support file names like ".profile" at the moment. + * The current implementation does not allow international + * characters for resource names. + * + * @return 0 for a system-valid resource name, otherwise error codes + * defined in InvalidNameException. + * @see InvalidNameException + */ + protected static int isValidName(String name) { + Perl5Util util = new Perl5Util(); + + // check invalid characters at start of name + String INVALID_START_PATTERN = "/^[.]+/"; + if (util.match(INVALID_START_PATTERN, name)) { + return InvalidNameException.LEADING_CHARACTER_ERROR; + } + + // check invalid characters internal to name + String INVALID_NAME_PATTERN = "/[^a-zA-Z0-9\\_\\.\\-\\ ]+/"; + if (util.match(INVALID_NAME_PATTERN, name)) { + return InvalidNameException.INVALID_CHARACTER_ERROR; + } + + return 0; + } + + /** + * Returns a canonical path by removing leading or trailing + * separator characters as needed. + */ + public static String getCanonicalPath(String path) + throws InvalidNameException { + + String errMsg = "Unable to construct canonical path for: "; + + if (null == path) { + throw new InvalidNameException(errMsg + path); + } + + int start; + if (path.charAt(0) == SEPARATOR_CHAR) { + start = 1; + } else { + start = 0; + } + + int end; + int length = path.length(); + if (path.charAt(length-1) == SEPARATOR_CHAR) { + end = length-1; + } else { + end = length; + } + + String canonicalPath = path.substring(start,end); + int pec; + if ( (pec=isValidPath(canonicalPath)) != 0) { + throw new InvalidNameException(pec); + } + + return canonicalPath; + } + + public BigDecimal getResourceID() { + return (BigDecimal)getID(); + } + + /** + * Retrieve the ID of a child resource using a relative path. + * This method is useful for checking the existence of a named + * child without the overhead of instantiating that child. + * + * @return the BigDecimal ID of the resource with the specified + * relative path + */ + public BigDecimal getResourceID(String path) + throws DataObjectNotFoundException, InvalidNameException { + int pec; + if ( (pec = isValidPath(path)) != 0) { + throw new InvalidNameException(pec); + } + + String absPath = getPath() + SEPARATOR + path; + Session session = SessionManager.getSession(); + DataQuery query = session.retrieveQuery + ("com.arsdigita.docs.getResourceByPath"); + query.setParameter("targetPath", absPath); + + if (query.next()) { + BigDecimal id = (BigDecimal) query.get(ID); + query.close(); + return id; + } else { + throw new DataObjectNotFoundException + ("No resource with path " + absPath); + } + } + + /** + * Return the list of declared property names for a Resource. + * This list only includes the properties that should be + * duplicated during a copy operation. + */ + protected Vector getPropertyNames() { + Vector names = new Vector(); + names.addElement(NAME); + names.addElement(DESCRIPTION); + names.addElement(IS_FOLDER); + return names; + } + + public java.util.Date getLastModifiedDate() { + java.util.Date date = (java.util.Date)get("lastModifiedDate"); + return date; + } + + public void setLastModifiedDate(java.util.Date date) { + set("lastModifiedDate",date); + } + + public java.util.Date getCreationDate() { + java.util.Date date = (java.util.Date)get("creationDate"); + return date; + } + + public void setCreationDate(java.util.Date date) { + set("creationDate",date); + } + + public User getCreationUser() { + DataObject dobj = (DataObject)get("creationUser"); + if(dobj == null) { + throw new DataObjectNotFoundException("Creation User not found"); + } + User user = (User)DomainObjectFactory.newInstance(dobj); + return user; + } + + public void setCreationUser(User user) { + set("creationUser", user); + } + + public User getLastModifiedUser() { + DataObject dobj = (DataObject)get("lastModifiedUser"); + if(dobj == null) { + throw new DataObjectNotFoundException("Last User not found"); + } + User user = (User)DomainObjectFactory.newInstance(dobj); + return user; + } + + public void setLastModifiedUser(User user) { + set("lastModifiedUser", user); + } + + public String getCreationIP() { + String ip = (String)get("creationIP"); + return ip; + } + + public void setCreationIP() { + String ip; + HttpServletRequest req = Web.getRequest(); + if(req == null) + ip = "127.0.0.1"; + else + ip = req.getRemoteAddr(); + set("creationIP",ip); + } + + public String getLastModifiedIP() { + String ip = (String)get("lastModifiedIP"); + return ip; + } + + public void setLastModifiedIP() { + String ip; + HttpServletRequest req = Web.getRequest(); + if(req == null) + ip = "127.0.0.1"; + else + ip = req.getRemoteAddr(); + set("lastModifiedIP",ip); + } + + /** + * Copy the generic properties of a Resource. Uses an explicit + * list of properties to copy as determined by {@link + * getPropertyNames}. + */ + protected static void copy(ResourceImpl src, ResourceImpl dest) { + Vector props = src.getPropertyNames(); + for (int i = 0; i < props.size(); i++) { + String name = (String) props.elementAt(i); + dest.set(name, src.get(name)); + } + } + + public Resource copyTo(Resource parent) { + return copyTo(getName(), parent); + } + + public Resource copyTo(String name) { + return copyTo(name, getParent()); + } + + public abstract Resource copyTo(String name, Resource parent); + + + /** + * Copy method implemented by extensions of this class. This + * method is protected because it isn't type safe, even though the + * BigDecimal ID of the parent resource is all that we really need + * to complete a copy. + */ + //protected abstract Resource copyTo(String name, BigDecimal parent); +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ResourceImplCollection.java b/ccm-docrepo/src/com/arsdigita/docrepo/ResourceImplCollection.java new file mode 100644 index 000000000..5090cf35d --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ResourceImplCollection.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +//import com.arsdigita.web.ApplicationCollection; +import com.arsdigita.util.Assert; +import com.arsdigita.persistence.DataCollection; +import com.arsdigita.persistence.DataObject; +import com.arsdigita.domain.DomainCollection; +import com.arsdigita.domain.DomainObject; + +//import java.math.BigDecimal; +import org.apache.log4j.Logger; + +/** + * + * @author Jim Parsons <jparsons@redhat.com> + */ +public class ResourceImplCollection extends DomainCollection { + + private static final Logger s_log = Logger.getLogger + (ResourceImplCollection.class); + + public ResourceImplCollection(DataCollection dataCollection) { + super(dataCollection); + } + + /** + * Get the current item as a ResourceImpl domain object. + * + * @return a ResourceImpl domain object. + * @post return != null + */ + @Override + public DomainObject getDomainObject() { + DomainObject domainObject = getResourceImpl(); + + // Assert.assertNotNull(domainObject); + Assert.exists(domainObject); + + return domainObject; + } + /** + * Get the current item as a ResourceImpl domain object. + * + * @return a ResourceImpl domain object. + * @post return != null + */ + public ResourceImpl getResourceImpl() { + DataObject dataObject = m_dataCollection.getDataObject(); + + File rimpl = File.retrieveFile(dataObject); + + // Assert.assertNotNull(rimpl); + Assert.exists(rimpl); + + return rimpl; + } + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ResourceNotEmptyException.java b/ccm-docrepo/src/com/arsdigita/docrepo/ResourceNotEmptyException.java new file mode 100644 index 000000000..10b9b7971 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ResourceNotEmptyException.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +import com.arsdigita.persistence.PersistenceException; + +/** + * Exception thrown to indicate that resource contains children and + * cannot be deleted. + * + * @version $Id: ResourceNotEmptyException.java pboy $ + */ + +public class ResourceNotEmptyException extends PersistenceException { + + /** + * Creates a new exception with a given error message. + * @param message the error message + */ + public ResourceNotEmptyException(String message) { + super(message,null); + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/TypeChangeException.java b/ccm-docrepo/src/com/arsdigita/docrepo/TypeChangeException.java new file mode 100644 index 000000000..6eba2dfb6 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/TypeChangeException.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +/** + * Exception thrown to indicate that a resource name (or path) contains + * invalid characters. + * + * @version $Id: TypeChangeException.java pboy $ + */ + +public class TypeChangeException extends ResourceException { + + /** + * Creates a new exception with a given error message. + * @param message the error message + */ + public TypeChangeException(String message) { + super(message); + } + + public TypeChangeException(String oldType, String newType) { + super(makeErrorMsg(oldType, newType)); + } + + private static String makeErrorMsg(String oldType, String newType) { + String msg = "Attempt to change mime type of file from " + + oldType + " to " + newType; + return msg; + } + + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/Util.java b/ccm-docrepo/src/com/arsdigita/docrepo/Util.java new file mode 100644 index 000000000..1de3bf0df --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/Util.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +import com.arsdigita.bebop.PageState; +import com.arsdigita.web.LoginSignal; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.log4j.Logger; + +/** + * + * + */ +public class Util { + private static Logger s_log = Logger.getLogger(Util.class); + + public static void redirectToLoginPage(PageState ps) { + throw new LoginSignal(ps.getRequest()); + } + + /** + * Guess the content type for a file by checking the file + * extension agains the know database of types, or for the + * existence of a MIME type header in an HttpServletRequest. If + * these both fail, or if the content type set in the request is + * not one of the recognized types on the system, return a content + * type of "application/octet-stream". + * + * @param name the name of a file to be used for an + * extension-based type lookup + * @param request an HttpServletRequest which might contain a + * Content-Type header, and can be null + */ + public static String guessContentType(String name, + HttpServletRequest request) { + + s_log.debug("CALLED", new Throwable()); + // Try looking up the type based on the filename extensions + + com.arsdigita.mimetypes.MimeType mimeType = + com.arsdigita.mimetypes.MimeType.guessMimeTypeFromFile(name); + + // Try looking up from the request. We require that the + // resolved type correspond to a known MIME type in the + + if (mimeType == null && request != null) { + String contentType = request.getHeader("Content-Type"); + s_log.debug("Retrieved content type " + contentType + + "from request " + request); + if (contentType != null) { + mimeType = com.arsdigita.mimetypes.MimeType.loadMimeType(contentType); + if (mimeType == null) { + s_log.warn("Couldn't load mime type for " + contentType); + } + } + } + + if (mimeType != null) { + return mimeType.getMimeType(); + } else { + return File.DEFAULT_MIME_TYPE; + } + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/enterprise.init b/ccm-docrepo/src/com/arsdigita/docrepo/enterprise.init new file mode 100644 index 000000000..187fca0e1 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/enterprise.init @@ -0,0 +1 @@ +init com.arsdigita.docmgr.installer.Initializer { } diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/installer/Initializer.java b/ccm-docrepo/src/com/arsdigita/docrepo/installer/Initializer.java new file mode 100644 index 000000000..3d4c24682 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/installer/Initializer.java @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.installer; + +import com.arsdigita.docrepo.ui.RecentUpdatedDocsPortlet; +import com.arsdigita.docrepo.File; +import com.arsdigita.docrepo.Folder; +import com.arsdigita.docrepo.ResourceImpl; +import com.arsdigita.docrepo.DocBlobject; +import com.arsdigita.docrepo.Repository; +import com.arsdigita.docrepo.Constants; +import com.arsdigita.domain.DomainObject; +import com.arsdigita.domain.DomainObjectFactory; +import com.arsdigita.domain.DomainObjectInstantiator; +import com.arsdigita.initializer.Configuration; +import com.arsdigita.kernel.ACSObjectInstantiator; +import com.arsdigita.persistence.DataObject; +import com.arsdigita.persistence.SessionManager; +import com.arsdigita.persistence.TransactionContext; +//import com.arsdigita.util.ResourceManager; +import com.arsdigita.web.ApplicationSetup; +import com.arsdigita.web.ApplicationType; +import com.arsdigita.portal.apportlet.AppPortletSetup; +import com.arsdigita.portal.PortletType; + +//import java.io.FileInputStream; +import org.apache.log4j.Logger; + + +/** + * Initializes the document manager package, sets up the + * DomainFactory, registers knowledge types and portlets. + * + * @author Stefan Deusch + * @author David Dao + * + * @version $Revision: #10 $ $Date: 2004/08/17 $ + */ + +public class Initializer implements com.arsdigita.initializer.Initializer { + + private Configuration m_conf = new Configuration(); + + private static final String SEPARATOR = java.io.File.separator; + + private static String PACKAGE_TYPE_NAME = "docs"; + + private static Logger s_log = + Logger.getLogger(Initializer.class); + + public Initializer() { } + + /** + * Returns the configuration object used by this initializer. + */ + public Configuration getConfiguration() { + return m_conf; + } + + /** + * Called on startup. + */ + public void startup() { + s_log.info("Document Manager is initializing."); + + setupDomainFactory(); + + TransactionContext txn = SessionManager.getSession() + .getTransactionContext(); + txn.beginTxn(); + + ApplicationType docsAppType = setupDocs(); + setupDocManagerPortlet(docsAppType); + + txn.commitTxn(); + s_log.info("Document Manager Initializer completed."); + } + + /** + * Set up the document manager. Checks to see if the necessary + * package exists, and if not it creates it for the first time. + */ + + private ApplicationType setupDocs() { + ApplicationSetup setup = new ApplicationSetup(s_log); + setup.setApplicationObjectType(Repository.BASE_DATA_OBJECT_TYPE); + setup.setKey(PACKAGE_TYPE_NAME); + setup.setTitle("Document Manager Application"); + setup.setSingleton(true); + setup.setDescription + ("The document manager empowers users to share documents."); + setup.setDispatcherClass("com.arsdigita.docmgr.ui.DMDispatcher"); + // setup.setStylesheet("/packages/docmgr/xsl/docs.xsl"); + setup.setInstantiator(new ACSObjectInstantiator() { + @Override + public DomainObject doNewInstance(DataObject dataObject) { + return new Repository(dataObject); + } + }); + + return setup.run(); + + } + + private void setupDocManagerPortlet(ApplicationType provider) { + // Create the document manager portlet + AppPortletSetup setup = new AppPortletSetup(s_log); + + setup.setPortletObjectType(RecentUpdatedDocsPortlet.BASE_DATA_OBJECT_TYPE); + setup.setTitle("Recently Updated Documents"); + setup.setDescription("Displays the most recent documents in the document manager."); + setup.setProfile(PortletType.WIDE_PROFILE); + setup.setProviderApplicationType(provider); + setup.setInstantiator(new ACSObjectInstantiator() { + protected DomainObject doNewInstance(DataObject dataObject) { + return new RecentUpdatedDocsPortlet(dataObject); + } + }); + + setup.run(); + } + + /** + * Set up domain object factories for basic document manager + * object types. + */ + private void setupDomainFactory() { + DomainObjectFactory.registerInstantiator + (ResourceImpl.BASE_DATA_OBJECT_TYPE, + new ACSObjectInstantiator() { + public DomainObject doNewInstance(DataObject obj) { + Boolean isFolder = (Boolean) obj.get(Constants.IS_FOLDER); + if (isFolder != null && isFolder.booleanValue()) { + return new Folder(obj); + } else { + return new File(obj); + } + } + }); + // File + DomainObjectFactory.registerInstantiator( + File.BASE_DATA_OBJECT_TYPE, new ACSObjectInstantiator() { + public DomainObject doNewInstance(DataObject dataObject) { + return new File(dataObject); + } + } + ); + + // Folder + DomainObjectFactory.registerInstantiator( + Folder.BASE_DATA_OBJECT_TYPE, new ACSObjectInstantiator() { + public DomainObject doNewInstance(DataObject dataObject) { + return new Folder(dataObject); + } + } + ); + + DomainObjectFactory.registerInstantiator( + DocBlobject.BASE_DATA_OBJECT_TYPE, new DomainObjectInstantiator() { + public DomainObject doNewInstance(DataObject dataObject) { + return new DocBlobject(dataObject); + } + } + ); + } + + /** + * Shutdown the document manager. + */ + public void shutdown() { } + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/BrowsePane.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/BrowsePane.java new file mode 100644 index 000000000..8fd8f98d5 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/BrowsePane.java @@ -0,0 +1,437 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + + +import com.arsdigita.bebop.ActionLink; +import com.arsdigita.bebop.BoxPanel; +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.Container; +import com.arsdigita.bebop.GridPanel; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Link; +import com.arsdigita.bebop.List; +import com.arsdigita.bebop.ModalContainer; +import com.arsdigita.bebop.Page; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.bebop.SegmentedPanel; +import com.arsdigita.bebop.SimpleComponent; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.bebop.TabbedPane; +import com.arsdigita.bebop.Tree; +import com.arsdigita.bebop.event.ActionEvent; +import com.arsdigita.bebop.event.ActionListener; +import com.arsdigita.bebop.event.ChangeEvent; +import com.arsdigita.bebop.event.ChangeListener; +import com.arsdigita.bebop.event.RequestEvent; +import com.arsdigita.bebop.event.RequestListener; +import com.arsdigita.bebop.list.ListCellRenderer; +import com.arsdigita.bebop.parameters.BigDecimalParameter; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.docrepo.File; +import com.arsdigita.docrepo.ResourceImpl; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.xml.Element; + +import java.math.BigDecimal; +import java.util.ArrayList; + +/** + * User Interface component of the Document Repository application which + * which serves as entry-point and navigation tool of the repositories + * that a user has subscribed too. + * The tree of all subscribed repositories is on the left side, the full + * listing of the currently selected directory is on the right side. + * + * @author Stefan Deusch + */ +class BrowsePane extends ModalContainer + implements DRConstants, ChangeListener, RequestListener { + + private Component m_folderContent; + private Component m_destinationFolderPanel; + private Component m_newFileForm; + private Component m_newFolderForm; + private Component m_errorMsgPanel; + private DestinationFolderForm m_destinationFolderForm; + private ErrorMessageLabel m_errorMsgLabel; + private Container m_mainBrowseContainer; + + private TabbedPane m_mainTabPane; + + private Tree m_tree; + + + private BigDecimalParameter m_rootFolderIdParam = new BigDecimalParameter(ROOTFOLDER_ID_PARAM_NAME); + private BigDecimalParameter m_selFolderIdParam = new BigDecimalParameter(SEL_FOLDER_ID_PARAM_NAME); + private BigDecimalParameter m_fileIdParam = new BigDecimalParameter(FILE_ID_PARAM_NAME); + private StringParameter m_rootAddDocParam= new StringParameter(ROOT_ADD_DOC_PARAM_NAME); + + /** + * Default constructor + */ + + public BrowsePane() { + + m_mainTabPane = new TabbedPane(); + + m_mainBrowseContainer = new BoxPanel(); + m_mainTabPane.addTab(WS_BROWSE_TITLE, + m_mainBrowseContainer); + + m_mainBrowseContainer.setClassAttr("sidebarNavPanel"); + //m_mainBrowseContainer.setAttribute("navbar-title", "Folders"); + + BoxPanel leftSide = new BoxPanel(); + leftSide.setClassAttr("navbar"); + m_tree = new SuperTree(new RepositoriesSuperTreeModel()); + m_tree.addChangeListener(this); + leftSide.add(m_tree); + + m_mainBrowseContainer.add(leftSide); + + /* + * Create all panels on the right side. + */ + + SegmentedPanel rightSide = new SegmentedPanel(); + rightSide.setClassAttr("main"); + + m_folderContent = makeContentPanel(rightSide); + + m_mainBrowseContainer.add(rightSide); + + add(m_mainTabPane); + + m_newFileForm = makeFileUploadForm(); + add(m_newFileForm); + + m_newFolderForm = makeFolderCreateForm(); + add(m_newFolderForm); + + m_destinationFolderPanel = makeExpandFolderPanel(); + add(m_destinationFolderPanel); + + m_errorMsgPanel = makeErrorMsgPanel(); + add(m_errorMsgPanel); + } + + /** + * Register the page the fist time + */ + @Override + public void register(Page p) { + p.addGlobalStateParam(m_rootFolderIdParam); + p.addGlobalStateParam(m_selFolderIdParam); + p.addGlobalStateParam(m_rootAddDocParam); + p.addGlobalStateParam(m_fileIdParam); + + p.addRequestListener(this); + + super.register(p); + } + + /** + * Checks if a folder is selected in the page state and consequently + * hides or shows the Folder Contents or Folder Action panels. + */ + public void pageRequested(RequestEvent e) { + PageState state = e.getPageState(); + + BigDecimal fid = (BigDecimal) state.getValue(m_fileIdParam); + + boolean display = false; + String key = (String) m_tree.getSelectedKey(state); + + // start out with root folder selected and open + if (key == null) { + key = DRUtils.getRootFolder(state).getID().toString(); + m_tree.setSelectedKey(state, key); + display = true; + } + + // need this only when coming from 1-file page + if (fid != null) { + try { + File file = new File(fid); + + ResourceImpl parent = (ResourceImpl) file.getParent(); + + key = parent.getID().toString(); + + while (!parent.isRoot()) { + parent = (ResourceImpl) parent.getParent(); + m_tree.expand(parent.getID().toString(), state); + } + } catch (DataObjectNotFoundException exc) { + exc.printStackTrace(); + } + + // to display this file's folder in the table + m_tree.setSelectedKey(state, key); + + // now wipe out file param to avoid trouble elsewhere + state.setValue(m_fileIdParam, null); + } + + // finally expand selected folder + m_tree.expand(key, state); + + if (display) { + if( "t".equalsIgnoreCase(((String)state + .getValue(m_rootAddDocParam)))) { + // Entry hook to display FileUpload Form for Root folder + displayFileUpload(state); + } else { + displayFolderContentPanel(state); + } + } + + + } + + /** + * Helper method to communicate selected folder ID to subcomponents. + * Return onle non-null after tree has been displayed at least once. + */ + public BigDecimal getFolderID(PageState state) { + return new BigDecimal((String) m_tree.getSelectedKey(state)); + } + + /** + * Implementation of the change listener, clicking on the folder + * loads the directory on the right side. + */ + public void stateChanged(ChangeEvent e) { + PageState state = e.getPageState(); + + // Display folder on the right side corresponding to the key + displayFolderContentPanel(state); + } + + /** + * Build a panel to display the Folder content of the selected Folder + * and add it as a segment to the passed in Segmented Panel. + */ + private Component makeContentPanel(SegmentedPanel main) { + + Label folder_info_header = new Label + (new GlobalizedMessage("ui.folder.content.header", BUNDLE_NAME)); + folder_info_header.addPrintListener( + new FolderNamePrintListener(m_tree)); + + ActionLink newFileLink = new ActionLink(new Label(FOLDER_NEW_FILE_LINK)); + newFileLink.setClassAttr("actionLink"); + + ActionLink newFolderLink = + new ActionLink(new Label(FOLDER_NEW_FOLDER_LINK)); + newFolderLink.setClassAttr("actionLink"); + + newFileLink.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + displayFileUpload(e.getPageState()); + } + }); + + newFolderLink.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + displayFolderCreate(e.getPageState()); + } + }); + + GridPanel folderGrid = new GridPanel(1); + SimpleContainer pane = new SimpleContainer(); + pane.add(newFileLink); + pane.add(new Label(" ")); + pane.add(newFolderLink); + folderGrid.add(pane, GridPanel.RIGHT | GridPanel.BOTTOM); + folderGrid.add(new FolderContentsTableForm(this, m_tree), + GridPanel.LEFT | GridPanel.BOTTOM); + + return main.addSegment(folder_info_header, + folderGrid); + } + + /** + * Build File upload form + */ + private Component makeFileUploadForm() { + GridPanel gridPanel = new GridPanel(1); + + Label fileUploadFormHeaderLabel = new Label(new GlobalizedMessage("ui.file.upload.header", BUNDLE_NAME)); + fileUploadFormHeaderLabel.addPrintListener( + new FolderNamePrintListener(m_tree)); + + gridPanel.add(fileUploadFormHeaderLabel); + gridPanel.add(new FileUploadForm(this, m_tree)); + + return gridPanel; + + } + + /** + * Build Folder create form + */ + private Component makeFolderCreateForm() { + GridPanel gridPanel = new GridPanel(1); + Label folderCreateFormHeaderLabel = new Label + (new GlobalizedMessage("ui.folder.create.header", BUNDLE_NAME)); + folderCreateFormHeaderLabel.addPrintListener( + new FolderNamePrintListener(m_tree)); + + gridPanel.add(folderCreateFormHeaderLabel); + gridPanel.add(new FolderCreateForm(this, m_tree)); + return gridPanel; + + } + + /** + * Build a destination folders tree. + */ + private Component makeExpandFolderPanel() { + GridPanel gridPanel = new GridPanel(1); + gridPanel.add(DESTINATION_FOLDER_PANEL_HEADER); + m_destinationFolderForm = new DestinationFolderForm(this); + gridPanel.add(m_destinationFolderForm); + return gridPanel; + } + + /* + * Build panel to display error message when copy/move failed. + */ + private Component makeErrorMsgPanel() { + ColumnPanel c = new ColumnPanel(1); + m_errorMsgLabel = new ErrorMessageLabel(); + c.add(m_errorMsgLabel); + + ActionLink link = new ActionLink(ACTION_ERROR_CONTINUE); + link.setClassAttr("actionLink"); + link.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + displayFolderContentPanel(e.getPageState()); + } + }); + + c.add(link); + return c; + } + + public void displayFileUpload(PageState state) { + setVisibleComponent(state, m_newFileForm); + } + + public void displayFolderCreate(PageState state) { + setVisibleComponent(state, m_newFolderForm); + } + + public void displayFolderContentPanel(PageState state) { + setVisibleComponent(state, m_mainTabPane); + } + + public void displayDestinationFolderPanel(PageState state, + Object[] resourceList, + boolean isMove) { + + setVisibleComponent(state, m_destinationFolderPanel); + m_destinationFolderForm.setResourceList(state, resourceList); + if (isMove) { + m_destinationFolderForm.setMove(state); + } else { + m_destinationFolderForm.setCopy(state); + } + } + + public void displayErrorMsgPanel(PageState state, + String action, + ArrayList list) { + + m_errorMsgLabel.setMessages(state, action, list); + + setVisibleComponent(state, m_errorMsgPanel); + } + + + /** + * Error message panel that allows to set customized error + * messages without showing a tomcat stacktrace + */ + private static class ErrorMessageLabel extends SimpleComponent + implements DRConstants { + + private RequestLocal m_msgs; + private RequestLocal m_action; + + public ErrorMessageLabel() { + m_msgs = new RequestLocal(); + m_action = new RequestLocal(); + + } + + /** + * Set list of file/folder that could not be delete/move/copy. + * + * @param action file operation (action, move, copy) + */ + public void setMessages(PageState state, + String action, + ArrayList msgs) { + m_action.set(state, action); + m_msgs.set(state, msgs); + } + + @Override + public void generateXML(PageState state, Element parent) { + Element element = parent.newChildElement("docs:error-label", + DOCS_XML_NS); + element.addAttribute("action", (String) m_action.get(state)); + + ArrayList list = (ArrayList) m_msgs.get(state); + + if (list != null) { + for (int i = 0; i < list.size(); i++) { + Element item = element.newChildElement("docs:item", + DOCS_XML_NS); + item.addAttribute("name", ((String) list.get(i))); + } + } + } + + + } + + /** + * Table Cell Renderer that provides clickable Links to follow + * directory links . + */ + private static class DirLinkRenderer implements ListCellRenderer { + + public Component getComponent(List list, PageState state, + Object value, String key, + int index, boolean isSelected) { + + Link link = new Link((String)value, + "?" + SEL_FOLDER_ID_PARAM.getName() + + "=" + key); + return link; + } + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/CancelButton.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/CancelButton.java new file mode 100644 index 000000000..969fadce3 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/CancelButton.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.form.Submit; +import com.arsdigita.globalization.GlobalizedMessage; + +/** + * Customized Cancel button that takes you 1 level back in + * the browser history. + */ +class CancelButton extends Submit { + public CancelButton(GlobalizedMessage label) { + super(label); + avoidDoubleClick(false); + setAttribute(ON_CLICK, + "history.go(-1); return false;"); + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/DRConstants.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/DRConstants.java new file mode 100644 index 000000000..e523ab59c --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/DRConstants.java @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.parameters.BigDecimalParameter; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.globalization.GlobalizedMessage; + +/** + * Variously used constant objects used in Document Repository UI + * + * @author Stefan Deusch + */ + +public interface DRConstants { + + // PDL vars + String FOLDER_ID = "folderID"; + String IS_LOCKED = "isLocked"; + String IS_MOUNTED = "isMounted"; + String LAST_MODIFIED = "lastModified"; + String MODIFYING_USER = "modifyingUser"; + String MIME_TYPE_LABEL = "mimeTypeDescription"; + String NAME = "name"; + String ABS_PATH = "absPath"; + String NUM_FILES = "numFiles"; + String REPOSITORY_ID = "repositoryID"; + String RESOURCE_ID = "resourceID"; + String SIZE = "size"; + String TYPE = "mimeType"; + String IS_FOLDER = "isFolder"; + + // PDL queries + String GET_ALL_TREES = "com.arsdigita.docrepo.getAllTreesView"; + String GET_REPOSITORIES = "com.arsdigita.docrepo.getRepositoriesView"; + String GET_REPOSITORIES_ROOTS = "com.arsdigita.docrepo.getRepositoryRoots"; + String GET_CHILDREN = "com.arsdigita.docrepo.getChildren"; + + // PDL associations + String FILES = "files"; + String FOLDERS = "folders"; + + /** + * The XML namespace. + */ + String DOCS_XML_NS = "http://www.arsdigita.com/docs-ui/1.0"; + + /** + * Globalization resource + */ + String BUNDLE_NAME = "com.arsdigita.docrepo.DRResources"; + + /** + * Global state parameters. + */ + String ROOTFOLDER_ID_PARAM_NAME = "r_id"; + BigDecimalParameter ROOTFOLDER_ID_PARAM = new BigDecimalParameter(ROOTFOLDER_ID_PARAM_NAME); + + String SEL_FOLDER_ID_PARAM_NAME = "f_id"; + BigDecimalParameter SEL_FOLDER_ID_PARAM = new BigDecimalParameter(SEL_FOLDER_ID_PARAM_NAME); + + String FILE_ID_PARAM_NAME = "d_id"; + BigDecimalParameter FILE_ID_PARAM = new BigDecimalParameter(FILE_ID_PARAM_NAME); + + /** + * DM Index page title + */ + Label PAGE_TITLE_LABEL = new Label + (new GlobalizedMessage("ui.title", BUNDLE_NAME)); + + /** + * DM File Info Page + */ + Label FILE_INFO_LABEL = new Label + (new GlobalizedMessage("ui.fileinfo.title", BUNDLE_NAME)); + + // File Info Navigational Tabs + Label FILE_INFO_PROPERTIES_TITLE = new Label + (new GlobalizedMessage("ui.fileinfo.properties.title", BUNDLE_NAME)); + + Label FILE_INFO_HISTORY_TITLE = new Label + (new GlobalizedMessage("ui.fileinfo.history.title", BUNDLE_NAME)); + + Label FILE_INFO_COMMENTS_TITLE = new Label + (new GlobalizedMessage("ui.fileinfo.comments.title", BUNDLE_NAME)); + + Label FILE_INFO_LINKS_TITLE = new Label + (new GlobalizedMessage("ui.fileinfo.links.title", BUNDLE_NAME)); + + Label GO_BACK_LABEL = new Label + (new GlobalizedMessage("ui.fileinfo.goback.label", BUNDLE_NAME)); + + /** + * Navigational dimensional bar + */ + Label MY_WORKSPACE_LABEL = new Label + (new GlobalizedMessage("ui.workspace.title", BUNDLE_NAME)); + + Label SIGN_OUT_LABEL = new Label + (new GlobalizedMessage("ui.nav.signout", BUNDLE_NAME)); + + Label HELP_LABEL = new Label + (new GlobalizedMessage("ui.nav.help", BUNDLE_NAME)); + + + /** + * Page navigational tabs + */ + Label WS_BROWSE_TITLE = new Label + (new GlobalizedMessage("ui.workspace.browse.title", BUNDLE_NAME)); + + Label WS_SEARCH_TITLE = new Label + (new GlobalizedMessage("ui.workspace.search.title", BUNDLE_NAME)); + + Label WS_REPOSITORIES_TITLE = new Label + (new GlobalizedMessage("ui.workspace.repositories.title", BUNDLE_NAME)); + + /** + * One Folder content + */ + Label FOLDER_INFORMATION_HEADER = new Label + (new GlobalizedMessage("ui.folder.content.header", BUNDLE_NAME)); + + /** + * Repositories + */ + Label REPOSITORIES_INFORMATION_HEADER = new Label + (new GlobalizedMessage("ui.repositories.content.header", BUNDLE_NAME)); + + GlobalizedMessage REPOSITORY_RECENTDOCS_EMPTY + = new GlobalizedMessage("ui.repositories.recentDocs.empty", BUNDLE_NAME); + + /** + * File Uplaod Form + */ + Label FILE_UPLOAD_FORM_HEADER = new Label + (new GlobalizedMessage("ui.file.upload.header", BUNDLE_NAME)); + + /** + * Folder Create Form + */ + Label FOLDER_CREATE_FORM_HEADER = new Label + (new GlobalizedMessage("ui.folder.create.header", BUNDLE_NAME)); + + /** + * File Properties + */ + Label FILE_PROPERTIES_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.properties.header", BUNDLE_NAME)); + + /** + * File Edit Panel + */ + Label FILE_EDIT_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.edit.header", BUNDLE_NAME)); + + GlobalizedMessage FILE_EDIT_ACTION_DESCRIPTION = + new GlobalizedMessage("ui.fileinfo.edit.action.description", BUNDLE_NAME); + + /** + * File Upload Panel + */ + Label FILE_UPLOAD_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.upload.header", BUNDLE_NAME)); + + GlobalizedMessage FILE_UPLOAD_INITIAL_TRANSACTION_DESCRIPTION = + new GlobalizedMessage("ui.fileinfo.upload.initialversion.description", BUNDLE_NAME); + + /** + * File Download Panel + */ + Label FILE_DOWNLOAD_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.download.header", BUNDLE_NAME)); + + /** + * File-Send-to-Colleague Form + */ + Label FILE_SEND_COLLEAGUE_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.sendcolleague.header", BUNDLE_NAME)); + + /** + * File-Delete Form + */ + Label FILE_DELETE_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.delete.header", BUNDLE_NAME)); + + /** + * File Action Panel + */ + Label FILE_ACTION_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.actions.header", BUNDLE_NAME)); + + /** + * File Revision History Panel + */ + + Label FILE_REVISION_HISTORY_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.history.header", BUNDLE_NAME)); + + + /** + * File Feedback Panel + */ + + Label FILE_FEEDBACK_HEADER = new Label + (new GlobalizedMessage("ui.fileinfo.feedback.header", BUNDLE_NAME)); + + + /** + * Action Panel Constants + */ + + Label DESTINATION_FOLDER_PANEL_HEADER = new Label( + new GlobalizedMessage("ui.folder.destination.list.header", BUNDLE_NAME)); + + Label FOLDER_EMPTY_LABEL = new Label( + new GlobalizedMessage("ui.folder.empty", BUNDLE_NAME)); + + GlobalizedMessage FOLDER_NEW_FOLDER_LINK = + new GlobalizedMessage("ui.action.newfolder", BUNDLE_NAME); + + GlobalizedMessage FOLDER_NEW_FILE_LINK = + new GlobalizedMessage("ui.action.newfile", BUNDLE_NAME); + + Label ACTION_CUT_LABEL = new Label( + new GlobalizedMessage("ui.action.edit.cut", BUNDLE_NAME)); + + Label ACTION_COPY_LABEL = new Label( + new GlobalizedMessage("ui.action.edit.copy", BUNDLE_NAME)); + + Label ACTION_DELETE_LABEL = new Label( + new GlobalizedMessage("ui.action.edit.delete", BUNDLE_NAME)); + + GlobalizedMessage ACTION_DELETE_CONFIRM = + new GlobalizedMessage("ui.action.delete.confirm", BUNDLE_NAME); + + Label ACTION_ERROR_LABEL = new Label( + new GlobalizedMessage("ui.action.error", BUNDLE_NAME)); + + Label ACTION_ERROR_CONTINUE = new Label( + new GlobalizedMessage("ui.action.error.continue", BUNDLE_NAME)); + + String ACTION_CUT_VALUE = "resource-cut"; + String ACTION_COPY_VALUE = "resource-copy"; + String ACTION_DELETE_VALUE = "resource-delete"; + + GlobalizedMessage ACTION_DELETE_SUBMIT = + new GlobalizedMessage("ui.action.delete.submit", BUNDLE_NAME); + + GlobalizedMessage ACTION_COPY_SUBMIT = + new GlobalizedMessage("ui.action.copy.submit", BUNDLE_NAME); + + GlobalizedMessage ACTION_MOVE_SUBMIT = + new GlobalizedMessage("ui.action.move.submit", BUNDLE_NAME); + + + /** + * Portlet Panel Constants + */ + GlobalizedMessage ROOT_ADD_RESOURCE_LINK = + new GlobalizedMessage("ui.portlet.action.newresource", BUNDLE_NAME); + + String ROOT_ADD_DOC_PARAM_NAME = "root_add_doc"; + StringParameter ROOT_ADD_DOC_PARAM = + new StringParameter(ROOT_ADD_DOC_PARAM_NAME); + + + /** + * File Action Panel Constants + */ + + GlobalizedMessage FILE_EDIT_LINK = + new GlobalizedMessage("ui.fileinfo.edit.link", BUNDLE_NAME); + + GlobalizedMessage FILE_NEW_VERSION_LINK = + new GlobalizedMessage("ui.fileinfo.newversion.link", BUNDLE_NAME); + + GlobalizedMessage FILE_DOWNLOAD_LINK = + new GlobalizedMessage("ui.fileinfo.download.link", BUNDLE_NAME); + + GlobalizedMessage FILE_SEND_COLLEAGUE_LINK = + new GlobalizedMessage("ui.fileinfo.sendcolleague.link", BUNDLE_NAME); + + GlobalizedMessage FILE_DELETE_LINK = + new GlobalizedMessage("ui.fileinfo.delete.link", BUNDLE_NAME); + + + /** + * Error messages + */ + + GlobalizedMessage FOLDER_PARENTNOTFOUND_ERROR = + new GlobalizedMessage("ui.error.parentnotfound", BUNDLE_NAME); + + GlobalizedMessage RESOURCE_EXISTS_ERROR = + new GlobalizedMessage("ui.error.resourceexists", BUNDLE_NAME); + + GlobalizedMessage EMAIL_INVALID_ERROR = + new GlobalizedMessage("ui.email.formatinvalid", BUNDLE_NAME); + + GlobalizedMessage DIFFERENT_MIMETYPE_ERROR = + new GlobalizedMessage("ui.error.mimetype", BUNDLE_NAME); + + + /** + * FILE DELETE link + */ + + GlobalizedMessage FILE_DELETE_CONFIRM = + new GlobalizedMessage("ui.filedelete.confirm", BUNDLE_NAME); + + // Labels for Files + GlobalizedMessage FILE_NAME = + new GlobalizedMessage("ui.file.name", BUNDLE_NAME); + + GlobalizedMessage FILE_NAME_REQUIRED = + new GlobalizedMessage("ui.file.name.required", BUNDLE_NAME); + + GlobalizedMessage FILE_UPLOAD_ADD_FILE = + new GlobalizedMessage("ui.file.upload", BUNDLE_NAME); + + GlobalizedMessage FILE_SOURCE = + new GlobalizedMessage("ui.file.source", BUNDLE_NAME); + + GlobalizedMessage FILE_DESCRIPTION = + new GlobalizedMessage("ui.file.description", BUNDLE_NAME); + + GlobalizedMessage FILE_VERSION_DESCRIPTION = + new GlobalizedMessage("ui.file.version.description", BUNDLE_NAME); + + GlobalizedMessage FILE_KEYWORDS = + new GlobalizedMessage("ui.file.keywords", BUNDLE_NAME); + + GlobalizedMessage FILE_SAVE = + new GlobalizedMessage("ui.file.save", BUNDLE_NAME); + + GlobalizedMessage FILE_SUBMIT = + new GlobalizedMessage("ui.file.submit", BUNDLE_NAME); + + GlobalizedMessage CANCEL = + new GlobalizedMessage("ui.cancel", BUNDLE_NAME); + + /** + * Folder parameters + */ + String FOLDER_NAME = "folder-name"; + String FOLDER_DESCRIPTION = "folder-description"; + + Label FOLDER_NAME_LABEL = new Label( + new GlobalizedMessage("ui.folder.name", BUNDLE_NAME)); + + Label FOLDER_DESCRIPTION_LABEL = new Label( + new GlobalizedMessage("ui.folder.description", BUNDLE_NAME)); + + GlobalizedMessage FOLDER_SAVE = + new GlobalizedMessage("ui.folder.save", BUNDLE_NAME); + + /** + * Repsitories Selection Form + */ + GlobalizedMessage REPOSITORIES_MOUNTED_SAVE = + new GlobalizedMessage("ui.repositories.mounted.save", BUNDLE_NAME); + + /** + * Send to colleague form variables. + */ + + Label SEND_FRIEND_FORM_EMAIL_SUBJECT = new Label( + new GlobalizedMessage("ui.send.friend.email.subject", BUNDLE_NAME)); + + Label SEND_FRIEND_FORM_EMAIL_LIST = new Label( + new GlobalizedMessage("ui.send.friend.email.list", BUNDLE_NAME)); + + Label SEND_FRIEND_FORM_DESCRIPTION = new Label( + new GlobalizedMessage("ui.send.friend.description", BUNDLE_NAME)); + + GlobalizedMessage SEND_FRIEND_FORM_SUBMIT = + new GlobalizedMessage("ui.send.friend.submit", BUNDLE_NAME); +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/DRDispatcher.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/DRDispatcher.java new file mode 100644 index 000000000..3fb797bbc --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/DRDispatcher.java @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + + +import com.arsdigita.bebop.ActionLink; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Page; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.TabbedPane; +import com.arsdigita.bebop.event.ActionEvent; +import com.arsdigita.bebop.event.ActionListener; +import com.arsdigita.bebop.event.PrintEvent; +import com.arsdigita.bebop.event.PrintListener; +import com.arsdigita.bebop.page.BebopMapDispatcher; +import com.arsdigita.dispatcher.DispatcherHelper; +import com.arsdigita.dispatcher.ObjectNotFoundException; +import com.arsdigita.dispatcher.RequestContext; +import com.arsdigita.docrepo.File; +import com.arsdigita.kernel.permissions.PrivilegeDescriptor; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.web.Web; +import com.arsdigita.persistence.Session; +import com.arsdigita.persistence.SessionManager; +import com.arsdigita.persistence.DataQuery; +import com.arsdigita.util.UncheckedWrapperException; +import org.apache.log4j.Category; + +import java.io.*; +import java.math.BigDecimal; + +/** + * Dispatcher for document repository application. + * + * @author Stefan Deusch + * @version $Id: DRDispatcher.java pboy $ + */ + +public class DRDispatcher extends BebopMapDispatcher implements DRConstants { + + private static Category s_log = Category.getInstance + (DRDispatcher.class.getName()); + + /** + * Default constructor instantiating the URL-page map. + */ + public DRDispatcher() { + addPage("", buildDMIndexPage(), true); + addPage("file", buildFileInfoPage()); + } + + /** + * Build index page for the document repository, + */ + + private Page buildDMIndexPage() { + + Page p = new DocrepoBasePage(); + + /** + * Create main administration tab. + */ + TabbedPane tb = new TabbedPane(); + tb.setIdAttr("page-body"); + + //tb.addTab(WS_BROWSE_TITLE, new BrowsePane()); + + /* + * Disable Repositories tab because + * Still need to decide what to do with mounting + * repository, since repository are now application. + * + tb.addTab(WS_REPOSITORIES_TITLE, new RepositoryPane()); + */ + + p.add(new BrowsePane()); + p.lock(); + + return p; + } + + + /** + * Build page for the administration of one file. + * (Implementation according to wireframes at) + */ + private Page buildFileInfoPage() { + + DocrepoBasePage p = new DocrepoBasePage() { + // need to override this to show the File name + @Override + protected void buildTitle() { + Label title = new Label(); + title.addPrintListener(new PrintListener() { + public void prepare(PrintEvent e) { + PageState state = e.getPageState(); + Label t = (Label) e.getTarget(); + BigDecimal fid = + (BigDecimal) state.getValue(FILE_ID_PARAM); + if (fid!=null) { + t.setLabel + (DRUtils.getFile(fid).getName()); + } + } + }); + setTitle(title); + } + }; + + /* Temporary fix to sdm #204233, NavBar of Application allows only + one URL per application, so here we add a Link back to the parent folder + */ + Label backLinkLabel = GO_BACK_LABEL; + backLinkLabel.addPrintListener(new PrintListener() { + public void prepare(PrintEvent e) { + PageState state = e.getPageState(); + + Label t= (Label) e.getTarget(); + String fixed = t.getLabel(e.getPageState()); + String url = Web.getContext().getApplication().getTitle(); + + t.setLabel(fixed + " " + url); + }}); + ActionLink backLink = new ActionLink(backLinkLabel); + backLink.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + PageState state = e.getPageState(); + String url = Web.getContext().getApplication().getPath(); + BigDecimal fid = (BigDecimal) state.getValue(FILE_ID_PARAM); + + if (fid != null) { + url = url + "?d_id="+fid; + } + /* + BigDecimal pid = null; + BigDecimal fid = (BigDecimal) state.getValue(FILE_ID_PARAM); + if (fid!=null) { + pid = DRUtils.getFile(fid).getParentResource().getID(); + } + */ + try { + DispatcherHelper.sendRedirect(state.getRequest(), + state.getResponse(), + url); + } catch (IOException iox) { + throw new RuntimeException("Redirect to Application failed" + +iox); + } + }}); + backLink.setClassAttr("actionLink"); + p.add(backLink); + + // create main File-Info tabs + TabbedPane tb = new TabbedPane(); + tb.setIdAttr("page-body"); + + tb.addTab(FILE_INFO_PROPERTIES_TITLE, new FileInfoPropertiesPane(p)); + tb.addTab(FILE_INFO_HISTORY_TITLE, new FileInfoHistoryPane()); + + /* + * Disable Links tab because we have not + * decided how to link other KnItems to a document. + * 01/04/02 Stefan Deusch + * + tb.addTab(FILE_INFO_LINKS_TITLE, new FileInfoLinksPane()); + */ + p.add(tb); + p.lock(); + + return p; + } + + /** + * convenience wrapper method that allows to register a "" page + * for an index page, if the isIndex flag is try + */ + private void addPage(String url, Page p, boolean isIndex) { + if (isIndex) { + super.addPage("", p); + } + super.addPage(url, p); + } + + /** + * + * @param req + * @param resp + * @param ctx + * @throws IOException + * @throws javax.servlet.ServletException + */ + public void dispatch(javax.servlet.http.HttpServletRequest req, + javax.servlet.http.HttpServletResponse resp, + RequestContext ctx) + throws IOException, javax.servlet.ServletException { + + String url = req.getRequestURI(); + int index = url.lastIndexOf("/download/"); + + if (index > 0) { + s_log.debug("Downloading"); + String str = req.getParameter(FILE_ID_PARAM.getName()); + if (str != null) { + BigDecimal id = new BigDecimal(str); + + File file = null; + try { + file = new File(id); + } catch(DataObjectNotFoundException nfe) { + throw new ObjectNotFoundException( + "The requested file no longer exists."); + } + + //Check to see if current user is allowed to read this file + file.assertPrivilege(PrivilegeDescriptor.READ); + + String mimetype = file.getContentType(); + if (mimetype == null) { + mimetype = File.DEFAULT_MIME_TYPE; + } + + + resp.setContentType(mimetype); + + InputStream is; + final String transaction = req.getParameter("trans_id"); + if (transaction == null || transaction.equals("current")) { + is = file.getInputStream(); + } else { + is = getFileRevision(transaction); + } + + sendToOutput(is, resp.getOutputStream()); + + } + } else { + s_log.debug("dispatching"); + super.dispatch(req, resp, ctx); + } + + } + + private static void sendToOutput(InputStream is, OutputStream os) { + byte[] buf = new byte[8192]; // 8k buffer + + try { + int sz = 0; + while ((sz = is.read(buf, 0 , 8192)) != -1) { + os.write(buf, 0, sz); + } + } catch (IOException iox) { + iox.printStackTrace(); + throw new UncheckedWrapperException("IO Error streaming file", iox); + } finally { + try { + is.close(); + os.close(); + } catch(IOException iox2) { } + } + + } + + private static InputStream getFileRevision(String transaction) { + BigDecimal transactionID = new BigDecimal(transaction); + + Session session = SessionManager.getSession(); + DataQuery query = session.retrieveQuery + ("com.arsdigita.docrepo.getFileRevisionBlob"); + query.setParameter("transactionID", transactionID); + InputStream is = null; + if (query.next()) { + Object blob = query.get("content"); + is = new ByteArrayInputStream((byte[]) blob); + } + + return is; + } + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/DRUtils.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/DRUtils.java new file mode 100644 index 000000000..00b9c2aca --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/DRUtils.java @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + + +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.Tree; +import com.arsdigita.bebop.tree.TreeNode; +import com.arsdigita.dispatcher.ObjectNotFoundException; +import com.arsdigita.docrepo.File; +import com.arsdigita.docrepo.Folder; +import com.arsdigita.docrepo.Repository; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.kernel.Kernel; +import com.arsdigita.kernel.User; +import com.arsdigita.util.UncheckedWrapperException; +import com.arsdigita.web.Application; +import com.arsdigita.web.Web; +import org.apache.log4j.Logger; + +import javax.servlet.http.HttpServletRequest; +import java.math.BigDecimal; +import java.text.NumberFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * Public static helper methods and classes for recurring tasks + * in Document Repository UI. + * + * @author Stefan Deusch + * @version $Id: DRUtils.java pboy $ + */ +public class DRUtils implements DRConstants { + + private static final Logger s_log = Logger.getLogger(DRUtils.class); + + /** + * Gets or sets the root folder id and returns the root Folder + */ + public static Folder getRootFolder(PageState state) { + // Because user-profile is also making use of the doc + // repository for storing user portraits, the current + // application could be something other than a repository. + // So, we'll assume that if the current application is not a + // repository, it is a user-profile application. + + Repository currentRepository = null; + + // Check if it is a repository. + Application app = Web.getContext().getApplication(); + String sAppType = app.getApplicationType().getApplicationObjectType(); + + // Unfortunately, I have to hard-code these constants in here + // because ant forces me to build docs before user-profile. + String sUserProfileBaseObjectType = "com.arsdigita.userprofile.UserProfile"; + String sUserProfileRepoPath = "/cw-admin/user-profile/repository/"; + + if (sAppType.compareTo(sUserProfileBaseObjectType) == 0) { + // This is a user-profile app, so get the repository for + // the user-profile app. + currentRepository = (Repository)Application.retrieveApplicationForPath(sUserProfileRepoPath); + } else { + // Normal repository + currentRepository = (Repository) Web.getContext().getApplication(); + } + + Folder root = currentRepository.getRoot(); + setRoot(state, root); + return root; + } + + /** + * Get the selected folder in the tree node or the root tree id + */ + public static BigDecimal getSelFolderOrRootID(PageState state, TreeNode n) { + String idS = (String) n.getKey(); + + if (idS != null) { + return new BigDecimal(idS); + } + + // No folder is selected. Get root folder. + Folder root = getRootFolder(state); + return root.getID(); + } + + /** + * Change global state parameter of root folder. + */ + public static void setRoot(PageState state, Folder root) { + state.setValue(ROOTFOLDER_ID_PARAM, root.getID()); + } + + + /** + * Get User object from request context. + */ + public static User getUser(PageState state) { + User user = Web.getContext().getUser(); + + if (user == null) { + // User should be authenticated. + throw new RuntimeException("User not logged in"); + } + + return user; + } + + /** + * Wrapper to get the selected folder in a tree. Works only if + * we are already showing an expanded tree. + */ + public static BigDecimal getSelectedFolderID(PageState state, Tree t) { + String id = (String) t.getSelectedKey(state); + + if (id != null) { + return new BigDecimal(id); + } + + throw new RuntimeException("No tree node selected"); + } + + /** + * Attempts to load a file by ID. + */ + public static File getFile(BigDecimal id) { + try { + return new File(id); + } catch(DataObjectNotFoundException nfe) { + throw new ObjectNotFoundException("The requested file no longer exists."); + } + } + + /** + * Get the selected folder in the tree + */ + public static String getFolderName(PageState state, Tree tree) { + BigDecimal id = getSelectedFolderID(state, tree); + Folder folder = null; + + try { + folder = new Folder(id); + } catch(DataObjectNotFoundException nfe) { + throw new UncheckedWrapperException("Folder not found", nfe); + } + + return folder.getName(); + } + + /** + * Extract the true filename from the uploaded filepath name + * taking OS-specific file-separator into account The considered + * OS'es are Windows, Mac, and Linux/Unixes. The default case is + * Linux/Unix. + */ + public static String extractFileName(String rawName, PageState state) { + // Get the page request header and read the User-agent + + HttpServletRequest request = state.getRequest(); + String userAgent = request.getHeader("User-Agent").toUpperCase(); + + char separator; + + // Micro$oft browser + if (userAgent.indexOf("WINDOWS") != -1) { + separator = '\\'; + } + + // MacIntosh browser + else if (userAgent.indexOf("MAC") != -1) { + separator = ':'; + } + + // Default, the nerds who use Linux + else { + separator = '/'; + } + + int idx = rawName.lastIndexOf(separator); + + if (idx != -1) { + return rawName.substring(idx + 1); + } else { + return rawName; + } + } + + /** + * Class to describe and format file sizes in request specific locales + */ + public static class FileSize { + /** + * Chooses the units for the file such that the file size is + * greater or equal unity in the smallest units possible. + */ + public static String formatFileSize(long n, PageState state) { + Locale locale = Kernel.getContext().getLocale(); + + NumberFormat nf = NumberFormat.getNumberInstance(locale); + nf.setMaximumFractionDigits(0); + + // Try finding a good matching going from small to large + // files, assuming that most files will be small. + + double size = (double) n; + + if (size < 1000) { + return nf.format(size) + " B"; + } else if ((size = byteToKilo(n)) < 1000) { + return nf.format(size) + " KB"; + } + + // Must be one MB or larger. Change pricision and keep + // checking. + + nf.setMaximumFractionDigits(2); + + if ((size = byteToMega(n)) < 1000) { + return nf.format(size) + " MB"; + } else { + return nf.format(size) + " GB"; + } + } + + /** + * Wrapper for converting from BigDecimal to long file size + */ + public static String formatFileSize(BigDecimal size, PageState state) { + return formatFileSize(size.longValue(), state); + } + + /* + * Converstion methods + */ + private static double byteToKilo(long size) { + return ((double) size) / 1024.; + } + + private static double byteToMega(long size) { + return ((double) size) / 1048576.; + } + } + + /** + * Class to render java.util.Date in request specific locale + * and pattern. + */ + public static class DateFormat { + /** + * Default Date format should look like this + * 12/19/01 07:21 PM + */ + public static String format(Date date) { + return format(date, "MM/dd/yy hh:mm a"); + } + + /** + * This allows to pass in any formatting strings for the date + */ + public static String format(Date date, String fmt) { + SimpleDateFormat formatter = + new SimpleDateFormat(fmt, Kernel.getContext().getLocale()); + return formatter.format(date); + } + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/DestinationFolderForm.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/DestinationFolderForm.java new file mode 100644 index 000000000..9c0a00922 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/DestinationFolderForm.java @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.FormValidationException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.form.Hidden; +import com.arsdigita.bebop.form.RadioGroup; +import com.arsdigita.bebop.form.Submit; +import com.arsdigita.bebop.parameters.ArrayParameter; +import com.arsdigita.docrepo.File; +import com.arsdigita.docrepo.Folder; +import com.arsdigita.docrepo.Repository; +import com.arsdigita.docrepo.ResourceImpl; +import com.arsdigita.docrepo.Util; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.domain.DomainObjectFactory; +import com.arsdigita.kernel.Kernel; +import com.arsdigita.persistence.DataCollection; +import com.arsdigita.persistence.DataQuery; +import com.arsdigita.persistence.Filter; +import com.arsdigita.persistence.OID; +import com.arsdigita.persistence.PersistenceException; +import com.arsdigita.persistence.Session; +import com.arsdigita.persistence.SessionManager; +import com.arsdigita.web.Web; +import com.arsdigita.xml.Element; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +/** + * Intermediate form of the "Move-to" and "Copy-to" process. + * It shows the folder tree of the repositories expanded + * with checkboxes next to it. + * + * @author David Dao + * @author Stefan Deusch + */ +class DestinationFolderForm extends Form + implements FormInitListener, FormProcessListener, DRConstants { + + private Hidden m_resourceList; + + private ExpandedFolderTree m_radioGroup; + + private Submit m_copySubmit; + private Submit m_moveSubmit; + private BrowsePane m_parent; + + public DestinationFolderForm(BrowsePane parent) { + super("Destination-Folder", new ColumnPanel(1)); + m_parent = parent; + m_resourceList = new Hidden(new ArrayParameter("resourceList")); + add(m_resourceList); + + m_radioGroup = new ExpandedFolderTree(); + + add(m_radioGroup); + + m_copySubmit = new Submit("Copy"); + add(m_copySubmit); + + m_moveSubmit = new Submit("Move"); + add(m_moveSubmit); + addInitListener(this); + addProcessListener(this); + } + + @Override + public void generateXML(PageState ps, Element elt) { + doSubmit(ps); + super.generateXML(ps, elt); + } + + private void doSubmit(PageState ps) { + Object[] list = (Object[]) m_resourceList.getValue(ps); + ArrayList l = new ArrayList(); + for (int i = 0; i < list.length; i++) { + l.add(list[i]); + } + m_radioGroup.setSources(ps, l); + } + + public void setResourceList(PageState state, Object[] list) { + m_resourceList.setValue(state, list); + } + + public void setCopy(PageState state) { + state.setVisible(m_moveSubmit, false); + state.setVisible(m_copySubmit, true); + } + + public void setMove(PageState state) { + state.setVisible(m_moveSubmit, true); + state.setVisible(m_copySubmit, false); + } + + public void init(FormSectionEvent e) { + if ( Kernel.getContext().getParty() == null ) { + Util.redirectToLoginPage(e.getPageState()); + } + } + + public void process(FormSectionEvent e) + throws FormProcessException { + PageState state = e.getPageState(); + + boolean isCopy = true; + boolean isError = false; + + ArrayList msgList = new ArrayList(); + if (m_moveSubmit.isSelected(state)) { + isCopy = false; + } + + try { + String parent = (String) m_radioGroup.getValue(state); + if (parent == null) { + throw new FormValidationException( + "Please choose a destination." + ); + } + OID parentOID = + new OID(ResourceImpl.BASE_DATA_OBJECT_TYPE, + new BigDecimal(parent)); + ResourceImpl parentResource = + (Folder) DomainObjectFactory.newInstance(parentOID); + + String[] resourceIDs = (String[]) m_resourceList.getValue(state); + for (int i = 0; i < resourceIDs.length; i++) { + + OID oid = new OID(ResourceImpl.BASE_DATA_OBJECT_TYPE, + new BigDecimal(resourceIDs[i])); + + ResourceImpl resource = null; + try { + resource = + (ResourceImpl) DomainObjectFactory.newInstance(oid); + if (resource.isFile()) { + resource = (File) DomainObjectFactory.newInstance( + new OID( + File.BASE_DATA_OBJECT_TYPE, + new BigDecimal(resourceIDs[i]))); + } + if (isCopy) { + resource.copyTo(parentResource); + } else { + resource.setParent(parentResource); + resource.save(); + } + } catch (PersistenceException exc) { + isError = true; + if (resource != null) { + msgList.add(resource.getName()); + } + // Can't delete file and folder. + } catch (DataObjectNotFoundException exc) { + isError = true; + if (resource != null) { + msgList.add(resource.getName()); + } + // Move on to the next object. + } + } + } catch (DataObjectNotFoundException exc) { + isError = true; + // Unable to find parent object. + } + + if (isError) { + String action = null; + if (isCopy) { + action = "copy"; + } else { + action = "move"; + } + + m_parent.displayErrorMsgPanel(state, action, msgList); + } else { + m_parent.displayFolderContentPanel(state); + } + } + + + /** + * Create an expanded tree of all repositories and folder for given user. + * Each folder has a checkbox to be selected as destination folder. + * The parent folder is not selectable. This class should not be use + * outside of document repository. + */ + + private class ExpandedFolderTree extends RadioGroup { + + private RequestLocal m_srcResources; // Exclusion list of folders. + + public ExpandedFolderTree() { + super("resourceID"); + m_srcResources = new RequestLocal(); + } + + public void setSources(PageState state, ArrayList list) { + m_srcResources.set(state, list); + } + + @Override + public void generateXML(PageState state, Element parent) { + Element treeElement = parent.newChildElement("bebop:tree", BEBOP_XML_NS); + + BigDecimal sourceFolderID = m_parent.getFolderID(state); + + HashMap map = new HashMap(); + map.put(new BigDecimal("-1"), treeElement); + + Session session = SessionManager.getSession(); + DataQuery query = + session + .retrieveQuery("com.arsdigita.docrepo.listDestinationFolders"); + + Repository repository = (Repository) Web.getContext().getApplication(); + BigDecimal rootID = repository.getRoot().getID(); + String path = repository.getRoot().getPath(); + + query.setParameter("rootID", rootID); + query.setParameter("rootPath", path); + //query.setParameter("srcResources", + // (ArrayList) m_srcResources.get(state)); + + // it may be possible to do this with one query but for right + // now this works since this is not a page that is loaded very + // often + ArrayList resources = (ArrayList) m_srcResources.get(state); + if (resources != null) { + DataCollection collection = + session.retrieve(ResourceImpl.BASE_DATA_OBJECT_TYPE); + Iterator iterator = resources.iterator(); + while (iterator.hasNext()) { + collection.addEqualsFilter(ResourceImpl.ID, + iterator.next()); + } + if (resources.size() > 0) { + // we add each path as part of the filter + int item = 0; + while (collection.next()) { + Filter filter = query.addFilter + (" not " + ResourceImpl.PATH + " like " + + ":item" + item); + filter.set("item" + item, + collection.get(ResourceImpl.PATH)); + } + } + } + + query.addOrder(ResourceImpl.PATH); + query.addOrder(ResourceImpl.NAME); + + while (query.next()) { + BigDecimal parentID = (BigDecimal) query.get("parentID"); + BigDecimal resourceID = (BigDecimal) query.get("resourceID"); + + String name = null; + + if (resourceID.equals(rootID)) { + name = "Documents"; + } else { + name = (String) query.get("name"); + } + Element p = (Element) map.get(parentID); + + boolean isSelectable = !resourceID.equals(sourceFolderID); + + if (p != null) { + map.put(resourceID, createNode(state, p, isSelectable, + resourceID, name)); + } + } + + } + + private Element createNode(PageState state, + Element parent, + boolean makeSelectable, + BigDecimal id, + String name) { + + Element element = parent.newChildElement("bebop:t_node", BEBOP_XML_NS); + + element.addAttribute("indentStart", "t"); + element.addAttribute("indentClose", "t"); + if(makeSelectable) { + element.addAttribute("resourceID", id.toString()); + element.addAttribute("radioGroup", "t"); + element.addAttribute("radioGroupName", getName()); + } else { + element.addAttribute("radioGroup", "f"); + } + + Label label = new Label(name); + label.generateXML(state, element); + + return element; + } + } + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/DocrepoBasePage.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/DocrepoBasePage.java new file mode 100644 index 000000000..1f30d1bf8 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/DocrepoBasePage.java @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + + +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.Container; +import com.arsdigita.bebop.DimensionalNavbar; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Link; +import com.arsdigita.bebop.Page; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.bebop.event.PrintEvent; +import com.arsdigita.bebop.event.PrintListener; +import com.arsdigita.bebop.parameters.IntegerParameter; +import com.arsdigita.docrepo.util.GlobalizationUtil; +import com.arsdigita.kernel.Kernel; +import com.arsdigita.kernel.permissions.PermissionDescriptor; +import com.arsdigita.kernel.permissions.PermissionService; +import com.arsdigita.kernel.permissions.PrivilegeDescriptor; +import com.arsdigita.util.Assert; +import com.arsdigita.web.Application; +import com.arsdigita.web.Web; +import com.arsdigita.xml.Element; +import org.apache.log4j.Logger; + +/** + *

BasePage class

+ * + * + * @author Jim Parsons + */ + +public class DocrepoBasePage extends Page { + + private final Container m_global; + private final Container m_header; + private final Container m_body; + private final Container m_footer; + + private IntegerParameter m_selected = new IntegerParameter("m"); + + public static final String DOC_GLOBAL_ELEMENT = "docs:global"; + public static final String DOC_HEADER_ELEMENT = "docs:header"; + public static final String DOC_BODY_ELEMENT = "docs:body"; + public static final String DOC_FOOTER_ELEMENT = "docs:footer"; + public static final String DOC_XML_NS = + "http://www.redhat.com/docs/1.0"; + + private static final Logger s_log = Logger.getLogger(DocrepoBasePage.class); + + /* + * There are 2 views: user and admin. + * m_view determines which context bar and + * view link to show. + */ + private String m_view; + + private Link m_viewLink; + + private boolean CHECK_PERMISSION = true; + + public DocrepoBasePage() { + this(null); + } + + /** + * @param view A String that specifies which application view to + * show. Valid values: "user", "admin" and "null". If view is + * "null", there will be no right-hand navigation link. Note - + * We've decided not to have the right-hand navigation link at + * all. Instead, you should create tabs. So, once the + * applications are migrated, view will always be null and we can + * remove view altogether. + */ + public DocrepoBasePage(String view) { + super(new Label(), new SimpleContainer()); + + setClassAttr("DOCS"); + + m_panel = new Panel(); + + addGlobalStateParam(m_selected); + + m_global = new SimpleContainer + (DOC_GLOBAL_ELEMENT, DOC_XML_NS); + m_header = new SimpleContainer + (DOC_HEADER_ELEMENT, DOC_XML_NS); + m_body = new SimpleContainer + (DOC_BODY_ELEMENT, DOC_XML_NS); + m_footer = new SimpleContainer + (DOC_FOOTER_ELEMENT, DOC_XML_NS); + + super.add(m_global); + super.add(m_header); + super.add(m_body); + super.add(m_footer); + + + m_view = view; + + } + + + @Override + public void lock() { + buildPage(); + + super.lock(); + } + + // Only the PortalPage.lock() should invoke this + // method, though users of this class may sometimes want to + // override this method. + protected final void buildPage() { + buildTitle(); + buildContextBar(); + buildGlobal(getGlobal()); + buildHeader(getHeader()); + buildBody(getBody()); + buildFooter(getFooter()); + } + + + + protected void buildTitle() { + class ApplicationAdminLabelPrinter implements PrintListener { + public void prepare(PrintEvent e) { + Label targetLabel = (Label)e.getTarget(); + PageState pageState = e.getPageState(); + + Application application = Web.getContext().getApplication(); + + Assert.exists(application, Application.class); + + targetLabel.setLabel + (application.getTitle() + " Administration"); + } + } + + if (m_view != null && m_view.equals("admin")) { + setTitle(new Label(new ApplicationAdminLabelPrinter())); + } else { + setTitle(new Label(new CurrentApplicationLabelPrinter())); + } + } + + protected void buildContextBar() { + DimensionalNavbar navbar = new DimensionalNavbar(); + + navbar.setClassAttr("portalNavbar"); + + navbar.add(new Link(new ParentApplicationLinkPrinter())); + + navbar.add(new Link(new CurrentApplicationLinkPrinter())); + + getHeader().add(navbar); + } + + protected void buildGlobal(Container global) { + Link link = new Link( new Label(GlobalizationUtil.globalize("cw.workspace.sign_out")), "/register/logout"); + + link.setClassAttr("signoutLink"); + + getGlobal().add(link); + } + + protected void buildHeader(Container header) { + if (m_view != null) { + if (m_view.equals("user")) { + m_viewLink = new Link + ( new Label(GlobalizationUtil.globalize("cw.doc.ui.admin_view")), "./admin/index.jsp") { + public boolean isVisible(PageState ps) { + return userIsAdmin(ps); + }}; + } else if (m_view.equals("admin")) { + m_viewLink = new Link( new Label(GlobalizationUtil.globalize("cw.doc.ui.user_view")), "../index.jsp"); + } + } + + if (m_viewLink != null) { + m_viewLink.setClassAttr("portalControl"); + + header.add(m_viewLink); + } + } + + protected void buildBody(Container body) { + // Nothing by default + } + + protected void buildFooter(Container footer) { + // Nothing by default + } + + + + private class Panel extends SimpleContainer { + @Override + public void generateXML(PageState ps, Element p) { + Component selected = getSelected(ps); + if (selected == null) { + super.generateXML(ps, p); + } else { + SimpleContainer fakeBody = + new SimpleContainer(DOC_BODY_ELEMENT, + DOC_XML_NS); + fakeBody.add(selected); + + Element parent = generateParent(p); + + m_header.generateXML(ps, parent); + fakeBody.generateXML(ps, parent); + m_footer.generateXML(ps, parent); + } + } + } + + + /** + * Makes the given component the only visible component between + * the header and footer of this page. + */ + public void goModal(PageState ps, Component c) { + Component old = getSelected(ps); + if (old != null) { + old.setVisible(ps, false); + } + c.setVisible(ps, true); + setSelected(ps, c); + } + + private Component getSelected(PageState ps) { + Integer stateIndex = (Integer) ps.getValue(m_selected); + Component c = null; + if (stateIndex != null) { + c = getComponent(stateIndex.intValue()); + } + + return c; + } + + private void setSelected(PageState ps, Component c) { + if (c == null) { + ps.setValue(m_selected, null); + } else { + ps.setValue(m_selected, new Integer(stateIndex(c))); + } + } + + /** + * Clears the currently selected modal component if it has been set. + */ + public void goUnmodal(PageState ps) { + Component old = getSelected(ps); + if (old != null) { + old.setVisible(ps, false); + } + setSelected(ps, null); + } + + private boolean userIsAdmin(PageState ps) { + PermissionDescriptor permDescriptor = + new PermissionDescriptor(PrivilegeDescriptor.ADMIN, + Web.getContext().getApplication(), + Kernel.getContext().getParty()); + return PermissionService.checkPermission(permDescriptor); + } + + /** + * Adds a component to the body. + * + * @param pc the component to be added + */ + @Override + public void add(Component pc) { + // Assert.assertNotLocked(this); + Assert.isUnlocked(this); + m_body.add(pc); + } + + public Container getGlobal() { + return m_global; + } + + public Container getHeader() { + return m_header; + } + + public Container getBody() { + return m_body; + } + + public Container getFooter() { + return m_footer; + } + + protected class CurrentApplicationLinkPrinter implements PrintListener { + public CurrentApplicationLinkPrinter() { + // Empty + } + + public void prepare(PrintEvent e) { + Link link = (Link) e.getTarget(); + PageState pageState = e.getPageState(); + + Application app = Web.getContext().getApplication(); + + Assert.exists(app, Application.class); + + link.setChild(new Label(app.getTitle())); + link.setTarget(app.getPath()); + } + } + + protected class ParentApplicationLinkPrinter implements PrintListener { + public ParentApplicationLinkPrinter() { + // Empty + } + + public void prepare(PrintEvent e) { + Link link = (Link) e.getTarget(); + PageState pageState = e.getPageState(); + + Application app = Web.getContext().getApplication(); + + Assert.exists(app, Application.class); + + Application parent = app.getParentApplication(); + if (parent != null ) { + link.setChild(new Label(parent.getTitle())); + link.setTarget(parent.getPath()); + } else { + link.setChild(new Label("/")); + link.setTarget(com.arsdigita.web.URL.root().toString()); + } + } + } + + protected class CurrentApplicationLabelPrinter implements PrintListener { + public CurrentApplicationLabelPrinter() { + // Empty + } + + public void prepare(PrintEvent e) { + Label label = (Label) e.getTarget(); + PageState pageState = e.getPageState(); + + Application app = Web.getContext().getApplication(); + + Assert.exists(app, Application.class); + + label.setLabel(app.getTitle()); + } + } + + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/DocsResources.properties b/ccm-docrepo/src/com/arsdigita/docrepo/ui/DocsResources.properties new file mode 100644 index 000000000..3cfca07f0 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/DocsResources.properties @@ -0,0 +1 @@ +cw.docs.ui.=    diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileActionPane.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileActionPane.java new file mode 100644 index 000000000..972eaae43 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileActionPane.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + + +import com.arsdigita.bebop.ActionLink; +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Link; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.bebop.event.ActionEvent; +import com.arsdigita.bebop.event.ActionListener; +import com.arsdigita.bebop.event.PrintEvent; +import com.arsdigita.bebop.event.PrintListener; +import com.arsdigita.dispatcher.DispatcherHelper; +import com.arsdigita.dispatcher.ObjectNotFoundException; +import com.arsdigita.docrepo.File; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.util.UncheckedWrapperException; +import com.arsdigita.kernel.Kernel; +import com.arsdigita.kernel.KernelExcursion; +import com.arsdigita.web.Web; +import org.apache.log4j.Logger; + +//import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.math.BigDecimal; + +/** + * This component shows the meta data of a file with links to + * administrative actions on it. + * + * @author Stefan Deusch + */ +class FileActionPane extends ColumnPanel + implements DRConstants +{ + + private FileInfoPropertiesPane m_parent; + private RequestLocal m_fileData; + private ActionLink m_newVersion; + private Link m_download; + private ActionLink m_email; + private ActionLink m_delete; + + private static final Logger s_log = Logger.getLogger(FileActionPane.class); + + /** + * Constructor + */ + FileActionPane(FileInfoPropertiesPane parent) { + super(1); + + m_parent = parent; + + m_fileData = new RequestLocal() { + protected Object initialValue(PageState state) { + BigDecimal id = (BigDecimal) state.getValue(FILE_ID_PARAM); + File file = null; + try { + file = new File(id); + } catch(DataObjectNotFoundException nfe) { + throw new ObjectNotFoundException("The requested file no longer exists."); + } + return file; + } + }; + + + m_newVersion = addActionLink(FILE_NEW_VERSION_LINK); + + PrintListener printListener = new PrintListener() { + public void prepare(PrintEvent e) { + Link l = (Link) e.getTarget(); + PageState state = e.getPageState(); + File f = getFile(state); + l.setTarget("download/" + f.getName() + "?" + + FILE_ID_PARAM.getName() + "=" + f.getID()); + } + }; + + m_download = new Link(new Label(FILE_DOWNLOAD_LINK), + printListener); + m_download.setClassAttr("actionLink"); + add(m_download); + + m_email = addActionLink(FILE_SEND_COLLEAGUE_LINK); + m_delete = addActionLink(FILE_DELETE_LINK); + + m_newVersion.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + m_parent.displayUploadForm(e.getPageState()); + } + }); + + + m_email.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + m_parent.displaySendColleagueForm(e.getPageState()); + + } + }); + + m_delete.addActionListener(new DeleteListener()); + m_delete.setConfirmation(FILE_DELETE_CONFIRM.localize().toString()); + } + + + private ActionLink addActionLink(GlobalizedMessage msg) { + ActionLink ln = new ActionLink(new Label(msg)); + ln.setClassAttr("actionLink"); + this.add(ln); + return ln; + } + + /** + * return File initialized in RequestLocal + */ + private File getFile(PageState s) { + return (File)m_fileData.get(s); + } + + + /** + * Delete Listener of a file. + */ + private final class DeleteListener implements ActionListener { + + public void actionPerformed(ActionEvent e) { + PageState state = e.getPageState(); + final File file = getFile(state); + String parentFolderID = file.getParent().getID().toString(); + + KernelExcursion ex = new KernelExcursion() { + protected void excurse() { + setEffectiveParty(Kernel.getSystemParty()); + file.delete(); + } + }; + ex.run(); + + try { + String appURI = getRedirectURI(state); + + DispatcherHelper + .sendRedirect(state.getRequest(), + state.getResponse(), + appURI+"?"+SEL_FOLDER_ID_PARAM.getName()+"="+ + parentFolderID); + } catch(IOException iox) { + throw new UncheckedWrapperException(iox); + } + } + + private String getRedirectURI(PageState state) { + String appURI = state.getRequestURI(); + s_log.debug("Original app URI: " + appURI); + int idx = appURI.indexOf("/file/"); + appURI = appURI.substring(0, idx); + + final String servletPath = Web.getConfig().getDispatcherServletPath(); + if (appURI.startsWith(servletPath)) { + appURI = appURI.substring(servletPath.length()); + } + + + s_log.debug("New URI: " + appURI); + return appURI; + } + } + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileEditForm.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileEditForm.java new file mode 100644 index 000000000..ff10801a9 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileEditForm.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.FormData; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.event.FormValidationListener; +import com.arsdigita.bebop.form.Submit; +import com.arsdigita.bebop.form.TextArea; +import com.arsdigita.bebop.form.TextField; +import com.arsdigita.bebop.parameters.NotEmptyValidationListener; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.docrepo.File; +import com.arsdigita.docrepo.Folder; +import com.arsdigita.docrepo.InvalidNameException; +import com.arsdigita.docrepo.Util; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.kernel.Kernel; +//import com.arsdigita.versioning.Transaction; +//import com.arsdigita.versioning.TransactionCollection; + +import javax.servlet.http.HttpServletRequest; +import java.math.BigDecimal; + +/** + * This component allows to change the file name and the + * description of a file. It also serves to associate + * keywords to a file (knowledge object). + * + * @author Stefan Deusch + */ +class FileEditForm extends Form + implements FormValidationListener, + FormProcessListener, + FormInitListener, + DRConstants +{ + + private final static String FILE_EDIT = "file-edit"; + private final static String FILE_EDIT_FNAME = "file-edit-name"; + private final static String FILE_EDIT_DESCRIPTION = "file-edit-description"; + + private StringParameter m_FileName; + private StringParameter m_FileDesc; + private FileInfoPropertiesPane m_parent; + + /** + * Constructor + */ + + public FileEditForm(FileInfoPropertiesPane parent) { + super(FILE_EDIT, new ColumnPanel(2)); + + m_parent = parent; + + m_FileName = new StringParameter(FILE_EDIT_FNAME); + m_FileDesc = new StringParameter(FILE_EDIT_DESCRIPTION); + + add(new Label(FILE_NAME_REQUIRED)); + TextField fnameEntry = new TextField(m_FileName); + fnameEntry.addValidationListener(new NotEmptyValidationListener()); + add(fnameEntry); + + add(new Label(FILE_DESCRIPTION)); + TextArea descArea = new TextArea(m_FileDesc); + descArea.setRows(10); + descArea.setCols(40); + add(descArea); + + Submit submit = new Submit("file-edit-save"); + submit.setButtonLabel(FILE_SAVE); + add(new Label()); // spacer + + SimpleContainer sc = new SimpleContainer(); + sc.add(submit); + sc.add(new CancelButton(CANCEL)); + + add(sc); + + addInitListener(this); + addProcessListener(this); + addValidationListener(this); + } + + /** + * Initializer to pre-fill name and description + */ + public void init(FormSectionEvent e) + throws FormProcessException { + PageState state = e.getPageState(); + + if ( Kernel.getContext().getParty() == null ) { + Util.redirectToLoginPage(state); + } + + FormData data = e.getFormData(); + + BigDecimal id = (BigDecimal) state.getValue(FILE_ID_PARAM); + File file = DRUtils.getFile(id); + + data.put(FILE_EDIT_FNAME, file.getName()); + data.put(FILE_EDIT_DESCRIPTION, file.getDescription()); + } + + /** + * read form and update + */ + public void process(FormSectionEvent e) + throws FormProcessException { + PageState state = e.getPageState(); + HttpServletRequest req = state.getRequest(); + FormData data = e.getFormData(); + + String fname = (String) data.get(FILE_EDIT_FNAME); + String fdesc = (String) data.get(FILE_EDIT_DESCRIPTION); + + File file = DRUtils.getFile + ((BigDecimal) state.getValue(FILE_ID_PARAM)); + file.setName(file.appendExtension(fname)); + file.setDescription(fdesc); + file.applyTag(FILE_EDIT_ACTION_DESCRIPTION.localize(req).toString()); + file.save(); // creates a new revision + + + m_parent.displayPropertiesAndActions(state); + } + + /** + * Test if the new name already exists in the current folder + */ + + public void validate(FormSectionEvent event) + throws FormProcessException { + + PageState state = event.getPageState(); + FormData data = event.getFormData(); + HttpServletRequest req = state.getRequest(); + + File file = DRUtils.getFile + ((BigDecimal) state.getValue(FILE_ID_PARAM)); + + // Construct a name with the optional extension + + String name = file.appendExtension + ((String) data.get(FILE_EDIT_FNAME)); + + if (!file.isValidNewName(name)) { + data.addError(FILE_EDIT_FNAME, + "Not a valid new name for this file"); + } + + // Verify that the new name does not correspond to an existing + // resource (file or folder) + + if (!name.equals(file.getName())) { + try { + Folder parent = (Folder) file.getParent(); + parent.getResourceID(name); + data.addError(FILE_EDIT_FNAME, + (String)RESOURCE_EXISTS_ERROR.localize(req)); + } catch(DataObjectNotFoundException nfe) { + // good, so we can rename it + } catch (InvalidNameException ex) { + data.addError(FILE_EDIT_FNAME, + ex.getMessage()); + } + } + } + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileInfoHistoryPane.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileInfoHistoryPane.java new file mode 100644 index 000000000..a95eb9d85 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileInfoHistoryPane.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.Page; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.bebop.SegmentedPanel; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.docrepo.File; +import java.math.BigDecimal; +import com.arsdigita.domain.DataObjectNotFoundException; + +/** + * This component shows the version history of a document. It allows + * to download historical versions. + * + * @author Stefan Deusch + * + */ +class FileInfoHistoryPane extends SimpleContainer + implements DRConstants +{ + private Component m_history; + + // share file instance for all sub components + private RequestLocal m_file; + + public FileInfoHistoryPane() { + + m_file = new RequestLocal() { + @Override + protected Object initialValue(PageState state) { + BigDecimal id = (BigDecimal) state.getValue(FILE_ID_PARAM); + File file = null; + try { + file = new File(id); + } catch(DataObjectNotFoundException nfe) { + // ... + } + return file; + } + }; + + SegmentedPanel main = new SegmentedPanel(); + main.setClassAttr("main"); + + m_history = makeHistoryPane(main); + + add(main); + } + + private Component makeHistoryPane(SegmentedPanel panel) { + + return panel.addSegment(FILE_REVISION_HISTORY_HEADER, + new FileRevisionsTable(this)); + } + + @Override + public void register(Page p) { + p.addGlobalStateParam(FILE_ID_PARAM); + super.register(p); + } + + File getFile(PageState state) { + return (File)m_file.get(state); + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileInfoLinksPane.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileInfoLinksPane.java new file mode 100644 index 000000000..39074adbf --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileInfoLinksPane.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.SimpleContainer; + +/** + * This component shows links to related knowledge objects. + * + * @author Stefan Deusch + * + */ +class FileInfoLinksPane extends SimpleContainer implements DRConstants { + + // To be implemented + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileInfoPropertiesPane.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileInfoPropertiesPane.java new file mode 100644 index 000000000..a98114bb8 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileInfoPropertiesPane.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.ActionLink; +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Page; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.SegmentedPanel; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.bebop.event.ActionEvent; +import com.arsdigita.bebop.event.ActionListener; +import java.util.ArrayList; + +/** + * This component shows all the properties of a file with links + * to administrative actions to change those. + * + * @author Stefan Deusch + */ +class FileInfoPropertiesPane extends SimpleContainer + implements DRConstants +{ + + private ArrayList m_componentList; + + private Component m_properties; + private Component m_upload; + private Component m_sendColleague; + private Component m_edit; + private Component m_action; + + private DocrepoBasePage m_page; + + public FileInfoPropertiesPane(DocrepoBasePage p) { + m_page = p; + + SegmentedPanel main = new SegmentedPanel(); + main.setClassAttr("main"); + + m_componentList = new ArrayList(); + + m_properties = makePropertiesPane(main); + m_componentList.add(m_properties); + + m_edit = makeEditPane(main); + m_componentList.add(m_edit); + + m_action = makeActionPane(main); + m_componentList.add(m_action); + + m_upload = makeUploadPane(main); + m_componentList.add(m_upload); + + m_sendColleague = makeSendColleaguePane(main); + m_componentList.add(m_sendColleague); + + add(main); + } + + private Component makePropertiesPane(SegmentedPanel main) { + SimpleContainer container= new SimpleContainer(); + + container.add(new FilePropertiesPanel()); + ActionLink link = new ActionLink(new Label(FILE_EDIT_LINK)); + link.setClassAttr("actionLink"); + link.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + PageState state = e.getPageState(); + displayEditForm(state); + } + }); + container.add(link); + return main.addSegment(FILE_PROPERTIES_HEADER, container); + } + + private Component makeEditPane(SegmentedPanel main) { + return main.addSegment(FILE_EDIT_HEADER, + new FileEditForm(this)); + } + + private Component makeActionPane(SegmentedPanel main) { + return main.addSegment(FILE_ACTION_HEADER, + new FileActionPane(this)); + } + + private Component makeUploadPane(SegmentedPanel main) { + return main.addSegment(FILE_UPLOAD_HEADER, + new VersionUploadForm(this)); + } + + private Component makeSendColleaguePane(SegmentedPanel main) { + return main.addSegment(FILE_SEND_COLLEAGUE_HEADER, + new FileSendColleagueForm(this)); + } + + public void register(Page p) { + for (int i = 0; i < m_componentList.size(); i++) { + p.setVisibleDefault((Component) m_componentList.get(i), false); + } + p.setVisibleDefault( m_properties, true); + p.setVisibleDefault( m_action, true); + + p.addGlobalStateParam(FILE_ID_PARAM); + + super.register(p); + } + + + /** + * Visibility of components management methods + */ + private void hideAll(PageState state) { + for (int i = 0; i < m_componentList.size(); i++) { + ((Component) m_componentList.get(i)).setVisible(state, false); + } + } + + public void displayPropertiesAndActions(PageState state) { + m_page.goUnmodal(state); + hideAll(state); + m_properties.setVisible(state, true); + m_action.setVisible(state, true); + } + + public void displayEditForm(PageState state) { + m_page.goModal(state, m_edit); + } + + public void displayUploadForm(PageState state) { + m_page.goModal(state, m_upload); + } + + public void displaySendColleagueForm(PageState state) { + m_page.goModal(state, m_sendColleague); + } + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/FilePropertiesPanel.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FilePropertiesPanel.java new file mode 100644 index 000000000..ba44ac1f5 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FilePropertiesPanel.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.SimpleComponent; +import com.arsdigita.mimetypes.MimeType; +import com.arsdigita.docrepo.File; +import com.arsdigita.domain.DataObjectNotFoundException; +//import com.arsdigita.web.Web; +import com.arsdigita.web.URL; +import com.arsdigita.web.ParameterMap; +import com.arsdigita.versioning.TransactionCollection; +import com.arsdigita.xml.Element; +import com.arsdigita.kernel.permissions.PrivilegeDescriptor; +import java.math.BigDecimal; +import javax.servlet.http.HttpServletRequest; +import org.apache.log4j.Logger; + +/** + * A simple custom bebop component that summarizes the properties of a + * file in tabular form. + * + * @author StefanDeusch@computer.org, ddao@arsdigita.com + * @version $Id: FilePropertiesPanel.java pboy $ + */ +class FilePropertiesPanel extends SimpleComponent implements DRConstants { + + private static final Logger s_log = Logger.getLogger + (FilePropertiesPanel.class); + + @Override + public void generateXML(PageState state, Element parent) { + // Get file id. + BigDecimal id = (BigDecimal) state.getValue(FILE_ID_PARAM); + Element element = parent.newChildElement("docs:file-info", DOCS_XML_NS); + + try { + // Retrieve resource properties. + File file = new File(id); + + file.assertPrivilege(PrivilegeDescriptor.READ); + + Element nameElement = + element.newChildElement("docs:name", DOCS_XML_NS); + nameElement.setText(file.getName()); + + Element descriptionElement = + element.newChildElement("docs:description", DOCS_XML_NS); + String description = file.getDescription(); + if (description != null) { + descriptionElement.setText(description); + } + + Element sizeElement = + element.newChildElement("docs:size", DOCS_XML_NS); + sizeElement.setText + (DRUtils.FileSize.formatFileSize(file.getSize(), state)); + + Element typeElement = + element.newChildElement("docs:type", DOCS_XML_NS); + // Retrieve pretty name for a mime type. + MimeType mimeType = MimeType.loadMimeType(file.getContentType()); + + typeElement.setText(mimeType.getLabel()); + + Element lastModifiedElement = + element.newChildElement("docs:last-modified", DOCS_XML_NS); + lastModifiedElement.setText + (DRUtils.DateFormat.format(file.getLastModifiedDate())); + + Element revisionElement = + element.newChildElement("docs:revision", DOCS_XML_NS); + + TransactionCollection tc = + file.getTransactions(); + long numRevs = tc.size(); + revisionElement.setText(numRevs + ""); + + // Must allow for the possibility that not author is available. + + Element authorElement = + element.newChildElement("docs:author", DOCS_XML_NS); + com.arsdigita.kernel.User author = file.getCreationUser(); + if (null != author) { + authorElement.setText(author.getName()); + } else { + authorElement.setText("Unknown"); + } + + Element uriElement = + element.newChildElement("docs:uri", DOCS_XML_NS); + uriElement.setText(makeFileURL(file, state)); + + } catch (DataObjectNotFoundException exc) { + Element notfoundElement = + element.newChildElement("docs:notfound", DOCS_XML_NS); + } + } + + private static String makeFileURL(File file, PageState state) { + final HttpServletRequest req = state.getRequest(); + + final ParameterMap params = new ParameterMap(); + params.setParameter(FILE_ID_PARAM.getName(), file.getID()); + + return URL.here(req, "/download/" + file.getName(), params).toString(); + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileRevisionsTable.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileRevisionsTable.java new file mode 100644 index 000000000..54bc2572f --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileRevisionsTable.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Link; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.Table; +import com.arsdigita.bebop.event.TableActionEvent; +import com.arsdigita.bebop.event.TableActionListener; +import com.arsdigita.bebop.table.TableCellRenderer; +import com.arsdigita.bebop.table.TableModel; +import com.arsdigita.bebop.table.TableModelBuilder; +import com.arsdigita.docrepo.File; +import com.arsdigita.util.LockableImpl; +import com.arsdigita.versioning.Tag; +import com.arsdigita.versioning.TagCollection; +import com.arsdigita.versioning.Transaction; +import com.arsdigita.versioning.TransactionCollection; +import org.apache.log4j.Logger; +import java.math.BigDecimal; + +/** + * This component lists all file revisions in tabular form. + * The right-most column has a button to download that particular + * version. + * + * @author Stefan Deusch + */ + +class FileRevisionsTable extends Table + implements TableActionListener, DRConstants { + + private static Logger s_log = Logger.getLogger(FileRevisionsTable.class); + private FileInfoHistoryPane m_parent; + static String[] s_tableHeaders = { + "", + "Author", + "Date", + "Comments", + "" + }; + + + /** + * Constructor + */ + + public FileRevisionsTable(FileInfoHistoryPane parent) { + + super(new FileRevisionsTableModelBuilder(parent), s_tableHeaders); + m_parent = parent; + + setClassAttr("AlternateTable"); + setWidth("100%"); + setCellRenderers(); + addTableActionListener(this); + } + public void cellSelected(TableActionEvent e) { + + } + public void headSelected(TableActionEvent e) { + throw new UnsupportedOperationException(); + } + + private void setCellRenderers() { + getColumn(4).setCellRenderer(new LinkRenderer()); + } + + private final class LinkRenderer implements TableCellRenderer { + public Component getComponent(Table table, + PageState state, + Object value, + boolean isSelected, + Object key, + int row, + int column) { + if (value != null) { + + File file = m_parent.getFile(state); + Link link = new Link("Download", + "download/?" + + FILE_ID_PARAM.getName() + "=" + file.getID() + "&trans_id=" + key); + link.setClassAttr("downloadLink"); + return link; + + } else { + return new Label(); + } + } + } + +} + +class FileRevisionsTableModelBuilder + extends LockableImpl implements TableModelBuilder { + + private FileInfoHistoryPane m_parent; + + FileRevisionsTableModelBuilder(FileInfoHistoryPane parent) { + m_parent = parent; + } + + public TableModel makeModel(Table t, PageState state) { + return new FileRevisionsTableModel(m_parent.getFile(state), state); + } +} + +class FileRevisionsTableModel implements TableModel, DRConstants { + + private FileInfoHistoryPane m_parent; + private File m_file; + private PageState m_state; + private TransactionCollection m_tc; + private Transaction m_transaction; + private Transaction m_lastContentChange; + private int m_row; + private int m_last = 2; + + FileRevisionsTableModel(File file, PageState state) { + m_file = file; + m_state = state; + + m_tc = m_file.getTransactions(); + m_row = (int)m_tc.size()+1; + m_last = m_row; + + // separate collection from last content changes + } + + public int getColumnCount() { + return 5; + } + + public Object getElementAt(int columnIndex) { + switch (columnIndex) { + case 0 : + return new BigDecimal(m_row); + case 1: { + com.arsdigita.kernel.User user = m_file.getLastModifiedUser(); + if (null == user) { + return "Unknown"; + } else { + return user.getPersonName().toString(); + } + } + case 2: + if(m_row == 0) + return DRUtils.DateFormat.format(m_file.getCreationDate()); + else + return DRUtils.DateFormat.format(m_file.getLastModifiedDate()); + case 3: { + StringBuffer sb = new StringBuffer(); + TagCollection tc = m_transaction.getTags(); + int counter = 0; + while(tc.next()) { + counter++; + Tag t = tc.getTag(); + sb.append(counter + ") " + t.getDescription() + " "); + } + return sb.toString(); + } + case 4: + return "download"; + default: + break; + } + return null; + } + + public Object getKeyAt(int columnIndex) { + if (columnIndex == 4) { + if(m_row == m_last - 1) { + return "current"; + } else { + return m_transaction.getID(); + } + } else { + return m_file.getID() + "." + (m_row); + } + } + + public boolean nextRow() { + m_row--; + if (m_tc.next() ) { + m_transaction = m_tc.getTransaction(); + return true; + } else { + m_tc.close(); + return false; + } + } + + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileSendColleagueForm.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileSendColleagueForm.java new file mode 100644 index 000000000..0bbeb7a54 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileSendColleagueForm.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.FormData; +//import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.form.Submit; +import com.arsdigita.bebop.form.TextArea; +import com.arsdigita.bebop.form.TextField; +import com.arsdigita.bebop.parameters.NotEmptyValidationListener; +import com.arsdigita.docrepo.File; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.mail.Mail; +import com.arsdigita.kernel.Kernel; +import com.arsdigita.util.StringUtils; +import com.arsdigita.docrepo.Util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import javax.mail.MessagingException; +import javax.servlet.http.HttpServletRequest; + +/** + * This component allows the user to send the document to + * someone by e-mail. The document is enclosed as an attachment + * and send using the com.arsdigita.mail package services, this + * package is built ontop of javax.mail. + * + * @see com.arsdigita.mail + * + * @author Stefan Deusch + * @author David Dao + */ + +class FileSendColleagueForm extends Form + implements FormProcessListener, + FormInitListener, + DRConstants +{ + private static final char EMAIL_SEPARATOR = ';'; + private static final String EMAIL_LIST = "emailList"; + private static final String EMAIL_SUBJECT = "subject"; + private static final String DESCRIPTION = "description"; + + private RequestLocal m_fileData; + private TextField m_emailList; + private TextField m_subject; + private TextArea m_message; + + private FileInfoPropertiesPane m_parent; + + FileSendColleagueForm(FileInfoPropertiesPane parent) { + super("FileSendColleagueForm", new ColumnPanel(2)); + m_parent = parent; + + // initialize the file + m_fileData = new RequestLocal() { + protected Object initialValue(PageState state) { + BigDecimal id = (BigDecimal) state.getValue(FILE_ID_PARAM); + File file = null; + try { + file = new File(id); + } catch(DataObjectNotFoundException nfe) { + // ... + } + return file; + } + }; + + add(SEND_FRIEND_FORM_EMAIL_SUBJECT); + m_subject = new TextField(EMAIL_SUBJECT); + m_subject.addValidationListener(new NotEmptyValidationListener()); + add(m_subject); + + add(SEND_FRIEND_FORM_EMAIL_LIST); + m_emailList = new TextField(EMAIL_LIST); + m_emailList.addValidationListener(new NotEmptyValidationListener()); + add(m_emailList); + + add(SEND_FRIEND_FORM_DESCRIPTION); + m_message = new TextArea(DESCRIPTION); + m_message.setRows(10); + m_message.setCols(40); + add(m_message); + + SimpleContainer sc = new SimpleContainer(); + + sc.add(new Submit(SEND_FRIEND_FORM_SUBMIT)); + CancelButton cancel = new CancelButton(CANCEL); + sc.add(cancel); + + add(new Label()); // spacer + add(sc, ColumnPanel.LEFT); + + addInitListener(this); + addProcessListener(this); + } + + private File getFile(PageState s) { + return (File)m_fileData.get(s); + } + + /** + * Pre-fill the e-mail subject field with file name. + */ + public void init(FormSectionEvent e) + throws FormProcessException { + PageState state = e.getPageState(); + + if ( Kernel.getContext().getParty() == null ) { + Util.redirectToLoginPage(state); + return; + } + + FormData data = e.getFormData(); + + data.put(EMAIL_SUBJECT, getFile(state).getName()); + } + + + /** + * No Form validation happens here, the email addresses are parsed + * and the file is e-mailed as attachment. + */ + public void process(FormSectionEvent e) + throws FormProcessException { + + PageState state = e.getPageState(); + FormData data = e.getFormData(); + HttpServletRequest req = state.getRequest(); + + String emailRecpts = (String) m_emailList.getValue(state); + String recipient[] = StringUtils.split(emailRecpts, EMAIL_SEPARATOR); + String subject = (String) m_subject.getValue(state); + + // message to go with the doc attachment + String message = (String) m_message.getValue(state); + + // Sender e-mail address + String from = DRUtils.getUser(state).getPrimaryEmail().toString(); + + File file = getFile(state); + String filename = file.getName(); + String mimeType = file.getContentType(); + byte[] attachment = getBytes(file); + + for (int i=0; i < recipient.length; i++) { + // TODO validate email of recipient for format + sendDocument(recipient[i], + from, + subject, + message, + filename, + mimeType, + attachment); + } + + m_parent.displayPropertiesAndActions(state); + } + + /** + * Send the document as attachement to one e-mail recipient + */ + + private static void sendDocument(String recipient, + String sender, + String subject, + String message, + String filename, + String mimeType, + byte[] attchmnt) { + + try { + Mail mail = new Mail(recipient, sender, subject); + mail.setBody(message); + mail.attach(attchmnt, mimeType, filename); + mail.send(); + } catch (MessagingException exc) { + exc.printStackTrace(); + // log in some buffer, or schedule for re-try later + } + } + + /** + * Get the bytes from the passed in document resource + */ + private static byte[] getBytes(File file) { + ByteArrayOutputStream outputStream = null; + try { + outputStream = new ByteArrayOutputStream(); + InputStream inputStream = file.getInputStream(); + byte[] buf = new byte[8192]; + int sz = 0; + while ((sz = inputStream.read(buf, 0, 8192)) != -1) { + outputStream.write(buf, 0, sz); + } + } catch(IOException iox) { + iox.printStackTrace(); + } + return outputStream.toByteArray(); + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileUploadForm.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileUploadForm.java new file mode 100644 index 000000000..8565effd6 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FileUploadForm.java @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.FormData; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.bebop.Tree; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.event.FormValidationListener; +import com.arsdigita.bebop.form.FileUpload; +import com.arsdigita.bebop.form.Submit; +import com.arsdigita.bebop.form.TextArea; +import com.arsdigita.bebop.parameters.StringLengthValidationListener; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.dispatcher.MultipartHttpServletRequest; +import com.arsdigita.dispatcher.ObjectNotFoundException; +//import com.arsdigita.docrepo.ContentTypeException; +import com.arsdigita.docrepo.File; +import com.arsdigita.docrepo.Folder; +import com.arsdigita.docrepo.InvalidNameException; +import com.arsdigita.docrepo.Util; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.kernel.Kernel; +import com.arsdigita.kernel.KernelExcursion; +import com.arsdigita.kernel.Party; +import com.arsdigita.kernel.permissions.PermissionDescriptor; +import com.arsdigita.kernel.permissions.PermissionService; +import com.arsdigita.kernel.permissions.PrivilegeDescriptor; +import com.arsdigita.util.Assert; +//import com.arsdigita.versioning.Transaction; +//import com.arsdigita.versioning.TransactionCollection; +import com.arsdigita.web.Application; +import com.arsdigita.web.Web; +import org.apache.log4j.Logger; + +import javax.servlet.http.HttpServletRequest; +import java.math.BigDecimal; + +/** + * Form to upload and submit a file to the document repository. + * + * @author Stefan Deusch + * @version $Id: FileUploadForm.java pboy $ + */ +public class FileUploadForm extends Form + implements FormInitListener, FormValidationListener, + FormProcessListener, DRConstants { + + private static final Logger s_log = Logger.getLogger(FileUploadForm.class); + + // Form constants + private final static String FILE_UPLOAD = "file-upload"; + private final static String FILE_UPLOAD_FORM = "file-upload-form"; + private final static String FILE_UPLOAD_INPUT_DESCRIPTION = "file-description"; + + private FileUpload m_fileUpload; + + private StringParameter m_FileDesc; + private Tree m_tree; + private BrowsePane m_parent; + + /** + * Constructor + */ + public FileUploadForm(BrowsePane parent, Tree tree) { + this(parent, tree, true); + } + + public FileUploadForm(BrowsePane parent, Tree tree, boolean initListeners) { + super(FILE_UPLOAD_FORM, new ColumnPanel(2)); + + m_parent = parent; + + setMethod(Form.POST); + setEncType("multipart/form-data"); + + m_tree = tree; + + m_fileUpload = new FileUpload(FILE_UPLOAD); + + m_FileDesc = new StringParameter(FILE_UPLOAD_INPUT_DESCRIPTION); + m_FileDesc.addParameterListener + (new StringLengthValidationListener(4000)); + + add(new Label(FILE_UPLOAD_ADD_FILE)); + add(m_fileUpload); + + add(new Label(FILE_DESCRIPTION)); + TextArea textArea = new TextArea(m_FileDesc); + textArea.setRows(10); + textArea.setCols(40); + add(textArea); + + SimpleContainer sc = new SimpleContainer(); + Submit submit = new Submit("submit"); + submit.setButtonLabel(FILE_SUBMIT); + sc.add(submit); + CancelButton cancel = new CancelButton(CANCEL); + sc.add(cancel); + + add(new Label()); // spacer + add(sc, ColumnPanel.LEFT); + + if (initListeners) { + addInitListener(this); + addProcessListener(this); + addValidationListener(this); + } + } + + /** + * Post the file to a temporary file on the server and + * insert it into the database + */ + protected BigDecimal insertFile(FormSectionEvent e) + throws FormProcessException { + s_log.debug("Inserting a file into the database"); + + PageState state = e.getPageState(); + FormData data = e.getFormData(); + final HttpServletRequest req = state.getRequest(); + + String fname = getFileName(e); + String fdesc = (String) data.get(FILE_UPLOAD_INPUT_DESCRIPTION); + String fpath = (String) data.get(FILE_UPLOAD); + + if (s_log.isDebugEnabled()) { + s_log.debug("getFileName() -> '" + fname + "'"); + s_log.debug("description == '" + fdesc + "'"); + s_log.debug("path == '" + fpath + "'"); + } + + java.io.File src = null; + + if (fpath != null && fpath.length() > 0) { + HttpServletRequest mreq = e.getPageState().getRequest(); + + // Assert.assertTrue(mreq instanceof MultipartHttpServletRequest, + Assert.isTrue(mreq instanceof MultipartHttpServletRequest, + "I got a " + mreq + " when I was " + + "expecting a MultipartHttpServletRequest"); + + src = ((MultipartHttpServletRequest) mreq).getFile(FILE_UPLOAD); + } + + if (s_log.isDebugEnabled()) { + s_log.debug("file == '" + src + "'"); + } + + Folder parent = null; + String selKey = (String) m_tree.getSelectedKey(state); + + if (selKey == null) { + parent = DRUtils.getRootFolder(state); + } else { + BigDecimal folderID = new BigDecimal(selKey); + try { + parent = new Folder(folderID); + } catch(DataObjectNotFoundException nf) { + throw new ObjectNotFoundException + ((String) FOLDER_PARENTNOTFOUND_ERROR.localize(req)); + } + } + + // insert the file in the data base below parent + + final String mimeType = Util.guessContentType(fname, req); + final File f1 = new File(parent); + f1.setContent(src, fname, fdesc, mimeType); + + // annotate first file upload as initial version + f1.setDescription(FILE_UPLOAD_INITIAL_TRANSACTION_DESCRIPTION + .localize(req) + .toString()); + + f1.applyTag(FILE_UPLOAD_INITIAL_TRANSACTION_DESCRIPTION + .localize(req) + .toString()); + + f1.save(); + + new KernelExcursion() { + protected void excurse() { + Party currentParty = Kernel.getContext().getParty(); + setParty(Kernel.getSystemParty()); + PermissionService.grantPermission(new PermissionDescriptor(PrivilegeDescriptor.ADMIN, + f1, + currentParty)); + Application app = Web.getContext().getApplication(); + Assert.exists(app, Application.class); + PermissionService.setContext(f1, app); + }}.run(); + + return f1.getID(); + } + + public void init(FormSectionEvent e) { + PageState state = e.getPageState(); + + if ( Kernel.getContext().getParty() == null ) { + Util.redirectToLoginPage(state); + } + + } + + /** + * Post the file to a temporary file on the server and + * insert it into the database + */ + public void process(FormSectionEvent e) + throws FormProcessException { + s_log.debug("Processing form submission"); + + insertFile(e); + + if (m_parent != null) { + m_parent.displayFolderContentPanel(e.getPageState()); + } + + } + + /** + * Gets either the file name from the widget + * or takes the filename from the upload + * widget in this order. + */ + protected String getFileName(FormSectionEvent e) { + FormData data = e.getFormData(); + String filename = (String) data.get(FILE_UPLOAD); + return DRUtils.extractFileName(filename, e.getPageState()); + } + + + /** + * Verify that the parent folder exists and does not contain any + * other files or sub folders with the same name as the file being + * uploaded. + */ + + public void validate(FormSectionEvent e) throws FormProcessException { + PageState state = e.getPageState(); + FormData data = e.getFormData(); + HttpServletRequest req = state.getRequest(); + + String fname = DRUtils.extractFileName(getFileName(e), state); + + // XXX Not localized as the other errors are. + if (fname.length() > 200) { + data.addError + (FILE_UPLOAD, + "This filename is too long. It must be fewer than 200 " + + "characters."); + } + + Folder parent = null; + String selKey = (String) m_tree.getSelectedKey(state); + + if (selKey == null) { + parent = DRUtils.getRootFolder(state); + } else { + BigDecimal folderID = new BigDecimal(selKey); + try { + parent = new Folder(folderID); + } catch(DataObjectNotFoundException nf) { + throw new ObjectNotFoundException(FOLDER_PARENTNOTFOUND_ERROR + .localize(req).toString()); + } + } + + try { + parent.getResourceID(fname); + data.addError(FILE_UPLOAD, + RESOURCE_EXISTS_ERROR + .localize(req).toString()); + } catch(DataObjectNotFoundException nf) { + // ok here + } catch(InvalidNameException ex) { + data.addError(FILE_UPLOAD, + ex.getMessage()); + } + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/FolderContentsTableForm.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FolderContentsTableForm.java new file mode 100644 index 000000000..af5810de0 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FolderContentsTableForm.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Page; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.bebop.Tree; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.form.SingleSelect; +import com.arsdigita.bebop.form.Submit; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.docrepo.ResourceImpl; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.domain.DomainObjectFactory; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.persistence.OID; +import com.arsdigita.persistence.PersistenceException; +import com.arsdigita.kernel.Kernel; +import com.arsdigita.kernel.KernelExcursion; +//import com.arsdigita.kernel.permissions.*; +import java.math.BigDecimal; +import java.util.ArrayList; + +/** + * This class has dual functionality as the name implies. + * Firstly, it contains a table that lists the contents of + * a given directory. + * Secondly, it contains following buttons to apply the + * corrsponding operation to the selected files and folders: + * CUT, COPY, DELETE + * + * @author Stefan Deusch + */ + +class FolderContentsTableForm extends Form + implements FormProcessListener, + DRConstants { + + private Tree m_tree; + private FolderTable m_folder; + private SingleSelect m_actionSelect ; + private StringParameter m_action = new StringParameter("folder-action"); + + private Submit m_deleteSubmit; + private Submit m_copySubmit; + private Submit m_moveSubmit; + private SimpleContainer m_actionBar; + private Label m_emptyFolderLabel; + private BrowsePane m_parent; + ResourceImpl m_resource; + + /** + * Constructor + */ + public FolderContentsTableForm(BrowsePane parent, Tree tree) { + super("FolderContentAction", new ColumnPanel(1)); + + m_tree = tree; + m_parent = parent; + + m_folder = new FolderTable(m_tree, this); + add(m_folder); + + m_actionBar = new SimpleContainer(); + + m_copySubmit = new Submit(ACTION_COPY_SUBMIT); + m_actionBar.add(m_copySubmit); + + m_moveSubmit = new Submit(ACTION_MOVE_SUBMIT); + m_actionBar.add(m_moveSubmit); + + m_deleteSubmit = new DeleteSubmit(ACTION_DELETE_SUBMIT); + m_actionBar.add(m_deleteSubmit); + + add(m_actionBar); + + m_emptyFolderLabel = FOLDER_EMPTY_LABEL; + add( m_emptyFolderLabel); + + addProcessListener(this); + } + + /** + * Register the defa + */ + @Override + public void register(Page p) { + + p.setVisibleDefault( m_actionBar, true); + p.setVisibleDefault( m_emptyFolderLabel, false); + super.register(p); + } + + + public void process(FormSectionEvent e) + throws FormProcessException { + PageState state = e.getPageState(); + + ArrayList msgList = new ArrayList(); + boolean isError = false; + + String[] selectedItems = + (String[]) m_folder.getCheckboxGroup().getValue(state); + + if (selectedItems == null) { + // Nothing selected, can stop process right here. + return; + } + + ArrayList list = new ArrayList(); + for (int i = 0; i < selectedItems.length; i++) { + list.add(selectedItems[i]); + } + + if (m_deleteSubmit.isSelected(state)) { + + for (int i = 0; i < selectedItems.length; i++) { + OID oid = new OID(ResourceImpl.BASE_DATA_OBJECT_TYPE, + new BigDecimal(selectedItems[i])); + + m_resource = null; + try { + + m_resource = + (ResourceImpl) DomainObjectFactory.newInstance(oid); + KernelExcursion ex = new KernelExcursion() { + protected void excurse() { + setEffectiveParty(Kernel.getSystemParty()); + m_resource.delete(); + } + }; + ex.run(); + } catch (PersistenceException exc) { + // Can't delete file and folder. + isError = true; + if (m_resource != null) { + msgList.add(m_resource.getName()); + } + + + } catch (DataObjectNotFoundException exc) { + // Move on to the next object. + isError = true; + if (m_resource != null) { + msgList.add(m_resource.getName()); + } + + } + } + } else if (m_copySubmit.isSelected(state)) { + m_parent.displayDestinationFolderPanel(state, + list.toArray(), + false); + + } else if (m_moveSubmit.isSelected(state)) { + m_parent.displayDestinationFolderPanel(state, + list.toArray(), + true); + } + + // Reset selected item in checkbox. + m_folder.getCheckboxGroup().setValue(state, null); + + if (isError) { + m_parent.displayErrorMsgPanel(state, "delete", msgList); + } + } + + public void hideActionLinks(PageState state) { + m_actionBar.setVisible(state, false); + m_emptyFolderLabel.setVisible(state, true); + } + + public void hideEmptyLabel(PageState state) { + m_emptyFolderLabel.setVisible(state, false); + m_actionBar.setVisible(state, true); + } + +} + + +/** + * Display a confirmation dialog box when clicked. + */ +class DeleteSubmit extends Submit implements DRConstants { + public DeleteSubmit(GlobalizedMessage label) { + super(label); + avoidDoubleClick(false); + setAttribute(ON_CLICK, + "return confirm("+ + ACTION_DELETE_CONFIRM.localize() + +");"); + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/FolderCreateForm.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FolderCreateForm.java new file mode 100644 index 000000000..e05c198ec --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FolderCreateForm.java @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + + +//import com.arsdigita.docrepo.util.GlobalizationUtil; + +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.FormData; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.FormValidationException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.bebop.Tree; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.event.FormValidationListener; +import com.arsdigita.bebop.form.Submit; +import com.arsdigita.bebop.form.TextArea; +import com.arsdigita.bebop.form.TextField; +import com.arsdigita.bebop.parameters.NotEmptyValidationListener; +import com.arsdigita.bebop.parameters.StringLengthValidationListener; +//import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.kernel.Kernel; +import com.arsdigita.kernel.KernelExcursion; +import com.arsdigita.kernel.Party; +import com.arsdigita.kernel.permissions.PermissionDescriptor; +import com.arsdigita.kernel.permissions.PermissionService; +import com.arsdigita.kernel.permissions.PrivilegeDescriptor; +import com.arsdigita.docrepo.Util; + +import com.arsdigita.docrepo.Folder; +import com.arsdigita.docrepo.ResourceExistsException; +import com.arsdigita.docrepo.InvalidNameException; + +import java.math.BigDecimal; +import javax.servlet.http.HttpServletRequest; + +/** + * This form serves to attach a child node folder to the selected folder + * + * @author Stefan Deusch + * @version $Id: FolderCreateForm.java pboy $ + */ +class FolderCreateForm extends Form + implements FormInitListener, FormValidationListener, + FormProcessListener, DRConstants { + + private StringParameter m_FolderName; + private StringParameter m_FolderDesc; + private Tree m_tree; + private BrowsePane m_parent; + + public FolderCreateForm(BrowsePane parent, Tree tree) { + super("CreateFolderForm", new ColumnPanel(2)); + + m_parent = parent; + m_tree = tree; + + add(FOLDER_NAME_LABEL); + m_FolderName = new StringParameter(FOLDER_NAME); + m_FolderName.addParameterListener + (new StringLengthValidationListener(200)); + TextField fnameEntry = new TextField(m_FolderName); + fnameEntry.addValidationListener(new NotEmptyValidationListener()); + add(fnameEntry); + + add(FOLDER_DESCRIPTION_LABEL); + m_FolderDesc = new StringParameter(FOLDER_DESCRIPTION); + m_FolderDesc.addParameterListener + (new StringLengthValidationListener(4000)); + TextArea textArea = new TextArea(m_FolderDesc); + textArea.setRows(10); + textArea.setCols(40); + add(textArea); + + SimpleContainer sc = new SimpleContainer(); + Submit submit = new Submit("submit"); + submit.setButtonLabel(FOLDER_SAVE); + sc.add(submit); + CancelButton cancel = new CancelButton(CANCEL); + sc.add(cancel); + + add(new Label()); // spacer + add(sc, ColumnPanel.LEFT); + + addInitListener(this); + addProcessListener(this); + addValidationListener(this); + } + + public void init(FormSectionEvent e) { + PageState state = e.getPageState(); + + if ( Kernel.getContext().getParty() == null ) { + Util.redirectToLoginPage(state); + } + + } + + public void process(FormSectionEvent e) throws FormProcessException { + PageState state = e.getPageState(); + FormData data = e.getFormData(); + + String fname = (String) data.get(FOLDER_NAME); + String fdesc = (String) data.get(FOLDER_DESCRIPTION); + + String selKey = (String) m_tree.getSelectedKey(state); + Folder parent = null; + if (selKey == null) { + parent = DRUtils.getRootFolder(state); + } else { + BigDecimal folderID = new BigDecimal(selKey); + + try { + parent = new Folder(folderID); + } catch (DataObjectNotFoundException nf) { + // TODO show error lable instead + throw new RuntimeException("Could not find folder"); + } + } + + // already validated fname + final Folder folder = new Folder(fname, fdesc, parent); + + try { + folder.save(); + } catch (ResourceExistsException ree) { + throw new FormValidationException + ("A folder with this name already exists."); + } + + new KernelExcursion() { + protected void excurse() { + Party currentParty = Kernel.getContext().getParty(); + setParty(Kernel.getSystemParty()); + PermissionService.grantPermission + (new PermissionDescriptor(PrivilegeDescriptor.ADMIN, + folder, + currentParty)); + } + }.run(); + + if (m_parent != null) { + m_parent.displayFolderContentPanel(state); + } + } + + /** + * Validate that the folder we want to attach does not already + * exist in the current parent folder. + */ + public void validate(FormSectionEvent event) throws FormProcessException { + PageState state = event.getPageState(); + FormData data = event.getFormData(); + HttpServletRequest req = state.getRequest(); + + String fname = (String) data.get(FOLDER_NAME); + + Folder parent = null; + String selKey = (String) m_tree.getSelectedKey(state); + + if (selKey == null) { + parent = DRUtils.getRootFolder(state); + + if (parent == null) { + data.addError(FOLDER_NAME, + (String) FOLDER_PARENTNOTFOUND_ERROR + .localize(req)); + } + } else { + BigDecimal folderID = new BigDecimal(selKey); + + try { + parent = new Folder(folderID); + } catch(DataObjectNotFoundException nf) { + data.addError(FOLDER_NAME, + (String) FOLDER_PARENTNOTFOUND_ERROR + .localize(req)); + } + } + + try { + if (parent != null) { + parent.retrieveFolder(fname); + data.addError + (FOLDER_NAME, (String) RESOURCE_EXISTS_ERROR.localize(req)); + } + } catch(DataObjectNotFoundException e) { + // ok if here + } catch(InvalidNameException ex) { + data.addError(FOLDER_NAME, ex.getMessage()); + } + } + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/FolderNamePrintListener.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FolderNamePrintListener.java new file mode 100644 index 000000000..8a7c4f595 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FolderNamePrintListener.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.Tree; +import com.arsdigita.bebop.event.PrintEvent; +import com.arsdigita.bebop.event.PrintListener; +import com.arsdigita.docrepo.Folder; +import com.arsdigita.domain.DataObjectNotFoundException; +import java.math.BigDecimal; +import java.util.StringTokenizer; + +/** + * Add a Print Listener to components showing the selected Folder + * + * @author Stefan Deusch + */ +class FolderNamePrintListener implements PrintListener { + + private Tree m_tree; + + public FolderNamePrintListener(Tree tree) { + m_tree = tree; + } + + public void prepare(PrintEvent e) { + Label t= (Label) e.getTarget(); + String fixed = t.getLabel(e.getPageState()); + PageState state = e.getPageState(); + //t.setLabel(fixed + " " + DMUtils.getFolderName(e.getPageState(), m_tree)); + + String id = (String) m_tree.getSelectedKey(state); + + if (id != null) { + try { + Folder folder = new Folder(new BigDecimal(id)); + StringTokenizer st = new StringTokenizer(folder.getPath(), "/"); + + StringBuffer sb = new StringBuffer(fixed + " Documents"); + if (st.hasMoreTokens()) { + st.nextToken(); + } + while (st.hasMoreTokens()) { + sb.append(" > ").append(st.nextToken()); + } + t.setLabel(sb.toString()); + } catch (DataObjectNotFoundException exc) {} + } else { + t.setLabel(fixed); + } + + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/FolderTable.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FolderTable.java new file mode 100644 index 000000000..b4c456904 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/FolderTable.java @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.ControlLink; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Link; +import com.arsdigita.bebop.Page; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.bebop.Table; +import com.arsdigita.bebop.Tree; +import com.arsdigita.bebop.event.TableActionEvent; +import com.arsdigita.bebop.event.TableActionListener; +import com.arsdigita.bebop.form.CheckboxGroup; +import com.arsdigita.bebop.form.Option; +import com.arsdigita.bebop.parameters.ArrayParameter; +import com.arsdigita.bebop.parameters.BigDecimalParameter; +import com.arsdigita.bebop.table.TableCellRenderer; +import com.arsdigita.bebop.table.TableModel; +import com.arsdigita.bebop.table.TableModelBuilder; +import com.arsdigita.docrepo.File; +import com.arsdigita.docrepo.Folder; +import com.arsdigita.docrepo.ResourceImpl; +import com.arsdigita.persistence.DataQuery; +import com.arsdigita.persistence.Session; +import com.arsdigita.persistence.SessionManager; +import com.arsdigita.util.LockableImpl; +import com.arsdigita.web.ParameterMap; +import com.arsdigita.web.RedirectSignal; +import com.arsdigita.web.URL; + +import java.math.BigDecimal; + +/** + * This class has dual functionality as the name implies. + * Firstly, it contains a table that lists the contents of + * a given directory whose unique Folder ID is described + * in the m_folderID model parameter that is passed in + * the constructor or changed after construction at runtime. + * (currently retrieved by the folder ID of the + * the global state parameter SEL_FOLDER_ID_PARAM) + * The table contains a checkbox for each item for bulk operations. + * + * @author Stefan Deusch + */ + +class FolderTable extends Table + implements TableActionListener, DRConstants { + + private final static String FOLDER_LIST_CONTENT_IDS = "folder-listing-ids"; + + static String[] s_tableHeaders = { + "", + "Name", + "Size", + "Type", + "Modified", + "" + }; + + private CheckboxGroup m_checkboxGroup; + private ArrayParameter m_sources; + private FolderContentsTableForm m_parent; + private Tree m_tree; + + + /** + * Constructor + * @param tree to get the selected folder + * @param parent corresponding form to this table + */ + + public FolderTable(Tree tree, FolderContentsTableForm parent) { + + super(new FolderTableModelBuilder(tree, parent), s_tableHeaders); + m_parent = parent; + m_tree = tree; + + m_sources = new ArrayParameter(new BigDecimalParameter + (FOLDER_LIST_CONTENT_IDS)); + m_checkboxGroup = new CheckboxGroup(FOLDER_LIST_CONTENT_IDS); + m_parent.add(m_checkboxGroup); + + // setClassAttr("AlternateTable"); + setWidth("100%"); + setCellRenderers(); + addTableActionListener(this); + } + + @Override + public void register(Page p) { + super.register(p); + p.addComponentStateParam(this, m_sources); + } + + public CheckboxGroup getCheckboxGroup() { + return m_checkboxGroup; + } + + public void cellSelected(TableActionEvent e) { + PageState state = e.getPageState(); + int col = e.getColumn().intValue(); + String rowkey = (String)e.getRowKey(); + + int j = rowkey.indexOf("."); + String id = rowkey.substring(0, j); + + char isFolder = rowkey.charAt(j+1); // either '1' or 'n' from "null" + + // set new Folder ID + if (isFolder == 't') { + String oldKey = (String) m_tree.getSelectedKey(state); + m_tree.setSelectedKey(state, id); + m_tree.expand(oldKey, state); + + // wipe out selected file in state or we get lost in BrowsePane + state.setValue(FILE_ID_PARAM, null); + + } else { + // redirect to file-info + ParameterMap params = new ParameterMap(); + params.setParameter(FILE_ID_PARAM.getName(), id); + final URL url = URL.here(state.getRequest(),"/file", params); + throw new RedirectSignal(url,true); + } + + } + + public void headSelected(TableActionEvent e) { + throw new UnsupportedOperationException(); + } + + private void setCellRenderers() { + getColumn(0).setCellRenderer(new CheckBoxRenderer()); + getColumn(1).setCellRenderer(new LinkRenderer()); + getColumn(5).setCellRenderer(new DownloadLinkRenderer()); + } + + private final class DownloadLinkRenderer implements TableCellRenderer { + public Component getComponent(Table table, + PageState state, + Object value, + boolean isSelected, + Object key, + int row, + int column) { + if (value==null) { + return new Label(); + } else { + Link link = new Link("Download", + "download/" + value + "?" + + FILE_ID_PARAM.getName() + "=" + key); + link.setClassAttr("downloadLink"); + return link; + } + } + } + + private final class LinkRenderer implements TableCellRenderer { + public Component getComponent(Table table, + PageState state, + Object value, + boolean isSelected, + Object key, + int row, + int column) { + + + ResourceImpl resource = (ResourceImpl) value; + + String classAttr; + if (resource.isFolder()) { + classAttr = "isFolder"; + } else { + classAttr = "isFile"; + } + + // mimeTypes not supported yet + + Label iconLabel = new Label(); + if (classAttr != null) { + iconLabel.setClassAttr(classAttr); + } + + // return container + SimpleContainer link = new SimpleContainer(); + link.add(iconLabel); + + link.add(new ControlLink(resource.getName())); + + return link; + } + } + + private final class CheckBoxRenderer implements TableCellRenderer { + public Component getComponent(Table table, + PageState state, + Object value, + boolean isSelected, + Object key, + int row, + int column) { + + String encodedKey = (String) key; + int j = encodedKey.indexOf("."); + BigDecimal id = new BigDecimal(encodedKey.substring(0, j)); + + Option result = new Option(m_sources.marshalElement(id.abs()), ""); + result.setGroup(m_checkboxGroup); + return result; + } + } + + +} + +class FolderTableModelBuilder + extends LockableImpl implements TableModelBuilder { + + private Tree m_tree; + private FolderContentsTableForm m_parent; + + FolderTableModelBuilder(Tree tree, FolderContentsTableForm parent) { + m_tree = tree; + m_parent = parent; + } + + public TableModel makeModel(Table t, PageState state) { + + // get parent folderID + BigDecimal fid = DRUtils.getSelectedFolderID(state, m_tree); + + // create and return a FolderTableModel + return new FolderTableModel(fid, state); + } + + + class FolderTableModel implements TableModel, DRConstants { + + private BigDecimal m_parentFolderID; + private PageState m_state; + private boolean m_more; + private DataQuery m_query; + + /** + * Constructor takes folder ID + */ + FolderTableModel(BigDecimal folderID, PageState state) { + m_parentFolderID = folderID; + m_state = state; + + Session session = SessionManager.getSession(); + m_query = session.retrieveQuery(GET_CHILDREN); + m_query.setParameter(FOLDER_ID, m_parentFolderID); + + if (m_query.size() == 0) { + m_parent.hideActionLinks(state); + } else { + m_parent.hideEmptyLabel(state); + } + + } + + public int getColumnCount() { + return 6; // same length as header String[] + } + + public Object getElementAt(int columnIndex) { + final boolean isFolder = ((Boolean)m_query.get(IS_FOLDER)).booleanValue(); + + switch (columnIndex) { + case 0 : + return Boolean.FALSE; + case 1: { + String name = (String) m_query.get(NAME); + String type = (String) m_query.get(TYPE); + + + if (isFolder) { + Folder folder = new Folder((BigDecimal) m_query.get("id") ); + return folder; + } else { + File file = new File((BigDecimal) m_query.get("id")); + return file; + } + } + case 2: + + if ( isFolder ) { + return null; + } else { + File file = new File((BigDecimal) m_query.get("id")); + long size = ((BigDecimal)file.getSize()).longValue(); + return DRUtils.FileSize.formatFileSize(size, m_state); + } + case 3: + if (isFolder) { + return "Folder"; + } else { + return m_query.get(MIME_TYPE_LABEL); + } + case 4: + return m_query.get(LAST_MODIFIED); + case 5: + if (isFolder) { + return null; + } else { + return m_query.get(NAME); + } + default: + break; + } + return null; + } + + public Object getKeyAt(int columnIndex) { + if (columnIndex == 5) { + return m_query.get("id"); + } else { + return m_query.get("id") + "." + m_query.get(IS_FOLDER); + } + } + + public boolean nextRow() { + return m_query.next(); + } + + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/RecentUpdatedDocsPortlet.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/RecentUpdatedDocsPortlet.java new file mode 100644 index 000000000..8c881df69 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/RecentUpdatedDocsPortlet.java @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.GridPanel; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Link; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.Table; +import com.arsdigita.bebop.portal.AbstractPortletRenderer; +import com.arsdigita.docrepo.Repository; +import com.arsdigita.docrepo.File; +//import com.arsdigita.docrepo.ResourceImpl; +import com.arsdigita.docrepo.ResourceImplCollection; +//import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.kernel.User; +import com.arsdigita.persistence.DataObject; +//import com.arsdigita.persistence.DataQuery; +//import com.arsdigita.persistence.Session; +//import com.arsdigita.persistence.SessionManager; +import com.arsdigita.web.Application; +import com.arsdigita.portal.apportlet.AppPortlet; +import com.arsdigita.xml.Element; +import org.apache.log4j.Category; + +import javax.servlet.http.HttpServletRequest; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; + +/** + * Portlet showing the n most recently updated documents of a + * repository . + * + * @author Stefan Deusch + * @version $Id: RecentUpdatedDocsPortlet.java pboy $ + */ +public class RecentUpdatedDocsPortlet extends AppPortlet { + + private static Category s_log = Category.getInstance + (RecentUpdatedDocsPortlet.class.getName()); + + public static final String BASE_DATA_OBJECT_TYPE = + "com.arsdigita.docrepo.ui.RecentUpdatedDocsPortlet"; + + @Override + protected String getBaseDataObjectType() { + return BASE_DATA_OBJECT_TYPE; + } + + public RecentUpdatedDocsPortlet(DataObject dataObject) { + super(dataObject); + } + + @Override + protected AbstractPortletRenderer doGetPortletRenderer() { + return new RecentUpdatedDocsPortletRenderer(this); + } +} + +class RecentUpdatedDocsPortletRenderer extends AbstractPortletRenderer + implements DRConstants { + private RecentUpdatedDocsPortlet m_portlet; + + public RecentUpdatedDocsPortletRenderer + (RecentUpdatedDocsPortlet docsPortlet) { + + m_portlet = docsPortlet; + } + + + /** + * + * + * @param pageState + * @param parentElement + */ + protected void generateBodyXML(PageState pageState, + Element parentElement) { + + Application application = m_portlet.getParentApplication(); + + String fileURL = application.getPath(); + Repository rep = (Repository) application; + HttpServletRequest req = pageState.getRequest(); + + ResourceImplCollection files = + Repository.getRecentlyModifiedDocuments(rep); + + + GridPanel panel; + + // Table with 5 columns + String[] tableHeaders = { + "File", + "Type", + "Size", + "Author", + "Date", + "" + }; + + + // Determine number of rows + int size = 0; + int maxDocs = (int)files.size(); + int maxCount = 10; + if ( maxCount < maxDocs ) { + size = maxCount; + } else { + size = maxDocs; + } + + // No documents. + if (size == 0 ) { + panel = new GridPanel(1); + addResourceLink(panel); + panel.add + (new Label(REPOSITORY_RECENTDOCS_EMPTY.localize(req).toString())); + panel.generateXML(pageState, parentElement); + return; + } + + // We have documents. Present them in the table. + panel = new GridPanel(1); + addResourceLink(panel); + Object tableData[][] = new Object[size][6]; + for ( int i = 0; i < size && files.next(); i++) { + File resource = (File)files.getDomainObject(); + // File name column. + tableData[i][0] = new Link((String) resource.getName(), + fileURL+"/file?" +FILE_ID_PARAM.getName() + + "=" + resource.getResourceID()); + + // File type column + tableData[i][1] = + new Label((String) resource.getPrettyContentType()); + + long fileSize = ((BigDecimal)resource.getSize()).longValue(); + + // File size column + tableData[i][2] = new Label + (DRUtils.FileSize.formatFileSize(fileSize, pageState)); + + // Author column + User user = resource.getLastModifiedUser(); + String author = null; + if (null != user) { + author = user.getPersonName().toString(); + } + + if (null == author) { + author = "Unknown"; + } + + tableData[i][3] = new Label(author); + + // Date column + java.util.Date date = resource.getLastModifiedDate(); + SimpleDateFormat dft = new SimpleDateFormat(); + String textdate = dft.format(date); + tableData[i][4] = new Label(textdate); + + // Download column + Link link = new Link("Download", + fileURL + "/download/" + resource.getName() + "?" + + FILE_ID_PARAM.getName() + "=" + + resource.getResourceID()); + link.setClassAttr("downloadLink"); + tableData[i][5] = link; + } + files.close(); + Table table = new Table(tableData, tableHeaders); + panel.add(table, GridPanel.FULL_WIDTH); + panel.generateXML(pageState, parentElement); + } + + + private void addResourceLink(GridPanel panel) { + Link addResourceLink = + new Link(new Label(ROOT_ADD_RESOURCE_LINK), + m_portlet.getParentApplication().getPath() + + "?"+ROOT_ADD_DOC_PARAM.getName()+"="+"t"); + addResourceLink.setClassAttr("actionLink"); + + panel.add(addResourceLink, + GridPanel.FULL_WIDTH | GridPanel.RIGHT | GridPanel.BOTTOM); + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/RepositoriesSelectionForm.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/RepositoriesSelectionForm.java new file mode 100644 index 000000000..ec301b6cf --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/RepositoriesSelectionForm.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Page; +//import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.form.Hidden; +import com.arsdigita.bebop.form.OptionGroup; +import com.arsdigita.bebop.form.SingleSelect; +import com.arsdigita.bebop.form.Submit; +import com.arsdigita.bebop.parameters.ArrayParameter; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.kernel.User; +import com.arsdigita.persistence.DataOperation; +import com.arsdigita.persistence.SessionManager; +import java.math.BigDecimal; +import java.util.HashSet; + +/** + * This form shows all accessible repositories + * and allows to check/uncheck those one whishes to subscribe to. + * + * @author Stefan Deusch + */ +class RepositoriesSelectionForm extends Form + implements FormInitListener, + FormProcessListener, + DRConstants { + + private OptionGroup m_selection; + private Hidden m_subscribed; + private ArrayParameter m_origIDs; + + private RepositoriesTable m_table; + private SingleSelect m_actionSelect ; + private StringParameter m_action = new StringParameter("folder-action"); + + + /** + * Constructor + * + * @param the table into which this form is embedded. + */ + + public RepositoriesSelectionForm(RepositoriesTable table) { + super("FolderContentAction", new ColumnPanel(1)); + + m_table = table; + + add(m_table.getTable()); + + m_selection = m_table.getCheckboxGroup(); + m_subscribed = m_table.getSubscribedHidden(); + + add(m_selection); + add(m_subscribed); + add(new Submit( REPOSITORIES_MOUNTED_SAVE)); + + addInitListener(this); + addProcessListener(this); + } + + @Override + public void register(Page p) { + super.register(p); + } + + public void reset(PageState state) { + m_selection.setValue(state, m_table.getSelectedIDs(state)); + m_subscribed.setValue(state, m_table.getSelectedIDs(state)); + } + + public void init(FormSectionEvent e) throws FormProcessException { + reset(e.getPageState()); + } + + public void process (FormSectionEvent e) + throws FormProcessException { + + PageState state = e.getPageState(); + User subscriber = DRUtils.getUser(state); + + /* + Construct sets for previously subscribed + and currently selected repository IDs + */ + HashSet subscribed = new HashSet(); + BigDecimal[] subID = (BigDecimal[]) m_subscribed.getValue(state); + for(int i=0; subID != null && i 0 ) { + DataOperation operation = SessionManager.getSession() + .retrieveDataOperation( + "com.arsdigita.docs.addUserRepositoriesMapping"); + operation.setParameter("userID", subscriber.getID()); + operation.setParameter("repositoryIDs", selected); + operation.execute(); + operation.close(); + } + + // Delete from repository mapping newly unselected repositories + subscribed.removeAll(selected_bk); + if(subscribed.size() > 0 ) { + DataOperation operation = SessionManager.getSession() + .retrieveDataOperation( + "com.arsdigita.docrepo.removeUserRepositoriesMapping"); + operation.setParameter("userID", subscriber.getID()); + operation.setParameter("repositoryIDs", subscribed); + operation.execute(); + operation.close(); + } + reset(state); + } + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/RepositoriesSuperTreeModel.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/RepositoriesSuperTreeModel.java new file mode 100644 index 000000000..9bcb300ff --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/RepositoriesSuperTreeModel.java @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.tree.TreeModel; +import com.arsdigita.bebop.tree.TreeNode; +import com.arsdigita.docrepo.Folder; +import com.arsdigita.docrepo.Repository; +import com.arsdigita.docrepo.ResourceImpl; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.kernel.User; +import com.arsdigita.persistence.DataQuery; +import com.arsdigita.persistence.Session; +import com.arsdigita.persistence.SessionManager; +import com.arsdigita.web.Web; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Iterator; + +/** + * Tree model that incorporates the views of all subsribed repositories. + * + * @author Stefan Deusch + */ +class RepositoriesSuperTreeModel implements TreeModel, DRConstants { + + private static BigDecimal REPOSITORIES_ROOT_ID = new BigDecimal(0); + + private class RepositoryIterator implements Iterator { + + private DataQuery m_query; + + public RepositoryIterator(DataQuery query) { + m_query = query; + } + + public boolean hasNext() { + if(!m_query.isEmpty()) { + + if(m_query.next()){ + return true; + } + m_query.close(); + } + return false; + } + + public Object next() { + BigDecimal id = (BigDecimal) m_query.get("id"); + + Folder f = null; + try { + f = new Folder(id); + } catch(DataObjectNotFoundException e) { + throw new RuntimeException(e.getMessage()); + } + + return new RepositoryTreeNode(f); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + + + /** + * Obtain the root folder of the tree + */ + + public TreeNode getRoot(PageState state) { + + /* sdm #204157: Ron requests that we only show the one repository + of the Application, not a tree of repositories. + + return new RootTreeNode(); + */ + + // Return the Root of this Application's repository + Repository repository = (Repository) Web.getContext().getApplication(); + + Folder root = repository.getRoot(); + + return new RepositoryTreeNode(root); + } + + /** + * Check whether a given node has children + */ + + public boolean hasChildren(TreeNode n, PageState state) { + + // The Root not has always at least 1 child (one's own repository) + if (n instanceof RootTreeNode) { + return true; + + } + + // otherwise docs.folders + + Session session = SessionManager.getSession(); + DataQuery query = session.retrieveQuery(GET_CHILDREN); + + BigDecimal folderID = DRUtils.getSelFolderOrRootID(state, n); + query.setParameter(FOLDER_ID, folderID); + query.addEqualsFilter(IS_FOLDER, Boolean.TRUE); + + // if this node has any children, return true + long s = query.size(); + query.close(); + + return s > 0; + } + + /** + * Get direct children in this node which are folders in this application + */ + + public Iterator getChildren(TreeNode n, PageState state) { + + BigDecimal folderID = DRUtils.getSelFolderOrRootID(state, n); + + Session ssn = SessionManager.getSession(); + DataQuery query = null; + if(folderID.equals(REPOSITORIES_ROOT_ID)) { + + // Get Root folder. + Repository currentRepository = + (Repository) Web.getContext().getApplication(); + + Folder root = currentRepository.getRoot(); + + ArrayList list = new ArrayList(); + list.add(new RepositoryTreeNode(root)); + + return list.iterator(); + //query = ssn.retrieveQuery(GET_REPOSITORIES_ROOTS); + //query.setParameter("userID", DRUtils.getUser(state).getID()); + } else { + query = ssn.retrieveQuery(GET_CHILDREN); + query.setParameter(FOLDER_ID, folderID); + query.addEqualsFilter(IS_FOLDER, "1"); + } + + return new RepositoryIterator(query); + } + +} + +class RepositoryTreeNode implements TreeNode { + + String m_key; + String m_name; + + public RepositoryTreeNode() { + // empty default constructor needed by subclass + } + + public RepositoryTreeNode(ResourceImpl o) { + m_key = o.getID().toString(); + if (o.isRoot()) { + m_name = "Documents"; + } else { + m_name = o.getName(); + } + } + + public Object getKey() { + return m_key; + } + + public Object getElement() { + return m_name; + } +} + +class RootTreeNode extends RepositoryTreeNode { + + final static String ROOT_ID = "0"; + + public RootTreeNode(ResourceImpl o) { + super(o); + } + + /** + * Constructor for repositories root tree node + */ + public RootTreeNode() { + m_name = "My Repositories"; + m_key = ROOT_ID; + } + +} + +/** + * Non-persistent helper class that models the repositories root nodes + * + */ + +class RepositoryFolder extends Folder { + + static final BigDecimal s_rootID = new BigDecimal(0); + User m_user; + + RepositoryFolder(User user) { + m_user = user; + } + + // overwrite getID to return magic # for root folder + @Override + public BigDecimal getID() { + return s_rootID; + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/RepositoriesTable.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/RepositoriesTable.java new file mode 100644 index 000000000..a7a51ce35 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/RepositoriesTable.java @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.Page; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.bebop.Table; +import com.arsdigita.bebop.event.TableActionEvent; +import com.arsdigita.bebop.form.CheckboxGroup; +import com.arsdigita.bebop.form.Hidden; +import com.arsdigita.bebop.form.Option; +import com.arsdigita.bebop.parameters.ArrayParameter; +import com.arsdigita.bebop.parameters.BigDecimalParameter; +import com.arsdigita.bebop.table.TableCellRenderer; +import com.arsdigita.bebop.table.TableModel; +import com.arsdigita.bebop.table.TableModelBuilder; +import com.arsdigita.kernel.User; +import com.arsdigita.persistence.DataQuery; +import com.arsdigita.persistence.Session; +import com.arsdigita.persistence.SessionManager; +import com.arsdigita.util.LockableImpl; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Vector; + +/** + * This class has dual functionality as the name implies. + * Firstly, it lists all the repositories a user has + * acces to. These are currently all repositories of fellow + * group members. + * Secondly, it contains a checkbox group to select/unselect + * a repository to be mounted. (One's own repository is always + * mounted). + * + * @author Stefan Deusch + */ + +class RepositoriesTable implements DRConstants { + + private static String REPOSITORIES_IDS + = "repositories-ids"; + private static String REPOSITORIES_SUBSCRIBED_IDS = + "repositories-subscribed-ids"; + + static String[] s_tableHeaders = { + "", + "Portal", + "Files" + }; + + private CheckboxGroup m_checkboxGroup; + private Hidden m_subscribed; + private ArrayParameter m_sourcesSubscribed; + + private ArrayParameter m_sources; + private Table m_table; + private TableModelBuilder m_tableBuilder; + + // this query only once per page request + private RequestLocal m_query; + + + /** + * Default constructor + */ + + public RepositoriesTable() { + + // store query result once + m_query = new RequestLocal() { + protected Object initialValue(PageState s) { + User viewer = DRUtils.getUser(s); + Session session = SessionManager.getSession(); + DataQuery query = session.retrieveQuery(GET_REPOSITORIES); + query.setParameter("userID", viewer.getID()); + Vector result = new Vector(); + while(query.next()) { + + Object[] row = new Object[4]; + row[0] = query.get(REPOSITORY_ID); + row[1] = query.get(IS_MOUNTED); + row[2] = query.get(NAME); + row[3] = query.get(NUM_FILES); + result.add(row); + } + query.close(); + return result; + } + }; + + m_tableBuilder = new RepositoriesTableModelBuilder(this); + m_table = new Table(m_tableBuilder, + s_tableHeaders); + + m_sources = new ArrayParameter(new BigDecimalParameter + (REPOSITORIES_IDS)); + m_checkboxGroup = new CheckboxGroup(m_sources); + + m_sourcesSubscribed = new ArrayParameter(new BigDecimalParameter + (REPOSITORIES_SUBSCRIBED_IDS)); + m_subscribed = new Hidden(m_sourcesSubscribed); + + setCellRenderers(); + m_table.setClassAttr("AlternateTable"); + } + + /** + * Get the sotred query results + */ + public Iterator getQuery(PageState state) { + return ((Vector) m_query.get(state)).iterator(); + } + + public void setQuery(PageState state, ArrayList list) { + m_query.set(state, list); + } + + Table getTable() { + return m_table; + } + + CheckboxGroup getCheckboxGroup() { + return m_checkboxGroup; + } + + Hidden getSubscribedHidden() { + return m_subscribed; + } + + Object[] getSelectedIDs(PageState s) { + Iterator it = getQuery(s); + ArrayList a = new ArrayList(); + BigDecimal id = null; + while(it.hasNext()) { + Object[] field = (Object [])it.next(); + if( 1 == ((BigDecimal) field[1]).intValue()) { + id = (BigDecimal) field[0]; + a.add( id.toString()); + } + } + return a.toArray(); + } + + public void register(Page p) { + m_table.register(p); + p.addComponentStateParam(m_table, m_sources); + p.addComponentStateParam(m_table, m_sourcesSubscribed); + } + + public void headSelected(TableActionEvent e) { + throw new UnsupportedOperationException(); + } + + private void setCellRenderers() { + m_table.getColumn(0).setCellRenderer(new CheckBoxRenderer()); + } + + private final class CheckBoxRenderer implements TableCellRenderer { + public Component getComponent(Table table, PageState state, Object value, + boolean isSelected, Object key, + int row, int column) { + BigDecimal id = (BigDecimal) key; + String optionName = m_sources.marshalElement(id.abs()); + + + Option option = new Option(optionName, ""); + option.setGroup(m_checkboxGroup); + return option; + } + } + + +} + + +class RepositoriesTableModelBuilder + extends LockableImpl implements TableModelBuilder { + + RepositoriesTable m_parent; + + RepositoriesTableModelBuilder(RepositoriesTable parent) { + m_parent = parent; + } + + + public TableModel makeModel(Table t, PageState state) { + + return new RepositoriesTableModel(state); + } + + + class RepositoriesTableModel implements TableModel, DRConstants { + + private Iterator m_it; + private Object[] m_field = new Object[4]; + + RepositoriesTableModel(PageState state) { + m_it = m_parent.getQuery(state); + } + + public int getColumnCount() { + return 3; // same length as header String[] + } + + public Object getElementAt(int columnIndex) { + switch(columnIndex) { + case 0 : + int isMounted = ((BigDecimal) m_field[1]).intValue(); + if(isMounted == 1) { + return Boolean.TRUE; + } else { + return Boolean.FALSE; + } + case 1: + // return name + return m_field[2]; + case 2: + // return num of files + return m_field[3]; + default: + break; + } + return null; + } + + // always return the ID as key + public Object getKeyAt(int columnIndex) { + return m_field[0]; + } + + public boolean nextRow() { + if(m_it.hasNext()) { + m_field = (Object [])m_it.next(); + return true; + } else { + return false; + } + } + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/RepositoryPane.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/RepositoryPane.java new file mode 100644 index 000000000..b57d0d666 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/RepositoryPane.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.BoxPanel; +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.Page; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.SegmentedPanel; +import com.arsdigita.bebop.Tree; +import com.arsdigita.bebop.event.ChangeEvent; +import com.arsdigita.bebop.event.ChangeListener; +import java.math.BigDecimal; + +/** + * This class is the component in the Doc Repository UI that shows all + * mounted repositories and a form where to sign up or sign off + * repositories of group members. + * The current policy is to allow access to all the repositories + * of the members of a group. + * + * @author Stefan Deusch + */ + +class RepositoryPane extends BoxPanel + implements DRConstants, ChangeListener { + + private Tree m_tree; + + private Component m_Repositories; + + + /** + * Default constructor + */ + + public RepositoryPane() { + + setClassAttr("sidebarNavPanel"); + setAttribute("navbar-title", "Repositories"); + + BoxPanel leftSide = new BoxPanel(); + leftSide.setClassAttr("navbar"); + m_tree = new SuperTree(new RepositoriesSuperTreeModel()); + m_tree.addChangeListener(this); + leftSide.add(m_tree); + add(leftSide); + + SegmentedPanel rightSide = new SegmentedPanel(); + rightSide.setClassAttr("main"); + m_Repositories = makeRepositoriesPanel(rightSide); + add(rightSide); + } + + @Override + public void register(Page p) { + p.addGlobalStateParam(ROOTFOLDER_ID_PARAM); + p.addGlobalStateParam(SEL_FOLDER_ID_PARAM); + super.register(p); + } + + /** + * Implementation of the change listener. + * Updates the selected folder globally. + */ + public void stateChanged(ChangeEvent e) { + + PageState state = e.getPageState(); + String key = (String) m_tree.getSelectedKey(state); + + // first time, set to tree root and expand tree level + if(key==null) { + key = DRUtils.getRootFolder(state).getID().toString(); + m_tree.expand(key, state); + } + state.setValue(SEL_FOLDER_ID_PARAM, new BigDecimal(key)); + } + + /** + * Make the Repositories Table before the form. + */ + private Component makeRepositoriesPanel(SegmentedPanel main) { + + RepositoriesTable table = new RepositoriesTable(); + + return main.addSegment(REPOSITORIES_INFORMATION_HEADER, + new RepositoriesSelectionForm(table)); + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/SuperTree.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/SuperTree.java new file mode 100644 index 000000000..f46854623 --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/SuperTree.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.ControlLink; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.Tree; +import com.arsdigita.bebop.tree.TreeModel; +import com.arsdigita.bebop.tree.TreeCellRenderer; + +/** + * Customized Bebop Tree that shows the accessible Repositories + * at the root level and the inidividual File trees beneath it. + * The root level is constructed expanded. + * + * @author Stefan Deusch + */ +class SuperTree extends Tree { + + SuperTree(TreeModel tm) { + super(tm); + setCellRenderer(new RepositoryTreeCellRenderer()); + } +} + + +class RepositoryTreeCellRenderer implements TreeCellRenderer { + + public Component getComponent(Tree tree, + PageState state, + Object value, + boolean isSelected, + boolean isExpanded, + boolean isLeaf, + Object key) { + + String m_key = (String) key; + + if("0".equals(m_key)) { + return new Label(value.toString()); + } else { + return new ControlLink(value.toString()); + } + + } + + +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/ui/VersionUploadForm.java b/ccm-docrepo/src/com/arsdigita/docrepo/ui/VersionUploadForm.java new file mode 100644 index 000000000..1f19820ae --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/ui/VersionUploadForm.java @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.ui; + +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.FormData; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.event.FormValidationListener; +import com.arsdigita.bebop.event.PrintEvent; +import com.arsdigita.bebop.event.PrintListener; +import com.arsdigita.bebop.form.FileUpload; +import com.arsdigita.bebop.form.Submit; +import com.arsdigita.bebop.form.TextArea; +import com.arsdigita.bebop.parameters.NotEmptyValidationListener; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.dispatcher.MultipartHttpServletRequest; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.kernel.Kernel; + +import com.arsdigita.docrepo.File; +import com.arsdigita.docrepo.TypeChangeException; +import com.arsdigita.docrepo.Util; + +import java.math.BigDecimal; +import javax.servlet.http.HttpServletRequest; + +import org.apache.log4j.Logger; + +/** + * This component uploads a new version of a file. + * + * @author Stefan Deusch + */ + +class VersionUploadForm extends Form + implements FormInitListener, + FormProcessListener, + FormValidationListener, + DRConstants +{ + private static final String VERSION_UPLOAD_FORM = + "file-version"; + private static final String VERSION_TRANSACTION_DESCRIPTION = + "file-transaction-description"; + private static final String VERSION_FILE_UPLOAD = + "file-version-upload"; + + private static Logger s_log = Logger.getLogger(VersionUploadForm.class); + private FileUpload m_fileUpload; + private StringParameter m_versionDesc; + private RequestLocal m_fileData; + private FileInfoPropertiesPane m_parent; + + //This const allows for less than 4k bytes of 2byte unicode chars, plus + // a little wiggle room... + private static int FOUR_K_CHAR_LIMIT = 1994; + + /** + * Constructor with parent component. + */ + + public VersionUploadForm(FileInfoPropertiesPane parent) { + super(VERSION_UPLOAD_FORM, new ColumnPanel(2)); + setMethod(Form.POST); + setEncType("multipart/form-data"); + + m_parent = parent; + + // initialize the file + m_fileData = new RequestLocal() { + @Override + protected Object initialValue(PageState state) { + BigDecimal id = (BigDecimal) state.getValue(FILE_ID_PARAM); + File file = null; + try { + file = new File(id); + } catch(DataObjectNotFoundException nfe) { + // ... + } + return file; + } + }; + + m_fileUpload = new FileUpload(VERSION_FILE_UPLOAD); + m_fileUpload.addValidationListener(new NotEmptyValidationListener()); + + m_versionDesc = new StringParameter(VERSION_TRANSACTION_DESCRIPTION); + + add(new Label(FILE_NAME)); + add(makeFileLabel()); + + add(new Label(FILE_SOURCE)); + add(m_fileUpload); + + add(new Label(FILE_VERSION_DESCRIPTION)); + TextArea fversionDesc = new TextArea(m_versionDesc); + fversionDesc.setRows(10); + fversionDesc.setCols(40); + fversionDesc.addValidationListener(new NotEmptyValidationListener()); + add( fversionDesc); + + Submit submit = new Submit("file-version-upload"); + submit.setButtonLabel(FILE_SAVE); + add(new Label()); // spacer + + SimpleContainer sc = new SimpleContainer(); + sc.add(submit); + CancelButton cancel = new CancelButton(CANCEL); + sc.add(cancel); + + add(sc, ColumnPanel.LEFT); + + addInitListener(this); + addValidationListener(this); + addProcessListener(this); + } + + private File getFile(PageState s) { + return (File)m_fileData.get(s); + } + + private Label makeFileLabel() { + Label label = new Label(); + label.addPrintListener(new PrintListener() { + public void prepare(PrintEvent e) { + PageState state = e.getPageState(); + Label t= (Label) e.getTarget(); + t.setLabel(getFile(state).getName()); + } + }); + return label; + } + + public void init(FormSectionEvent e) { + PageState state = e.getPageState(); + + if ( Kernel.getContext().getParty() == null ) { + Util.redirectToLoginPage(state); + } + + } + + /** + * Receive uploaded file and reset file content, mime type, and + * description. Return to File properties screen. + */ + public void process(FormSectionEvent e) + throws FormProcessException { + + PageState state = e.getPageState(); + FormData data = e.getFormData(); + HttpServletRequest req = state.getRequest(); + + String fpath = (String)data.get(VERSION_FILE_UPLOAD); + fpath = DRUtils.extractFileName(fpath, state); + + java.io.File src = null; + if (fpath != null && fpath.length() > 0) { + src = ((MultipartHttpServletRequest)e.getPageState().getRequest()) + .getFile(VERSION_FILE_UPLOAD); + } + + // Try to update the file in the database + + File file = getFile(state); + // Annotate transaction description + String vdesc = (String)data.get(VERSION_TRANSACTION_DESCRIPTION); + //If version description string is over 4K in size, truncate... + if(vdesc.length() > FOUR_K_CHAR_LIMIT) + vdesc = vdesc.substring(0, FOUR_K_CHAR_LIMIT); + + try { + file.saveNewRevision(src, fpath, vdesc); + } catch (TypeChangeException ex) { + throw new FormProcessException(ex.getMessage(), ex); + } + + + m_parent.displayPropertiesAndActions(state); + } + + + /** + * Validate if user tries to upload a file with a different Mime type than + * the original. This is not supported. + */ + public void validate(FormSectionEvent e) + throws FormProcessException { + + PageState state = e.getPageState(); + FormData data = e.getFormData(); + HttpServletRequest req = state.getRequest(); + + String uploadedFileName = (String) data.get(VERSION_FILE_UPLOAD); + String newType = Util.guessContentType(uploadedFileName,req); + String oldType = getFile(state).getContentType(); + + if (!newType.equalsIgnoreCase(oldType)) { + data.addError(VERSION_FILE_UPLOAD, + DIFFERENT_MIMETYPE_ERROR.localize(req).toString()); + } + } +} diff --git a/ccm-docrepo/src/com/arsdigita/docrepo/util/GlobalizationUtil.java b/ccm-docrepo/src/com/arsdigita/docrepo/util/GlobalizationUtil.java new file mode 100644 index 000000000..7b5ca401f --- /dev/null +++ b/ccm-docrepo/src/com/arsdigita/docrepo/util/GlobalizationUtil.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo.util; + +import com.arsdigita.globalization.Globalized; +import com.arsdigita.globalization.GlobalizedMessage; + +/** + *

+ * . + * Contains methods to simplify globalizing keys + *

+ * + * @author sarnold@redhat.com + * @version $Revision: #4 $ $Date: 2004/08/17 $ + */ + +public class GlobalizationUtil implements Globalized { + + private static final String BUNDLE_NAME = + "com.arsdigita.docrepo.ui.DocsResources"; + + public static GlobalizedMessage globalize(String key) { + return new GlobalizedMessage(key, BUNDLE_NAME); + } + public static GlobalizedMessage globalize(String key, Object[] args) { + return new GlobalizedMessage(key, BUNDLE_NAME, args); + + } +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/DocsSuite.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/DocsSuite.java new file mode 100644 index 000000000..3e0c8ab7f --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/DocsSuite.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +import com.arsdigita.kernel.EmailAddress; +import com.arsdigita.kernel.Group; +import com.arsdigita.kernel.PersonName; +import com.arsdigita.kernel.User; +import com.arsdigita.tools.junit.extensions.BaseTestSetup; +import com.arsdigita.tools.junit.framework.PackageTestSuite; +import junit.framework.Test; + +/** + * Document Manager test suite. + * + * @author ron@arsdigita.com, sdeusch@arsdigita.com + * @version $Id: docrepo/DocsSuite.java pboy $ + */ + +public class DocsSuite extends PackageTestSuite { + + public static Test suite() { + DocsSuite suite = new DocsSuite(); + populateSuite(suite); + BaseTestSetup wrapper = new BaseTestSetup(suite); + wrapper.setInitScriptTarget("com.arsdigita.docmgr.installer.Initializer"); + //wrapper.setSetupSQLScript(System.getProperty("test.sql.dir") + "/kernel/setup.sql"); + //wrapper.setTeardownSQLScript(System.getProperty("test.sql.dir") + "/kernel/teardown.sql"); + return wrapper; + } + + + /** + * Utility method to generate a random user for testing + */ + + static User getRandomUser() { + + String key = String.valueOf(System.currentTimeMillis()); + String email = key + "-docs-test@arsdigita.com"; + String first = key + "-docs-test-given-name"; + String last = key + "-docs-test-family-name"; + + User user = new User(); + user.setPrimaryEmail(new EmailAddress(email)); + + PersonName name = user.getPersonName(); + name.setGivenName(first); + name.setFamilyName(last); + + user.save(); + + return user; + } + + /** + * Utility method to generate a random group for testing + */ + + static Group getRandomGroup() { + + String key = String.valueOf(System.currentTimeMillis()); + String email = key + "-docs-test@arsdigita.com"; + String name = key + "-docs-test-group-name"; + + Group group = new Group(); + group.setPrimaryEmail(new EmailAddress(email)); + group.setName(name); + group.save(); + + return group; + } +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/FileTest.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/FileTest.java new file mode 100644 index 000000000..4233876c4 --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/FileTest.java @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr; + +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.domain.DomainObjectFactory; +import com.arsdigita.mail.ByteArrayDataSource; +import com.arsdigita.persistence.OID; +import com.arsdigita.tools.junit.framework.BaseTestCase; +import com.arsdigita.versioning.TransactionCollection; + +import javax.activation.DataHandler; +import javax.activation.DataSource; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Test cases for files. + * + * @author ron@arsdigita.com + * @author stefan@arsdigita.com + * @version $Id: //apps/docmgr/dev/test/src/com/arsdigita/docmgr/FileTest.java#8 $ + */ + +public class FileTest extends BaseTestCase { + + private Folder m_parent; + + final static String TEST_IMAGE = + System.getProperty("test.base.dir") + "/com/arsdigita/docmgr/file.gif"; + final static String TEST_FILE = + System.getProperty("test.base.dir") + "/com/arsdigita/docmgr/file.html"; + final static String TEST_FILE_NOEXT = + System.getProperty("test.base.dir") + "/com/arsdigita/docmgr/file"; + + private static final org.apache.log4j.Logger s_log = + org.apache.log4j.Logger.getLogger(FileTest.class); + + public FileTest(String name) { + super(name); + } + + /** + * Create a parent folder to store files in. + */ + + protected void setUp() throws Exception { + super.setUp(); + String name = "file-test-folder"; + String desc = null; + + m_parent = new Folder(name,desc); + m_parent.save(); + + s_log.error("Starting test " + getName()); + } + + + protected void tearDown() throws Exception { + s_log.error("Ending test " + getName()); + super.tearDown(); + } + + /** + * Create a File. + */ + public void testFileCreate001() throws Exception { + String name = "f001"; + String desc = "f001 description"; + + File f = new File(name,desc,m_parent); + f.save(); + assertEquals(f.getName(), name); + assertEquals(f.getDescription(), desc); + } + + /** + * Create a File and use it to store an HTML document. This is + * the common operation used when transferring an uploaded file + * into the document manager. + */ + + public void testFileCreate002() throws Exception { + String name = "f002"; + String desc = "f002 description"; + + java.io.File src = new java.io.File(TEST_FILE); + + File f1 = null; + final String mimeType = Util.guessContentType(TEST_FILE, null); + f1 = new File(m_parent); + f1.setContent(src,name,desc, mimeType); + f1.save(); + + assertEquals(f1.getName(), name); + assertEquals(f1.getDescription(), desc); + assertEquals(f1.getContentType(), "text/html"); + + File f2 = null; + f2 = new File(f1.getID()); + + assertEquals(f1.getName(), f2.getName()); + assertEquals(f1.getDescription(), f2.getDescription()); + assertEquals(f1.getContentType(), f2.getContentType()); + assertEquals(f1.getSize(), f2.getSize()); + assertNotNull(f1.getRawContent()); + assertNotNull(f2.getRawContent()); + assertEquals(new String(f1.getRawContent()), + new String(f2.getRawContent())); + } + + /** + * Create a File and use it to store an image. + */ + + public void testFileCreate003() throws Exception { + String name = "f003"; + String desc = "f003 description"; + + java.io.File src = new java.io.File(TEST_IMAGE); + + File f1 = null; + final String mimeType = Util.guessContentType(TEST_IMAGE, null); + f1 = new File(m_parent); + f1.setContent(src,name,desc, mimeType); + f1.save(); + + assertEquals(f1.getName(), name); + assertEquals(f1.getDescription(), desc); + assertEquals(f1.getContentType(), "image/gif"); + + File f2 = null; + f2 = new File(f1.getID()); + + assertEquals(f1.getName(), f2.getName()); + assertEquals(f1.getDescription(), f2.getDescription()); + assertEquals(f1.getContentType(), f2.getContentType()); + } + + /** + * Create a File and use it to store data encapsulated by a + * DataHandler. This is the method typically used to transfer + * content from an email attachment into the document manager. + */ + + public void testFileCreate004() throws Exception { + String name = "f004.txt"; + String desc = "f004 description"; + String type = "text/plain"; + String text = "hello, world"; + + + // Store a plain text "document" in the File + DataSource source = new ByteArrayDataSource(text, type, name); + + File f1 = null; + f1 = new File(m_parent); + f1.setContent(source, name, desc, type); + f1.save(); + + assertEquals(name, f1.getName()); + assertEquals(desc, f1.getDescription()); + assertEquals(type, f1.getContentType()); + assertEquals(text, new String(f1.getRawContent())); + + File f2 = null; + f2 = new File(f1.getID()); + + assertEquals(name, f2.getName()); + assertEquals(desc, f2.getDescription()); + assertEquals(type, f2.getContentType()); + assertEquals(text, new String(f2.getRawContent())); + } + + /** + * Verify that a file can be moved from one folder to another. + */ + + public void testFileMove() throws Exception { + Folder root = FolderTest.buildFolderTree(); + + Folder f0 = null; + Folder f1 = null; + + f0 = root.retrieveFolder("f0"); + f1 = root.retrieveFolder("f1"); + + String name = "file"; + String desc = "file description"; + File file = null; + + file = new File(name,desc,f0); + file.save(); + + assertEquals(file.getID(), f0.getResourceID(name)); + + // Move the file from f0 to f1 + + file.setParent(f1); + file.save(); + + // Verify the file no longer exists in old location + + try { + f0.getResourceID(name); + fail("Retrieved file from old location"); + } catch (DataObjectNotFoundException ex) { + // correct + } + + // Retrieve the file from the new location + + BigDecimal id = new BigDecimal(-1); + id = f1.getResourceID(name); + + + assertEquals(file.getID(), id); + assertEquals(file.getPath(), f1.getPath() + Resource.SEPARATOR + name); + + } + + + /** + * Verify that a file can be copied. + */ + + public void testFileCopy() throws Exception { + String name = "file"; + String desc = "file desc"; + + java.io.File src = new java.io.File(TEST_FILE); + + final String mimeType = Util.guessContentType(TEST_FILE, null); + File orig = new File(m_parent); + orig.setContent(src,name,desc, mimeType ); + orig.save(); + + File copy = null; + copy = (File) orig.copyTo(name + "-copy"); + + assertEquals(orig.getDescription(), copy.getDescription()); + assertEquals(orig.getContentType(), copy.getContentType()); + + + } + + /** + * Test factory method for instantiating files. + */ + + public void testFileFactory() throws Exception { + + String name = "file"; + String desc = "file desc"; + + java.io.File src = new java.io.File(TEST_FILE); + + final String mimeType = Util.guessContentType(TEST_FILE, null); + File f0 = new File(m_parent); + f0.setContent(src,name,desc, mimeType); + f0.save(); + + OID oid = new OID(File.BASE_DATA_OBJECT_TYPE, + f0.getID()); + File f1 = (File) DomainObjectFactory.newInstance(oid); + + assertEquals(f0.getID(), f1.getID()); + assertEquals(f0.getName(), f1.getName()); + assertEquals(f0.getDescription(), f1.getDescription()); + assertEquals(f0.getContentType(), f1.getContentType()); + } + + /** + * Test basic revision history. + */ + + public void testFileRevisions() throws Exception { + + String name = "file"; + String desc = "file-description"; + File file = new File(name,desc,m_parent); + + // Save several revisions of this file + int numRevisions = 10; + + // Store the content and symbolic revision tags in arrays so + // we can use them below. + + String content[] = new String[numRevisions]; + String tags[] = new String[numRevisions]; + + for (int i = 0; i < numRevisions; i++) { + content[i] = "file-content-" + i; + //file.saveNewRevision(); + file.setText(content[i]); + file.save(); + + // Apply a tag to the last transaction + final String tag = String.valueOf(i) + "-"; + tags[i] = tag; + file.applyTag(tag); + } + + } + + public void testFileDisplayName() throws Exception { + + // Create a hash map with file name as a key mapping to + // expected value + + HashMap fileNames = new HashMap(); + fileNames.put("f001.txt", "f001"); + fileNames.put("file.html", "file"); + fileNames.put("file.htm", "file"); + fileNames.put("file name", "file name"); + fileNames.put(".file", ".file"); + fileNames.put("file name.doc", "file name"); + fileNames.put(".a.b.c", ".a.b.c"); + fileNames.put("file a.b.c", "file a.b"); + fileNames.put("a.b.c", "a.b"); + + File file = new File(m_parent); + + Iterator iter = fileNames.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + String name = (String) entry.getKey(); + String displayName = (String) entry.getValue(); + + file.setName(name); + assertEquals(displayName, file.getDisplayName()); + } + } + + /** + * Verify that file MIME types cannot be changed once the file is + * persistent. + */ + + public void testFileTypeChange() throws Exception { + + String name = "file.html"; + String desc = "file desc"; + + java.io.File src = new java.io.File(TEST_FILE); + + final String mimeType = Util.guessContentType(TEST_FILE, null); + File file = new File(m_parent); + file.setContent(src,name,desc, mimeType); + file.save(); + + assertEquals("text/html", file.getContentType()); + + // Update properties of the file and verify that changes can + // be saved. + + file.setName("a new name"); + file.setDescription("a new description"); + file.save(); + + // Try setting the content to a different MIME type and saving + // the file. + + try { + final String gifType = Util.guessContentType(TEST_IMAGE, null); + src = new java.io.File(TEST_IMAGE); + name = "file.gif"; + file.setContent(src,name,desc, gifType); + file.save(); + fail("Changed MIME type of existing file"); + } catch (TypeChangeException ex) { + // correct + } + } + + /** + * Create an HTML file for testing. The file is initialized but + * not saved. + */ + + private File createTestFile() throws Exception { + + String name = "file.html"; + String desc = "file desc"; + + java.io.File src = new java.io.File(TEST_FILE); + + final String mimeType = Util.guessContentType(TEST_FILE, null); + File file = new File(m_parent); + file.setContent(src,name,desc, mimeType); + return file; + } + + /** + * Verify the behavior of rules governing file names and changes + * to file names. + */ + + public void testFileNameRules() throws Exception { + + File file = createTestFile(); + file.save(); + + HashMap fileExtensions = new HashMap(); + fileExtensions.put("file", "file.html"); + fileExtensions.put("file.html", "file.html"); + fileExtensions.put("file.txt", "file.txt"); + + // Test the appendExtension utility to verify that it + // correctly constructs file names with inherited extensions. + + Iterator iter = fileExtensions.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + String name = (String) entry.getKey(); + String expected = (String) entry.getValue(); + + assertEquals("Failed generating extension for " + name, + expected, + file.appendExtension(name)); + } + + // Verify the set of file names that are valid for renaming + // our test file. + + HashMap fileNames = new HashMap(); + fileNames.put("f001.txt", Boolean.FALSE); + fileNames.put("f001.htm", Boolean.TRUE); + fileNames.put("f001", Boolean.TRUE); + fileNames.put("f001 bar", Boolean.TRUE); + fileNames.put("foo bar .htm", Boolean.TRUE); + + iter = fileNames.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + String name = (String) entry.getKey(); + Boolean isValid = (Boolean) entry.getValue(); + + assertEquals("Failed testing the validity of " + name, + isValid.booleanValue(), + file.isValidNewName(name)); + } + } + + + /** + * Test the correct initialize of MIME type from an HTTP request + * with and without an explicit content type header. + */ + public void testFileUpload() throws Exception { + + String name = "file"; + String desc = "file desc"; + + TestServletRequest request = new TestServletRequest(); + request.setContentType("text/html"); + + java.io.File src = new java.io.File(TEST_FILE); + + final String mimeType = Util.guessContentType(TEST_FILE, null); + File file = new File(m_parent); + file.setContent(src,name,desc, mimeType); + + + file.save(); + assertEquals("Failed to set the content type from the request", + "text/html", + file.getContentType()); + + // Verify that we can't reset the content type after the file + // has been saved + + try { + file.setContent(src,name,desc, "application/zip"); + fail("Set content type to a different type!"); + } catch (TypeChangeException ex) { + // correct + } + + // Verify that setting the same type works + file.setContent(src,name,desc, Util.guessContentType(TEST_FILE, null)); + file.save(); + + } + + + + /** + * Main method required to make this test runnable. + */ + + public static void main(String args[]) { + junit.textui.TestRunner.run(FileTest.class); + } +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/FolderTest.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/FolderTest.java new file mode 100644 index 000000000..e4a28efbd --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/FolderTest.java @@ -0,0 +1,503 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr; + +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.domain.DomainObjectFactory; +import com.arsdigita.persistence.DataQuery; +import com.arsdigita.persistence.OID; +import com.arsdigita.persistence.Session; +import com.arsdigita.persistence.SessionManager; +import com.arsdigita.persistence.UniqueConstraintException; +import com.arsdigita.persistence.DataCollection; +import com.arsdigita.tools.junit.framework.BaseTestCase; +import com.arsdigita.versioning.TransactionCollection; +import org.apache.log4j.Logger; + +import java.math.BigDecimal; +import java.util.Vector; + +/** + * Test cases for folders; + * + * @author ron@arsdigita.com + * @author sdeusch@arsdigita.com + * @version $Id: //apps/docmgr/dev/test/src/com/arsdigita/docmgr/FolderTest.java#6 $ + */ + +public class FolderTest extends BaseTestCase { + + final static String TEST_FILE_NAME = "file.html"; + final static String TEST_IMAGE_NAME = "file.gif"; + + final static String TEST_FILE_PATH = + System.getProperty("test.base.dir") + "/com/arsdigita/docmgr/" + TEST_FILE_NAME; + final static String TEST_IMAGE_PATH = + System.getProperty("test.base.dir") + "/com/arsdigita/docmgr/" + TEST_FILE_NAME; + + private static final Logger s_log = Logger.getLogger(FolderTest.class); + public FolderTest(String name) { + super(name); + } + + /** + * Tests to make sure uniqueness constraints work as intended + */ + public void testConstraints() throws Exception { + + Vector folderNames = new Vector(); + folderNames.addElement("textxx/subfolder1"); + folderNames.addElement("textxx/subfolder2"); + + Folder root = new Folder("ROOT", "root"); + root.save(); + + Vector folders = new Vector(); + for (int j = 0; j < folderNames.size(); j++) { + String folderName = (String) folderNames.elementAt(j); + try { + Folder currentFolder = root.retrieveFolder(folderName); + folders.addElement(currentFolder); + } catch (DataObjectNotFoundException notFound) { + Folder currentFolder = root.createFolders(folderName); + folders.addElement(currentFolder); + } + } + + assertEquals(2, folders.size()); + } + + /** + * Create a folder. + */ + + public void testFolderCreate() throws Exception { + String name = "f001"; + String desc = "f001 folder"; + + Folder f = new Folder(name, desc); + f.save(); + assertEquals(f.getName(), name); + assertEquals(f.getDescription(), desc); + } + + /** + * Create subfolders and verify that a parent cannot contain two + * folders with the same name. + */ + + public void testFolderUniquenes() throws Exception { + String name = "f002"; + String desc = "f002 folder"; + + Folder f0 = null; + Folder f1 = null; + f0 = new Folder(name, desc); + f0.save(); + + f1 = new Folder(name, desc, f0); + f1.save(); + + try { + Folder f2 = new Folder(name, desc, f0); + f2.save(); + fail("Created identical sub folders"); + } catch (ResourceExistsException ex) { + // triggered unique contraint violation + } + } + + /** + * Retrieve sub folders by name. + */ + + public void testFolderRetrieveByName() throws Exception { + String name = "f003"; + String desc = "f003 folder"; + + Folder fldr[] = new Folder[3]; + + fldr[0] = new Folder(name,desc); + fldr[0].save(); + for (int i = 1; i < fldr.length; i++) { + fldr[i] = new Folder(name,desc,fldr[i-1]); + fldr[i].save(); + } + + // Set up the path elements. This array will store the + // relative path from the root folder to each sub folder. + + String path[] = new String[fldr.length]; + path[0] = ""; + path[1] = name; + for (int i = 2; i < path.length; i++) { + path[i] = path[i-1] + Resource.SEPARATOR + name; + } + + // Retrieve each sub folder by path + + for (int i = 1; i < fldr.length; i++) { + Folder f = null; + try { + f = fldr[0].retrieveFolder(path[i]); + } catch (DataObjectNotFoundException ex) { + fail(ex.getMessage()); + } catch (InvalidNameException ex) { + fail(ex.getMessage()); + } + + assertNotNull(f); + assertEquals(fldr[i].getID(), f.getID()); + } + + // Verify that retrieving a non-existing path returns null + + try { + fldr[0].retrieveFolder("non-existent-path"); + fail("Retrieved a non-existent path"); + } catch (DataObjectNotFoundException ex) { + // ignore + } + } + + /** + * Create sub folders using relative path names. + */ + + public void testFolderCreateByPath() throws Exception { + String name = "f004"; + String desc = "f004 folder"; + + // Create the root folder + + Folder root = null; + root = new Folder(name,desc); + root.save(); + + // Create all path elements (relative to root) + + String path[] = new String[4]; + path[0] = root.getName(); + for (int i = 1; i < path.length; i++) { + path[i] = path[i-1] + Folder.SEPARATOR + name; + } + + // Create the first and last sub folders + + root.createFolders(path[1]); + root.createFolders(path[path.length-1]); + + // Verify that all intermediate folders were also created + + for (int i = 1; i < path.length; i++) { + Folder f = null; + f = root.retrieveFolder(path[i]); + assertNotNull(f); + } + + // Verify that trying to create an existing folder fails + + try { + root.createFolders(path[path.length-1]); + fail("Created duplicate folder"); + } catch (ResourceExistsException ex) { + // caught the unique constraint violation + } + } + + + /** + * Retrieve a file in a folder + */ + + public void testFolderRetrieveFile() throws Exception { + // create parent folder with one file + String name = "f006"; + String desc = "f006 folder"; + Folder parent = null; + File f1 = null; + parent = new Folder(name,desc); + parent.save(); + s_log.warn(""); + final String mimeType = Util.guessContentType(TEST_FILE_NAME, null); + f1 = new File(parent); + f1.setContent(new java.io.File(TEST_FILE_PATH),TEST_FILE_NAME, + "test file", + mimeType); + f1.save(); + s_log.warn(""); + s_log.warn("File name:" + f1.getDisplayName()); + + s_log.warn("Folder path:" + parent.getPath()); + s_log.warn("File path: " + f1.getPath()); + // retrieve file by name + File f2 = null; + f2 = parent.retrieveFile(TEST_FILE_NAME); + + assertNotNull(f2); + assertEquals(f1.getID(), f2.getID()); + assertEquals(f1.getPath(), f2.getPath()); + + // load a non-existing file + f2 = null; + try { + f2 = parent.retrieveFile("nonExistingFileName"); + fail("Loaded non-existing File"); + } catch(DataObjectNotFoundException e) { + // correctly caught the exception + } + } + + + /** + * Verify that a folder cannot be deleted if it contains files or + * other folders. + */ + + public void testFolderDelete() throws Exception { + String name = "root"; + String desc = "root folder"; + + Folder root = new Folder(name,desc); + root.save(); + + // add a subfolder + Folder sub = new Folder(name,desc,root); + sub.save(); + + // add a file + File file = new File(name+".txt",desc,root); + file.save(); + + root.delete(); + } + + /** + * Test moving a folder to a new location. + */ + + public void testFolderMove() throws Exception { + Folder root = buildFolderTree(); + + // Create one additional subfolder inside the folder we'll be + // moving. + + Folder child = null; + // pre /root/f0/f0 + // post /root/f0/f0/f0 + child = root.createFolders("f0/f0/f0"); + child.save(); + assertEquals("/root/f0/f0/f0", child.getPath()); + assertEquals("f0", child.getName()); + // Try moving /root/f0/f0 to /root/f2 + + Folder target = null; + target = root.retrieveFolder("f0/f0"); + + assertEquals(target.getID(), child.getParentResourceID()); + assertEquals("/root/f0/f0", target.getPath()); + target.setName("f2"); + target.save(); + assertEquals("/root/f0/f2", target.getPath()); + assertEquals("f2", target.getName()); + + target.setParent(root); + target.save(); + + assertEquals("/root/f2", target.getPath()); + assertEquals(target.getID(), child.getParentResourceID()); + try { + root.retrieveFolder("f0/f0"); + fail("Folder should no longer be in this location"); + } catch (DataObjectNotFoundException ex) { + // correct + } + + // Try retrieving the original subfolder f0/f0 using its new + // path. + + Folder sub = null; + sub = root.retrieveFolder("f2"); + + assertEquals(sub.getID(), target.getID()); + assertEquals("/root/f2", sub.getPath()); + + // Try retrieving the subfolder from the new location + sub = new Folder(child.getID()); + System.out.println("EXPECT: "); + System.out.println("/root/f2/f0"); + System.out.println("Actual:"); + System.out.println(sub.getPath()); + + // Needed because of session caching. The DataOperation that updates the child + // paths happens behind the scenes of the cache. The retrieve operation + // will flush the cache for the type. + DataCollection folders = SessionManager.getSession().retrieve(Folder.BASE_DATA_OBJECT_TYPE); + folders.addEqualsFilter("id", child.getID()); + folders.next(); + + sub = new Folder(folders.getDataObject()); + System.out.println("EXPECT: "); + System.out.println("/root/f2/f0"); + System.out.println("Actual:"); + System.out.println(sub.getPath()); + + assertEquals("/root/f2/f0", sub.getPath()); + + } + + /** + * Verify that a folder can't be moved to one of its own + * subdirectories + */ + + public void testFolderMoveCycle() throws Exception { + try { + Folder root = buildFolderTree(); + Folder destination = root.createFolders("f0/f0/f0/f0/f0"); + Folder source = root.retrieveFolder("f0/f0"); + + System.out.println("testFolderMoveCycle sourcepath: " + source.getPath()); + System.out.println("testFolderMoveCycle destpath: " + destination.getPath()); + source.setParent(destination); + source.save(); + fail("moved a folder into one of its sub folders"); + } catch (ResourceException ex) { + // Correct, this should NOT work! + } + } + + + /** + * Verify that a folder and all of its content can be copied. + */ + + public void testFolderCopy() throws Exception { + + Folder root = buildFolderTree(); + + Folder orig = null; + orig = root.retrieveFolder("f0"); + + // Place some children into the subfolder + + String desc = "child"; + String child[] = { + "child-0", + "child-1" + }; + + for (int i = 0; i < child.length; i++) { + File f = new File(child[i], desc, orig); + f.save(); + } + + // Copy the subfolder to a new root-level folder named "f2" + + Folder copy = (Folder) orig.copyTo("f2", root); + + // Verify that the children were copied successfully + + for (int i = 0; i < child.length; i++) { + BigDecimal id = copy.getResourceID(child[i]); + File f = new File(id); + assertEquals(child[i], f.getName()); + assertEquals(desc, f.getDescription()); + } + } + + /** + * Test factory method for instantiating folders. + */ + + public void testFolderFactory() throws Exception { + + Folder root = buildFolderTree(); + Folder fldr = null; + OID oid = new OID(ResourceImpl.BASE_DATA_OBJECT_TYPE, + root.getID()); + fldr = (Folder) DomainObjectFactory.newInstance(oid); + + assertEquals(root.getID(), fldr.getID()); + assertEquals(root.getName(), fldr.getName()); + assertEquals(root.getDescription(), fldr.getDescription()); + } + + + /** + * Build a folder tree for testing, of the following form: + * + * root/f0 + * root/f0/f0 + * root/f0/f1 + * root/f1 + * root/f1/f0 + * root/f1/f1 + * + * @return the root of the folder tree + */ + + protected static Folder buildFolderTree() throws Exception { + String name = "root"; + String desc = "root folder"; + Folder root = null; + + String folderNames[] = { + "f0/f0", + "f0/f1", + "f1/f0", + "f1/f1" + }; + + root = new Folder(name,desc); + root.save(); + + for (int i = 0; i < folderNames.length; i++) { + root.createFolders(folderNames[i]); + } + return root; + } + + /** + * List the contents of a folder (for debugging) + */ + + private void list(Folder folder) { + Session session = SessionManager.getSession(); + DataQuery query = session.retrieveQuery + ("com.arsdigita.docmgr.getResourceTree"); + query.setParameter("startFolderID", folder.getID()); + + System.out.println("----- Listing folder " + folder.getName()); + while (query.next()) { + System.out.println((BigDecimal) query.get("id") + " " + + (String) query.get("name") + " " + + (String) query.get("path")); + } + query.close(); + } + + /** + * Main method required to make this test runnable. + */ + + public static void main(String args[]) { + junit.textui.TestRunner.run(FolderTest.class); + } +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/MimeTypeTest.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/MimeTypeTest.java new file mode 100644 index 000000000..9619021ed --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/MimeTypeTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr; + +import com.arsdigita.mimetypes.MimeType; +import com.arsdigita.tools.junit.framework.BaseTestCase; + +import java.io.*; + + +/** + * Test cases for Mime types. + * + * @author ron@arsdigita.com + * @author stefan@arsdigita.com + * @version $Id: //apps/docmgr/dev/test/src/com/arsdigita/docmgr/MimeTypeTest.java#6 $ + */ + +public class MimeTypeTest extends BaseTestCase { + + final static String MIME_TYPE = "test/docmgr"; + final static String MIME_EXTENSION = "dmgr"; + final static String MIME_LABEL= "Test Mime Type"; + final static String MIME_CLASS = "MimeType"; + + public MimeTypeTest(String name) { + super(name); + } + + /** + * Test loading a simple XML configuration. + */ + + public void testMimeTypeCreation() { + + // create an XML configuration and load it + + loadMimeType(getMimeXML(MIME_TYPE, + MIME_EXTENSION, + MIME_LABEL, + MIME_CLASS)); + + // verify the created type can be retrieved + + MimeType type = MimeType.loadMimeType(MIME_TYPE); + assertNotNull(type); + + // verify that all attributes are correct, and that file types + // are guessed correctly based on the extensions. + + assertEquals(MIME_EXTENSION, type.getFileExtension()); + assertEquals(MIME_LABEL, type.getLabel()); + assertEquals(MIME_TYPE, + type.guessMimeType("dmgr").getMimeType()); + assertEquals(MIME_TYPE, + type.guessMimeTypeFromFile("test.dmgr").getMimeType()); + } + + /** + * Test that MIME types are updated. + */ + + public void testMimeTypeUpdates() { + + // create a MIME type that will be updated + + String javaClass = MimeType.class.getName(); + + MimeType type = MimeType.createMimeType + (MIME_TYPE, javaClass, MimeType.TYPE); + type.setLabel(MIME_LABEL + " to be updated"); + type.setFileExtension(MIME_EXTENSION); + type.save(); + + // load the new configuration + + loadMimeType(getMimeXML(MIME_TYPE, + MIME_EXTENSION, + MIME_LABEL, + MIME_CLASS)); + + // verify that the type was updated + + type = MimeType.loadMimeType(MIME_TYPE); + assertEquals(MIME_LABEL, type.getLabel()); + } + + /** + * Creates the XML document describing the MIME type specified by + * the arguments. + */ + + private static String getMimeXML(String type, + String extensions, + String label, + String mimeClass) { + return + ""+ + "" + + ""; + } + + /** + * Invokes the XML loader to read a configuration from a String. + */ + + private static void loadMimeType(String mimeXML) { + try { + MimeTypeXMLLoader.parse + (new StringBufferInputStream(mimeXML)); + } catch(java.io.IOException ioex) { + System.out.println("DOCS: "+ioex.getMessage()); + } catch (InvalidMimeTypeFormatException imex) { + System.out.println("DOCS: "+imex.getMessage()); + } + } + + + /** + * Main method required to make this test runnable. + */ + + public static void main(String args[]) { + junit.textui.TestRunner.run(MimeTypeTest.class); + } +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/PermissionsTest.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/PermissionsTest.java new file mode 100644 index 000000000..5c011f189 --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/PermissionsTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr; + +import com.arsdigita.xmlutil.XMLTestCase; +import com.arsdigita.docmgr.xml.DocsJDOMFactory; + +public class PermissionsTest extends XMLTestCase { + public PermissionsTest(String name) { + super(name); + } + + protected void setUp() throws Exception { + super.setUp(); + //TestRepository.get(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + //TestRepository.clear(); + } + + public void testDocsPermissions() throws Exception { + //executeXMLTest(new DocsJDOMFactory(), "com/arsdigita/docmgr/xml/CreateTests.xml", false); + } + public void testMovePermissions() throws Exception { + //executeXMLTest(new DocsJDOMFactory(), "com/arsdigita/docmgr/xml/MoveTests.xml", false); + } +} + diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/PopulateDocrepo.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/PopulateDocrepo.java new file mode 100644 index 000000000..bf8279e6b --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/PopulateDocrepo.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docrepo; + +import java.math.BigDecimal; +import java.util.List; + +import com.arsdigita.docrepo.ui.RecentUpdatedDocsPortlet; +import com.arsdigita.kernel.User; +import com.arsdigita.persistence.Session; +import com.arsdigita.persistence.SessionManager; +import com.arsdigita.persistence.TransactionContext; +import com.arsdigita.populate.Utilities; +import com.arsdigita.populate.apps.AbstractPopulateApp; +import com.arsdigita.populate.apps.PopulateApp; +import com.arsdigita.util.Assert; +import com.arsdigita.web.ApplicationType; + +/** + * @author bche + */ +public class PopulateDocrepo + extends AbstractPopulateApp + implements PopulateApp { + + private static final String ARGS_DESC = + "3 PopulateDocrepo args: numFolderLevels, numFolders, numFiles"; + + /* (non-Javadoc) + * @see com.arsdigita.populate.apps.PopulateApp#populateApp(java.util.List) + */ + public void populateApp(List args) { + Session ses = SessionManager.getSession(); + TransactionContext txn = ses.getTransactionContext(); + + Repository repo = (Repository) getApp(); + + // validate the arguments + validateArgs(args, 3, ARGS_DESC); + int iFolderLevels = ((Integer) args.get(0)).intValue(); + int iFolders = ((Integer) args.get(1)).intValue(); + int iFiles = ((Integer) args.get(2)).intValue(); + + // Assert.assertTrue(iFolderLevels > 0, "iFolderLevels must be > 0"); + // Assert.assertTrue(iFolders >= 0, "iFolders must be >= 0"); + // Assert.assertTrue(iFiles > 0, "iFiles must be > 0"); + Assert.isTrue(iFolderLevels > 0, "iFolderLevels must be > 0"); + Assert.isTrue(iFolders >= 0, "iFolders must be >= 0"); + Assert.isTrue(iFiles > 0, "iFiles must be > 0"); + + //get binary file for uploading + java.io.File binaryFile = Utilities.getBinaryFile(); + + //get a user for making the files + User u = User.retrieve((BigDecimal)(Utilities.getUsersIDs(1).get(0))); + s_log.debug("using user " + u.getName() + " to create files"); + + Folder rootFolder = repo.getRoot(); + txn.beginTxn(); + rootFolder.setLastModifiedUser(u); + rootFolder.setCreationUser(u); + rootFolder.save(); + txn.commitTxn(); + + String sBaseString = Utilities.getBaseString(getBaseStringSeed()); + + //populate the repository + for (int i = 0; i < iFolders; i++) { + txn.beginTxn(); + Folder parentFolder = rootFolder; + Folder folder = null; + + //create sub-folders + for (int j = 0; j < iFolderLevels; j++) { + + //create the folder + String sFolderName = "Folder" + sBaseString + i + j; + folder = new Folder(sFolderName, "", parentFolder); + folder.setCreationUser(u); + folder.setLastModifiedUser(u); + folder.save(); + s_log.info( + "Inserted folder " + + sFolderName + + ", child of " + + parentFolder.getName()); + + //create files in this folder + for (int k = 0; k < iFiles; k++) { + String sFileName = + "File" + sBaseString + i + j + k + ".gif"; + File file = new File(folder); + file.setContent( + binaryFile, + sFileName, + "uploaded file", + "image/gif"); + file.setCreationUser(u); + file.setLastModifiedUser(u); + file.save(); + s_log.info( + "Inserted file " + + sFileName + + " in folder " + + folder.getName()); + } + //update parentFolder + parentFolder = folder; + } + txn.commitTxn(); + } + } + + /* (non-Javadoc) + * @see com.arsdigita.populate.apps.PopulateApp#getArgsDescription() + */ + public String getArgsDescription() { + return ARGS_DESC; + } + + /* (non-Javadoc) + * @see com.arsdigita.populate.apps.PopulateApp#getAppType() + */ + public ApplicationType getAppType() { + ApplicationType appType = + ApplicationType.retrieveApplicationTypeForApplication( + Repository.BASE_DATA_OBJECT_TYPE); + if (s_log.isDebugEnabled()) { + s_log.debug( + "returning app type " + appType.getApplicationObjectType()); + } + return appType; + } + + /* (non-Javadoc) + * @see com.arsdigita.populate.apps.AbstractPopulateApp#getPortletType() + */ + protected String getPortletType() { + return RecentUpdatedDocsPortlet.BASE_DATA_OBJECT_TYPE; + } + +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/QueryTest.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/QueryTest.java new file mode 100644 index 000000000..ab5f3d2ac --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/QueryTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr; + +/* + * Copyright (C) 2003, 2003 Red Hat Inc. All Rights Reserved. + * + * The contents of this file are subject to the CCM Public + * License (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of + * the License at http://www.redhat.com/licenses/ccmpl.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + */ + + +/** + * QueryTest + * + */ + +import com.arsdigita.tools.junit.framework.BaseTestCase; +import com.arsdigita.persistence.Session; +import com.arsdigita.persistence.SessionManager; +import com.arsdigita.persistence.DataQuery; +import com.arsdigita.docmgr.ui.DMUtils; +import com.arsdigita.docmgr.ui.DMConstants; +import org.apache.log4j.Logger; + +import java.math.BigDecimal; + +public class QueryTest extends BaseTestCase implements DMConstants { + private static Logger s_log = Logger.getLogger(QueryTest.class); + + public QueryTest(String name) { + super(name); + } + + + public void testGetChildren() { + Session session = SessionManager.getSession(); + Folder root = new Folder("root", "root"); + root.save(); + + DataQuery query = session.retrieveQuery(GET_CHILDREN); + query.setParameter(FOLDER_ID, root.getID()); + + assertEquals("Empty folder shouldn't have children", 0, query.size()); + File file = new File("ChildFile", "Child File", root); + file.save(); + + assertEquals("Folder should have one child!", 1, query.size()); + + query.addEqualsFilter(IS_FOLDER, Boolean.TRUE); + assertEquals("Folder shouldn't have folder children", 0, query.size()); + Folder subfolder = new Folder("sub", "sub", root); + subfolder.save(); + + assertEquals("Folder should have 1 folder child", 1, query.size()); + + } + + +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/RepositoryTest.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/RepositoryTest.java new file mode 100644 index 000000000..74a483b38 --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/RepositoryTest.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr; + +import com.arsdigita.tools.junit.framework.BaseTestCase; + + +/** + * Test cases for repositories. + * + * @author ron@arsdigita.com + * @author ddao@arsdigita.com + * @author gavin@arsdigita.com + * @version $Id: //apps/docmgr/dev/test/src/com/arsdigita/docmgr/RepositoryTest.java#4 $ + */ + +public class RepositoryTest extends BaseTestCase { + + private static final String REPOSITORY_URL = "Repository-test"; + private static final String REPOSITORY_TITLE = "RepositoryTest"; + private static final String WORKSPACE_URL = "workspace-test"; + private static final String WORKSPACE_TITLE = "WorkspaceTest"; + + public RepositoryTest(String name) { + super(name); + } + + + /** + * Create a Repository. + */ + + public void testRepositoryCreate001() { + Repository r1 = Repository.create(REPOSITORY_URL, + REPOSITORY_TITLE, + null); + + assertNotNull(r1.getRoot()); + + } + + public void testRepositoryRetrieveByUser() { + /* + User user = DocsSuite.getRandomUser(); + user.save(); + + + Repository personalRepository = Repository.create(REPOSITORY_URL, + REPOSITORY_TITLE, null); + + Repository r0 = Repository.retrieveRepository(user); + assertNotNull(r0.getRoot()); + assertEquals(personalRepository.getID(), r0.getID()); + + User user2 = new User(user.getID()); + + Repository r1 = Repository.retrieveRepository(user2); + assertEquals(r0.getID(), r1.getID()); + */ + } + + + + /** + * Test creating folders inside a repository. This test is meant + * to cover the basic usage of the inbound document handler. + */ + + public void testRepositoryCreateFolders() throws Exception { + + Repository r = Repository.create(REPOSITORY_URL, + REPOSITORY_TITLE, + null); + r.save(); + + // Retrieve the root folder + + Folder root = r.getRoot(); + + // Verify that sub folders can be created correctly + + assertNotNull(root.createFolders("test/s0")); + assertNotNull(root.createFolders("test/s1")); + assertNotNull(root.createFolders("1")); + + // Test several variants of malformed paths, including leading + // and trailing slashes, and single-character folder names. + + String malformedPath[] = { + "/test/s0/", + "/test/s0", + "test/s0/", + "/1", + "/1/", + "1/" + }; + + for (int i = 0; i < malformedPath.length; i++) { + + Folder f; + + try { + f = root.retrieveFolder(malformedPath[i]); + fail("Retrieved malformed path: " + malformedPath[i]); + } catch (InvalidNameException ex) { + // Correctly caught the name excepion. Recover by + // trying again with a canonicalized path + + f = root.retrieveFolder + (Folder.getCanonicalPath(malformedPath[i])); + } + } + + // Verify that canonicalizing a null string simply throws an + // exception + + try { + Folder.getCanonicalPath(null); + fail("Canonicalized a null string"); + } catch (InvalidNameException ex) { + // correct + } + + } + + + /** + * Main method required to make this test runnable. + */ + + public static void main(String args[]) { + junit.textui.TestRunner.run(RepositoryTest.class); + } + +} + + + diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/TestRepository.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/TestRepository.java new file mode 100644 index 000000000..515f5cf4e --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/TestRepository.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr; + +/* + * Copyright (C) 2003, 2003 Red Hat Inc. All Rights Reserved. + * + * The contents of this file are subject to the CCM Public + * License (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of + * the License at http://www.redhat.com/licenses/ccmpl.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + */ + + +/** + * TestRepository + * + */ +public class TestRepository { + static Repository s_repository = null; + + public static Repository get() { + if (null == s_repository) { + s_repository = Repository.create("docmgr", "My Doc Mgr", null); + } + return s_repository; + } + + public static void clear() { + s_repository = null; + } +} + diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/TestServletRequest.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/TestServletRequest.java new file mode 100644 index 000000000..e59fc2ada --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/TestServletRequest.java @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr; + +import javax.servlet.*; +import javax.servlet.http.*; +import java.io.UnsupportedEncodingException; +import java.util.Map; +import java.util.HashMap; + + +/** + * A simple implementation of the HTTP servlet request interface for + * testing. It only provides methods to set and get the Content-Type + * header. + */ + +class TestServletRequest implements HttpServletRequest { + + private String m_contentType; + private HashMap parameters; + + private static String CONTENT_TYPE = "Content-Type"; + + public TestServletRequest() { + // empty + } + + void setContentType(String contentType) { + m_contentType = contentType; + } + + public String getHeader(String name) { + if (name.equals(CONTENT_TYPE)) { + return m_contentType; + } else { + return null; + } + } + + // The remaining methods are not used + + public String getAuthType() { + throw new UnsupportedOperationException(); + } + + public String getContextPath() { + throw new UnsupportedOperationException(); + } + + public Cookie[] getCookies() { + throw new UnsupportedOperationException(); + } + + public long getDateHeader(String name) { + throw new UnsupportedOperationException(); + } + + public java.util.Enumeration getHeaderNames() { + throw new UnsupportedOperationException(); + } + + public java.util.Enumeration getHeaders(String name) { + throw new UnsupportedOperationException(); + } + + public int getIntHeader(String name) { + throw new UnsupportedOperationException(); + } + + public String getMethod() { + throw new UnsupportedOperationException(); + } + + public String getPathInfo() { + throw new UnsupportedOperationException(); + } + + public String getPathTranslated() { + throw new UnsupportedOperationException(); + } + + public String getQueryString() { + throw new UnsupportedOperationException(); + } + + public String getRemoteUser() { + throw new UnsupportedOperationException(); + } + + public String getRequestedSessionId() { + throw new UnsupportedOperationException(); + } + + public String getRequestURI() { + throw new UnsupportedOperationException(); + } + + public String getServletPath() { + throw new UnsupportedOperationException(); + } + + public HttpSession getSession() { + throw new UnsupportedOperationException(); + } + + public HttpSession getSession(boolean create) { + throw new UnsupportedOperationException(); + } + + public java.security.Principal getUserPrincipal() { + throw new UnsupportedOperationException(); + } + + public boolean isRequestedSessionIdFromCookie() { + throw new UnsupportedOperationException(); + } + + public boolean isRequestedSessionIdFromURL() { + throw new UnsupportedOperationException(); + } + + public boolean isRequestedSessionIdFromUrl() { + throw new UnsupportedOperationException(); + } + + public boolean isRequestedSessionIdValid() { + throw new UnsupportedOperationException(); + } + + public boolean isUserInRole(String role) { + throw new UnsupportedOperationException(); + } + + // Unused method from ServletRequest + + public java.lang.Object getAttribute(java.lang.String name) { + throw new UnsupportedOperationException(); + } + + public java.util.Enumeration getAttributeNames() { + throw new UnsupportedOperationException(); + } + + public java.lang.String getCharacterEncoding() { + throw new UnsupportedOperationException(); + } + + public int getContentLength() { + throw new UnsupportedOperationException(); + } + + public java.lang.String getContentType() { + throw new UnsupportedOperationException(); + } + + public ServletInputStream getInputStream() { + throw new UnsupportedOperationException(); + } + + public java.util.Locale getLocale() { + throw new UnsupportedOperationException(); + } + + public java.util.Enumeration getLocales() { + throw new UnsupportedOperationException(); + } + + public java.lang.String getParameter(java.lang.String name) { + throw new UnsupportedOperationException(); + } + + public java.util.Enumeration getParameterNames() { + throw new UnsupportedOperationException(); + } + + public java.lang.String[] getParameterValues(java.lang.String name) { + throw new UnsupportedOperationException(); + } + + public java.lang.String getProtocol() { + throw new UnsupportedOperationException(); + } + + public java.io.BufferedReader getReader() { + throw new UnsupportedOperationException(); + } + + public java.lang.String getRemoteAddr() { + throw new UnsupportedOperationException(); + } + + public java.lang.String getRemoteHost() { + throw new UnsupportedOperationException(); + } + + public RequestDispatcher getRequestDispatcher(java.lang.String path) { + throw new UnsupportedOperationException(); + } + + public java.lang.String getScheme() { + throw new UnsupportedOperationException(); + } + + public java.lang.String getServerName() { + throw new UnsupportedOperationException(); + } + + public java.lang.String getRealPath(java.lang.String path) { + throw new UnsupportedOperationException(); + } + + public int getServerPort() { + throw new UnsupportedOperationException(); + } + + public boolean isSecure() { + throw new UnsupportedOperationException(); + } + + public void removeAttribute(java.lang.String name) { + throw new UnsupportedOperationException(); + } + + public void setAttribute(java.lang.String name, java.lang.Object o) { + throw new UnsupportedOperationException(); + } + + public Map getParameterMap() { + return parameters; + } + + public StringBuffer getRequestURL() { + return null; + } + + public void setCharacterEncoding(String env) + throws UnsupportedEncodingException { + } +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/file b/ccm-docrepo/test/src/com/arsdigita/docrepo/file new file mode 100644 index 000000000..db0eaba19 --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/file @@ -0,0 +1 @@ +binary test data diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/file.gif b/ccm-docrepo/test/src/com/arsdigita/docrepo/file.gif new file mode 100644 index 000000000..93bfb9f78 Binary files /dev/null and b/ccm-docrepo/test/src/com/arsdigita/docrepo/file.gif differ diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/file.html b/ccm-docrepo/test/src/com/arsdigita/docrepo/file.html new file mode 100644 index 000000000..c63f833c8 --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/file.html @@ -0,0 +1,19 @@ + + + This is an attached HTML document + + +

This is an attached HTML document

+ + + +
+ArsDigita -- Open for e-business +
+What are you looking at? +
+ + + + diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/CreateTests.xml b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/CreateTests.xml new file mode 100644 index 000000000..824a45f5c --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/CreateTests.xml @@ -0,0 +1,52 @@ + + + + + + + SWA + This is a folder created by SWA + + + + + User + This is a folder created by Joe User + + + + + Editor + This is a folder created by Joe Editor + + + + + Manager + This is a folder created by Joe Manager + + + + + + + + + docs-mimetypes.xml + ./build/WEB-INF/resources + Test File + + + + + docs-mimetypes.xml + ./build/WEB-INF/resources + New Revision! + + + + + diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DeleteFolder.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DeleteFolder.java new file mode 100644 index 000000000..87f21a98b --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DeleteFolder.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr.xml; + +import com.arsdigita.xmlutil.PermissionsAction; +import com.arsdigita.docmgr.Folder; +import com.arsdigita.kernel.Party; +import org.apache.log4j.Logger; + +public class DeleteFolder extends PermissionsAction { + private static Logger s_log = Logger.getLogger(DeleteFolder.class); + + public DeleteFolder() { + super("delete_folder", Namespaces.DOCS); + } + + public void doPermissionTest() throws Exception { + String id = getFolderID(); + Folder folder = DocMap.instance().getFolder(id); + Party user = getUser(); + s_log.warn("User: " + user.getPrimaryEmail() + " is deleting folder: " + folder.getName() + " with id: " + folder.getOID()); + + folder.delete(); + s_log.warn("Deleted"); + DocMap.instance().removeFolder(id); + } + + public String getFolderID() { + String id = getAttributeValue("folder_id"); + return id; + } +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DocMap.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DocMap.java new file mode 100644 index 000000000..d112ea877 --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DocMap.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr.xml; + +import com.arsdigita.docmgr.Folder; +import com.arsdigita.docmgr.File; +import com.arsdigita.docmgr.Repository; +import com.arsdigita.docmgr.TestRepository; +import com.arsdigita.persistence.OID; +import com.arsdigita.xmlutil.TestResource; +import com.arsdigita.xmlutil.ResourceRegistry; + +import java.util.HashMap; +import java.util.Map; + +public class DocMap implements TestResource { + + public static DocMap instance() { + return s_instance; + } + + public void cleanUp() { + m_folderMap.clear(); + } + + public void addFolder(String folderID, Folder folder) throws Exception { + m_folderMap.put(folderID, folder.getOID()); + } + + public void removeFolder(String folderID) { + m_folderMap.remove(folderID); + } + public Folder getFolder(String folderID) throws Exception { + Folder folder; + if ( folderID.equals("root") ) { + Repository docManager = TestRepository.get(); + folder = docManager.getRoot(); + + } else { + OID id = (OID) m_folderMap.get(folderID); + folder = new Folder(id); + } + return folder; + } + + public void addFile(String fileID, File file) throws Exception { + m_fileMap.put(fileID, file.getOID()); + } + + public void removeFile(String fileID) { + m_fileMap.remove(fileID); + } + public File getFile(String fileID) throws Exception { + + OID id = (OID) m_fileMap.get(fileID); + File file = new File(id); + return file; + } + + private DocMap() { + ResourceRegistry.instance().addResource(this); + } + private Map m_folderMap = new HashMap(); + private Map m_fileMap = new HashMap(); + + private static DocMap s_instance = new DocMap(); +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DocTests.xml b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DocTests.xml new file mode 100644 index 000000000..4327322b6 --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DocTests.xml @@ -0,0 +1,93 @@ + + + + + + + SWA + This is a folder created by SWA + + + + + User + This is a folder created by Joe User + + + + + Editor + This is a folder created by Joe Editor + + + + + Manager + This is a folder created by Joe Manager + + + + + + + + + SWA2 + This is a folder created by SWA + + + + + User2 + This is a folder created by Joe User + + + + + Editor2 + This is a folder created by Joe Editor + + + + + User3 + This is a folder created by Joe User + + + + + Editor3 + This is a folder created by Joe Editor + + + + + Manager2 + This is a folder created by Joe Manager + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DocsJDOMFactory.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DocsJDOMFactory.java new file mode 100644 index 000000000..cd090f1e3 --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DocsJDOMFactory.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr.xml; + +import com.arsdigita.xmlutil.TestJDOMFactory; +import org.jdom.JDOMException; + +public class DocsJDOMFactory extends TestJDOMFactory { + public DocsJDOMFactory() throws JDOMException { + super(); + } + + public String getTypeDefs() { + return System.getProperty("user.dir") + "/test/src/" + TYPE_DEFS; + } + + + private static final String TYPE_DEFS = DocsJDOMFactory.class.getName().replace('.','/') + ".xml"; + + +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DocsJDOMFactory.xml b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DocsJDOMFactory.xml new file mode 100644 index 000000000..a58382d8f --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/DocsJDOMFactory.xml @@ -0,0 +1,14 @@ + + + +]> + + + + + + + + + diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/FileElement.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/FileElement.java new file mode 100644 index 000000000..9f8082d16 --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/FileElement.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr.xml; +import org.jdom.Element; +import com.arsdigita.docmgr.Folder; + +public class FileElement extends Element { + public FileElement() { + super("file", Namespaces.DOCS); + } + + public Folder getParentFolder() throws Exception { + String parentID = getAttributeValue("folder_id"); + + if (null == parentID) { + parentID = "root"; + } + + Folder parent = DocMap.instance().getFolder(parentID); + return parent; + } + + public String getFileID() { + String id = getAttributeValue("file_id"); + return id; + + } + public String getFileName() { + String name = getChild("file_name", Namespaces.DOCS).getTextTrim(); + return name; + } + + public String getFilePath() { + String path = getChild("file_path", Namespaces.DOCS).getTextTrim(); + return path; + } + + public String getFullPath() { + return getFilePath() + "/" + getFileName(); + } + public String getDescription() { + String description = getChild("description",Namespaces.DOCS).getTextTrim(); + return description; + } + +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/FolderElement.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/FolderElement.java new file mode 100644 index 000000000..1a1df874f --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/FolderElement.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr.xml; + +import org.jdom.Element; + +public class FolderElement extends Element { + public FolderElement() { + super("folder", Namespaces.DOCS); + } + + public String getFolderName() { + Element nameElem = getChild("name", Namespaces.DOCS); + String name = nameElem.getTextTrim(); + return name; + } + public String getDescription() { + Element descElem = getChild("description", Namespaces.DOCS); + String description = descElem.getTextTrim(); + return description; + } + + public String getID() { + String id = getAttributeValue("folder_id"); + return id; + } + + public String getParentID() { + String id = getAttributeValue("parent_id"); + return id; + } +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/MoveFolder.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/MoveFolder.java new file mode 100644 index 000000000..d0f4f3511 --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/MoveFolder.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr.xml; + +import com.arsdigita.xmlutil.PermissionsAction; +import com.arsdigita.docmgr.Folder; +import com.arsdigita.util.Assert; + +public class MoveFolder extends PermissionsAction { + public MoveFolder() { + super("move_folder", Namespaces.DOCS); + } + + public void doPermissionTest() throws Exception { + Folder destination = getDestinationFolder(); + Folder movingFolder = getFolderToMove(); + + movingFolder.setParent(destination); + movingFolder.save(); + Assert.equal(destination, movingFolder.getParent()); + } + + private Folder getDestinationFolder() throws Exception { + String id = getAttributeValue("dest_folder_id"); + Folder folder = DocMap.instance().getFolder(id); + return folder; + } + + private Folder getFolderToMove() throws Exception { + String id = getAttributeValue("folder_id"); + Folder folder = DocMap.instance().getFolder(id); + return folder; + } +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/MoveTests.xml b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/MoveTests.xml new file mode 100644 index 000000000..56ef612ee --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/MoveTests.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/Namespaces.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/Namespaces.java new file mode 100644 index 000000000..98603e9ca --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/Namespaces.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr.xml; + +import org.jdom.Namespace; + +public class Namespaces { + public static final Namespace DOCS = Namespace.getNamespace("docs", "http://redhat.com/xml/docs"); + +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/NewFile.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/NewFile.java new file mode 100644 index 000000000..602817e68 --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/NewFile.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr.xml; + +import com.arsdigita.docmgr.*; +import com.arsdigita.docmgr.ui.DMConstants; +import com.arsdigita.kernel.Kernel; +import com.arsdigita.kernel.KernelExcursion; +import com.arsdigita.kernel.Party; +import com.arsdigita.kernel.permissions.PermissionDescriptor; +import com.arsdigita.kernel.permissions.PermissionService; +import com.arsdigita.kernel.permissions.PrivilegeDescriptor; +import com.arsdigita.util.UncheckedWrapperException; +import com.arsdigita.versioning.Transaction; +import com.arsdigita.versioning.TransactionCollection; +import com.arsdigita.xmlutil.PermissionsAction; +import org.apache.log4j.Logger; + +import java.util.Locale; +public class NewFile extends PermissionsAction { + private static Logger s_log = Logger.getLogger(NewFile.class); + + public NewFile() { + super("new_file", Namespaces.DOCS); + s_log.warn("Creating NewFile Element!!!!"); + } + + public void doPermissionTest() throws Exception { + s_log.warn("Creating file!"); + File file = makeFile(); + s_log.warn("created file: " + file.getName() + " with mime-type: " + file.getContentType()); + } + + private File makeFile() throws Exception { + FileElement elem = (FileElement) getChild("file", Namespaces.DOCS); + Folder parent = elem.getParentFolder(); + java.io.File diskFile = new java.io.File(elem.getFullPath()); + + final String mimeType = Util.guessContentType(elem.getFileName(), null); + final File f1 = new File(parent); + try { + f1.setContent(diskFile, + elem.getFileName(), + elem.getDescription(), + mimeType); + f1.save(); + } catch (TypeChangeException ex) { + throw new UncheckedWrapperException(ex.getMessage(), ex); + } + + new KernelExcursion() { + protected void excurse() { + Party currentParty = Kernel.getContext().getParty(); + setParty(Kernel.getSystemParty()); + PermissionService.grantPermission(new PermissionDescriptor(PrivilegeDescriptor.ADMIN, + f1, + currentParty)); + PermissionService.setContext(f1, TestRepository.get()); + }}.run(); + + // annotate first file upload as initial version + + TransactionCollection tc = f1.getTransactions(false); + if (tc.next()) { + Transaction t1 = tc.getTransaction(); + // t1.setDescription(DMConstants.FILE_UPLOAD_INITIAL_TRANSACTION_DESCRIPTION.localize(Locale.ENGLISH) + // .toString()); + // t1.save(); + } + tc.close(); + DocMap.instance().addFile(elem.getFileID(), f1); + + return f1; + } + + +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/NewFolder.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/NewFolder.java new file mode 100644 index 000000000..ab7c19e79 --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/NewFolder.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr.xml; + +import com.arsdigita.xmlutil.PermissionsAction; +import com.arsdigita.docmgr.Folder; + +public class NewFolder extends PermissionsAction { + public NewFolder() { + super("new_folder", Namespaces.DOCS); + } + + public void doPermissionTest() throws Exception { + FolderElement elem = (FolderElement) getChild("folder", Namespaces.DOCS); + String parentID = elem.getParentID(); + Folder parent = getRootFolder(parentID); + + Folder newFolder = new Folder(elem.getFolderName(), elem.getDescription(), parent); + newFolder.save(); + + DocMap.instance().addFolder(elem.getID(), newFolder); + } + + private Folder getRootFolder(String parentID) throws Exception { + Folder parent; + if (null == parentID) { + parentID = "root"; + } + + parent = DocMap.instance().getFolder(parentID); + return parent; + } +} diff --git a/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/UploadRevision.java b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/UploadRevision.java new file mode 100644 index 000000000..0c6ddd010 --- /dev/null +++ b/ccm-docrepo/test/src/com/arsdigita/docrepo/xml/UploadRevision.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +package com.arsdigita.docmgr.xml; + +import com.arsdigita.xmlutil.PermissionsAction; +import com.arsdigita.docmgr.File; + +public class UploadRevision extends PermissionsAction { + public UploadRevision() { + super("upload_revision", Namespaces.DOCS); + } + + public void doPermissionTest() throws Exception { + FileElement elem = (FileElement) getChild("file", Namespaces.DOCS); + java.io.File diskFile = new java.io.File(elem.getFullPath()); + + File file = DocMap.instance().getFile(elem.getFileID()); + file.saveNewRevision(diskFile, + diskFile.getName(), + elem.getDescription()); + } +} diff --git a/ccm-docrepo/web/WEB-INF/resources/docs-mimetypes.xml b/ccm-docrepo/web/WEB-INF/resources/docs-mimetypes.xml new file mode 100644 index 000000000..e1c6d1894 --- /dev/null +++ b/ccm-docrepo/web/WEB-INF/resources/docs-mimetypes.xml @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ccm-docrepo/web/__ccm__/apps/docrepo/xsl/index.xsl b/ccm-docrepo/web/__ccm__/apps/docrepo/xsl/index.xsl new file mode 100644 index 000000000..faf2f3d70 --- /dev/null +++ b/ccm-docrepo/web/__ccm__/apps/docrepo/xsl/index.xsl @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/ccm-docrepo/web/assets/cw/applications/document-16.gif b/ccm-docrepo/web/assets/cw/applications/document-16.gif new file mode 100644 index 000000000..1c9cb6125 Binary files /dev/null and b/ccm-docrepo/web/assets/cw/applications/document-16.gif differ diff --git a/ccm-docrepo/web/assets/cw/applications/document-32.gif b/ccm-docrepo/web/assets/cw/applications/document-32.gif new file mode 100644 index 000000000..5c2892797 Binary files /dev/null and b/ccm-docrepo/web/assets/cw/applications/document-32.gif differ diff --git a/ccm-docrepo/web/packages/docrepo/xsl/docrepo.xsl b/ccm-docrepo/web/packages/docrepo/xsl/docrepo.xsl new file mode 100644 index 000000000..91fe9ae0e --- /dev/null +++ b/ccm-docrepo/web/packages/docrepo/xsl/docrepo.xsl @@ -0,0 +1,599 @@ + + + + + + + + + + + + + + + +/packages/portalserver/www/assets +/packages/portalserver/www/css + + + + + + <xsl:value-of select="bebop:title"/> + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + + + + + + + +
+ + + + + + + + + #e1d5b0 + #ffffff + + + + + + + + + + + + + + + + + + + + + + + +   + + + + + + + + +   + + + + + + + &nbsp;&nbsp;&nbsp;&nbsp; + + + + + + split_pane_left_item_selected + split_pane_left_item + + + + + + + + Expand + + /assets/plus-box.gif + + + + + + Collapse + + /assets/minus-box.gif + + + + + + + + + + + + + folder + + /assets/folder.gif + + + +      + + folder + + /assets/folder.gif + + + + +   + + + + + +   + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+ + + + + Unable to copy on following items. + + + Unable to move on following items. + + + Unable to delete on following items. + + +
    + +
  • +
    +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name:
Description:
Size:
Type:
Last Modified:
Revision:
Author:
URI:
+ +
+ + + + + + + + + + + + + + +
+ + + + +
+
+ + +
+ + + + + + +
+ + + + +
+ +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
       + + + + + + + +
    
+
  
+ + + +
+
+ + + +
+
+
+ + + + +
+ + + +
+ +
+ + + + + + + + + + + + + + +
+ + +
+
+ + +
+
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
       + + + + + + + +
   +   
+
  
+ + + +
+ + +
+ + + + + + + + + + +
+
+ + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ccm-docrepo/web/packages/docrepo/xsl/docrepo_en.xsl b/ccm-docrepo/web/packages/docrepo/xsl/docrepo_en.xsl new file mode 100644 index 000000000..9bda4d132 --- /dev/null +++ b/ccm-docrepo/web/packages/docrepo/xsl/docrepo_en.xsl @@ -0,0 +1,126 @@ + + + + + + + + + + +
    +
  • Name:
  • +
  • Email: + + +
    +
  • +
  • Screen Name:
  • +
  • URL:
  • +
  • User ID:
  • +
  • Member State: +
  • +
+ +
+ + + + +

Adminstrative Actions

+ + + +
+ + + + For +
+
+ + + +

Note

+

If this user does not currently have an authentication record, + one will be created when you submit this form and the account + will be enabled for login to the system.

+
+ + + + + + + + + (primary) + + + + + + + + + + + + + + + + + + +
+

You don't have permission to perform the requested action.

+
+
+ + + +

Your search returned no results.

+
+ + + +

Results matching your query:

+
    + +
  • +
    +
+
+ + + + +
    +
  • Group Name:
  • +
  • Primary Email:
  • +
+ +
+ + +

None

+
+ + +   + ( + + ) + + +
+ +