|
3 | 3 |
|
4 | 4 | from nexus import __version__ |
5 | 5 | from nexus.Freqlog.backends.Backend import Backend |
6 | | -from nexus.Freqlog.Definitions import Banlist, BanlistAttr, CaseSensitivity, ChordMetadata, ChordMetadataAttr, \ |
| 6 | +from nexus.Freqlog.Definitions import BanlistAttr, BanlistEntry, CaseSensitivity, ChordMetadata, ChordMetadataAttr, \ |
7 | 7 | WordMetadata, WordMetadataAttr |
8 | 8 |
|
9 | 9 | # WARNING: Loaded into SQL query, do not use unsanitized user input |
@@ -35,8 +35,9 @@ def __init__(self, db_path: str) -> None: |
35 | 35 | # Banlist table |
36 | 36 | self._execute( |
37 | 37 | "CREATE TABLE IF NOT EXISTS banlist (word TEXT PRIMARY KEY, dateadded timestamp NOT NULL) WITHOUT ROWID") |
38 | | - self._execute("CREATE INDEX IF NOT EXISTS banlist_lower ON banlist(word COLLATE NOCASE)") |
39 | | - self._execute("CREATE UNIQUE INDEX IF NOT EXISTS banlist_dateadded ON banlist(dateadded)") |
| 38 | + self._execute("CREATE INDEX IF NOT EXISTS banlist_dateadded ON banlist(dateadded)") |
| 39 | + self._execute("CREATE TABLE IF NOT EXISTS banlist_lower (word TEXT PRIMARY KEY COLLATE NOCASE," |
| 40 | + "dateadded timestamp NOT NULL) WITHOUT ROWID") |
40 | 41 |
|
41 | 42 | def _execute(self, query: str, params=None) -> None: |
42 | 43 | if params: |
@@ -83,9 +84,11 @@ def get_word_metadata(self, word: str, case: CaseSensitivity) -> WordMetadata | |
83 | 84 | res_u = self._fetchone(f"{SQL_SELECT_STAR_FROM_FREQLOG} WHERE word=?", (word_u,)) |
84 | 85 | res_l = self._fetchone(f"{SQL_SELECT_STAR_FROM_FREQLOG} WHERE word=?", (word_l,)) |
85 | 86 | word_meta_u = WordMetadata(word, res_u[1], datetime.fromtimestamp(res_u[2]), |
86 | | - timedelta(seconds=res_u[3])) |
| 87 | + timedelta(seconds=res_u[3])) if res_u else None |
87 | 88 | word_meta_l = WordMetadata(word, res_l[1], datetime.fromtimestamp(res_l[2]), |
88 | | - timedelta(seconds=res_l[3])) |
| 89 | + timedelta(seconds=res_l[3])) if res_l else None |
| 90 | + if not word_meta_u: |
| 91 | + return word_meta_l |
89 | 92 | return word_meta_u | word_meta_l |
90 | 93 | case CaseSensitivity.SENSITIVE: |
91 | 94 | res = self._fetchone(f"{SQL_SELECT_STAR_FROM_FREQLOG} WHERE word=?", (word,)) |
@@ -134,30 +137,32 @@ def check_banned(self, word: str, case: CaseSensitivity) -> bool: |
134 | 137 | res = self._fetchone("SELECT word FROM banlist WHERE word=?", (word,)) |
135 | 138 | return res is not None |
136 | 139 |
|
137 | | - def ban_word(self, word: str, case: CaseSensitivity) -> None: |
| 140 | + def ban_word(self, word: str, case: CaseSensitivity, time: datetime) -> None: |
138 | 141 | """Delete a word entry and add it to the ban list""" |
139 | 142 | match case: |
140 | 143 | case CaseSensitivity.INSENSITIVE: |
141 | 144 | word = word.lower() |
142 | 145 | self._execute("DELETE FROM freqlog WHERE word = ? COLLATE NOCASE", (word,)) |
143 | | - self._execute("INSERT INTO banlist VALUES (?)", (word,)) |
| 146 | + self._execute("INSERT INTO banlist VALUES (?, ?)", (word, time.timestamp())) |
| 147 | + self._execute("INSERT INTO banlist_lower VALUES (?, ?)", (word, time.timestamp())) |
144 | 148 | case CaseSensitivity.FIRST_CHAR: |
145 | 149 | word_u = word[0].upper() + word[1:] |
146 | 150 | word_l = word[0].lower() + word[1:] |
147 | 151 | self._execute("DELETE FROM freqlog WHERE word=?", (word_u,)) |
148 | 152 | self._execute("DELETE FROM freqlog WHERE word=?", (word_l,)) |
149 | | - self._execute("INSERT INTO banlist VALUES (?)", (word_u,)) |
150 | | - self._execute("INSERT INTO banlist VALUES (?)", (word_l,)) |
| 153 | + self._execute("INSERT INTO banlist VALUES (?, ?)", (word_u, time.timestamp())) |
| 154 | + self._execute("INSERT INTO banlist VALUES (?, ?)", (word_l, time.timestamp())) |
151 | 155 | case CaseSensitivity.SENSITIVE: |
152 | 156 | self._execute("DELETE FROM freqlog WHERE word=?", (word,)) |
153 | | - self._execute("INSERT INTO banlist VALUES (?)", (word,)) |
| 157 | + self._execute("INSERT INTO banlist VALUES (?, ?)", (word, time.timestamp())) |
154 | 158 |
|
155 | 159 | def unban_word(self, word: str, case: CaseSensitivity) -> None: |
156 | 160 | """Remove a word from the ban list""" |
157 | 161 | match case: |
158 | 162 | case CaseSensitivity.INSENSITIVE: |
159 | 163 | word = word.lower() |
160 | 164 | self._execute("DELETE FROM banlist WHERE word = ? COLLATE NOCASE", (word,)) |
| 165 | + self._execute("DELETE FROM banlist_lower WHERE word = ? COLLATE NOCASE", (word,)) |
161 | 166 | case CaseSensitivity.FIRST_CHAR: |
162 | 167 | word_u = word[0].upper() + word[1:] |
163 | 168 | word_l = word[0].lower() + word[1:] |
@@ -208,16 +213,27 @@ def list_chords(self, limit: int, sort_by: ChordMetadataAttr, |
208 | 213 | """ |
209 | 214 | raise NotImplementedError # TODO: implement |
210 | 215 |
|
211 | | - def list_banned_words(self, limit: int, sort_by: BanlistAttr, reverse: bool) -> list[Banlist]: |
| 216 | + def list_banned_words(self, limit: int, sort_by: BanlistAttr, reverse: bool) \ |
| 217 | + -> tuple[list[BanlistEntry], list[BanlistEntry]]: |
212 | 218 | """ |
213 | 219 | List banned words |
214 | 220 | :param limit: Maximum number of banned words to return |
215 | 221 | :param sort_by: Attribute to sort by: word |
216 | 222 | :param reverse: Reverse sort order |
| 223 | + :returns: Tuple of (banned words with case, banned words without case) |
217 | 224 | """ |
218 | | - raise NotImplementedError # TODO: implement |
219 | | - |
220 | | - def close(self): |
| 225 | + if reverse: |
| 226 | + sql_sort_limit = f"{sort_by.value} DESC" |
| 227 | + else: |
| 228 | + sql_sort_limit = sort_by.value |
| 229 | + if limit > 0: |
| 230 | + sql_sort_limit += f" LIMIT {limit}" |
| 231 | + res = self._fetchall(f"SELECT * FROM banlist ORDER BY {sql_sort_limit}") |
| 232 | + res_lower = self._fetchall(f"SELECT * FROM banlist_lower ORDER BY {sql_sort_limit}") |
| 233 | + return [BanlistEntry(row[0], datetime.fromtimestamp(row[1])) for row in res], \ |
| 234 | + [BanlistEntry(row[0], datetime.fromtimestamp(row[1])) for row in res_lower] |
| 235 | + |
| 236 | + def close(self) -> None: |
221 | 237 | """Close the database connection""" |
222 | 238 | self.cursor.close() |
223 | 239 | self.conn.close() |
0 commit comments