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:
parent
3d1919287b
commit
9d4a33218f
|
@ -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": "",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
|
@ -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="(.*?)"' )
|
||||
|
|
|
@ -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__":
|
||||
|
|
Reference in New Issue