Merge branch 'master' of git://github.com/cristen/Radicale into cristen-master

Conflicts:
	radicale/storage/database.py
	schema.sql
This commit is contained in:
Guillaume Ayoub 2013-12-17 14:42:20 +01:00
commit fae2b30ec4
5 changed files with 65 additions and 48 deletions

4
config
View File

@ -25,6 +25,10 @@ ssl = False
certificate = /etc/apache2/ssl/server.crt certificate = /etc/apache2/ssl/server.crt
# SSL private key # SSL private key
key = /etc/apache2/ssl/server.key key = /etc/apache2/ssl/server.key
# SSL Protocol used. See python's ssl module for available values
protocol = PROTOCOL_SSLv23
# Ciphers available. See python's ssl module for available ciphers
ciphers =
# Reverse DNS to resolve client address in logs # Reverse DNS to resolve client address in logs
dns_lookup = True dns_lookup = True
# Root URL of Radicale (starting and ending with a slash) # Root URL of Radicale (starting and ending with a slash)

View File

@ -98,7 +98,9 @@ class HTTPSServer(HTTPServer):
server_side=True, server_side=True,
certfile=config.get("server", "certificate"), certfile=config.get("server", "certificate"),
keyfile=config.get("server", "key"), keyfile=config.get("server", "key"),
ssl_version=ssl.PROTOCOL_SSLv23) ssl_version=getattr(ssl, config.get("server", "protocol"),
ssl.PROTOCOL_SSLv23),
ciphers=config.get("server", "ciphers") or None)
self.server_bind() self.server_bind()
self.server_activate() self.server_activate()

View File

@ -45,6 +45,8 @@ INITIAL_CONFIG = {
"ssl": "False", "ssl": "False",
"certificate": "/etc/apache2/ssl/server.crt", "certificate": "/etc/apache2/ssl/server.crt",
"key": "/etc/apache2/ssl/server.key", "key": "/etc/apache2/ssl/server.key",
"protocol": "PROTOCOL_SSLv23",
"ciphers": "",
"dns_lookup": "True", "dns_lookup": "True",
"base_prefix": "/", "base_prefix": "/",
"realm": "Radicale - Password Required"}, "realm": "Radicale - Password Required"},

View File

@ -24,7 +24,7 @@ SQLAlchemy storage backend.
import time import time
from datetime import datetime from datetime import datetime
from contextlib import contextmanager from contextlib import contextmanager
from sqlalchemy import create_engine, Column, String, DateTime, ForeignKey from sqlalchemy import create_engine, Column, Unicode, Integer, ForeignKey
from sqlalchemy import func from sqlalchemy import func
from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
@ -44,17 +44,20 @@ class DBCollection(Base):
"""Table of collections.""" """Table of collections."""
__tablename__ = "collection" __tablename__ = "collection"
path = Column(String, primary_key=True) path = Column(Unicode, primary_key=True)
parent_path = Column(String) parent_path = Column(Unicode, ForeignKey("collection.path"))
parent = relationship(
"DBCollection", backref="children", remote_side=[path])
class DBItem(Base): class DBItem(Base):
"""Table of collection's items.""" """Table of collection's items."""
__tablename__ = "item" __tablename__ = "item"
name = Column(String, primary_key=True) name = Column(Unicode, primary_key=True)
tag = Column(String) tag = Column(Unicode)
collection_path = Column(String, ForeignKey("collection.path")) collection_path = Column(Unicode, ForeignKey("collection.path"))
collection = relationship("DBCollection", backref="items") collection = relationship("DBCollection", backref="items")
@ -63,10 +66,10 @@ class DBHeader(Base):
"""Table of item's headers.""" """Table of item's headers."""
__tablename__ = "header" __tablename__ = "header"
key = Column(String, primary_key=True) name = Column(Unicode, primary_key=True)
value = Column(String) value = Column(Unicode)
collection_path = Column( collection_path = Column(
String, ForeignKey("collection.path"), primary_key=True) Unicode, ForeignKey("collection.path"), primary_key=True)
collection = relationship("DBCollection", backref="headers") collection = relationship("DBCollection", backref="headers")
@ -75,23 +78,23 @@ class DBLine(Base):
"""Table of item's lines.""" """Table of item's lines."""
__tablename__ = "line" __tablename__ = "line"
key = Column(String) name = Column(Unicode)
value = Column(String) value = Column(Unicode)
item_name = Column(String, ForeignKey("item.name")) item_name = Column(Unicode, ForeignKey("item.name"))
timestamp = Column(DateTime, default=datetime.now, primary_key=True) timestamp = Column(
Integer, default=lambda: time.time() * 10 ** 6, primary_key=True)
item = relationship( item = relationship("DBItem", backref="lines", order_by=timestamp)
"DBItem", backref="lines", order_by=timestamp)
class DBProperty(Base): class DBProperty(Base):
"""Table of collection's properties.""" """Table of collection's properties."""
__tablename__ = "property" __tablename__ = "property"
key = Column(String, primary_key=True) name = Column(Unicode, primary_key=True)
value = Column(String) value = Column(Unicode)
collection_path = Column( collection_path = Column(
String, ForeignKey("collection.path"), primary_key=True) Unicode, ForeignKey("collection.path"), primary_key=True)
collection = relationship( collection = relationship(
"DBCollection", backref="properties", cascade="delete") "DBCollection", backref="properties", cascade="delete")
@ -116,17 +119,20 @@ class Collection(ical.Collection):
.order_by(DBItem.name).all()) .order_by(DBItem.name).all())
for item in items: for item in items:
text = "\n".join( text = "\n".join(
"%s:%s" % (line.key, line.value) for line in item.lines) "%s:%s" % (line.name, line.value) for line in item.lines)
item_objects.append(item_type(text, item.name)) item_objects.append(item_type(text, item.name))
return item_objects return item_objects
@property @property
def _modification_time(self): def _modification_time(self):
"""Collection's last modification time.""" """Collection's last modification time."""
return ( timestamp = (
self.session.query(func.max(DBLine.timestamp)) self.session.query(func.max(DBLine.timestamp))
.join(DBItem).filter_by(collection_path=self.path).first()[0] .join(DBItem).filter_by(collection_path=self.path).first()[0])
or datetime.now()) if timestamp:
return datetime.fromtimestamp(float(timestamp) / 10 ** 6)
else:
return datetime.now()
@property @property
def _db_collection(self): def _db_collection(self):
@ -154,7 +160,7 @@ class Collection(ical.Collection):
for header in headers: for header in headers:
db_header = DBHeader() db_header = DBHeader()
db_header.key, db_header.value = header.text.split(":", 1) db_header.name, db_header.value = header.text.split(":", 1)
db_header.collection_path = self.path db_header.collection_path = self.path
self.session.add(db_header) self.session.add(db_header)
@ -167,7 +173,7 @@ class Collection(ical.Collection):
for line in ical.unfold(item.text): for line in ical.unfold(item.text):
db_line = DBLine() db_line = DBLine()
db_line.key, db_line.value = line.split(":", 1) db_line.name, db_line.value = line.split(":", 1)
db_line.item_name = item.name db_line.item_name = item.name
self.session.add(db_line) self.session.add(db_line)
@ -187,9 +193,9 @@ class Collection(ical.Collection):
headers = ( headers = (
self.session.query(DBHeader) self.session.query(DBHeader)
.filter_by(collection_path=self.path) .filter_by(collection_path=self.path)
.order_by(DBHeader.key).all()) .order_by(DBHeader.name).all())
return [ return [
ical.Header("%s:%s" % (header.key, header.value)) ical.Header("%s:%s" % (header.name, header.value))
for header in headers] for header in headers]
@classmethod @classmethod
@ -238,16 +244,16 @@ class Collection(ical.Collection):
self.session.query(DBProperty) self.session.query(DBProperty)
.filter_by(collection_path=self.path).all()) .filter_by(collection_path=self.path).all())
for prop in db_properties: for prop in db_properties:
properties[prop.key] = prop.value properties[prop.name] = prop.value
old_properties = properties.copy() old_properties = properties.copy()
yield properties yield properties
# On exit # On exit
if self._db_collection and old_properties != properties: if self._db_collection and old_properties != properties:
for prop in db_properties: for prop in db_properties:
self.session.delete(prop) self.session.delete(prop)
for key, value in properties.items(): for name, value in properties.items():
prop = DBProperty() prop = DBProperty()
prop.key = key prop.name = name
prop.value = value prop.value = value
prop.collection_path = self.path prop.collection_path = self.path
self.session.add(prop) self.session.add(prop)

View File

@ -1,28 +1,31 @@
-- This is the database schema for PostgreSQL. -- This is the database schema for PostgreSQL and MySQL and SQLite.
create table collection ( create table collection (
path varchar primary key not null, path varchar(200) not null,
parent_path varchar not null); parent_path varchar(200) references collection (path),
primary key (path));
create table item ( create table item (
name varchar primary key not null, name varchar(200) not null,
tag varchar not null, tag text not null,
collection_path varchar references collection (path) not null); collection_path varchar(200) references collection (path),
primary key (name));
create table header ( create table header (
key varchar not null, name varchar(200) not null,
value varchar not null, value text not null,
collection_path varchar references collection (path) not null, collection_path varchar(200) references collection (path),
primary key (key, collection_path)); primary key (name, collection_path));
create table line ( create table line (
key varchar not null, name text not null,
value varchar not null, value text not null,
item_name varchar references item (name) not null, item_name varchar(200) references item (name),
timestamp timestamp not null); timestamp bigint not null,
primary key (timestamp));
create table property ( create table property (
key varchar not null, name varchar(200) not null,
value varchar not null, value text not null,
collection_path varchar references collection (path) not null, collection_path varchar(200) references collection (path),
primary key (key, collection_path)); primary key (name, collection_path));