Merge branch 'master' of git://github.com/cristen/Radicale into cristen-master
Conflicts: radicale/storage/database.py schema.sql
This commit is contained in:
commit
fae2b30ec4
4
config
4
config
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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"},
|
||||||
|
@ -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)
|
||||||
|
39
schema.sql
39
schema.sql
@ -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));
|
||||||
|
Loading…
Reference in New Issue
Block a user