New screens for browsing/editing Principals & Collections.

This commit is contained in:
Andrew McMillan 2009-11-22 22:33:56 +13:00
parent 6c121e9782
commit 516dc03880
6 changed files with 1043 additions and 0 deletions

49
htdocs/davical.php Normal file
View File

@ -0,0 +1,49 @@
<?php
require_once('../inc/always.php');
require_once('classViewer.php');
require_once('classEditor.php');
require_once('classBrowser.php');
include("DAViCalSession.php");
$session->LoginRequired();
param_to_global('action', '{(edit|view|browse)}', 'action');
param_to_global('component', '{[a-z0-9-_]+}', 't');
param_to_global('id', '{[a-z0-9-_]+}', 'id');
$c->stylesheets[] = 'css/'.$action.'.css';
$c->scripts[] = 'js/'.$action.'.js';
require_once('interactive-page.php');
$page_elements = array();
$code_file = sprintf( 'ui/%s-%s.php', $component, $action );
if ( ! @include_once( $code_file ) ) {
$c->messages[] = sprintf('No page found to %s %s%s%s', $action, ($action == 'browse' ? '' : 'a '), $component, ($action == 'browse' ? 's' : ''));
include('page-header.php');
include('page-footer.php');
exit(0);
}
include('page-header.php');
/**
* Page elements could be an array of viewers, browsers or something else
* that supports the Render() method... or a non-object which we assume is
* just a string of text that we echo.
*/
$heading_level = null;
foreach( $page_elements AS $k => $page_element ) {
if ( is_object($page_element) ) {
echo $page_element->Render($heading_level);
$heading_level = 'h2';
}
else {
echo $page_element;
}
}
if (function_exists("post_render_function")) {
post_render_function();
}
include('page-footer.php');

478
inc/classEditor.php Normal file
View File

@ -0,0 +1,478 @@
<?php
/**
* Class for editing a record using a templated form.
*
* @package apms
* @subpackage classEditor
* @author Andrew McMillan <andrew@mcmillan.net.nz>
* @copyright Catalyst IT Ltd, Morphoss Ltd <http://www.morphoss.com/>
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
*/
require_once("DataUpdate.php");
require_once("DataEntry.php");
/**
* A class for the fields in the editor
* @package apms
*/
class EditorField
{
var $Field;
var $Sql;
var $Value;
var $Attributes;
var $LookupSql;
var $OptionList;
function EditorField( $field, $sql="", $lookup_sql="" ) {
global $session;
$this->Field = $field;
$this->Sql = $sql;
$this->LookupSql = $lookup_sql;
$this->Attributes = array();
$session->Log("DBG: New field '%s' SQL='%s', Lookup='%s'", $field, $sql, $lookup_sql );
}
function Set($value) {
$this->Value = $value;
}
function SetSql( $sql ) {
$this->Sql = $sql;
}
function SetLookup( $lookup_sql ) {
$this->LookupSql = $lookup_sql;
}
function SetOptionList( $options, $current = null, $parameters = null) {
if ( gettype($options) == 'array' ) {
$this->OptionList = '';
if ( is_array($parameters) ) {
if ( isset($parameters['maxwidth']) ) $maxwidth = max(4,intval($parameters['maxwidth']));
if ( isset($parameters['translate']) ) $translate = true;
}
foreach( $options AS $k => $v ) {
if (is_array($current)) {
$selected = ( ( in_array($k,$current,true) || in_array($v,$current,true)) ? ' selected="selected"' : '' );
}
else {
$selected = ( ( "$k" == "$current" || "$v" == "$current" ) ? ' selected="selected"' : '' );
}
if ( isset($translate) ) $v = translate( $v );
if ( isset($maxwidth) ) $v = substr( $v, 0, $maxwidth);
$this->OptionList .= "<option value=\"".htmlspecialchars($k)."\"$selected>".htmlspecialchars($v)."</option>";
}
}
else {
$this->OptionList = $options;
}
}
function GetTarget() {
if ( $this->Sql == "" ) return $this->Field;
return "$this->Sql AS $this->Field";
}
function AddAttribute( $k, $v ) {
$this->Attributes[$k] = $v;
}
function RenderAttributes() {
$attributes = "";
if ( count($this->Attributes) == 0 ) return $attributes;
foreach( $this->Attributes AS $k => $v ) {
$attributes .= " $k=\"" . str_replace('"', '\\"', $v) . '"';
}
return $attributes;
}
}
/**
* The class for the Editor form in full
* @package apms
*/
class Editor
{
var $Title;
var $Action;
var $Fields;
var $OrderedFields;
var $BaseTable;
var $Joins;
var $Where;
var $NewWhere;
var $Order;
var $Limit;
var $Query;
var $Template;
var $RecordAvailable;
var $Record;
var $SubmitName;
var $Id;
function Editor( $title = "", $fields = null ) {
global $c, $session, $form_id_increment;
$this->Title = $title;
$this->Order = "";
$this->Limit = "";
$this->Template = "";
$this->RecordAvailable = false;
$this->SubmitName = 'submit';
$form_id_increment = (isset($form_id_increment)? ++$form_id_increment : 1);
$this->Id = 'editor_'.$form_id_increment;
if ( isset($fields) ) {
if ( is_array($fields) ) {
foreach( $fields AS $k => $v ) {
$this->AddField($v);
}
}
else if ( is_string($fields) ) {
// We've been given a table name, so get all fields for it.
$this->BaseTable = $fields;
$field_list = get_fields($fields);
foreach( $field_list AS $k => $v ) {
$this->AddField($k);
}
}
}
dbg_error_log("classEditor", "DBG: New editor called $title");
}
function &AddField( $field, $sql="", $lookup_sql="" ) {
$this->Fields[$field] = new EditorField( $field, $sql, $lookup_sql );
$this->OrderedFields[] = $field;
return $this->Fields[$field];
}
function SetSql( $field, $sql ) {
$this->Fields[$field]->SetSql( $sql );
}
function SetLookup( $field, $lookup_sql ) {
$this->Fields[$field]->SetLookup( $lookup_sql );
}
function Value( $value_field_name ) {
if ( !isset($this->Record->{$value_field_name}) ) return null;
return $this->Record->{$value_field_name};
}
function Assign( $value_field_name, $new_value ) {
$this->Record->{$value_field_name} = $new_value;
}
function Id( $id = null ) {
if ( isset($id) ) $this->Id = preg_replace( '#[^a-z0-9_+-]#', '', $id);
return $this->Id;
}
function SetOptionList( $field, $options, $current = null, $parameters = null) {
$this->Fields[$field]->SetOptionList( $options, $current, $parameters );
}
function AddAttribute( $field, $k, $v ) {
$this->Fields[$field]->AddAttribute($k,$v);
}
function SetBaseTable( $base_table ) {
$this->BaseTable = $base_table;
}
function SetJoins( $join_list ) {
$this->Joins = $join_list;
}
/**
* Accessor for the Title for the browse, which could set the title also.
*
* @param string $new_title The new title for the browser
* @return string The current title for the browser
*/
function Title( $new_title = null ) {
if ( isset($new_title) ) $this->Title = $new_title;
return $this->Title;
}
function SetSubmitName( $new_submit ) {
$this->SubmitName = $new_submit;
}
function IsSubmit() {
return isset($_POST[$this->SubmitName]);
}
function IsUpdate() {
$is_update = $this->Available();
if ( isset( $_POST['_editor_action']) && isset( $_POST['_editor_action'][$this->Id]) ) {
$is_update = ( $_POST['_editor_action'][$this->Id] == 'update' );
dbg_error_log("ERROR", "Checking update: %s => %d", $_POST['_editor_action'][$this->Id], $is_update );
}
return $is_update;
}
function SetWhere( $where_clause ) {
$this->Where = $where_clause;
}
function WhereNewRecord( $where_clause ) {
$this->NewWhere = $where_clause;
}
function MoreWhere( $operator, $more_where ) {
if ( $this->Where == "" ) {
$this->Where = $more_where;
return;
}
$this->Where = "$this->Where $operator $more_where";
}
function AndWhere( $more_where ) {
$this->MoreWhere("AND",$more_where);
}
function OrWhere( $more_where ) {
$this->MoreWhere("OR",$more_where);
}
function SetTemplate( $template ) {
$this->Template = $template;
}
function Layout( $template ) {
if ( strstr( $template, '##form##' ) === false && stristr( $template, '<form' ) === false ) $template = '##form##' . $template;
if ( stristr( $template, '</form' ) === false ) $template .= '</form>';
$this->Template = $template;
}
function Available( ) {
return $this->RecordAvailable;
}
function SetRecord( $row ) {
$this->Record = $row;
$this->RecordAvailable = is_object($this->Record);
return $this->Record;
}
/**
* Set some particular values to the ones from the array.
*
* @param array $values An array of fieldname / value pairs
*/
function Initialise( $values ) {
$this->RecordAvailable = false;
foreach( $values AS $fname => $value ) {
$this->Record->{$fname} = $value;
}
}
function GetRecord( $where = "" ) {
global $session;
$target_fields = "";
foreach( $this->Fields AS $k => $column ) {
if ( $target_fields != "" ) $target_fields .= ", ";
$target_fields .= $column->GetTarget();
}
if ( $where == "" ) $where = $this->Where;
$sql = sprintf( "SELECT %s FROM %s %s WHERE %s %s %s",
$target_fields, $this->BaseTable, $this->Joins, $where, $this->Order, $this->Limit);
$this->Query = new PgQuery( $sql );
$session->Log("DBG: EditorGetQry: %s", $sql );
if ( $this->Query->Exec("Browse:$this->Title:DoQuery") ) {
$this->Record = $this->Query->Fetch();
$this->RecordAvailable = is_object($this->Record);
}
if ( !$this->RecordAvailable ) {
$this->Record = (object) array();
}
return $this->Record;
}
/**
* Replace parts into the form template.
* @param array $matches The matches found which preg_replace_callback is calling us for.
* @return string What we want to replace this match with.
*/
function ReplaceEditorPart($matches)
{
global $session;
// $matches[0] is the complete match
switch( $matches[0] ) {
case "##form##": /** @todo It might be nice to construct a form ID */
return sprintf('<form method="POST" enctype="multipart/form-data" class="editor" id="%s">', $this->Id);
case "##submit##":
$action = ( $this->RecordAvailable ? 'update' : 'insert' );
$submittype = ($this->RecordAvailable ? 'Apply Changes' : 'Create');
return sprintf('<input type="hidden" name="_editor_action[%s]" value="%s"><input type="submit" class="submit" name="%s" value="%s">',
$this->Id, $action, $this->SubmitName, $submittype );
}
// $matches[1] the match for the first subpattern
// enclosed in '(...)' and so on
$field_name = $matches[1];
$what_part = $matches[3];
$part3 = (isset($matches[5]) ? $matches[5] : null);
$value_field_name = $field_name;
if ( substr($field_name,0,4) == 'xxxx' ) {
// Sometimes we will prepend 'xxxx' to the field name so that the field
// name differs from the column name in the database. We also remove it
// when it's submitted.
$value_field_name = substr($field_name,4);
}
$attributes = "";
if ( isset($this->Fields[$field_name]) && is_object($this->Fields[$field_name]) ) {
$field = $this->Fields[$field_name];
$attributes = $field->RenderAttributes();
}
$field_value = (isset($this->Record->{$value_field_name}) ? $this->Record->{$value_field_name} : null);
switch( $what_part ) {
case "options":
$currval = $part3;
if ( ! isset($currval) && isset($field_value) )
$currval = $field_value;
if ( isset($field->OptionList) && $field->OptionList != "" ) {
$option_list = $field->OptionList;
}
else {
$session->Log("DBG: Current=%s, OptionQuery: %s", $currval, $field->LookupSql );
$opt_qry = new PgQuery( $field->LookupSql );
$option_list = $opt_qry->BuildOptionList($currval, "FieldOptions: $field_name" );
$field->OptionList = $option_list;
}
return $option_list;
case "select":
$currval = $part3;
if ( ! isset($currval) && isset($field_value) )
$currval = $field_value;
if ( isset($field->OptionList) && $field->OptionList != "" ) {
$option_list = $field->OptionList;
}
else {
$session->Log("DBG: Current=%s, OptionQuery: %s", $currval, $field->LookupSql );
$opt_qry = new PgQuery( $field->LookupSql );
$option_list = $opt_qry->BuildOptionList($currval, "FieldOptions: $field_name" );
$field->OptionList = $option_list;
}
return "<select class=\"entry\" name=\"$field_name\"$attributes>$option_list</select>";
case "checkbox":
switch ( $field_value ) {
case 'f':
case 'off':
case 'false':
case '':
case '0':
$checked = "";
break;
default:
$checked = " CHECKED";
}
return "<input type=\"hidden\" value=\"off\" name=\"$field_name\"><input class=\"entry\" type=\"checkbox\" value=\"on\" name=\"$field_name\"$checked$attributes>";
case "input":
$size = (isset($part3) ? $part3 : 6);
return "<input class=\"entry\" value=\"".htmlspecialchars($field_value)."\" name=\"$field_name\" size=\"$size\"$attributes>";
case "file":
$size = (isset($part3) ? $part3 : 30);
return "<input type=\"file\" class=\"entry\" value=\"".htmlspecialchars($field_value)."\" name=\"$field_name\" size=\"$size\"$attributes>";
case "money":
$size = (isset($part3) ? $part3 : 8);
return "<input class=\"money\" value=\"".htmlspecialchars(sprintf("%0.2lf",$field_value))."\" name=\"$field_name\" size=\"$size\"$attributes>";
case "date":
$size = (isset($part3) ? $part3 : 10);
return "<input class=\"date\" value=\"".htmlspecialchars($field_value)."\" name=\"$field_name\" size=\"$size\"$attributes>";
case "textarea":
list( $cols, $rows ) = split( 'x', $part3);
return "<textarea class=\"entry\" name=\"$field_name\" rows=\"$rows\" cols=\"$cols\"$attributes>".htmlspecialchars($field_value)."</textarea>";
case "hidden":
return sprintf( "<input type=\"hidden\" value=\"%s\" name=\"$field_name\">", htmlspecialchars($field_value) );
case "password":
return sprintf( "<input type=\"password\" value=\"%s\" name=\"$field_name\" size=\"10\">", htmlspecialchars($part3) );
case "encval":
case "enc":
return htmlspecialchars($field_value);
case "submit":
$action = ( $this->RecordAvailable ? 'update' : 'insert' );
return sprintf('<input type="hidden" name="_editor_action[%s]" value="%s"><input type="submit" class="submit" name="%s" value="%s">',
$this->Id, $action, $this->SubmitName, $value_field_name );
default:
return str_replace( "\n", "<br />", $field_value );
}
}
/**
* Render the templated component. The heavy lifting is done by the callback...
*/
function Render( $title_tag = null ) {
dbg_error_log("classEditor", "Rendering editor $this->Title" );
if ( $this->Template == "" ) $this->DefaultTemplate();
$html = sprintf('<div class="editor" id="%s">', $this->Id);
if ( isset($this->Title) && $this->Title != "" ) {
if ( !isset($title_tag) ) $title_tag = 'h1';
$html = "<$title_tag>$this->Title</$title_tag>\n";
}
// Stuff like "##fieldname.part## gets converted to the appropriate value
$replaced = preg_replace_callback("/##([^#.]+)(\.([^#.]+))?(\.([^#.]+))?##/", array(&$this, "ReplaceEditorPart"), $this->Template );
$html .= $replaced;
$html .= '</div>';
return $html;
}
/**
* Write the record
* @param boolean $is_update Tell the write whether it's an update or insert. Hopefully it
* should be able to figure it out though.
*/
function Write( $is_update = null ) {
global $c, $component;
dbg_error_log("classEditor", "DBG: Writing editor $this->Title");
if ( !isset($is_update) ) {
if ( isset( $_POST['_editor_action']) && isset( $_POST['_editor_action'][$this->Id]) ) {
$is_update = ( $_POST['_editor_action'][$this->Id] == 'update' );
}
else {
/** @todo Our old approach will not work for translation. We need to have a hidden field
* containing the submittype. Probably we should add placeholders like ##form##, ##script## etc.
* which the editor can use for internal purposes.
*/
// Then we dvine the action by looking at the submit button value...
$is_update = preg_match( '/(save|update|apply)/i', $_POST[$this->SubmitName] );
dbg_error_log("ERROR", $_SERVER['REQUEST_URI']. " is using a deprecated method for controlling insert/update" );
}
}
$this->Action = ( $is_update ? "update" : "create" );
$qry = new PgQuery( sql_from_post( $this->Action, $this->BaseTable, "WHERE ".$this->Where ) );
if ( !$qry->Exec("Editor::Write") ) {
$c->messages[] = "ERROR: $qry->errorstring";
return 0;
}
if ( $this->Action == "create" && isset($this->NewWhere) ) {
$this->GetRecord($this->NewWhere);
}
else {
$this->GetRecord($this->Where);
}
return $this->Record;
}
}

View File

@ -21,6 +21,9 @@ $help_menu->AddOption(translate('Report Bug'),'http://sourceforge.net/tracker/?f
$user_menu = new MenuSet('submenu', 'submenu', 'submenu_active');
$user_menu->AddOption(translate('View My Details'),$c->base_url.'/usr.php?user_no='.$session->user_no,translate('View my own user record'));
$user_menu->AddOption(translate('List Users'),$c->base_url.'/davical.php?action=browse&t=principal&type=1');
$user_menu->AddOption(translate('List Resources'),$c->base_url.'/davical.php?action=browse&t=principal&type=2');
$user_menu->AddOption(translate('List Groups'),$c->base_url.'/davical.php?action=browse&t=principal&type=3');
$admin_menu = new MenuSet('submenu', 'submenu', 'submenu_active');
if ( $session->AllowedTo('Admin' )) {

204
inc/ui/collection-edit.php Normal file
View File

@ -0,0 +1,204 @@
<?php
// Editor component for company records
$editor = new Editor(translate('Collection'), 'collection');
param_to_global('id', 'int', 'old_id', 'collection_id' );
$editor->SetLookup( 'timezone', 'SELECT \'\', \'*** Unknown ***\' UNION SELECT tz_id, tz_locn FROM time_zone WHERE tz_id = tz_locn AND length(tz_spec) > 100 ORDER BY 1' );
$editor->SetLookup( 'schedule_transp', sprintf('SELECT \'opaque\', \'%s\' UNION SELECT \'transp\', \'%s\'', translate('Opaque'), translate('Transparent') ) );
$editor->AddAttribute('timezone', 'id', 'fld_timezone' );
$editor->AddAttribute('schedule_transp', 'id', 'fld_schedule_transp' );
$editor->AddAttribute('is_calendar', 'onclick', 'toggle_enabled(self.checked,\'fld_timezone\',\'fld_schedule_transp\');');
$editor->SetWhere( 'collection_id='.$id );
$privilege_names = array( 'read', 'write-properties', 'write-content', 'unlock', 'read-acl', 'read-current-user-privilege-set',
'bind', 'unbind', 'write-acl', 'read-free-busy', 'schedule-deliver-invite', 'schedule-deliver-reply',
'schedule-query-freebusy', 'schedule-send-invite', 'schedule-send-reply', 'schedule-send-freebusy' );
$pwstars = '@@@@@@@@@@';
if ( $editor->IsSubmit() ) {
$editor->WhereNewRecord( "collection_id=(SELECT CURRVAL('dav_id_seq'))" );
if ( isset($_POST['default_privileges']) ) {
$privilege_bitpos = array_flip($privilege_names);
$priv_names = array_keys($_POST['default_privileges']);
$privs = privilege_to_bits($priv_names);
$_POST['default_privileges'] = sprintf('%024s',decbin($privs));
$editor->Assign('default_privileges', $privs_dec);
}
$editor->Write();
}
else {
$editor->GetRecord();
}
if ( $editor->Available() ) {
$c->page_title = $editor->Title(translate('Collection').': '.$editor->Value('dav_displayname'));
}
else {
$c->page_title = $editor->Title(translate('Create New Collection'));
$privs = decbin(privilege_to_bits($c->default_privileges));
$editor->Assign('default_privileges', $privs);
}
$privilege_xlate = array(
'read' => translate('Read'),
'write-properties' => translate('Write Metadata'),
'write-content' => translate('Write Data'),
'unlock' => translate('Override a Lock'),
'read-acl' => translate('Read Access Controls'),
'read-current-user-privilege-set' => translate('Read Current User\'s Access'),
'bind' => translate('Create Resources'),
'unbind' => translate('Delete Resources'),
'write-acl' => translate('Write Access Controls'),
'read-free-busy' => translate('Read Free/Busy Information'),
'schedule-deliver-invite' => translate('Scheduling: Deliver an Invitation'),
'schedule-deliver-reply' => translate('Scheduling: Deliver a Reply'),
'schedule-query-freebusy' => translate('Scheduling: Query free/busy'),
'schedule-send-invite' => translate('Scheduling: Send an Invitation'),
'schedule-send-reply' => translate('Scheduling: Send a Reply'),
'schedule-send-freebusy' => translate('Scheduling: Send free/busy')
);
$default_privileges = bindec($editor->Value('default_privileges'));
$privileges_set = '<div id="privileges">';
for( $i=0; $i<count($privilege_names); $i++ ) {
$privilege_set = ( (1 << $i) & $default_privileges ? ' CHECKED' : '');
$privileges_set .= '<label class="privilege"><input name="default_privileges['.$privilege_names[$i].']" id="priv_checkbox_'.$privilege_names[$i].'" type="checkbox"'.$privilege_set.'>'.$privilege_xlate[$privilege_names[$i]].'</label>'."\n";
}
$privileges_set .= '</div>';
$prompt_collection_id = translate('Collection ID');
$prompt_dav_name = translate('DAV Path');
$prompt_displayname = translate('Displayname');
$prompt_public = translate('Publicly Readable');
$prompt_calendar = translate('Is a Calendar');
$prompt_addressbook = translate('Is an Addressbook');
$prompt_privileges = translate('Default Privileges');
$prompt_description = translate('Description');
$prompt_schedule_transp = translate('Schedule Transparency');
$prompt_timezone = translate('Calendar Timezone');
$id = $editor->Value('collection_id');
$template = <<<EOTEMPLATE
##form##
<script language="javascript">
function toggle_privileges() {
var argv = toggle_privileges.arguments;
var argc = argv.length;
if ( argc < 1 ) {
return;
}
var set_to = -1;
if ( argv[0] == 'all' ) {
var fieldcount = document.forms[0].elements.length;
for (var i = 0; i < fieldcount; i++) {
var fieldname = document.forms[0].elements[i].name;
if ( fieldname.match( /^default_privileges/ ) ) {
if ( set_to == -1 ) {
set_to = ( document.forms[0].elements[i].checked ? 0 : 1 );
}
document.forms[0].elements[i].checked = set_to;
}
}
}
else {
for (var i = 0; i < argc; i++) {
var f = document.getElementById( 'priv_checkbox_' + argv[i]);
if ( set_to == -1 ) {
set_to = ( f.checked ? 0 : 1 );
}
f.checked = set_to;
}
}
}
function toggle_enabled() {
var argv = toggle_enabled.arguments;
var argc = argv.length;
if ( argc < 2 ) {
return;
}
for (var i = 1; i < argc; i++) {
var f = document.getElementById(argv[i]);
f.disabled = !argv[0];
}
}
</script>
<style>
th.right, label.privilege {
white-space:nowrap;
}
label.privilege {
margin:0.2em 1em 0.2em 0.1em;
padding:0 0.2em;
line-height:1.6em;
}
</style>
<table>
<tr> <th class="right">$prompt_collection_id:</th> <td class="left">##collection_id.value##</td> </tr>
<tr> <th class="right">$prompt_dav_name:</th> <td class="left">/caldav.php##dav_name.value##</td> </tr>
<tr> <th class="right">$prompt_displayname:</th> <td class="left">##dav_displayname.input.50##</td> </tr>
<tr> <th class="right">$prompt_public:</th> <td class="left">##publicly_readable.checkbox##</td> </tr>
<tr> <th class="right">$prompt_calendar:</th> <td class="left">##is_calendar.checkbox##</td> </tr>
<tr> <th class="right">$prompt_addressbook:</th> <td class="left">##is_addressbook.checkbox##</td> </tr>
<tr> <th class="right">$prompt_privileges:</th><td class="left">
<input type="button" value="All" class="submit" title="Toggle all privileges" onclick="toggle_privileges('all');">
<input type="button" value="Read/Write" class="submit" title="Set read+write privileges"
onclick="toggle_privileges('read', 'write-properties', 'write-content', 'bind', 'unbind', 'read-free-busy',
'read-current-user-privilege-set', 'schedule-deliver-invite', 'schedule-deliver-reply', 'schedule-query-freebusy',
'schedule-send-invite', 'schedule-send-reply', 'schedule-send-freebusy' );">
<input type="button" value="Read" class="submit" title="Set read privileges"
onclick="toggle_privileges('read', 'read-free-busy', 'schedule-query-freebusy', 'read-current-user-privilege-set' );">
<input type="button" value="Free/Busy" class="submit" title="Set free/busy privileges"
onclick="toggle_privileges('read-free-busy', 'schedule-query-freebusy' );">
<input type="button" value="Schedule Deliver" class="submit" title="Set schedule-deliver privileges"
onclick="toggle_privileges('schedule-deliver-invite', 'schedule-deliver-reply', 'schedule-query-freebusy' );">
<input type="button" value="Schedule Send" class="submit" title="Set schedule-deliver privileges"
onclick="toggle_privileges('schedule-send-invite', 'schedule-send-reply', 'schedule-send-freebusy' );">
<br>$privileges_set</td> </tr>
<tr> <th class="right">$prompt_timezone:</th> <td class="left">##timezone.select##</td> </tr>
<tr> <th class="right">$prompt_schedule_transp:</th> <td class="left">##schedule_transp.select##</td> </tr>
<tr> <th class="right">$prompt_description:</th> <td class="left">##description.textarea.78x6##</td> </tr>
<tr> <th class="right"></th> <td class="left" colspan="2">##submit##</td> </tr>
</table>
</form>
EOTEMPLATE;
$editor->SetTemplate( $template );
$page_elements[] = $editor;
$c->stylesheets[] = 'css/browse.css';
$c->scripts[] = 'js/browse.js';
$browser = new Browser(translate('Collection Grants'));
$browser->AddColumn( 'to_principal', translate('To ID'), 'right', '##principal_link##' );
$rowurl = $c->base_url . '/davical.php?action=edit&t=principal&id=';
$browser->AddHidden( 'principal_link', "'<a href=\"$rowurl' || to_principal || '\">' || to_principal || '</a>'" );
$browser->AddColumn( 'displayname', translate('Display Name') );
$browser->AddColumn( 'privs', translate('Privileges'), '', '', 'privileges_list(privileges)' );
$browser->AddColumn( 'members', translate('Has Members'), '', '', 'has_members_list(principal_id)' );
$browser->SetOrdering( 'displayname', 'A' );
$browser->SetJoins( "grants LEFT JOIN dav_principal ON (to_principal = principal_id) " );
$browser->SetWhere( 'by_collection = '.$id );
if ( $c->enable_row_linking ) {
$browser->RowFormat( '<tr onMouseover="LinkHref(this,1);" title="'.translate('Click to edit principal details').'" class="r%d">', '</tr>', '#even' );
}
else {
$browser->RowFormat( '<tr class="r%d">', '</tr>', '#even' );
}
$browser->DoQuery();
$page_elements[] = $browser;

View File

@ -0,0 +1,46 @@
<?php
param_to_global( 'principal_type', 'int', 'type' );
$browser = new Browser(translate('Calendar Principals'));
if ( isset($principal_type) ) {
switch($principal_type) {
case 1: $browser->Title(translate('User Calendar Principals')); break;
case 2: $browser->Title(translate('Resource Calendar Principals')); break;
case 3: $browser->Title(translate('Group Principals')); break;
}
}
$browser->AddColumn( 'principal_id', translate('ID'), 'right', '##principal_link##' );
$browser->AddColumn( 'username', translate('Name') );
$rowurl = $c->base_url . '/davical.php?action=edit&t=principal&id=';
$browser->AddHidden( 'principal_link', "'<a href=\"$rowurl' || principal_id || '\">' || principal_id || '</a>'" );
$browser->AddColumn( 'displayname', translate('Display Name') );
$browser->AddColumn( 'email', translate('EMail') );
$browser->AddColumn( 'member_of', translate('Is Member of'), '', '', 'is_member_of_list(principal_id)' );
if ( !isset($principal_type) || $principal_type == 3 ) {
$browser->AddColumn( 'members', translate('Has Members'), '', '', 'has_members_list(principal_id)' );
}
$browser->SetOrdering( 'username', 'A' );
$browser->SetJoins( "dav_principal " );
$browser->SetWhere( 'user_active' );
if ( isset($principal_type) ) {
$browser->AndWhere( 'type_id = '.$principal_type );
}
$c->page_title = $browser->Title();
if ( $c->enable_row_linking ) {
$browser->RowFormat( '<tr onMouseover="LinkHref(this,1);" title="'.translate('Click to display user details').'" class="r%d">', '</tr>', '#even' );
}
else {
$browser->RowFormat( '<tr class="r%d">', '</tr>', '#even' );
}
$browser->DoQuery();
$page_elements[] = $browser;

263
inc/ui/principal-edit.php Normal file
View File

@ -0,0 +1,263 @@
<?php
// Editor component for company records
$editor = new Editor(translate('Principal'), 'dav_principal');
$editor->AddField( 'date_format_type', null, "SELECT 'E', 'European' UNION SELECT 'U', 'US Format' UNION SELECT 'I', 'ISO Format'" );
$editor->AddField( 'type_id', null, 'SELECT principal_type_id, principal_type_desc FROM principal_type ORDER BY principal_type_id' );
param_to_global('id', 'int', 'old_id', 'principal_id' );
$editor->SetWhere( 'principal_id='.$id );
$privilege_names = array( 'read', 'write-properties', 'write-content', 'unlock', 'read-acl', 'read-current-user-privilege-set',
'bind', 'unbind', 'write-acl', 'read-free-busy', 'schedule-deliver-invite', 'schedule-deliver-reply',
'schedule-query-freebusy', 'schedule-send-invite', 'schedule-send-reply', 'schedule-send-freebusy' );
$pwstars = '@@@@@@@@@@';
if ( $editor->IsSubmit() ) {
$editor->WhereNewRecord( "principal_id=(SELECT CURRVAL('dav_id_seq'))" );
unset($_POST['password']);
if ( $_POST['newpass1'] != '' && $_POST['newpass1'] != $pwstars ) {
if ( $_POST['newpass1'] == $_POST['newpass2'] ) {
$_POST['password'] = $_POST['newpass1'];
}
else {
$c->messages[] = "Password not updated. The supplied passwords do not match.";
}
}
if ( isset($_POST['default_privileges']) ) {
$privilege_bitpos = array_flip($privilege_names);
$priv_names = array_keys($_POST['default_privileges']);
$privs = privilege_to_bits($priv_names);
$_POST['default_privileges'] = sprintf('%024s',decbin($privs));
$editor->Assign('default_privileges', $privs_dec);
}
$editor->Write();
}
else {
$editor->GetRecord();
}
if ( $editor->Available() ) {
$c->page_title = $editor->Title(translate('Principal').': '.$editor->Value('fullname'));
}
else {
$c->page_title = $editor->Title(translate('Create New Principal'));
$privs = decbin(privilege_to_bits($c->default_privileges));
$editor->Assign('default_privileges', $privs);
}
$privilege_xlate = array(
'read' => translate('Read'),
'write-properties' => translate('Write Metadata'),
'write-content' => translate('Write Data'),
'unlock' => translate('Override a Lock'),
'read-acl' => translate('Read Access Controls'),
'read-current-user-privilege-set' => translate('Read Current User\'s Access'),
'bind' => translate('Create Resources'),
'unbind' => translate('Delete Resources'),
'write-acl' => translate('Write Access Controls'),
'read-free-busy' => translate('Read Free/Busy Information'),
'schedule-deliver-invite' => translate('Scheduling: Deliver an Invitation'),
'schedule-deliver-reply' => translate('Scheduling: Deliver a Reply'),
'schedule-query-freebusy' => translate('Scheduling: Query free/busy'),
'schedule-send-invite' => translate('Scheduling: Send an Invitation'),
'schedule-send-reply' => translate('Scheduling: Send a Reply'),
'schedule-send-freebusy' => translate('Scheduling: Send free/busy')
);
$default_privileges = bindec($editor->Value('default_privileges'));
$privileges_set = '<div id="privileges">';
for( $i=0; $i<count($privilege_names); $i++ ) {
$privilege_set = ( (1 << $i) & $default_privileges ? ' CHECKED' : '');
$privileges_set .= '<label class="privilege"><input name="default_privileges['.$privilege_names[$i].']" id="priv_checkbox_'.$privilege_names[$i].'" type="checkbox"'.$privilege_set.'>'.$privilege_xlate[$privilege_names[$i]].'</label>'."\n";
}
$privileges_set .= '</div>';
$prompt_principal_id = translate('Principal ID');
$prompt_username = translate('Username');
$prompt_password_1 = translate('Change Password');
$prompt_password_1 = translate('Confirm Password');
$prompt_fullname = translate('Fullname');
$prompt_email = translate('Email Address');
$prompt_date_format = translate('Date Format Style');
$prompt_type = translate('Principal Type');
$prompt_privileges = translate('Default Privileges');
$id = $editor->Value('principal_id');
$template = <<<EOTEMPLATE
##form##
<script language="javascript">
function toggle_privileges() {
var argv = toggle_privileges.arguments;
var argc = argv.length;
if ( argc < 1 ) {
return;
}
var set_to = -1;
if ( argv[0] == 'all' ) {
var fieldcount = document.forms[0].elements.length;
for (var i = 0; i < fieldcount; i++) {
var fieldname = document.forms[0].elements[i].name;
if ( fieldname.match( /^default_privileges/ ) ) {
if ( set_to == -1 ) {
set_to = ( document.forms[0].elements[i].checked ? 0 : 1 );
}
document.forms[0].elements[i].checked = set_to;
}
}
}
else {
for (var i = 0; i < argc; i++) {
var f = document.getElementById( 'priv_checkbox_' + argv[i]);
if ( set_to == -1 ) {
set_to = ( f.checked ? 0 : 1 );
}
f.checked = set_to;
}
}
}
</script>
<style>
th.right, label.privilege {
white-space:nowrap;
}
label.privilege {
margin:0.2em 1em 0.2em 0.1em;
padding:0 0.2em;
line-height:1.6em;
}
</style>
<table>
<tr> <th class="right">$prompt_principal_id:</th> <td class="left">##principal_id.value##</td> </tr>
<tr> <th class="right">$prompt_username:</th> <td class="left">##xxxxusername.input.10##</td> </tr>
<tr> <th class="right">$prompt_password_1:</th> <td class="left">##newpass1.password.$pwstars##</td> </tr>
<tr> <th class="right">$prompt_password_1:</th> <td class="left">##newpass2.password.$pwstars##</td> </tr>
<tr> <th class="right">$prompt_fullname:</th> <td class="left">##fullname.input.50##</td> </tr>
<tr> <th class="right">$prompt_email:</th> <td class="left">##email.input.50##</td> </tr>
<tr> <th class="right">$prompt_date_format:</th> <td class="left">##date_format_type.select##</td> </tr>
<tr> <th class="right">$prompt_type:</th> <td class="left">##type_id.select##</td> </tr>
<tr> <th class="right">$prompt_privileges:</th><td class="left">
<input type="button" value="All" class="submit" title="Toggle all privileges" onclick="toggle_privileges('all');">
<input type="button" value="Read/Write" class="submit" title="Set read+write privileges"
onclick="toggle_privileges('read', 'write-properties', 'write-content', 'bind', 'unbind', 'read-free-busy',
'read-current-user-privilege-set', 'schedule-deliver-invite', 'schedule-deliver-reply', 'schedule-query-freebusy',
'schedule-send-invite', 'schedule-send-reply', 'schedule-send-freebusy' );">
<input type="button" value="Read" class="submit" title="Set read privileges"
onclick="toggle_privileges('read', 'read-free-busy', 'schedule-query-freebusy', 'read-current-user-privilege-set' );">
<input type="button" value="Free/Busy" class="submit" title="Set free/busy privileges"
onclick="toggle_privileges('read-free-busy', 'schedule-query-freebusy' );">
<input type="button" value="Schedule Deliver" class="submit" title="Set schedule-deliver privileges"
onclick="toggle_privileges('schedule-deliver-invite', 'schedule-deliver-reply', 'schedule-query-freebusy' );">
<input type="button" value="Schedule Send" class="submit" title="Set schedule-deliver privileges"
onclick="toggle_privileges('schedule-send-invite', 'schedule-send-reply', 'schedule-send-freebusy' );">
<br>$privileges_set</td> </tr>
<tr> <th class="right"></th> <td class="left" colspan="2">##submit##</td> </tr>
</table>
</form>
EOTEMPLATE;
$editor->SetTemplate( $template );
$page_elements[] = $editor;
$browser = new Browser(translate('Group Memberships'));
$c->stylesheets[] = 'css/browse.css';
$c->scripts[] = 'js/browse.js';
$browser->AddColumn( 'group_id', translate('ID'), 'right', '##principal_link##' );
$rowurl = $c->base_url . '/davical.php?action=edit&t=principal&id=';
$browser->AddHidden( 'principal_link', "'<a href=\"$rowurl' || principal_id || '\">' || principal_id || '</a>'" );
$browser->AddColumn( 'displayname', translate('Display Name') );
$browser->AddColumn( 'member_of', translate('Is Member of'), '', '', 'is_member_of_list(principal_id)' );
$browser->AddColumn( 'members', translate('Has Members'), '', '', 'has_members_list(principal_id)' );
$browser->SetOrdering( 'displayname', 'A' );
$browser->SetJoins( "group_member LEFT JOIN dav_principal ON (group_id = principal_id) " );
$browser->SetWhere( 'user_active AND member_id = '.$id );
if ( $c->enable_row_linking ) {
$browser->RowFormat( '<tr onMouseover="LinkHref(this,1);" title="'.translate('Click to edit principal details').'" class="r%d">', '</tr>', '#even' );
}
else {
$browser->RowFormat( '<tr class="r%d">', '</tr>', '#even' );
}
$browser->DoQuery();
$page_elements[] = $browser;
if ( $editor->Value('type_id') == 3 ) {
$browser = new Browser(translate('Group Members'));
$browser->AddColumn( 'group_id', translate('ID'), 'right', '##principal_link##' );
$rowurl = $c->base_url . '/davical.php?action=edit&t=principal&id=';
$browser->AddHidden( 'principal_link', "'<a href=\"$rowurl' || principal_id || '\">' || principal_id || '</a>'" );
$browser->AddColumn( 'displayname', translate('Display Name') );
$browser->AddColumn( 'member_of', translate('Is Member of'), '', '', 'is_member_of_list(principal_id)' );
$browser->AddColumn( 'members', translate('Has Members'), '', '', 'has_members_list(principal_id)' );
$browser->SetOrdering( 'displayname', 'A' );
$browser->SetJoins( "group_member LEFT JOIN dav_principal ON (member_id = principal_id) " );
$browser->SetWhere( 'user_active AND group_id = '.$id );
if ( $c->enable_row_linking ) {
$browser->RowFormat( '<tr onMouseover="LinkHref(this,1);" title="'.translate('Click to edit principal details').'" class="r%d">', '</tr>', '#even' );
}
else {
$browser->RowFormat( '<tr class="r%d">', '</tr>', '#even' );
}
$browser->DoQuery();
$page_elements[] = $browser;
}
$browser = new Browser(translate('Principal Grants'));
$browser->AddColumn( 'to_principal', translate('To ID'), 'right', '##principal_link##' );
$rowurl = $c->base_url . '/davical.php?action=edit&t=principal&id=';
$browser->AddHidden( 'principal_link', "'<a href=\"$rowurl' || to_principal || '\">' || to_principal || '</a>'" );
$browser->AddColumn( 'displayname', translate('Display Name') );
$browser->AddColumn( 'privs', translate('Privileges'), '', '', 'privileges_list(privileges)' );
$browser->AddColumn( 'members', translate('Has Members'), '', '', 'has_members_list(principal_id)' );
$browser->SetOrdering( 'displayname', 'A' );
$browser->SetJoins( "grants LEFT JOIN dav_principal ON (to_principal = principal_id) " );
$browser->SetWhere( 'by_principal = '.$id );
if ( $c->enable_row_linking ) {
$browser->RowFormat( '<tr onMouseover="LinkHref(this,1);" title="'.translate('Click to edit principal details').'" class="r%d">', '</tr>', '#even' );
}
else {
$browser->RowFormat( '<tr class="r%d">', '</tr>', '#even' );
}
$browser->DoQuery();
$page_elements[] = $browser;
$browser = new Browser(translate('Principal Collections'));
$browser->AddColumn( 'collection_id', translate('ID'), 'right', '##collection_link##' );
$rowurl = $c->base_url . '/davical.php?action=edit&t=collection&id=';
$browser->AddHidden( 'collection_link', "'<a href=\"$rowurl' || collection_id || '\">' || collection_id || '</a>'" );
$browser->AddColumn( 'dav_name', translate('Path') );
$browser->AddColumn( 'dav_displayname', translate('Display Name') );
$browser->AddColumn( 'privs', translate('Privileges'), '', '', 'privileges_list(default_privileges)' );
$browser->SetOrdering( 'dav_name', 'A' );
$browser->SetJoins( "collection " );
$browser->SetWhere( 'user_no = '.intval($editor->Value('user_no')) );
if ( $c->enable_row_linking ) {
$browser->RowFormat( '<tr onMouseover="LinkHref(this,1);" title="'.translate('Click to edit principal details').'" class="r%d">', '</tr>', '#even' );
}
else {
$browser->RowFormat( '<tr class="r%d">', '</tr>', '#even' );
}
$browser->DoQuery();
$page_elements[] = $browser;