Commit 45e050d0 authored by Daniel Morlock's avatar Daniel Morlock

Merge branch 'caldav_pgsql' into 'feature_caldav'

Caldav pgsql

Adds initial postgresql back-end support, but this is just an initial PoC that breaks mysql support for caldav in order to get postgresql working; related to issue #20. The existing mysql db has a column name `user`, which is a reserved keyword in postgresql, so renamed that to `username`.

TODO:
 - add mysql db update file to update `user` column to `username`
 - work out db-agnostic code for timestamps in the `last_change` column in `caldav_props`

See merge request !5
parents e2b75973 a9baf3e2
......@@ -25,7 +25,7 @@ CREATE TABLE IF NOT EXISTS `caldav_props` (
`obj_type` enum('vcal','vevent','vtodo','') NOT NULL,
`url` varchar(255) NOT NULL,
`tag` varchar(255) DEFAULT NULL,
`user` varchar(255) DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
`pass` varchar(1024) DEFAULT NULL,
`last_change` TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY `obj_id` (`obj_id`,`obj_type`)
......
ALTER TABLE `caldav_props` change `user` `username` varchar(255);
/**
* CalDAV Client
*
* @version @package_version@
* @author Hugo Slabbert <hugo@slabnet.com>
*
* Copyright (C) 2014, Hugo Slabbert <hugo@slabnet.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
CREATE TYPE caldav_type AS ENUM ('vcal','vevent','vtodo','');
CREATE TABLE IF NOT EXISTS caldav_props (
obj_id int NOT NULL,
obj_type caldav_type NOT NULL,
url varchar(255) NOT NULL,
tag varchar(255) DEFAULT NULL,
username varchar(255) DEFAULT NULL,
pass varchar(1024) DEFAULT NULL,
last_change timestamp without time zone DEFAULT now() NOT NULL,
PRIMARY KEY (obj_id, obj_type)
);
CREATE OR REPLACE FUNCTION upd_timestamp() RETURNS TRIGGER
LANGUAGE plpgsql
AS
$$
BEGIN
NEW.last_change = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$;
CREATE TRIGGER update_timestamp
BEFORE INSERT OR UPDATE
ON caldav_props
FOR EACH ROW
EXECUTE PROCEDURE upd_timestamp();
......@@ -114,7 +114,7 @@ class caldav_driver extends database_driver
* @param array List of caldav properties:
* url: Absolute calendar URL or relative event URL.
* tag: Calendar ctag or event etag.
* user: Authentication user in case of calendar obj.
* username: Authentication user in case of calendar obj.
* pass: Authentication password in case of calendar obj.
*
* @return True on success, false otherwise.
......@@ -131,13 +131,14 @@ class caldav_driver extends database_driver
}
$query = $this->rc->db->query(
"INSERT INTO ".$this->db_caldav_props." (obj_id, obj_type, url, tag, user, pass) ".
"INSERT INTO ".$this->db_caldav_props.
" (obj_id, obj_type, url, tag, username, pass) ".
"VALUES (?, ?, ?, ?, ?, ?)",
$obj_id,
$obj_type,
$props["url"],
isset($props["tag"]) ? $props["tag"] : null,
isset($props["user"]) ? $props["user"] : null,
isset($props["username"]) ? $props["username"] : null,
$password);
return $this->rc->db->affected_rows($query);
......@@ -151,7 +152,7 @@ class caldav_driver extends database_driver
* @return array List of caldav properties or false on error:
* url: Absolute calendar URL or relative event URL.
* tag: Calendar ctag or event etag.
* user: Authentication user in case of calendar obj.
* username: Authentication user in case of calendar obj.
* pass: Authentication password in case of calendar obj.
* last_change: Read-only DateTime obj of the last change.
*/
......@@ -234,10 +235,10 @@ class caldav_driver extends database_driver
// Atomic sql: Check for exceeded sync period and update last_change.
$query = $this->rc->db->query(
"UPDATE ".$this->db_caldav_props." ".
"SET last_change = CURRENT_TIMESTAMP ".
"WHERE obj_id = ? AND obj_type = ? ".
"AND last_change <= (CURRENT_TIMESTAMP - ?);",
$cal_id, self::OBJ_TYPE_VCAL, $this->sync_period);
"SET last_change = NOW() WHERE obj_id = ? AND obj_type = ? AND ".
$this->unixtimestamp('last_change') ." + ? <= ".
$this->unixtimestamp('NOW()'),
$cal_id, self::OBJ_TYPE_VCAL, $this->sync_period);
if($query->rowCount() > 0)
{
......@@ -261,14 +262,14 @@ class caldav_driver extends database_driver
* @param array List of caldav properties
* url: Absolute calendar URL or relative event URL.
* tag: Calendar ctag or event etag.
* user: Authentication user in case of calendar obj.
* username: Authentication user in case of calendar obj.
* pass: Authentication password in case of calendar obj.
* last_change: Read-only DateTime obj of the last change.
*
* @return array List of caldav properties, with expanded 'pass' element. Original array is modified too.
* url: Absolute calendar URL or relative event URL.
* tag: Calendar ctag or event etag.
* user: Authentication user in case of calendar obj.
* username: Authentication user in case of calendar obj.
* pass: Authentication password in case of calendar obj.
* last_change: Read-only DateTime obj of the last change.
*
......@@ -329,7 +330,7 @@ class caldav_driver extends database_driver
* Auto discover calenders available to the user on the caldav server
* @param array $props
* url: Absolute URL to calendar server
* user: Username
* username: Username
* pass: Password
* @return False on error or an array with the following calendar props:
* name: Calendar display name
......@@ -343,7 +344,7 @@ class caldav_driver extends database_driver
$cal_attribs = array('{DAV:}resourcetype', '{DAV:}displayname');
require_once ($this->cal->home.'/lib/caldav-client.php');
$caldav = new caldav_client($props["url"], $props["user"], $props["pass"]);
$caldav = new caldav_client($props["url"], $props["username"], $props["pass"]);
$tokens = parse_url($props["url"]);
$base_uri = $tokens['scheme']."://".$tokens['host'].($tokens['port'] ? ":".$tokens['port'] : null);
......@@ -476,7 +477,7 @@ class caldav_driver extends database_driver
$formfields["caldav_user"] = array(
"label" => $this->cal->gettext("username"),
"value" => $input_caldav_user->show($props["user"]),
"value" => $input_caldav_user->show($props["username"]),
"id" => "caldav_user",
);
......@@ -505,7 +506,7 @@ class caldav_driver extends database_driver
$result = false;
$props = $prop;
$props['url'] = self::_encode_url($prop["caldav_url"]);
$props['user'] = $prop["caldav_user"];
$props['username'] = $prop["caldav_user"];
$props['pass'] = $prop["caldav_pass"];
if(!isset($props['color'])) $props['color'] = 'cc0000';
$pwd_expanded_props = $props;
......@@ -568,7 +569,7 @@ class caldav_driver extends database_driver
return $this->_set_caldav_props($prop["id"], self::OBJ_TYPE_VCAL, array(
"url" => self::_encode_url($prop["caldav_url"]),
"user" => $prop["caldav_user"],
"username" => $prop["caldav_user"],
"pass" => $prop["caldav_pass"]
));
}
......@@ -742,6 +743,23 @@ class caldav_driver extends database_driver
self::debug_log("Successfully synced calendar id \"$cal_id\".");
}
/**
* Returns db-specific timestamp queries for epoch format
*
* @param str column name or valid timestamp (e.g. NOW())
* @return str db-specific timestamp query for epoch format
*/
private function unixtimestamp($field)
{
$rcmail = rcmail::get_instance();
switch ($rcmail->db->db_provider) {
case 'postgres':
return "EXTRACT (EPOCH FROM $field)";
default:
return "UNIX_TIMESTAMP($field)";
}
}
/**
* Synchronizes events and loads them.
......
......@@ -31,7 +31,7 @@ class caldav_sync
private $cal_id = null;
private $ctag = null;
private $user = null;
private $username = null;
private $pass = null;
private $url = null;
......@@ -52,10 +52,10 @@ class caldav_sync
$this->url = $props["url"];
$this->ctag = isset($props["tag"]) ? $props["tag"] : null;
$this->user = isset($props["user"]) ? $props["user"] : null;
$this->username = isset($props["username"]) ? $props["username"] : null;
$this->pass = isset($props["pass"]) ? $props["pass"] : null;
$this->caldav = new caldav_client($this->url, $this->user, $this->pass);
$this->caldav = new caldav_client($this->url, $this->username, $this->pass);
}
/**
......@@ -255,4 +255,4 @@ class caldav_sync
return $this->caldav->remove_event($props["url"]);
}
};
?>
\ No newline at end of file
?>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment