Add support for tags

This commit is contained in:
Schimon Jehudah 2024-02-25 19:21:10 +00:00
parent afeaa8707b
commit 5135186717
4 changed files with 302 additions and 19 deletions

View file

@ -211,6 +211,22 @@ def create_tables(db_file):
);
"""
)
feeds_tags_table_sql = (
"""
CREATE TABLE IF NOT EXISTS feeds_tags (
id INTEGER NOT NULL,
feed_id INTEGER NOT NULL,
tag_id INTEGER NOT NULL,
FOREIGN KEY ("feed_id") REFERENCES "feeds" ("id")
ON UPDATE CASCADE
ON DELETE CASCADE,
FOREIGN KEY ("tag_id") REFERENCES "tags" ("id")
ON UPDATE CASCADE
ON DELETE CASCADE,
PRIMARY KEY ("id")
);
"""
)
# TODO
# Consider parameter unique:
# entry_id TEXT NOT NULL UNIQUE,
@ -246,6 +262,15 @@ def create_tables(db_file):
);
"""
)
tags_table_sql = (
"""
CREATE TABLE IF NOT EXISTS tags (
id INTEGER NOT NULL,
tag TEXT NOT NULL UNIQUE,
PRIMARY KEY ("id")
);
"""
)
cur = conn.cursor()
# cur = get_cursor(db_file)
cur.execute(archive_table_sql)
@ -254,10 +279,12 @@ def create_tables(db_file):
cur.execute(feeds_state_table_sql)
cur.execute(feeds_properties_table_sql)
cur.execute(feeds_rules_table_sql)
cur.execute(feeds_tags_table_sql)
cur.execute(filters_table_sql)
# cur.execute(statistics_table_sql)
cur.execute(settings_table_sql)
cur.execute(status_table_sql)
cur.execute(tags_table_sql)
def get_cursor(db_file):
@ -598,7 +625,8 @@ async def remove_feed_by_index(db_file, ix):
# cur.execute(sql, par)
sql = (
"""
DELETE FROM feeds
DELETE
FROM feeds
WHERE id = ?
"""
)
@ -606,6 +634,231 @@ async def remove_feed_by_index(db_file, ix):
cur.execute(sql, par)
def get_tags_by_feed_id(db_file, feed_id):
"""
Get tags of given feed.
Parameters
----------
db_file : str
Path to database file.
feed_id : str
Feed ID.
Returns
-------
result : list
List of tags.
"""
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
SELECT tags.tag
FROM tags
INNER JOIN feeds_tags ON tags.id = feeds_tags.tag_id
INNER JOIN feeds ON feeds.id = feeds_tags.feed_id
WHERE feeds.id = ?;
"""
)
par = (feed_id,)
result = cur.execute(sql, par).fetchall()
return result
async def set_feed_id_and_tag_id(db_file, feed_id, tag_id):
"""
Set Feed ID and Tag ID.
Parameters
----------
db_file : str
Path to database file.
feed_id : str
Feed ID
tag_id : str
Tag ID
"""
async with DBLOCK:
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
INSERT
INTO feeds_tags(
feed_id, tag_id)
VALUES(
:feed_id, :tag_id)
"""
)
par = {
"feed_id": feed_id,
"tag_id": tag_id
}
cur.execute(sql, par)
def get_tag_id(db_file, tag):
"""
Get ID of given tag. Check whether tag exist.
Parameters
----------
db_file : str
Path to database file.
tag : str
Tag.
Returns
-------
ix : str
Tag ID.
"""
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
SELECT id
FROM tags
WHERE tag = ?
"""
)
par = (tag,)
ix = cur.execute(sql, par).fetchone()
return ix
def is_tag_id_associated(db_file, tag_id):
"""
Check whether tag_id is associated with any feed.
Parameters
----------
db_file : str
Path to database file.
tag_id : str
Tag ID.
Returns
-------
tag_id : str
Tag ID.
"""
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
SELECT tag_id
FROM feeds_tags
WHERE tag_id = :tag_id
"""
)
par = {
"tag_id": tag_id
}
tag_id = cur.execute(sql, par).fetchone()
return tag_id
async def delete_tag_by_index(db_file, ix):
async with DBLOCK:
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
DELETE
FROM tags
WHERE id = :id
"""
)
par = {
"id": ix
}
cur.execute(sql, par)
def is_tag_id_of_feed_id(db_file, tag_id, feed_id):
"""
Check whether given tag is related with given feed.
Parameters
----------
db_file : str
Path to database file.
feed_id : str
Feed ID.
tag_id : str
Tag ID.
Returns
-------
tag_id : str
Tag ID.
"""
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
SELECT tag_id
FROM feeds_tags
WHERE tag_id = :tag_id AND feed_id = :feed_id
"""
)
par = {
"tag_id": tag_id,
"feed_id": feed_id
}
tag_id = cur.execute(sql, par).fetchone()
return tag_id
async def delete_feed_id_tag_id(db_file, feed_id, tag_id):
async with DBLOCK:
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
DELETE
FROM feeds_tags
WHERE tag_id = :tag_id AND feed_id = :feed_id
"""
)
par = {
"tag_id": tag_id,
"feed_id": feed_id
}
cur.execute(sql, par)
async def set_new_tag(db_file, tag):
"""
Set new Tag
Parameters
----------
db_file : str
Path to database file.
tag : str
Tag
"""
async with DBLOCK:
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
INSERT
INTO tags(
tag)
VALUES(
:tag)
"""
)
par = {
"tag": tag
}
cur.execute(sql, par)
async def get_feed_id_and_name(db_file, url):
"""
Get Id and Name of feed.
@ -1112,7 +1365,8 @@ async def delete_archived_entry(cur, ix):
"""
sql = (
"""
DELETE FROM archive
DELETE
FROM archive
WHERE id = ?
"""
)
@ -1469,7 +1723,8 @@ async def maintain_archive(db_file, limit):
if difference > 0:
sql = (
"""
DELETE FROM archive
DELETE
FROM archive
WHERE id
IN (
SELECT id

View file

@ -1,2 +1,2 @@
__version__ = '0.1.21'
__version_info__ = (0, 1, 21)
__version__ = '0.1.22'
__version_info__ = (0, 1, 22)

View file

@ -621,14 +621,14 @@ class Slixfeed(slixmpp.ClientXMPP):
ftype='text-single',
label='Allow list',
value=value,
desc=('Keywords to allow (comma-separated keywords).'))
desc='Keywords to allow (comma-separated keywords).')
value = sqlite.get_filter_value(db_file, 'deny')
if value: value = str(value[0])
form.add_field(var='deny',
ftype='text-single',
label='Deny list',
value=value,
desc=('Keywords to deny (comma-separated keywords).'))
desc='Keywords to deny (comma-separated keywords).')
session['allow_complete'] = True
session['has_next'] = False
session['next'] = self._handle_filters_complete
@ -1366,9 +1366,14 @@ class Slixfeed(slixmpp.ClientXMPP):
feed_id = feed_id[0]
title = sqlite.get_feed_title(db_file, feed_id)
title = title[0]
tags_result = sqlite.get_tags_by_feed_id(db_file, feed_id)
tags_sorted = sorted(x[0] for x in tags_result)
tags = ', '.join(tags_sorted)
form['instructions'] = 'Editing subscription #{}'.format(feed_id)
else:
form['instructions'] = 'Adding subscription'
title = ''
tags = ''
form.add_field(ftype='fixed',
value='Properties')
form.add_field(var='name',
@ -1391,11 +1396,14 @@ class Slixfeed(slixmpp.ClientXMPP):
label='ID #',
value=feed_id_str)
options.addOption(feed_id_str, feed_id_str)
form.add_field(var='tags',
form.add_field(var='tags_new',
ftype='text-single',
# ftype='text-multi',
label='Tags',
value='')
desc='Comma-separated tags.',
value=tags)
form.add_field(var='tags_old',
ftype='hidden',
value=tags)
form.add_field(ftype='fixed',
value='Options')
options = form.add_field(var='priority',
@ -1443,8 +1451,32 @@ class Slixfeed(slixmpp.ClientXMPP):
await sqlite.set_enabled_status(db_file, feed_id, enabled_status)
name = values['name']
await sqlite.set_feed_title(db_file, feed_id, name)
values['priority']
values['tags']
priority = values['priority']
tags_new = values['tags_new']
tags_old = values['tags_old']
# Add new tags
for tag in tags_new.split(','):
tag = tag.strip()
if not tag:
continue
tag_id = sqlite.get_tag_id(db_file, tag)
if not tag_id:
await sqlite.set_new_tag(db_file, tag)
tag_id = sqlite.get_tag_id(db_file, tag)
tag_id = tag_id[0]
if not sqlite.is_tag_id_of_feed_id(db_file, tag_id, feed_id):
await sqlite.set_feed_id_and_tag_id(db_file, feed_id, tag_id)
# Remove tags that were not submitted
for tag in tags_old[0].split(','):
tag = tag.strip()
if not tag:
continue
if tag not in tags_new:
tag_id = sqlite.get_tag_id(db_file, tag)
tag_id = tag_id[0]
await sqlite.delete_feed_id_tag_id(db_file, feed_id, tag_id)
sqlite.is_tag_id_associated(db_file, tag_id)
await sqlite.delete_tag_by_index(db_file, tag_id)
# form = self['xep_0004'].make_form('form', 'Subscription')
# form['instructions'] = ('📁️ Subscription #{} has been {}'
# .format(feed_id, action))

View file

@ -39,7 +39,7 @@ from slixfeed.xmpp.muc import XmppGroupchat
from slixfeed.xmpp.message import XmppMessage
from slixfeed.xmpp.presence import XmppPresence
from slixfeed.xmpp.upload import XmppUpload
from slixfeed.xmpp.utility import get_chat_type
from slixfeed.xmpp.utility import get_chat_type, is_moderator
import time
@ -81,9 +81,7 @@ async def message(self, message):
if (message['muc']['nick'] == self.alias):
return
jid_full = str(message['from'])
alias = jid_full[jid_full.index('/')+1:]
role = self.plugin['xep_0045'].get_jid_property(jid, alias, 'role')
if role != 'moderator':
if not is_moderator(self, jid, jid_full):
return
# NOTE This is an exceptional case in which we treat
@ -132,9 +130,7 @@ async def message(self, message):
# return
# approved = False
jid_full = str(message['from'])
role = self.plugin['xep_0045'].get_jid_property(
jid, jid_full[jid_full.index('/')+1:], 'role')
if role != 'moderator':
if not is_moderator(self, jid, jid_full):
return
# if role == 'moderator':
# approved = True