uid and etag (optimistic locking) for addressbook

This commit is contained in:
Ralf Becker 2008-04-25 19:06:15 +00:00
parent 684d6551f2
commit 86368a1903
11 changed files with 242 additions and 159 deletions

View File

@ -529,6 +529,7 @@ class bocontacts extends socontacts
if(!($this->error = parent::save($to_write)) && is_object($GLOBALS['egw']->contenthistory)) if(!($this->error = parent::save($to_write)) && is_object($GLOBALS['egw']->contenthistory))
{ {
$contact['id'] = $to_write['id']; $contact['id'] = $to_write['id'];
$contact['etag'] = $to_write['etag'];
$GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $contact['id'],$isUpdate ? 'modify' : 'add', time()); $GLOBALS['egw']->contenthistory->updateTimeStamp('contacts', $contact['id'],$isUpdate ? 'modify' : 'add', time());
if ($contact['account_id']) // invalidate the cache of the accounts class if ($contact['account_id']) // invalidate the cache of the accounts class
@ -902,45 +903,6 @@ class bocontacts extends socontacts
return $result; return $result;
} }
/**
* Hook called by link-class to include calendar in the appregistry of the linkage
*
* @param array/string $location location and other parameters (not used)
* @return array with method-names
*/
function search_link($location)
{
return array(
'query' => 'addressbook.bocontacts.link_query',
'title' => 'addressbook.bocontacts.link_title',
'titles' => 'addressbook.bocontacts.link_titles',
'view' => array(
'menuaction' => 'addressbook.uicontacts.view'
),
'view_id' => 'contact_id',
'add' => array(
'menuaction' => 'addressbook.uicontacts.edit'
),
'add_app' => 'link_app',
'add_id' => 'link_id',
'add_popup' => '850x440',
);
}
/**
* Register contacts as calendar resources (items which can be sheduled by the calendar)
*
* @param array $args hook-params (not used)
* @return array
*/
function calendar_resources($args)
{
return array(
'type' => 'c',// one char type-identifiy for this resources
'info' => 'addressbook.bocontacts.calendar_info',// info method, returns array with id, type & name for a given id
);
}
/** /**
* returns info about contacts for calender * returns info about contacts for calender
* *

View File

@ -464,6 +464,7 @@ class socontacts
if (!($error_nr = $this->somain->save())) if (!($error_nr = $this->somain->save()))
{ {
$contact['id'] = $this->somain->data['id']; $contact['id'] = $this->somain->data['id'];
$contact['etag'] = $this->somain->data['etag'];
if ($this->contact_repository == 'sql-ldap') if ($this->contact_repository == 'sql-ldap')
{ {

View File

@ -582,6 +582,58 @@ class socontacts_sql extends so_sql
return $this->db->affected_rows(); return $this->db->affected_rows();
} }
/**
* Reads a contact, reimplemented to use the uid, if a non-numeric key is given
*
* @param int|string|array $keys
* @param string|array $extra_cols
* @param string $join
* @return array|boolean
*/
function read($keys,$extra_cols='',$join='')
{
if (!is_array($keys) && !is_numeric($keys))
{
$keys = array('contact_uid' => $keys);
}
return parent::read($keys,$extra_cols,$join);
}
/**
* Saves a contact, reimplemented to check a given etag and set a uid
*
* @param array $keys if given $keys are copied to data before saveing => allows a save as
* @param string|array $extra_where=null extra where clause, eg. to check the etag, returns 'nothing_affected' if not affected rows
* @return int 0 on success and errno != 0 else
*/
function save($keys=null)
{
if (is_array($keys) && count($keys)) $this->data_merge($keys);
if (isset($this->data['etag']))
{
$etag = $this->data['etag'];
unset($this->data['etag']);
if (!($err = parent::save(array('contact_etag=contact_etag+1'),array('contact_etag' => $etag))))
{
$this->data['etag'] = $etag+1;
}
else
{
$this->data['etag'] = $etag;
}
}
else
{
$err = parent::save();
}
if (!$err && !$this->data['uid'])
{
$this->update(array('uid' => common::generate_uid('addressbook',$this->data['id'])));
}
return $err;
}
/** /**
* Read data of a distribution list * Read data of a distribution list

View File

@ -1278,6 +1278,16 @@ class uicontacts extends bocontacts
} }
} }
} }
elseif($this->error === true)
{
$content['msg'] = lang('Error: the entry has been updated since you opened it for editing!').'<br />'.
lang('Copy your changes to the clipboard, %1reload the entry%2 and merge them.','<a href="'.
htmlspecialchars($GLOBALS['egw']->link('/index.php',array(
'menuaction' => 'addressbook.uicontacts.edit',
'contact_id' => $content['id'],
))).'">','</a>');
break; // dont refresh the list
}
else else
{ {
$content['msg'] = lang('Error saving the contact !!!'). $content['msg'] = lang('Error saving the contact !!!').

View File

@ -106,6 +106,7 @@ contacts to ldap, account contact-data to sql admin de Kontakte nach LDAP, Konta
contains addressbook de beinhaltet contains addressbook de beinhaltet
copied by %1, from record #%2. addressbook de Kopiert von %1, vom Datensatz Nr. %2. copied by %1, from record #%2. addressbook de Kopiert von %1, vom Datensatz Nr. %2.
copy a contact and edit the copy addressbook de Kopiert einen Kontakt und bearbeitet dann die Kopie copy a contact and edit the copy addressbook de Kopiert einen Kontakt und bearbeitet dann die Kopie
copy your changes to the clipboard, %1reload the entry%2 and merge them. addressbook de Kopieren Sie Ihre Änderungen in die Zwischenablage, %1laden Sie den Eintrag neu%2 und fügen diese wieder ein.
country common de Land country common de Land
create new links addressbook de Neue Verknüpfung erstellen create new links addressbook de Neue Verknüpfung erstellen
created addressbook de Angelegt created addressbook de Angelegt
@ -158,6 +159,7 @@ end addressbook de Ende
enter the path to the exported file here addressbook de Bitte geben Sie den Pfad für die exportierte Datei an enter the path to the exported file here addressbook de Bitte geben Sie den Pfad für die exportierte Datei an
error deleting the contact !!! addressbook de Fehler beim Löschen des Kontakts !!! error deleting the contact !!! addressbook de Fehler beim Löschen des Kontakts !!!
error saving the contact !!! addressbook de Fehler beim Speichern des Kontakts !!! error saving the contact !!! addressbook de Fehler beim Speichern des Kontakts !!!
error: the entry has been updated since you opened it for editing! addressbook de Fehler: der Eintrag wurde geändert, seit Sie ihn zum Bearbeiten geöffnet haben!
example $$if n_prefix~mr~hello mr.~hello ms.$$ - search the field "n_prefix", for "mr", if found, write hello mr., else write hello ms. addressbook de Beispiel: "$$IF n_prefix~Herr~Sehr geehrter~Sehr geehrte$$" - suche in dem Feld "n_prefix" nach "Herr", wenn gefunden, schreibe "Sehr geehrter", wenn nicht gefunden schreibe "Sehr geehrte" example $$if n_prefix~mr~hello mr.~hello ms.$$ - search the field "n_prefix", for "mr", if found, write hello mr., else write hello ms. addressbook de Beispiel: "$$IF n_prefix~Herr~Sehr geehrter~Sehr geehrte$$" - suche in dem Feld "n_prefix" nach "Herr", wenn gefunden, schreibe "Sehr geehrter", wenn nicht gefunden schreibe "Sehr geehrte"
existing links addressbook de Bestehende Verknüpfungen existing links addressbook de Bestehende Verknüpfungen
export addressbook de Export export addressbook de Export
@ -362,7 +364,7 @@ updated addressbook de Aktualisiert
upload or delete the photo addressbook de Foto hochladen oder löschen upload or delete the photo addressbook de Foto hochladen oder löschen
url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin de URL mit denen Telefonnummern verlinkt werden sollen (verwenden Sie %1 = anzurufende Nummer, %u = Benutzernamen, %t = Telefon des Benutzers) url to link telephone numbers to (use %1 = number to call, %u = account name, %t = account phone) admin de URL mit denen Telefonnummern verlinkt werden sollen (verwenden Sie %1 = anzurufende Nummer, %u = Benutzernamen, %t = Telefon des Benutzers)
use an extra category tab? addressbook de Separaten Reiter für Kategorien verwenden? use an extra category tab? addressbook de Separaten Reiter für Kategorien verwenden?
use an extra tab for private custom fields? admin de Soll ein extra Tab für private Benutzerdefinierte Felder benutzt werden? use an extra tab for private custom fields? admin de Separaten Reiter für private benutzerdefinierte Felder verwenden?
use country list addressbook de Länderliste benutzen use country list addressbook de Länderliste benutzen
use setup for a full account-migration admin de für eine komplette Benutzer Migration setup verwenden use setup for a full account-migration admin de für eine komplette Benutzer Migration setup verwenden
used for links and for the own sorting of the list addressbook de wird für Verküpfungen und die eigene Sortierung der Liste benützt used for links and for the own sorting of the list addressbook de wird für Verküpfungen und die eigene Sortierung der Liste benützt

View File

@ -106,6 +106,7 @@ contacts to ldap, account contact-data to sql admin en contacts to LDAP, account
contains addressbook en contains contains addressbook en contains
copied by %1, from record #%2. addressbook en Copied by %1, from record #%2. copied by %1, from record #%2. addressbook en Copied by %1, from record #%2.
copy a contact and edit the copy addressbook en Copy a contact and edit the copy copy a contact and edit the copy addressbook en Copy a contact and edit the copy
copy your changes to the clipboard, %1reload the entry%2 and merge them. addressbook en Copy your changes to the clipboard, %1reload the entry%2 and merge them.
country common en Country country common en Country
create new links addressbook en Create new links create new links addressbook en Create new links
created addressbook en Created created addressbook en Created
@ -158,6 +159,7 @@ end addressbook en End
enter the path to the exported file here addressbook en Enter the path to the exported file here enter the path to the exported file here addressbook en Enter the path to the exported file here
error deleting the contact !!! addressbook en Error deleting the contact !!! error deleting the contact !!! addressbook en Error deleting the contact !!!
error saving the contact !!! addressbook en Error saving the contact !!! error saving the contact !!! addressbook en Error saving the contact !!!
error: the entry has been updated since you opened it for editing! addressbook en Error: the entry has been updated since you opened it for editing!
example $$if n_prefix~mr~hello mr.~hello ms.$$ - search the field "n_prefix", for "mr", if found, write hello mr., else write hello ms. addressbook en Example $$IF n_prefix~Mr~Hello Mr.~Hello Ms.$$ - search the field "n_prefix", for "Mr", if found, write Hello Mr., else write Hello Ms. example $$if n_prefix~mr~hello mr.~hello ms.$$ - search the field "n_prefix", for "mr", if found, write hello mr., else write hello ms. addressbook en Example $$IF n_prefix~Mr~Hello Mr.~Hello Ms.$$ - search the field "n_prefix", for "Mr", if found, write Hello Mr., else write Hello Ms.
existing links addressbook en Existing links existing links addressbook en Existing links
export addressbook en export export addressbook en export

File diff suppressed because one or more lines are too long

View File

@ -53,7 +53,7 @@
</rows> </rows>
</grid> </grid>
</template> </template>
<template id="addressbook.edit.general" template="" lang="" group="0" version="1.3.005"> <template id="addressbook.edit.general" template="" lang="" group="0" version="1.5.002">
<grid height="258"> <grid height="258">
<columns> <columns>
<column/> <column/>
@ -98,7 +98,7 @@
<row> <row>
<image src="home"/> <image src="home"/>
<description value="Organisation"/> <description value="Organisation"/>
<textbox id="org_name" size="45" maxlength="64" onchange="setName(this);"/> <textbox id="org_name" size="45" maxlength="128" onchange="setName(this);"/>
</row> </row>
<row> <row>
<description/> <description/>
@ -326,6 +326,30 @@
</rows> </rows>
</grid> </grid>
</template> </template>
<template id="addressbook.edit.distribution_list" template="" lang="" group="0" version="1.5.001">
<grid width="100%" height="258" overflow="auto">
<columns>
<column/>
</columns>
<rows>
<row class="th">
<description value="Distribution lists"/>
</row>
<row>
<grid>
<columns>
<column/>
</columns>
<rows>
<row>
<description span="all" id="distrib_lists"/>
</row>
</rows>
</grid>
</row>
</rows>
</grid>
</template>
<template id="addressbook.edit.custom" template="" lang="" group="0" version="1.5.001"> <template id="addressbook.edit.custom" template="" lang="" group="0" version="1.5.001">
<grid width="100%" height="258" class="row_on" spacing="0" padding="0" overflow="auto"> <grid width="100%" height="258" class="row_on" spacing="0" padding="0" overflow="auto">
<columns> <columns>
@ -443,7 +467,7 @@
</rows> </rows>
</grid> </grid>
</template> </template>
<template id="addressbook.edit" template="" lang="" group="0" version="1.5.002"> <template id="addressbook.edit" template="" lang="" group="0" version="1.5.003">
<grid> <grid>
<columns> <columns>
<column width="450"/> <column width="450"/>
@ -451,7 +475,7 @@
</columns> </columns>
<rows> <rows>
<row disabled="!@msg"> <row disabled="!@msg">
<description span="all" class="redItalic" id="msg" no_lang="1"/> <htmlarea span="all" class="redItalic" id="msg" no_lang="1" readonly="true"/>
<description/> <description/>
</row> </row>
<row> <row>
@ -481,6 +505,7 @@
<tab label="Private" statustext="Home address, Birthday, ..."/> <tab label="Private" statustext="Home address, Birthday, ..."/>
<tab label="Details" statustext="Categories, Notes, ..."/> <tab label="Details" statustext="Categories, Notes, ..."/>
<tab label="Links" statustext="Links"/> <tab label="Links" statustext="Links"/>
<tab label="Distribution lists" statustext="Distribution lists, ..."/>
<tab label="Extra" statustext="Custom fields"/> <tab label="Extra" statustext="Custom fields"/>
<tab label="Extra private" statustext="Private custom fields"/> <tab label="Extra private" statustext="Private custom fields"/>
</tabs> </tabs>
@ -490,6 +515,7 @@
<template id="addressbook.edit.home"/> <template id="addressbook.edit.home"/>
<template id="addressbook.edit.details"/> <template id="addressbook.edit.details"/>
<template id="addressbook.edit.links"/> <template id="addressbook.edit.links"/>
<template id="addressbook.edit.distribution_list"/>
<template id="addressbook.edit.custom"/> <template id="addressbook.edit.custom"/>
<template id="addressbook.edit.custom_private"/> <template id="addressbook.edit.custom_private"/>
</tabpanels> </tabpanels>
@ -561,12 +587,12 @@
<row> <row>
<image src="email.png"/> <image src="email.png"/>
<description value="email" options=",,,email"/> <description value="email" options=",,,email"/>
<textbox id="email" size="28" maxlength="64"/> <textbox id="email" size="28" maxlength="128"/>
</row> </row>
<row> <row>
<description/> <description/>
<description value="Private" options=",,,email_home"/> <description value="Private" options=",,,email_home"/>
<textbox id="email_home" size="28" maxlength="64"/> <textbox id="email_home" size="28" maxlength="128"/>
</row> </row>
</rows> </rows>
</grid> </grid>

View File

@ -12,7 +12,7 @@
/* Basic information about this app */ /* Basic information about this app */
$setup_info['phpgwapi']['name'] = 'phpgwapi'; $setup_info['phpgwapi']['name'] = 'phpgwapi';
$setup_info['phpgwapi']['title'] = 'eGroupWare API'; $setup_info['phpgwapi']['title'] = 'eGroupWare API';
$setup_info['phpgwapi']['version'] = '1.5.008'; $setup_info['phpgwapi']['version'] = '1.5.009';
$setup_info['phpgwapi']['versions']['current_header'] = '1.28'; $setup_info['phpgwapi']['versions']['current_header'] = '1.28';
$setup_info['phpgwapi']['enable'] = 3; $setup_info['phpgwapi']['enable'] = 3;
$setup_info['phpgwapi']['app_order'] = 1; $setup_info['phpgwapi']['app_order'] = 1;
@ -44,9 +44,9 @@ $setup_info['phpgwapi']['tables'][] = 'egw_addressbook_extra';
$setup_info['phpgwapi']['tables'][] = 'egw_addressbook_lists'; $setup_info['phpgwapi']['tables'][] = 'egw_addressbook_lists';
$setup_info['phpgwapi']['tables'][] = 'egw_addressbook2list'; $setup_info['phpgwapi']['tables'][] = 'egw_addressbook2list';
$setup_info['phpgwapi']['tables'][] = 'egw_sqlfs'; $setup_info['phpgwapi']['tables'][] = 'egw_sqlfs';
$setup_info['phpgwapi']['tables'][] = 'egw_index_keywords';
$setup_info['phpgwapi']['tables'][] = 'egw_index'; $setup_info['phpgwapi']['tables'][] = 'egw_index';
$setup_info['phpgwapi']['tables'][] = 'egw_cat2entry'; $setup_info['phpgwapi']['tables'][] = 'egw_cat2entry';
$setup_info['phpgwapi']['tables'][] = 'egw_index_keywords';
// hooks used by vfs_home_hooks to manage user- and group-directories for the new stream based VFS // hooks used by vfs_home_hooks to manage user- and group-directories for the new stream based VFS
$setup_info['phpgwapi']['hooks']['addaccount'] = 'phpgwapi.vfs_home_hooks.addAccount'; $setup_info['phpgwapi']['hooks']['addaccount'] = 'phpgwapi.vfs_home_hooks.addAccount';
@ -64,3 +64,4 @@ $setup_info['notifywindow']['enable'] = 2;
$setup_info['notifywindow']['app_order'] = 1; $setup_info['notifywindow']['app_order'] = 1;
$setup_info['notifywindow']['tables'] = ''; $setup_info['notifywindow']['tables'] = '';
$setup_info['notifywindow']['hooks'][] = 'home'; $setup_info['notifywindow']['hooks'][] = 'home';

View File

@ -383,11 +383,13 @@ $phpgw_baseline = array(
'contact_modified' => array('type' => 'int','precision' => '8','nullable' => False), 'contact_modified' => array('type' => 'int','precision' => '8','nullable' => False),
'contact_modifier' => array('type' => 'int','precision' => '4'), 'contact_modifier' => array('type' => 'int','precision' => '4'),
'contact_jpegphoto' => array('type' => 'blob'), 'contact_jpegphoto' => array('type' => 'blob'),
'account_id' => array('type' => 'int','precision' => '4') 'account_id' => array('type' => 'int','precision' => '4'),
'contact_etag' => array('type' => 'int','precision' => '4','default' => '0'),
'contact_uid' => array('type' => 'varchar','precision' => '255')
), ),
'pk' => array('contact_id'), 'pk' => array('contact_id'),
'fk' => array(), 'fk' => array(),
'ix' => array('contact_owner','cat_id','n_fileas',array('n_family','n_given'),array('n_given','n_family'),array('org_name','n_family','n_given')), 'ix' => array('contact_owner','cat_id','n_fileas','contact_uid',array('n_family','n_given'),array('n_given','n_family'),array('org_name','n_family','n_given')),
'uc' => array('account_id') 'uc' => array('account_id')
), ),
'egw_addressbook_extra' => array( 'egw_addressbook_extra' => array(
@ -484,5 +486,5 @@ $phpgw_baseline = array(
'fk' => array(), 'fk' => array(),
'ix' => array('cat_id'), 'ix' => array('cat_id'),
'uc' => array() 'uc' => array()
), )
); );

View File

@ -364,3 +364,28 @@ function phpgwapi_upgrade1_5_007()
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.5.008'; return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.5.008';
} }
$test[] = '1.5.008';
function phpgwapi_upgrade1_5_008()
{
// add UID and etag columns to addressbook, required eg. for CardDAV
$GLOBALS['egw_setup']->oProc->AddColumn('egw_addressbook','contact_etag',array(
'type' => 'int',
'precision' => '4',
'default' => '0',
));
// add UID column to addressbook, required eg. for CardDAV
$GLOBALS['egw_setup']->oProc->AddColumn('egw_addressbook','contact_uid',array(
'type' => 'varchar',
'precision' => '255'
));
$GLOBALS['egw_setup']->db->query("SELECT config_value FROM egw_config WHERE config_app='phpgwapi' AND config_name='install_id'",__LINE__,__FILE__);
$install_id = $GLOBALS['egw_setup']->db->next_record() ? $GLOBALS['egw_setup']->db->f(0) : md5(time());
$GLOBALS['egw_setup']->db->query('UPDATE egw_addressbook SET contact_uid='.$GLOBALS['egw_setup']->db->concat("'addressbook-'",'contact_id',"'-$install_id'"),__LINE__,__FILE__);
$GLOBALS['egw_setup']->oProc->CreateIndex('egw_addressbook',array('contact_uid'),false);
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.5.009';
}