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() );