Zope3 for Djangoers. Part 3: Views and templates

September 12th, 2007

I’ve been talking about how to make a web application in my last two posts but still no single html code has been written so far. What an hoax you may think. Well don’t panic, in this article you will finally get some pixels on the screen. :-)

As usually I’ll start remembering how to write a view in Django. We’ll use the models of our last article to keep things simple. So, let’s say you want a view that renders a list of your records, each one with a list of songs. Not too hard. You start writing your view function in a file called views.py inside your app directory:

from django.shortcuts import render_to_response
from myapp.models import Record

def all_my_records(request):
    records = Record.objects.all()
    return render_to_response('record_list.html', dict(records=records))

Now you need to write your template file, in this case we’ve called it record_list.html and it will live inside a templates directory in the root directory of your Django project:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 Strict//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head><title>Record list</title></head>
<body>
  <h1>My records:</h1>
  {% for record in records %}
    <h2>{{ record.title }} - {{ record.artist }}</h2>
    <ul>
    {% for song in record.song_set.all() %}
      <li>{{ song.title }} - {{ song.length }} seconds</li>
    {% endfor %}
    </ul>
  {% endfor %}
</body>
</html>

Now we need to do a couple of administrative tasks to make this work. First, we need to tell Django that our templates directory is that one. We said so in the settings.py file of our project:

TEMPLATE_DIRS = ('/home/lgs/DJProject/templates',)

Next, we should write a urls.py file inside the project and another one inside the application. Let’s start with the one inside the application directory:

from django.conf.urls.defaults import patterns

urlpatterns = patterns('',
    (r'^my_records/$', 'DJProject.DJApp.views.all_my_records'),
)

As you can see we associate a url (/my_records/) with a view function. Now we just need to include this urls from the master urls.py file in the project directory:

from django.conf.urls.defaults import patterns, include

urlpatterns = patterns('',
(r'^/', include('DJProject.DJApp.urls')
)

And finally a line in the settings.py file:

ROOT_URLCONF = 'DJProject.urls'

Even that Django does not have a configuration language (ZCML) it needs quite a few of configuration settings. This is good indeed since it makes it a lot more powerful and flexible. Note that the settings.py changes and the urls.py of the project directory needs to be changed only onced. If we were to write another view for the DJApp only the urls.py of this directory would need to be changed.

Another good point for Django is its template system. It’s quite readable and pretty powerful. But as any other template system, simple examples like this one are no real issue for it. We will push it harder later on and we will see how good it actually is.

You can test your view by starting the web server and pointing your browser to http://127.0.0.1:8000/my_records/
You will probably get an empty list since there is no records in your database yet :-)

Time to move to Zope3. Let’s try to write the same view but first let’s do an assumption. Our record objects will be stored in the root of the ZODB tree. This will make things simple enough to concentrate in the view issue.

As a convention we will put our HTTP view code in a subpackage called ‘browser’. So let’s create that directory inside our project package and put this code in its __init__.py file:

from myapp.interfaces import IRecord

class AllMyRecordsView(object):
    def records(self):
        for obj in self.context.values():
            if IRecord.providedBy(obj):
                yield obj

This time it’s not a function but a class. Not much harder than the Django version, huh? It just have a method that returns an iterator of the records in the context object. Here the context will be the root container. We need the extra if just in case there is something else in the root container.

Now time for the template, introducing the ZPT (Zope Page Template) language:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 Strict//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head><title>Record list</title></head>
<body>
  <h1>My records:</h1>
  <div tal:repeat="record view/records" tal:omit-tag="">
    <h2 tal:content="python:'%s - %s' % (record.title, record.artist)">Sticky Fingers - Rolling Stones</h2>
    <ul>
      <li tal:repeat="song record/values"
             tal:content="python:'%s - %d seconds' % (song.title, song.length)">Wild Horses - 220 seconds</li>
    </ul>
  </div>
</body>
</html>

I will tell you that the final html is the same in both versions. I think the Django one is easier to read but we have an advantage with the Zope one is that it is a valid xhtml file that can be edited and previsualized in any HTML editor so you can split your work between programmers and web designers. As you have seen in the previous example we even provided some default values (they will be replaced with the real ones in the runtime version) so we can get a grasp of how it will look like at the end.

Supposed we save the previous template in a file called record_list.pt. We will need to plug the pieces with a bit of configuration code. Put this code in a configure.zcml file inside your browser package:

<configure xmlns="http://namespaces.zope.org/browser">

<page
    name="my_records"
    for="zope.app.folder.interfaces.IFolder"
    class=".AllMyRecordsView"
    template="record_list.pt"
    permission="zope.Public" />

</configure>

Now include this browser package from your main configure.zcml file in the root of your app:

<include package=".browser"/>

And you are ready to go. Start the server and go to http://127.0.0.1:8080/my_records

But having no way to add content to our web application is not really fun. We could add it from a pure Python app but we should expect something else from this great frameworks. See you in part 4 of these series where we’ll discover the black magick mistery of automatic web forms for adding and editing content!

Zope3 for Djangoers. Part 2: Writing your models

September 12th, 2007

Yesterday I wrote an (introduction) article about how to start developing webapps with Zope coming with a Django background. We got to the point where a development environment for both frameworks was ready to start coding. It’s time to get our hands dirty.

As any modern web framework, both Django and Zope are based on a more or less formal variant of the MVC pattern. Usually in this pattern you start writing your models. You do this in Django creating a models.py file inside your app and writing classes that inherit from django.db.models.Model. For example if you are modeling a multimedia library application you will probably have the following models:

from django.db.import models

class Record(models.Model):
    artist = models.CharField('Artist', maxlength=80)
    title = models.CharField('Title', maxlength=150)
    length = models.PositiveIntField('Length', blank=True)
    date = models.DateField('Date', blank=True)

class Song(models.Model):
    title = models.CharField('Title', maxlength=150)
    length = models.PositiveIntField('Length', blank=True)
    record = models.ForeignKey(Record)

class Movie(models.Model):
    title = models.CharField('Title', maxlength=150)
    director = models.CharField('Director', maxlength=80, blank=True
    date = models.DateField('Date', blank=True)
    length = models.PositiveIntField('Length', blank=True)

Ok, that’s enough to have a semi-realistic example. Let’s see how to do the same with your Zope3 app. As pretty much everything else in Zope3 a model is a component, made up by an interface and an implementation. The interface says how the model looks like and what kind of things you allow others on your data. The implementation is an example of something that support your interface. You write your interfaces in a interfaces.py file and the implementation in another file or files. Note that the name of the file ‘interfaces.py’ is just a convention. The ‘models.py’ file in you Django app need to be called that way. Not a big deal though. Let’s write our interfaces.py file:

import zope.app.container.constraints
import zope.app.container.interfaces
import zope.schema

class IRecord(zope.app.container.interfaces.IContainer):
    artist = zope.schema.TextLine(title=u'Artist', description=u'Author of the record')
    title = zope.schema.TextLine(title=u'Title', description=u'Title')
    length = zope.schema.Int(title=u'Length', description=u'Length in seconds', min=0, required=False)
    date = zope.schema.Date(title=u'Date', description=u'Release date', required=False)

    contains('.ISong')

    def length_in_minutes():
        """Return a pretty string with the length in the mm:ss format"""

class ISong(zope.app.container.interfaces.IContained):
    title = zope.schema.TextLine(title=u'Title', description=u'Title')
    length = zope.schema.Int(title=u'Length', description=u'Length in seconds', min=0, required=False)

    containers(IRecord)

    def length_in_minutes():
        """Return a pretty string with the length in the mm:ss format"""

class IMovie(zope.app.container.interfaces.IContained):
    title = zope.schema.TextLine(title=u'Title', description=u'Title')
    director = zope.schema.TextLine(title=u'Director', description=u'Director', required=False)
    date = zope.schema.TextLine(title=u'Date', description=u'Release date', required=False)
    length = zope.schema.Int(title=u'Length', description=u'Length in minutes', min=0, required=False)

Now, time for some comments. Even that our Django models.py and our Zope3 interfaces.py have a lot of things in common as they are defining our models they have some important differences:

  • The classes in interfaces.py are not classes but interfaces. In Python there is no support for interfaces (as there is in Java) so we use the ‘class’ word but they are not clases. You can see they are not classes as the methods we defined doesn’t have the ‘self’ or ‘cls’ arguments.
  • In Zope3 every string you put in your code must be unicode. Looks like a drawback but believe me, it will make your life much easier later on.
  • Both in Django and Zope3 a field is mandatory by default. If you want to make a field optional you use the blank=True or required=False argument respectively. I prefer the wording of Zope3 much more.
  • In Django you have a ORM that finally use a Relational Database (hint: ForeignKey field is no surprise here). In Zope3 you use an object oriented database (ZODB). To represent the 1:n relationship between Records and Songs you justs say a Record is a container for Songs. This is much more intuitive and easier to model with an object oriented database. Having said that I must tell you can use a relational database with Zope3. We will do that in following articles.
  • The ‘I’ prefix for our interfaces is a common convention to remind you they are interfaces, not classes.

We still need to implement our interfaces in Zope3 so we’ll write a file called multimedia.py where we can put the implementations. Usually I use several files, one implementation in each one but we’ll put everything in the same file for the sake of simplicity:

import persistent
import zope.interfacefrom zope.app.container.btree import BTreeContainer
from zope.app.container.contained import Contained

import myapp.interfaces

class Record(BTreeContainer):
    zope.interface.implements(myapp.interfaces.IRecord)
    def __init__(self, artist, title, length=None, date=None):
        super(Record, self).__init__()
        self.artist, self.title, self.length, self.date = artist, title, length, date

class Song(Contained, persistent.Persistent):
    zope.interface.implements(myapp.interfaces.ISong)
    def __init__(self, title, length=None):
        super(Song, self).__init__()
        self.title, self.length = title, length

class Movie(Contained, persistent.Persistent):
    zope.interface.implements(myapp.interfaces.IMovie)
    def __init__(self, title, director=None, date=None, length=None):
        super(Song, self).__init__()
        self.title, self.director, self.date, self.length = title, director, date, length

Ok, that’s it. Not as scary as you thought thanks to the existence of a lot of useful base classes we can use. We use BTreeContainer and Contained to make our models aware of the relationship between Records and Songs. We also use Persistent to allow our objects to persist in the ZODB. We could use SQLAlchemy, Storm or even Django ORM here if we wanted to persist our objects in a Relational Database.

Now we must hook the models into the main app. We do this in Django with a two steps process:

  1. Include our application in the settings.py file, in the INSTALLED_APPS tuple
  2. Run the manage.py script with the syncdb argument. This will create a bunch of tables in our database backend. If you also installed the django.contrib.auth, here this command will ask you for a admin username and password. Something Zope3 did the first time the server was run.

In Zope3 we need to register the interfaces. In the next article, we’ll also write some security declarations to our implementations. The database is not affected until we create objects. So we open the configure.zcml file in the root of our application source directory and add this lines:

<interface interface=".interfaces.IRecord"
    type="zope.app.content.interfaces.IContentType" />
<interface interface=".interfaces.ISong"
    type="zope.app.content.interfaces.IContentType" />
<interface interface=".interfaces.IMovie"
    type="zope.app.content.interfaces.IContentType" />

What we are doing is fill some records for the Zope3 component registry, which is a small database of components that is kept globaly in memory but can be overriden with values in the ZODB database. Remember, it’s all about the component architecture: that’s what gives you real power. But every great power comes with great responsability and here the responsability is to correctly fill the configure.zcml file. I hear you little boy crying and winning about that ugly XML file. As we will see later, having a registry of components and the relationships between them allows you to do pretty amazing things.

So I’d say this is the first really important (and probably biggest) difference between Django and Zope3: the component architecture. Love it or hate it, that’s one thing that Django lacks. Before you complaint about this let met tell you a little history: I onced had to explain Django to a PHP experienced developer. As many PHP developers he used to write the <?php > tag scattered in his html files. No templates, no models, no views. Controller? what’s that?. I tried to explain him that using the MVC pattern was a good thing that will help him to design and maintain his applications. He was not sure that this extra learn effort was worthy. I ask the Django developer the same question: is the Component Architecture twist of mind worthy for you?

The answer will depend on your project. As a rule of thumb all I can say is: the more complex your project is the more value you will get from the CA. Every time I hear Zope3 is too hard, it has a very sloppy learning curve, etc, etc. I can’t say that’s not true. That is indeed true for every software project with a component architecture: think about Mozilla XUL, Microsoft COM or OpenOffice.org UNO. Zope3 looks easy next to them :-)

See you in the next article, where we will see how to render pixel on the screen: the exciting part!

Zope3 for Djangoers. Part 1: Installation

September 10th, 2007

I’m been working on a couple of Django projects for two months and I must say it’s a great platform for making web applications. Even when this is not the first time I play with Django. I tend to forget things too easily…

Having said that I must say I still prefer another Python web framework. One that’s pretty big but at the same time it’s small. One that it’s new but at the same time quite old. Yes, I’m talking about Zope. Zope3 precisely.

But I still think there is no perfect framework and each one has its strengths and its weaknesses. So, as always, you should study your requirements and your problem and decide which tool is best for you. As an overly simplified statement I’d say take Django for small 3-5 months projects that won’t change in the future and take Zope3 for everything else. Don’t use the same hammer for every nail.

Now, one of the things Django gets much better than Zope3 is documentation. It’s much easier to get started with Django not only because it doesn’t have a component architecture but because its tutorial and the rest of documentation really rocks.

I’ll try to write a series of posts to give the Zope3 newbie a little bit of knowledge so he/she doesn’t get lost in the Zope3 forrest. And more important, I’ll write them from a Djangoer perspective so you can always compare both frameworks.

Note of caution: in the zope3 world there are a lot of ways to do the same things. You may like this or not but that’s the way it is. In these articles I’ll just choose one of such ways. Probably not the best and hopefully not the worst. Just don’t think it is the canonical zope3 development process. I don’t think there is such one.

In this first article we’ll talk about installation. In Django you just need to have Python installed in your box and a database management system like sqlite, Mysql or Postgresql. That’s pretty much everything you need. Then you write this command:

django-admin.py startproject DJProject

and it creates an environment where you can start writing your code. Actually your are supposed to create applications inside of your project. I don’t like this wording since for me, a project is an application most of the time. Usually I split my project in components following best practices but they are not applications by their own. I know, Django lets you live without creating apps but things get out of the main road and you start living by your own. So let’s be good citizen and create our application:

cd DJProject
./manage.py startapp DJApp

Finally if you want to start your development server all you have to do is type this command:

./manage.py runserver

Ok, let’s jump into the zope3 side. In the old days Zope was a big fat framework and your app was just a module that you hooked into it. Now recently Zope3 has been splitted into lots of small components distributed as Python eggs. This approach has the advantage that you only use what you need keeping it simpler. The disadvantage is that usually you don’t know what you need :-) At least at the beginning. With some practice everything get easier.

Zope3 doesn’t currently work with Python 2.5 due to some changes in the C extensions mechanism that the 2.5 version introduced. There is quite a lot of C code in Zope3 to optimize things: some examples are the ZODB and the security system. That’s why you should stick to 2.4 until the 2.5 support is finished.

To work with Python eggs you need Easy Install which is the tool than manages them. Installing it is super simple:

wget http://peak.telecommunity.com/dist/ez_setup.py
python ez_setup.py

This will download everything needed to get started. Next step is install zopeproject. It is a great tool to start a Zope3 project. Its philosophy is that Zope3 is just a library and your app should use that library, not the other way around. It creates a WSGI application with a lot of default configuration made for you. Check out this great article to learn why WSGI is such a great thing. Ok, let’s get back to our project:

easy_install zopeproject
zopeproject Z3Project

The last command will ask you for a directory to place the zope3 eggs. This way other applications can use those eggs without duplicating them. It will also ask you for an administrator username and password. Something similar to what you get when you syncdb your Django project after adding the django.contrib.auth application.

Now you have a Z3Project directory pretty similar to your myproject Django directory. Running an http development server is quite simple:

cd Z3Project
bin/paste serve deploy.ini

But wait, I’ve got a bunch of files I don’t understand!, what are they for? And where is my code supposed to live? Well, don’t panic. I’ll try to answer these questions. The environment we just created is managed by buildout. This software handle the dependencies for your project and create/update the starting points for running, testing and debugging it among other things. These are the files you get:

  • setup.py: it’s a regular distutils file that says how to make an egg for your application. The important thing is that it lists the list of eggs your app depends on.
  • zope.conf: them main zope configuration file. You put your database here and the ZCML file the application will load on startup. Kind of a part of the settings.py file of Django.
  • site.zcml: the file which configures the component architecture of Zope. More on this later.
  • buildout.cfg: the buildout configuration file that basically tells buildout to build the egg each time it is executed taking care of the dependencies and to update the scripts in the bin directory.
  • deploy.ini: as we use Paste for the http server, this file tell it which port and IP to use.

And your code is supposed to live in the z3project subdirectory inside the Z3Project that zopeproject created. You will see a configure.zcml and an application.py files inside that directory, that is a Python package actually. The configure.zcml is included from the site.zcml we already saw and it loads a bunch of sane defaults for Zope3. It’s also the place where you should register your own components. The application.py defines a WSGI application factory that Paste will use to run the http server.

We’ll see how to write our models in the next article. See you then!

Repeat after me: Javascript is not Python

August 29th, 2007

I guess I’m too used to the Python programming language that whenever I have to write simple Javascript functions I keep making the same mistakes. I tend to write as much functionality as possible in the server side (Python :) ) but in order to create rich user interfaces I have to use the client side (Javascript :( ) and things like this happens:

function addTopic(topic) {
    var input_attrs = {
        type: "checkbox",
        checked: "checked",
        name: "topics",
        value: topic,
    };
    var li = Builder.node('li', [Builder.node('label', [Builder.node('input', input_attrs), topic.title])]);
    $("topic_list").appendChild(li);
}

For those of you who are curious, yes I’m using Script.aculo.us and Prototype libraries here but here is the point: There is a syntax error in the previous code, one that Firefox (and thus Firebug) won’t catch but one that Internet Explorer will. The funny thing is the Internet Explorer error message:

Error: Expected identifier, string or number

So, anybody can answer me: is the trailing comma a real Javascript syntax error or just another Internet Explorer flaw?

The display:inline vs whitespace battle

August 28th, 2007

Yesterday I spent quite a lot of time debugging an annoying CSS issue. I wanted to make an horizontal navigation bar so I started using this markup:


<ul>
<li><a href="/section1/">Section 1</a></li>
<li><a href="/section2/">Section 2</a></li>
<li><a href="/section3/">Section 3</a></li>
<li><a href="/section4/">Section 4</a></li>
</ul>

In order to make the list horizontal there are two CSS techniques you can use: 1) float everything or 2) use display: inline. I decided to use option 2) since it is less intrusive and I didn’t want to change the rest of the page layout.

So this is how the CSS looks like:


ul { display: inline; }
li { display: inline; border: 1px solid black; }

My problem was that there was some unwanted space between the list elements that made them difficult to stylish properly. After trying everything on earth to fix it I google for a while until I found the offending thing.

As you make the elements inline whitespace matters and the new line characters in the markup are the ones making the little margin between the list elements. You can fix this problem putting all the elements in a single line but that’s not very readable and it’s quite ugly. So this is how I fix it:

<ul>
<li><a href="/section1/">Section 1</a></li
><li><a href="/section2/">Section 2</a></li
><li><a href="/section3/">Section 3</a></li
><li><a href="/section4/">Section 4</a></li>
</ul>

A creative job offer

August 12th, 2007

Today I got a pretty creative email from the Zope3-Users mailing list. It seems they are hiring super heroes. I can’t expect less from a company with such a name….

Running Maemo scratchbox on Fedora 7

August 7th, 2007

The Maemo SDK runs on top of Scratchbox, which has some problems with Fedora kernels and memory managers. If you see an error like this when trying to log in in your scratchbox environment:


Inconsistency detected by ld.so: rtld.c: 1192: dl_main: Assertion `(void *) ph->p_vaddr == _rtld_local._dl_sysinfo_dso' failed!

Then you can try this:


# su -
# echo 0 > /proc/sys/vm/vdso_enabled

Note that the maemo-sdk-install_3.1.sh script will fail if you don’t disable the vdso kernel feature as above.

La red de casa

August 4th, 2007

El otro día hice inventario del cacharreo que tengo en casa y tengo que admitir que me sorprendí al darme cuenta de que tenía más máquinas conectadas en red de las que en principio creía:

red-casa

Un breve comentario sobre cada una:

  • El cable modem Motorola es el segundo que uso en mi conexión a Internet y me lo dieron los de Supercable, luego Auna, y ahora Ono. El primero murió en una subida de tensión.
  • El router wifi neutro Linksys WRT54Gv5 también es el segundo que tengo ya que el primero, un WRT54Gv2 también murió por las mismas causas que el cable modem. Me gustaba más el primero ya que tenía Linux dentro y estaba bien entrar por ssh y ajustar las iptables a mano. Con el que tengo ahora me tengo que limitar a la interfaz web.
  • El PC Clónico lo compré el año pasado y es un AMD64 de doble núcleo con 2 Gigas de RAM. Bastante bien para programar a diario e incluso para jugar a juegos como el Doom III. En verano hace un ruido bastante feo así que este año le he comprado una fuente sin ventilador y algo se ha notado.
  • El ordenador negro pequeñito (en vertical mide meno que un boli) tiene dentro mi placa EPIAM1000, una gran compra que hice hace ya casi 4 años. Antes la tenía en un tupperware pero el año pasado decidí darle el alojamiento que merece. Tiene 256 MB de RAM y un disco IDE de 120 Gigas. Ahora mismo sirve mi blog y algunas cosillas más sin problemas.
  • El portatil me lo compró la empresa estas navidades y tras muchos problemas con los repartidores de DELL (UPS) conseguí que llegará a casa. Es un Dell XPS 1210 y estoy muy contento con lo poco que pesa, lo poco que ocupa y lo rápido que va.
  • El Internet Tablet PC (así lo llaman los de Nokia) N800 es una pijada muy útil cuando quieres ver cualquier cosa de Internet y tienes los ordenadores apagados. O cuando quieres leerte ese PDF tan chulo que has encontrado desde tu cama. O para ver un episodio de la serie de turno también desde tu cama. Este N800 no fue gratis como el anterior N770 pero me dieron un descuento por desarrollador y me salió muy baratico.
  • Y por último la Wii, mi adquisición más polémica de estas navidades pero de la que más contento estoy. Recientemente me he pasado el Resident Evil 4 y he de decir que desde pequeño había querido tener una consola y esta es la primera que tengo. Todo un acierto y si no, preguntad al que pasa por mi casa y se echa un tenis en pista cubierta.

Y ahora algunas curiosidades sobre estas máquinas:

  • Tres de ellas usan Fedora Linux, una de ellas la versión Core 6 y las otras dos la versión 7.
  • Nota freak: estos son los nombres de algunas: nyarlathotep, sub-nigurath, yog-sothoth. Me falta por bautizar otras tres.
  • Dentro de poco la familia se ampliará con el PC de Ana, su Nintendo DS y su N770. Veremos a ver si me sale más rentable montar un cluster.
  • La red Wifi la tenía abierta para el uso y disfrute comunal hasta hace poco pero la tuve que proteger con WPA cuando los vecinos no supieron distinguir entre ver su correo/navegar por páginas web y bajarse la serie completa de Bola de Dragón del eMule.
  • En el dibujo, las lineas azules denotan conexiones cableadas y las lineas naranjas conexiones inalámbricas

Los nuevos leones de la Alhambra

August 2nd, 2007

Desde que voy a trabajar a la Alhambra dos días por semana veo cosas muy interesantes. Lo último ha sido estar presente ante la renovación de los leones del Patio de los Leones:

el nuevo león de la Alhambra

gatos escaladores

Mi pesadilla con RegisterFly

July 31st, 2007

Hasta hace un par de años los dominios que gestionabamos desde Sicem se manejaban desde nuestra cuenta en NameBay.com. Pero debido a que su interfaz de usuario era bastante complicada (ahora ha mejorado un poco) decidí registrar los nuevos dominios en otro proveedor. Después de preguntar aquí y allá y tras un poco de investigación me decidí por RegisterFly.com (no pongo enlace no les vaya a subir el pagerank).

La verdad es que salvo algún que otro problema renovando un dominio o dos, el trato con RegisterFly era bastante bueno y todo era más fácil con su interfaz de usuario, mucho más cómoda y fácil que la de NameBay.

El jueves pasado me llama un cliente diciendome que su correo electrónico ha dejado de funcionar. Tras comprobar que no es problema del servidor de correo me doy cuenta que lo que falla es su dominio. Su web tampoco funciona y sospechosamente te envia a una de esas páginas genéricas de revendedores de dominios. Entro corriendo en la web de RegisterFly y para mi sorpresa veo que el dominio ha caducado. Y no sólo este, sino también otro dominio de otro cliente.

Lo primero que pensé es por qué demonios no me habían avisado de que el dominio iba a caducar para que pudiera renovarlo. Como me llega tanto spam últimamente pues pensé que mi filtro se había colado y se había tragado estos avisos. Más tarde descubriría que no fue mi filtro antispam: esos correos nunca fueron enviados. Total que armado con la Visa me dispongo a renovar el dominio y cual es mi sorpresa cuando tras hacer el trámite, el dominio no se renueva.

Poco a poco me voy acojonando cuando veo que el panel de control de RegisterFly es poco menos que una fachada ante un sistema que no guarda cambios ni permite hacer ninguna modificación en el registro WHOIS. Lo curioso es que error tampoco da. Y lo más curioso es que la única parte del sistema que sí que funciona es la que te cobra el dinero de la renovación en la visa.

Así que viendome impotente con RegisterFly comienzo a investigar en la red si hay más gente con el mismo problema. Y vaya si los hay. Parece ser que el CEO de RegisterFly se largó con la pasta a otra parte y dejo a la compañia tiritando. Eso ha ido causando fallos en el servicio y un sin fín de protestas por parte de sus usuarios. Todo esto sin que yo me enterara de nada…

Así hasta que el ICANN decidió meter cartas en el asunto y transferir todos los dominios de RegisterFly a GoDaddy.com. Y todo sin informar a los legítimos dueños. Aunque bueno parece que no fue por su culpa. El motivo es que los dominios de RegisterFly disponían de un servicio llamado ProtectFly que enmascara la información del WHOIS para evitar que los spammers usen esa información para sus fines. Pero justo esa protección causaba que la gente de GoDaddy.com no supiera de quién eran los dominios en realidad. Parece que las bases de datos de RegisterFly estaban más pa allá que pa aca y esa información no estaba disponible…

Asi que me veo con dos dominios de nuestros clientes parcialmente secuestrados. A decir verdad mis primeras impresiones eran que algún listo los había comprado justo después de su expiración para hacer negocio con ellos. Lo más curioso es que justo cuando renové el dominio que acababa de caducar, su información de WHOIS cambió y su nuevo dueño pasó a ser Enom.com. Justo lo que necesitaba, un nuevo actor en mi tragicomedia.

Afortunadamente la gente de Enom han resultado ser serios, y tras un primer contacto con ellos, su soporte técnico ha funcionado eficientemente y tras enviarle la documentación que me solicitaban, hoy martes he podido recuperar el dominio que perdimos el jueves. Menos mal que estamos en verano y hay poco tráfico de correo electrónico…

Ahora estoy haciendo lo propio con el otro dominio y GoDaddy.com y espero que no haya más problemas.

Por último os dejo un video de un usuario casi tan cabreado como yo con RegisterFly: