annotateable._pike
Go to the documentation of this file.
1 /* Copyright (C) 2000-2005 Thomas Bopp, Thorsten Hampel, Ludger Merkens
2  *
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.
7  *
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.
12  *
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
16  *
17  * $Id: annotateable.pike,v 1.6 2008/04/15 14:14:44 exodusd Exp $
18  */
19 #include <macros.h>
20 #include <exception.h>
21 #include <classes.h>
22 #include <access.h>
23 #include <database.h>
24 #include <roles.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.
30 class annotateable {
31 public:
32 
33 
34 
35 
36 
37  array aoAnnotations; // list of annotations
38  object oAnnotates; // refering to ...
39 
40 string get_identifier();
41 void update_path();
42  void require_save(void|string ident, void|string index);
43 
44 /**
45  * Initialization of annotations on this object.
46  *
47  * @see add_annotation
48  * @see remove_annotation
49  */
50 private:
51  void init_annotations()
52 {
53  aoAnnotations = ({ });
54  oAnnotates = 0;
55 }
56 
57 public:
58 
59 /**
60  * Add an annotation to this object. Any object can be an annotations, but
61  * usually a document should be used here.
62  *
63  * @param object ann - the documentation
64  * @return if adding was successfull or not.
65  * @see remove_annotation
66  */
67 protected:
68  bool add_annotation(object ann)
69 {
70  if ( !IS_PROXY(ann) )
71  THROW("Fatal error: annotation is not a proxy !", E_ERROR);
72  LOG("Adding annotation: " + ann->get_object_id() + " on "+
73  get_identifier());
74  return do_add_annotation(ann);
75 }
76 
77 public:
78 
79 protected:
80  bool do_add_annotation(object ann)
81 {
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 });
86 
87  require_save(STORE_ANNOTS);
88  return true;
89 }
90 
91 public:
92 
93 /**
94  * Remove an annotation from the object. The function just removes
95  * the annotation from the list of annotations.
96  *
97  * @param object ann - the annotation to delete
98  * @return if removing was successfull.
99  * @see add_annotation
100  */
101 protected:
102  bool remove_annotation(object ann)
103 {
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);
108 
109  aoAnnotations -= ({ ann });
110  ann->set_annotating(0);
111  require_save(STORE_ANNOTS);
112  return true;
113 }
114 
115 public:
116 
117 /**
118  * Remove all annotations. This will move the annotation to their
119  * authors. The function is called when the object is deleted.
120  *
121  */
122 protected:
123  void remove_all_annotations()
124 {
125  mixed err;
126 
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);
131  err = catch {
132  ann->delete();
133  };
134  if ( err != 0 )
135  {
136  FATAL("Failed to delete Annotation: %O", err);
137  }
138  }
139  }
140  if ( objectp(oAnnotates) )
141 }
142 
143 public:
144 
145 /**
146  * This function returns a copied list of all annotations of this
147  * object.
148  *
149  * @return the array of annotations
150  * @see get_annotations_for
151  */
152 array get_annotations(void|int from_obj, void|int to_obj)
153 {
154  array annotations = ({ });
155 
156  if ( !arrayp(aoAnnotations) )
157  aoAnnotations = ({ });
158 
159  aoAnnotations -= ({ 0 }); // remove 0 values of deleted annotations
160  for (int i = sizeof(aoAnnotations) - 1; i >= 0; i-- )
161  {
162  object ann = aoAnnotations[i];
163  if ( ann->status() >= 0 && i >= from_obj && ( !to_obj || i < to_obj ) )
164  annotations += ({ ann });
165  }
166  return annotations;
167 }
168 
169 /**
170  * This function returns a copied list of all annotations of this
171  * object which match a given classtype
172  *
173  * @return the array of annotations
174  * @see get_annotations
175  */
176 array get_annotations_by_class(int class_id)
177 {
178  array tmp=get_annotations();
179  foreach(tmp, object curr)
180  if((curr->get_object_class() & class_id)==0)
181  tmp-=({curr});
182  return tmp;
183 }
184 
185 object get_annotation_byid(string name)
186 {
187  array tmp=get_annotations();
188  foreach(tmp, object ann) {
189  if ( ann->get_object_id() == (int)name )
190  return ann;
191  }
192  return 0;
193 }
194 
195 /**
196  * Get the object we are annotating.
197  *
198  * @return the object we annotated
199  */
200 object get_annotating()
201 {
202  return oAnnotates;
203 }
204 
205 /**
206  * Set the annotating object.
207  *
208  * @param object obj - the annotating object
209  */
210 void set_annotating(object obj)
211 {
212  oAnnotates = obj;
213  require_save(STORE_ANNOTS);
214  update_path();
215 }
216 
217 /**
218  * Get only the annotations for a specific user. If no user is given
219  * this_user() will be used.
220  *
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
224  */
225 array
226 get_annotations_for(object|void user, void|int from_obj, void|int to_obj)
227 {
228  if ( !objectp(user) ) user = this_user();
229 
230  array user_annotations = ({ });
231  if ( !intp(from_obj) )
232  from_obj = 1;
233 
234  foreach ( aoAnnotations, object annotation ) {
235  if ( !objectp(annotation) ) continue;
236 
237  mixed err = catch {
238  _SECURITY->check_access(
239  annotation, user, SANCTION_READ, ROLE_READ_ALL, false);
240  };
241  if ( err == 0 )
242  user_annotations = ({ annotation }) + user_annotations;
243  }
244  if ( !to_obj )
245  return user_annotations[from_obj-1..];
246  return user_annotations[from_obj-1..to_obj-1];
247 }
248 
249 
250 /**
251  * Retrieve annotations is for storing the annotations in the database.
252  * Only the global _Database object is able to call this function.
253  *
254  * @return Mapping of object data.
255 private:
256  * @see restore_annotations
257  */
258 private:
259 final mapping retrieve_annotations()
260 {
261  if ( CALLER != _Database )
262  THROW("Caller is not the Database object !", E_ACCESS);
263 
264  return ([ "Annotations":aoAnnotations,
265  "Annotates": oAnnotates, ]);
266 }
267 
268 public:
269 
270 /**
271  * Called by database to restore the object data again upon loading.
272  *
273  * @param mixed data - the object data
274 private:
275  * @see retrieve_annotations
276  */
277 final void
278 private:
279 restore_annotations(mixed data)
280 {
281  if ( CALLER != _Database )
282  THROW("Caller is not the Database object !", E_ACCESS);
283 
284  aoAnnotations = data["Annotations"];
285  oAnnotates = data["Annotates"];
286  if ( !arrayp(aoAnnotations) )
287  {
288  aoAnnotations = ({ });
289  require_save(STORE_ANNOTS);
290  }
291 }
292 
293 public:
294 
295 /**
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.
300  *
301  * Example:
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(
306  * ({ // filters:
307  * ({ "-", "!class", CLASS_DOCUMENT }),
308  * ({ "-", "attribute", "DOC_LAST_MODIFIED", "<", time()-86400 }),
309  * ({ "+", "function", "get_creator", "==", USER("root") }),
310  * ({ "+", "attribute", "DOC_USER_MODIFIED", "==", USER("root") }),
311  * }),
312  * ({ // sort:
313  * ({ ">", "attribute", "DOC_LAST_MODIFIED" })
314  * }), 0, 10 );
315  *
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)
321  * this index
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).
334  */
335 mapping get_annotations_paginated ( array|void filters, array|void sort, int|void offset, int|void length, int|void max_depth )
336 {
337  return get_module( "searching" )->paginate_object_array( low_get_annotations_recursive( 0, max_depth ), filters, sort, offset, length );
338 }
339 
340 /**
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).
345  *
346  * @see get_annotations_paginated
347  */
348 array get_annotations_filtered ( array|void filters, array|void sort, int|void offset, int|void length, int|void max_depth )
349 {
350  return get_annotations_paginated( filters, sort, offset, length, max_depth )["objects"];
351 }
352 
353 protected array low_get_annotations_recursive ( int depth, void|int max_depth )
354 {
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;
362  }
363  return annotations;
364 }
365 
366 
367 };