dissabte, 26 de febrer del 2011

com fer un newsletter

Què és un Newsletter?

Els butlletins o newsletter són publicacions digitals que poden ser periòdiques o de campanya, aporten noticies i informació especialitzada i personalitzada a un conjunt de subscriptors. Es tracta d'una eina de comunicació de comunitats digitals que ve fent-se servir des de fa molt de temps i que continua fent-se servir a la web 2.0.

La temàtica dels newsletter, doncs, pot ser qualsevol: notícies, productes, serveis, ofertes... Tot allò que pugui tenir interès per als subscriptors.



Característiques dels newsletter

El newsletter no és molt llarg. Típicament és l'equivalent a un, o dos com a màxim, folis de text.

Els newsletter es reben com correu electrònics. La gestió de la llista de correu dels destinataris és, doncs, clau per a l'èxit del newsletter.

El format amb el que s'envia el newsletter és important. Si volem assegurar que el newsletter arriba a tothom de forma llegible aleshores no hi ha més remei que apostar per un mínim comú, i aquest és el text simple, que és la forma de presentació minimalista (però eficient) d'un newsletter. Ara bé, també és cert que la majoria de programes per llegir correu admeten el format HTML.

Una altre opció és enviar el newsletter com adjunt en un format de text ric, com poden ser RTF (Rich Text Format), DOC (Format de MSWord 2003),  ODT (Document de Text OpenDocument Format, el format nadiu d'OpenOffice.org/LibreOffice), o el clàssic PDF.

Si es fa servir HTML, o un format ric, aleshores és una bona idea que el newsletter tingui una coherència formal característica,  un “llibre d'estil”, que tingui en compte, per exemple, la font de lletra o l'us amb criteri de subratllats, negretes, cursives i ressaltats. Una forma de mantenir aquest estil és fer servir plantilles.

La incorporació d'enllaços també enriqueix la presentació del Newsletter. És recomanable afegir al mateix newsletter enllaços de contacte, per subscriure's o desubscriure's, i enllaços a la pàgina web, bloc, Facebook, Twitter o qualsevol de les eines 2.0 que també estiguin disponibles per a la comunitat del newsletter.

És una bona idea que el newsletter no ocupi molt d'espai a la bústia de correu dels subscriptors. Un missatge de molts KB pot provocar el rebuig pel destinatari i també és un candidat a ser esborrat quan es plena la bústia. No tots els usuaris tenen, o coneixen, l'opció d'arxivar els correus de la bústia. Això vol dir que en cas d'incloure imatges, millor que siguin poques i que tinguin dimensions raonables.

El que es pot fer és afegir enllaços al contingut multimèdia, en comptes d'encastar-lo al newsletter. També és interessant mantenir una versió online del newsletter, de forma que l'usuari tingui l'opció d'accedir-hi i veure-la amb el navegador, per si el seu client de correu té alguna limitació amb l'HTML.



L'estructura del newsletter

Per exemple, aquesta:

Els destinataris: Al BCC, ocults al públic . Si hi han molts subscriptors la solució més potent és fer servir programari de gestió de llistes de correu. La llista de correu ens permetrà moderar els missatges, gestionar els usuaris, les respostes automàtiques...

L'assumpte del missatge: pot incloure algun text que l'identifiqui i així es facilitarà a l'usuari la creació d'un filtre per a organitzar la bústia en carpetes. En tot cas, cal que el títol principal sigui breu i atractiu (però no enganyós) i que anunciï el contingut del butlletí.

L'encapçalament:  podria incloure un petit logo, el número de publicació del newsletter, la data de publicació, un enllaç a la versió online del newsletter, un enllaç per subscriure's i/o desubscriue's...

El contingut: breu, concís, personalitzat si és possible. Amb un criteri coherent per a la mida de lletra, subratllats, negretes, cursives o ressaltats. Preferiblement amb poques imatges i, si calen, més aviat petites, adaptades a la mida més reduïda que tenen els panells de vista prèvia dels lectors de correu. Enllaçar, millor que encastar, el contingut multimèdia, fitxers de descàrregues, altres pàgines.

Un peu, que pot tenir els enllaços al correu electrònic de contacte, a la pàgina web, blog, facebook, twitter... de la comunitat digital.



Quin programari cal per a fer un newsletter?

Amb tots els requeriments esmentats, una bona opció de programari per a newsletter serà, doncs, tot aquell programari (lliure ;-) que permeti:
  • generar format HTML (i posar enllaços).
  • ús de plantilles.
  • automatitzar l'enviament dels correus.
  • publicar el Newsletter a Internet com una pàgina web.
Podem fer servir el següent programari per a crear i enviar un Newsletter.
  • OpenOffice.org / LibreOffice. Permet l'us de plantilles. Generació de formats ODT, PDF, DOC, RTF, HTML. OOo/LO correctament configurats permeten l'enviament del correu personalitzat (emailing i combinació de correu).
  • Editor d'HTML. Us de plantilles. Limitat a HTML. HTML estàndard i major controls de la presentació al client. Publicació (FTP) a Internet. Cal combinar-lo amb un programari de correu.
  • Enviament de correu a pocs usuaris: Thunderbird, fent servir la seva agenda d'adreces. Si es fa servir Thunderbird recordar-se de posar els destinataris en BCC. Cal anar amb molt de compte amb això. Podem tenir problemes inesperats si la llista d'adreces de correu dels subscriptors es fa pública.
  • Enviament per correu a molts usuaris: programari de llistes de correu com Mailman. Gestió d'altes i baixes de subscripcions, respostes automàtiques, rebots...
  • Finalment, una opció més sofisticada podria ser un editor de newsletter i llista de correu tot integrat a un CMS, per exemple, un mòdul de newsletter a Drupal. La integració amb el CMS, de la llista de correu, del newsletter, i workflows d'aprovació i publicació permeten la col·laboració de diversos departaments en la creació del newsletter i la gestió de comunitats grans o múltiples comunitats de subscriptors.

diumenge, 20 de febrer del 2011

transposar una cel·la

Un "truc" ràpid:

Com passar de
Una cel·la amb a/b/c/d/e
A una cel·la amb
a
b
c
d
e

És dir, com "transposar" una cel·la?

1. OpenOffice.org / LibreOffice
amb aquesta fòrmula: =SUBSTITUEIX(A1;"/";CARAC(10))

Amb OOoBasic

Sub Transposa()
    Dim s1 As String
    Dim s2 As String

    s1 = ThisComponent.Sheets.getByName("Full1").GetCellByPosition(0,0).String
    s2 = Replace(s1, "/", Chr(10))
    ThisComponent.Sheets.getByName("Full1").GetCellByPosition(0,1).String = s2
End Sub

2. Excel
Una fórmula pràcticament idèntica: =SUSTITUIR(A1;"/";CARACTER(10))

Amb VisualBasic:

Sub Transposa()
    Dim s1 As String
    Dim s2 As String


    s1 = Hoja1.Cells(1, 1)
    s2 = Replace(s1, "/", Chr(10))
    Hoja1.Cells(2, 1) = s2
End Sub

L'única diferència en el BASIC és la forma d'accedir a les cel·les.

Obrir, reemplaçar, desar i tancar amb OpenOffice.org Basic i amb VisualBasic

Aquesta setmana passada un conegut em va demanar el següent: en un full d'excel tenia, en la primera columna un prefix, i en la segona un nom. Es tractava de, per a cada prefix de la primera columna, fer una copia d'un document word a una carpeta de destinació  donant-li de nom, el prefix corresponent, més una part fixa. A continuació, calia substituir dins del document, un text determinat pel nom respectiu de la segona columna.

De fet, això no és més que la combinació d'un text amb una taula i no és res que no es vingui fent des de temps immemorials. Poc o molt tots els  processadors de text disposen d'una opció de combinació per a fer, per exemple, emailings.

En tot cas el conegut aquest partia d'un full Excel i d'un fitxer Word i no semblava disposat a investigar en els misteris de la combinació de documents. Així que em va demanar si el podia ajudar. Realment, el problema no acabava d'adaptar-se exactament a la  combinació de documents per a correspondència, així que em va semblar que era una bona ocasió per a exercitar-me amb les macros d'Excel i Word.

Doncs bé, vet aquí l'esquema general de la solució que li vaig donar. Vaig fer una macro amb excel. Va ser necessari incloure les referències als documents de MSWord per a poder utilitzar-ne els objectes. El procés general era executar primer la creació dels documents i, a continuació, la substitució.
També hauria pogut fer-ho tot d'una tacada.

Suposarem aquest full excel:

Prefix
Nom
pre1Substitut 1
pre2Substitut 2
pre3Substitut 3
pre4Substitut 4
pre5Substitut 5

i el següent doc. word: plantilla.doc

Això és un experiment.
Es tracta de substituir #NOM# per un text que tinc al Calc
I fer-ne un munt de còpies.

A continuació, les macros d'Excel en Visual Basic. Primer de tot, ubico la plantilla.doc a la carpeta C:\fitxers\
També creo la carpeta de destinació C:\fitxers\copies

' Generar els fitxers
Sub generarFitxers()
Dim sFitxer As String
Dim i As Integer
Dim fs As Object
Dim sPathBase As String
Dim sPrefix As String


' crea un objecte FileSystemObject
Set fs = CreateObject("Scripting.FileSystemObject")
sPathBase = "C:\fitxers\"


For i = 3 To 22
sPrefix = Hoja1.Cells(i, 1)
Debug.Print sPrefix
fs.CopyFile sPathBase & "plantilla.doc", sPathBase & "copies\" & sPrefix & "copia.doc"
Next
End Sub




' A cada un dels fitxers generats, fa la substitució de #NOM# pel text de la columna 2
Sub Substitucio1()
Dim sFitxer As String
Dim i As Integer
Dim wrdApp As Word.Application 'Object
Dim wrdDoc As Word.Document
Dim wrdContent As Word.Range
Dim wrdSelection As Word.Selection
Dim sPathBase As String
Dim sPrefix As String
Dim sSubstitucio As String


sPathBase = "C:\fitxers\"


For i = 3 To 7
sPrefix = Hoja1.Cells(i, 1)
sSubstitucio = Hoja1.Cells(i, 2)
Debug.Print sPrefix
Set wrdApp = New Word.Application
wrdApp.Visible = True
Set wrdDoc = wrdApp.Documents.Open(sPathBase & "copies\" & sPrefix & "copia.doc")
Set wrdContent = wrdDoc.Content
FindReplace wrdContent, "#NOM#", sSubstitucio
wrdDoc.Save
Set wrdContent = Nothing
Set wrdDoc = Nothing
wrdApp.Quit
Set wrdApp = Nothing
Next


Debug.Print "fet!"


Set wrdApp = Nothing
End Sub


Sub FindReplace(wrdContent As Word.Range, sOriginal As String, sSubstitut As String)
'- FIND & REPLACE
wrdContent.Find.ClearFormatting
wrdContent.Find.Replacement.ClearFormatting
With wrdContent.Find
.Text = sOriginal
.Replacement.Text = sSubstitut
.Forward = True
.Wrap = wdFindContinue
.Format = Falsei
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
wrdContent.Find.Execute Replace:=wdReplaceAll
End Sub

Doncs bé, això mateix es pot fer amb OpenOffice.org (o LibreOffice, si ja heu fet el canvi). El plantejament és molt similar. Creo una macro a OpenOffice.org Calc (el full de càlcul) que copiarà un document d'OpenOffice.org Writer a una carpeta de destinació per cada fila de la columna de prefixes. Per a cada copia, l'obrirà, reemplaçarà #NOM# pel valor corresponent de la columna 2, desarà els canvis i tancarà. Vet aquí el codi:

Sub Main
    Dim sPathBase as String


    sPathBase = "/home/albert/fitxers/"


    generarFitxers(sPathBase)
    msgbox "Creats els fitxers"
    Substitucio(sPathBase) d'
    msgbox "Substitució realitzada"
End Sub


' genera els fitxers de plantilla
Sub generarFitxers(sPathBase as String )
    Dim sFitxer As String
    Dim i As Integer
    Dim sPrefix As String


    sPrefix = ""


    For i = 2 To 6
        sPrefix = ThisComponent.Sheets.getByName("Full1").GetCellByPosition(0,i).String
        if Not FileExists("file://" & sPathBase & "prova") then
        MkDir( sPathBase & "prova")
        end if
        FileCopy sPathBase & "plantilla.odt", sPathBase & "copies/" & sPrefix & "copia.odt"
    Next


End Sub


' A cada un dels fitxers generats, fer una substitució total
Sub Substitucio(sPathBase as String)
    Dim sFitxer As String
    Dim i As Integer
    Dim sPrefix As String
    Dim sNomFitxer as String
    Dim sUrlNomFitxer as String
    Dim sNomNou As String
    Dim docWriter as Object


    For i = 2 To 6
        sPrefix = ThisComponent.Sheets.getByName("Full1").GetCellByPosition(0,i).String
        sNomNou = ThisComponent.Sheets.getByName("Full1").GetCellByPosition(1,i).String
        sNomFitxer = sPathBase & "prova/" & sPrefix & "copiaplantilla.odt"
        sUrlNomFitxer = convertToUrl(sNomFitxer)
        docWriter = starDeskTop.loadComponentFromUrl (sUrlNomFitxer, "_blank", 0, Array())
        FindReplace docWriter, "#NOM#",sNomNou
        docWriter.storeAsURL(sUrlNomFitxer, Array())
        docWriter.Close (True)storeAsURL
    Next
End Sub


' cerca i substitueix text
Sub FindReplace(objDoc as Object, sOriginal As String, sSubstitut As String)
    dim objReplace as Object


    objReplace = objDoc.createReplaceDescriptor
    objReplace.SearchRegularExpression = True
    objReplace.SearchString = sOriginal
    objReplace.ReplaceString = sSubstitut


    objDoc.replaceAll(objReplace)
End Sub


Destacaria com en OOoBasic, el tractament de fitxers està incorporat al llenguatge, a diferència del VBA en el que cal invocar un objecte FileSystemObject.
També, el diferent accés a les cel·les en OOoBAsic (GetCellByPosition) i en VBA (Cells).
Molt important: en OOoBasic, degut a que es tracta d'un aplicatiu multiplataforma,  és necessari convertir el nom dels fitxers a una forma d'URL neutral. Això es fa amb ConvertToURL.
La càrrega del fitxer, en OOoBasic es fa amb StarDesktop.LoadComponentFromURL. En canvi, a VBA faig new Word.Application
La cerca i substitució dins del fitxer de text és sensiblement diferent entre  OOoBAsic i VBA.
Finalment, guardar i sortir , en OOoBAsic es fa a partir de mètodes de l'objecte Document (StoreAsURL, per desar, i Close, per tancar. A VBA, en canvi, desar es fa amb un mètode de l'objecdte del document, Save, i sortir, de l'objecte de d'aplicació, Quit.

dissabte, 12 de febrer del 2011

Com fer servir MySQL amb Python. Mòdul MySQL-DB

Aquest post és molt similar al'anterior, però en aquest la base de dades és MySQL. Per a desenvolupar aplicacions que facin servir MySQL amb Python, el primer pas és instal·lar algun mòdul que permeti accedir-hi amb Python.

El mòdul més popular per accedir a MySQL amb Python és MySQL-DB (http://sourceforge.net/projects/mysql-python/).

Com en d'altres ocasions, és possible instal·lar aquest mòdul a la una distribució Ubuntu des del"Centre de Programari de l'Ubuntu".

També instal·lo l'extensió de debug, tot des del "Centre de Programari de l'Ubuntu"


És imprescindible llegir la documentació (recordem que amb pydoc podrem consultar la documentació o presentar-la en format html).


La documentació online la trobem a http://mysql-python.sourceforge.net/MySQLdb.html

A continuació, repetiré el senzill experiment del post anterior que consistia en connectar-se a una base de dades existent i executar-hi consultes, però, en aquesta ocasió, fent servir una base de dades MySQL.

Primer de tot, amb l'Anjuta, creo un projecte nou del tipus Python generic.

Hi enganxaré el següent script. Remarcar-ne només l'us dels parametres charset='utf8' i use_unicode=True en el connect. SCalen per a recuperar correctament dades de tipus text que puguin tenir accents, dièresis... La resta de l'script és molt senzill i els comentaris expliquen que fa el codi.

 #!/usr/bin/python
# coding: latin-1
#

import MySQLdb
import sys


def main():
    print "Connectant a la base de dades localhost / proves"
      
    try:

        # obté una connexió, si no es pot connectar, llença una excepció
        # charset='utf8', use_unicode=True -> necessaris per a recuperar dades amb accents
        v_conn=MySQLdb.connect(host='localhost', user='root', passwd='password', db='proves', charset='utf8', use_unicode=True)
        print "Connectat!\n"
      
        # conn.cursor retorna un objecte cursor, per a fer les consultes.
        v_cur=v_conn.cursor()
      
        #executa una query
        v_cur.execute("select id,valor,traduccio from taula1")
      
        # obté totes les files
        v_files = v_cur.fetchall()

        # mostra les files
        for v_fila in v_files:
            print str(v_fila[0]) + " ; " + v_fila[1] + " ; " + v_fila[2]

        # tanca el cursor
        v_cur.close()
      
        # tanca la connexió
        v_conn.close()
 
      
    except:
    # obté informació de l'excepció
        e_exceptionType, e_exceptionValue, e_exceptionTraceback = sys.exc_info()
        # mostra la informació i acaba.
        sys.exit("error, %s" % (e_exceptionValue))

# final
if __name__ == "__main__":
    sys.exit(main())


Des del mateix Anjuta puc provar:

EXECUTING:
/home/albert/wp-python/prova-Mysql/src/python_mysql.py
----------------------------------------------
Connectant a la base de dades localhost / proves
Connectat!

1 ; valor 1 ; traducció 1
2 ; valor 2 ; traducció 2
3 ; valor 3 ; traducció 3
4 ; valor 4 ; traducció 4
5 ; valor 5 ; traducció 5
6 ; valor 6 ; traducció 6

----------------------------------------------
Program exited successfully with errcode (0)
Press the Enter key to close this terminal ...


Un senzill experiment de com accedir a MySQL amb scripts de Python fent servir el mòdul MySQLdb.

dissabte, 5 de febrer del 2011

Com fer servir PostgreSQL amb Python. Mòdul Psycopg2

Per a desenvolupar aplicacions que facin servir PostgreSQL amb Python, el primer pas és instal·lar algun mòdul que permeti accedir a la base de dades des del llenguatge.

El mòdul més popular per accedir a PostgreSQL amb Python és Psycopg2 (http://initd.org/psycopg/).

Instal·lar aquest mòdul a la una distribució Ubuntu no presenta cap dificultat perquè està disponible al "Centre de Programari de l'Ubuntu".

També instal·lo la testsuite i l'extensió de debug, tot des del "Centre de Programari de l'Ubuntu"



Un cop instal·lats, ja es pot treballar. El primer  pas és revisar la documentació i els exemples. La documentació en línia la podem trobar a http://initd.org/psycopg/docs/. I ha un altre enllaç molt interessant a la wiki de PostgreSQL: http://wiki.postgresql.org/wiki/Using_psycopg2_with_PostgreSQL.

Encara millor: podem utilitzar la documentació local de Python. si a la consola fem pydoc -g, se'ns obrirà   aquesta petita aplicació, que és un mini servidor web de les pàgines HTML de l'ajuda de Python i els seus mòduls:


A més, compta amb un cercador molt senzill amb el que podrem consultar sobre el mòdul que acabem d'instal·lar, el psycopg2. Fent click als tòpics trobats


Ens obrirà un navegador amb la pàgina desitjada.

Doncs bé, un cop vist això, el que faré serà un experiment molt senzill que consistirà en connectar-se a una base de dades existent i executar-hi consultes.

Primer de tot, amb l'Anjuta, creo un projecte nou del tipus Python generic. Per a fer les coses més fàcils, copio l'script de prova disponible

#!/usr/bin/python
# coding: latin-1
#
import psycopg2
import sys


def main():
#Defineix la cadena de connexió
conn_string = "host='localhost' dbname='proves' user='postgres' password='postgres'"
# la mostra
print "Connectant a la base de dades\n ->%s" % (conn_string)
try:
# obté una connexió, si no es pot connectar, llença una excepció
conn = psycopg2.connect(conn_string)

# conn.cursor retorna un objecte cursor, per a fer les consultes.
cursor = conn.cursor()

print "Connectat!\n"
except:
# obté informació de l'excepció
exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
# mostra la informació i acaba.
sys.exit("Database connection failed!\n ->%s" % (exceptionValue))


# final
if __name__ == "__main__":
sys.exit(main()) 

Des del mateix Anjuta puc provar:


EXECUTING:
/media/DISC57GB/wk-python/ProvaPG/src/prova_pg.py 
----------------------------------------------
Connectant a la base de dades
->host='localhost' dbname='proves' user='postgres' password='postgres'
Connectat!




----------------------------------------------
Program exited successfully with errcode (0)
Press the Enter key to close this terminal ... 


Net i a la primera. Ara faré una consulta, afegeixo


#!/usr/bin/python
# coding: latin-1
#
import psycopg2
import sys


def main():
#Defineix la cadena de connexió
conn_string = "host='localhost' dbname='proves' user='postgres' password='postgres'"
# la mostra
print "Connectant a la base de dades\n ->%s" % (conn_string)
try:
# obté una connexió, si no es pot connectar, llença una excepció
conn = psycopg2.connect(conn_string)

# conn.cursor retorna un objecte cursor, per a fer les consultes.
cursor = conn.cursor()

print "Connectat!\n"

# executa una consulta
cursor.execute("SELECT * FROM taula1")


# recupera files de la taula
v_files = cursor.fetchall()

print "Retorna: " + str(cursor.rowcount) + " files"


# mostra les files 
for v_fila in v_files:
print str(v_fila[0]) + " ; " + v_fila[1] + " ; " + v_fila[2]

# i surt
conn.close()
except:
# obté informació de l'excepció
exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
# mostra la informació i acaba.
sys.exit("Database connection failed!\n ->%s" % (exceptionValue))


# final
if __name__ == "__main__":
sys.exit(main())


I el resultat, com calia esperar:

EXECUTING:
/media/DISC57GB/wk-python/ProvaPG/src/prova_pg.py 
----------------------------------------------
Connectant a la base de dades
->host='localhost' dbname='proves' user='postgres' password='postgres'
Connectat!


Retorna: 5 files
1 ; valor 1 ; traducció 1
2 ; valor 2 ; traducció 2
3 ; valor 3 ; traducció 3
4 ; valor 4 ; traducció 4
5 ; valor 5 ; traducció 5


----------------------------------------------
Program exited successfully with errcode (0)
Press the Enter key to close this terminal ...

Un senzill experiment de com utilitzar PostgreSQL amb scripts de Python fent servir el mòdul Psycopg2.