[cpif] r279 - in trunk: . backend frontend-web
svn at argo.es
svn at argo.es
Sun Jul 15 21:52:20 CEST 2007
Author: jcea
Date: Sun Jul 15 21:52:18 2007
New Revision: 279
Log:
Ya podemos modificar la configuracion global de CPIF, no solo visualizarla.
Podemos enviar mensajes por correo electronico, con control de errores,
reintentos, etc.
Added:
trunk/backend/smtp.py (contents, props changed)
trunk/frontend-web/url_edit_config_POST.py
- copied, changed from r278, /trunk/frontend-web/url_perfil_POST.py
Modified:
trunk/TODO
trunk/backend/database.py
trunk/backend/upgrade.py
trunk/frontend-web/init.py
trunk/frontend-web/url_edit_config.py
Modified: trunk/TODO
==============================================================================
--- trunk/TODO (original)
+++ trunk/TODO Sun Jul 15 21:52:18 2007
@@ -258,15 +258,6 @@
- 20070712: Ya que estamos conservando la base de datos entre versiones,
eliminar el backup de usuarios, que se ha quedado anticuado.
-- 20070712: Ya podemos visualizar la configuracion CPIF via web, pero
- todavia no podemos cambiarla.
-
- Ojo en esta opcion, ya que si la transaccion DURUS se aborta, no debemos
- modificar el estado global. La forma mas simple de lograrlo es hacer
- un "commit" al final del cuerpo de la funcion, luego actualizar el estado
- global y, por ultimo, regresar. No debe hacerse nada mas, so pena de que
- ocurra una excepcion y nos deje el estado global a medio cambiar.
-
- 20070712: Poder grabar en un fichero toda la configuracion de una
instalacion CPIF, tipo Pickle o XML.
@@ -283,4 +274,17 @@
- http://www.darkreading.com/document.asp?doc_id=127731
- http://www.darkreading.com/document.asp?doc_id=107651
+
+- 20070715: Si hay algun problema en el envio de mensajes por correo
+ electronico, lo volvemos a intentar de nuevo al cabo de un minuto.
+ Pero hay que tener en cuenta el caso de envios con problemas persistentes, por
+ ejemplo, porque el usuario pertenece al servidor de correo local,
+ pero no existe.
+
+- 20070715: Si el servidor SMTP nos desconecta en medio de un envio,
+ todos los mensajes siguientes se encolaran. Si es algo persistente,
+ no saldra correo.
+
+- 20070715: Cuando se encola un mensaje de correo electronico, puede
+ tardar hasta un minuto en intentar enviarse.
Modified: trunk/backend/database.py
==============================================================================
--- trunk/backend/database.py (original)
+++ trunk/backend/database.py Sun Jul 15 21:52:18 2007
@@ -1,7 +1,7 @@
# $Id$
-VERSION_DB="2007071202"
+VERSION_DB="2007071503"
import globales
@@ -51,6 +51,8 @@
mensajes["num_mensajes"]=0
root["mensajes"]=mensajes
+ root["outgoing emails"]=BTree()
+
seguimiento_no_leidos=PersistentDict()
seguimiento_no_leidos["hilo2last_msg"]=BTree()
seguimiento_no_leidos["last_msg2hilo"]=BTree()
@@ -73,6 +75,12 @@
conf["allow_bbcode"]=True
conf["allow_html"]=True
conf["allow_avatar_change"]=True
+ conf["smtp_server"]=""
+ conf["smtp_server_port"]=25
+ conf["smtp_auth_user"]=""
+ conf["smtp_auth_passwd"]=""
+ conf["smtp_use_tls"]=False
+ conf["smtp_email_sender"]=""
@monitor
def load_initial_config(conn) :
Added: trunk/backend/smtp.py
==============================================================================
--- (empty file)
+++ trunk/backend/smtp.py Sun Jul 15 21:52:18 2007
@@ -0,0 +1,76 @@
+# $Id$
+
+from globales import monitor
+
+from globales import smtp_server,smtp_server_port,smtp_email_sender,smtp_use_tls,smtp_auth_user,smtp_auth_passwd
+
+def process_queue() :
+ @monitor
+ def outgoing_pending(conn) :
+ emails=conn.get_root()["outgoing emails"]
+ if not emails : return None,None # Nothing to do
+ return emails,emails.keys() # Load all keys in RAM, so we can delete element in the BTree safely while iterating
+
+ emails,pending=outgoing_pending()
+ if not pending : return None
+
+ import smtplib
+ m=smtplib.SMTP(smtp_server,smtp_server_port)
+ m.ehlo()
+ if smtp_use_tls :
+ m.starttls()
+ m.ehlo() # We need a new "ehlo" because capabilities could have changed
+ if smtp_auth_user :
+ m.login(smtp_auth_user,smtp_auth_passwd)
+
+# We don't keep the monitor locked because mail sending can be
+# fairly slow.
+ for k in pending :
+ @monitor
+ def get_msg(conn,emails,k) :
+ destinations,message_obj,error=emails[k]
+ text=message_obj[0]
+ return destinations,message_obj,text
+
+ @monitor
+ def requeue(conn,emails,k,destinations,message,error) :
+ emails[k]=(destinations,message,error)
+
+ @monitor
+ def del_message(conn,emails,k) :
+ del emails[k]
+
+ destinations,message_obj,text=get_msg(emails,k)
+ try :
+ ret=m.sendmail(smtp_email_sender,destinations,text)
+ except :
+ import sys
+ requeue(emails,k,destinations,message_obj,sys.exc_value)
+ continue
+ if ret=={} :
+ del_message(emails,k)
+ continue
+ destinations=ret.keys() # The destinations that were not processed
+ error=ret.popitem()
+ requeue(emails,k,destinations,message,error)
+
+def smtp() :
+ import time
+ while True :
+ try :
+ process_queue()
+ except :
+ raise
+ time.sleep(60)
+
+def enqueue(conn,destinations,message) :
+ from durus.persistent_list import PersistentList
+ emails=conn.get_root()["outgoing emails"]
+ if not emails :
+ k=0
+ else :
+ k=emails.get_max_item()[0]+1
+ message_obj=PersistentList()
+ message_obj.append(message)
+ emails[k]=(destinations,message_obj,None)
+
Modified: trunk/backend/upgrade.py
==============================================================================
--- trunk/backend/upgrade.py (original)
+++ trunk/backend/upgrade.py Sun Jul 15 21:52:18 2007
@@ -199,3 +199,31 @@
root["config"]=conf
conn.commit()
+ if root["version del foro"]=="2007071202" :
+ print "Actualizando la base de datos: 2007071202 -> 2007071501"
+ root["version del foro"]="2007071501"
+ conf=root["config"]
+ conf["smtp_server"]=""
+ conf["smtp_server_port"]=25
+ conf["smtp_auth_user"]=""
+ conf["smtp_auth_passwd"]=""
+ conf["smtp_use_tls"]=False
+ conf["smtp_email_sender"]=""
+ conn.commit()
+
+ if root["version del foro"]=="2007071501" :
+ print "Actualizando la base de datos: 2007071501 -> 2007071502"
+ root["version del foro"]="2007071502"
+ root["outgoing emails"]=BTree()
+ conn.commit()
+
+ if root["version del foro"]=="2007071502" :
+ print "Actualizando la base de datos: 2007071502 -> 2007071503"
+ root["version del foro"]="2007071503"
+ conf=root["config"]
+ conf2=PersistentDict()
+ conf2.update(conf)
+ root["config"]=conf2
+ conn.commit()
+
+
Modified: trunk/frontend-web/init.py
==============================================================================
--- trunk/frontend-web/init.py (original)
+++ trunk/frontend-web/init.py Sun Jul 15 21:52:18 2007
@@ -96,7 +96,19 @@
database.mensaje_add(conn,"Cuerpo del hilo %d" %i,r.sample(usuarios,1)[0],titulo="Hilo %d" %i,metatag=0)
time.time=t
+ if globales.smtp_server=="mail2.argo.es" :
+ import smtp
+ smtp.enqueue(conn,["jcea at argo.es"],"Subject: Arranque CPIF\r\n\r\nArrancamos CPIF")
+
inicializa(masterkey=sys.argv[1])
+
+# Lanzamos el servicio de envios de mensajes
+# electronicos en un hilo separado
+ from smtp import smtp
+ import threading
+ t=threading.Thread(target=smtp)
+ t.setDaemon(True)
+ t.start()
# Lanzamos el servidor web en un hilo separado
from servidor_web import servidor_web
Modified: trunk/frontend-web/url_edit_config.py
==============================================================================
--- trunk/frontend-web/url_edit_config.py (original)
+++ trunk/frontend-web/url_edit_config.py Sun Jul 15 21:52:18 2007
@@ -16,14 +16,20 @@
return pagina.web()
texto=['<tr><td>Number of messages per page on a thread</td><td><input type="text" name="thread_len" size="5" value="%d" /></td></tr>' %globales.thread_len]
- texto.append('<tr><td>Allow anonymous access?</td><td><input type="checkbox" name="allow_anonymous" %s /></td></tr>' % "CHECKED" if globales.allow_anonymous else "")
+ texto.append('<tr><td>Allow anonymous access?</td><td><input type="checkbox" name="allow_anonymous" %s /></td></tr>' % ("CHECKED" if globales.allow_anonymous else ""))
texto.append('<tr><td>Simultaneous HTTP connections</td><td><input type="text" name="http_max_clients" size="5" value="%d" /></td></tr>' %globales.http_max_clients)
texto.append('<tr><td>Specify initial HTTP timeout</td><td><input type="text" name="http_initial_timeout" size="5" value="%d" /></td></tr>' %globales.http_initial_timeout)
texto.append('<tr><td>Keep-alive timeout<br/>(if zero or False, no keep-alive support)</td><td><input type="text" name="http_keep_alive_timeout" size="5" value="%d" /></td></tr>' %globales.http_keep_alive_timeout)
- texto.append('<tr><td>OpenID Support<br/>(Requires library. See docs)</td><td><input type="checkbox" name="openid_support" %s /></td></tr>' % "CHECKED" if globales.openid_support else "")
- texto.append('<tr><td>Allow BBcode?</td><td><input type="checkbox" name="allow_bbcode" %s /></td></tr>' % "CHECKED" if globales.allow_bbcode else "")
- texto.append('<tr border=1><td>Allow HTML?</td><td><input type="checkbox" name="allow_html" %s /></td></tr>' % "CHECKED" if globales.allow_html else "")
- texto.append('<tr><td>Allow avatar change<br/>(Requires library. See docs)</td><td><input type="checkbox" name="allow_avatar_change" %s /></td></tr>' % "CHECKED" if globales.allow_avatar_change else "")
+ texto.append('<tr><td>OpenID Support<br/>(Requires library. See docs)</td><td><input type="checkbox" name="openid_support" %s /></td></tr>' % ("CHECKED" if globales.openid_support else ""))
+ texto.append('<tr><td>Allow BBcode?</td><td><input type="checkbox" name="allow_bbcode" %s /></td></tr>' % ("CHECKED" if globales.allow_bbcode else ""))
+ texto.append('<tr><td>Allow HTML?</td><td><input type="checkbox" name="allow_html" %s /></td></tr>' % ("CHECKED" if globales.allow_html else ""))
+ texto.append('<tr><td>Allow avatar change<br/>(Requires library. See docs)</td><td><input type="checkbox" name="allow_avatar_change" %s /></td></tr>' % ("CHECKED" if globales.allow_avatar_change else ""))
+ texto.append('<tr><td>Outgoing SMTP server</td><td><input type="text" name="smtp_server" size="30" value="%s" /></td><tr>' %globales.smtp_server)
+ texto.append('<tr><td>Outgoing SMTP server port</td><td><input type="text" name="smtp_server_port" size="5" value="%d" /></td></tr>' %globales.smtp_server_port)
+ texto.append('<tr><td>SMTP sender address</td><td><input type="text" name="smtp_email_sender" size="30" value="%s" /></td><tr>' %globales.smtp_email_sender)
+ texto.append('<tr><td>Use TLS for SMTP</td><td><input type="checkbox" name="smtp_use_tls" %s /></td></tr>' % ("CHECKED" if globales.smtp_use_tls else ""))
+ texto.append('<tr><td>Outgoing SMTP user<br/>(if server requires authentication)</td><td><input type="text" name="smtp_auth_user" size="25" value="%s" /></td><tr>' %globales.smtp_auth_user)
+ texto.append('<tr><td>Outgoing SMTP password<br/>(if server requires authentication)</td><td><input type="password" name="smtp_auth_passwd" size="20" value="%s" /></td><tr>' %globales.smtp_auth_passwd)
return (200, {"Content-Type":"text/html; charset=utf-8"},
"""
Copied: trunk/frontend-web/url_edit_config_POST.py (from r278, /trunk/frontend-web/url_perfil_POST.py)
==============================================================================
--- /trunk/frontend-web/url_perfil_POST.py (original)
+++ trunk/frontend-web/url_edit_config_POST.py Sun Jul 15 21:52:18 2007
@@ -4,65 +4,45 @@
@monitor
def gestiona_url(conn,handler,path,usuario) :
- if not usuario : # Acceso anonimo
+ if usuario!="master" : # Acceso anonimo
return None
- if len(path)!=2 : return None
+ if len(path)!=1 : return None
- import database
- usuario_pedido=path[1]
- usuario_pedido_normalizado=database.normaliza_nick(usuario_pedido)
-
- if (usuario!="master") and (usuario_pedido_normalizado!=database.normaliza_nick(usuario)) :
- return None
-
- import skins
- pagina = skins.Skin(path,usuario)
- pagina.load_dict({"page_title": "cpif - Cambio de perfil exitoso"})
-
import cgi
ctype,pdict=cgi.parse_header(handler.headers.getheader('content-type'))
cuerpo=cgi.FieldStorage(fp=handler.rfile,headers=handler.headers,environ={'REQUEST_METHOD':'POST'},keep_blank_values=1)
- clave1=cuerpo.getfirst("clave1")
- clave2=cuerpo.getfirst("clave2")
- avatar=cuerpo.getfirst("avatar")
- if clave1==None or clave2==None or avatar==None: # Comprobamos el caso de campos inexistentes
- return None
-
- clave1=clave1.strip()
- clave2=clave2.strip()
- OpenIDs=set()
- for i in xrange(1,6) :
- OpenID=cuerpo.getfirst("OpenID%d" %i)
- if OpenID : # Comprobamos el caso de campos inexistentes
- OpenID=OpenID.strip()
- if OpenID :
- if '"' in OpenID : # XSS
- pagina.load_url(["error"])
- pagina.load_dict({"generic_message": "<h1>Caracteres extraños en los servidores OpenID</h1>"})
- return pagina.web()
- OpenIDs.add(OpenID)
-
- if clave1!=clave2 :
- pagina.load_url(["error"])
- pagina.load_dict({"generic_message": "<h1>Las claves introducidas no coinciden</h1>"})
- return (pagina.web())
import database
- if not database.usuario_verifica(conn,nick=usuario_pedido) :
- pagina.load_url(["error"])
- pagina.load_dict({"generic_message": "<h1>El usuario NO existe</h1>"})
- return (pagina.web())
-
- if avatar :
- error=database.avatar_update(conn,usuario_pedido,avatar)
- if error :
- pagina.load_url(["error"])
- pagina.load_dict({"generic_message": "<h1>%s</h1>" %error})
- return (pagina.web())
-
- database.usuario_update(conn,usuario_pedido,clave=clave1,OpenIDs=OpenIDs)
+ root=conn.get_root()
+ conf=root["config"]
+ new_conf={}
+ for k,v in conf.items() :
+ t=type(v)
+ if type(True)==t :
+ v=cuerpo.getfirst(k,"*") # If we don't have a value, then false
+ new_conf[k]=(v!="*")
+ elif type(0)==t :
+ v=cuerpo.getfirst(k)
+ try :
+ v=int(v) # Be sure it is present and a number
+ except :
+ return None
+ new_conf[k]=v
+ elif type("")==t :
+ v=cuerpo.getfirst(k)
+ if v==None : return None # Be sure it is present
+ new_conf[k]=v
+ else :
+ return None # Error!!
+ # conf.clear() # Don't need "clear", since keys are overwritten
+ conf.update(new_conf) # Be careful, since the dictionary is persistent
+
+# We do a commit here to be sure we store the
+# new configuration before activating it.
+# This code should be the very last code in this function.
+ conn.commit()
+ database.load_new_config(new_conf)
- pagina.load_dict({"generic_message": "<h1>Cambio de perfil exitoso</h1>"})
- return pagina.web()
+ return (200,{"Content-Type":"text/plain; charset=utf-8"},"Cambio de configuracion CPIF efectuado")
More information about the cpif
mailing list