| @@ -20,6 +20,7 @@ | |||||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| # SOFTWARE. | # SOFTWARE. | ||||
| from datetime import datetime | |||||
| from os import path | from os import path | ||||
| import sqlite3 as sqlite | import sqlite3 as sqlite | ||||
| from threading import Lock | from threading import Lock | ||||
| @@ -42,7 +43,6 @@ class Notes(Command): | |||||
| "read": self.do_read, | "read": self.do_read, | ||||
| "edit": self.do_edit, | "edit": self.do_edit, | ||||
| "info": self.do_info, | "info": self.do_info, | ||||
| "history": self.do_history, | |||||
| "rename": self.do_rename, | "rename": self.do_rename, | ||||
| "delete": self.do_delete, | "delete": self.do_delete, | ||||
| } | } | ||||
| @@ -58,15 +58,6 @@ class Notes(Command): | |||||
| else: | else: | ||||
| self.reply("Unknown subcommand: \x0303{0}\x0F.".format(command)) | self.reply("Unknown subcommand: \x0303{0}\x0F.".format(command)) | ||||
| def create_db(self, conn): | |||||
| """Initialize the notes database with its necessary tables.""" | |||||
| script = """ | |||||
| CREATE TABLE entries (entry_id, entry_slug, entry_title, entry_revision); | |||||
| CREATE TABLE users (user_id, user_host); | |||||
| CREATE TABLE revisions (rev_id, rev_entry, rev_user, rev_timestamp, rev_content); | |||||
| """ | |||||
| conn.executescript(script) | |||||
| def do_list(self, data): | def do_list(self, data): | ||||
| """Show a list of entries in the notes database.""" | """Show a list of entries in the notes database.""" | ||||
| query = "SELECT entry_title FROM entries" | query = "SELECT entry_title FROM entries" | ||||
| @@ -95,7 +86,7 @@ class Notes(Command): | |||||
| with sqlite.connect(self._dbfile) as conn, self._db_access_lock: | with sqlite.connect(self._dbfile) as conn, self._db_access_lock: | ||||
| try: | try: | ||||
| title, content = conn.execute(query, (slug,)).fetchone() | title, content = conn.execute(query, (slug,)).fetchone() | ||||
| except sqlite.OperationalError: | |||||
| except (sqlite.OperationalError, TypeError): | |||||
| title, content = slug, None | title, content = slug, None | ||||
| if content: | if content: | ||||
| @@ -105,22 +96,60 @@ class Notes(Command): | |||||
| def do_edit(self, data): | def do_edit(self, data): | ||||
| """Edit an entry in the notes database.""" | """Edit an entry in the notes database.""" | ||||
| pass | |||||
| query1 = """SELECT entry_id, entry_title, user_host FROM entries | |||||
| INNER JOIN revisions ON entry_revision = rev_id | |||||
| INNER JOIN users ON rev_user = user_id | |||||
| WHERE entry_slug = ?""" | |||||
| query2 = "INSERT INTO revisions VALUES (?, ?, ?, ?, ?)" | |||||
| query3 = "INSERT INTO entries VALUES (?, ?, ?, ?)" | |||||
| query4 = "UPDATE entries SET entry_revision = ? WHERE entry_id = ?" | |||||
| try: | |||||
| slug = data.args[1].lower().replace("_", "").replace("-", "") | |||||
| except IndexError: | |||||
| self.reply(data, "Please name an entry to edit.") | |||||
| return | |||||
| content = " ".join(data.args[2:]).strip() | |||||
| if not content: | |||||
| self.reply(data, "Please give some content to put in the entry.") | |||||
| return | |||||
| with sqlite.connect(self._dbfile) as conn, self._db_access_lock: | |||||
| create = True | |||||
| try: | |||||
| id_, title, author = conn.execute(query1, (slug,)).fetchone() | |||||
| create = False | |||||
| except sqlite.OperationalError: | |||||
| id_, title, author = 1, data.args[1], data.host | |||||
| self.create_db(conn) | |||||
| except TypeError: | |||||
| id_ = self.get_next_entry(conn) | |||||
| title, author = data.args[1], data.host | |||||
| permdb = self.config.irc["permissions"] | |||||
| if author != data.host and not permdb.is_admin(data): | |||||
| msg = "You must be an author or a bot admin to edit this entry." | |||||
| self.reply(data, msg) | |||||
| return | |||||
| revid = self.get_next_revision(conn) | |||||
| userid = self.get_user(conn, data.host) | |||||
| now = datetime.utcnow() | |||||
| conn.execute(query2, (revid, id_, userid, now, content)) | |||||
| if create: | |||||
| conn.execute(query3, (id_, slug, title, revid)) | |||||
| else: | |||||
| conn.execute(query4, (revid, id_)) | |||||
| self.reply(data, "Entry \x0302{0}\x0F updated.".format(title)) | |||||
| def do_info(self, data): | def do_info(self, data): | ||||
| """Get info on an entry in the notes database.""" | """Get info on an entry in the notes database.""" | ||||
| pass | |||||
| def do_history(self, data): | |||||
| """Get the history of an entry in the notes database.""" | |||||
| query = """SELECT entry_title, rev_timestamp, user_host FROM entries | query = """SELECT entry_title, rev_timestamp, user_host FROM entries | ||||
| INNER JOIN revisions ON entry_revision = rev_id | |||||
| INNER JOIN revisions ON entry_id = rev_entry | |||||
| INNER JOIN users ON rev_user = user_id | INNER JOIN users ON rev_user = user_id | ||||
| WHERE entry_slug = ?""" | WHERE entry_slug = ?""" | ||||
| try: | try: | ||||
| slug = data.args[1].lower().replace("_", "").replace("-", "") | slug = data.args[1].lower().replace("_", "").replace("-", "") | ||||
| except IndexError: | except IndexError: | ||||
| self.reply(data, "Please name an entry to get the history of.") | |||||
| self.reply(data, "Please name an entry to get info on.") | |||||
| return | return | ||||
| with sqlite.connect(self._dbfile) as conn, self._db_access_lock: | with sqlite.connect(self._dbfile) as conn, self._db_access_lock: | ||||
| @@ -151,3 +180,39 @@ class Notes(Command): | |||||
| def do_delete(self, data): | def do_delete(self, data): | ||||
| """Delete an entry from the notes database.""" | """Delete an entry from the notes database.""" | ||||
| pass | pass | ||||
| def create_db(self, conn): | |||||
| """Initialize the notes database with its necessary tables.""" | |||||
| script = """ | |||||
| CREATE TABLE entries (entry_id, entry_slug, entry_title, | |||||
| entry_revision); | |||||
| CREATE TABLE users (user_id, user_host); | |||||
| CREATE TABLE revisions (rev_id, rev_entry, rev_user, rev_timestamp, | |||||
| rev_content); | |||||
| """ | |||||
| conn.executescript(script) | |||||
| def get_next_entry(self, conn): | |||||
| """Get the next entry ID.""" | |||||
| query = "SELECT MAX(entry_id) FROM entries" | |||||
| next = conn.execute(query).fetchone()[0] | |||||
| return next + 1 if next else 1 | |||||
| def get_next_revision(self, conn): | |||||
| """Get the next revision ID.""" | |||||
| query = "SELECT MAX(rev_id) FROM revisions" | |||||
| next = conn.execute(query).fetchone()[0] | |||||
| return next + 1 if next else 1 | |||||
| def get_user(self, conn, host): | |||||
| """Get the user ID corresponding to a hostname, or make one.""" | |||||
| query1 = "SELECT user_host FROM users WHERE user_id = ?" | |||||
| query2 = "SELECT MAX(user_id) FROM users" | |||||
| query3 = "INSERT INTO users VALUES (?, ?)" | |||||
| user = conn.execute(query1).fetchone()[0] | |||||
| if user: | |||||
| return user | |||||
| last = conn.execute(query2).fetchone()[0] | |||||
| next = last + 1 if last else 1 | |||||
| conn.execute(query3, (next, host)) | |||||
| return next | |||||