1 /* Copyright (C) 2000-2005 Thomas Bopp, Thorsten Hampel, Ludger Merkens
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * $Id: annotateable.pike,v 1.6 2008/04/15 14:14:44 exodusd Exp $
20 #include <exception.h>
25 #include <attributes.h>
26 //! The annotation features of a sTeam object are implemented in this file.
27 //! Object uses it so any object inside a sTeam server features a list
28 //! of annotations. The functions to add and remove annotations are located
29 //! in Object and call the low level functions in this class.
37 array aoAnnotations; // list of annotations
38 object oAnnotates; // refering to ...
40 string get_identifier();
42 void require_save(void|string ident, void|string index);
45 * Initialization of annotations on this object.
48 * @see remove_annotation
51 void init_annotations()
53 aoAnnotations = ({ });
60 * Add an annotation to this object. Any object can be an annotations, but
61 * usually a document should be used here.
63 * @param object ann - the documentation
64 * @return if adding was successfull or not.
65 * @see remove_annotation
68 bool add_annotation(object ann)
71 THROW("Fatal error: annotation is not a proxy !", E_ERROR);
72 LOG("Adding annotation: " + ann->get_object_id() + " on "+
74 return do_add_annotation(ann);
80 bool do_add_annotation(object ann)
82 if ( objectp(ann->get_annotating() ) )
83 steam_error("add_annotation: Annotation already on %d",
84 ann->get_annotating()->get_object_id());
85 aoAnnotations += ({ ann });
87 require_save(STORE_ANNOTS);
94 * Remove an annotation from the object. The function just removes
95 * the annotation from the list of annotations.
97 * @param object ann - the annotation to delete
98 * @return if removing was successfull.
102 bool remove_annotation(object ann)
104 if ( !IS_PROXY(ann) )
105 THROW("Fatal error: annotation is not a proxy !", E_ERROR);
106 if ( search(aoAnnotations, ann) == -1 )
107 THROW("Annotation not present at document !", E_ERROR);
109 aoAnnotations -= ({ ann });
110 ann->set_annotating(0);
111 require_save(STORE_ANNOTS);
118 * Remove all annotations. This will move the annotation to their
119 * authors. The function is called when the object is deleted.
123 void remove_all_annotations()
127 foreach( aoAnnotations, object ann ) {
128 if ( objectp(ann) && ann->get_environment() == null ) {
129 object creator = ann->get_creator();
130 object trash = creator->query_attribute(USER_TRASHBIN);
136 FATAL("Failed to delete Annotation: %O", err);
140 if ( objectp(oAnnotates) )
146 * This function returns a copied list of all annotations of this
149 * @return the array of annotations
150 * @see get_annotations_for
152 array get_annotations(void|int from_obj, void|int to_obj)
154 array annotations = ({ });
156 if ( !arrayp(aoAnnotations) )
157 aoAnnotations = ({ });
159 aoAnnotations -= ({ 0 }); // remove 0 values of deleted annotations
160 for (int i = sizeof(aoAnnotations) - 1; i >= 0; i-- )
162 object ann = aoAnnotations[i];
163 if ( ann->status() >= 0 && i >= from_obj && ( !to_obj || i < to_obj ) )
164 annotations += ({ ann });
170 * This function returns a copied list of all annotations of this
171 * object which match a given classtype
173 * @return the array of annotations
174 * @see get_annotations
176 array get_annotations_by_class(int class_id)
178 array tmp=get_annotations();
179 foreach(tmp, object curr)
180 if((curr->get_object_class() & class_id)==0)
185 object get_annotation_byid(string name)
187 array tmp=get_annotations();
188 foreach(tmp, object ann) {
189 if ( ann->get_object_id() == (int)name )
196 * Get the object we are annotating.
198 * @return the object we annotated
200 object get_annotating()
206 * Set the annotating object.
208 * @param object obj - the annotating object
210 void set_annotating(object obj)
213 require_save(STORE_ANNOTS);
218 * Get only the annotations for a specific user. If no user is given
219 * this_user() will be used.
221 * @param object|void user - the user to get the annotations for
222 * @return array of annotations readable by the user
223 * @see get_annotations
226 get_annotations_for(object|void user, void|int from_obj, void|int to_obj)
228 if ( !objectp(user) ) user = this_user();
230 array user_annotations = ({ });
231 if ( !intp(from_obj) )
234 foreach ( aoAnnotations, object annotation ) {
235 if ( !objectp(annotation) ) continue;
238 _SECURITY->check_access(
239 annotation, user, SANCTION_READ, ROLE_READ_ALL, false);
242 user_annotations = ({ annotation }) + user_annotations;
245 return user_annotations[from_obj-1..];
246 return user_annotations[from_obj-1..to_obj-1];
251 * Retrieve annotations is for storing the annotations in the database.
252 * Only the global _Database object is able to call this function.
254 * @return Mapping of object data.
256 * @see restore_annotations
259 final mapping retrieve_annotations()
261 if ( CALLER != _Database )
262 THROW("Caller is not the Database object !", E_ACCESS);
264 return ([ "Annotations":aoAnnotations,
265 "Annotates": oAnnotates, ]);
271 * Called by database to restore the object data again upon loading.
273 * @param mixed data - the object data
275 * @see retrieve_annotations
279 restore_annotations(mixed data)
281 if ( CALLER != _Database )
282 THROW("Caller is not the Database object !", E_ACCESS);
284 aoAnnotations = data["Annotations"];
285 oAnnotates = data["Annotates"];
286 if ( !arrayp(aoAnnotations) )
288 aoAnnotations = ({ });
289 require_save(STORE_ANNOTS);
296 * Returns the annotations of this object, optionally filtered by object
297 * class, attribute values or pagination.
298 * The description of the filters and sort options can be found in the
299 * filter_objects_array() function of the "searching" module.
302 * Return all the annotations that have been created or last modified by user
303 * "root" in the last 24 hours, recursively and sorted by modification date
304 * (newest first) and return only the first 10 results:
305 * get_inventory_filtered(
307 * ({ "-", "!class", CLASS_DOCUMENT }),
308 * ({ "-", "attribute", "DOC_LAST_MODIFIED", "<", time()-86400 }),
309 * ({ "+", "function", "get_creator", "==", USER("root") }),
310 * ({ "+", "attribute", "DOC_USER_MODIFIED", "==", USER("root") }),
313 * ({ ">", "attribute", "DOC_LAST_MODIFIED" })
316 * @param filters (optional) an array of filters (each an array as described
317 * in the "searching" module) that specify which objects to return
318 * @param sort (optional) an array of sort entries (each an array as described
319 * in the "searching" module) that specify the order of the items
320 * @param offset (optional) only return the objects starting at (and including)
322 * @param length (optional) only return a maximum of this many objects
323 * @param max_depth (optional) max recursion depth (0 = only return
324 * annotations of this object)
325 * @return a mapping ([ "objects":({...}), "total":nr, "length":nr,
326 * "start":nr, "page":nr ]), where the "objects" value is an array of
327 * objects that match the specified filters, sort order and pagination.
328 * The other indices contain pagination information ("total" is the total
329 * number of objects after filtering but before applying "length", "length"
330 * is the requested number of items to return (as in the parameter list),
331 * "start" is the start index of the result in the total number of objects,
332 * and "page" is the page number (starting with 1) of pages with "length"
333 * objects each, or 0 if invalid).
335 mapping get_annotations_paginated ( array|void filters, array|void sort, int|void offset, int|void length, int|void max_depth )
337 return get_module( "searching" )->paginate_object_array( low_get_annotations_recursive( 0, max_depth ), filters, sort, offset, length );
341 * Returns the annotations of this object, optionally filtered, sorted and
342 * limited by offset and length. This returns the same as the "objects" index
343 * in the result of get_annotations_paginated() and is here for compatibility
344 * reasons and ease of use (if you don't need pagination information).
346 * @see get_annotations_paginated
348 array get_annotations_filtered ( array|void filters, array|void sort, int|void offset, int|void length, int|void max_depth )
350 return get_annotations_paginated( filters, sort, offset, length, max_depth )["objects"];
353 protected array low_get_annotations_recursive ( int depth, void|int max_depth )
355 if ( max_depth > 0 && depth > max_depth ) return ({ });
356 array annotations = ({ });
357 foreach ( aoAnnotations, mixed annotation ) {
358 if ( !objectp(annotation) ) continue;
359 annotations += ({ annotation });
360 mixed rec_res = annotation->low_get_annotations_recursive( depth + 1, max_depth );
361 if ( arrayp(rec_res) ) annotations += rec_res;