diff --git a/htdocs/davical.php b/htdocs/davical.php new file mode 100644 index 00000000..465501d8 --- /dev/null +++ b/htdocs/davical.php @@ -0,0 +1,49 @@ +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'); diff --git a/inc/classEditor.php b/inc/classEditor.php new file mode 100644 index 00000000..54bab1f6 --- /dev/null +++ b/inc/classEditor.php @@ -0,0 +1,478 @@ + +* @copyright Catalyst IT Ltd, Morphoss Ltd +* @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 .= ""; + } + } + 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, '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('
', $this->Id); + case "##submit##": + $action = ( $this->RecordAvailable ? 'update' : 'insert' ); + $submittype = ($this->RecordAvailable ? 'Apply Changes' : 'Create'); + return sprintf('', + $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 ""; + case "checkbox": + switch ( $field_value ) { + case 'f': + case 'off': + case 'false': + case '': + case '0': + $checked = ""; + break; + + default: + $checked = " CHECKED"; + } + return ""; + case "input": + $size = (isset($part3) ? $part3 : 6); + return ""; + case "file": + $size = (isset($part3) ? $part3 : 30); + return ""; + case "money": + $size = (isset($part3) ? $part3 : 8); + return ""; + case "date": + $size = (isset($part3) ? $part3 : 10); + return ""; + case "textarea": + list( $cols, $rows ) = split( 'x', $part3); + return ""; + case "hidden": + return sprintf( "", htmlspecialchars($field_value) ); + case "password": + return sprintf( "", htmlspecialchars($part3) ); + case "encval": + case "enc": + return htmlspecialchars($field_value); + case "submit": + $action = ( $this->RecordAvailable ? 'update' : 'insert' ); + return sprintf('', + $this->Id, $action, $this->SubmitName, $value_field_name ); + default: + return str_replace( "\n", "
", $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('
', $this->Id); + if ( isset($this->Title) && $this->Title != "" ) { + if ( !isset($title_tag) ) $title_tag = 'h1'; + $html = "<$title_tag>$this->Title\n"; + } + + // Stuff like "##fieldname.part## gets converted to the appropriate value + $replaced = preg_replace_callback("/##([^#.]+)(\.([^#.]+))?(\.([^#.]+))?##/", array(&$this, "ReplaceEditorPart"), $this->Template ); + $html .= $replaced; + + $html .= '
'; + 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; + } +} + diff --git a/inc/interactive-page.php b/inc/interactive-page.php index 2b223f49..e4115bcd 100644 --- a/inc/interactive-page.php +++ b/inc/interactive-page.php @@ -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' )) { diff --git a/inc/ui/collection-edit.php b/inc/ui/collection-edit.php new file mode 100644 index 00000000..f04af8df --- /dev/null +++ b/inc/ui/collection-edit.php @@ -0,0 +1,204 @@ +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 = '
'; +for( $i=0; $i'.$privilege_xlate[$privilege_names[$i]].''."\n"; +} +$privileges_set .= '
'; + +$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 = << +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]; + } +} + + + + + + + + + + + + + + +
$prompt_collection_id: ##collection_id.value##
$prompt_dav_name: /caldav.php##dav_name.value##
$prompt_displayname: ##dav_displayname.input.50##
$prompt_public: ##publicly_readable.checkbox##
$prompt_calendar: ##is_calendar.checkbox##
$prompt_addressbook: ##is_addressbook.checkbox##
$prompt_privileges: + + + + + + +
$privileges_set
$prompt_timezone: ##timezone.select##
$prompt_schedule_transp: ##schedule_transp.select##
$prompt_description: ##description.textarea.78x6##
##submit##
+ +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', "'' || to_principal || ''" ); +$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( '', '', '#even' ); +} +else { + $browser->RowFormat( '', '', '#even' ); +} +$browser->DoQuery(); +$page_elements[] = $browser; + + + diff --git a/inc/ui/principal-browse.php b/inc/ui/principal-browse.php new file mode 100644 index 00000000..787fedb3 --- /dev/null +++ b/inc/ui/principal-browse.php @@ -0,0 +1,46 @@ +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', "'' || principal_id || ''" ); +$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( '', '', '#even' ); +} +else { + $browser->RowFormat( '', '', '#even' ); +} + +$browser->DoQuery(); +$page_elements[] = $browser; + + diff --git a/inc/ui/principal-edit.php b/inc/ui/principal-edit.php new file mode 100644 index 00000000..5aca7532 --- /dev/null +++ b/inc/ui/principal-edit.php @@ -0,0 +1,263 @@ +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 = '
'; +for( $i=0; $i'.$privilege_xlate[$privilege_names[$i]].''."\n"; +} +$privileges_set .= '
'; + +$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 = << +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; + } + } +} + + + + + + + + + + + + + +
$prompt_principal_id: ##principal_id.value##
$prompt_username: ##xxxxusername.input.10##
$prompt_password_1: ##newpass1.password.$pwstars##
$prompt_password_1: ##newpass2.password.$pwstars##
$prompt_fullname: ##fullname.input.50##
$prompt_email: ##email.input.50##
$prompt_date_format: ##date_format_type.select##
$prompt_type: ##type_id.select##
$prompt_privileges: + + + + + + +
$privileges_set
##submit##
+ +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', "'' || principal_id || ''" ); +$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( '', '', '#even' ); +} +else { + $browser->RowFormat( '', '', '#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', "'' || principal_id || ''" ); + $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( '', '', '#even' ); + } + else { + $browser->RowFormat( '', '', '#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', "'' || to_principal || ''" ); +$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( '', '', '#even' ); +} +else { + $browser->RowFormat( '', '', '#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', "'' || collection_id || ''" ); +$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( '', '', '#even' ); +} +else { + $browser->RowFormat( '', '', '#even' ); +} +$browser->DoQuery(); +$page_elements[] = $browser; + +