forked from sch/Slixfeed
Add support for tags
This commit is contained in:
parent
afeaa8707b
commit
5135186717
4 changed files with 302 additions and 19 deletions
|
@ -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
|
# TODO
|
||||||
# Consider parameter unique:
|
# Consider parameter unique:
|
||||||
# entry_id TEXT NOT NULL 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 = conn.cursor()
|
||||||
# cur = get_cursor(db_file)
|
# cur = get_cursor(db_file)
|
||||||
cur.execute(archive_table_sql)
|
cur.execute(archive_table_sql)
|
||||||
|
@ -254,10 +279,12 @@ def create_tables(db_file):
|
||||||
cur.execute(feeds_state_table_sql)
|
cur.execute(feeds_state_table_sql)
|
||||||
cur.execute(feeds_properties_table_sql)
|
cur.execute(feeds_properties_table_sql)
|
||||||
cur.execute(feeds_rules_table_sql)
|
cur.execute(feeds_rules_table_sql)
|
||||||
|
cur.execute(feeds_tags_table_sql)
|
||||||
cur.execute(filters_table_sql)
|
cur.execute(filters_table_sql)
|
||||||
# cur.execute(statistics_table_sql)
|
# cur.execute(statistics_table_sql)
|
||||||
cur.execute(settings_table_sql)
|
cur.execute(settings_table_sql)
|
||||||
cur.execute(status_table_sql)
|
cur.execute(status_table_sql)
|
||||||
|
cur.execute(tags_table_sql)
|
||||||
|
|
||||||
|
|
||||||
def get_cursor(db_file):
|
def get_cursor(db_file):
|
||||||
|
@ -598,7 +625,8 @@ async def remove_feed_by_index(db_file, ix):
|
||||||
# cur.execute(sql, par)
|
# cur.execute(sql, par)
|
||||||
sql = (
|
sql = (
|
||||||
"""
|
"""
|
||||||
DELETE FROM feeds
|
DELETE
|
||||||
|
FROM feeds
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@ -606,6 +634,231 @@ async def remove_feed_by_index(db_file, ix):
|
||||||
cur.execute(sql, par)
|
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):
|
async def get_feed_id_and_name(db_file, url):
|
||||||
"""
|
"""
|
||||||
Get Id and Name of feed.
|
Get Id and Name of feed.
|
||||||
|
@ -1112,7 +1365,8 @@ async def delete_archived_entry(cur, ix):
|
||||||
"""
|
"""
|
||||||
sql = (
|
sql = (
|
||||||
"""
|
"""
|
||||||
DELETE FROM archive
|
DELETE
|
||||||
|
FROM archive
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@ -1469,7 +1723,8 @@ async def maintain_archive(db_file, limit):
|
||||||
if difference > 0:
|
if difference > 0:
|
||||||
sql = (
|
sql = (
|
||||||
"""
|
"""
|
||||||
DELETE FROM archive
|
DELETE
|
||||||
|
FROM archive
|
||||||
WHERE id
|
WHERE id
|
||||||
IN (
|
IN (
|
||||||
SELECT id
|
SELECT id
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
__version__ = '0.1.21'
|
__version__ = '0.1.22'
|
||||||
__version_info__ = (0, 1, 21)
|
__version_info__ = (0, 1, 22)
|
||||||
|
|
|
@ -621,14 +621,14 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
label='Allow list',
|
label='Allow list',
|
||||||
value=value,
|
value=value,
|
||||||
desc=('Keywords to allow (comma-separated keywords).'))
|
desc='Keywords to allow (comma-separated keywords).')
|
||||||
value = sqlite.get_filter_value(db_file, 'deny')
|
value = sqlite.get_filter_value(db_file, 'deny')
|
||||||
if value: value = str(value[0])
|
if value: value = str(value[0])
|
||||||
form.add_field(var='deny',
|
form.add_field(var='deny',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
label='Deny list',
|
label='Deny list',
|
||||||
value=value,
|
value=value,
|
||||||
desc=('Keywords to deny (comma-separated keywords).'))
|
desc='Keywords to deny (comma-separated keywords).')
|
||||||
session['allow_complete'] = True
|
session['allow_complete'] = True
|
||||||
session['has_next'] = False
|
session['has_next'] = False
|
||||||
session['next'] = self._handle_filters_complete
|
session['next'] = self._handle_filters_complete
|
||||||
|
@ -1366,9 +1366,14 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
feed_id = feed_id[0]
|
feed_id = feed_id[0]
|
||||||
title = sqlite.get_feed_title(db_file, feed_id)
|
title = sqlite.get_feed_title(db_file, feed_id)
|
||||||
title = title[0]
|
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)
|
form['instructions'] = 'Editing subscription #{}'.format(feed_id)
|
||||||
else:
|
else:
|
||||||
form['instructions'] = 'Adding subscription'
|
form['instructions'] = 'Adding subscription'
|
||||||
|
title = ''
|
||||||
|
tags = ''
|
||||||
form.add_field(ftype='fixed',
|
form.add_field(ftype='fixed',
|
||||||
value='Properties')
|
value='Properties')
|
||||||
form.add_field(var='name',
|
form.add_field(var='name',
|
||||||
|
@ -1391,11 +1396,14 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
label='ID #',
|
label='ID #',
|
||||||
value=feed_id_str)
|
value=feed_id_str)
|
||||||
options.addOption(feed_id_str, 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-single',
|
||||||
# ftype='text-multi',
|
|
||||||
label='Tags',
|
label='Tags',
|
||||||
value='')
|
desc='Comma-separated tags.',
|
||||||
|
value=tags)
|
||||||
|
form.add_field(var='tags_old',
|
||||||
|
ftype='hidden',
|
||||||
|
value=tags)
|
||||||
form.add_field(ftype='fixed',
|
form.add_field(ftype='fixed',
|
||||||
value='Options')
|
value='Options')
|
||||||
options = form.add_field(var='priority',
|
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)
|
await sqlite.set_enabled_status(db_file, feed_id, enabled_status)
|
||||||
name = values['name']
|
name = values['name']
|
||||||
await sqlite.set_feed_title(db_file, feed_id, name)
|
await sqlite.set_feed_title(db_file, feed_id, name)
|
||||||
values['priority']
|
priority = values['priority']
|
||||||
values['tags']
|
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 = self['xep_0004'].make_form('form', 'Subscription')
|
||||||
# form['instructions'] = ('📁️ Subscription #{} has been {}'
|
# form['instructions'] = ('📁️ Subscription #{} has been {}'
|
||||||
# .format(feed_id, action))
|
# .format(feed_id, action))
|
||||||
|
|
|
@ -39,7 +39,7 @@ from slixfeed.xmpp.muc import XmppGroupchat
|
||||||
from slixfeed.xmpp.message import XmppMessage
|
from slixfeed.xmpp.message import XmppMessage
|
||||||
from slixfeed.xmpp.presence import XmppPresence
|
from slixfeed.xmpp.presence import XmppPresence
|
||||||
from slixfeed.xmpp.upload import XmppUpload
|
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
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,9 +81,7 @@ async def message(self, message):
|
||||||
if (message['muc']['nick'] == self.alias):
|
if (message['muc']['nick'] == self.alias):
|
||||||
return
|
return
|
||||||
jid_full = str(message['from'])
|
jid_full = str(message['from'])
|
||||||
alias = jid_full[jid_full.index('/')+1:]
|
if not is_moderator(self, jid, jid_full):
|
||||||
role = self.plugin['xep_0045'].get_jid_property(jid, alias, 'role')
|
|
||||||
if role != 'moderator':
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# NOTE This is an exceptional case in which we treat
|
# NOTE This is an exceptional case in which we treat
|
||||||
|
@ -132,9 +130,7 @@ async def message(self, message):
|
||||||
# return
|
# return
|
||||||
# approved = False
|
# approved = False
|
||||||
jid_full = str(message['from'])
|
jid_full = str(message['from'])
|
||||||
role = self.plugin['xep_0045'].get_jid_property(
|
if not is_moderator(self, jid, jid_full):
|
||||||
jid, jid_full[jid_full.index('/')+1:], 'role')
|
|
||||||
if role != 'moderator':
|
|
||||||
return
|
return
|
||||||
# if role == 'moderator':
|
# if role == 'moderator':
|
||||||
# approved = True
|
# approved = True
|
||||||
|
|
Loading…
Reference in a new issue