1 /* Copyright (C) 2000-2006 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: groups.pike,v 1.2 2010/01/26 12:09:01 astra Exp $
19 inherit "/kernel/secure_mapping.pike";
21 #include <attributes.h>
25 //! This module maps the name of the group to the group object.
26 //! Its possible to get a list of all groups inside here. Apart
27 //! from that its only used by the server directly.
28 class groups : public secure_mapping.pike{
36 private array test_objects = ({ });
39 * Get a list of groups.
41 * @return an array of groups.
45 array index = index();
49 foreach ( index, string idx ) {
50 object obj = get_value(idx);
57 array get_top_groups()
59 array groups = do_query_attribute("groups_top_groups") || ({ });
64 void unregister_group(object grp)
66 WARN("groups module: unregister from invalid %O", CALLER);
67 THROW("Unauthorized call to groups module: unregister()", E_ACCESS);
69 unregister(grp->get_group_name());
73 int unregister(string groupName)
75 return ::unregister(groupName);
80 int register(string name, object obj)
82 WARN("groups module: register from invalid %O", CALLER);
83 THROW("Unauthorized call to groups module: register()", E_ACCESS);
85 if (!objectp(obj->get_parent())) {
86 MESSAGE("New top level group %O", obj);
87 array topgroups = get_top_groups();
88 topgroups += ({ obj });
89 do_set_attribute("groups_top_groups", topgroups);
91 return ::register(name, obj);
94 void rename_group(object group, string new_name)
96 if ( CALLER != get_factory(CLASS_GROUP) )
97 steam_error("Invalid call to rename_group() !");
98 string old_name = group->get_group_name();
99 set_value(new_name, group);
100 if ( stringp(old_name) && new_name != old_name ) delete( old_name );
104 * Initialize the module. Only sets the description attribute.
110 set_attribute(OBJ_NAME, "groups");
111 set_attribute(OBJ_DESC, "This is the database table for lookup "+
120 array topgroups = ({ });
121 array groups = get_groups();
122 foreach(groups, object grp) {
123 if ( !objectp(grp->get_parent()))
124 topgroups += ({ grp });
126 do_set_attribute("groups_top_groups", topgroups);
136 array topgroups = do_query_attribute("groups_top_groups");
137 if ( !arrayp(topgroups) )
139 add_global_event(EVENT_ADD_MEMBER, event_add_member, PHASE_NOTIFY);
140 add_global_event(EVENT_REMOVE_MEMBER, event_remove_member, PHASE_NOTIFY);
145 void event_add_member(int e, object grp, object caller, object add, bool pw)
147 array topgroups = get_top_groups();
148 if ( search(topgroups, add) >= 0 ) {
149 topgroups -= ({ add });
150 do_set_attribute("groups_top_groups", topgroups);
154 void event_remove_member(int e, object grp, object caller, object user)
156 array topgroups = get_top_groups();
157 if ( user->get_object_class() & CLASS_GROUP ) {
158 if ( !objectp(user->get_parent()) ) {
159 topgroups += ({ user });
160 do_set_attribute("groups_top_groups", topgroups);
165 object lookup(string index)
167 return _Persistence->lookup_group(index);
172 * Lookup a group by name
174 * @param string name the name of the group to search
175 * @param bool like optional parameter to specify "like" instead of "="
176 * @return array of matching groups
178 array lookup_name(string name, void|bool like)
180 return _Persistence->lookup_groups( ([ "name":name ]), false,
185 object get_group ( string name )
187 return get_value(name);
191 * Drops a group from any caches, so that it will receive fresh data on the
192 * next lookup. This can be useful if you know that group data has changed in
193 * one of the persistence layers and you want the group object to update its
194 * data accordingly (before the regular update after the cache times out).
196 * @param identifier the identifier (full group name with parent groups
197 * separated by ".") of the group that shall be dropped from cache
198 * @return 1 if the group was dropped from the object cache,
199 * 0 if it wasn't found in the object cache (regardless of this return value,
200 * the group might have been dropped from any persistence layer caches)
202 int uncache_group ( string identifier )
204 return _Persistence->uncache_group( identifier );
207 string get_identifier() { return "groups"; }
208 string get_table_name() { return "groups"; }
210 void check_integrity()
212 array topgroups = get_top_groups();
213 foreach (topgroups, object grp) {
215 if ( grp->get_parent() )
216 steam_error("Found Top-Group with Parent !");
218 array groups = get_groups();
219 foreach(groups, object grp) {
220 if ( !objectp(grp->get_parent()) && search(topgroups, grp) == -1 ) {
221 register(grp->get_group_name(), grp);
222 steam_error("Found Top-Group %O not in get_top_groups() ... fixed!",
228 int check_updates () {
229 int result = 0; // set to 1 if an update needs a server restart
232 string parent_update = "fixed parents of all groups";
233 if ( !_Server->get_update( parent_update ) ) {
234 array groups = get_groups();
235 int nr_groups = sizeof(groups);
236 MESSAGE( "Fixing parents for all %d groups...", nr_groups );
237 string update_log = "=Fixing-Parents=\n\n" + ctime(time())
238 + sprintf( "\nFixing parents of all %d groups.\n\n", nr_groups );
241 object group_factory = get_factory( CLASS_GROUP );
242 foreach ( groups, object group ) {
244 if ( (count % 100) == 0 )
245 MESSAGE("Fixed parent for %d of %d groups...", count, nr_groups);
246 string identifier = group->get_identifier();
247 if ( !stringp(identifier) ) {
248 update_log += "* '''ERROR:''' skipping group with empty identifier "
249 + "(id: " + group->get_object_id() + ")\n";
250 werror( "group with empty identifier: %O\n", group );
254 object old_parent = group->get_parent();
255 if ( objectp(old_parent) ) {
256 mixed old_parent_identifier = old_parent->get_identifier();
257 if ( !stringp(old_parent_identifier) )
258 old_parent_identifier = "(invalid identifier)";
259 update_log += "* " + identifier + " : already has parent: "
260 + old_parent_identifier + " (id: " + old_parent->get_object_id()
264 object new_parent = group_factory->fix_group_parent( group );
265 if ( !objectp(new_parent) ) {
266 if ( !arrayp(group->get_groups()) || sizeof(group->get_groups())==0 ) {
267 update_log += "* "+identifier+" : is top-level group, skipping\n";
270 update_log += "* '''ERROR:''' "+identifier+" : could not be fixed\n";
271 werror( "Failed to fix group parent of %O\n", group );
275 mixed new_parent_identifier = new_parent->get_identifier();
276 if ( !stringp(new_parent_identifier) )
277 new_parent_identifier = "(empty identifier)";
278 if ( new_parent != group->get_parent() ) {
279 update_log += "* '''ERROR:''' " + identifier + " : parent could not be"
280 + " set: " + new_parent_identifier + " (id: "
281 + new_parent->get_object_id() + ")\n";
282 werror( "Could not set parent %O to group %O\n", new_parent, group );
286 update_log += "* " + identifier + " : new parent: "
287 + new_parent_identifier + " (id: "+new_parent->get_object_id()+")\n";
289 update_log += "\n" + ctime(time()) + "\n";
290 update_log += "\n" + failed + " errors occurred.\n";
291 object update = get_factory(CLASS_DOCUMENT)->execute(
292 ([ "name":parent_update, "mimetype":"text/wiki" ]) );
293 if ( objectp(update) ) {
294 update->set_content( update_log );
295 _Server->add_update( update );
296 MESSAGE( "Finished fixing group parents." );
299 MESSAGE( "Failed to store group parent update." );
300 werror( "Failed to store group parent update.\n" );
308 object oldgroup = GROUP("groupstestgroup");
309 if ( objectp(oldgroup) )
310 catch( oldgroup->delete() );
311 oldgroup = GROUP("groupstestgroup.groupstestgroup");
312 if ( objectp(oldgroup) )
313 catch( oldgroup->delete() );
314 oldgroup = GROUP("Groups.groupstestgroup");
315 if ( objectp(oldgroup) )
316 catch( oldgroup->delete() );
319 // new top level group
320 object factory = get_factory(CLASS_GROUP);
321 object grp = factory->execute( ([ "name": "groupstestgroup", ]) );
322 if ( objectp(grp) ) test_objects += ({ grp });
323 Test.test( "creating new top-level group",
324 ( search(get_top_groups(), grp) != -1 ) );
325 object grp2 = factory->execute( ([ "name": "groupstestgroup",
326 "parentgroup": grp ]) );
327 if ( objectp(grp2) ) test_objects += ({ grp2 });
328 Test.test( "creating sub-group",
329 ( search(get_top_groups(), grp2) == -1 ),
330 "found sub-group in top-level groups" );
333 Test.test( "add_member",
334 GROUP("Groups")->add_member(grp) == 1,
335 "Cannot Add Group to Groups");
336 Test.add_test_function(test_more, 1, grp, grp2);
340 void test_more(object grp, object grp2)
342 Test.test( "moving group",
343 (grp->get_parent() == GROUP("Groups")),
344 "Moved groups parent is not Groups (is "+
345 sprintf("%O", grp->get_parent()) + ")");
347 Test.test( "top groups",
348 ( search(get_top_groups(), grp) == -1 ),
349 "Found moved group (" + grp->get_group_name()+
350 ") in top-level groups" );
355 void test_cleanup () {
356 if ( arrayp(test_objects) ) {
357 foreach ( test_objects, object obj )
358 catch( obj->delete() );