mirror of
https://github.com/writefreely/writefreely
synced 2025-02-17 16:28:23 +00:00
SQLite support added.
This commit is contained in:
parent
dd5f6870d8
commit
6cb86214d7
5 changed files with 245 additions and 13 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,3 +4,4 @@
|
|||
|
||||
build
|
||||
config.ini
|
||||
writefreely.db
|
16
app.go
16
app.go
|
@ -256,9 +256,15 @@ func Serve() {
|
|||
connectToDatabase(app)
|
||||
defer shutdown(app)
|
||||
|
||||
schema, err := ioutil.ReadFile("schema.sql")
|
||||
schemaFileName := "schema.sql"
|
||||
|
||||
if cfg.Database.Type == "sqlite3" {
|
||||
schemaFileName = "sqlite.sql"
|
||||
}
|
||||
|
||||
schema, err := ioutil.ReadFile(schemaFileName)
|
||||
if err != nil {
|
||||
log.Error("Unable to load schema.sql: %v", err)
|
||||
log.Error("Unable to load schema file: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
@ -438,15 +444,15 @@ func connectToDatabase(app *app) {
|
|||
log.Error("%s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
app.db = &datastore{db}
|
||||
app.db = &datastore{db, "mysql"}
|
||||
app.db.SetMaxOpenConns(50)
|
||||
} else if app.cfg.Database.Type == "sqlite3" {
|
||||
db, err := sql.Open("sqlite3", "./writefreely.db")
|
||||
db, err := sql.Open("sqlite3", "./writefreely.db?parseTime=true")
|
||||
if err != nil {
|
||||
log.Error("%s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
app.db = &datastore{db}
|
||||
app.db = &datastore{db, "sqlite3"}
|
||||
app.db.SetMaxOpenConns(50)
|
||||
} else {
|
||||
log.Error("Invalid database type '%s'. Only 'mysql' and 'sqlite3' are supported right now.", app.cfg.Database.Type)
|
||||
|
|
46
database.go
46
database.go
|
@ -100,6 +100,7 @@ type writestore interface {
|
|||
|
||||
type datastore struct {
|
||||
*sql.DB
|
||||
driverName string
|
||||
}
|
||||
|
||||
func (db *datastore) CreateUser(u *User, collectionTitle string) error {
|
||||
|
@ -115,7 +116,7 @@ func (db *datastore) CreateUser(u *User, collectionTitle string) error {
|
|||
|
||||
// 1. Add to `users` table
|
||||
// NOTE: Assumes User's Password is already hashed!
|
||||
res, err := t.Exec("INSERT INTO users (username, password, email, created) VALUES (?, ?, ?, NOW())", u.Username, u.HashedPass, u.Email)
|
||||
res, err := t.Exec("INSERT INTO users (username, password, email) VALUES (?, ?, ?)", u.Username, u.HashedPass, u.Email)
|
||||
if err != nil {
|
||||
t.Rollback()
|
||||
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
|
||||
|
@ -478,7 +479,7 @@ func (db *datastore) GetTemporaryOneTimeAccessToken(userID int64, validSecs int,
|
|||
expirationVal = fmt.Sprintf("DATE_ADD(NOW(), INTERVAL %d SECOND)", validSecs)
|
||||
}
|
||||
|
||||
_, err = db.Exec("INSERT INTO accesstokens (token, user_id, created, one_time, expires) VALUES (?, ?, NOW(), ?, "+expirationVal+")", string(binTok), userID, oneTime)
|
||||
_, err = db.Exec("INSERT INTO accesstokens (token, user_id, one_time, expires) VALUES (?, ?, ?, "+expirationVal+")", string(binTok), userID, oneTime)
|
||||
if err != nil {
|
||||
log.Error("Couldn't INSERT accesstoken: %v", err)
|
||||
return "", err
|
||||
|
@ -571,7 +572,12 @@ func (db *datastore) CreatePost(userID, collID int64, post *SubmittedPost) (*Pos
|
|||
}
|
||||
}
|
||||
|
||||
stmt, err := db.Prepare("INSERT INTO posts (id, slug, title, content, text_appearance, language, rtl, privacy, owner_id, collection_id, created, updated, view_count) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), ?)")
|
||||
timeFunction := "NOW()"
|
||||
if db.driverName == "sqlite3" {
|
||||
timeFunction = "strftime('%Y-%m-%d %H-%M-%S','now')"
|
||||
}
|
||||
|
||||
stmt, err := db.Prepare("INSERT INTO posts (id, slug, title, content, text_appearance, language, rtl, privacy, owner_id, collection_id, created, updated, view_count) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + timeFunction + ", ?)")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -668,7 +674,13 @@ func (db *datastore) UpdateOwnedPost(post *AuthenticatedPost, userID int64) erro
|
|||
return ErrPostNoUpdatableVals
|
||||
}
|
||||
|
||||
queryUpdates += sep + "updated = NOW()"
|
||||
timeFunction := "NOW()"
|
||||
|
||||
if db.driverName == "sqlite3" {
|
||||
timeFunction = "strftime('%Y-%m-%d %H-%M-%S','now')"
|
||||
}
|
||||
|
||||
queryUpdates += sep + "updated = " + timeFunction
|
||||
|
||||
res, err := db.Exec("UPDATE posts SET "+queryUpdates+" WHERE id = ? AND "+authCondition, params...)
|
||||
if err != nil {
|
||||
|
@ -984,6 +996,10 @@ func (db *datastore) GetPostsCount(c *CollectionObj, includeFuture bool) {
|
|||
timeCondition := ""
|
||||
if !includeFuture {
|
||||
timeCondition = "AND created <= NOW()"
|
||||
|
||||
if db.driverName == "sqlite3" {
|
||||
timeCondition = "AND created <= strftime('%Y-%m-%d %H-%M-%S','now')"
|
||||
}
|
||||
}
|
||||
err := db.QueryRow("SELECT COUNT(*) FROM posts WHERE collection_id = ? AND pinned_position IS NULL "+timeCondition, c.ID).Scan(&count)
|
||||
switch {
|
||||
|
@ -1023,6 +1039,10 @@ func (db *datastore) GetPosts(c *Collection, page int, includeFuture, forceRecen
|
|||
timeCondition := ""
|
||||
if !includeFuture {
|
||||
timeCondition = "AND created <= NOW()"
|
||||
|
||||
if db.driverName == "sqlite3" {
|
||||
timeCondition = "AND created <= strftime('%Y-%m-%d %H-%M-%S','now')"
|
||||
}
|
||||
}
|
||||
rows, err := db.Query("SELECT "+postCols+" FROM posts WHERE collection_id = ? AND pinned_position IS NULL "+timeCondition+" ORDER BY created "+order+limitStr, collID)
|
||||
if err != nil {
|
||||
|
@ -1080,6 +1100,10 @@ func (db *datastore) GetPostsTagged(c *Collection, tag string, page int, include
|
|||
timeCondition := ""
|
||||
if !includeFuture {
|
||||
timeCondition = "AND created <= NOW()"
|
||||
|
||||
if db.driverName == "sqlite3" {
|
||||
timeCondition = "AND created <= strftime('%Y-%m-%d %H-%M-%S','now')"
|
||||
}
|
||||
}
|
||||
rows, err := db.Query("SELECT "+postCols+" FROM posts WHERE collection_id = ? AND LOWER(content) RLIKE ? "+timeCondition+" ORDER BY created "+order+limitStr, collID, "#"+strings.ToLower(tag)+"[[:>:]]")
|
||||
if err != nil {
|
||||
|
@ -1455,7 +1479,11 @@ func (db *datastore) GetLastPinnedPostPos(collID int64) int64 {
|
|||
}
|
||||
|
||||
func (db *datastore) GetPinnedPosts(coll *CollectionObj) (*[]PublicPost, error) {
|
||||
rows, err := db.Query("SELECT id, slug, title, LEFT(content, 80), pinned_position FROM posts WHERE collection_id = ? AND pinned_position IS NOT NULL ORDER BY pinned_position ASC", coll.ID)
|
||||
clipFunction := "LEFT"
|
||||
if db.driverName == "sqlite3" {
|
||||
clipFunction = "SUBSTR"
|
||||
}
|
||||
rows, err := db.Query("SELECT id, slug, title, "+clipFunction+"(content, 80), pinned_position FROM posts WHERE collection_id = ? AND pinned_position IS NOT NULL ORDER BY pinned_position ASC", coll.ID)
|
||||
if err != nil {
|
||||
log.Error("Failed selecting pinned posts: %v", err)
|
||||
return nil, impart.HTTPError{http.StatusInternalServerError, "Couldn't retrieve pinned posts."}
|
||||
|
@ -2141,7 +2169,13 @@ func (db *datastore) GetDynamicContent(id string) (string, *time.Time, error) {
|
|||
}
|
||||
|
||||
func (db *datastore) UpdateDynamicContent(id, content string) error {
|
||||
_, err := db.Exec("INSERT INTO appcontent (id, content, updated) VALUES (?, ?, NOW()) ON DUPLICATE KEY UPDATE content = ?, updated = NOW()", id, content, content)
|
||||
timeFunction := "NOW()"
|
||||
|
||||
if db.driverName == "sqlite3" {
|
||||
timeFunction = "strftime('%Y-%m-%d %H-%M-%S','now')"
|
||||
}
|
||||
|
||||
_, err := db.Exec("INSERT INTO appcontent (id, content, updated) VALUES (?, ?, "+timeFunction+") ON DUPLICATE KEY UPDATE content = ?, updated = "+timeFunction, id, content, content)
|
||||
if err != nil {
|
||||
log.Error("Unable to INSERT appcontent for '%s': %v", id, err)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ CREATE TABLE IF NOT EXISTS `accesstokens` (
|
|||
`user_id` int(6) NOT NULL,
|
||||
`sudo` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`one_time` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`created` datetime NOT NULL,
|
||||
`created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`expires` datetime DEFAULT NULL,
|
||||
`user_agent` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`token`)
|
||||
|
@ -197,7 +197,7 @@ CREATE TABLE IF NOT EXISTS `users` (
|
|||
`username` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
|
||||
`password` char(60) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
|
||||
`email` varbinary(255) DEFAULT NULL,
|
||||
`created` datetime NOT NULL,
|
||||
`created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `username` (`username`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
|
191
sqlite.sql
Normal file
191
sqlite.sql
Normal file
|
@ -0,0 +1,191 @@
|
|||
--
|
||||
-- Database: writefreely
|
||||
--
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table accesstokens
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS accesstokens (
|
||||
token TEXT NOT NULL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL,
|
||||
sudo INTEGER NOT NULL DEFAULT '0',
|
||||
one_time INTEGER NOT NULL DEFAULT '0',
|
||||
created DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
expires DATETIME DEFAULT NULL,
|
||||
user_agent TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table appcontent
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS appcontent (
|
||||
id TEXT NOT NULL PRIMARY KEY,
|
||||
content TEXT NOT NULL,
|
||||
updated DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table collectionattributes
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS collectionattributes (
|
||||
collection_id INTEGER NOT NULL,
|
||||
attribute TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
PRIMARY KEY (collection_id, attribute)
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table collectionkeys
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS collectionkeys (
|
||||
collection_id INTEGER PRIMARY KEY,
|
||||
public_key blob NOT NULL,
|
||||
private_key blob NOT NULL
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table collectionpasswords
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS collectionpasswords (
|
||||
collection_id INTEGER PRIMARY KEY,
|
||||
password TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table collectionredirects
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS collectionredirects (
|
||||
prev_alias TEXT NOT NULL PRIMARY KEY,
|
||||
new_alias TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table collections
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS collections (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
alias TEXT DEFAULT NULL UNIQUE,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
style_sheet TEXT,
|
||||
script TEXT,
|
||||
format TEXT DEFAULT NULL,
|
||||
privacy INTEGER NOT NULL,
|
||||
owner_id INTEGER NOT NULL,
|
||||
view_count INTEGER NOT NULL
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table posts
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS posts (
|
||||
id TEXT NOT NULL,
|
||||
slug TEXT DEFAULT NULL,
|
||||
modify_token TEXT DEFAULT NULL,
|
||||
text_appearance TEXT NOT NULL DEFAULT 'norm',
|
||||
language TEXT DEFAULT NULL,
|
||||
rtl INTEGER DEFAULT NULL,
|
||||
privacy INTEGER NOT NULL,
|
||||
owner_id INTEGER DEFAULT NULL,
|
||||
collection_id INTEGER DEFAULT NULL,
|
||||
pinned_position INTEGER UNSIGNED DEFAULT NULL,
|
||||
created DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
view_count INTEGER NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
CONSTRAINT id_slug UNIQUE (collection_id, slug),
|
||||
CONSTRAINT owner_id UNIQUE (owner_id, id),
|
||||
CONSTRAINT privacy_id UNIQUE (privacy, id)
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table remotefollows
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS remotefollows (
|
||||
collection_id INTEGER NOT NULL,
|
||||
remote_user_id INTEGER NOT NULL,
|
||||
created DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (collection_id,remote_user_id)
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table remoteuserkeys
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS remoteuserkeys (
|
||||
id TEXT NOT NULL,
|
||||
remote_user_id INTEGER NOT NULL,
|
||||
public_key blob NOT NULL,
|
||||
CONSTRAINT follower_id UNIQUE (remote_user_id)
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table remoteusers
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS remoteusers (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
actor_id TEXT NOT NULL,
|
||||
inbox TEXT NOT NULL,
|
||||
shared_inbox TEXT NOT NULL,
|
||||
CONSTRAINT collection_id UNIQUE (actor_id)
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table userattributes
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS userattributes (
|
||||
user_id INTEGER NOT NULL,
|
||||
attribute TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
PRIMARY KEY (user_id, attribute)
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table users
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
password TEXT NOT NULL,
|
||||
email TEXT DEFAULT NULL,
|
||||
created DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
Loading…
Add table
Reference in a new issue