witten
/
luminotes
Archived
1
0
Fork 0

Updated Database.py, initdb.py, and updatedb.py to support local SQLite database. Still need other changes in model/*.py though.

This commit is contained in:
Dan Helfman 2008-08-15 17:27:03 -07:00
parent 3d1919287b
commit 9d4a33218f
7 changed files with 341 additions and 37 deletions

View File

@ -22,7 +22,7 @@ settings = {
"luminotes.https_url": "",
"luminotes.http_proxy_ip": "127.0.0.1",
"luminotes.https_proxy_ip": "127.0.0.2",
"luminotes.db_host": "localhost",
"luminotes.db_host": "localhost", # hostname for PostgreSQL or None (no quotes) for SQLite
"luminotes.db_ssl_mode": "allow", # "disallow", "allow", "prefer", or "require"
"luminotes.support_email": "",
"luminotes.payment_email": "",

View File

@ -6,8 +6,9 @@ settings = {
"global": {
"server.thread_pool": 1,
"static_filter.root": os.getcwd(),
"server.log_to_screen": False,
"server.log_to_screen": True,
"luminotes.launch_browser": True,
"luminotes.db_host": None, # use local SQLite database
},
"/static": {
"static_filter.on": True,

View File

@ -2,8 +2,6 @@ import re
import os
import sha
import cherrypy
import psycopg2 as psycopg
from psycopg2.pool import PersistentConnectionPool
import random
from model.Persistent import Persistent
from model.Notebook import Notebook
@ -33,6 +31,11 @@ class Database( object ):
@param connection: database connection to use (optional, defaults to making a connection pool)
@type cache: cmemcache.Client or something with a similar API, or NoneType
@param cache: existing memory cache to use (optional, defaults to making a cache)
@type host: unicode or NoneType
@param host: hostname of PostgreSQL database, or None to use a local SQLite database
@type ssl_mode: unicode
@param ssl_mode: SSL mode for the database connection, one of "disallow", "allow", "prefer", or
"require". ignored if host is None
@rtype: Database
@return: newly constructed Database
"""
@ -40,29 +43,39 @@ class Database( object ):
# makes SQLite angry.
os.putenv( "PGTZ", "UTC" )
# forcibly replace psycopg's connect() function with another function that returns the psycopg
# connection wrapped in a class with a pending_saves member, used in save() and commit() below
original_connect = psycopg.connect
if host is None:
from pysqlite2 import dbapi2 as sqlite
def connect( *args, **kwargs ):
return Connection_wrapper( original_connect( *args, **kwargs ) )
psycopg.connect = connect
if connection:
self.__connection = connection
self.__connection = connection or \
Connection_wrapper( sqlite.connect( "luminotes.db", detect_types = 0 ) )
self.__pool = None
else:
self.__connection = None
self.__pool = PersistentConnectionPool(
1, # minimum connections
50, # maximum connections
"host=%s sslmode=%s dbname=luminotes user=luminotes password=%s" % (
host or "localhost",
ssl_mode or "allow",
os.getenv( "PGPASSWORD", "dev" )
),
)
import psycopg2 as psycopg
from psycopg2.pool import PersistentConnectionPool
# forcibly replace psycopg's connect() function with another function that returns the psycopg
# connection wrapped in a class with a pending_saves member, used in save() and commit() below
original_connect = psycopg.connect
def connect( *args, **kwargs ):
return Connection_wrapper( original_connect( *args, **kwargs ) )
psycopg.connect = connect
if connection:
self.__connection = connection
self.__pool = None
else:
self.__connection = None
self.__pool = PersistentConnectionPool(
1, # minimum connections
50, # maximum connections
"host=%s sslmode=%s dbname=luminotes user=luminotes password=%s" % (
host or "localhost",
ssl_mode or "allow",
os.getenv( "PGPASSWORD", "dev" )
),
)
self.__cache = cache
@ -266,6 +279,23 @@ class Database( object ):
if commit:
connection.commit()
def execute_script( self, sql_commands, commit = True ):
"""
Execute the given sql_commands.
@type sql_command: unicode
@param sql_command: multiple SQL commands to execute
@type commit: bool
@param commit: True to automatically commit after the command
"""
connection = self.__get_connection()
cursor = connection.cursor()
cursor.executescript( sql_commands )
if commit:
connection.commit()
def uncache_command( self, sql_command ):
cache = self.__get_cache_connection()
if not cache: return

View File

@ -17,10 +17,10 @@ SOCKET_TIMEOUT_SECONDS = 60
def main( args ):
cherrypy.config.update( Common.settings )
if len( args ) > 0 and args[ 0 ] == "-d":
if args and "-d" in args:
from config import Development
settings = Development.settings
elif len( args ) > 0 and args[ 0 ] == "-l":
if args and "-l" in args:
from config import Desktop
settings = Desktop.settings
else:

229
model/schema.sqlite Normal file
View File

@ -0,0 +1,229 @@
--
-- Name: file; Type: TABLE; Schema: public; Owner: luminotes; Tablespace:
--
CREATE TABLE file (
id text NOT NULL,
revision timestamp with time zone,
notebook_id text,
note_id text,
filename text,
size_bytes integer,
content_type text
);
--
-- Name: invite; Type: TABLE; Schema: public; Owner: luminotes; Tablespace:
--
CREATE TABLE invite (
id text NOT NULL,
revision timestamp with time zone NOT NULL,
from_user_id text,
notebook_id text,
email_address text,
read_write boolean,
"owner" boolean,
redeemed_user_id text
);
--
-- Name: luminotes_group; Type: TABLE; Schema: public; Owner: luminotes; Tablespace:
--
CREATE TABLE luminotes_group (
id text NOT NULL,
revision timestamp with time zone NOT NULL,
name text
);
--
-- Name: luminotes_group_current; Type: VIEW; Schema: public; Owner: luminotes
--
CREATE VIEW luminotes_group_current AS
SELECT id, revision, name FROM luminotes_group WHERE (luminotes_group.revision IN (SELECT max(sub_group.revision) AS max FROM luminotes_group sub_group WHERE (sub_group.id = luminotes_group.id)));
--
-- Name: luminotes_user; Type: TABLE; Schema: public; Owner: luminotes; Tablespace:
--
CREATE TABLE luminotes_user (
id text NOT NULL,
revision timestamp with time zone NOT NULL,
username text,
salt text,
password_hash text,
email_address text,
storage_bytes integer,
rate_plan integer
);
--
-- Name: luminotes_user_current; Type: VIEW; Schema: public; Owner: luminotes
--
CREATE VIEW luminotes_user_current AS
SELECT id, revision, username, salt, password_hash, email_address, storage_bytes, rate_plan FROM luminotes_user WHERE (luminotes_user.revision IN (SELECT max(sub_user.revision) AS max FROM luminotes_user sub_user WHERE (sub_user.id = luminotes_user.id)));
--
-- Name: note; Type: TABLE; Schema: public; Owner: luminotes; Tablespace:
--
CREATE TABLE note (
id text NOT NULL,
revision timestamp with time zone NOT NULL,
title text,
contents text,
notebook_id text,
startup boolean DEFAULT false,
deleted_from_id text,
rank numeric,
search tsvector,
user_id text
);
--
-- Name: note_current; Type: VIEW; Schema: public; Owner: luminotes
--
CREATE VIEW note_current AS
SELECT id, revision, title, contents, notebook_id, startup, deleted_from_id, rank, search, user_id FROM note WHERE (note.revision IN (SELECT max(sub_note.revision) AS max FROM note sub_note WHERE (sub_note.id = note.id)));
--
-- Name: notebook; Type: TABLE; Schema: public; Owner: luminotes; Tablespace:
--
CREATE TABLE notebook (
id text NOT NULL,
revision timestamp with time zone NOT NULL,
name text,
trash_id text,
deleted boolean DEFAULT false,
user_id text
);
--
-- Name: notebook_current; Type: VIEW; Schema: public; Owner: luminotes
--
CREATE VIEW notebook_current AS
SELECT id, revision, name, trash_id, deleted, user_id FROM notebook WHERE (notebook.revision IN (SELECT max(sub_notebook.revision) AS max FROM notebook sub_notebook WHERE (sub_notebook.id = notebook.id)));
--
-- Name: password_reset; Type: TABLE; Schema: public; Owner: luminotes; Tablespace:
--
CREATE TABLE password_reset (
id text NOT NULL,
revision timestamp with time zone NOT NULL,
email_address text,
redeemed boolean
);
--
-- Name: user_group; Type: TABLE; Schema: public; Owner: luminotes; Tablespace:
--
CREATE TABLE user_group (
user_id text NOT NULL,
group_id text NOT NULL,
"admin" boolean DEFAULT false
);
--
-- Name: user_notebook; Type: TABLE; Schema: public; Owner: luminotes; Tablespace:
--
CREATE TABLE user_notebook (
user_id text NOT NULL,
notebook_id text NOT NULL,
read_write boolean DEFAULT false,
"owner" boolean DEFAULT false,
rank numeric
);
--
-- Name: file_note_id_index; Type: INDEX; Schema: public; Owner: luminotes; Tablespace:
--
CREATE INDEX file_note_id_index ON file (note_id);
--
-- Name: file_notebook_id_index; Type: INDEX; Schema: public; Owner: luminotes; Tablespace:
--
CREATE INDEX file_notebook_id_index ON file (notebook_id);
--
-- Name: luminotes_group_pkey; Type: INDEX; Schema: public; Owner: luminotes; Tablespace:
--
CREATE INDEX luminotes_group_pkey ON luminotes_group (id, revision);
--
-- Name: luminotes_user_email_address_index; Type: INDEX; Schema: public; Owner: luminotes; Tablespace:
--
CREATE INDEX luminotes_user_email_address_index ON luminotes_user (email_address);
--
-- Name: luminotes_user_username_index; Type: INDEX; Schema: public; Owner: luminotes; Tablespace:
--
CREATE INDEX luminotes_user_username_index ON luminotes_user (username);
--
-- Name: note_notebook_id_index; Type: INDEX; Schema: public; Owner: luminotes; Tablespace:
--
CREATE INDEX note_notebook_id_index ON note (notebook_id);
--
-- Name: note_notebook_id_startup_index; Type: INDEX; Schema: public; Owner: luminotes; Tablespace:
--
CREATE INDEX note_notebook_id_startup_index ON note (notebook_id, startup);
--
-- Name: note_notebook_id_title_index; Type: INDEX; Schema: public; Owner: luminotes; Tablespace:
--
CREATE INDEX note_notebook_id_title_index ON note (notebook_id, title);
--
-- Name: password_reset_email_address_index; Type: INDEX; Schema: public; Owner: luminotes; Tablespace:
--
CREATE INDEX password_reset_email_address_index ON password_reset (email_address);
--
-- Name: search_index; Type: INDEX; Schema: public; Owner: luminotes; Tablespace:
--
CREATE INDEX search_index ON note (search);
-- vim: ft=sql

View File

@ -25,15 +25,19 @@ class Initializer( object ):
( u"enable JavaScript.html", False ),
]
def __init__( self, database, nuke = False ):
def __init__( self, database, host, settings, nuke = False ):
self.database = database
self.settings = settings
self.main_notebook = None
self.anonymous = None
if nuke is True:
self.database.execute( file( "model/drop.sql" ).read(), commit = False )
self.database.execute( file( "model/schema.sql" ).read(), commit = False )
if host:
self.database.execute( file( "model/schema.sql" ).read(), commit = False )
else:
self.database.execute_script( file( "model/schema.sqlite" ).read(), commit = False )
self.create_main_notebook()
self.create_anonymous_user()
@ -53,7 +57,7 @@ class Initializer( object ):
rank = 0
for ( filename, startup ) in self.NOTE_FILES:
full_filename = os.path.join( self.HTML_PATH, filename )
contents = fix_note_contents( file( full_filename ).read(), main_notebook_id, note_ids )
contents = fix_note_contents( file( full_filename ).read(), main_notebook_id, note_ids, self.settings )
if startup:
rank += 1
@ -74,6 +78,23 @@ class Initializer( object ):
def main( args = None ):
nuke = False
import cherrypy
from config import Common
cherrypy.config.update( Common.settings )
if args and "-d" in args:
from config import Development
settings = Development.settings
if args and "-l" in args:
from config import Desktop
settings = Desktop.settings
else:
from config import Production
settings = Production.settings
cherrypy.config.update( settings )
if args and ( "-n" in args or "--nuke" in args ):
nuke = True
print "This will nuke the contents of the database before initializing it with default data. Continue (y/n)? ",
@ -85,13 +106,16 @@ def main( args = None ):
return
print "Initializing the database with default data."
database = Database()
initializer = Initializer( database, nuke )
host = settings[ u"global" ].get( u"luminotes.db_host" )
database = Database(
host = host,
ssl_mode = settings[ u"global" ].get( u"luminotes.db_ssl_mode" ),
)
initializer = Initializer( database, host, settings, nuke )
def fix_note_contents( contents, notebook_id, note_ids ):
def fix_note_contents( contents, notebook_id, note_ids, settings ):
import re
from config.Common import settings
LINK_PATTERN = re.compile( '(<a\s+href=")([^"]+note_id=)([^"]*)("[^>]*>)(.*?)(</a>)' )
TITLE_PATTERN = re.compile( ' title="(.*?)"' )

View File

@ -26,8 +26,9 @@ class Updater( object ):
( u"enable JavaScript.html", False ),
]
def __init__( self, database ):
def __init__( self, database, settings ):
self.database = database
self.settings = settings
self.update_main_notebook()
self.database.commit()
@ -57,7 +58,7 @@ class Updater( object ):
def update_note( self, filename, startup, main_notebook, note_ids, note = None ):
full_filename = os.path.join( self.HTML_PATH, filename )
contents = fix_note_contents( file( full_filename ).read(), main_notebook.object_id, note_ids )
contents = fix_note_contents( file( full_filename ).read(), main_notebook.object_id, note_ids, self.settings )
if note:
if note.contents == contents:
@ -71,8 +72,27 @@ class Updater( object ):
self.database.save( note, commit = False )
def main( args ):
database = Database()
initializer = Updater( database )
import cherrypy
from config import Common
cherrypy.config.update( Common.settings )
if args and "-d" in args:
from config import Development
settings = Development.settings
if args and "-l" in args:
from config import Desktop
settings = Desktop.settings
else:
from config import Production
settings = Production.settings
cherrypy.config.update( settings )
database = Database(
host = settings[ u"global" ].get( u"luminotes.db_host" ),
ssl_mode = settings[ u"global" ].get( u"luminotes.db_ssl_mode" ),
)
initializer = Updater( database, settings )
if __name__ == "__main__":