Commit 1e98d5a8 authored by N07070's avatar N07070

Réécriture du système de commandes, première étape

parent 71fd441f
# -*- coding: utf-8 -*-
import sqlalchemy as sql_orm
from logs import Log
import dialogue
class Db(object):
"""Class wrapping all the databases connexions and code"""
def __init__(self, arg):
"""Initialization of the database
- Does it exist ? First run setup
- Try connection, fail if error
- Return a connection object
"""
Log.debug("Starting the database class with versin %s of %s" % sql_orm.__version__, dialogue.orm_startup )
super(Db, self).__init__()
self.arg = arg
def connect_to_db():
pass
#encoding: utf-8
# This file centralizes all the strings for the program.
# General program dialogues
orm_name = "SQLAlchemy"
# Source
source = """Mon code source est disponible à cette adresse : https://git.laquadrature.net/la-quadrature-du-net/rpteam/wantzel"""
# Licence command dialogue
licence = """J'ai été créée sous licence AGPLv3. Tu peux la lire ici : https://www.gnu.org/licenses/agpl-3.0.en.html"""
# Help command dialogue
help = """
%s Commandes disponibles :
!aide - Affiche ce message d'aide
Pour obtenir de l'aide sur une commande en particulier, il suffit de taper !aide <commande>
"""
help_help = """
Bravo %s!
Tu viens d'entrer dans le monde récursif où l'aide sert à expliciter l'aide.
"""
help_rp = """
%s, cette commande sert à ajouter un article à la Revue de Presse (https://wiki.laquadrature.net/Revue_de_presse)
L'utilisation se fait sous la forme: ~rp(cpa) <url de l'article à ajouter>
"""
help_status = """
%s, cette commande sert à retrouver les informations concernant un article ajouté à la Revue de Presse (https://wiki.laquadrature.net/Revue_de_presse)
L'utilisation se fait sous la forme: ~status <url de l'article>
"""
help_stats = """
%s, cette commande permet de fournir quelques statistiques sur la Revue de Presse (https://wiki.laquadrature.net/Revue_de_presse)
Les statistiques sont calculées sur des notes supérieurs ou égales à 0, 3, et 4. Et sur les 1, 3, 7, et 15 derniers jours.
"""
help_kill = """
*Attention %s* seuls les vrais rp-jedis ont accès à cette commande <3
Fixe la note de l'article donné en paramètre à -100.
Utile en cas d'erreur ou pour s'assurer que l'article ne sera pas publié dans la RP
Utilisation: ~kill <url de l'article>
"""
help_admin = """
*Attention %s* seuls les vrais rp-jedis ont accès à cette commande <3
Permet de gérer la liste des utilisateurs ayant un accès privilégié. Il n'y a qu'un seul niveau de privilège.
Utilisation:
~admin list Fournit la liste des utilisateurs privilégiés
~admin add user[, user]> Ajoute un ou plusieurs utilisateurs à la liste
~admin del user[, user] Supprime un ou plusieurs utilisateurs de la liste
~admin testtimer Teste le timer
~admin timer Relance un timer pour gérer le topic et les tweets
"""
help_unknown = """
Désolé %s, cette commande n'est pas disponible.
"""
# -*- coding: utf-8 -*-
# Here, we have the differents commands used by wantzel
from logs import Log
import db
class Dispatcher(object):
"""docstring for Dispatcher."""
def __init__(self):
super(Dispatcher, self).__init__()
def aide(self, user, channel, msg):
"""
Show global help.
If a known command is behind the ~!help command, an adequate message is
returned.
"""
Log.info("Help command called")
# Searching for a command after help keyword
command = re.search("[!~]aide (help|rp|status|stats|kill|admin)", msg)
if command:
command = command.group(1)
print(command)
if command=="aide":
return (dialogue.help_help % user)
elif command=="rp":
return (dialogue.help_rp % user)
elif command=="status":
return (dialogue.help_status % user)
elif command=="stats":
return (dialogue.help_stats % user)
elif command=="kill":
return (dialogue.help_kill % user)
elif command=="admin":
return (dialogue.help_admin % user)
else:
return (dialogue.help_unknown % user)
else:
return (dialogue.help % user)
def rp(self, user, channel, msg):
# Is user allowed to rp ?
# If not, fail
# Connect to DB
# Check if the url hasn't been added yet
# If not, then add it, say something
# Else, say something.
return ("Désolé %s, mais cet article à déjà été ajouté..." % user)
def oui(self, user, channel, msg):
# Is the user allowed to add a oui ?
# If not, fail
# Is the first argument an URL or an ID ?
# If it's an URL, make sure it's in the DB
# Connect to the DB
# If the URL exists, continue
# Else, fail
# If it's an ID, make sure it's in the DB
# Connect to the DB
# If the ID exists, continue
# Else, fail
# Make sure the article hasn't been published yet
# If so, fail, say something
# Does it have a reason ?
# Add a point to the article, say something.
pass
def non(self, user, channel, msg):
# Is the user allowed to add a non ?
# If not, fail
# Is the first argument an URL or an ID ?
# If it's an URL, make sure it's in the DB
# Connect to the DB
# If the URL exists, continue
# Else, fail
# If it's an ID, make sure it's in the DB
# Connect to the DB
# If the ID exists, continue
# Else, fail
# Make sure the article hasn't been published yet
# If so, fail, say something
# Does it have a reason ?
# Add a point to the article, say something.
pass
def pub(self, user, channel, msg):
# Is the user allowed to pub ?
# If not, fail
# Check article existence
# Does the article have enough votes ?
# Does the user need enough votes to publish ?
# Assert condition
# Publish to RSS feed
pass
def statut(self, user, channel, msg):
# Does article exist ?
# Get status
# Send back the status
pass
def recent(self, user, channel, msg):
# Make sure argument is valid
# Get argument last entries in reverse chronological order
# Send back list
pass
def revue(self, user, channel, msg):
# Choose argument articles in database that haven't been published yet
pass
def confiance(self, user, channel, msg):
# Is user allowed to use confiance ?
# Is the argument valid ?
# Does the user exist ?
# Is the user trusting themselves ?
pass
def info(self, user, channel, msg):
# Is the user asking for information about an article ?
# Does it exist ?
# Send back
# - Overall score
# - Date added
# - Publishing status
# - if published, date of publication
# ... another user ?
# Does the user exist ?
# Do they have information ?
# ... themselves ?
# Do they have information ?
pass
def archives(self, user, channel, msg):
# Send a link to the archive of all and every article
# that's been published.
pass
def stats(self, user, channel, msg):
# Send back
# - Number of users
# - Average trust
# - Average article adding
# - Number of articles
# - Need review
# - Published
# - Censored
# - Average of days between adding and publishing
pass
def censure(self, user, channel, msg):
# Is the user allowed to censore ?
# Does the article exist ?
# Is the article unlocked ?
# Lock article
pass
def decensure(self, user, channel, msg):
# Is the user allowed to decensore ?
# Does the article exist ?
# Is the article locked ?
# Unlock article
pass
def chut(self, user, channel, msg):
# Is the user allow to chut ?
# Does the user exist ?
# Are they chut'ted already ?
# Mute the user
pass
def parle(self, user, channel, msg):
# Is the user allowed to unchut ?
# Does the user exist ?
# Are they chut'ted already ?
# Mute the user
pass
def supp(self, user, channel, msg):
# Delete any information the user has in the database
pass
def op(self, user, channel, msg):
# Is the user allowed to use op ?
# Are the arguments valid ?
# Update the op status of user
pass
......@@ -4,9 +4,10 @@ Messages destinés à l'aide
"""
help = """
%s Mes commandes sont : ~help ~rp(cpa) ~status ~kill ~stats et ~admin.
%s Commandes disponibles :
Pour plus d'informations, voir ici: https://wiki.laquadrature.net/Wantzel
Pour obtenir de l'aide sur une commande en particulier, il suffit de taper ~help <commande>
Pour obtenir de l'aide sur une commande en particulier, il suffit de taper !aide <commande>
"""
help_help = """
......@@ -27,7 +28,7 @@ L'utilisation se fait sous la forme: ~status <url de l'article>
help_stats = """
%s, cette commande permet de fournir quelques statistiques sur la Revue de Presse (https://wiki.laquadrature.net/Revue_de_presse)
Les statistiques sont calculées sur des notes supérieurs ou égales à 0, 3, et 4. Et sur les 1, 3, 7, et 15 derniers jours.
"""
"""
help_kill = """
*Attention %s* seuls les vrais rp-jedis ont accès à cette commande <3
......@@ -48,9 +49,5 @@ help_admin = """
"""
help_unknown = """
Désolé %s, je ne connais pas cette commande.
Désolé %s, cette commande n'est pas disponible.
"""
......@@ -5,6 +5,7 @@ A simplistic IRC client connecting to freenode network.
from twisted.internet import reactor, protocol
from twisted.words.protocols import irc
from logs import Log
class IrcClient(irc.IRCClient):
def __init__(self, config):
......@@ -31,15 +32,16 @@ class IrcClientFactory(protocol.ClientFactory):
pass
def buildProtocol(self, addr):
print("Building protocol")
Log.info("Building IRC protocol...")
self.client = IrcClient(self.config)
self.set_callbacks()
return self.client
def clientConnectionLost(self, connector, reason):
"""If we get disconnected, reconnect to server."""
Log.info("Lost connection, reconnecting...")
connector.connect()
def clientConnectionFailed(self, connector, reason):
print("Connection failed: %s" % reason)
Log.error("Connection failed: %s" % reason)
reactor.stop()
......@@ -54,4 +54,3 @@ class Log(object):
"""
if config.LOG_LEVEL >= config.ERROR:
cls.log("%s: %s" % ("ERROR", message))
......@@ -5,7 +5,6 @@ Press review methods.
import feedparser
import json
import MySQLdb
import requests
import sqlite3
import time
......@@ -15,20 +14,6 @@ import config
from logs import Log
from utils import get_url, is_moderator
def get_cursor():
"""
This function connects to a MySQL database and returns a usable cursor.
"""
connection = MySQLdb.connect(
host=config.dbserver,
user=config.dbuser,
passwd=config.dbpassword,
db=config.dbname
)
if connection:
return connection.cursor()
return None
def tweet(message):
"""
Tweet message on specified account
......@@ -78,61 +63,61 @@ class Rp():
for feed in config.feeds:
self.rp_to_twitter(feed)
def rp_to_twitter(self, feed):
"""
By parsing the RSS feed of the press-review, we know what to tweet.
"""
Log.debug("rp_to_twitter method")
now = time.localtime()
today = time.strptime("%s-%s-%s %s" % (
now.tm_year,
now.tm_mon,
now.tm_mday,
time.tzname[0]
), "%Y-%m-%d %Z")
language = "fr"
if "/en/" in feed:
language = "en"
entries = feedparser.parse(feed)['entries']
entries.reverse()
Log.debug(self.last_entry_published)
for entry in entries:
# if date of publication is greater than today, midnight, and
# lesser than future
if today < entry.published_parsed < now:
if self.last_entry_published < entry.published_parsed:
# Let's see if we can truncate the lenght of the tweet
# We have 5 chars for the language, so max-length is 135
title = entry.title.encode("utf-8")
link = entry.link.encode("utf-8")
if len(title) + min(len(link),23) > 135:
# What is the number of chars we need to remove
excess = len(title) + min(len(link),23) - 135
title = ''.join([title[:-(excess + 2)], ' …'])
tweet("[%s] %s — %s" % (
language,
title,
link,
))
Log.debug(entry.published_parsed)
Log.debug(entry.title)
# Save last_entry_published
self.last_entry_published = entry.published_parsed
last_entry_published = time.strftime(
"%Y-%m-%d %H:%M:%S %Z",
self.last_entry_published
)
connection = sqlite3.connect(config.sqlite_db)
connection.execute(
"UPDATE tweets SET last_entry_published=?",
(last_entry_published,)
)
connection.commit()
# Tweet only one message in order not to spam
return
else:
Log.debug(entry.title)
Log.debug(entry.published_parsed)
# def rp_to_twitter(self, feed):
# """
# By parsing the RSS feed of the press-review, we know what to tweet.
# """
# Log.debug("rp_to_twitter method")
# now = time.localtime()
# today = time.strptime("%s-%s-%s %s" % (
# now.tm_year,
# now.tm_mon,
# now.tm_mday,
# time.tzname[0]
# ), "%Y-%m-%d %Z")
# language = "fr"
# if "/en/" in feed:
# language = "en"
# entries = feedparser.parse(feed)['entries']
# entries.reverse()
# Log.debug(self.last_entry_published)
# for entry in entries:
# # if date of publication is greater than today, midnight, and
# # lesser than future
# if today < entry.published_parsed < now:
# if self.last_entry_published < entry.published_parsed:
# # Let's see if we can truncate the lenght of the tweet
# # We have 5 chars for the language, so max-length is 135
# title = entry.title.encode("utf-8")
# link = entry.link.encode("utf-8")
# if len(title) + min(len(link),23) > 135:
# # What is the number of chars we need to remove
# excess = len(title) + min(len(link),23) - 135
# title = ''.join([title[:-(excess + 2)], ' …'])
# tweet("[%s] %s — %s" % (
# language,
# title,
# link,
# ))
# Log.debug(entry.published_parsed)
# Log.debug(entry.title)
# # Save last_entry_published
# self.last_entry_published = entry.published_parsed
# last_entry_published = time.strftime(
# "%Y-%m-%d %H:%M:%S %Z",
# self.last_entry_published
# )
# connection = sqlite3.connect(config.sqlite_db)
# connection.execute(
# "UPDATE tweets SET last_entry_published=?",
# (last_entry_published,)
# )
# connection.commit()
# # Tweet only one message in order not to spam
# return
# else:
# Log.debug(entry.title)
# Log.debug(entry.published_parsed)
def count_articles(self):
"""
......@@ -141,15 +126,16 @@ class Rp():
"""
Log.debug("count_articles method")
# TODO: Adapt this to new RP
cursor = get_cursor()
cursor.execute("""SELECT COUNT(*) FROM presse
WHERE DATE_SUB(NOW(), INTERVAL 2 MONTH)<datec
AND note > 2
AND nid = 0""")
rows = cursor.fetchall()
number = int(rows[0][0])
Log.debug("Found %s articles." % number)
return "Canal de la revue de presse de La Quadrature du Net ~ %s articles en attente ~ Mode d'emploi https://wiki.laquadrature.net/Revue_de_presse ~ Une arme, le savoir est. Le diffuser, notre devoir c'est." % number
# cursor = get_cursor()
# cursor.execute("""SELECT COUNT(*) FROM presse
# WHERE DATE_SUB(NOW(), INTERVAL 2 MONTH)<datec
# AND note > 2
# AND nid = 0""")
# rows = cursor.fetchall()
# number = int(rows[0][0])
# Log.debug("Found %s articles." % number)
# return "Canal de la revue de presse de La Quadrature du Net ~ %s articles en attente ~ Mode d'emploi https://wiki.laquadrature.net/Revue_de_presse ~ Une arme, le savoir est. Le diffuser, notre devoir c'est." % number
return "count_articles unavailable"
def clean_master_rp(self):
"""
......@@ -181,20 +167,20 @@ class Rp():
# Looking for such an article in database
# TODO: Is this possible with new RP ?
cursor = get_cursor()
# cursor = get_cursor()
# We need to be able to retrieve an url with "http" or "https"
if url.startswith("https"):
url2 = "http" + url[5:]
else:
url2 = "https" + url[4:]
cursor.execute("""
SELECT cite, nid, note
FROM presse
WHERE url = %s
OR url = %s""",
(url, url2)
)
rows = cursor.fetchall()
# cursor.execute("""
# SELECT cite, nid, note
# FROM presse
# WHERE url = %s
# OR url = %s""",
# (url, url2)
# )
# rows = cursor.fetchall()
if not rows:
return "Désolé %s, l'url donnée n'existe pas dans la base de données." % user
message = "%s: note %s / " % (user, rows[0][2])
......@@ -223,20 +209,20 @@ class Rp():
elif url == "http":
return "Merci %s, mais je prends en compte uniquement les adresses internet qui commencent par http ou https" % user
# Looking for such an article in database
cursor = get_cursor()
# We need to be able to retrieve an url with "http" or "https"
if url.startswith("https"):
url2 = "http" + url[5:]
else:
url2 = "https" + url[4:]
cursor.execute("""
SELECT id, note
FROM presse
WHERE url = %s
OR url = %s""",
(url, url2)
)
rows = cursor.fetchall()
# cursor = get_cursor()
# # We need to be able to retrieve an url with "http" or "https"
# if url.startswith("https"):
# url2 = "http" + url[5:]
# else:
# url2 = "https" + url[4:]
# cursor.execute("""
# SELECT id, note
# FROM presse
# WHERE url = %s
# OR url = %s""",
# (url, url2)
# )
# rows = cursor.fetchall()
if not rows:
return "%s n'existe pas dans la base de données." % url
else:
......@@ -249,32 +235,33 @@ class Rp():
Returns stats on articles in press review.
"""
Log.debug("stats command")
cursor = get_cursor()
periods = [1, 3, 7, 15]
notes = [0, 3, 4]
notnull = 0
somethingatall = 0
for note in notes:
notnull = 0
period_result = ""
for period in periods:
cursor.execute("""
SELECT COUNT(id) AS cid
FROM presse
WHERE nid=0
AND datec>(NOW()-INTERVAL %s DAY)
AND note>=%s""",
(period, note)
)
rows = cursor.fetchall()
if rows[0][0] > 0:
period_result = period_result + "%sj:%s, " % (period, rows[0][0])
notnull = 1
somethingatall = 1
if notnull:
return "note>=%s: " % note + period_result[:-2]
if somethingatall == 0:
return "Bravo les neurones, rien en retard depuis ces %s derniers jours!" % periods[-1]
# cursor = get_cursor()
# periods = [1, 3, 7, 15]