BeBot - An Anarchy Online and Age Of Conan chat automaton

Development => Coding and development discussion => Topic started by: Blueeagle on March 05, 2007, 06:15:59 am

Title: Implementation of the settings and modules
Post by: Blueeagle on March 05, 2007, 06:15:59 am
I realized that if every module has their own settings that would make a bazillion windows to open to configure the bot when setting it up.

I was thinking about an access settings window similar to the security settings so that you can configure access to all modules on the same page. That way you don't have to open one window to set up News and one for MassMsg and one for privgroup relay.

It would be something like:

Relay_Access_Toggle:  GUEST
  Description: Who should be able to toggle relay on/off
  Change to: [ ADMIN | LEADER | MEMBER | GUEST | ANONYMOUS ]

MassMsg_Access_Send:  LEADER
  Description: Who should be able to send mass messages
  Change to: [ ADMIN | LEADER | MEMBER | GUEST | ANONYMOUS ]

Mail_Access_Read:  GUEST
  Description: Who should be able to read mail
  Change to: [ ADMIN | LEADER | MEMBER | GUEST | ANONYMOUS ]

Mail_Access_Send:  MEMBER
  Description: Who should be able to send mail
  Change to: [ ADMIN | LEADER | MEMBER | GUEST | ANONYMOUS ]


However it would be nice to be able the same settings from both this common window _and_ individual module settings. But that would require rewriting of the security module.

Any thoughts?
Title: Re: Implementation of the settings and modules
Post by: Alreadythere on March 05, 2007, 12:37:28 pm
Aren't those the rights that the rights management are supposed to handle?
Title: Re: Implementation of the settings and modules
Post by: jjones666 on March 05, 2007, 12:59:11 pm
If we had a lot of modules using Glara's settings it would be spammy in my opinion.  Imagine having APF alerts and Quotes alerts on the same page, it would also look confusing I think...

I have about 9 modules using the new settings interface and it's much better to have them seperate.  Of course, having an option to change between different styles of interface would suit both :-)

I think he's talking about lower level access Alreadythere, ie. !mail would be controlled by the security module, !mail read and !mail send by the module itself (i much prefer the freedom of settings in this case than hardcoding into the module).

-jj-
Title: Re: Implementation of the settings and modules
Post by: Glarawyn on March 05, 2007, 06:10:27 pm
Name a settings group core or some other generic term for settings that need to be set on first run maybe?

While I named groups of settings modules, the module column in the database is really a group, but group seems to be a reserved term in MySQL so I renamed things to what I assumed would be the most common use of a group: settings for a specific module. :)

There is nothing that prevents you from using settings from one "module" in a different module, the settings array is global. 
Title: Re: Implementation of the settings and modules
Post by: Blueeagle on March 05, 2007, 07:32:57 pm
I feel that I am being a bit misunderstood here so I'll attempt to clarify what I am meaning:

Say you've got a couple of modules with settings windows like

Code: [Select]
Settings for Mail

Access_Read:  GUEST
  Description: Who should be able to read mail
  Change to: [ ADMIN | LEADER | MEMBER | GUEST | ANONYMOUS ]

Access_Send:  GUEST
  Description: Who should be able to send mail
  Change to: [ ADMIN | LEADER | MEMBER | GUEST | ANONYMOUS ]

Life_Read:  2 weeks
  Description: How long should a read message be kept?
  Change to: [ 1 week |  2 weeks |  1 month |  6 months |  1 year |  2 years ]

Life_Unread:  6 months
  Description: How long should an unread message be kept?
  Change to: [ 1 week |  2 weeks |  1 month |  6 months |  1 year |  2 years ]

Logon_Notification:  On
  Description: Notify about new messages at logon
  Change to: [ On | Off ]

and

Code: [Select]
Settings for Relay

Access_Toggle:  GUEST
  Description: Who should be able to toggle relay on/off
  Change to: [ ADMIN | LEADER | MEMBER | GUEST | ANONYMOUS ]

Status:  On
  Description: Relay to private group should be
  Change to: [ On | Off ]

Now when setting up the bot one would probably want to review the access levels of all modules, thus instead of having to open every module window separately one could have a common window for access settings that would (for the two above examples) look like:

Code: [Select]
Module access settings

(Mail) Access_Read:  GUEST
  Description: Who should be able to read mail
  Change to: [ ADMIN | LEADER | MEMBER | GUEST | ANONYMOUS ]

(Mail) Access_Send:  GUEST
  Description: Who should be able to send mail
  Change to: [ ADMIN | LEADER | MEMBER | GUEST | ANONYMOUS ]

(Relay) Access_Toggle:  GUEST
  Description: Who should be able to toggle relay on/off
  Change to: [ ADMIN | LEADER | MEMBER | GUEST | ANONYMOUS ]

Ie. it would only provide settings that control access and not other aspects of each module.


I hope that clarifies things.
Title: Settings module again
Post by: Blueeagle on March 19, 2007, 01:06:12 pm
Also it would be nice if each setting or module had an access level tied to it so that one could configure certain settings to be modifiable by ie. members while other settings are reserved for admins and others again are reserved for superadmins. That would make the settings module much more versatile.

Any thoughts on how this could be implemented?
Title: Re: Settings module again
Post by: Glarawyn on March 19, 2007, 06:37:59 pm
Also it would be nice if each setting or module had an access level tied to it so that one could configure certain settings to be modifiable by ie. members while other settings are reserved for admins and others again are reserved for superadmins. That would make the settings module much more versatile.

Any thoughts on how this could be implemented?


Add an access_level column to the database with the access level required to change the setting. Default level is admin. Modify the create function to accept access level...

Then I'd add another array to the settings module to cache access levels.
$this -> access_level['Module']['Setting'] = ADMIN;

Modify the save function to respect access levels...

I think that would do it.
Title: Re: Settings module again
Post by: Alreadythere on March 20, 2007, 10:44:57 am
Also it would be nice if each setting or module had an access level tied to it so that one could configure certain settings to be modifiable by ie. members while other settings are reserved for admins and others again are reserved for superadmins. That would make the settings module much more versatile.

Any thoughts on how this could be implemented?
I'd just write an interface for the settings I want user with lower rights to be able to change and set the access rights for those via the rights management.
Title: Thoughts on module design overhaul to take advantages of PHP5 features
Post by: Blueeagle on March 25, 2007, 01:34:03 pm
What one could do is to abstract a base module that defines stuff common to all (read: most) modules.

I find this to be "a good idea"(tm) for the following reasons:
  * most commands reply to the channel in which the command was issued
  * saves exact duplicates in modules
  * may or may not save memory as the abstracted methods are only held in one place I think
  * Provides an out-of-the-way place to define Access_control variable for the module
  * Provides $this -> module_name which is usable atleast in the constructor
  * Provides a place to impliment an in-module help system. (Needs more thought tho)
  * Reuses the settings interface to control access levels thus eliminating the requirement for a separate GUI. (Even if a special handler for Access_control module in settings that would list all access control settings would be handy)

This may be a bad idea because
  * If memory is allocated for every class that extends a base module (which I don't think it is) then memory is used for unneded command handlers where some channels are not used
  * Causes needs of revamp for all modules even if the need is not immediate (ie. doesn't break old modules for other things than the access_control)
  * The default handlers are somewhat hidden and it may cause confusion for module developers even with the explination of how to re-define default handlers.

In addition of requiering alterations similar as to what Allreadythere has made to bot.php for access control the new module structure requires the mentioned alteration to the settings-gui.

The proposed core/Basemodule.php looks like this:

Code: [Select]
<?php

/*******************
 core/BaseModule.php
********************/
abstract class BaseModule
{
var $bot;
var $module_name;

function __construct (&$bot$module_name)
{
//Save reference to bot
$this -> bot = &$bot;
$this -> module_name $module_name;

//Create Access_control setting for this module (NEEDS TO BE CONFIGURED BEFORE COMMAND IS ENABLED)
$this -> bot -> set -> create ($module_name"Access_control""UNDEFINED""Who should have access to this command""SUPERADMIN;ADMIN;LEADER;MEMBER;GUEST;ANONYMOUS");
}

/************************************************************************
 Default to replying in the same channel as the command has been recieved
*************************************************************************/
public function gc($name$msg)
{
$reply $this -> command_handler($name$msg"gc");
if ($reply <> FALSE)
$this -> bot -> send_gc($reply);
}

public function tell($name$msg)
{
$reply $this -> command_handler($name$msg"tell");
if ($reply <> FALSE)
$this -> bot -> send_tell($name$reply);
}

public function tell2($name$msg)
{
$reply $this -> command_handler($name$msg"tell2");
if ($reply <> FALSE)
$this -> bot -> send_tell($name$reply);
}

public function pgmsg($name$msg)
{
$reply $this -> command_handler($name$msg"pgmsg");
if ($reply <> FALSE)
$this -> bot -> send_pgroup($reply);
}

//Prototype for the command_handler
abstract protected function command_handler($name$msg$origin);

//Implementation of a show_help() function. $this -> help_window would be defined in the module definition.
//Making a $this -> bot -> make_help(modulename, text); wouldn't be all whack as it can impliment a common
//header for all help windows. Not entirely sure of how this would be called tho.
public function show_help()
{
$this -> bot -> send_tell($this -> bot -> make_blob($this -> module_name$this -> help_window));
}
}
?>


And an example module would then look like:

Code: [Select]
<?php
//snipped out lots of comments to save some space
$testclass = new TestClass($bot);

$commands["tell"]["testing"] = &$testclass;
$commands["pgmsg"]["testing"] = &$testclass;
$commands["gc"]["testing"] = &$testclass;

/*
The Class itself...
*/
class TestClass extends BaseModule
{
/*
Class variables (static) are defined here
*/
var $help_window;

/*
constructor. Hands over a reference to the bot and sets default actions for commands
*/

function __construct (&$bot)
{
//call base module constructor
parent::__construct(&$botget_class($this));
//Set a sensible default for Access_control if none has been set yet.
if($this -> bot -> settings[$this -> module_name]['Access_control']=='UNDEFINED')
{
//If this is omitted access to the command will be disabled until configured with either !settings Access_control or !settings modulename
$this -> bot -> set -> save ($this -> module_name"Access_control""MEMBER");
}

//create other settings for this module
$this -> bot -> set -> create ($this -> module_name"SettingName""DefaultValue""This a setting used with the settings module""DefaultValue;OtherValue");

//Define the help window text here
$this -> help_window "This module really doesn't do anything very useful.";
}

/******************************************************
 Implement the command handler referenced by BaseModule
*******************************************************/
protected function command_handler($name$msg$origin)
{
//Here you would normally parse $msg and act accordingly. For this test class tho, just send a reply
return("{$this -> module_name} is responding to command '$msg' sendt via $origin by $name.");
}

/********************************************************************************************************
 It is possible to redefine the default command handlers here to they do something other than the default
*********************************************************************************************************/
//When command is recieved via gc reply in a tell instead of spamming gc
public function gc($name$msg)
{
$reply $this -> command_handler($name$msg"gc");
if ($reply <> FALSE)
$this -> bot -> send_tell($name$reply);
}

/*************************************************************************************************************
 Non-command hooks (leave them in module because there's "no sensible default"(tm) availible for such handlers
**************************************************************************************************************/
function privgroup($name$msg){}
function gmsg($name$group$msg){}
function pgjoin($name){}
function pgleave($name){}
function buddy($name$msg){}
function cron(){}
function connect(){}
function disconnect(){}

/*
Custom functions go below here
*/



}
?>


What do you think about splitting it up like this? I am undecided on putting the different handlers in the base module. They might just as well might be keept in the modules even if it causes redundant code.

Title: Re: Implementation of the settings and modules
Post by: Alreadythere on March 25, 2007, 01:47:11 pm
Just a quick question - doesn't all those OOP stuff need php5?

Because right now I (and prolly a couple of others too) are still using php4 for various reasons.
Title: Re: Implementation of the settings and modules
Post by: Blueeagle on March 25, 2007, 04:17:14 pm
According to http://auno.org/dev/aochat.html (http://auno.org/dev/aochat.html) so does the latest aochat.

Quote
Update! Nov 25 2005
revision 1.18
. Requires PHP 5 (for new object model).
Title: Re: Implementation of the settings and modules
Post by: Alreadythere on March 25, 2007, 04:29:19 pm
It works perfectly for me under 4.3.10 here.
Title: Re: Implementation of the settings and modules
Post by: Blueeagle on March 25, 2007, 04:51:11 pm
Hmm.. Odd.

But yes, you are right. The new objects are not supported under php4.

So we'll hang an eventual overhaul on the wall until PHP5 is more widely deployed then. :)
Title: Re: Implementation of the settings and modules
Post by: Vhab on March 25, 2007, 05:27:15 pm
I don't think it's a problem to do it now, just don't use the php5 specific stuff.
Title: Re: Implementation of the settings and modules
Post by: Glarawyn on March 26, 2007, 06:22:41 am
But yes, you are right. The new objects are not supported under php4.

So we'll hang an eventual overhaul on the wall until PHP5 is more widely deployed then. :)

Khalem and I discussed php4 vs. php5 and Khalem's opinion was that we should continue to support php4 for the 0.4 release unless there was a critical reason to move to php5. AOChat only working in php5 would be a critical reason. :)
Title: Re: Implementation of the settings and modules
Post by: Blueeagle on March 28, 2007, 06:28:44 am
Would it be "a good idea"TM to add a field to the settings module so that it could be used to modify some settings on a per-user basis? Ie, add an enum to the db-table to indicate if it's a user or a bot setting. If it's a bot setting handle it like it's handled now. If it's a user setting add the info to either the users table or to a new user_setting table.

That would open up a whole new dimention of bot configurability. Ie if they want to recieve online lists and news when they log in, have raid commands sendt in tells to those who want that.. and so on.

It will probably not be very hard to implement either.

Any thoughts?
Title: Re: Implementation of the settings and modules
Post by: Blueeagle on March 28, 2007, 06:43:12 am
And while we're on the topic of the settings module, the interface might be a tad more bloated than it needs to be. I've "slimmed" it down a bit to:

Code: [Select]
Settings for SettingsTest

  bool_test: Testing saving bool
  [ On | Off ]

  float_test: Testing saving floating point numbers
  [ 1.5 | 2.5 | 3.5 | 4.5 | 5.5 ] (Currently: 123.123)

  int_test: Testing saving integers
  [ 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 ] (Currently: 1174912172)

  NULL_test: Testing saving NULL
  [ NULL | String 1 | String 3 ]

  string_test: Testing saving text strings.
  [ String Option 1 | String Option 2 | String Option 3 ] (Currently: This is a string.)

Now the current values are highlighted (in white) and not clickable. If a value is not one of the default selections it's maked as after the options as (Corrently: <value>)

The module with alterations is below:

modules/SettingsInterface.php
Code: [Select]
<?
/*
SettingsInterface.php - Settings Managment Interface.
Version: 0.0
Created by Andrew Zbikowski <[email protected]> (AKA Glarawyn, RK1)
*/

$setconf = new SetConf($bot);

$commands["tell"]["settings"] = &$setconf;
$commands["tell2"]["settings"] = &$setconf;
$commands["pgmsg"]["settings"] = &$setconf;
$commands["gc"]["settings"] = &$setconf;

$commands["tell"]["set"] = &$setconf;
$commands["tell2"]["set"] = &$setconf;
$commands["pgmsg"]["set"] = &$setconf;
$commands["gc"]["set"] = &$setconf;

/*
The Class itself...
*/
class SetConf
{ // Start Class
var $bot;

/*
Constructor:
Hands over a referance to the "Bot" class.
*/
function SetConf (&$bot)
{
$this -> bot = &$bot;
}

/*
This gets called on a tell with the command
*/
function tell($name, $msg)
{ // Start function tell()
$reply = $this -> process_command($name, $msg, "tell");
if ($reply <> FALSE)
$this -> bot -> send_tell($name, $reply);
} // End function tell()

/*
This gets called on a tell with the command from person outside guild
*/
function tell2($name, $msg)
{ // Start function tell2()
$reply = $this -> process_command($name, $msg, "tell2");
if ($reply <> FALSE)
$this -> bot -> send_tell($name, $reply);
} // End function tell2()

/*
This gets called on a msg in the privmodule with the command
*/
function pgmsg($name, $msg)
{ // Start function pgmsg()
$reply = $this -> process_command($name, $msg, "pgmsg");
if ($reply <> FALSE)
$this -> bot -> send_pgroup($reply);
} // End function pgmsg()

/*
This gets called on a msg in the guildchat with the command
*/
function gc($name, $msg)
{ // Start function gc()
$reply = $this -> process_command($name, $msg, "gc");
if ($reply <> FALSE)
$this -> bot -> send_gc($reply);
} // End function gc()

/*
This function handles all the inputs and returns FALSE if the
handler should not send output, otherwise returns a string
sutible for output via send_tell, send_pmodule, and send_gc.
*/
function process_command($name, $msg, $source)
{ // Start function process_command()
$access = $this -> bot -> security -> check_access($name, $this -> bot -> settings['Security']['Settings']);
if ($access)
{
if (preg_match("/^" . $this -> bot -> commpre . "set[A-Za-z]{0,5} (.+?) (.+?) (.+)$/i", $msg, $info))
{
return $this -> change_setting($info[1], $info[2], $info[3]);
}
elseif (preg_match("/^" . $this -> bot -> commpre . "set[A-Za-z]{0,5} (.+)$/i", $msg, $info))
{
return $this -> show_module($info[1]);
}
else
{
return $this -> show_all_modules();
}
}
return "Only administrators can access the settings interface.";
} // End function process_command()

/*
Retruns a click window with the setting modules.
*/
function show_all_modules()
{ // Start function show_all_modules()
$sql = "SELECT DISTINCT module FROM #___settings WHERE hidden = FALSE ORDER BY module";
$result = $this -> bot -> db -> select($sql);
if (empty($result))
{
return "No settings defined.";
}

$output = "##ao_infoheader##Setting groups for <botname>:##end##\n\n";
foreach ($result as $module)
{
if ($module[0] <> "")
{
$output .= "<a href='chatcmd:///tell <botname> <pre>settings ".$module[0]."'>".$module[0]."</a>\n";
}
}
return $this -> bot -> make_blob("Settings groups for <botname>", $output);
} // End function show_all_modules()

/*
Returns a click window with settings for a specific module.
*/
function show_module($module)
{ // Start function show_module()
$module = str_replace (" ", "_", $module); // FIXME: Do regexp right and shouldn't need this?
$sql = "SELECT setting, value, datatype, longdesc, defaultoptions FROM #___settings ";
$sql .= "WHERE module = '".$module."' AND hidden = FALSE ";
$sql .= "ORDER BY disporder, setting";
$result = $this -> bot -> db -> select($sql);
if (empty($result))
{
return "No settings for module ".$module;
}
$inside = "##ao_infoheader##Settings for ".$module."##end##\n\n";
foreach ($result as $setting)
{ // 0 = setting, 1 = value, 2 = datatype, 3 = longdesc, 4 = defaultoptions
// Provide generic description if none exists.
if (empty($setting[3]))
{
if ($setting[2] == "int" || $setting[2] == "float")
{
$longdesc = "Numeric";
}
elseif ($setting[2] == "bool")
{
$longdesc = "On/Off";
}
elseif ($setting[2] == "string")
{
$longdesc = "Text String";
}
else
{
$longdesc = "Not configured.";
}
}
else
{
$longdesc = $setting[3];
}

//Convert bools to something prettier
if (strtoupper($setting[1]) == "TRUE")
{
$setting[1] = "On";
}
elseif (strtoupper($setting[1]) == "FALSE")
{
$setting[1] = "Off";
}
elseif (strtoupper($setting[1]) == "NULL")
{
$setting[1] = "NULL";
}

// Make configuration links if options are provided.
$options = explode(";", $setting[4]);

$optionlinks = "  ##ao_infotextbold##[";
$found_match=false;
foreach ($options as $option)
{
if ($option == $setting[1])
{
$found_match = true;
$optionlinks .= " $option |";
}
else
{
$optionlinks .= " <a href='chatcmd:///tell <botname> <pre>set ".$module." ".$setting[0]." ".$option."'>".$option."</a> |";
}
}
$optionlinks = rtrim($optionlinks, "|");
$optionlinks .= "]##end##";

if(!$found_match)
{
$optionlinks .= " (Currently: {$setting[1]})";
}

// Setting: longdesc
// Change To: optionlinks [(Currently: value)]
// Make inside data...
if (strtolower($setting[0]) == "password") // Mask passwords
{
$inside .= "##ao_infoheadline##".$setting[0].":##end##  ##ao_infotextbold##************##end##\n";
}
elseif (preg_match("/^#[0-9a-f]{6}$/i", $setting[1])) // Show HTML Color Codes in Color
{
$inside .= "##ao_infoheadline##".$setting[0].":##end##  <font color=".$setting[1].">".$setting[1]."</font>\n";
}
else // Normal Setting Display.
{
//$inside .= "##ao_infoheadline##".$setting[0].":##end##  ##ao_infotextbold##".$setting[1]."##end##\n";
}

$inside .= "  ##ao_infotextbold##{$setting[0]}:##end## ##ao_infotext##".$longdesc."##end##\n";
if (count($options) >= 1)
{
$inside .= $optionlinks."\n\n";
}
else
{
$inside .= "/tell <botname> <pre>set ".$module." ".$setting[0]." &lt;new value&gt;\n\n";
}
}
return $this -> bot -> make_blob("Settings for ".$module, $inside);
} // End fucnction show_module()

function change_setting($module, $setting, $value)
{ // Start function change_setting()
//return "Changing settings not implimented yet.";
$module = ucfirst(strtolower($this -> bot -> set -> remove_space($module)));
$setting = ucfirst(strtolower($this -> bot -> set -> remove_space($setting)));
if (!isset($this -> bot -> settings[$module][$setting] ))
{
if (!is_null($this -> bot -> settings[$module][$setting]))
{
return "Setting ".$setting." for module ".$module." does not exisit.";
}
}

$datatype = $this -> bot -> set -> get_data_type($this -> bot -> settings[$module][$setting]);
// Deal with possibly bad input from the user before continuing.
switch ($datatype)
{
case "bool": // A bool value comes in as on or off.
$value = strtolower($value);
if ($value == "on")
{
$value = TRUE;
}
elseif ($value == "off")
{
$value = FALSE;
}
else
{
return "Unrecgonized value for setting ".$setting." for module ".$module.". No change made.";
}
break;
case "null":
// If the string is null, change it to a null value.
// Otherwise, $value will be saved as a string. (No modification needed)
if (strtolower($value) == "null")
{
$value = NULL;
}
break;
case "array": // Changing arrays are not supported! :D
return "Modifying array values is not supported in this interface. See the help for ".$module;
break;
default:
$value = $this -> bot -> set -> set_data_type($value, $datatype);
break;
}
$result = $this -> bot -> set -> save($module, $setting, $value);
if ($result['error'])
{
return $result['errordesc'];
}
else
{
if ($datatype == "bool")
{
if ($value) {$value = "On";}
else {$value = "Off";}
}
return "Changed setting ".$setting." for module ".$module." to ".strval($value)." [".$this -> show_module($module)."]";
}

} // End function change_setting()

} // End of Class
?>

Now I haven't really bug-hunted these changes, but they appear to work in the few cases I've tested it.

Thoughts and feed back please?
Title: Re: Implementation of the settings and modules
Post by: Khalem on April 07, 2007, 03:16:52 am
Regarding AOChat and PHP5, we use a forked version of AOChat which has been modified to be PHP4 compatible. The only thing missing is Auno's changes to the queue.
SimplePortal 2.3.7 © 2008-2024, SimplePortal