[cpif] r221 - in trunk: . backend frontend-web

svn at argo.es svn at argo.es
Mon Jul 2 22:46:03 CEST 2007


Author: jcea
Date: Mon Jul  2 22:46:01 2007
New Revision: 221

Log:
Soporte de avatares. Se puede, subir los avatares
en la pagina de perfil del usuario. Se pueden cambiar.

Ademas, se ha implementado la funcion de servir
contenido estatico. Se garantiza que esos objetos
no cambian, asi que les fijo una expiracion de
365 dias...



Added:
   trunk/frontend-web/url_static.py
      - copied, changed from r220, /trunk/frontend-web/url_.py
Modified:
   trunk/TODO
   trunk/backend/database.py
   trunk/backend/upgrade.py
   trunk/frontend-web/globales.py
   trunk/frontend-web/init.py
   trunk/frontend-web/url_perfil.py
   trunk/frontend-web/url_perfil_POST.py

Modified: trunk/TODO
==============================================================================
--- trunk/TODO	(original)
+++ trunk/TODO	Mon Jul  2 22:46:01 2007
@@ -206,3 +206,15 @@
   una cookie antigua que, por ejemplo, hayamos dejado
   en un cibercafe.
 
+- 20070702: FRONTAL WEB: En algun momento tendremos que borrar
+  los avatares "abandonados" (es decir, que sus usuarios los
+  han reemplazado).
+
+- 20070702: FRONTAL WEB: Permitimos que varios usuarios usen
+  el mismo avatar (mismo hash). Hay que tener cuidado con esto
+  si un usuario borra su avatar, ya que puede estar siendo
+  usado por otro usuario.
+
+- 20070702: FRONTAL WEB: Meter algun mecanismo de control
+  para que el usuario no nos pueda enviar gigabytes de datos...
+

Modified: trunk/backend/database.py
==============================================================================
--- trunk/backend/database.py	(original)
+++ trunk/backend/database.py	Mon Jul  2 22:46:01 2007
@@ -1,7 +1,7 @@
 # $Id$
 
 
-VERSION_DB="2007063001"
+VERSION_DB="2007070202"
 
 from globales import thread_len
 
@@ -57,6 +57,9 @@
 
     root["punto_de_lectura_global"]=BTree()
 
+    root["static"]=PersistentDict()
+    root["static"]["avatars"]=BTree()
+
   init()
 
 # Si suministramos una cookie, de ahi se saca el
@@ -88,6 +91,59 @@
 
   return None
 
+def get_static(conn,section,name) :
+  root=conn.get_root()
+  section=root["static"].get(section)
+  if not section : return None
+  data=section.get(name)
+  return data # If None -> not found
+
+def get_static_metadata(conn,section,name) :
+  metadata=get_static(conn,section,name)
+  if metadata : metadata=metadata[0]
+  return metadata
+
+def save_static(conn,section,data,metadata,allow_duplicates) :
+  from durus.persistent_list import PersistentList
+  root=conn.get_root()
+  import md5
+  hash=md5.new(data).hexdigest()
+  d=root["static"][section]
+  if (not allow_duplicates) and (hash in d) : return None
+  d[hash]=(metadata,PersistentList([data]))
+  return hash
+
+def avatar_update(conn,nick,avatar) :
+  avatar_metadata={}
+  if len(avatar)>125*1024 :
+    return "El avatar mide m´s de 125Kbytes"
+  from PIL import Image
+  from cStringIO import StringIO
+  f=StringIO(avatar)
+  try :
+    im=Image.open(f)
+    avatar_metadata["size"]=im.size
+    if im.size[0]>150 or im.size[1]>150 :
+      return "Solo admitimos imágenes de un máximo de 150*150 pixels"
+    format=im.format
+    if format not in ("PNG","JPEG","GIF") :
+      return "Solo admitimos imágenes en formato PNG, JPEG o GIF"
+    avatar_metadata["content-type"]="image/%s" %format.lower()
+    im.verify()
+  except :
+    return "El fichero parece corrupto o no se corresponde a una imagen"
+
+  name=save_static(conn,"avatars",avatar,avatar_metadata,allow_duplicates=True)
+  assert name
+
+  root=conn.get_root()
+  usuarios=root["usuarios"]["usuarios"]
+
+  usuario=usuarios.get(normaliza_nick(nick))
+  assert usuario
+
+  usuario["avatar"]=name
+
 def usuario_update(conn,nick,clave=None,OpenIDs=None) :
   root=conn.get_root()
   usuarios=root["usuarios"]["usuarios"]
@@ -104,7 +160,6 @@
       old_OpenIDs.clear() # Este tipo es persistente, asi que lo reutilizamos
       old_OpenIDs.update(OpenIDs)
 
-
 def usuario_add(conn,nick,datos,clave=None,OpenIDs=set()) :
   from durus.btree import BTree
   from durus.persistent_dict import PersistentDict
@@ -134,6 +189,7 @@
                         "TS ultima entrada":0,
                         "num mensajes":0,
                         "mensajes":BTree(),
+                        "avatar":None,
                         "datos":datos,
                         "clave":clave,
                         "OpenID":PersistentSet(OpenIDs),

Modified: trunk/backend/upgrade.py
==============================================================================
--- trunk/backend/upgrade.py	(original)
+++ trunk/backend/upgrade.py	Mon Jul  2 22:46:01 2007
@@ -110,3 +110,17 @@
       mensaje["texto"]=[texto_bruto,texto_procesado]
     conn.commit()
 
+  if root["version del foro"]=="2007063001" :
+    print "Actualizando la base de datos: 2007063001 -> 2007070201"
+    root["version del foro"]="2007070201"
+    root["static"]=PersistentDict()
+    root["static"]["avatars"]=BTree()
+    conn.commit()
+
+  if root["version del foro"]=="2007070201" :
+    print "Actualizando la base de datos: 2007070201 -> 2007070202"
+    root["version del foro"]="2007070202"
+    for usuario in root["usuarios"]["usuarios"].itervalues() :
+      usuario["avatar"]=None
+    conn.commit()
+

Modified: trunk/frontend-web/globales.py
==============================================================================
--- trunk/frontend-web/globales.py	(original)
+++ trunk/frontend-web/globales.py	Mon Jul  2 22:46:01 2007
@@ -26,7 +26,7 @@
 # Keep-alive timeout (if zero or False, no keep-alive support)
 http_keep_alive_timeout=5
 
-# OpenID Support
+# OpenID Support (Requires library. See docs)
 openid_support=True
 
 # Allow BBcode?
@@ -34,3 +34,7 @@
 
 # Allow HTML?
 allow_html=True
+
+# Allow avatar change (Requires library. See docs)
+allow_avatar_change=True
+

Modified: trunk/frontend-web/init.py
==============================================================================
--- trunk/frontend-web/init.py	(original)
+++ trunk/frontend-web/init.py	Mon Jul  2 22:46:01 2007
@@ -12,6 +12,9 @@
   if globales.openid_support :
     import openid  # Nos aseguramos de tener la libreria
 
+  if globales.allow_avatar_change :
+    from PIL import Image # Nos aseguramos de tener la libreria
+
   for i in os.walk(directorio_padre) :
     if i[0].endswith("durus-berkeleydbstorage") : continue
     if i[2] :

Modified: trunk/frontend-web/url_perfil.py
==============================================================================
--- trunk/frontend-web/url_perfil.py	(original)
+++ trunk/frontend-web/url_perfil.py	Mon Jul  2 22:46:01 2007
@@ -35,6 +35,15 @@
   for i,j in zip([3,4,5],OpenIDs[2:]) :
     texto.append('<tr><td>&nbsp;</td><td><input type="text" name="OpenID%d" size=55 value="%s" /></td></tr>' %(i,j))
 
+  texto.append('<tr><td>Nuevo avatar:</td><td><input type="file" name="avatar" size=45 value="" /></td></tr>')
+
+  avatar=u["avatar"]
+  if not avatar :
+    avatar=""
+  else :
+    size=database.get_static_metadata(conn,"avatars",avatar)["size"]
+    avatar='<img src="/static/avatars/%s" width="%d" height="%d" />' %(avatar,size[0],size[1])
+
   return (200,{"Content-Type":"text/html; charset=utf-8"},"""
 <html>
 <head><title>Perfil - %s</title></head>
@@ -44,6 +53,7 @@
 %s
 <tr><td colspan=2 align=right><input class="form-element" type="submit" name="submit" value="Cambia perfil"/></td></tr>
 </table>
+%s
 </body>
-</html>""" %(usuario_pedido,usuario_pedido,"\r\n".join(texto)))
+</html>""" %(usuario_pedido,usuario_pedido,"\r\n".join(texto),avatar))
 

Modified: trunk/frontend-web/url_perfil_POST.py
==============================================================================
--- trunk/frontend-web/url_perfil_POST.py	(original)
+++ trunk/frontend-web/url_perfil_POST.py	Mon Jul  2 22:46:01 2007
@@ -25,7 +25,8 @@
   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")
-  if clave1==None or clave2==None : # Comprobamos el caso de campos inexistentes
+  avatar=cuerpo.getfirst("avatar")
+  if clave1==None or clave2==None or avatar==None: # Comprobamos el caso de campos inexistentes
     return None
 
   clave1=clave1.strip()
@@ -52,6 +53,13 @@
     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)
 

Copied: trunk/frontend-web/url_static.py (from r220, /trunk/frontend-web/url_.py)
==============================================================================
--- /trunk/frontend-web/url_.py	(original)
+++ trunk/frontend-web/url_static.py	Mon Jul  2 22:46:01 2007
@@ -4,20 +4,21 @@
 
 @monitor
 def gestiona_url(conn,handler,path,usuario) :
-  if len(path)!=1 : return None
+  if len(path)!=3 : return None
+  section,etag=path[1],path[2]
+  headers={"ETag":etag,"Cache-Control":"max-age=31536000"}
 
   import database
-  database.actualiza_no_leidos(conn,usuario)
-  
-  import skins
-  pagina = skins.Skin(path,usuario,handler.headers)
+  data=database.get_static(conn,section,etag)
+  if not data : return None # Not found
 
-  d = {
-      "page_title": "cpif - listado de subforos",
-      "metatags":database.get_metatags(conn,usuario)
-      }
+  metadata,data=data
+  data=data[0] # de-encapsulate
 
-  pagina.load_dict(d)
+  if handler.headers.get("if-none-match")==etag :
+    return (304,headers,"")
 
-  return(pagina.web())
+  headers["Content-Type"]=metadata["content-type"]
+
+  return (200,headers,data)
 



More information about the cpif mailing list