Memoria - Departament d`Enginyeria Informàtica i Matemàtiques

Transcription

Memoria - Departament d`Enginyeria Informàtica i Matemàtiques
Departament d’Enginyeria Informàtica i Matemàtiques
Portal de Gremio de Ragnarok Online con DRUPAL
TITULACIÓN: Ingeniería Técnica Informática de Gestión
AUTOR: Cristian Garcés Ruiz
DIRECTOR: Carlos Molina Clemente
FECHA: 06 / 2011
2
Prefacio
Internet es una herramienta más usada cada día en todos los sectores, pero si hay algún
sector en que el uso de Internet este más expandido es posiblemente el del ocio y más
concretamente en el de los videojuegos. La cantidad de jugadores online se ha
incrementado considerablemente, sobretodo a partir del lanzamiento del popular juego de
Blizzard World of Warcraft, esto ha hecho que la curiosidad por otros juegos online
también se haya incrementado.
Ragnarok Online es un juego ya antiguo desde algunos puntos de vista, pero mantiene una
gran cantidad de jugadores que se ha visto incrementada por la moda de los juegos online.
Uno de los aspectos más característicos de Ragnarok Online es que requiere de la
agrupación en guild (clanes, gremios) para poder experimentar en la totalidad el juego.
Estos clanes pueden ser de hasta un máximo de 76 personas. La organización y
comunicación entre este número de personas puede ser complicado, y si tenemos en cuenta
que este número se puede ver multiplicado por cuatro debido al sistema de alianzas del
juego, puede convertirse todo en un autentico caos si no se usan las herramientas
adecuadas. Por estos motivos en este proyecto se quiere implementar un portal para la
administración y gestión de una guild y su alianza.
La implementación del portal se va a realizar mediante el uso del CMS Drupal. Los CMS
son herramientas software que nos proporciona la estructura y funciones básicas de una
web, como la creación, edición y publicación de contenidos y la gestión de usuarios entre
otras.
Drupal es un CMS modular, esto quiere decir que está formado por una estructura básica, a
la cual podemos ir añadiendo funcionalidades mediante la instalación de pequeñas
aplicaciones que reciben el nombre de módulo. La gran cantidad de módulos disponibles
en la comunidad de Drupal permite la construcción del sitio sin la necesidad de crear
prácticamente código.
Aunque dispongamos de un gran repositorio de de módulos, al tratarse de un portal para
una labor tan específica y poco habitual nos encontraremos en situaciones en que los
módulos ya creados no cumplan los requisitos que nosotros queremos o que simplemente
3
no exista módulo para cierta funcionalidad, en este punto es cuando deberemos desarrollar
nuestros propios módulos para satisfacer nuestras necesidades.
Podemos resumir que en este proyecto se va a implementar un portal para la gestión de una
guild de Ragnarok Online, mediante el uso de Drupal, el cual ya nos proporciona un
amplio abanico de módulos para satisfacer necesidades básicas de un sitio web y para las
necesidades y/o funcionalidades para las que no encontremos una solución entre los
módulos disponibles, procederemos a la programación de unos módulos propios para
satisfacer dichas necesidades.
4
Índice
1. Introducción ….............................................................................................................. 11
1.1. CMS …...................................................................................................................... 11
1.1.1 Definición ….............…....................................................................................... 11
1.1.2 Historia …............................................................................................................ 12
1.1.3 Funcionalidades …............................................................................................... 12
1.1.4 Tipos de CMS ….................................................................................................. 14
1.2. Drupal …................................................................................................................... 16
1.2.1 Qué es Drupal ….................................................................................................. 16
1.2.2 Arquitectura …..................................................................................................... 16
1.3 Ragnarok Online ….................................................................................................... 18
1.3.1 Qué es MMORPG …............................................................................................18
1.3.2 Qué es Ragnarok Online ….................................................................................. 18
2. Objetivos ….................................................................................................................... 21
3. Especificaciones …........................................................................................................ 23
3.1. Funcionalidades ….................................................................................................... 23
3.2. Restricciones …........................................................................................................ 25
3.2.1 Restricciones en cuanto a tipos de contenido ….................................................. 26
3.2.2 Restricciones en cuanto a visibilidad de secciones …......................................... 26
3.2.3 Restricciones en cuanto a acceso a funcionalidades …....................................... 27
4. Diseño …........................................................................................................................ 29
4.1. Roles …..................................................................................................................... 29
4.2. Tipos de Contenido ….............................................................................................. 31
5
4.3 Bloques …................................................................................................................. 38
5. Instalación y Configuración ….................................................................................... 41
5.1 Requerimientos del Sistema ….................................................................................. 41
5.2 Instalación del Servidor Web y Drupal …................................................................. 41
5.3 Instalación de Módulos y Temas para Drupal …....................................................... 49
6. Implementación …........................................................................................................ 51
6.1 Módulos del Core Utilizados …................................................................................. 51
6.1.1 Obligatorios …..................................................................................................... 51
6.1.2 Opcionales …....................................................................................................... 51
6.2 Módulos Adicionales Instalados …........................................................................... 54
6.2.1 Acces Control ….................................................................................................. 54
6.2.2 Administración …................................................................................................ 55
6.2.3 CCK …................................................................................................................. 55
6.2.4 Media …............................................................................................................... 57
6.2.5 Fecha y Hora …................................................................................................... 58
6.2.6 Views …............................................................................................................... 58
6.2.7 Votación ….......................................................................................................... 59
6.2.8 Otros …................................................................................................................ 60
6.2.9 Ragnarok Guild (módulos de desarrollo propio) …............................................. 61
6.3 Creación de Tipos de Contenidos mediante CCK …................................................. 62
6.3.1 Creación del Tipo de Contenido …...................................................................... 62
6.3.2 Creación de grupos de campos …........................................................................ 67
6.3.3 Creación de campos …......................................................................................... 68
6.3.4 Asociar un campo con un grupo …...................................................................... 69
6.3.5 Mostrar Campos ….............................................................................................. 69
6
6.4 Creación de Secciones mediante Views …................................................................ 70
6.4.1 Creación de vistas …............................................................................................ 71
6.4.2 Configuración Básica de la Vista ….................................................................... 73
6.4.3 Filtrado y Ordenación de la Vista …................................................................... 75
6.4.4 Creación de la Presentación de la Vista ….......................................................... 77
6.5 Creación de Menús …................................................................................................ 78
6.6 Creación de Roles y Concesión de Permisos …........................................................ 82
6.6.1 Creación de Roles …............................................................................................ 82
6.6.2 Asignación de Permisos a Roles …..................................................................... 83
6.6.3 Asignación de Roles a usuarios …....................................................................... 83
6.7 Creación de Alias de URL Automáticos mediante Pathauto …................................ 85
6.8 Desarrollo de Módulos en Drupal …......................................................................... 86
6.8.1 Creación del Módulo …....................................................................................... 86
6.8.2 Creación del Archivo .install …........................................................................... 88
6.8.3 Creación de Menús y Páginas …......................................................................... 91
6.8.4 Creación de Formularios …................................................................................. 93
6.8.5 Creación de Bloques …........................................................................................ 94
6.8.6 Creación de Tipo de Contenido …....................................................................... 95
6.8.7 Creación de Vistas …........................................................................................... 97
6.9 Desarrollo del Módulo Achievements …................................................................... 98
6.9.1 Tablas de la base de datos …............................................................................... 98
6.9.2 Tipos de contenido …...........................................................................................99
6.9.3 Formularios …..................................................................................................... 99
6.9.4 Bloques ….......................................................................................................... 100
6.9.5 Vistas …............................................................................................................. 100
7
6.9.6 Otras Funciones Importantes Implementadas …............................................... 100
6.10 Desarrollo del Módulo Castle Control ….............................................................. 101
6.10.1 Tablas de la base de datos …........................................................................... 101
6.10.2 Formularios …................................................................................................. 102
6.10.3 Bloques …........................................................................................................ 102
6.10.4 Otras Funciones Importantes Implementadas …............................................. 102
6.11 Desarrollo del Módulo Guild Shop …................................................................... 103
6.11.1 Tablas de la base de datos …........................................................................... 103
6.11.2 Tipos de contenido …...................................................................................... 104
6.11.3 Formularios …................................................................................................. 104
6.11.4 Bloques …........................................................................................................ 105
6.11.5 Vistas …........................................................................................................... 105
6.11.6 Otras Funciones Importantes Implementadas …..............................................105
6.12 Desarrollo del Módulo Assistance ….................................................................... 107
6.12.1 Tablas de la base de datos …........................................................................... 107
6.12.2 Tipos de contenido …...................................................................................... 108
6.12.3 Formularios …................................................................................................. 108
6.12.4 Vistas …........................................................................................................... 108
6.12.5 Otras Funciones Importantes Implementadas …............................................. 109
6.13 Desarrollo del Módulo Party …............................................................................. 110
6.13.1 Tablas de la base de datos …........................................................................... 110
6.13.2 Tipos de contenido …...................................................................................... 110
6.13.3 Formularios …................................................................................................. 111
6.13.4 Vistas …........................................................................................................... 112
6.13.5 Otras Funciones Importantes Implementadas …............................................. 113
8
6.14 Desarrollo de Temas en Drupal …......................................................................... 115
6.15 Desarrollo del Tema Propio ….............................................................................. 116
6.15.1 Definición del Tema Archivo .info …............................................................. 116
6.15.2 Creación de Plantillas ….................................................................................. 117
6.15.3 Creación del Archivo Template.php …........................................................... 117
7. Evaluación …............................................................................................................... 119
7.1 Evaluación del Módulo Achievements …................................................................ 119
7.1.1 Creación Edición Eliminación y Presentación de Nodos ….............................. 119
7.1.2 Asignación y Desasignación de los Logros …................................................... 120
7.1.3 Funcionamiento de los Bloques ….................................................................... 120
7.2 Evaluación del Módulo Castle Control …............................................................... 121
7.2.1 Creación Edición Eliminación y Presentación de Bloques …........................... 121
7.3 Evaluación del Módulo Guild Shop ….................................................................... 121
7.3.1 Creación Edición Eliminación y Presentación de Nodos ….............................. 121
7.3.2 Uso del Área de Administración …................................................................... 122
7.3.3 Realización de Compras …................................................................................ 122
7.3.4 Funcionamiento de los Bloques ….................................................................... 123
7.4 Evaluación del Módulo Assistance …..................................................................... 123
7.4.1 Creación Edición y Eliminación de Nodos …................................................... 123
7.5 Evaluación del Módulo Party ….............................................................................. 124
7.5.1 Creación de las Partys …................................................................................... 124
7.5.2 Adición y Eliminación de Asistencias a las Partys …....................................... 124
7.5.3 Presentación de las Partys …............................................................................. 125
7.6 Evaluaciones sobre Permisos y Visibilidad …......................................................... 125
8.Aspectos legales …........................................................................................................ 127
9
9. Costes …....................................................................................................................... 129
10. Conclusiones ….......................................................................................................... 131
11. Planificación temporal …......................................................................................... 133
12. Bibliografía ………………………………………………………………………… 135
13. Anexos ………..………………………………………………………………….... 137
13.1 Módulo Achievements .......................................................................................... 137
13.2 Módulo Assistance …………………………………………………...…………. 153
13.3 Módulo Castle Control ………………………………………………………….. 165
13.4 Módulo Guiad Shop …………………………………………………………….. 174
13.5 Módulo Party ……………………………………………………………………. 198
13.6 Tema Propio …………………………………………………………………….. 226
10
1. Introducción
1.1. CMS
1.1.1 Definición
CMS
son
las
siglas
de
Content
Management System, que se traduce
directamente al español como Sistema
Gestor de Contenidos. Como su propio
nombre indica, es un sistema que nos
permite gestionar contenidos. En líneas
generales, un CMS permitiría administrar
contenidos en un medio digital y para el
caso particular que nos ocupa, un CMS
permitiría gestionar los contenidos de una
web.
Dicho de otra forma, un CMS es una herramienta que permite a un editor crear, clasificar y
publicar cualquier tipo de información en una página web. Generalmente los CMS trabajan
contra una base de datos, de modo que el editor simplemente actualiza una base de datos,
incluyendo nueva información o editando la existente.
Una herramienta CMS generalmente contendrá una interfaz basada en formularios, a los
que habitualmente se accede con el navegador, donde se pueden dar de alta los contenidos
fácilmente. Esos contenidos luego aparecerán en la página en los lugares donde se ha
indicado al darlos de alta. Por lo tanto, un CMS estará compuesto de dos partes, un back y
un front, siendo el back la parte donde los administradores publican las informaciones y el
front la parte donde los visitantes visualizan las mismas.
Los primeros sistemas de administración de contenidos fueron desarrollados por
organizaciones que publicaban una gran cantidad de contenido en Internet, y necesitaban
de continuas actualizaciones; como revistas en línea, periódicos y publicaciones
corporativas.
11
1.1.2 Historia
En 1995, el sitio de noticias tecnológicas CNET sacó su sistema de administración de
documentos y publicación y creó una compañía llamada Vignette, pionero de los sistemas
de administración de contenido comerciales.
La evolución de Internet hacia portales con más contenido y la alta participación de los
usuarios directamente, a través de blogs y redes sociales, ha convertido a los gestores de
contenidos en una herramienta esencial en Internet, tanto para empresas e instituciones
como para las personas.
1.1.3 Funcionalidades
La funcionalidad de los sistemas de gestión de contenidos se pueden dividir en cuatro
categorías: creación de contenido, gestión de contenido, publicación y presentación.
Creación de contenido
Un CMS aporta herramientas para que los creadores sin conocimientos técnicos en páginas
web puedan concentrarse en el contenido. Lo más habitual es proporcionar un editor de
texto WYSIWYG, en el que el usuario ve el resultado final mientras escribe, al estilo de
los editores comerciales, pero con un rango de formatos de texto limitado. Esta limitación
tiene sentido, ya que el objetivo es que el creador pueda poner énfasis en algunos puntos,
pero sin modificar mucho el estilo general del sitio web.
Hay otras herramientas como la edición de los documentos en XML, utilización de
aplicaciones ofimáticas con las que se integra el CMS, importación de documentos
existentes y editores que permiten añadir marcas, habitualmente HTML, para indicar el
formato y estructura de un documento.
Un CMS puede incorporar una o varias de estas herramientas, pero siempre tendría que
proporcionar un editor WYSIWYG por su facilidad de uso y la comodidad de acceso desde
cualquier ordenador con un navegador y acceso a Internet.
12
Para la creación del sitio propiamente dicho, los CMS aportan herramientas para definir la
estructura, el formato de las páginas, el aspecto visual, uso de patrones, y un sistema
modular que permite incluir funciones no previstas originalmente.
Gestión de contenido
Los documentos creados se depositan en una base de datos central donde también se
guardan el resto de datos de la web, cómo son los datos relativos a los documentos
(versiones hechas, autor, fecha de publicación y caducidad, etc.), datos y preferencias de
los usuarios, la estructura de la web, etc.
La estructura de la web se puede configurar con una herramienta que, habitualmente,
presenta una visión jerárquica del sitio y permite modificaciones. Mediante esta estructura
se puede asignar un grupo a cada área, con responsables, editores, autores y usuarios con
diferentes permisos. Eso es imprescindible para facilitar el ciclo de trabajo con un circuito
de edición que va desde el autor hasta el responsable final de la publicación. El CMS
permite la comunicación entre los miembros del grupo y hace un seguimiento del estado de
cada paso del ciclo de trabajo.
Publicación
Una página aprobada se publica automáticamente cuando llega la fecha de publicación, y
cuando caduca se archiva para futuras referencias. En su publicación se aplica el patrón
definido para toda la web o para la sección concreta donde está situada, de forma que el
resultado final es un sitio web con un aspecto consistente en todas sus páginas. Esta
separación entre contenido y forma permite que se pueda modificar el aspecto visual de un
sitio web sin afectar a los documentos ya creados y libera a los autores de preocuparse por
el diseño final de sus páginas.
Presentación
Un CMS puede gestionar automáticamente la accesibilidad del web, con soporte de normas
internacionales de accesibilidad como WAI, y adaptarse a las preferencias o necesidades
de cada usuario. También puede proporcionar compatibilidad con los diferentes
navegadores disponibles en todas las plataformas (Windows, Linux, Mac, Palm, etc.) y su
capacidad de internacionalización lo permite adaptarse al idioma, sistema de medidas y
cultura del visitante.
13
El sistema se encarga de gestionar muchos otros aspectos como son los menús de
navegación o la jerarquía de la página actual dentro del web, añadiendo enlaces de forma
automática. También gestiona todos los módulos, internos o externos, que incorpore al
sistema.
1.1.4 Tipos de CMS
Podemos dividir de diferentes maneras, la más básica es según el tipo de portal que nos
permiten implementar, así de esta manera, podemos encontrar los siguientes tipos:
•
Genéricos: ofrecen la plataforma necesaria para desarrollar e implementar
aplicaciones que den solución a necesidades específicas. Pueden servir para
construir soluciones de gestión de contenidos, para soluciones de comercio
electrónico, blogs, portales. Algunos de los más usados son Joomla, Drupal, Typo3.
•
Foros: sitio que permite la discusión en línea donde los usuarios pueden reunirse y
discutir temas en los que están interesados. Los más usados son phpBB, Invision o
Vbulletin.
•
Blog: publicación de noticias o artículos en orden cronológico con espacio para
comentarios y discusión. Algunos de los más populares son WordPress o Blogger.
14
•
Wikis: sitio web dónde todos los usuarios pueden colaborar en los artículos,
aportando información o reescribiéndola. También permite espacio para
discusiones. Indicado para material que irá evolucionando con el tiempo. Los más
utilizados són MediaWiki o TikiWiki.
•
Ecommerce: son Sitios web para comercio electrónico. Los más conocidos son
osCommerce y Dynamicweb eCommerce.
•
Galería: permite administrar y generar automáticamente un portal o sitio web que
muestra contenido audiovisual, normalmente imágenes. El más utilizado es Gallery.
•
E-Learning: sirve para la enseñanza de conocimientos. Los usuarios son los
profesores y estudiantes, tenemos aulas virtuales donde se ponen a disposición el
material del curso. La publicación de un contenido por un profesor es la puesta a
disposición de los estudiantes, en una aula virtual, de ese contenido. Los más
conocidos son WebCT o Moodle.
15
•
Publicaciones digitales: son plataformas especialmente diseñadas teniendo en
cuenta las necesidades de las publicaciones digitales, tales como periódicos,
revistas, etc. Los más conocidos son ePrints y Thinkindot CMS.
1.2 Drupal
1.2.1 Qué es Drupal
Drupal es un CMS que se distribuye como software libre bajo licencia GNU
GPL. El software está desarrollado con el lenguaje de programación PHP y
utiliza base de datos MYSQL. Está maquetado con hojas de estilo CSS, con lo
que es posible construir sitios web totalmente accesibles.
Además de las funcionalidades básicas que vienen integradas con el software, es poisble
añadir nuevas funcionalidades mediante módulos.
1.2.2 Arquitectura
Los módulos
Los módulos son aplicaciones desarrolladas que se distribuyen libremente bajo la misma
licencia GPL, mediante las cuales es posible añadir funcionalidades adicionales al núcleo
de Drupal. Estos módulos implementan diferentes funciones llamadas hooks, las cuales
serán llamadas por el núcleo de Drupal en el momento necesario.
El núcleo
El núcleo de Drupal aporta la base necesaria para su funcionamiento y para la
incorporación del resto de componentes de la arquitectura. Es posible acceder al núcleo y
hacer uso directo de sus funciones a través de la API de programación.
16
Para el funcionamiento básico de Drupal hay 5 módulos obligatorios que forman parte del
núcleo :
•
Block: controla los bloques del sitio.
•
Filter: realiza acciones de filtrado sobre los contenidos a mostrar.
•
Node: realiza las acciones necesarias para la publicación y gestión de los
contenidos.
•
System: encargado de la administración general del sitio.
•
User: necesario para el registro, acceso y gestión de usuarios.
Área de administración
Una de las características que diferencia a Drupal de otros CMS es que su área de
administración viene totalmente integrada en la interfaz del portal. No existe una área de
administración en si, sino un menú de navegación que permite acceso a las opciones de
administración.
Nodos
Los nodos son el tipo de contenido básico con el que trabaja el núcleo de Drupal, para el
que se proporcionan las acciones básicas de creación, publicación etc. El resto de tipos de
contenido heredan del tipo nodo.
Bloques
Los bloques son contenidos principalmente dinámicos que se pueden habilitar en distintas
zonas del sitio.
Temas
El tema define un diseño específico para el sitio, estan formados por diferentes archivos
php que definen la estructura y por archivos css que definen el diseño.
17
1.3 Ragnarok Online
1.3.1 Qué es MMORPG
Un mmorpg es lo que se conoce como juego de rol multijugador masivo en línea. Son
juegos de rol que permiten que miles de usuarios interactuen en un mundo virtual mediante
internet.
El juego consiste en crear un personaje, el cual va evolcuionando mediante el aumento de
niveles a través de la experiencia conseguida luchando contra monstruos o realizando
misiones (llamadas habitualmente quest). El atractivo de este juego no solo reside en el
hecho de jugar al juego, sino también en la posibilidad de poder interpretar un personaje y
crear una historia alrededor de él.
Características comunes entre los MMORPG
Un estilo de juego típico de los juegos de rol tradicionales, que incluye misiones y sistema
de recompensa basado en la recogida de tesoros.
•
Un sistema de desarrollo de estadísticas, normalmente relacionado con niveles y
puntos de experiencia.
•
Una economía basada en el trueque y una unidad monetaria o más de una.
•
Organización de los jugadores en clanes, estén o no soportados directamente por el
juego.
•
Moderadores del juego y, en algunas ocasiones, personas retribuidas por vigilar el
mundo.
•
1.3.2 Qué es Ragnarok Online
Ragnarok online (RO) es un mmorpg de origen coreano basado en la
mitología nórdica. Su éxito reside en su estética de tipo manga, su
versatilidad en el desarrollo de los personajes y en sus eventos gvg
(guild vs guild).
18
Sistema de personajes
La versatilidad de la que hablábamos anteriormente, viene dada por 2 conceptos:
•
Job: define el tipo de personaje que vas a usar. Mago, guerrero, curador etc.
•
Build: se entiende por build las características únicas de cada personaje. De esta
forma, dentro de un mismo tipo de clase, podemos encontrar diferentes tipos de
personajes que se adecuaran mejor a unos roles que otros dentro del juego.
Sistema de guilds
Las guilds, o clanes, son la agrupación de personajes (hasta un máximo de 76) con el fin de
conseguir propósitos en común o simplemente por tener una misma filosofía de juego.
Normalmente los propósitos se resumen en participar en las WoEs y cooperación en el
progreso del juego. El sello identificativo de las guilds es una pequeña imagen conocida
como emblema, que se muestra al lado de todos los personajes que forman parte de ella.
Sistema de partys
Las partys son una pequeña agrupación temporal de personajes (hasta 12 miembros) las
cuales suelen estar destinadas a la cooperación entre los usuarios, para poder subir de nivel
en zonas en las que no se puede hacer de forma individual o para eliminar determinados
monstruos considerados como jefes (MvP).
También se usan como unidad de organización dentro de la guild a la hora de asistir a
WoEs u otros eventos.
War of Emperium
Las War of Emperium (WoE) es una guerra entre guilds para reclamar un castillo . Si
destruis el Emperio del castillo, tu guild se convierte en la propietaria del castillo y se
mostrará el emblema de tu guild en las banderas del castillo y también las banderas de los
castillos que hay en la ciudad. Para conseguir el castillo, tu guild debe ser la propietaria de
él a la hora de finalización de la WoE.
La obtención de un castillo supone una gran recompensa. Diariamente el castillo genera
unos cofres que dan items de forma aleatoria. Para poder recoger los cofres, sólo hace falta
19
mantener el castillo en el momento que termine la WoE, pero para poder tener más cofres,
es necesario invertir diariamente en Comercio (únicamente una vez al dia). Cada vez que
una guild atacante rompe el Emperio, la Defensa y Comercio del castillo bajan 5 niveles.
El nivel máximo es 100.
Sistema de alianzas
Una guild puede tener hasta un máximo de 3 guilds aliadas. Gracias a la alianza entre las
guilds, los miembros integrantes de las diferentes guilds no pueden recibir daño entre ellos
durante el desarrollo de las WoEs.
20
2. Objetivos
Ragnarok online es un juego que se creó en 2002, eso implica que el conocimiento sobre el
juego de los usuarios sea muy extenso, de esta manera cada día las diferencias entre guilds
a nivel de juego son menores, lo que hace que una buena organización dentro de la guild
sea un factor determinante para el éxito de la misma. Si añadimos la variedad de
nacionalidades de los jugadores, haciendo a veces que el contacto online a través del juego
sea mínimo por causas horarias, hace que la existencia de de un sitio de contacto externo al
juego, para mantener informado a todos los miembros de la guild y organizarlos, sea a
veces un factor directo en la competitividad de la guild.
Por estás razones se ha planteado este proyecto, una web en la que cumpla las siguientes
características:
•
Agrupar los elementos básicos para la organización de la guild.
•
Mantener informados a los miembros del entorno actual en el juego.
•
Facilitar la comunicación entre usuarios con distintas franjas horarias.
•
Crear un repositorio con información valiosa para el desarrollo del juego.
Además de crear la web que cumpla estas características, también se quiere lograr con este
proyecto lo siguiente:
•
Aprender el funcionamiento del framework Drupal.
•
Aprender a desarrollar módulos para Drupal.
•
Aprender a desarrollar temas gráficos para Drupal.
21
22
3. Especificaciones
3.1. Funcionalidades:
Las funcionalidades que debe implementar la web para la correcta organización de la guild,
la mejora de comunicación entre usuarios y la recopilación de información relevante para
los miembros de la guild son las siguientes
1. Posteo de noticias.
Para mantener informados a los miembros de la web sobre los acontecimientos
importantes que sucedan.
2. Posteo de eventos.
Para informar de cuando se va a realizar un evento, temática del mismo e
información relevante sobre el.
3. Posteo de estrategias.
1. WoEs.
Sección web donde queden recogidas las estrategias que se usarán
en los diferentes castillos.
2. Mvp.
Sección web donde queden recogidas las estrategias que se usarán
para matar a los diferentes MvP.
4. Tienda interna.
Para poder repartir los items que se consigan de los cofres de castillo o de los
eventos de guild mediante un saldo propio ficticio.
23
5. Posteo de guiás de ayuda.
Sección de la web en la que se puedan encontrar diferentes tipos de guias de ayuda
sobre el juego.
6. Roster de guild.
Sección de la web con un listado con información sobre los personajes de los que
disponen los integrantes de la guild para participar en los diferentes eventos.
7. Calendario de eventos.
Calendario donde poder apuntar los días en los que exista algún evento.
8. Posteo de applys y puntuación de los mismos.
Sistema para que gente interesada en entrar a la guild pueda dejar su solicitud y los
integrantes de la guild puedan votar si quieren que la persona solicitante ingrese o
no.
9. Organizador de partys.
Sistema para poder tener una sección de web donde haya un listado de las partys
que se formarán para los distintos eventos y woes.
10. Posteo de eventos interguild.
Para que los encargados de las guilds aliadas puedan dejar constancia en la web de
eventos que van realizar a los que estamos invitados.
11. Indice de videos de woes hechos por los usuarios.
Listado de videos hechos por los miembros de la guild que quieran compartirlos.
12. Sistema logros.
Sistema mediante el cual un usuario tendrá una puntuación en consecuencia de los
logros conseguidos, además de poder acceder al listado de logros conseguidos por
cada usuario o al listado general de logros disponibles con una breve explicación.
24
13. Posteo de encuestas.
Para poder someter a consulta algunas de las decisiones que se tengan que tomar.
14. Listado de guilds secundarias.
Listado de las guilds secundarias que pertenezcan a miembros de la guild en la que
podamos entrar con nuestros personajes secundarios.
15. Foro de guild
Foro para poder discutir algunos temas relacionados con la guild.
16. Foros privados
Foros de acceso restringido a los cuales solo podrán acceder los altos cargos de las
guilds.
17. Control de castillos.
Para tener información de los castillos conquistados por la guild/alianza y detalle
del estado de ellos.
3.2. Restricciones
Las únicas restricciones que encontraremos en este sitio web, serán las relacionadas con la
visibilidad de las diferentes secciones o acceso a las áreas de administración, creación de
contenidos y acceso a funcionalidades concretas, todas ellas definidas por el tipo de
usuario. Las restricciones identificadas son las siguientes.
25
3.2.1 Restricciones en cuanto a tipos de contenido
1. Únicamente podrán realizar guiás de ayuda aquellos usuarios que el el guildmaster
crea adecuado.
2. Únicamente podrán postear videos de woes aquellos usuarios que el el guildmaster
crea adecuado.
3. Las encuestas solo podrán ser posteadas por los mandos de la guild.
4. Únicamente el administrador de logros podrá crear logros.
5. Únicamente el tesorero de la guild podrá crear items de la tienda.
6. Los eventos podrán ser creados por el organizador de eventos o los guildmaster de
las otras guilds.
7. Las eventos referentes a las woes (tipo de contenido WoE) solamente podrán ser
creados por el organizador de woes.
8. Las partys de eventos y woes solo podrán ser creadas por los organizadores de
eventos y woes respectivamente.
9. Las estrategias de mvp solo podrán ser creadas por el organizador de eventos.
10. Las estrategias de castillos/woes solo podrán ser creadas por el organizador de
WoEs.
11. Sólo los miembros de guild podrán postear sus personajes en el roster.
12. Únicamente los usuarios no registrados podrán realizar applys.
3.2.2 Restricciones en cuanto a visibilidad de secciones
1. Únicamente serán visibles para los miembros de guilds aliadas las secciones de:
1. Guiás de ayuda
2. Videos de woes
3. Estrategias de woes
4. Guilds secundarias
5. Foros comunes.
2. La sección de compras realizadas solo será visible para el tesorero de la guild.
3. Los miembros de la guild podrán ver sus propias compras realizadas.
4. El área de administración de la tienda solo será visible para el tesorero de la guild.
26
5. El área de administración de logros solo será visible para el administrador de
logros.
6. El área de administración de bloques será visible para los usuarios que puedan crear
los bloques de seguimiento de castillos.
7. Las secciones sin ninguna restricción mencionada anteriormente serán visibles para
todos los miembros de la guild.
8. Únicamente los guildmaster/subguildmaster de las guilds tendrán acceso a los foros
privados.
3.2.3 Restricciones en cuanto a acceso a funcionalidades
1. Únicamente los miembros de la guild podrán votar los applys.
2. Los miembros de guilds aliadas no podrán postear comentarios en ningún
contenido.
3. Los guildmasters de guilds aliadas podrán postear comentarios en las secciones
visibles para ellos.
4. Únicamente los miembros de la guild podrán votar las encuestas.
5. Únicamente el encargado de los logros podrá asignar logros conseguidos a los
usuarios.
6. Únicamente los usuarios de la guild tendrán acceso a la compra de items.
7. Los bloques de control de castillos podrán ser creados por el tesorero, los mandos
de la guild y los mandos de las guilds aliadas.
8. Únicamente el organizador de eventos podrá añadir miembros a una party de
evento creada.
9. Únicamente el organizador de eventos podrá eliminar miembros a una party de
evento creada.
10. Únicamente el organizador de woes podrá añadir miembros a una party de woes
creada.
11. Únicamente el organizador de woes podrá eliminar miembros a una party de woes
creada.
27
28
4. Diseño
4.1. Roles
Podemos dividir los roles en 3 grupos:
•
Básicos:
Roles para distinguir a los miembros segun a que guild pertenecen (la nuestra o una
aliada) y si son un miembro general de la guild, o un miembro con poderes.
•
Funciones Intraguild:
Roles específicos relacionados directamente con alguna de las funciones que
afectan al funcionamiento de la guild.
•
Funciones Web:
Roles específicos relacionados con funciones del contenido web estrictamente.
1. Básicos:
1. GuildMaster
Miembro líder de la guild, por lo tanto gozará de todos los permisos
posibles y podrá editar o eliminar cualquier tipo de contenido.
2. SubGuildMaster
Miembro de la guild ayudante del líder, como tal, tendrá todos los permisos
generales exceptuando los de funciones de intraguild y podrá editar y
eliminar el contenido que no este relacionado con las funciones intraguild.
3. GuildMember
Miembro general, este miembro solo tendrá permisos para contenidos
generales y únicamente podrá editar sus contenidos, pero no eliminarlos.
29
4. Ally Guildmaster
Miembro jefe de una guild aliada, podrá postear eventos únicamente, y
postear comentarios en las zonas que tenga visibles.
5. Ally Guildmember
Miembro general de una guild aliada, únicamente podrá ver unas pocas
zonas visibles, pero no postear ningún tipo de contenido ni comentario.
2. Funciones intraguild:
1. Tesorero
Miembro dedicado a repartir y mantener un control de los items de la guild,
será el encargado de administrar la tienda interna.
2. Organizador de eventos
Miembro dedicado a organizar los eventos, será el único que pueda crear
eventos de la guild y el único que pueda organizar partys para los mismos.
3. Organizador de woes
Miembro dedicado a organizar las woes, será el único que pueda crear
estrategias de woes y el único que pueda organizar partys para las mismas.
3. Funciones web:
1. Editor
Rol para todo miembro al cual se le permita postear guías de ayuda o
estrategias para mvp de la guild.
2. Moderador foros
Rol para todo miembro que ayude a controlar el posteo de temas en el foro.
3. Uploader de videos
Rol para todo miembro al cual se le permita enlazar sus videos.
30
4. Controlador de logros
Rol para el miembro de la guild que se encargue de controlar la asignación
de logros del resto de miembros.
4.2. Tipos de Contenido:
Para poder implementar las funcionalidades listadas, se van a crear los siguientes tipos de
contenido.
1. Apply
Este contenido se utilizará para que usuarios no miembros de la guild puedan
solicitar su ingreso en la misma. En este contenido se ha de encontrar representada
la información básica del personaje del usuario, los hábitos de juego de la persona,
además de alguna información más que pueda ser interesante para la guild.
También ha de ser posible que este tipo de contenido tenga una puntuación que le
darán los miembros de la guild, para poder decidir si la solicitud es aceptada o no.
Una vez publicado este contenido únicamente puede ser visto por los miembros de
la guild, igual que su votación, ni la persona que lo postea ni los integrantes de
guilds aliadas han de poder ver el contenido. Este contenido únicamente puede ser
publicado por usuarios no registrados.
2. Asistencia a evento
Este contenido se utilizará para que los miembros de la guild confirmen o soliciten
(dependiendo de si es cupo cerrado o no) su asistencia a un evento. En ese
contenido se ha de encontrar referenciado el usuario que solicita la asistencia, el
personaje con el cual quiere asistir, y a que evento se refiere. Una vez publicado
este contenido únicamente puede ser visto por los mandos de la guild, por el
encargado de eventos y por el usuario que posteo el contenido. Este contenido sólo
puede ser publicado por miembros de la guild.
31
3. Asistencia a woes
Este contenido se utilizará para que los miembros de la guild confirmen su
asistencia a las woes de la semana. En ese contenido se ha de encontrar
referenciado el usuario que confirma la asistencia, el personaje con el cual va a
asistir y a que woes va a asistir. Una vez publicado este contenido únicamente
puede ser visto por los mandos de la guild, por el encargado de woes y por el
usuario que posteo el contenido . Este contenido sólo puede ser publicado por
miembros de la guild.
4. Encuesta
Este contenido se utilizará para someter a votación aspectos de interés general de la
guild, su estructura es la de una encuesta normal, la pregunta que se somete a
votación y las posibles respuestas. Únicamente los miembros de la guild pueden
votar en dichas encuestas. Este contenido sólo puede ser creado por uno de los
mandos de la guild.
5. Estrategia woes FE
Este contenido se utilizará para publicar una guías sobre como defender un castillo
de las woes fe en concreto. En este contenido se ha de encontrar la ciudad a la que
pertenece el castillo, un esquema de cada una de las salas del castillo con la
disposición de los miembros de la guild, además de una explicación escrita para
aclarar los esquemas y dar las indicaciones que se crean necesarias. Este contenido
ha de ser visible tanto para lo miembros de las guild como para los miembros de las
guilds aliadas. Este contenido solo puede ser creado por el organizador de woes.
6. Estrategia woes SE
Este contenido se utilizará para publicar una guías sobre como defender un castillo
de las woes se en concreto. En este contenido se ha de encontrar la ciudad a la que
pertenece el castillo, esquemas de las diferentes zonas del castillo donde se tenga
que poder montar un precast, un listado de las banderas para llegar a cada una de
esas zonas y una explicación escrita para aclarar los esquemas y dar las
indicaciones que se crean necesarias. Este contenido ha de ser visible tanto para lo
32
miembros de las guild como para los miembros de las guilds aliadas. Este
contenido solo puede ser creado por el organizador de woes.
7. Estrategia MvP
Este contenido se utilizará para realizar una guía del procedimiento a seguir a la
hora de matar un MvP. En este contenido se ha de encontrar un listado con la gente
mínima que se requiere para poder lleva a cabo la estrategia, una explicación escrita
de dicha estrategia, puede ir acompañada de imágenes o no y un video donde se vea
la estrategia puesta en funcionamiento. Únicamente los miembros de guild pueden
ver este contenido. Este contenido sólo puede ser publicado por editores.
8. Evento
Este contenido se utilizará para informar sobre la existencia de un futuro evento. En
este contenido se ha de encontrar la fecha en que se realizará el evento, donde se
reunirá la gente para él, una breve descripción del cometido del evento y si es
necesario un link a una de las estrategias de mvp disponibles. Este contenido
únicamente ha de ser visible para los miembros de la guild. Este contenido solo
puede ser creado por el organizador de eventos.
9. WoE
Este contenido se utilizará para informar sobre la existencia de una WoE. En este
contenido se ha de encontrar la fecha en que se realizará el evento, donde se reunirá
la gente para él, una breve explicación de los objetivo de la woe y si es necesario un
link a una de las estrategias de castillo disponibles. Este contenido únicamente ha
de ser visible para los miembros de la guild. Este contenido solo puede ser creado
por el organizador de woes.
10. Guía Quest
Este contenido se utilizará para crea guías para ayudar a los usuarios a completar
quest del juego. En este contenido se ha de encontrar toda la información de la
quest como son el lvl mínimo para hacerla, los items que se requieren y su
recompensa, ya sean items o experiencia, además por supuesto ha de tener un
33
escrito de como realizar la quest paso a paso, este escrito puede ir acompañado o no
de imágenes. Este contenido ha de ser visible tanto para miembros de la guild como
para aliados. Este contenido sólo puede ser publicado por editores.
11. Guild secundaria
Este contenido se utilizará para tener un listado de las guilds secundarias
pertenecientes a personas de la guild. Este contenido ha de indicar a que usuario
pertenece esa guild y con que fin fue creada. Este contenido puede ser visto tanto
por miembros de guild como aliados. y sólo puede ser creado por miembros de la
guild.
12. Noticia
Este contenido se utilizará para informar a los integrantes de la guild de algún
suceso importante. Este contenido podrá ser leído exclusivamente por los miembros
de la guild. Este contenido solo podrá ser creado por mandos de la guild.
13. Party de evento
Este contenido servirá para informar a los usuarios de como han quedado
confeccionadas las partys para un evento en concreto. Este contenido sólo puede
ser visto por los usuarios de la guild y únicamente puede ser creado por el
organizador de eventos.
14. Party de woe
Este contenido servirá para informar a los usuarios de como han quedado
confeccionadas las partys para una woe. Este contenido sólo puede ser visto por los
usuarios de la guild y únicamente puede ser creado por el organizador de woes.
15. Personaje roster
Este contenido servirá para tener un listado de los personajes de los que dispone la
guild para eventos y woes. En este contenido ha de quedar reflejado el usuario al
que pertenece el personaje y toda la información básica del personaje, job, lvl etc.
Este contenido solo puede ser visto y creado por los miembros de la guild.
34
16. Video de woes
Este contenido es para realizar un repositorio de los videos de woes creados por
miembros de la guild y aliados. Aquí constará la fecha del video, la guild a la cual
pertenece el personaje con el que se grabó el video y un embed del video en
cuestión.
Este contenido puede ser posteado por aquellos miembros que tengan permiso
explicito para hacerlo.
17. Foros
Con este contenido se pretende tener una zona donde los miembros de la guild
puedan hablar sobre vario temas, para ello se crearan los siguientes foros:
1. GuildMasters
1. Discusión general
Foro para que los guildmasters de las diferentes guilds de la alianza
discutan cualquier tema referente a la misma.
2. Planificación de WoEs
Foro para que los guildmasters de las diferentes guilds de la alianza
concreten los objetivos a realizar en cada una de las WoEs.
2. Discusión general
1. Eventos
Foro para hablar de como salieron los eventos realizados, poner
imágenes de ellos etc.
2. Sugerencias
Foro para que los miembros de la guild puedan hacer sugerencias
sobre cualquier cosa a los mandos de la guild.
35
3. WoEs
Foro destinado a discutir la actuación de la guild y alianza en cada
una de las woes.
3. Comercio
1. Compra
Foro para que los miembros de la guild pongan en que items están
interesados para ver si algún otro miembro de la guild puede
vendérselo.
2. Venta
Foro para que los miembros de guild informen al resto de que items
disponen para la venta.
4. Ayuda
1. Quest
Foro destinado por si algún miembro se queda encallado con una
quest y las guiás no son suficiente.
2. Jobs
En realidad no se tratará de un foro sino de varios, uno por cada
rama. Estos foros servirán para debatir sobre tipos de builds de las
distintas ramas o para pedir ayuda sobre la build de tu personaje.
5. Offtopic
1. Fan art
Foro para que los miembros de la guild que quieran compartir sus
creaciones lo hagan.
36
2. Fotos de los miembros
Foro para que los miembros posteen sus fotos .
3. Full offtopic
Foro para postear todo lo que no tenga lugar en el resto de foros.
4. Ocio
Foro para discutir sobre otros pasatiempos a parte del juego, como
series, libros etc.
5. Quedadas
Foro para organizar quedadas entre la gente de la guild.
18. Logro
Este contenido representará un logro conseguido. Estos logros serán creados por el
encargado de controlar los logros, normalmente representarán hitos difíciles de
conseguir en el juego. Cada logro tendrá una pequeña descripción de lo que
representa, una puntuación asociada y si así se determina una imagen representativa
del logro.
19. Item de tienda
Este contenido sirve para tener un listado de los items conseguidos por lo miembros
de la guild de forma común, ya sea obtenido de cofres de castillos, loot de cualquier
evento o donación directa de un miembro. El contenido contará de una imagen
representativa de dicho objeto, una descripción de él , la categoría de item y su
precio expresado en saldo interno. Este contenido solo será visible para los
miembros de la guild.
37
20. Compra
Este contenido está destinado a reflejar las compras realizas por los miembros en la
tienda de la guild. El contenido estará formado por el usuario que ha comprado el
item, el item que ha comprado y la cantidad de items comprados. Este contenido
solo será visible para el tesorero de la guild.
4.3. Bloques
Para completar las funcionalidades se crearán los siguientes bloques que añadan
información adicional.
1. Calendario de eventos
Bloque con un calendario donde estarán indicados lo eventos que se realicen cada
uno d ellos días. Este bloque sólo será visible para miembros de la guild.
2. Hall of fame
Bloque que presentará un ranking con los miembros que tengan mayor puntuación
acumulada por la asignación de logros. Este bloque no será visible para invitados.
3. Menú de la tienda de la guild
Bloque que presentará el menú de acceso a los items de la tienda, categorizados por
tipo. Este bloque sólo será visible para miembros de la guild.
4. Últimos items añadidos a la tienda
Bloque que presentará la lista de los últimos items que se han añadido a la tienda.
Este bloque sólo será visible para miembros de la guild.
5. Últimas compras realizadas
Bloque que presentará la lista de las últimas compras realizadas por los usuarios.
Este bloque sólo será visible para el tesorero de la guild.
38
6. Información del usuario sobre la tienda
Bloque que mostrará a cada usuario su saldo interno actual y la última compra que
realizó. Este bloque sólo será visible para miembros de la guild.
7. Control de castillos
En realidad no se trata de un único bloque, sino de una plantilla para bloques. En
este bloque se mostrará la información principal de un castillo, Nombre, dueño,
cofres que da al día, coste de la inversión, nivel de comercio etc. Este bloque no
será visible para invitados.
8. Menú de invitados
Tendrá un link a las dos únicas secciones que tienen acceso los invitados, creación
de apply y repositorio de videos de WoEs.
39
40
5. Instalación y Configuración
5.1 Requerimientos del Sistema
Para la instalación de Drupal requerimos 3 cosas a parte del software propio del
framework:
1. Un servidor web que ejecute scripts PHP.
2. PHP, versión 4.1 o superior de PHP. Extensión XML de PHP (para los módulos
bloggerapi, drupal, jabber, ping).
3. Un servidor de base de datos soportado por PHP.
5.2 Instalación del Servidor Web y Drupal
Para agilizar y facilitar la fase de instalación se opta por usar wampserver, que en una sola
instalación nos proporciona el servidor web Apache versión 2.2.11, el entorno PHP5
versión 5.0.3, la base de datos MySQL versión 5.1.36, así como el gestor PHPmyadmin
versión 3.2.0.1. La versión de php que incorpora por defecto el servidor wamp no es
compatible con el núcleo de Drupal utilizado, por lo que se debe descargar de la propia
página de wampserver la versión anterior, 5.2.11.
Una vez descargado el servidor wamp y el módulo php con la versión que nos interesa.,
deberemos instalar los componentes en el ordenador, primero el servidor wamp y después
el módulo de php con la versión anterior. Una vez instalado todo debemos seleccionar en la
configuración del servidor wamp que utilice la versión anterior que hemos instalado
(Figura 5.1), ya que sino por defecto seguirá usando la versión que el traía por defecto.
41
Figura 5.1
El siguiente paso es crear la base de datos que va a utilizar nuestra web. Accederemos a
PHPmyadmin y crearemos una nueva base de datos (Figura 5.2).
Figura 5.2
Una vez creada la base de datos, descomprimiremos el archivo de la instalación de Drupal
(descargado anteriormente). Copiaremos la carpeta en el directorio www del servidor
wamp y le cambiaremos el nombre por el nombre que queramos darle a la web. Por
defecto el idioma de nuestro software Drupal será el inglés, para traducirlo deberemos
descargar el pack de traducción que nos interese y descomprimirlo en la misma carpeta de
instalación.
42
Ahora para seguir con la instalación de Drupal, accederemos mediante el navegador a la
dirección http://localhost/nombredelacarpeta y tendremos un asistente que nos guiará por
la instalación del software, el asistente nos permitirá elegir entre los lenguajes instalados
(Figura 5.3).
Figura 5.3
En el siguiente paso nos pedirá la información de la base de datos, nombre, usuario y
password (Figura 5.4).
Figura 5.4
En opciones avanzadas encontraremos algunos datos adicionales que podria ser necesario
configurar en algún caso como por ejemplo un prefijo para las tablas de la base de datos,
43
puerto y servidor de la base de datos, aunque en nuestro caso no será necesario modificar
ninguna de esas opciones.
Después nos pedirá la información básica del sitio, nombre, mail, la información sobre la
cuenta de superadministrador, usuario, password y mail, zona horaria predifinida y si se
desea activar las URL's limpias, está opción por defecto no está disponible posteriormente
se explicará como activarlas (Figura 5.5).
Con esto finaliza el proceso de instalación de Drupal y queda listo para su uso.
44
Figura 5.5
Lo siguiente es configurar la información básica del sitio, pero antes de seguir activaremos
como anteriormente mencionamos el uso de URL's limpias. Para ello lo único que
debemos hacer es acceder al archivo httpd.conf del servidor apache y descomentar la linea
que pone LoadModule rewrite_module modules/mod_rewrite.so. Una vez hecho esto
45
debemos reiniciar nuestro servidor web y después ir a nuestro sitio web en el área de
administración y acceder a Administrar > Configuración del sitio > URLS limpios
(Figura 5.6) y acativar la opción. Mediante las URL's limpias conseguimos que las
direcciones de nuestro sitio en vez de ser del tipo http://web.es/?q=node/3 pasen a
ser del tipo http://web.es/node/3, mucho más fáciles de recordar para el
usuario.
Figura 5.6
Ahora si podemos ir a la configuración de nuestro sitio, podemos acceder a ella yendo a
Administrar > Configuración del sitio > Información del sitio (Figura 5.7) donde
podremos introducir los siguientes datos:
•
Nombre
El nombre del sitio web
•
Dirección de correo
La dirección De en los correos automáticos enviados durante el registro y tras la
solicitud de nueva contraseña, y otros avisos.
•
Eslogan
El lema, declaración o frase vendedora de su sitio.
46
•
Misión
La declaración de misión o de enfoque de su sitio.
•
Mensaje del pie de página
•
Este texto se mostrará al final de cada página. Es útil para agregar un aviso de
derechos de autor a sus páginas.
•
Nombre del usuario anónimo
El nombre usado para indicar usuarios anónimos.
•
Página inicial predeterminada
La página de inicio muestra el contenido de este URL relativo.
47
Figura 5.7
Algunos de estos datos ya los pudimos introducir en el momento de la instalación pero de
está manera pueden ser modificados en cualquier momento. Con esto acabamos la
instalación y configuración básica de nuestro sitio, el próximo paso será la instalación de
los módulos que vayamos a usar para complementar la funcionalidad de la página.
48
5.3 Instalación de Módulos y Temas para Drupal
El proceso de instalación del módulo es común para cualquier módulo que queramos
instalar en nuestro sitio.
Lo primero que debemos hacer es descargar el módulo a instalar, una vez lo tengamos
únicamente debemos descomprimirlo y colocarlo dentro de la carpeta en la que se deben
colocar todos los módulos adicionales, su ruta es sites/all/modules (se recomienda instalar
aquí y no en sites/default/modules, ya que dado el caso de tener una instalación multisitio
tendríamos el módulo disponible para todos los sitios). Después de haberlo colocado en su
lugar la carpeta del módulo, únicamente debemos acceder a Administrar > Construcción
del sitio > Módulos buscar el módulo en el listado, activar su casilla de verificación y
guardar (Figura 5.8). Del resto del proceso como puede ser creación de las tablas de la
base de datos, creación de links etc se encarga Drupal de realizarlo mediante los hooks
apropiados.
Figura 5.8
49
El proceso de instalación de los temas de Drupal es análogo al proceso de instalación de
los módulos pero con dos pequeñas diferencias, la primera es que la ruta en la que
debemos situar la carpeta del tema es sites/all/themes en lugar de sites/all/modules
(nuevamente lo hacemos en el directorio all y no en el default por las mismas razones que
lo hacíamos con los módulos). La otra diferencia es que a la hora de activar el tema
deberemos dirigirnos a Administrar > Construcción del sitio > Temas establecerlo como
predeterminado y guardar (Figura 5.9).
Figura 5.9
Unas de las peculiaridades que tiene Drupal es que nos da la posibilidad de establecer un
tema para el sitio y otro para las áreas de administración, esto nos es beneficioso sobretodo
a la hora de desarrollar temas nuevos, ya que si el tema tiene algún error, siempre
podremos acceder al área de administración para desactivarlo, además de poder elegir un
tema con una interfaz más legible aunque menos atractiva para dichas áreas. Así que se
recomienda dejar uno de los temas que proporciona Drupal por defecto para las áreas de
administración.
50
6. Implementación
6.1 Módulos del Core Utilizados
Los módulos del core son aquellos que vienen provistos con la instalación del software de
Drupal. Podemos diferenciar entre dos tipos, los obligatorios y los opcionales.
6.1.1 Obligatorios
Estos módulos son los que manejan el funcionamiento básico del software y sin los cuales
no podría funcionar.
Block
Este módulo controla las cajas que se muestran alrededor del contenido principal.
Filter
Este módulo maneja el filtrado de contenido en preparación para mostrarlo.
Node
Este módulo permite que se envíe contenido al sitio y que se despliegue en páginas.
System
Este módulo provee la gestión de la configuración general del sitio por administradores.
User
Este módulo administra el registro de usuarios y el sistema de inicio de sesión.
6.1.2 Opcionales
Estos son módulos que también vienen en la instalación básica de Drupal, pero que no son
necesarios para el funcionamiento del software en si, aunque si añaden algunas de las
funcionalidades más habituales en los sitios web
51
Comment
Este módulo añade la funcionalidad de publicar comentarios en los contenidos publicados
para opinar o discutir sobre el contenido en cuestión. El módulo nos deja configurar si
queremos que se activen o no los comentarios para cada tipo de contenido y varias
opciones más como por ejemplo el número de mensajes mostrados, la disposición etc.
Este módulo además de añadirnos la funcionalidad comentada, es requerido para el
funcionamiento del módulo Forum.
Database logging
Este módulo anota y registra eventos del sistema en la base de datos.
Forum
Este módulo permite la construcción de foros de discusión en nuestro sitio. Nos añade la
infraestructura básica para poder crear las diferentes categorías y topics. Como ya se ha
dicho, este módulo requiere del módulo comment para funcionar, pero también requiere
que el módulo taxonomy esté activado.
Help
Módulo que administra el despliegue de ayuda en linea que puedan tener el resto de
módulos implementados.
Locale
Este módulo activa la función de traducción de interfaz. Este módulo nos presenta una lista
de las cadenas traducibles disponibles en la web y nos permite introducir la traducción para
el idioma en uso. Las cadenas traducibles vienen definidas por una función de la API de
Drupal, esta función, es la función t(), cualquier cadena que pongamos dentro de está
función será contemplada como una cadena que es susceptible de ser traducida.
52
Menu
Este módulo permite a los administradores del sitio personalizar el menú de navegación.
La personalización se resume en añadir o quitar links del menú, y en controlar la
visibilidad de los links ya añadidos.
Path
Este módulo permite cambiar el nombre de cualquier URL del sitio. Gracias a ello
podremos conseguir rutas más amigables para el usuario.
Poll
Este módulo es el encargado de crear toda la funcionalidad de publicación de encuestas y
de controlar los votos de las mismas.
Taxonomy
Este módulo permite la categorización del contenido mediante términos que después
pueden ser mostrados como etiquetas. Con este módulo Drupal intenta hacer un pequeño
acercamiento a lo conocido como web semántica.
Update Status
Este módulo es e encargado de comprobar las actualizaciones de Drupal disponibles, así
como las de los módulos y temas instalados.
53
6.2 Módulos Adicionales Instalados
Debido al número de módulos instalados, se va a hacer un listado separado por
paquetes/categorías de los módulos.
6.2.1 Access Control
ACL
Este módulo únicamente se encarga de incorporar una API para el control de acceso que
después puede ser utilizada por otros módulos.
Content Acces
Este módulo nos permite configurar para cada uno de los tipos de contenido disponibles en
nuestra web, las opciones de visibilidad y edición basándose en la propiedad del contenido
y el rol del usuario.
Gracias a este módulo podemos definir que “secciones” van a ser visibles y cuales no para
cada rol del sitio.
Forum Access
Este módulo nos permite aumentar las posibilidades de nuestro foro permitiendo crear
foros privados y añadir moderadores a cada uno de los foros. Este módulo agrega un rol al
sitio llamado moderator, el cual ya trae los permisos predefinidos para poder actuar como
moderador de los foros, por este motivo el rol moderador no hará falta crearlo
manualmente.
54
6.2.2 Administración
Administration menu
Este módulo Provee un menú desplegable para la mayoría de las tareas administrativas y
otros destinos comunes (para los usuarios con los permisos apropiados), con este módulo
los administradores del sitio pueden acceder directamente a las opciones de administración
sin necesidad de pasar por las páginas previas. No añade ninguna funcionalidad nueva para
el sitio, pero si permite un uso más cómodo del él.
6.2.3 CCK
Este conjunto de módulos es una de las herramientas más usadas de Drupal, CCK (Content
Construction Kit) provee al usuario de una forma fácil y rápida de crear tipos de contenido
sin necesidad de saber programar. Además también permite añadir nuevos campos a
cualquier tipo de contenido existente.
Content
Es el núcleo del paquete de módulos CCK és el que permite la creación del nuevo tipo de
contenido y permite añadir los campos básicos al contenido. Todo el resto de módulos
listados a continuación dependerán de este para su funcionamiento
CCK Time
Permite añadir campos de tipo tiempo a los tipos de contenido.
Content Copy
Activa la posibilidad de importar y exportar la definición de campos.
Content Permisions
Añade la posibilidad de definir permisos de visibilidad y edición para cada uno de los
campos creados mediante cualquier submódulo de CCK.
55
Content Templates
Crea plantillas de visualización de los campos definidos y permite modificar algunas de
sus características de visualización.
Email
Permite añadir campos de tipo email a los contenidos.
Fieldgroup
Permite crear grupos de campos (fieldsets) para separar los campos por algún criterio o por
simple esteticismo.
FileField
Define los campos de tipo fichero, este módulo nuevamente es más una herramienta para
otros módulos que una herramienta a usar por si solo. Cualquier módulo que provea una
subida de archivos o referencias a ellos, dependerá de este módulo para su funcionamiento.
ImageField
Permite añadir un campo de tipo imagen a los contenidos.
Link
Permite añadir un campo de tipo link a los contenidos.
Node reference
Permite añadir un campo que haga referencia a otro nodo (contenido) publicado en el web.
Number
Permite añadir un campo de tipo numérico.
56
Option Widgets
Permite añadir campos de selección de tipo checkbox o radiobutton para campos de texto y
numéricos.
Text
Permite añadir un campo de tipo texto.
6.2.4 Media
Este conjunto de módulos es otra extensión del CCK pero que solo se centra en la adición
de campos con contenido multimédia.
Embedded Media Field
Esté módulo es el núcleo de este paquete de módulos, provee de un motor para insertar
contenidos multimedia de diferentes proveedores.
Embedded Video File
Permite añadir campos para insertar videos incrustados en los tipos de contenidos.
Media: Megavideo
Este módulo provee de las reglas especificas para que el módulo Embedded Video File
pueda incrustar videos desde Megavideo.
Media: YouTube
Este módulo provee de las reglas especificas para que el módulo Embedded Video File
pueda incrustar videos desde YouTube.
Únicamente se han añadido los módulos para incrustar videos desde dos proveedores
diferentes por considerarse lo más usados entre el ámbito de players para subir sus videos,
aunque se podría haber optado por añadir más proveedores como vimeo o google videos
entre otros.
57
6.2.5 Fecha y Hora
Este conjunto de módulos es otra extensión del CCK pero que solo se centra en la adición
de campos de fechas y tiempo.
Date
Este módulo permite añadir campos y controles (widgets) de fecha/hora.
Date API
Este módulo únicamente se encarga de incorporar una API de fechas que puede ser usada
por otros módulos.
Date Timezone
Este módulo es requerido cuando se usa Date API. Modifica la gestión de zona horaria del
sitio y del usuario para usar nombres de zonas horarias en vez de un desplazamiento.
6.2.6 Views
Views
Este módulo provee a Drupal de una forma sencilla de crear listas y consultas a la base de
datos sin necesidad de tener conocimientos de programación. Este módulo únicamente
incluye el motor para realizar estas cosas, pero no la interficie para crear dichas listas y
consultas.
Views UI
Este módulo provee a Drupal de la interficie gráfica para crear las vistas mediante el
módulo views.
58
Views Exporter
Este módulo consigue provee de la función de exportar a views, mediante la cual podremos
obtener el código a incluir en un módulo programado para que al instalarse instale también
la vista.
6.2.7 Votación
Voting API
Este módulo únicamente se encarga de incorporar una API de votación para que pueda ser
usada por otros módulos.
Vote Up/Down
Este módulo provee un widget para la votación positiva/negativa par aque otros módulos lo
usen.
Vote Up/Down Nodes
Este módulo permite agregar un widget de votación de vote up/down a los tipos de
contenido seleccionados.
Chaos tools
Este módulo incluye una API de herramientas que pueden ser usadas por otros módulos, el
módulo Vote Up/Down requiere de ella.
59
6.2.8 Otros
Event
Este módulo proporciona un API de calendarización, para desplegar y exportar calendario.
CKEditor
Este módulo activa el uso de un editor de texto
WYSIWYG
sustituyendo al editor de texto
plano incorporado por defecto. Este módulo permite elegir que roles tendrán acceso a este
editor y cuales no.
Un editor WYSIWG es un editor de texto con formato que permiten escribir un documento
viendo directamente el resultado final.
IMCE
Este módulo provee a Drupal de una interfaz sencilla para poder incluir imágenes desde
disco duro a nuestros textos, basado en una aplicación tipo ftp que permite subir la imagen
al servidor y colocarla en nuestro texto.
Token
Este módulo provee de una API compartida para el remplazo de comodines textuales con
datos concretos.
PathAuto
Este módulo proporciona un método para que los módulos puedan crear automáticamente
alias de URLs del contenido que gestionan. Este módulo provee de un sistema de
reemplazo automatizado de urls según el tipo de contenido que se está publicando. De esta
manera podemos conseguir que por ejemplo que las rutas de nuestro sitio sean de la forma
http//:miweb/tipodecontenido/titulodelcontenido en vez del tipo http//:miweb/node/id
60
6.2.9 Ragnarok Guild (módulos de desarrollo propio)
Achievements
Módulo que añade un sistema de logros. Permite crear el tipo de contenido logro, que
después puede ser asignado y desasignado a los usuarios. El módulo también mantiene la
puntuación que van acumulando los usuarios al ir consiguiendo los logros y permite ver el
listado y puntuación de los logros de cada uno de los usuarios en su perfil. Este módulo
puede funcionar en cualquier instalación de Drupal.
Castle Control
Este módulo añade unos formularios para poder añadir/eliminar unos bloques que
contendrán toda la información básica sobre un castillo. Este módulo puede funcionar en
cualquier instalación de Drupal.
Guild Shop
Este modulo proporciona una tienda para items de Ragnarok Online que trabaja con saldo
propio, es decir, los items no se compran con dinero real, sino con un crédito que otorga el
encargado de la tienda. Además de la tienda añade el tipo de contenido Item de tienda y
compra, uno para poder añadir productos a la tienda y el otro para mantener una constancia
de los items que se van comprando en la tienda. Este módulo puede funcionar en cualquier
instalación de Drupal.
Assistance
Módulo que añade a Drupal la posibilidad de crear un tipo de contenido para confirmar la
asistencia a los eventos futuros (tanto normales como de WoEs) publicados y que su fecha
de realización aun no haya pasado. A la hora de crear el contenido nos dejará elegir un
evento disponible y con que personaje del roster vamos a asistir al evento. No deja crear
dos asistencias para un mismo evento ni que dos personas elijan un mismo personaje para
el mismo evento. Este módulo solo funciona completamente en esta instalación de Drupal
ya que requiere que los tipos de contenido Evento y WoEs estén creados.
61
Party
Módulo que complementa al módulo Assistance, mediante este módulo obtenemos el
método para poder crear partys, añadir miembros o eliminarlos de ellas en función de las
asistencias creadas con el módulo anterior. Este módulo solo funciona completamente en
esta instalación de Drupal al igual que al módulo que complementa por motivos derivados
de la dependencia de los módulos entre si.
6.3 Creación de Tipos de Contenidos mediante CCK
La comunidad de Drupal nos ofrece una potente herramienta para la implementación de
tipos de contenido sin necesidad de tener que picar código, esta herramienta es el módulo
CCK (Construction Content Kit) que ha sido utilizada para crear la mayor parte de los
tipos de contenido del sitio web. Por esta razón se va a explicar como crear un tipo de
contenido de muestra paso por paso.
6.3.1 Creación del Tipo de Contenido
Lo primero que debemos hacer es instalar el módulo CCK y todos los submódulos
necesarios para tener disponibles los tipos de campos que queramos añadir. El proceso de
instalación de módulos ya se explicó en el punto 5.3 de este documento.
Una vez tenemos instalados los módulos hemos de crear un nuevo tipo de contenido, esto
lo hacemos accediendo a Administrar > Administración de contenido > Tipos de
contenido y acceder a la pestaña Añadir tipo de contenido. Una vez estemos situados en
la pestaña Añadir tipo de contenido deberemos rellenar el formulario que consta de:
1. Identificación (Figura 6.1)
Información básica relativa al tipo. Consta de Nombre, se trata del nombre del tipo
de contenido. Este nombre será el que sistema muestre a los usuarios en los
diferentes apartados del sitio, por tanto debe ser un nombre legible para las
personas. Tipo, es el nombre con que Drupal conocerá el tipo de contenido, se
62
usará internamente para trabajar con este tipo de contenido, el nombre únicamente
puede incluir letras minúsculas, números y guiones bajos. Descripción, la
descripción servirá de ayuda para los usuarios para que se hagan una idea general
sobre el tipo de contenido. La descripción se mostrará en el listado de creación de
tipos de contenido.
Figura 6.1
2. Opciones del formulario de envío (Figura 6.2)
Información sobre como se mostrará al usuario el formulario de creación del
contenido. Consta de Titulo, valor de la etiqueta del titulo que se muestra al
usuario. Cuerpo, valor de la etiqueta del cuerpo del contenido que se muestra al
usuario. Número mínimo de palabras, en el caso de que se quiera definir un
63
número mínimo de palabras que deba tener el cuerpo del contenido. Explicación o
directrices para envíos, ayuda o instrucciones para el usuario.
Figura 6.2
3. Opciones de flujo de trabajo (Figura 6.3)
Permite establecer las opciones predeterminadas para el tipo de contenido a la hora
de la creación de un nodo. Consta de Publicado, indica si el nodo será publicado
cuando se cree. Promocionado en la pagina principal, indica si se verá en la
pagina de inicio del sitio. Pegajoso en la cima de las listas, indica si se situará al
principio de la pagina inicial de forma permanente. Crear nueva revisión, define si
se crea o no una nueva revisión cuando el nodo se modifique. Soporte
multilenguaje, permite habilitar o no el soporte multilenguaje.
64
Figura 6.3
4. Opciones de comentarios (Figura 6.4)
Define las opciones para configurar el comportamiento de los comentarios de este
tipo de contenido. Consta de Opciones predefinidas para comentarios, define si
estarán activos y en caso de estar activos si se podrán solo leer o leer y escribir. El
resto de opciones solo tiene sentido modificarlas en caso de que los comentarios
estén activos, son las siguientes, Modo predefinido de visualización, puedes
seleccionar entre lista plana o lista de hilos. Ordenación predefinida de
visualización, permite elegir si se mostraran primero los comentarios más nuevos o
los más antiguos. Comentarios predefinidos por pagina, número de mensajes
mostrados en cada pagina.. Controles de comentarios, permite activar un menú para
que cada usuario puede controlar el orden y el tipo de visualización de los
comentarios. Comentario anónimo, define si los usuarios anónimos pueden
comentar o no. Campo asunto del comentario, define si los comentarios han de
tener un campo asunto o no. Vista previa del usuario, define si los usuarios deben
previsualizar obligatoriamente u opcionalmente los comentarios. Ubicación de
formulario de envío de los comentarios, define donde se mostrara el formulario de
envió de comentarios, puede ser en una pagina a parte o mostrar al final de la
pagina.
65
Figura 6.4
66
Una vez creado el tipo de contenido buscaremos en la lista el tipo de contenido recién
creado y accederemos a Configurar los campos y nos encontraremos con una lista de
campos (Figura 6.5) que no podremos modificar o eliminar pero si ordenar, estos campos
provienen del núcleo o de otros módulos instalados. Desde la sección add podremos añadir
campos o grupos de campos.
Figura 6.5
6.3.2 Creación de grupos de campos
Los grupos son elementos que nos permiten juntar diferentes campos para mejorar la
presentación y la lógica del formulario. Para crear un Nuevo Grupo (new group), debemos
rellenar la Etiqueta, nombre que se mostrará en el formulario. Nombre del grupo, nombre
con que Drupal trabajará internamente con el grupo. Para ordenar el grupo solamente habrá
que arrastrarlo a la posición deseada.
67
6.3.3 Creación de campos
Para crear un Nuevo Campo (new field), debemos rellenar la Etiqueta, nombre que se
mostrará en el formulario. Nombre del campo, nombre con que Drupal trabajará
internamente con el campo. Tipo de datos, seleccionaremos de un listado el tipo de dato
que queremos que contenga el campo, el listado d ellos tipos de datos listados dependerá
de la cantidad de módulos que tengamos instalados. Widget, define el tipo de elemento o
control de formulario que se mostrará al usuario para el campo. Los tipos de widgets
dependen de el tipo de dato que sea el campo.
Una vez damos a guardar el sistema nos mostrará un formulario de configuración que
variará dependiendo del tipo de dato y el widget elegido. En la figura 6.6 se muestra un
ejemplo de formulario de configuración para un campo de mail.
Figura 6.6
68
6.3.4 Asociar un campo con un grupo
Para relacionar un campo con un grupo únicamente debemos arrastrar el campo debajo y a
la derecha del grupo. En la figura 6.7 se muestra como quedaría un campo asociado a un
grupo que ha sido situado debajo del titulo del formulario.
Figura 6.7
6.3.5 Mostrar Campos
Para finalizar la creación del tipo de contenido, podemos definir la visualización de cada
uno de los elementos añadidos mediante CCK en la presentación del nodo. Para ello
accederemos a la pestaña Display Fields (figura 6.8). Para cada campo podemos
especificar la visualización tanto para el resumen del nodo (teaser) como para el nodo
completo. Las opciones que nos dan son elegir si la etiqueta del campo se va a mostrar en
la misma linea que el contenido del campo o encima y si queremos que el campo sea
visible o no.
69
Figura 6.8
6.4 Creación de Secciones mediante Views
El módulo views es otro de los módulos que nos ofrece la comunidad de Drupal para poder
desarrollar nuestro sitio web sin necesidad de tener que picar nada de código, esta vez la
funcionalidad del módulo es la de crear páginas dinámicas (conocidas como vistas)
alimentadas con los contenidos del sitio. Con las vistas podemos crear contenidos
dinámicos de muchos tipos:
•
Un bloque con un listado de los últimos usuarios registrados en el sitio.
•
Una tabla de datos con campos ordenables.
•
Una página que muestre todos los nodos de un mismo tipo.
Precisamente esté último contenido es el que vamos a utilizar nosotros y así implementar
las secciones del sitio web.
70
6.4.1 Creación de vistas
Una vez más lo primero que debemos hacer es instalar los módulos views y views UI, el
proceso de instalación ya ha sido descrito en el apartado 5.3 de este mismo documento.
Una vez todo instalado nos dirigiremos a Administrar > Construcción del sitio > Views
y seleccionaremos la pestaña Añadir (add).
El primer paso será rellenar el formulario web (Figura 6.9) que consta de:
•
Nombre de la vista
Es el nombre interno para la vista.
•
Descripción de la vista
Es el nombre de la vista tal y como se le mostrará al usuario en el área de
administración de vistas.
•
Etiqueta de vista
Se trata de u campo opcional que permite etiquetar las vistas, para su clasificación
en el área de administración.
•
Tipo de vista
Según el tipo de vista seleccionado podremos construir tipos de vista diferentes, ya
que lo que estamos seleccionando es el elemento principal sobre el que la vista
realizará la consulta. En nuestro caso seleccionaremos Nodo, ya que lo que nos
interesa es hacer un listado de los nodos de cada tipo de contenido.
71
Figura 6.9
Después de rellenar estos campos haremos clic en Next para crear la vista y pasar a la
pantalla de edición (Figura 6.10).En la pantalla de edición de la vista podemos encontrar
varios bloques, pero a nosotros solo usaremos los de basic settings, filtros, sort criteria y
la opción de add display. Si ahora guardásemos la vista ya tendríamos la vista creada
aunque aun no podríamos usarla, para ello debemos definir las opciones de los bloques
mencionados anteriormente, cosa que nos disponemos a hacer a continuación.
72
Figura 6.10
6.4.2 Configuración Básica de la Vista
Del bloque de configuración básica lo primero que necesitamos modificar es el Row Style,
clicaremos sobre el enlace y en el cuadro que nos aparecerá (Figura 6.11)seleccionaremos
Nodo y le daremos a actualizar. Ahora nos aparecerá otro cuadro en el cual nos dejará
elehir si queremos que el nodo se muestre en su modo resumido o completo y si queremos
que se muestren los links al nodo y los comentarios del nodo, dejaremos tal y como nos
aparecen las opciones (Figura 6.12) visualización del nodo en resumen que muestre los
links del nodo y no muestre los comentarios, una vez demos a actualizar otra vez ya
quedará modificada la opción aunque no se guardará finalmente hasta que no demos al
botón guardar. Para saber si la vista ha sido guardada después de realizar un cambio,views
73
mantendrá las opciones modificadas sin guardar resaltas en amarillo para indicarnos que no
han sido guardadas aun.
Figura 6.11
Figura 6.12
El siguiente elemento que nos interesa del bloque de configuración básica es el de Access,
mediante este elemento podremos elegir criterios de acceso sobre la vista. Por defecto es
Unrestricted, caso que nos serviría para una sección pública como puede ser la de los
videos de woes, si por ejemplo la vista que estuviéramos creando ahora fuese al de
noticias, sección que solo pueden ver los miembros de la guild, lo que haríamos seria lo
siguiente, clicariamos en Unrestricted y nos aparecería un cuadro (Figura 6.13) que nos
daría a elegir entre Ninguno, Permiso o Role, en este nuestro caso seleccionaríamos Role y
le dariamos a actualizar y nos aparecería una lista de los roles creados en el sitio (Figura
6.14), únicamente deberíamos elegir los roles para los cuales queremos que sea accesible la
vista y volver a actualizar. Nuevamente quedará indicado que los cambios no están
salvados hasta que no demos a guardar.
Figura 6.13
74
Figura 6.14
Otra opción que podríamos modificar si nos interesa es la de Items to display, para definir
el numero de elementos que queremos que se nos muestre por pagina en la vista. También
podríamos modificar el Use pager que nos dejaría elegir entre un paginador o completo o
uno más minimalista. Con esto ya acabaríamos con la configuración básica de la vista, el
siguiente paso será definir que queremos que se muestre.
6.4.3 Filtrado y Ordenación de la Vista
Lo primero que vamos a definir son los filtros de nuestra consulta para decidir que es lo
que queremos que se muestre. Para añadir un filtro solo hemos de clicar en el símbolo +
del bloque filtros y nos aparecerá una larga lista de filtros (Figura 6.15), por suerte
tenemos una lista desplegable para filtrar los distintos grupos de filtros, en nuestro caso
como lo que queremos crear es una lista con los nodos de un mismo tipo, seleccionaremos
en la lista desplegable Nodo buscaremos el filtro Nodo: Tipo lo seleccionaremos y le
daremos a añadir. Después de esta acción nos aparecerá una lista de con los tipos de
contenido creados y la opción de escoger si queremos mostrar los nodos que sean del tipo
seleccionado o lo contrario (Figura 6.16), en nuestro caso lo más sencillo es seleccionar
que sean del tipo de contenido seleccionado y seleccionar el contenido en cuestión de la
lista y dar a actualizar, con esto ya se habrá añadido el filtro.
75
Figura 6.15
Figura 6.16
Ahora lo que falta es establecer un criterio de ordenación para la vista, el sistema de añadir
el filtro es totalmente análogo al de añadir un filtro, solo que esta vez después de haber
seleccionado el grupo de criterios nodo, buscaremos el criterio Nodo: update date (Figura
6.17), y cuando le demos a añadir nos dejará escoger entre si queremos orden ascendente o
descendente y la precisión que queremos (segundo, minuto, etc) (Figura 6.18). Una vez le
demos a actualizar y guardar ya solo nos quedará añadir un display a nuestra vista para que
sea usable.
Figura 6.17
76
Figura 6.18
6.4.4 Creación de la Presentación de la Vista
La presentación definirá la forma en la que se mostrará nuestra vista, una misma vista
puede tener varias presentaciones. En nuestro caso como lo que queremos es crear las
secciones de nuestra web, las presentaciones que crearemos serán del tipo página, así que
tendremos que seleccionar en la lista desplegable el tipo página y dar a añadir. Después de
esto nos aparecerá un nuevo bloque llamado Page Settings (Figura 6.19) con dos nuevas
opciones a configurar, Ruta, cuando cliquemos en ella nos aparecerá un cuadro de texto
donde podremos introducir la ruta relativa que le queremos dar a la vista para poder
acceder posteriormente a ella (figura 6.20). También tendríamos la opción de añadir esta
ruta a un menú, pero en vista de que las vistas puedan ser usadas en varios menús
diferentes, en vez de añadirla aquí nos encargaremos posteriormente de añadir el elemento
a los menús pertinentes.
Figura 6.19
77
Figura 6.20
6.5 Creación de Menús
Para crear un menú debemos acceder a Administrar > Construcción del sitio > Menús.
Lo primero que debemos hacer es añadir un nuevo menú desde la pestaña Añadir Menú
aquí deberemos rellenar un sencillo formulario (Figura 6.21) formado por el Nombre del
menú, este es el nombre interno mediante el cual Drupal trabajará con el menú. Titulo, es
el nombre que mostrará el menú en las diferentes interfaces del sitio. Descripción, esta
descripción sólo se ve en las áreas de administración y sirve para organizar mejor los
menús creados.
Una vez rellenado y guardado el formulario, tendremos el menú creado, aunque aun no se
mostrará en nuestro sitio, sólo estará disponible en el área de administración de menús, así
que después tendremos que colocarlo en una de las regiones del sitio para tenerlo
disponible, pero antes añadiremos los elementos al menú.
Figura 6.21
78
Después de guardar el formulario anterior, directamente nos encontraremos en el área de
edición del menú, desde la que podremos añadir elementos a nuestro menú, aprovechamos
para decir que si quisiéramos añadir un elemento a un menú ya existente, ya sea uno
predefinido o uno creado por nosotros los pasos serian los mismos, deberíamos acceder al
área de administración de menús de la misma forma que cuando queremos añadir un menú
y clicar sobre el menú que queremos editar.
Desde el área de edición del menú para añadir un elemento seleccionamos la pestaña
Añadir elemento y nos aparecerá un formulario a rellenar (Figura 6.22) con los siguientes
elementos, Ruta, que es el enlace a la página que se cargará cuando el usuario clique en el
elemento del menú. Las rutas pueden ser enlaces internos del sitio o enlaces externos.
Titulo del enlace, será el nombre que aparezca en el menú. Descripción, la descripción
aparecerá cuando se pase el ratón por encima del elemento del menú. Activado,
únicamente los elementos activos serán mostrados, de esta manera podemos hacer que un
elemento deje de mostrarse sin necesidad de eliminarlo para poder recuperarlo en un futuro
sin necesidad de introducir nuevamente todos los datos. Expandido, en caso de tratarse de
un elemento con hijos, si marcamos esta opción el menú aparecerá desplegado mostrando
sus elementos hijos. Elemento padre, sirve para indicar el elemento padre del elemento
que estamos añadiendo, si se trata de un menú de primer nivel el elemento padre será el
nombre que le hemos dado al menú, si queremos que el elemento que estamos añadiendo
sea un submenú de algún elemento, solo deberemos indicar el nombre de dicho elemento.
Peso, el peso representa la posición que tendrá el elemento respecto a elementos del mismo
nivel, los elementos de mayor peso se situarán más abajo que los de menor peso.
79
Figura 6.22
Una vez añadidos los elementos desde la pestaña Listado de elementos encontraremos una
estructura de árbol (Figura 6.23), mediante la cual podremos cambiar el orden de los
elementos arrastrándolos, cambiar las opciones de Activado y Expandido entre otras
cosas.
Figura 6.23
80
Una vez creado el menú y añadidos todos los elementos el último paso a realizar para tener
disponible el menú en el sitio es activarlo en una de las regiones del sitio, para ello
debemos acceder a Adminstrar > Construcción del sitio > Bloques, esto es debido a que
los menús una vez creados Drupal los trata como si fuesen bloques. Una vez en el área de
adminstración de bloques (Figura 6.24) solo tendremos que localizar nuestro menú en la
lista de bloques desactivados, y seleccionar en la lista desplegable que sale al lado del
nombre en que región queremos colocarlo, una vez colocado solo tendremos que guardar
los cambios y el menú ya estará disponible en el sitio.
Figura 6.24
81
En el caso de que quisiéramos crear un menú solo visible para alguno de los roles (el
procedimiento en realidad sirve para cualquier bloque, ya que lo que configuramos es la
visibilidad del bloque) desde la sección de administración de bloques deberíamos dar a la
opción Configurar del menú en cuestión y seleccionar los roles que queremos que puedan
ver el menú (Figura 6.25) de esta manera para el resto de roles será como si ese menú no
existiera.
Figura 6.25
6.6 Creación de Roles y Concesión de Permisos a Usuarios
6.6.1 Creación de Roles
Por defecto Drupal dispone de dos roles predefinidos que no pueden ser eliminados del
sistema, Usuario anónimo y Usuario autenticado. Para añadir nuevos roles deberemos
acceder a Administrar > Administración de usuarios > Roles. Para crear un rol
únicamente deberemos introducir el nombre del nuevo rol en el cuadro de texto (Figura
6.26) y dar a Añadir rol.
Figura 6.26
82
6.6.2 Asignación de Permisos a Roles
Para asignar permisos a los roles tenemos dos opciones, una es desde el área de
administración de Roles (Administrar > Administración de usuarios > Roles) clicar en
editar permisos del rol al que queramos asignar los permisos. La otra opción es acceder a
Administrar > Administración de usuarios > Permisos, en ambas opciones nos
encontraremos una tabla del mismo tipo (Figura 6.27), solo que en la primera opción
únicamente tendremos dos columnas, una para el nombre del permiso y otra para las
casillas de verificación del rol, mientras que en la segunda opción se mantendrá la columna
con el nombre de los permisos, pero tendremos una columna por cada rol creado en el sitio.
Con la segunda opción la asignación de los permisos es más rápida ya que de una sola vez
puedes asignar los permisos a todos los roles, pero puede llegar a ser tediosa si el número
de roles creados en el sitio es muy elevado. Para asignar un permiso a un rol únicamente
hay que marcar la casilla de verificación de dicho permiso.
Figura 6.27
6.6.3 Asignación de Roles a usuarios
Para asignar permisos debemos acceder a Administrar > Administración de usuarios >
Usuarios, ahora tenemos dos opciones para asignar los permisos, la primera y más
cómoda, es seleccionar los usuarios a los cuales queremos asignar un mismo rol activando
su casilla de verificación y a continuación desplegar la lista desplegable de Actualizar
opciones y seleccionar Añadir un rol a los usuarios seleccionados y el rol en cuestión
(Figura 6.28). La segunda opción es acceder a la configuración del usuario clicando sobre
el nombre del usuario ir a la pestaña de Editar y seleccionar los roles que queramos que
tenga de la lista de roles del sitio (Figura 6.29).
83
Figura 6.28
Figura 6.29
84
6.7 Creación de Alias de URL Automáticos mediante Pathauto
Para hacer las rutas más amigables y fáciles de recordar para los usuarios se suele aplicar
un alias a la URL del contenido que se esta creando mediante el formulario de creación de
este. Aunque no es un proceso complicado conseguir que los diferentes usuarios
mantengan un mismo patrón a la hora de crear los contenidos puede llegar a ser
complicado, por estas razones el uso del módulo pathauto es una buena manera de
solventar estos problemas. Mediante el este módulo podemos crear unos patrones para la
generación automática de los alias, tanto para contenidos, categorías, usuarios etc.
Aunque pathauto tiene muchas opciones de configuración únicamente explicaremos como
establecer los patrones de reemplazo para contenidos que es la función que se le ha dado en
el sitio.
Lo primero de todo es instalar los módulos pathauto y token, el módulo token es requerido
por pathauto para su funcionamiento. Una vez instalados los módulos accedemos a
Administrar > Construcción del sitio > Alias de URL y vamos a la pestaña Opciones de
alias de rutas automáticos. Una vez en esta página desplegamos Node paths y aquí es
donde deberemos introducir el patrón de reemplazo (Figura 6.30).
Figura 6.30
85
Como se ve en la imagen las rutas constan de dos partes, la primera que la definimos según
el tipo de contenido, y la segunda que es común a todas, esta segunda parte lo que hace es
coger el título que tenga el nodo que se esta creando y añadirlo, por ejemplo un nodo de
tipo encuesta con titulo hace buen día quedaría de la forma encuestas/hace-buen-dia. Para
la primera parte d ella ruta lo que hemos hecho es introducir el texto con el nombre que le
dimos a la vista creada con Views, de esta forma, aunque realmente los contenidos no
tengan relación con su vista a efectos del usuario es como si los nodos de cada tipo
colgaran de su vista.
6.8 Desarrollo de Módulos en Drupal
Dependiendo de la complejidad del módulo que se vaya a desarrollar la cantidad de
archivos y/o hooks que se han de definir puede variar de gran manera. A continuación se
va a explicar como se implementan los archivos y hooks más comunes en el desarrollo de
módulos en general. Por convención todos los archivos y hooks de Drupal deben empezar
con el nombre que se le da a la carpeta del módulo, en el caso de los archivos debe ir
seguido de la extensión del archivo y en el caso de los hooks del identificador de este.
6.8.1 Creación del Módulo
Todos los módulos necesitan dos archivos principales para funcionar, el archivo .info y el
archivo .module, aunque los archivos sean archivos de texto plano debemos especificar que
los archivos que trabajen con codificación UTF-8 sin BOM ya que es la codificación que
usa Drupal y en el caso de trabajar con otra podrían haber problemas con los caracteres
especiales como las tildes y las eñes.
Archivo .info
Este archivo contiene la información básica sobre el módulo, los requisitos mínimos y las
posibles dependencias con otros módulos.
La primera linea del archivo .info debe ser la cadena ; $Id$ esta cadena es usada por la
comunidad de Drupal para el servidor de control de versiones, en el caso de que
86
compartamos nuestro módulo en la comunidad. A continuación vienen los campos que
contienen la información del módulo:
•
name
Campo obligatorio. Define el nombre del módulo tal y como se le mostrará al
usuario.
•
description
Campo obligatorio. Es la descripción que se mostrará al usuario en el área de
administración de módulos.
•
core
Campo obligatorio.Define la versión de Drupal para la que se ha desarrollado el
módulo, no hace falta indicar la versión exacta como por ejemplo 6.22 sino que se
ha de indicar 6.x.
•
php
Campo opcional. Define la versión mínima de php que debemos tener instalada
para que el módulo funcione.
•
dependencies
Campo opcional. Define los módulos que nuestro módulo requiere que estén
instalados para funcionar.
•
package
Campo opcional. Define a que conjunto de módulos pertenece el módulo.
87
Ejemplo de archivo .info del módulo forum_access:
; $Id$
name = Forum Access
description = Allows forums to be set private and allows forums to be
given moderators.
dependencies[] = acl
dependencies[] = forum
package = Access control
core = 6.x
Archivo .module
Este archivo es donde se implementarán los principales hooks y funciones del código del
módulo.
6.8.2 Creación del Archivo .install
En el archivo .install se incluyen las acciones que ha de realizar el módulo en la
instalación o desisntalación del mismo. Estas acciones suelen estar relacionadas con la
base de datos, como la creación/supresión de tablas en la base de datos, modificación de
tablas existentes en la base de datos etc.
Para definir las tablas que se han de crear en la base de datos, no escribiremos el código en
SQL directamente, sino que utilizaremos un hook especifico de Drupal con una sintaxis
propia.
Función hook_schema
Esta es la función mediante la cual se definen las tablas que va a instalar el módulo, cabe
aclarar que esta función únicamente define las tablas, no las instala, para instalar y
desisntalar las tablas deberemos implementar los hook install y uninstall.
88
Las tablas se definirán por medio de arrays asociativos, los siguientes valores son los que
se pueden usar en la definición de las tablas del hook_schema.
•
description
Pequeña descripción de la tabla y su dunción.
•
fields
Se trata de otro array asociativo mediante el cual definimos la estructura de los
campos de la tabla. Cada campo vendrá identificado por su nombre y también será
un array asociativo que podrá tener las siguientes opciones:
•
description describe el campo y su función
•
type define el tipo de dato del campo.
•
size define el tamaño máximo del campo.
•
not null booleano que indica si el campo puede o no acceder valores nulos.
•
default define el valor por defecto del campo.
•
length define la longitud máxima para los campos de tipo varchar, text etc.
•
unsigned booleano que define si los tipos numéricos llevan o no signo.
•
precision/scale indica la precisión decimal para los tipos numéricos.
•
serialize booelano que define si el campo se almacena como una cadena
serializada
•
primary key
Array que toma por valor uno o más campos de la tabla que especifican la clave
primaria
•
unique keys
Array que define las claves únicas de la tabla
89
•
indexes
Array que define los índices de la tabla.
Ejemplo de la definición de una tabla mediante la función hook_schema del módulo
taxonomy.
$schema['term_hierarchy'] = array(
'description' => 'Stores the hierarchical relationship between terms.',
'fields' => array(
'tid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'description' => 'Primary Key: The {term_data}.tid of the term.',
),
'parent' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'description' => "Primary Key: The {term_data}.tid of the term's parent.
0 indicates no parent.",
),
),
'indexes' => array(
'parent' => array('parent'),
),
'primary key' => array('tid', 'parent'),
);
Funciones hook_install y hook_uninstall
Estas dos funciones son las que se llaman en el momento de instalación y desisntalación de
un módulo.
Para crear las tablas en la base de datos sólo tenemos que usar la función
drupal_install_schema()
pasandole
por
parametro
el
nombre
del
módulo,
automáticamente el recogerá la función hook_schema para obtener la definición de las
90
tablas. La función hook_uninstall funciona de manera análoga pero haciendo uso de la
función drupal_uninstall_schema(). Si queremos hacer alguna inserción/supresión en las
tablas de la base de datos, también es en estas funciones en las que deberíamos incluir el
código.
6.8.3 Creación de Menús y Páginas
Mediante la implementación del hook_menú conseguimos 2 cosas, la primera es crear los
elementos que se han de añadir a los menús para mantener organizado jerárquicamente el
sitio, la segunda es la de hacer que cualquier página definida además de ser añadida al
menú pertinente, sea accesible mediante la ruta que le definamos. Así por ejemplo con el
código
añadido
a
continuación
definiríamos
una
URL
con
dirección
www.web.com/example que ejecutaria la función de retorno example_function().
Código de ejemplo:
$items['example'] = array(
'title' => 'página de ejemplo',
'page callback' => 'example_function',
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
91
Los valores más importantes que puede contener el array con el que definimos la página
son:
•
title
Titulo de la página.
•
page callback
Función de retorno que nos presentará la página cuando se demande su URL a
través del navegador.
•
page arguments
Array de argumentos que se le han de pasar a la función definida en page callback
en caso de que sean necesarios.
•
access callback
Funcion de retonro para determinar quien puede acceder a la página.
•
access arguments
Array de argumentos que se le han de pasar a la función definida en access
callback en caso de que sean necesarios.
•
menu name
Nombre del menú en el que queremos que se cree el elemento, ha de ser el nombre
interno del menú.
•
type
Determina el tipo de elemento utilizado.
92
6.8.4 Creación de Formularios
Para crear un formulario lo primero que debemos hacer es definir la URL en la que va a
estar disponible el formulario mediante la función hook_menu. En el parámetro page
callback le indicaremos el valor drupal_get_form, función incluida en el API de Drupal
que recibe por parámetro una definición de un formulario y la presenta en el sitio. En el
parametro page arguments le indicaremos el nombre de la función en la que definamos el
formulario. Igual que pasaba con la definición de las tablas de la base de datos, Drupal
tiene una sintaxis propia para la definición de formularios nuevamente basada en arrays
asociativos. Siendo la URL del formulario form1 y la función que define el formulario
form1_function la definición en el hook menú quedaria de la siguiente manera:
$items['form1'] = array(
'title' => 'primer formulario',
'page_callback' => 'drupal_get_form',
'page arguments' => 'form1_function',
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
Validación y procesamiento de los formularios
De forma predeterminada Drupal utiliza para cada formulario unas funciones de validación
y procesamiento que debemos implementar. Sus nombres han de ser el nombre que el
dimos a la función que definía el formulario seguida de _validate en el caso de la función
de validación y _submit en el caso de la función de procesamiento.
93
6.8.5 Creación de Bloques
La creación de los bloques se realiza mediante la función hook_block. La función
hook_block tiene dos parámetros importantes, $op y $delta.
El parámetro $deta es el identificador mediante el cual Drupal diferencia un bloque de otro
bloque definido dentro del mismo módulo, los valores de $delta pueden ser tanto
númericos como cadenas.
•
El parámetro $op indica la acción que ha de realizar la función en esa ejecución.
Los valores de $op pueden ser: list
Retorna un vector con todos los bloques definidos, cada elemento del vector
(bloque) será identificado por su delta y podrá tener los siguientes campos:
•
info es la descripción del bloque apra el área de administración.
•
cache indica como debe funcionar la cache del bloque.
•
status booleano que indica si el bloque esta activado o desactivado por defecto
•
region marca la región en la que debe situarse el bloque en el caso de que este
activo por defecto.
•
weight indica la posición del bloque respecto a otros bloques de la misma
región.
•
pages indica en que páginas debe mostrarse el el bloque por defecto.
•
custom booleano que indica si es un bloque implmentado por un módulo.
•
title Indica el título del bloque por defecto.
•
configure
Devuelve un vector con la definición del formulario de configuración del
bloque.
•
save
Se realizan las operaciones de salvado de las opciones de configuración del
bloque.
94
•
view
Devuelve un vector con la información que ha de mostrar el bloque.
6.8.6 Creación de Tipos de Contenido
Podemos dividir la creación de tipos de contenidos en tres fases, definición del tipo de
contenido, gestión del nodo y presentación del nodo.
Definición del tipo de contenido
Para definir el tipo de contenido debemos implementar dos hooks, el hook_node_info() en
el cual definiremos el nombre y las propiedades del tipo de contenido, Definiremos dichos
atributos mediante un array asociativo que podrá tener varios componentes, los más
relevantes son:
•
name
Nombre del tipo de contenido que se presentará a los usuarios en la interfaz.
•
module
Nombre del módulo que implementa el contenido.
•
description
Deascripción del tipo de contenido para yuda del usuario.
•
has_title
Booleano que indica si el contenido tendrá o no titulo.
•
has_body
Booleano que indica si el contenido tendrá o no cuerpo.
95
Una vez implementado este hook deberemos implementar el hook_form(), este hook no es
más que otra función en la que deberemos definir un formulario mediante la sintaxis de
Drupal. Este formulario será el formulario de creación/edición de los nodos del tipo de
contenido.
Gestión de los nodos
Obviamente para mantener la integridad del contenido deberemos tener una tabla en la
base de datos donde almacenar la información del nodo. Para tarbajar con la información
del nodo y la base de datos tendremos que implementar cuatro hooks, hook_insert,
hook_update, hook_delete y hook_load.
hook_insert
A la hora de crear unn nodo los campos básicos del nodo como son el titulo y el cuerpo, se
encarga el núcleo de Drupal de almacenarlos, sin embargo el resto de campos adicionales
debemos indicar nosotros como deben ser guardados, es aquí donde indicaremos en que
tabla y en que cloumnas se ha de colocar cada uno de los campos del tipo de contenido.
hook_update
Del mismo modo que pasa a la hora de crear el nodo, cuando lo actualizamos los campos
adicionales del tipo de contenido no son almacenados por el núcleo de Drupal, asi que en
esta función hemos de implementar el tratamiento de los datos para que queden
almacenados en la base de datos.
hook_delete
De forma análoga al borrar un nodo, debemos implementar esta función para indicar que
información de la base de datos debe ser eliminada.
hook_load
Este hook se encarga de recuperar la información adicional de la base de datos para poder
presentarsela al usuario.
96
Presentación de los nodos
En la implementación de la presentación de nodos podemos diferenciar tres partes, los
hooks que debemos crear en el archivo .module que son el hook_view y el hook_theme, la
plantilla de presentación que se trata de un archivo php y el archivo css que es el
encargado dar los estilos a la plantilla.
hook_view
Es la función encargada de preparar el nodo para su presentación añadiendole la
información de los campos adicionales
hook_theme
Es la función encargada de definir la plantilla que va a utlizar el tipo de contenido y los
argumentos que va a recibir dicha plantilla.
Plantilla de presentación (archivo .tpl.php)
Este archivo es el que implementa el código html de presentación del nodo mediante
código php.
Archivo css
Define los estilos que se usarán en la plantilla de presentación.
6.8.7 Creación de Vistas
Para que nuestro módulo cree una vista en el momento de su instalación, lo más sencillo es
crear la vista mediante el módulo views, tal y como se explicó en el apartado 6.4 de este
mismo documento. Una veza creada la vista hemos de usar la herramienta de export del
mñodulo views, esta herramientas nos proporcionará el código a añadir a nuestro módulo.
Generalmente habrá que añadir el hook_views_api en el archivo .module, y crear el
archivo .views_default.inc con el código que implementa la vista.
97
6.9 Desarrollo del Módulo Achievements
Para el desarrollo del módulo se han seguido las directrices explicadas en el apartado
anterior (6.8 Desarrollo de Módulos en Drupal), por esta razón únicamente se
especificarán los hooks y funciones implementadas que no se hayan explicado en dicho
apartado, para el resto de situaciones se considerara implícita la información referente a los
hooks implementados y propiedades de los mismos. Este párrafo es aplicable a todos los
apartados referidos a la implementación de los módulos propios.
6.9.1 Tablas de la base de datos
Este módulo instala tres tablas en la base de datos.
•
achievements_list
En esta tabla se almacena la información adicional del nodo achievement. Está
formada por los campos:
•
•
nid, identificador del nodo que se ha creado.
•
vid, versión del nodo creado.
•
description_achievement, guarda la descripción del logro.
•
value, guarda la puntuación del logro.
•
picture, guarda la ruta donde se encuentra la imagen del logro.
achievements_user
En esta tabla se almacena la relación entre usuarios y logros asignados. Está
formada por los campos:
•
nid, identificador del nodo del logro que se asigna.
•
uid, identificador del usuario al que se asigna el logro
98
•
achievements_users_punctuation
En esta tabla se almacena la puntuación conseguida por cada usuario por los logros
conseguidos. Está formada por los campos:
•
uid, identificador del usuario.
•
punctuation, puntuación acumulada del usuario por la asignación de logros.
6.9.2 Tipos de contenido
Este módulo implementa un tipo de contenido llamado logro, este tipo de contenido esta
explicado en el apartado 4.2 de este mismo documento.
6.9.3 Formularios
Para implementar todas las funciones del módulo se implementan cuatro formularios.
El primer formulario es el formulario de selección de roles a los que se le pueden asignar
logros, este formulario nos presenta una serie de checkboxes con los roles disponibles del
sitio.
El segundo formulario es el formulario para la creación y edición del nodo del tipo de
contenido logro. Este formulario presenta los campos de texto para añadir la información
adicional del logro y un botón de selección de archivo para añadir la imagen del logro.
Los dos últimos formularios muy parecidos entre si, son los formularios de asignación y
desasignación de los logros a los usuarios. Ambos formularios se han implementado
mediante formularios de varios pasos. En el primero de los pasos nos aparece en el caso de
la asignación la lsita desplegable de los usuarios que tienen alguno de los roles que pueden
tener asignados logros, en el caso de la desasignación la lista contiene los usuarios que
tienen algun logro asignado. Una vez seleccionado el usuario damos a siguiente y nos
aparece una nueva lista desplegable, que en el caso de la asignación nos muestra la lista de
99
los logros que aun no han sido asignados a ese usuario y en el caso de la desasignación nos
muestra los logros que tiene asignados.
6.9.4 Bloques
El módulo crea un bloque llamado Hall of Fame en el que se muestra una lista de los
usuarios con la puntuación más alta conseguida hasta el momento por la asignación de
módulos.
6.9.5 Vistas
Elmódulo implementa una vista con una presentación de página en la que se muestran los
nodos del tipo logro ordenados por fecha de actualización.
6.9.6 Otras Funciones Importantes Implementadas
hook_user
Mediante este hook conseguimos que cuando borramos a un usuario se borren las entradas
de las tablas achievements_user y achievements_users_punctuation de la base de datos y
que se muestre en el perfil del usuario la lista de logros que tiene asignados y la puntuación
que tiene acumulada.
hook_perm
Mediante este hook definimos los permisos que proporciona este módulo para determinar
que acciones puede realizar cada rol. Los permisos son los siguientes:
•
create achievement
•
delete own achievement
•
delete any achievement
100
•
edit own achievement
•
edit any achievement
•
administer achievements
hook_access
Mediante este hook definimos los permisos que ha de tener un rol para poder crear,
actualizar y borrar un nodo del tipo de contenido implementado por el módulo.
6.10 Desarrollo del Módulo Castle Control
6.10.1 Tablas de la base de datos
Este módulo únicamente instala una tabla en la base de datos.
•
castle_info
Recoge la información que ha de presentar cada uno de los bloques que se creen
para representar el estado de un castillo. Los campos de la tabla son los siguientes:
•
delta, identificador del bloque, usado por Drupal a la hora de realizar operaciones
con el bloque.
•
economy, valor del nivel de economía del castillo.
•
defense, valor del nivel de defensa del castillo.
•
daily_chests, número de cofres diarios que da el castillo.
•
daily_cost, coste diario en zenys de aumentar los nieveles de economia y defensa
del castillo.
•
owner, guild dueña del castillo.
101
6.10.2 Formularios
Este módulo implementa tres formularios para la creación, edición y eliminación de los
bloques que representan la información de los castillos.
El formulario de creación de los bloques es un formulario de dos pasos,en un primer
instante nos presenta un campo de texto donde deberemos introducir el nombre del castillo,
este valor será utilizado como delta del bloque. En el siguiente paso se nos pide el resto de
información relativa al castillo, economía, defensa etc.
El formulario de actualización es muy similar al formulario de creación, pero esta vez en
el primer paso lo que nos encontramos es una lista desplegable con los bloques que hay
creados, en el siguiente paso se nos mostrará nuevamente los campos para introducir la
información del castillo.
El último formulario, el formulario de eliminación de bloques, únicamente presenta una
lista desplegable con los bloques creados para poder seleccionar cual queremos eliminar.
6.10.3 Bloques
Aunque el módulo no presenta ningún bloque de inicio si implementa el hook_block para
que una vez añadido un castillo se pueda mostrar la información deseada.
6.10.4 Otras Funciones Importantes Implementadas
hook_perm
Mediante este hook definimos los permisos que proporciona este módulo para determinar
que acciones puede realizar cada rol. Los permisos son los siguientes:
•
adminster castles
•
view castles
102
6.11 Desarrollo del Módulo Guild Shop
6.11.1 Tablas de la base de datos
Este módulo instala tres tablas en la base de datos.
•
gs_internal_balance
Esta tabla es la encargada de almacenar el crédito interno de cada uno de los
usuarios. Consta de los siguientes campos:
•
•
uid, es la id del usuario.
•
balance, es el saldo que tiene el usuario.
gs_item
Esta tabla almacena la información adicional del nodo del tipo de contenido item
shop. Tiene los siguientes campos:
•
•
nid, identificador del nodo que se ha creado.
•
vid, versión del nodo creado.
•
description_item, es la descripción del item.
•
type_item, nos indica de que tipo de item se trata, carta, armadura etc.
•
price, precio del item.
•
stock, cantidad de items de este tipo que hay.
•
picture, imagen del item.
gs_purchase
Esta tabla almacena la información adicional del tipo de contenido purchase. Esta
formada por los siguientes campos:
•
nid, identificador del nodo que se ha creado.
•
vid, versión del nodo creado.
•
user_name, nombre del usuario que ha realizado la compra.
103
•
item_name, nombre del item comprado.
•
amount, cantidad de items comprados.
Este módulo a parte de la creación de las tablas en la base de datos, en el momento de la
instalación realiza otra acción. Dicha acción es insertar en las tablas del módulo
taxonomía los valores necesarios para poder crear los términos para categorizar los items
cuando se creen según el tipo de item que son, esto posteriormente nos permitirá crear las
presentaciones de la vista según el tipo de item. En la desinstalación realizará el paso
contrario, es decir eliminar las entradas creadas en la instalación en las tablas del módulo
taxonomía.
6.11.2 Tipos de contenido
Este módulo implementa dos tipos de contenido llamados item de tienda y compra, estos
tipos de contenido están explicado en el apartado 4.2 de este mismo documento.
6.11.3 Formularios
Este módulo implementa cinco formularios, el formulario para añadir stock a un item de
la tienda, el formulario para añadir crédito a un usuario, el formulario de compra y los
formularios de creación y edición de los dos tipos de contenido implementados por el
módulo.
El formulario para añadir stock a un item nos presenta una lista desplegable en la que
aparecen todos los items creados para la tienda donde seleccionaremos a que item
queremos añadir el stock y un campo para añadir la cantidad que se debe añadir al stock de
dicho item.
El formulario para añadir crédito es muy similar al anterior formulario, solo que esta
vez la lista desplegable presentará la lista de usuarios a los que se les puede añadir saldo y
en el campo de texto inferior es donde deberemos añadir el saldo.
104
Si un usuario puede comprar cosas de la tienda y hay stock del mismo, aparecerá un link
para acceder al formulario de compra de dicho item, una vez accedamos a él veremos el
crédito total del que dispone el usuario que está realizando la compra, el item que se quiere
comprar, el precio de dicho item, el stock restante y un campo para poner que cantidad de
items queremos comprar. Si la compra tiene éxito, es decir, nos alcanza el crédito para
comprar la cantidad de items que hemos especificado y la cantidad especificada no es
superior al stock restante, seremos redirigidos a una página donde se nos indicará los datos
de la compra y el saldo restante después de realizarla. Esta compra creará automáticamente
el nodo relacionado con la compra para que el tesorero tenga constancia de la compra
realizada.
6.11.4 Bloques
Este módulo implementa cuatro bloques, el bloque con los últimos items añadidos a la
tienda, el bloque con las últimas compras realizadas por los usuarios, un bloque con el
menú de la tienda y un bloque con la información del usuario referente a la tienda.
El menú de tienda nos permite acceder a la vista que queramos según el tipo de item o a
una vista con todos los items de la tienda.
La información del usuario presenta la última compra realizada por el usuario y el saldo
actual en su poder.
6.11.5 Vistas
Este módulo incluye una vista con varias presentaciones, cada uno de ellas muestra los
items de un tipo de item determinado y una vista que presenta todos los items sin importar
el tipo.
105
6.11.6 Otras Funciones Importantes Implementadas
hook_perm
Mediante este hook definimos los permisos que proporciona este módulo para determinar
que acciones puede realizar cada rol. Los permisos son los siguientes:
•
create item shop
•
delete own item shop
•
delete any item shop
•
edit own item shop
•
edit any item shop
•
administer shop
•
create purchase
•
buy item
hook_access
Mediante este hook definimos los permisos que ha de tener un rol para poder crear,
actualizar y borrar un nodo del tipo de contenido implementado por el módulo.
106
6.12 Desarrollo del Módulo Assistance
6.12.1 Tablas de la base de datos
Este módulo utiliza dos tablas.
•
assistance_node
Almacena la información adicional del nodo del tipo de contenido asistencia. Está
formada por los siguientes campos:
•
•
nid, identificador del nodo que se ha creado.
•
vid, versión del nodo creado.
•
uid, usuario que realiza la asistencia.
•
enid, identificador del nodo de evento sobre el que se realiza la asistencia.
•
job, identificador del nodo que representa el personaje utilizado.
•
status, indica si la asistencia ha sido ya asignada a una party o no.
assistance_job
Almacena una relación de nombre de un job y un identificador numérico, esta tabla
se utilizará posteriormente para crear elementos de algunos formularios mediante
bucles. Esta formada por los siguientes campos:
•
id, identificador del job.
•
name, nombre del job.
Este módulo además de la creación de las tablas, en su instalación inserta toda la
información de la tabla assistance_job.
107
6.12.2 Tipos de contenido
Este módulo implementa dos tipos de contenido, el de asistencia a evento y el de asistencia
a woe, estos tipos de contenido están explicado en el apartado 4.2 de este mismo
documento.
En este caso, a la hora de gestionar los nodos de los tipos de contenido, en el momento de
actualizar y eliminar un nodo de uno de estos dos tipos de contenido debemos tener en
cuenta si el módulo party está instalado, ya que de ser así deberemos mirar si esa asistencia
había sido asignada a una party para eliminarla de ella y hacer los cambios pertinentes en
las tablas del módulo party.
6.12.3 Formularios
Este módulo a parte de los dos formularios para la creación y edición de los tipos de
contenido implementa otro formulario en el que indicar que tipo de contenido es el que
implementa el roster de personajes de la guild.
Este formulario presenta una lista de los tipos de contenidos disponibles en la web
mediante radio buttons para que podamos seleccionar el contenido adecuado.
6.12.4 Vistas
Este módulo implementa dos vistas que presentan los nodos de cada uno de los tipos de
contenido implementados por el módulo.
108
6.12.5 Otras Funciones Importantes Implementadas
hook_perm
Mediante este hook definimos los permisos que proporciona este módulo para determinar
que acciones puede realizar cada rol. Los permisos son los siguientes:
•
admin assistance
•
create assistance
•
edit any assistance
•
edit own assistance
•
delete any assistance
•
delete own assistance
hook_access
Mediante este hook definimos los permisos que ha de tener un rol para poder crear,
actualizar y borrar un nodo del tipo de contenido implementado por el módulo.
hook_user
En el caso de que no este instalado el módulo party, en el momento de eliminar un usuario
deberemos eliminar la información de los nodos de asistencia de dicho usuario.
function get_future_events
Esta función nos devuelve un array asociativo que contiene sólo los eventos con fecha de
realización posterior a la fecha actual y que son de woes o eventos normales según se le
especifique por parámetro. Esta función es usada en los formularios de creación de nodo
para crear la lista desplegable del evento a seleccionar para la asistencia.
109
6.13 Desarrollo del Módulo Party
6.13.1 Tablas de la base de datos
Este módulo instala dos tablas en la base de datos.
•
party
Almacena la información básica de una party, para cada una de las asistencias
asignadas a un party existirá una entrada en la tabla, consta de los siguientes
campos:
•
•
enid, identificador del nodo del evento para el que es la party
•
party_name, nombre de la party.
•
type_event, indica si el evento es un evento de woe o evento corriente.
•
anid, identificador del nodo asistencia que se asigna a la party.
party_members
Almacena la cantidad de gente que hay asignada a una party. Consta de los
siguientes campos:
•
enid, identificador del nodo del evento para el que es la party.
•
party_name, nombre de la party.
•
number, cantidad de gente asignada a la party.
6.13.2 Tipos de contenido
Este módulo presenta una peculiaridad respecto al resto de módulos implementados, aun
implementar un tipo de contenido como es la party (para eventos y woes), no lo
implementa mediante la creación de un nodo.
Para la presentación de estos tipos de contenido se ha creado una página estática que
presenta una lista desplegable con los eventos/woes (según de que partys se trate) para los
110
que hay creadas partys, una vez seleccionamos uno de los eventos se ejecuta una función
ajax que es la encargada de mostrar en la parte inferior todas las partys creadas para ese
evento y los miembros que están asignados a cada una de las partys (figura 6.31).
Figura 6.31
6.13.3 Formularios
Este módulo implementa seis formularios, uno para la creación de partys de cada uno de
los tipos de party y después dos para la adición y eliminación de miembros de las partys
para cada uno de los dos tipos de partys.
Solo se va a explicar los formularios para uno del tipo de las partys con la diferencia de
que los eventos, asistencias y/o partys que se mostrarán serán del tipo evento o del tipo
woe.
El formulario de creación de partys es un formulario de tres pasos, en el primero de estos
nos saldrá una lista desplegable con los eventos que tienen alguna asistencia pendiente de
asignar. En el segundo paso aparecerá un campo para introducir el nombre que queremos
dar a la party, este nombre no se puede repetir con el de otras partys del mismo evento,
pero si con el nombre de otra party de otro evento. Por último nos aparecerá el listado de
asistencias divididos por el job del personaje que esta asignado a la asistencia (figura
6.32).
111
Figura 6.32
El formulario para añadir un miembro a una party es un formulario de tres pasos. En el
primer paso nos aparcen los eventos que ya tienen alguna party creada y no estas llena, es
decir tiene menos de 12 integrantes. En el siguiente paso nos aparece una lista desplegable
con las partys creadas para dicho evento, para facilitar la colocación de los usuarios en las
partys, al selccionar una party en la lista desplegable cargamos mediante ajax el contenido
de esa party (de manera análoga a la hora de mostrar el contenido party) para poder revisar
que jobs hay añadidos en cada una de las partys. En el último paso se nos muestra la lista
de asistencias pendientes para ese evento de forma idéntica que se hacia en la creación de
la party.
El formulario para eliminar miembros es muy parecido al de añadir miembros, los dos
primeros pasos son iguales, aunque esta vez en el segundo paso no mostraremos los
miembros de la partys al cambiar el valor de la lista desplegable, esto lo hacemos así
porque se ha considerado que a la hora de eliminar un miembro de una party ya tienes
claro del miembro que se trata y a que party pertenece, asi que no nos aportaría ninguna
ayuda dicha presentación. En el último paso se muestra una lista de checkboxes con los
miembros de la party.
6.13.4 Vistas
Este módulo implementa dos vistas que presentan los nodos de cada uno de los tipos de
contenido implementados por el módulo.
112
6.13.5 Otras Funciones Importantes Implementadas
hook_perm
Mediante este hook definimos los permisos que proporciona este módulo para determinar
que acciones puede realizar cada rol. Los permisos son los siguientes:
•
create party event
•
create party woe
•
view party
hook_access
Mediante este hook definimos los permisos que ha de tener un rol para poder crear,
actualizar y borrar un nodo del tipo de contenido implementado por el módulo.
hook_user
En el momento de eliminar un usuario deberemos eliminar la información de los nodos de
asistencia y de las partys de dicho usuario.
function party_get_event
Función que devuelve los eventos que tienen alguna asistencia sin asignar aun, son del tipo
pasado por parámetro y la fecha de inicio es mayor que la fecha actual.
function party_get_assistances
Función que devuelve el listado de asistencias sin asignar para un evento pasado por
parámetro y para unos jobs concretos. Esta función se usa a la hora de crear el paso 3 de la
creación de partys o adición de miembros a una party, mediante un bucle, esta función y la
tabla assistance_jobs podemos crear todos los fieldsets de los jobs en pocas lineas de
código.
113
function get_partys
Función que devuelve el código html que mostrará todas las partys de un evento pasado
por parámetro.
function party_get_event_js
Función que devuelve los eventos que tienen alguna party creada
function party_get_event_nofull
Función que devuelve los eventos que tienen alguna party creada sin llenar y asistencias
pendientes.
function party_get_partys
Función que devuelve el nombre de las partys de un evento.
function party_get_partys_nofull
Función que devuelve el nombre de las partys de un evento que no estén llenas.
function get_partys_build
Función que devuelve el codigo html que mostrará la party del evento pasada por
parámetro.
function get_members_party
Función que devuelve los miembros de una party de un evento.
114
6.14 Desarrollo de Temas en Drupal
Los temas en Drupal estan formados por cuatro tipos de archivos, el archivo .info (archivo
único) los archivos de plantilla .tpl.php, los archivos de hojas de estilo .css y el archivo
template.php.
En el archivo .info describe las características básicas del tema, los parámetros que se
pueden definir en el archivo son los siguientes:
•
name, nombre del tema.
•
description, descripción del tema,
•
screenshot, ruta de la imagen que contiene la imagen previa del tema.
•
core, versión de Drupal para el que esta desarrollado el tema.
•
project, nombre del proyecto.
•
Engine, motor de plantilla utilizado.
•
version, versión de la plantilla.
•
regions[], vector con las regiones disponibles en el tema.
•
features[], vector con las funciones disponibles en el área de administración del
tema.
•
stylesheets[], define las hohas de estilo que utiliza el tema.
Los archivos de plantilla definen la presentación mediante un código php. Como mínimo
todos los temas deben tener el archivo page.tpl.php que es el archivo que define la
estructura de todas las páginas del sitio. A parte de este archivo podemos sobrescribir
cualquier plantilla implementada por otro módulo para modificar su presentación, por
ejemplo si queremos modificar la presentación de los nodos en general deberíamos
implementar el archivo node.tpl.php.
Los archivos .css se utilizan para definir los estilos que utilizarán las plantillas para
complementar su presentación.
El archivo template.php se usa para definir funciones que después son usadas por los
archivos tpl.php.
115
6.15 Desarrollo del Tema Propio
Este tema está compuesto por cinco archivos, el archivo .info donde definimos las
características básicas del tema, dos plantillas una para las páginas y otra para los nodos y
por último el archivo .css donde definimos los estilos usados por los dos archivos de
plantilla.
Se decide crear un tema a tres columnas, una central para el contenido más dos columnas
una a cada lado para colocar los bloques creados en el sitio web. Además tendremos las
zonas de cabecera y pié de página también disponibles.
6.15.1 Definición del Tema Archivo .info
En el archivo .info definimos cuatro regiones en las que podremos colocar bloques,
superior, izquierda, derecha e inferior.
También añadimos las siguientes opciones de administración:
•
logo.
•
Name.
•
node_user_picture.
•
comment_user_picture.
•
search.
•
favicon.
•
primary_links.
•
secondary_links.
116
6.15.2 Creación de Plantillas
page.tpl.php
Como hemos comentado anteriormente la página estará formada por tres columnas, una
cabecera y un pié de página.
En la cabecera únicamente imprimiremos el logo del sitio, el logo es una imagen del ancho
de las tres columnas que presenta el nombre de la supuesta guild dueña del sitio.
En la zona central, donde tenemos las tres columnas dejamos las columnas laterales para
imprimir solamente los bloques que decidamos colocar encada una de ellas, mientras que
en la columna central se imprimirá todo el resto de contenido del sitio.
Para un correcto funcionamiento del sitio debemos imprimir en la cabecera de la página
html (no confundir con la cabecera de la página mostrada) los scripts y archivos css que se
utilicen en el sitio, pues de otra forma no podrían ser utilizados.
Finalmente también es necesario imprimir la variable $closure, es una variable utilizada
por varios módulos para añadir scripts y código vario de utilidad para el módulo.
node.tpl.php
En realidad en esta plantilla mantenemos la estructura de presentación de la plantilla
proporcionada por el módulo node, con la única diferencia de que no mostramos el enlace
del término de taxonomía en caso de que el nodo lo tenga. Esto no es más que una decisión
de tipo estético.
6.15.3 Creación del Archivo Template.php
En este archivo sobrescribiremos una única función, la función de breadcrumb, por defecto
Drupal separa los enlaces del breadcrumb por los carácteres “>>” con nuestra función
hacemos que los enlaces vayan separados por el contenido de un array que contiene los
siguientes símbolos:
117
$char[0] = ' <(o.o<) ';
$char[1] = ' ^(o.o)^ ';
$char[2] =' (>o.o)> ';
Estos símbolos son un guiño a unos emoticonos que se suelen usar en varios juegos online
para simular una ola de celebración.
118
7. Evaluación
Las partes implementadas mediante módulos disponibles en la comunidad de Drupal no
serán evaluados en esta zona, ya que su utilización se resume prácticamente a la definición
de tipos de contenido y damos por hecho que módulos tan consolidados como son CCK y
Views no van a presentar problemas en su utilización.
Por estas razones la evaluación del sitio web se va a centrar en los módulos propios
desarrollados.
7.1 Evaluación del Módulo Achievements
7.1.1 Creación Edición Eliminación y Presentación de Nodos
La primera prueba a realizar es la de comprobación del correcto funcionamiento a la hora
de crear un nodo del tipo de contenido logro, así que para comprobarlo creamos un nodo y
miramos que efectivamente la información almacenada en la base de datos es la correcta y
que a la hora de visualizar el nodo la información es bien recuperada de la base de datos.
Lo siguiente que se prueba es la validación de entradas correctas en los campos del
formulario de creación y edición, hace falta comprobar que si intentamos introducir por
ejemplo un número negativo o una cadena en un campo numérico la creación del nodo no
se produzca y nos indique el error.
Otra prueba que debemos realizar es a la hora de modificar un nodo que el comportamiento
sea el correcto cuando modificas la imagen y cuando no, cuando la modificamos la ruta de
la imagen debe cambiar, mientras que si no se indica una imagen nueva la ruta no debe ser
cambiada por una cadena vacía.
También se ha comprobado que al modificar el valor de la puntuación de un logro, las
puntuaciones de los usuarios que tienen ese logro asignada es modificada.
Se comprueba que si el nodo no tiene ninguna imagen asignada en su presentación se
muestre una imagen comodín para mantener la estructura del nodo.
119
Por último, se ha comprobado que cuando se elimina un nodo del tipo logro, la
información es eliminada de todas las tablas necesarias y que las puntuaciones de los
usuarios que tenían asignado ese logro es actualizada.
7.1.2 Asignación y Desasignación de los Logros
Lo primero que se prueba es que si no existe ningún logro creado no nos deja elegir ningún
usuario en el formulario de asignación/desasignación.
La siguiente prueba mira que los usuarios que se muestran en los formularios de
asignación/desasignación realmente pertenezcan a los roles que se indicaron en el área de
administración del módulo.
También se comprueba que la lista de logros presentada en los formularios de
asignación/desasignación sean los que deben, es decir en el de asignación los logros que
aun no tiene asignados el usuario y en el de desasignación los que ya tiene asignados.
Otra prueba que se ha realizado es que la puntuación del usuario se actualice correctamente
con la asignación y desasignación de los logros.
Se comprueba que tras la desasignación de todos los logros de un usuario este es eliminado
de la tabla que guarda las puntuaciones de cada usuario.
Por último se comprueba que en el perfil del usuario se muestren los logros y la puntuación
correcta que tiene el usuario.
7.1.3 Funcionamiento de los Bloques
Se comprueba que en todo momento la información mostrada por el bloque Hall of Fame
es la correcta.
120
7.2 Evaluación del Módulo Castle Control
7.2.1 Creación Edición Eliminación y Presentación de Bloques
La primera prueba es que tras crear un bloque mediante el formulario de creación, el
bloque está realmente disponible en el área de administración de bloques.
Una vez creado el bloque se comprueba que la información guardada en la base de datos es
la correcta.
Otra prueba realizada es que usando el formulario de modificación del bloque, el bloque se
actualice correctamente.
También se prueba que no se puedan añadir dos castillos con el mismo nombre.
Otra prueba que se realiza es que después de eliminar un bloque, deje de mostrarse si se
estaba mostrando, que desaparezca del área de administración y que se borre toda la
información relativa a él en la base de datos.
Por último se prueba que no deje crease el bloque si se intenta introducir información no
válida en los campos de los formularios como cadenas en valores numéricos, campos
vacíos etc.
7.3 Evaluación del Módulo Guild Shop
7.3.1 Creación Edición Eliminación y Presentación de Nodos
La primera prueba a realizar es la de comprobación del correcto funcionamiento a la hora
de crear un nodo del tipo de contenido logro, así que para comprobarlo creamos un nodo y
miramos que efectivamente la información almacenada en la base de datos es la correcta y
que a la hora de visualizar el nodo la información es bien recuperada de la base de datos.
Lo siguiente que se prueba es la validación de entradas correctas en los campos del
formulario de creación y edición, hace falta comprobar que si intentamos introducir por
ejemplo un número negativo o una cadena en un campo numérico la creación del nodo no
se produzca y nos indique el error.
121
Otra prueba que debemos realizar es a la hora de modificar un nodo que el comportamiento
sea el correcto cuando modificas la imagen y cuando no, cuando la modificamos la ruta de
la imagen debe cambiar, mientras que si no se indica una imagen nueva la ruta no debe ser
cambiada por una cadena vacía.
Al borrar un nodo hemos de comprobar que realmente la información es eliminada de la
base de datos.
También se comprueba que si un objeto no tiene stock no se muestra la opción de comprar
dicho objeto.
7.3.2 Uso del Área de Administración
Se comprueba que al introducir un stock en el área de administración a uno de los items
este stock se ve reflejado tanto en la base de datos como en la presentación del nodo.
Se mira que al añadir crédito a un usuario mediante el área de administración este saldo se
le ve reflejado tanto en la base de datos como en el sitio web.
Por último se comprueba que los formularios del área de administración no dejen que las
entradas de sus campos contengan información no válida.
7.3.3 Realización de Compras
Se comprueba que el proceso de compra se realice con normalidad, es decir, que cuando
seleccionas un item a comprar y rellenas el formulario de compra que al enviarlo si
intentas comprar mayor cantidad del stock restante o no te alcanza tu saldo para realizar la
compra no te deje hacerlo.
La id del item que se está comprando se recoge como parámetro a través de la url, por este
motivo se comprueba que si cambias la id del item por una de un item sin stock o por una
id que corresponda a un nodo que no es del tipo item de tienda no muestre el formulario de
compra.
122
También hace falta validar que no se puedan introducir valores no permitidos en el
formulario de compra, como un número negativo por ejemplo.
Hay que comprobar que después de realizar una compra se crea correctamente el tipo de
contenido con la información relativa a la compra y que esta información es la correcta.
Hay que comprobar que después de una compra tanto el stock del item comprado como el
saldo del usuario que realiza la compra se actualicen correctamente.
7.3.4 Funcionamiento de los Bloques
Se comprueba que los bloques últimas compras realizadas, últimos items añadidos e
información de usuario presentan la información correctamente.
7.4 Evaluación del Módulo Assistance
7.4.1 Creación Edición y Eliminación de Nodos
Se comprueba que no deje a un usuario realizar dos nodos de asistencia para un mismo
evento.
Se comprueba que no deje utilizar un personaje para un evento si otra persona ya ha creado
una asistencia para ese evento con ese personaje.
Otra prueba que se realiza el correcto comportamiento a la hora de editar un nodo que ya
estaba asignado a una party, si este el caso, como se ha modificado ya sea el evento o el
personaje que el usuario piensa utilizar, dicha asistencia debe ser eliminada de la party y
puesta como pendiente de asignar de nuevo.
Cuando se actualice uno de los nodos se ha de comprobar que tanto la condición de no
asistir ya ha dicho evento como la de que el personaje no este en uso se han de comprobar.
123
Al eliminar un nodo su este estaba asignado a una party se ha de comprobar que
desaparece de dicha party. También habrá que comprobar que la información relativa al
nodo desaparece de la base de datos.
Hay que comprobar que cuando se crea un nodo del tipo asistencia su estado se pone
automáticamente a 0 es decir que no está signado.
7.5 Evaluación del Módulo Party
7.5.1 Creación de las Partys
Lo primero que debemos comprobar es que en el formulario de creación de partys el
listado de eventos y asistencias que se nos presenten sean realmente los que tocan a ese
formulario, es decir en el formulario de woes solo eventos de woes y una vez seleccionado
un evento en concreto que únicamente se nos presenten las asistencias de ese evento.
También es necesario comprobar que las asistencias se ordenan correctamente por el job
del personaje, es decir, que una asistencia con el job High Priest por ejemplo, este en el
fieldset correspondiente.
También hace falta comprobar que a la hora de crear la party si se intentan añadir más de
12 asistencias de error, ya que las partys son de un máximo de 12 personas. Como solo
habían 3 personajes de roster creados y no se podían repetir personajes, se redujo el limite
a 2 asistencias para comprobar el resultado al añadir 3 asistencias, se da por hecho que si
funciona con un limite de 2 también funcionará con un limite de 12.
Otra prueba a realizar es la comprobación de que la party una vez creada esta bien
almacenada en la base de datos.
7.5.2 Adición y Eliminación de Asistencias a las Partys
Lo primero es comprobar que en los formularios de adición y eliminación de asistencias a
las partys los eventos y partys que se muestran son los correctos, es decir, los eventos con
124
partys creadas y en el caso de adición que no estén llenas, que las partys mostradas después
de haber elegido el evento sean las correctas y que una vez elegida la party las asistencias
pendientes o asignada, dependiendo del formulario que se trate también sean las que
corresponden.
También hay que comprobar que a la hora de añadir miembros a una party no se supere el
limite de 12 personas, se ha realizado el mismo procedimiento que en el formulario de
creación de partys para comprobar este aspecto.
Otra prueba necesaria es la comprobación de la eliminación de la party de la base de datos
cuando ya no le quedan miembros asignados.
7.5.3 Presentación de las Partys
En este apartado solo hay que comprobar que los eventos que salgan en la lista sean los
que tienen alguna party creada y que la información de las partys creadas para dicho
evento y los miembros de las mismas sean los correctos.
7.6 Evaluaciones sobre Permisos y Visibilidad
Hay que comprobar que las visibilidades de las secciones y contenidos para cada uno de
los roles sea la correcta.
También hay que tener en cuenta que cada rol pueda realizar las funciones que tiene
asignadas pero no las del resto.
Otra prueba a realizar es que los bloques solo sean visibles para los roles correspondientes.
125
126
8. Apsectos Legales
En cuanto a la protección de datos de los usuarios
La gran expansión de los medios digitales; Internet; la telefonía móvil y la televisión
interactiva en el marco de las comunicaciones han traído consigo la proliferación de
negocios a través de estos medios electrónicos. El tráfico de datos generados en las
comunicaciones electrónicas aumenta diariamente poniendo en peligro la intimidad de las
personas.
El respeto a los usuarios de estos negocios exige que el tráfico de datos generados en todas
las comunicaciones electrónicas se vea sometido a prescripciones legales para facilitar su
aplicación y desarrollo.
Así, una de las preocupaciones de cualquier usuario de la red, es asegurarse, cuando
navega por Internet, que los datos que suministra -en un chat, en foros de discusión, o en
compras- no serán capturados, copiados, modificados o utilizados sin su previo
consentimiento. Por ello entiendo que la confianza del usuario en la preservación de su
intimidad en la sociedad digital, es básica para el desarrollo de la sociedad de la
información y de todas las actividades lícitas que se llevan en la red.
El tratamiento de los datos personales esta regulado por la LOPD ( Ley Órganica de Datos
de Carácter Personal).
En este sitio web los únicos datos de carácter personal que se piden son el nombre (en este
caso ni siquiera es obligatorio darlo), un rango de edad y la zona horaria, durante la fase de
solicitud de entrada a la guild, dichos datos van a ser eliminados en cuanto la votación de
la solicitud termine, por tanto a efectos prácticos los únicos datos personales que realmente
se van a mantener almacenados en la base de datos son las direcciones de correo de
registro de los usuarios. Por ese motivo y basándose en el articulo 3/a de la LOPD
referente a las definiciones de los diferentes aspectos sobre la lay que dice:
a) Datos de carácter personal: cualquier información concerniente a personas físicas
identificadas o identificables.
127
Se considera que no afecta al sitio puesto que una persona no puede ser identificada
únicamente por una dirección de correo electrónico. Así pues también se considera que la
dirección mail de un usuario sin ningún tipo más de información a cerca del usuario
tampoco es una información apta para distribuir y vender puesto que no presenta ninguna
información referente a gustos, inclinaciones o otros tipos de datos de carácter personal.
En cuanto al contenido publicado
La propiedad intelectual protege las creaciones originales literarias, artísticas o científicas
expresadas en cualquier medio, tales como libros, escritos, composiciones musicales,
obras dramáticas, coreografías, obras audiovisuales, esculturas, obras pictóricas, planos,
maquetas, mapas, fotografías, programas de ordenador y bases de datos. También protege
las interpretaciones artísticas, los fonogramas, las grabaciones audiovisuales y las
emisiones de radiodifusión.
Aunque si es cierto que los usuarios pueden llegar a publicar contenidos de creación propia
la mayoría de contenidos es posible que sean una reproducción de sitios como wikis o
foros públicos, por tanto no se contempla en ningún momento que dichos contenidos
puedan tener ningún tipo de propiedad intelectual ni copyright, ya que excepto en el caso
de los videos de woes, se considera que los contenidos publicados no se corresponden con
ninguno de los tipos citados anteriormente. Y en cuanto a los videos de WoEs únicamente
se publicarán videos hospedados en sitios de hosting como youtube y megavideo, que ya
regulan dichos derechos.
128
9. Costes
Costes de distribución
Dada la naturaleza del portal creado y con las herramientas que se han utilizado para
desarrollarlo, la aplicación se distribuirá bajo licencia GPL. La Licencia Pública General
de GNU o más conocida por su nombre en inglés GNU General Public License o
simplemente sus siglas del inglés GNU GPL, es una licencia creada por la Free Software
Foundation en 1989 (la primera versión), y está orientada principalmente a proteger la libre
distribución, modificación y uso de software. Su propósito es declarar que el software
cubierto por esta licencia es software libre y protegerlo de intentos de apropiación que
restrinjan esas libertades a los usuarios.
Por tanto el desarrollo, el mantenimiento y la distribución de esta aplicación no suponen
ningún coste monetario, únicamente costes de índole personal, como puede ser la
dedicación temporal al desarrollo de la aplicación.
Costes de puesta en marcha
El uso de la aplicación si podría suponer un gasto para los usuarios del portal siempre y
cuando no dispongan de un servidor web propio, que dado el ámbito al que está destinada
la aplicación no es descartable que ocurra.
En el caso de que no se disponga de un servidor propio, los usuarios necesitarán contratar
un servicio de hosting, por recomendaciones de la comunidad de usuarios de Drupal, se
recomeinda el uso de la empresa de hosting https://dinahosting.com/ , la cual ofrece
varias opciones de hosting válidos para nuestro tipo de aplicación, recomendando nosotros
https://dinahosting.com/hosting/hosting-profesional que proporciona los requerimientos
básicos necesarios como servidor php, servidor para bases de datos Mysql copias de
seguridad etc.
El coste de contratación del servicio depende de la cantidad de tiempo por el que la
contrates, a mayor tiempo menor precio, el precio máximo del servicio es de 11,42€
mensuales en un servidor corriendo bajo Linux y de 17,43€ en un servidor corriendo bajo
Windows.
129
A parte del servidor web requerimos de un dominio, este dominio podemos registrarlo con
la misma compañía con la que recomendamos para el servidor web. Las tarifas para el
dominio web varían según el dominio y el tiempo por el cual registremos el dominio,
siendo el precio máximo a pagar de 1,17€ al mes.
Así pues utilizando esta compañía de hosting el coste total de la puesta en marcha de la
aplicación seria de 12.59€ mensuales en el caso de usar un servidor trabajando sobre Linux
y de 18,6€ mensuales si se tratase de un servidor que funcionase sobre Windows.
130
10. Conclusiones
Los CMS son potentes herramientas que nos permiten crear un sitio web muy completo sin
necesidad de tener conocimientos de programación, pero aun se convierten en una
herramienta mucho más potentes si se poseen dichos conocimientos, ya que pasamos de
tener unas herramientas limitadas, si es que se puede considerar limitado los miles de
módulos que existen para un CMS como Drupal, a tener una estructura básica sobre la que
ampliar funcionalidades sin tener que preocuparnos por las funciones más básicas ya que
vienen implementadas directamente por el framework.
Una de las grandes ventajas de usar Drupal, que aunque quizá no sea el CMS más popular
entre los usuarios de Internet, si creo que se puede decir que es el más versátil y flexible,
aunque esto haga que su curva de aprendizaje sea mucho más compleja que la de otros
CMS, motivo principal por el que posiblemente Drupal no es tan popular como sus
competidores. Gracias a esta versatilidad y la gran cantidad de módulos ya implementados
hace que se puedan crear sitios de los estilos y funcionalidades más diversas, como por
ejemplo este proyecto, una aplicación a priori poco común, pero que para un sector muy
específico puede ser de gran uso, sobretodo porque no existen aplicaciones de este tipo y se
suele resolver siempre mediante el uso de un foro, con las limitaciones que esto conlleva.
Además el sistema modular y de hooks hace que sea un entorno muy cómodo para el
desarrollo de nuevas funcionalidades, ya que tienes unas pautas muy marcadas de como
realizar las cosas. Además el sistema de hooks te permite dejar algunas cosas en manos del
propio framework ya que si no implementas un hook específico para tu módulo
simplemente se pasará a ejecutar el hook del núcleo.
Otra gran ventaja del uso de Drupal es su uso por defecto de archivos CSS para sus
plantillas de presentación ya que así se puede separar perfectamente la presentación de la
funcionalidad de los módulos desarrollados.
La mayor problemática de trabajar con Drupal es la escasa información en algunos ámbitos
de su desarrollo, además de usar sintaxis propias para cosas como la creación de tablas o
definición de formularios html, que si hace que sea mucho más amigable el código
implementar, también provoca que en el momento que quieres realizar alguna función que
se sale de lo habitual es muy complicado encontrar documentación sobre ello, lo que
131
provoca que si los conocimientos sobre programación web y funcionamiento interno de
Drupal no son muy extensos aparezcan cosas que te resulten imposibles de implementar
para Drupal pero que por ejemplo se realizarían fácilmente para una web realizada
íntegramente en html y php.
132
11. Planificación Temporal
Intervalo
Tarea
8 – 26 de Octubre
Familiarización con Drupal y realización de
varios videotutoriales online.
27 de Octubre – 12 Noviembre
Definición de especificaciones del proyecto
13 Noviembre – 17 Diciembre
Implementación de tipos de contenido
medienat CCK y Vistas mediante Views
10 Enero – 25 febrero
Aprendizaje de desarrollo de Módulos en
Drupal y realización de tutoriales sobre ello.
7 marzo – 30 de abril
Implementación de módulos propios
2 – 6 Mayo
Implementación del tema propio
19 – 31 Mayo
Redacción de la memoria.
133
134
12. Bibliografia
Libros
“Pro Drupal Develoopment”, J.K.VanDyk, Apress, 2009
“Aprende Drupal 6 nivel inicial” Fran Gil y Adolfo Romaní, Forcontu, 2010
“Aprende Drupal 6 nivel intermedio” Fran Gil y Adolfo Romaní, Forcontu, 2010
“Aprende Drupal 6 nivel Avanzado” Fran Gil y Adolfo Romaní, Forcontu, 2010
Webs
http://drupal.org/
http://drupal.org.es/
http://www.miguelmanchego.com
http://www.documentados.com
http://www.desarrolloweb.com
http://www.illasaron.com/
http://api.drupal.org
http://es.php.net
135
136
12. Anexos
12.1 Módulo Achievements
Archivo achievements.info
; $Id$
name= "Achievements"
description = "Module to add achievements to the drupal."
core = 6.x
php = 5.1
dependencies[] = views
package = Ragnarok Guild
Archivo achievements.install
<?php
// $Id$
/**
* Implementation of hook_schema()
*/
function achievements_schema(){
$schema['achievements_list'] = array(
'description' => 'Stores achievements information.',
'fields' => array(
'nid' => array(
// id of the node set
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'vid' => array(
//version of the node set
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'description_achievement' => array(
//description of the achievement
137
'type' => 'text',
'not null' => TRUE,
'size' => 'big',
),
'value' => array(
//punctuation of the achievement
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'picture' => array(
//picture of the achievement
'type' => 'varchar',
'length' => 255,
'default' => '',
),
),
//primary key formed by nid field
'primary key' => array('nid'),
);
$schema['achievements_users'] = array(
'description' => 'Stores relationship between achievements
and users.',
'fields' => array(
'nid' => array(
//field referred to achievement identifier
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'uid' => array(
//field referred to user identifier
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
),
138
//primary key formed by node identifier and user identifier
'primary key' => array('nid', 'uid'),
);
$schema['achievements_users_punctuation'] = array(
'description' => 'Stores de punctuation of each user.',
'fields' => array(
'uid' => array(
//field referred to user identifier
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'punctuation' => array(
//User accumulated punctuation
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
),
//primary key formed by user identifier
'primary key' => array('uid'),
);
return $schema;
}
/**
* Implementation of hook_install()
*/
function achievements_install(){
drupal_install_schema('achievements');
}
/**
* Implementation of hook_uninstall()
*/
function achievements_uninstall(){
drupal_uninstall_schema('achievements');
}
139
Archivo achievements.achievements.module
/**
* Implementation of hook_load()
*/
function achievements_load($node){
$additions = db_fetch_object(db_query('SELECT
description_achievement, value FROM {achievements_list} WHERE vid = %d',
$node->vid));
return $additions;
}
/**
* Implementation of hook_view()
*/
function achievements_view($node, $teaser = FALSE, $page = FALSE){
global $base_root, $base_path;
$node = node_prepare($node, $teaser);
$picture = db_result(db_query('SELECT picture FROM {achievements_list} WHERE
nid = %d',$node->nid));
if($picture!=''){
$pic = $base_root.$base_path.$picture;
}
else{
$pic =
$base_root.$base_path.'sites/default/files/noimg90x120.jpg';
}
$node->content['node'] = array(
'#value' => theme('achievements_node', $pic, $node>value,$node->description_achievement ),
'#weight' => 1,
);
return $node;
}
/**
* Implementation of hook_theme()
*/
function achievements_theme(){
return array(
'achievements_node' => array(
'template' => 'achievements',
'arguments' => array('picture' => 0, 'value' => 0,
'description_achievement' => 0 ),
140
),
);
}
/**
* Implementation of hook_init().
*/
function achievements_init() {
drupal_add_css(drupal_get_path('module', 'achievements') .'/achievements.css');
}
/**
* Implementation of hook_perm()
*/
function achievements_perm(){
return array(
'create achievement',
'delete own achievement',
'delete any achievement',
'edit own achievement',
'edit any achievement',
'administer achievements',
);
}
/**
* Implementation of hook_acces()
*/
function achievements_access($op, $node, $account){
switch ($op){
case 'create':
return user_access('create achievement', $account) ?
TRUE : NULL;
case 'update':
return user_access('edit any achievement', $account) ||
(user_access('edit own achievement', $account)&&($account->uid == $node>uid)) ? TRUE : NULL;
case 'delete':
return user_access('delete any achievement', $account)
|| (user_access('delete own achievement', $account)&&($account->uid ==
$node->uid)) ? TRUE : NULL;
}
}
/**
* Implementation of hook_menu()
141
*/
function achievements_menu(){
$items['admin/settings/achievements'] = array(
'title' => t('Achievements settings'),
'description' => t('Select roles'),
'page callback' => 'drupal_get_form',
'page arguments' => array('achievements_select_roles'),
'access arguments' => array('administer achievements'),
'type' => MENU_NORMAL_ITEM,
'file' => 'achievements.admin.inc',
);
$items['admin/build/achievements'] = array(
'title' => t('Achievements build'),
'description' => t('Assign achievements'),
'page callback' => 'drupal_get_form',
'page arguments' => array('achievements_assign_achievement'),
'access arguments' => array('administer achievements'),
'type' => MENU_NORMAL_ITEM,
'file' => 'achievements.admin.inc',
);
$items['admin/build/achievements/assign_achievements'] = array(
'title' => t('Assign achievements'),
'description' => t('Assign achievements'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'file' => 'achievements.admin.inc',
);
$items['admin/build/achievements/deallocated_achievements'] = array(
'title' => t('Deallocate achievements'),
'description' => 'Deallocate achievements.',
'page callback' => 'drupal_get_form',
'page arguments' => array('achievements_deallocate_achievement'),
'access arguments' => array('administer achievements'),
'type' => MENU_LOCAL_TASK,
'file' => 'achievements.admin.inc',
);
return $items;
}
/**
142
* Implementation of hook_user()
*/
function achievements_user($op, &$edit, &$user, $category = NULL){
switch($op){
case 'delete':
db_query('DELETE FROM {achievements_users} WHERE uid = %d', $user>uid);
db_query('DELETE FROM {achievements_users_punctuation} WHERE uid =
%d', $user->uid);
case 'categories':
$data = array();
$data[]= array(
'name' => achievements,
'title' => t('Achievements'),
);
return $data;
case 'view':
$result = db_query("SELECT punctuation FROM
{achievements_users_punctuation} WHERE uid = %d",$user->uid);
$row = db_result($result);
$user->content['achievements'] = array();
$user->content['achievements'] = array(
'#type' => 'user_profile_category',
'#attributes' => array ('class' => 'user-achievements'),
'#title' => t('Achievements'),
'#weight'=> 0,
);
$user->content['achievements']['punctuation'] = array(
'#type' => 'user_profile_item',
'#title' => t('Total Achievement Punctuation'),
'#value' => $row,
'#weight'=> 2,
);
$result = db_query("SELECT al.nid, n.title FROM ({achievements_list} al INNER
JOIN {node} n ON al.nid = n.nid) INNER JOIN {achievements_users} au ON n.nid =
au.nid WHERE au.uid = %d", $user->uid);
while( $row = db_fetch_array($result)){
143
$user->content['achievements'][$row['nid']] = array(
'#type' => 'user_profile_item',
'#value' => l($row['title'],drupal_get_path_alias('node/'.$row[nid])),
'#weight'=> 1,
);
}
}
}
/**
* Implementation of hook_block()
*/
function achievements_block($op='list', $delta=0, $edit=array()){
switch($op){
case 'list':
$blocks[0]['info'] = t('Hall of Fame');
$blocks[0]['cache'] = BLOCK_NO_CACHE;
return $blocks;
case 'view':
$result= db_query_range("SELECT u.name, aup.punctuation, u.uid FROM {users}
u INNER JOIN {achievements_users_punctuation} aup on u.uid = aup.uid ORDER BY
punctuation desc",0,5);
$count = 1;
$items = array();
while($row= db_fetch_array($result)){
$items[] = $count."- ".l($row['name'], 'user/'.$row['uid'])."
".$row['punctuation']." ".t('points');
$count+=1;
}
$block['subject'] = t('Hall of Fame');
$block['content'] = theme('item_list', $items);
return $block;
}
}
/**
* Implementation of hook_views_api().
*/
144
function achievements_views_api() {
return array(
'api' => 2,
'path' => drupal_get_path('module', 'achievements'),
//'path' => drupal_get_path('module', 'achievements') . '/includes',
);
}
Archivo achievements.admin.inc
<?php
//$Id$
/**
* @file
* Resultado de llamadas a páginas de administración para el módulo
Achievements
*/
/*
* Funcion para guardar en bd que roles pueden tener logros
*/
function achievements_select_roles(){
$content_roles_list = user_roles($membersonly = TRUE);
$form['achievements_role_list'] = array(
'#type' => 'checkboxes',
'#title' => t('To assign to a role the ability to add
achievements to users of that role'),
'#options' => $content_roles_list,
'#default_value' => variable_get('achievements_role_list',
array('3')),
);
return system_settings_form($form);
}
/*
* Funcion que devuelve un array con todos los logros creados.
*/
function get_achievements(){
$result = db_query("SELECT a.nid, n.title FROM {achievements_list} a INNER JOIN
{node} n ON a.nid = n.nid");
while($row = db_fetch_array($result)){
$achievements[ $row['nid']]=$row['title'];
145
}
return $achievements;
}
/*
* Funcion que devuelve que usuarios pueden tener logros asignados
*/
function get_user_achievements(){
$var = variable_get('achievements_role_list', '');
$str;
foreach ($var as $clave => $valor) { //para cada valor del array
if($valor>0){ //si valor > 0 quiere decir que se le pueden asignar logros
if(isset($str)){ //miramos si ya hemos añadido algo al string, en ese caso la nueva id
del rol la mirarems en una or en la sentencia sql
$str.=" OR ur.rid= ".$valor;
}
else{ // si es la primera vez no ponemos or
$str="ur.rid= ".$valor;
}
}
}
$users['blanco']='Escoge un usuario';
$result = db_query("SELECT u.uid, u.name FROM {users} u INNER JOIN
{users_roles} ur ON ur.uid = u.uid WHERE ".$str);
//miramos el numero de logros totales creados
$num_ach = db_result(db_query('SELECT COUNT(*) FROM {achievements_list}'));
while($row = db_fetch_array($result)){
//para cada usuario miramos el numero total de logros que
tiene asignados, si es menor al total lo añadimos a la lista
$ach_user=db_result(db_query('SELECT COUNT(*) FROM
{achievements_users} WHERE uid = %d',$row['uid']));
if($ach_user<$num_ach){
$users[ $row['uid']]=$row['name'];
}
}
return $users;
}
/*
* Funcion que implementa la cosntruccion del formulario por pasos para asignar logros
146
*/
function achievements_assign_achievement(&$form_state = NULL){
//Miramos si ya estamos en un estado avanzado del formulario o si estamos en el primer
paso.
$step = isset($form_state['values']) ? (int)$form_state['storage']['step'] : 1;
//Guardamos el siguiente paso
$form_state['storage']['step'] = $step+1;
//ponemos el titulo la descripción y el nombre del boton de envio correspondiente al
paso en el que estamos
$form['indicator'] = array(
'#type' => 'fieldset',
'#title'=>t('Step @number', array('@number'=>$step))
);
if($step == 1){
$us = get_user_achievements();
$form['indicator'][$step] = array(
'#type' => 'select',
'#title' => t('User'),
'#options' => $us,
'#description'=>t('Choose user.')
);
$button_name = t('Next');
}
else{
$form['indicator'][$step] = array(
'#type' => 'select',
'#title' => t('Achievements'),
'#options' =>get_assign_list($form_state['values'][1]) ,
'#description'=>t('Choose achievement.')
);
$button_name = t('Submit');
}
$form['submit']= array(
'#type' => 'submit',
'#value' => $button_name,
);
147
if($step ==2){
$form_state['storage']['user']=$form_state['values'][1];
}
return $form;
}
/*
* Funcion de validacion del formulario por pasos de asignacion de logros
*/
function achievements_assign_achievement_validate($form, &$form_state){
if($form_state['values'][1]=='blanco'){
form_set_error (1, t('Choose a user'));
}
if($form_state['values'][2]=='sin'){
form_set_error (2, t('You cannot assign achievement to this user.'));
}
}
/*
* Funcion de submit del formulario por pasos de asignacion de logros
*/
function achievements_assign_achievement_submit($form, &$form_state){
if($form_state['storage']['step']<3){
return;
}
$result = db_query("SELECT * FROM {achievements_users_punctuation} WHERE uid
= %d",$form_state['storage']['user']);
$row =db_fetch_array($result);
$cont =count($row);
$punct = db_result(db_query("SELECT value FROM {achievements_list} WHERE nid
= %d", $form_state['values'][2]));
if($cont<2){
db_query("INSERT INTO {achievements_users_punctuation} (uid,punctuation)
VALUES (%d, %d)",$form_state['storage']['user'],$punct );
}
else{
$punct += $row['punctuation'];
db_query("UPDATE {achievements_users_punctuation} SET punctuation = %d
WHERE uid = %d", $punct, $form_state['storage']['user']);
148
}
db_query("INSERT INTO {achievements_users} (nid,uid) VALUES (%d,
%d)",$form_state['values'][2],$form_state['storage']['user']);
//borramos storage
unset($form_state['storage']);
}
/*
* funcion que devuelve un array con los logros que se le pueden asignar a un usuario
*/
function get_assign_list($uid){
$result = db_query("SELECT al.nid, n.title FROM ({achievements_list} al INNER JOIN
{node} n ON al.nid = n.nid) INNER JOIN {achievements_users} au ON n.nid = au.nid
WHERE au.uid = %d", $uid);
while($row = db_fetch_array($result)) {
$achievements_user[$row['nid']]=$row['title'];
}
$achievements_list=get_achievements();
if(count($achievements_user)>0){
foreach ($achievements_list as $clave => $valor) {
if(!in_array($valor, $achievements_user)){
$achievements[$clave]=$valor;
}
}
}
else{
$achievements = $achievements_list;
}
return $achievements;
}
/*
* Funcion que implementa la cosntruccion del formulario por pasos para desasignar logros
*/
function achievements_deallocate_achievement(&$form_state = NULL){
//Miramos si ya estamos en un estado avanzado del formulario o si estamos en el primer
paso.
$step = isset($form_state['values']) ? (int)$form_state['storage']['step'] : 1;
//Guardamos el siguiente paso
149
$form_state['storage']['step'] = $step+1;
//ponemos el titulo la descripción y el nombre del boton de envio correspondiente al
paso en el que estamos
$form['indicator'] = array(
'#type' => 'fieldset',
'#title'=>t('Step @number', array('@number'=>$step))
);
if($step == 1){
$us = get_users_with_achievements();
$form['indicator'][$step] = array(
'#type' => 'select',
'#title' => t('User'),
'#options' => $us,
'#description'=>t('Choose user.')
);
$button_name = t('Next');
}
else{
$form['indicator'][$step] = array(
'#type' => 'select',
'#title' => t('Achievements'),
'#options' =>get_deallocate_list($form_state['values'][1]) ,
'#description'=>t('Choose achievement.')
);
$button_name = t('Submit');
}
$form['submit']= array(
'#type' => 'submit',
'#value' => $button_name,
);
if($step==2){
$form_state['storage']['user']=$form_state['values'][1];
}
return $form;
}
/*
150
* Funcion de validacion del formulario para desasginar logros
*/
function achievements_deallocate_achievement_validate($form,
&$form_state){
if($form_state['values'][1]=='sin'){
form_set_error (1, t('Choose a user'));
}
}
/*
* Funcion de submit del formulario para desasginar logros
*/
function achievements_deallocate_achievement_submit($form, &$form_state){
if($form_state['storage']['step']<3){
return;
}
$user_punct =db_result( db_query("SELECT punctuation FROM
{achievements_users_punctuation} WHERE uid = %d",$form_state['storage']['user']));
$punct = db_result(db_query("SELECT value FROM {achievements_list} WHERE nid
= %d", $form_state['values'][2]));
$user_punct -= $punct;
if($user_punct!=0){
db_query("UPDATE {achievements_users_punctuation} SET punctuation = %d
WHERE uid = %d", $user_punct, $form_state['storage']['user']);
}
else{
db_query("DELETE FROM {achievements_users_punctuation} WHERE uid =
%d",$form_state['storage']['user']);
}
db_query("DELETE FROM {achievements_users} WHERE nid = %d AND uid =
%d",$form_state['values'][2],$form_state['storage']['user']);
//borramos storage
unset($form_state['storage']);
}
/*
* Funcion que retorna un array con los usuarios que tienen logros asignados
*/
function get_users_with_achievements(){
$users['sin']="Escoge un usuario";
151
$result = db_query("SELECT au.uid, u.name FROM ({achievements_users} au LEFT
JOIN {users} u ON au.uid = u.uid)");
while($row = db_fetch_array($result)){
$users[$row['uid']]=$row['name'];
}
return $users;
}
/*
* Funcion que devuelve array con los logros que tiene asignados un usuario
*/
function get_deallocate_list($uid){
$result = db_query("SELECT al.nid, n.title FROM ({achievements_list} al INNER
JOIN {node} n ON al.nid = n.nid) INNER JOIN {achievements_users} au ON n.nid =
au.nid WHERE au.uid = %d", $uid);
while($row = db_fetch_array($result)) {
$achievements_user[$row['nid']]=$row['title'];
}
return $achievements_user;
}
Archivo achievements.tpl.php
<div class="achievements-value">Puntuación: <?php print $value; ?></div>
<div class="achievements-picture"><img src="<?php print $picture;
?>"></div>
<div class="achievements-description_achievement"><b>Descripción:</b>
<?php print $description_achievement; ?></div>
Archivo achievements.css
.achievements-value{
float:right;
border-style:dotted;
border-width:1px;
padding: 7px;
border-color: black;
font-size: 170%;
font-weight: bold;
}
.achievements-picture{
width: 400px;
}
152
12.2 Módulo Assistance
Archivo assistance.info
; $Id$
name= "Assistance"
description = "Module to create assistance to events"
dependencies[] = event
dependencies[] = views
core = 6.x
package = Ragnarok Guild
Archivo assistance.install
<?php
// $Id$
/**
* Implementation of hook_schema()
*/
function assistance_schema(){
$schema['assistance_node'] = array(
'description' => 'Store assistance info',
'fields' => array(
'nid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'vid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'uid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
153
'enid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'job' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'status' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array('nid'),
);
$schema['assistance_job'] = array(
'description' => 'Store jobs name',
'fields' => array(
'id' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'name' => array(
'type' => 'varchar',
'length' => 255,
'default' => '',
),
),
'primary key' => array('id'),
);
return $schema;
154
}
/**
* Implementation of hook_install()
*/
function assistance_install(){
drupal_install_schema('assistance');
db_query("INSERT INTO {assistance_job} (id, name) VALUES ('1'
,'Knight'), ('2' , 'Crusader'), ('3' , 'Wizard'), ('4' , 'Sage'), ('5' ,
'Assassin'), ('6' , 'Rogue'), ('7' , 'Priest'), ('8' , 'Monk'),
('9' , 'BlackSmith'), ('10' , 'Alchemist'), ('11' , 'Hunter'),
('12' , 'Bard'), ('13' , 'Dancer'), ('14' , 'Soul Linker'), ('15' ,
'Ninja'), ('16' , 'Super novice'), ('17' , 'Lord Knight'),
('18' , 'Paladin'), ('19' , 'High Wizard'), ('20' ,
'Scholar'),('21' , 'Assasin Cross'), ('22' , 'Stalker'), ('23' , 'High
Priest'), ('24' , 'Champion'), ('25' , 'Whitesmith'), ('26' , 'Creator'),
('27' , 'Sniper'), ('28' , 'Clown'), ('29' , 'Gypsy'),('30' , 'Star
Gladiator'),('31' , 'Gunslinger')");
}
function assistance_uninstall(){
drupal_uninstall_schema('assistance');
}
Archivo assistance.module
<?php
// $Id$
/**
* Implementation of hook_node_info()
*/
function assistance_node_info(){
return array(
'assistance_event' => array(
'name' => t('Assitance Event'),
'module' => 'assistance',
'description' => t('Assitance to event.'),
'title label' => t('Assistance'),
'has body' => FALSE,
),
'assistance_woe' => array(
'name' => t('Assitance Woe'),
'module' => 'assistance',
'description' => t('Assitance to woe.'),
155
'title label' => t('Assistance'),
'has body' => FALSE,
),
);
}
/**
* Implementation of hook_form(&$node, $form_state)
*/
function assistance_form(&$node, $form_state){
$type = node_get_types('type', $node);
if ($type->has_title){
$form['title'] = array(
'#type' => 'textfield',
'#title' => check_plain($type->title_label),
'#required' => TRUE,
'#default_value' => $node->title,
);
}
global $user;
$form['uid'] = array(
'#type' => 'hidden',
'#value' => $user->uid,
);
if($type->type == 'assistance_event'){
$options = get_future_events('event');
$title = 'Event';
}
else{
$title = 'WoE';
$options = get_future_events('woe');
}
$form['enid'] = array(
'#type' => 'select',
'#title' => t($title),
'#default_value' => isset ($node->enid) ? $node->enid :
'null',
'#options' => $options,
'#description' => t('Select a event'),
156
);
$var = variable_get('assistance_types', '');
if($var!=''){
$form['job'] = array(
'#type' => 'select',
'#title' => t('Pj'),
'#default_value' => isset ($node->job) ? $node>job : 'null',
'#options' => get_node_info($var),
'#description' => t('Select a pj'),
);
}
return $form;
}
/**
* Implementation of hook_validate()
*/
function assistance_validate($node ){
if($node->enid == 'null'){
form_set_error('enid', t('Choose one'));
}
if($node->job == 'null'){
form_set_error('job', t('Choose one'));
}
}
/**
* Implementation of hook_insert()
*/
function assistance_insert($node){
$error = FALSE;
$uid = db_result(db_query('SELECT uid FROM {assistance_node} WHERE
enid = %d AND uid = %d', $node->enid, $node->uid));
if($uid==$node->uid){
global $base_root, $base_path;
drupal_set_message(t("You've confirmed your Assistance
in this event"), 'error');
db_query("DELETE FROM {node} WHERE nid = %d", $node>nid);
db_query("DELETE FROM {node_revisions} WHERE nid = %d",
$node->nid);
$error = TRUE;
157
drupal_goto($base_root.$_SERVER['REQUEST_URI']);
}
$var = variable_get('assistance_types', '');
if($var!=''){
$job = db_result(db_query('SELECT job FROM
{assistance_node} WHERE enid = %d AND job = %d', $node->enid, $node>job));
if($job == $node->job){
global $base_root, $base_path;
drupal_set_message(t("This character is already
in use"), 'error');
db_query("DELETE FROM {node} WHERE nid = %d",
$node->nid);
db_query("DELETE FROM {node_revisions} WHERE nid
= %d", $node->nid);
$error = TRUE;
drupal_goto($base_root.$_SERVER['REQUEST_URI']);
}
}
if($error == FALSE){
db_query('INSERT INTO {assistance_node} (nid, vid, uid,
enid, job) VALUES (%d,%d,%d,%d,%d)', $node->nid,$node->vid,$node>uid,$node->enid,$node->job);
}
}
/**
* Implementation of hook_update()
*/
function assistance_update($node){
$var = variable_get('assistance_types', '');
if($var!=''){
$job = db_result(db_query('SELECT job FROM
{assistance_node} WHERE enid = %d AND job = %d', $node->enid, $node>job));
if($job == $node->job){
global $base_root, $base_path;
drupal_set_message(t("This character is already
in use"), 'error');
$error = TRUE;
drupal_goto($base_root.$_SERVER['REQUEST_URI']);
}
}
158
if($error == FALSE){
if(module_exists('party')){
if($node->status == 1){
$result = db_result(db_query("SELECT party_name FROM
{party} WHERE anid = %d",$node->nid));
db_query("DELETE FROM {party} WHERE anid = %d",$node>nid);
db_query("UPDATE {party_members} SET number = number-1
WHERE enid = %d AND party_name = '%s'", $node->enid, $result);
}
$num = db_result(db_query("SELECT number FROM {party_members}
WHERE enid = %d AND party_name = '%s'", $node->enid, $result));
if($num==0){
db_query("DELETE FROM {party_members} WHERE enid = %d
AND party_name = '%s'", $node->enid, $result);
}
}
db_query('UPDATE {assistance_node} SET enid = %d, job = %d, status
= 0 WHERE nid = %d', $node->enid,$node->job, $node->nid);
}
if(module_exists('party')){
if($node->status == 1){
$result = db_result(db_query("SELECT party_name FROM
{party} WHERE anid = %d",$node->nid));
db_query("DELETE FROM {party} WHERE anid = %d",$node>nid);
db_query("UPDATE {party_members} SET number = number-1
WHERE enid = %d AND party_name = '%s'", $node->enid, $result);
}
$num = db_result(db_query("SELECT number FROM {party_members}
WHERE enid = %d AND party_name = '%s'", $node->enid, $result));
if($num==0){
db_query("DELETE FROM {party_members} WHERE enid = %d
AND party_name = '%s'", $node->enid, $result);
}
}
db_query('UPDATE {assistance_node} SET enid = %d, job = %d, status
= 0 WHERE nid = %d', $node->enid,$node->job, $node->nid);
}
/**
* Implementation of hook_delete()
*/
function assistance_delete($node){
db_query('DELETE FROM {assistance_node} WHERE nid = %d',$node>nid);
159
if(module_exists('party')){
if($node->status == 1){
$result = db_result(db_query("SELECT party_name FROM
{party} WHERE anid = %d",$node->nid));
db_query("DELETE FROM {party} WHERE anid = %d",$node>nid);
db_query("UPDATE {party_members} SET number = number-1
WHERE enid = %d AND party_name = '%s'", $node->enid, $result);
}
$num = db_result(db_query("SELECT number FROM {party_members}
WHERE enid = %d AND party_name = '%s'", $node->enid, $result));
if($num==0){
db_query("DELETE FROM {party_members} WHERE enid = %d
AND party_name = '%s'", $node->enid, $result);
}
}
}
/**
* Implementation of hook_load()
*/
function assistance_load($node){
$additions = db_fetch_object(db_query('SELECT uid, enid, job FROM
{assistance_node} WHERE vid = %d',$node->vid));
return $additions;
}
/**
* Implementation of hook_view()
*/
function assistance_view($node, $teaser = FALSE, $page = FALSE){
$node = node_prepare($node, $teaser);
$node->content['uid'] = array(
'#value' => theme('assistance_uid', $node->uid),
'#weight' => 1,
);
$node->content['enid'] = array(
'#value' => theme('assistance_enid', $node->enid),
'#weight' => 2,
);
$node->content['job'] = array(
'#value' => theme('assistance_job', $node->job),
'#weight' => 3,
);
160
return $node;
}
/**
* Implementation of hook_theme()
*/
function assistance_theme(){
return array(
'assistance_uid' => array(
'arguments' => array('uid'=>0),
),
'assistance_enid' => array(
'arguments' => array('enid'=>0),
),
'assistance_job' => array(
'arguments' => array('job'=>0),
),
);
}
function theme_assistance_uid($uid){
$name = db_result(db_query("SELECT u.name FROM {users} u LEFT JOIN
{assistance_node} pa ON u.uid = pa.uid WHERE u.uid = %d", $uid));
$output = '<div class="assistance-uid">';
$output .= 'Usuario: '.$name;
$output .= '</div>';
return $output;
}
function theme_assistance_enid($enid){
$title = db_result(db_query("SELECT n.title FROM {node} n LEFT JOIN
{assistance_node} pa ON n.nid = pa.enid WHERE n.nid = %d", $enid));
$output = '<div class="assistance-enid">';
$output .= 'Evento: '.l($title, drupal_get_path_alias('node/'.$enid));
$output .= '</div>';
return $output;
}
function theme_assistance_job($job){
$var = variable_get('assistance_types', '');
if($var!=''){
$user = db_result(db_query("SELECT n.title FROM {node} n
LEFT JOIN {assistance_node} pa ON n.nid = pa.job WHERE n.nid = %d",
$job));
161
$output = '<div class="assistance-job">';
$output .= 'Personaje: '.l($user,
drupal_get_path_alias('node/'.$job));
$output .= '</div>';
}
return $output;
}
/**
* Implementation of hook_menu()
*/
function assistance_menu(){
$items['admin/settings/assistance'] = array(
'title' => t('Assistance settings'),
'description' => t('Settings for module assistance'),
'page callback' => 'drupal_get_form',
'page arguments' => array('assistance_admin_settings'),
'access arguments' => array('admin assistance'),
'type' => MENU_NORMAL_ITEM,
'file' => 'assistance.admin.inc',
);
return $items;
}
function assistance_perm(){
return array(
'admin assistance',
'create assistance',
'edit any assistance',
'edit own assistance',
'delete any assistance',
'delete own assistance',
);
}
/*
** Implementacion of hook_user()
*/
function assistance_user($op, &$edit, &$account, $category){
global $user;
if($op == 'delete'){
if(!module_exists('party')){
$result = db_query("SELECT * FROM {node} WHERE (type =
'assistance_event' OR type = 'assistance_event') AND uid = 0");
162
while($data = db_fetch_object($result)){
assistance_delete($data);
db_query('DELETE FROM {node} WHERE nid = %d',
$data->nid);
db_query('DELETE FROM {node_revisions} WHERE nid
= %d', $data->nid);
}
}
}
}
/**
* Implementation of hook_acces()
*/
function assistance_access($op, $node, $account){
switch ($op){
case 'create':
return user_access('create assistance', $account) ? TRUE : NULL;
case 'update':
return user_access('edit any assistance', $account) || (user_access('edit own
assistance', $account)&&($account->uid == $node->uid)) ? TRUE : NULL;
case 'delete':
return user_access('delete any assistance', $account) || (user_access('delete
own assistance', $account)&&($account->uid == $node->uid)) ? TRUE : NULL;
}
}
/**
* Funcion que devuelve array con el nid y titulo del tipo de contenido
que se le pasa por parametro
*/
function get_node_info($name){
$node['null'] = 'Escoge uno';
$result = db_query("SELECT nid, title FROM {node} WHERE type =
'%s'",$name);
while($row = db_fetch_array($result)){
$node[$row['nid']] = $row['title'];
}
return $node;
}
/*
* Funcion que devuelve array con el nid y titulo de los eventos que aun
no ha pasado la fecha de inicio
*/
163
function get_future_events($type){
$time = time();
$event['null'] = 'Escoge uno';
if($type == 'woe'){
$event['null'] = 'Escoge una';
}
$result = db_query("SELECT n.nid, n.title, e.event_start FROM
{node} n INNER JOIN {event} e ON n.nid = e.nid WHERE n.type =
'%s'",$type);
while($row = db_fetch_array($result)){
if(strtotime($row[event_start])>$time){
$event[$row['nid']] = $row['title'];
}
}
return $event;
}
/**
* Implementation of hook_views_api().
*/
function assistance_views_api() {
return array(
'api' => 2,
'path' => drupal_get_path('module', 'assistance'),
//'path' => drupal_get_path('module', 'assistance') . '/includes',
);
}
Archivo assistance.admin.inc
<?php
function assistance_admin_settings(){
$types = node_get_types('names');
$form['assistance_types'] = array(
'#type' => 'radios',
'#title' => t('Node type'),
'#options' => $types,
'#default_value' => variable_get('assistance_types', ''),
);
return system_settings_form($form);
}
164
12.3 Módulo Castle Control
Archivo castle_control.info
; $Id$
name= "Castle Control"
description = "Module to have information on the status of Castles."
core = 6.x
php = 5.1
package = Ragnarok Guild
Archivo castle_control.install
?php
// $Id$
/**
* Implementation of hook_schema()
*/
function castle_control_schema(){
$schema['castle_info'] = array(
'description' => 'Stores castle information.',
'fields' => array(
'delta' => array(
'type' => 'varchar',
'length' => 255,
'default' => '',
'not null' => TRUE,
),
'economy' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'defense' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
165
'daily_chests' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'daily_cost' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'owner' => array(
'type' => 'varchar',
'length' => 255,
'default' => '',
'not null' => TRUE,
),
),
'primary key' => array('delta'),
);
return $schema;
}
/**
* Implementation of hook_install()
*/
function castle_control_install(){
drupal_install_schema('castle_control');
}
/**
* Implementation of hook_uninstall()
*/
function castle_control_uninstall(){
drupal_uninstall_schema('castle_control');
}
166
Archivo castle_control.module
<?php
function castle_control_menu(){
$items['admin/build/castle_control'] = array(
'title' => t('Castle Control'),
'page callback' => 'drupal_get_form',
'page arguments' => array('castle_control_edit'),
'access arguments' => array('administer castles'),
'type' => MENU_NORMAL_ITEM,
'file' => 'castle_control.admin.inc',
);
$items['admin/build/castle_control/edit'] = array(
'title' => t('Update Castle Info'),
'description' => t('Update castle info'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => 0,
'file' => 'castle_control.admin.inc',
);
$items['admin/build/castle_control/add'] = array(
'title' => t('Add castle'),
'description' => t('add castle'),
'page callback' => 'drupal_get_form',
'page arguments' => array('castle_control_add'),
'access callback' => user_access('administer castles'),
'type' => MENU_LOCAL_TASK,
'weight' => 1,
'file' => 'castle_control.admin.inc',
);
$items['admin/build/castle_control/delete'] = array(
'title' => t('Delete castle'),
'description' => t('delete castle'),
'page callback' => 'drupal_get_form',
'page arguments' => array('castle_control_delete'),
'access callback' => user_access('administer castles'),
'type' => MENU_LOCAL_TASK,
'weight' => 1,
'file' => 'castle_control.admin.inc',
167
);
return $items;
}
function castle_control_perm(){
return array(
'administer castles','view castles',
);
}
function castle_control_block($op = 'list', $delta = 0, $edit = array
()){
switch($op) {
case 'list':
$result =db_query("SELECT delta FROM {castle_info}");
while($row = db_fetch_array($result)){
$blocks[$row['delta']]['info'] = 'Info '.$row['delta'];
$blocks[$row['delta']]['cache']= BLOCK_NO_CACHE;
}
return $blocks;
case 'view':
if(user_access('view castles')){
$row = db_fetch_array(db_query("SELECT * FROM
{castle_info} WHERE delta = '%s'",$delta));
$cost =
number_format($row['daily_cost'],0,'','.');
$items = array();
$items[] = t('Economy').': '.$row['economy'];
$items[] = t('Defense').': '.$row['defense'];
$items[] = t('Daily Chests').':
'.$row['daily_chests'];
$items[] = t('Daily Cost').': '.$cost.' zenys';
$items[] = t('Owner').': '.$row['owner'];
$block['subject'] = $row['delta'];
$block['content'] = theme('item_list', $items);
}
return $block;
}
}
168
Archivo castle_control.admin.inc
<?php
//$Id$
/**
* @file
* Resultado de llamadas a páginas de administración para el módulo Castle
Control
*/
function castle_control_add(&$form_state = NULL){
//Miramos si ya estamos en un estado avanzado del formulario o si
estamos en el primer paso.
$step = isset($form_state['values']) ?
(int)$form_state['storage']['step'] : 1;
//Guardamos el siguiente paso
$form_state['storage']['step'] = $step+1;
//ponemos el titulo la descripción y el nombre del boton de envio
correspondiente al paso en el que estamos
$form['indicator'] = array(
'#type' => 'fieldset',
'#title'=>t('Step @number', array('@number'=>$step))
);
if($step == 1){
$form['indicator']['name'] = array(
'#type' => 'textfield',
'#title' => t('Castle Name'),
);
$button_name = t('Next');
}
else{
$form['indicator']['economy'] = array(
'#type' => 'textfield',
'#title' => t('Economy'),
'#default_value' => 0,
);
$form['indicator']['defense'] = array(
'#type' => 'textfield',
'#title' => t('Defense'),
'#default_value' => 0,
);
$form['indicator']['daily_chests'] = array(
'#type' => 'textfield',
'#title' => t('Daily Chests'),
'#default_value' => 0,
);
$form['indicator']['daily_cost'] = array(
'#type' => 'textfield',
'#title' => t('Daily Cost'),
'#default_value' => 0,
);
$form['indicator']['owner'] = array(
'#type' => 'textfield',
'#title' => t('Owner'),
'#default_value' => '',
);
$button_name = t('Submit');
}
$form['submit']= array(
'#type' => 'submit',
'#value' => $button_name,
169
);
if($step ==2){
$form_state['storage']['name']= $form_state['values']['name'];
}
return $form;
}
function castle_control_add_validate($form, &$form_state){
if($form_state['storage']['step']==2){
$name = $form_state['values']['name'];
$result =db_query("SELECT delta FROM {castle_info}");
while($row = db_fetch_array($result)){
if($row['delta']==$name) $exist = TRUE;
}
if(is_numeric($name)||$name=="" ){
form_set_error ('name', t('Invalid name'));
}
if($exist == TRUE){
form_set_error ('name', t('This castle is already in the
database'));
}
}
else{
$eco = 'a'.$form_state['values']['economy'];
$pos = strpos($eco, "-");
if(!is_numeric($form_state['values']['economy'])||($pos==1)){
form_set_error ('economy', t('Economy must be a positive
number'));
}
if($form_state['values']['economy']>100){
form_set_error ('economy', t('Economy can not be higher
than').'100');
}
$def = 'a'.$form_state['values']['defense'];
$pos = strpos($def, "-");
if(!is_numeric($form_state['values']['defense'])||($pos==1)){
form_set_error ('defense', t('Defense must be a positive
number'));
}
if($form_state['values']['defense']>100){
form_set_error ('defense', t('Defense can not be higher
than').'100');
}
$chest = 'a'.$form_state['values']['daily_chests'];
$pos = strpos($chest, "-");
if(!is_numeric($form_state['values']['daily_chests'])||($pos==1)){
form_set_error ('daily_chests', t('Daily chests must be a
positive number'));
}
$cost = 'a'.$form_state['values']['daily_cost'];
$pos = strpos($cost, "-");
if(!is_numeric($form_state['values']['daily_cost'])||($pos==1)){
form_set_error ('daily_cost', t('Daily cost must be a
positive number'));
}
if(is_numeric($form_state['values']['owner'])||$form_state['values']['own
er']=="" ){
form_set_error ('owner', t('Owner must be a string'));
}
}
170
}
function castle_control_add_submit($form, &$form_state){
if($form_state['storage']['step']<3){
return;
}
db_query("INSERT INTO {castle_info} (delta, economy, defense,
daily_chests, daily_cost, owner) VALUES ('%s', %d, %d, %d, %d,
'%s')",$form_state['storage']['name'],
$form_state['values']['economy'],$form_state['values']['defense'],$form_s
tate['values']['daily_chests'],$form_state['values']['daily_cost'],$form_
state['values']['owner'],$form_state['values']['castles']);
unset($form_state['storage']);
$form_state['redirect']='admin/build/block';
}
function castle_control_edit(&$form_state = NULL){
//Miramos si ya estamos en un estado avanzado del formulario o si
estamos en el primer paso.
$step = isset($form_state['values']) ?
(int)$form_state['storage']['step'] : 1;
//Guardamos el siguiente paso
$form_state['storage']['step'] = $step+1;
//ponemos el titulo la descripción y el nombre del boton de envio
correspondiente al paso en el que estamos
$form['indicator'] = array(
'#type' => 'fieldset',
'#title'=>t('Step @number', array('@number'=>$step))
);
if($step == 1){
$castles = get_castles();
$form['indicator']['castles'] = array(
'#type' => 'select',
'#title' => t('Castle'),
'#options' => $castles,
);
$button_name = t('Next');
}
else{
$row=db_fetch_array(db_query("SELECT * FROM {castle_info} WHERE
delta = '%s'",$form_state['values']['castles']));
$form['indicator']['name'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
'#default_value' => $row['delta'],
);
$form['indicator']['economy'] = array(
'#type' => 'textfield',
'#title' => t('Economy'),
'#default_value' => $row['economy'],
);
$form['indicator']['defense'] = array(
'#type' => 'textfield',
'#title' => t('Defense'),
'#default_value' => $row['defense'],
);
$form['indicator']['daily_chests'] = array(
'#type' => 'textfield',
'#title' => t('Daily Chests'),
'#default_value' => $row['daily_chests'],
);
171
$form['indicator']['daily_cost'] = array(
'#type' => 'textfield',
'#title' => t('Daily Cost'),
'#default_value' => $row['daily_cost'],
);
$form['indicator']['owner'] = array(
'#type' => 'textfield',
'#title' => t('Owner'),
'#default_value' => $row['owner'],
);
$button_name = t('Update');
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => $button_name,
);
if($step==2){
$form_state['storage']['name']= $form_state['values']['castles'];
}
return $form;
}
function castle_control_edit_validate($form, &$form_state){
if($form_state['storage']['step']==2){
if($form_state['values']['castles']=='sin'){
form_set_error ('castles', t('Choose a valid Castle'));
}
}
else{
if(is_numeric($form_state['values']['name'])||$form_state['values']['name
']=="" ){
form_set_error ('name', t('Owner must be a string'));
}
$eco = 'a'.$form_state['values']['economy'];
$pos = strpos($eco, "-");
if(!is_numeric($form_state['values']['economy'])||($pos==1)){
form_set_error ('economy', t('Economy must be a positive
number'));
}
if($form_state['values']['economy']>100){
form_set_error ('economy', t('Economy can not be higher
than').'100');
}
$def = 'a'.$form_state['values']['defense'];
$pos = strpos($def, "-");
if(!is_numeric($form_state['values']['defense'])||($pos==1)){
form_set_error ('defense', t('Defense must be a positive
number'));
}
if($form_state['values']['defense']>100){
form_set_error ('defense', t('Defense can not be higher
than').'100');
}
$chest = 'a'.$form_state['values']['daily_chests'];
$pos = strpos($chest, "-");
if(!is_numeric($form_state['values']['daily_chests'])||($pos==1)){
form_set_error ('daily_chests', t('Daily chests must be a
positive number'));
}
$cost = 'a'.$form_state['values']['daily_cost'];
172
$pos = strpos($cost, "-");
if(!is_numeric($form_state['values']['daily_cost'])||($pos==1)){
form_set_error ('daily_cost', t('Daily cost must be a
positive number'));
}
if(is_numeric($form_state['values']['owner'])||$form_state['values']['own
er']=="" ){
form_set_error ('owner', t('Owner must be a string'));
}
}
}
function castle_control_edit_submit($form, &$form_state){
if($form_state['storage']['step']<3){
return;
}
if($form_state['storage']['name']==$form_state['values']['name']){
db_query("UPDATE {castle_info} SET economy = %d, defense = %d,
daily_chests = %d, daily_cost = %d, owner = '%s' WHERE delta = '%s'",
$form_state['values']['economy'],$form_state['values']['defense'],$form_s
tate['values']['daily_chests'],$form_state['values']['daily_cost'],$form_
state['values']['owner'],$form_state['storage']['name']);
}
else{
db_query("UPDATE {castle_info} SET delta = '%s', economy = %d,
defense = %d, daily_chests = %d, daily_cost = %d, owner = '%s' WHERE
delta = '%s'", $form_state['values']['name'],
$form_state['values']['economy'],$form_state['values']['defense'],$form_s
tate['values']['daily_chests'],$form_state['values']['daily_cost'],$form_
state['values']['owner'],$form_state['storage']['name']);
db_query("UPDATE {blocks} SET delta = '%s' WHERE module =
'castle_control' AND delta =
'%s'",$form_state['values']['name'],$form_state['storage']['name']);
// $form_state['redirect']='admin/build/block';
}
unset($form_state['storage']);
}
function castle_control_delete(){
$castles = get_castles();
$form['castles'] = array(
'#type' => 'select',
'#title' => t('Castle'),
'#options' => $castles,
);
$form['delete'] = array(
'#type' => 'submit',
'#value' => t('Delete Castle'),
);
return $form;
}
function castle_control_delete_validate($form, &$form_state){
if($form_state['values']['castles']=='sin'){
form_set_error ('castles', t('Choose a valid Castle'));
}
}
function castle_control_delete_submit($form, &$form_state){
db_query("DELETE FROM {castle_info} WHERE delta =
173
'%s'",$form_state['values']['castles']);
db_query("DELETE FROM {blocks} WHERE delta = '%s' AND module =
'castle_control'",$form_state['values']['castles']);
}
function get_castles(){
$result = db_query("SELECT delta FROM {castle_info}");
$castles['sin'] = 'Escoge un castillo';
while($row = db_fetch_array($result)){
$castles[ $row['delta']]=$row['delta'];
}
return $castles;
}
12.4 Módulo Guild Shop
Archivo guild_shop.info
; $Id$
name= "Guild Shop"
description = "Module to add a guild shop with internal balance."
dependencies[] = views
dependencies[] = taxonomy
core = 6.x
package = Ragnarok Guild
Archivo guild_shop.install
<?php
// $Id$
/**
* Implementation of hook_schema()
*/
function guild_shop_schema(){
$schema['gs_internal_balance'] = array(
'description' => 'Stores internal balance of users',
'fields' => array(
'uid' => array(
//field referred to user identifier
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
174
'default' => 0,
),
'internal_balance' =>array(
//balance of user
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'
default' => 0,
),
),
'primary key' => array('uid','internal_balance'),
);
$schema['gs_item'] = array(
'description' => 'Stores items of guild shop',
'fields' => array(
'nid' => array(
// id of the node set
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'vid' => array(
//version of the node set
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'description_item' => array(
//description of the item
'type' => 'text',
'not null' => TRUE,
'size' => 'big',
),
175
'type_item' => array(
//type of the item
'type' => 'varchar',
'length' => 255,
'default' => '',
),
'price' => array(
//price of the item
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'stock' => array(
//stock of the item
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'picture' => array(
//picture of the item
'type' => 'varchar',
'length' => 255,
'default' => '',
),
),
//primary key formed by nid field
'primary key' => array('nid'),
);
$schema['gs_purchase'] = array(
'description' => 'Stores purchases made by users',
'fields' => array(
'nid' => array(
// id of the node set
'type' => 'int',
176
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'vid' => array(
// version of the node set
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'user_name' => array(
//name of the user making the purchase
'type' => 'varchar',
'length' => 255,
'default' => '',
),
'item_name' => array(
//name of the item that was purchased
'type' => 'varchar',
'length' => 255,
'default' => '',
),
'amount' => array(
//amount of items that was purchased
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array('nid'),
);
return $schema;
}
177
/**
* Implementation of hook_install()
*/
function guild_shop_install(){
drupal_install_schema('guild_shop');
db_query("INSERT INTO {vocabulary} (name, relations, hierarchy, multiple,
required, tags, module, weight)VALUES ('type item', 1,0,0,0,0,'Guild Shop',0)");
$vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE name = 'type
item'"));
db_query("INSERT INTO {term_data}(vid, name, weight) VALUES (%d, 'Armor',
0),(%d, 'Card', 1),(%d, 'Healing Item', 2),(%d, 'Miscellaneous', 3),(%d, 'Usable Item',
4),(%d, 'Weapon', 5)",$vid,$vid,$vid,$vid,$vid,$vid);
$result=db_query("SELECT tid FROM {term_data} WHERE vid = %d",$vid);
while($row = db_fetch_array($result)){
db_query("INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d,
0)",$row['tid']);
}
}
/**
* Implementation of hook_uninstall()
*/
function guild_shop_uninstall(){
drupal_uninstall_schema('guild_shop');
$vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE name = 'type
item'"));
$result=db_query("SELECT tid FROM {term_data} WHERE vid = %d",$vid);
while($row = db_fetch_array($result)){
db_query("DELETE FROM {term_hierarchy} WHERE tid = %d",$row['tid']);
}
db_query("DELETE FROM {term_data} WHERE vid = %d", $vid);
db_query("DELETE FROM {vocabulary} WHERE module = 'Guild Shop'");
}
Archivo guild_shop.module
<?php
// $Id$
/**
* Implementation of hook_node_info()
*/
178
function guild_shop_node_info(){
return array(
'gs_item' => array(
'name' => t('Shop Item'),
'module' => 'guild_shop',
'description' => t('Item for sale in the shop.'),
'title label' => t('Item name'),
'has body' => FALSE,
),
'gs_purchase' => array(
'name' => t('Purchase'),
'module' => 'guild_shop',
'description' => t('Purchase made by user.'),
'title label' => t('Purchase'),
'has body' => FALSE,
),
);
}
/**
* Implementation of hook_form(&$node, $form_state)
*/
function guild_shop_form(&$node, $form_state){
$type = node_get_types('type', $node);
if ($type->has_title){
$form['title'] = array(
'#type' => 'textfield',
'#title' => check_plain($type->title_label),
'#required' => TRUE,
'#default_value' => $node->title,
);
}
if($type->type==gs_item){
$form['#attributes'] = array('enctype' => "multipart/form-data");
$form['description_item'] = array(
'#type' => 'textarea',
'#title' => t('Description'),
'#required' => TRUE,
'#default_value' => isset($node->description_item) ? $node->description_item: '',
179
'#description' => t('Description of item.'),
);
$form['type_item'] = array(
'#type' => 'select',
'#title' => t('Type'),
'#default_value' => isset ($node->type_item) ? $node->type_item : 'armor',
'#options' => array(
'card' => t('Card'),
'armor' => t('Armor'),
'weapon' => t('Weapon'),
'healing item' => t('Healing Item'),
'usable item' => t('Usable Item'),
'miscellaneous' => t('Miscellaneous'),
),
'#description' => t('Select type of item'),
);
$form['price'] = array(
'#type' => 'textfield',
'#title' => t('Price'),
'#required' => TRUE,
'#default_value' => isset ($node->price) ? $node->price : '0',
'#description' => t('Price of item'),
);
$form['picture'] = array(
'#type' => 'file',
'#title' => t('Picture'),
'#description' => t('Picture of shop item.<br> resolution max: 90x120 pixels'),
);
}
if($type->type==gs_purchase){
$form['user_name'] = array(
'#type' => 'textfield',
'#title' => t('User name'),
'#required' => TRUE,
'#default_value' => isset ($node->user_name) ? $node->user_name : '',
180
'#description' => t('Name of the user making the purchase.'),
);
$form['item_name'] = array(
'#type' => 'textfield',
'#title' => t('Item name'),
'#required' => TRUE,
'#default_value' => isset ($node->item_name) ? $node->item_name : '',
'#description' => t('Name of the item that was purchased.'),
);
$form['amount'] = array(
'#type' => 'textfield',
'#title' => t('Amount'),
'#required' => TRUE,
'#default_value' => isset ($node->amount) ? $node->amount : '',
'#description' => t('Amount of items that was purchased.'),
);
}
return $form;
}
/**
* Implementation of hook_validate()
*/function guild_shop_validate($node ){
if($node->type==gs_item){
if(!is_numeric($node->price)||($node->price<0)){
form_set_error('price', t('The value must be a positive number'));
}
}
}
function guild_shop_insert($node){
if($node->type==gs_item){
$validators = array(
'file_validate_is_image' => array(),
'file_validate_image_resolution' => array('90x120'),
);
$directory = file_directory_path();
$directory .= '/pictures';
181
if($file = file_save_upload('picture', $validators,$directory,
FILE_EXISTS_RENAME)){
$file->description = $file->filename;
$file->new = TRUE;
file_set_status($file, FILE_STATUS_PERMANENT);
}
db_query("INSERT INTO {gs_item} (vid, nid, description_item, type_item, price,
picture) VALUES (%d, %d, '%s', '%s', %d, '%s')", $node->vid, $node->nid, $node>description_item, $node->type_item, $node->price, $file->filepath);
$vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE name =
'type item'"));
$tid = db_result(db_query("SELECT tid FROM {term_data} WHERE name = '%s'
AND vid = %d",$node->type_item,$vid));
db_query("INSERT INTO {term_node} (nid, vid, tid) VALUES
(%d,%d,%d)",$node->nid,$node->vid,$tid);
}
if($node->type==gs_purchase){
db_query("INSERT INTO {gs_purchase} (vid, nid, user_name, item_name,
amount) VALUES (%d, %d, '%s', '%s', %d)", $node->vid, $node->nid, $node>user_name, $node->item_name, $node->amount);
}
}
/**
* Implementation of hook_update()
*/
function guild_shop_update($node){
if($node->type==gs_item){
$pic = db_result(db_query('SELECT picture FROM {gs_item} WHERE nid =
%d',$node->nid));
$validators = array(
'file_validate_is_image' => array(),
'file_validate_image_resolution' => array('90x120'),
);
$directory = file_directory_path();
$directory .= '/pictures';
if($file = file_save_upload('picture', $validators,$directory,
FILE_EXISTS_RENAME)){
$file->description = $file->filename;
$file->new = TRUE;
182
file_set_status($file, FILE_STATUS_PERMANENT);
db_query("UPDATE {gs_item} SET description_item = '%s', type_item = '%s',
price = '%d', picture = '%s' WHERE vid = %d", $node->description_item, $node>type_item, $node->price, $file->filepath, $node->vid);
file_delete($pic);
}
else{
db_query("UPDATE {gs_item} SET description_item = '%s', type_item = '%s',
price = '%d' WHERE vid = %d", $node->description_item, $node->type_item, $node>price, $node->vid);
$vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE name =
'type item'"));
$tid = db_result(db_query("SELECT tid FROM {term_data} WHERE name = '%s'
AND vid = %d",$node->type_item,$vid));
db_query("UPDATE {term_node} SET tid = %d WHERE nid = %d",$tid,$node>nid);
}
}
}
/**
* Implementation of hook_delete()
*/
function guild_shop_delete($node){
if($node->type==gs_item){
$pic = db_result(db_query('SELECT picture FROM {gs_item} WHERE nid =
%d',$node->nid));
db_query('DELETE FROM {gs_item} WHERE nid = %d', $node->nid);
file_delete($pic);
db_query("DELETE FROM {term_node} WHERE nid = %d",$node->nid);
}
if($node->type==gs_purchase){
db_query('DELETE FROM {gs_purchase} WHERE nid = %d', $node->nid);
}
}
/**
* Implementation of hook_load()
*/
function guild_shop_load($node){
if($node->type==gs_item){
183
$additions = db_fetch_object(db_query('SELECT description_item, type_item, price,
stock FROM {gs_item} WHERE vid = %d', $node->vid));
}
if($node->type==gs_purchase){
$additions = db_fetch_object(db_query('SELECT user_name, item_name, amount
FROM {gs_purchase} WHERE vid = %d', $node->vid));
}
return $additions;
}
/**
* Implementation of hook_view()
*/
function guild_shop_view($node, $teaser = FALSE, $page = FALSE){
global $base_root, $base_path;
$node = node_prepare($node, $teaser);
if($node->type==gs_item){
$picture = db_result(db_query('SELECT picture FROM {gs_item}
WHERE nid = %d',$node->nid));
if($picture!=''){
$pic = $base_root.$base_path.$picture;
}
else{
$pic =
$base_root.$base_path.'sites/default/files/noimg90x120.jpg';
}
$node->content['node_item'] = array(
'#value' => theme('guild_shop_node_item', $pic, $node>description_item, $node->price, $node->stock, $node->nid),
'#weight' => 0,
);
}
if($node->type==gs_purchase){
$node->content['node_purchase'] = array(
'#value' => theme('guild_shop_node_purchase', $node>user_name, $node->item_name, $node->amount),
'#weight' => 0,
);
}
return $node;
}
184
/**
* Implementation of hook_theme()
*/
function guild_shop_theme(){
return array(
'guild_shop_node_item' => array(
'template' => 'guild_shop',
'arguments' => array('picture'=>0, 'description_item'=>0, 'price'=>0, 'stock'=>0,
'nid'=>0),
),
'guild_shop_node_purchase' => array(
'template' => 'purchase',
'arguments' => array('user_name'=>0, 'item_name'=>0, 'amount'=>0),
),
);
}
/**
* Implementation of hook_init().
*/
function guild_shop_init() {
drupal_add_css(drupal_get_path('module', 'guild_shop') .'/guild_shop.css');
}
function guild_shop_perm(){
return array(
'create item shop',
'delete own item shop',
'delete any item shop',
'edit own item shop',
'edit any item shop',
'administer shop',
'create purchase',
'buy item',
);
}
/**
* Implementation of hook_acces()
*/
function guild_shop_access($op, $node, $account){
185
switch ($op){
case 'create':
return user_access('create item shop', $account) ? TRUE : NULL;
case 'update':
return user_access('edit any item shop', $account) || (user_access('edit own
item shop', $account)&&($account->uid == $node->uid)) ? TRUE : NULL;
case 'delete':
return user_access('delete any item shop', $account) || (user_access('delete own
item shop', $account)&&($account->uid == $node->uid)) ? TRUE : NULL;
}
}
/**
* Implementation of hook_menu()
*/
function guild_shop_menu(){
$items['admin/build/guild_shop'] = array(
'title' => t('Guild Shop'),
'description' => t('Admin for module Guild Shop'),
'page callback' => 'drupal_get_form',
'page arguments' => array('guild_shop_stocks'),
'access arguments' => array('administer shop'),
'type' => MENU_NORMAL_ITEM,
'file' => 'guild_shop.admin.inc',
);
$items['admin/build/guild_shop/stocks'] = array(
'title' => t('Stocks'),
'description' => t('Update stocks'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => 0,
'file' => 'guild_shop.admin.inc',
);
$items['admin/build/guild_shop/balances'] = array(
'title' => t('User Balances'),
'description' => t('Update balances'),
'page callback' => 'drupal_get_form',
'page arguments' => array('guild_shop_balances'),
'access callback' => user_access('administer shop'),
'type' => MENU_LOCAL_TASK,
186
'weight' => 1,
'file' => 'guild_shop.admin.inc',
);
$items['purchase_submit/%'] = array(
'title' => t('Guild Shop'),
'page callback' => 'drupal_get_form',
'page arguments' => array('guild_shop_purchase_submit'),
'access callback' => user_access('buy item'),
'type' => MENU_CALLBACK,
);
$items['complete_purchase'] = array(
'title' => t('Guild Shop'),
'page callback' => 'guild_shop_complete_purchase',
'access callback' => user_access('buy item'),
'type' => MENU_CALLBACK,
);
return $items;
}
function guild_shop_purchase_submit(){
global $user;
if(!isset($_SESSION['id_item'])){
$dd = explode('/', $_SERVER['REQUEST_URI']);
$_SESSION['id_item']=$dd[3];
$id = $_SESSION['id_item'];
}
else{
$dd = explode('/', $_SERVER['REQUEST_URI']);
if($dd[3]!=$_SESSION['id_item']){
$_SESSION['id_item']=$dd[3];
}
$id = $_SESSION['id_item'];
}
$balance_query = db_result(db_query('SELECT internal_balance FROM
{gs_internal_balance} WHERE uid = %d', $user->uid));
$row = db_fetch_array(db_query("SELECT n.title, gi.price, gi.stock FROM {node} n
INNER JOIN {gs_item} gi ON gi.nid=n.nid WHERE n.nid=%d", $id));
$balance = number_format($balance_query,0,'','.');
$price = number_format($row['price'],0,'','.');
187
$stock = $row['stock'];
if($row['stock'] != 0){
$form['text_balance']= array(
'#value' => '<p><b>'.t('Balance').':
</b>'.$balance.'</p>',
);
$form['text_item'] = array(
'#value' => '<p><b>'.t('Item').':
</b>'.$row['title'].'</p>',
);
$form['text_price'] = array(
'#value' => '<p><b>'.t('Price').':
</b>'.$price.'</p>',
);
$form['text_stock'] = array(
'#value' => '<b>'.t('Stock').': </b>'.$stock,
);
$form['amount'] = array(
'#type' => 'textfield',
'#title' => t('Amount'),
);
$form['balance'] = array(
'#type' => 'hidden',
'#value' => $balance_query,
);
$form['stock'] = array(
'#type' => 'hidden',
'#value' => $stock,
);
$form['price'] = array(
'#type' => 'hidden',
'#value' => $row['price'],
);
$form['id'] = array(
'#type' => 'hidden',
'#value' => $id,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Purchase'),
'#redirect' => 'after_purchase',
188
);
}
else{
$form['text_balance']= array(
'#value' => '<p><h1><b>Estás realizando una
operación ilegal!!!!</h1></p>',
);
}
return $form;
}
function guild_shop_purchase_submit_validate($form, &$form_state){
$str = 'a'.$form_state['values']['amount'];
$pos = strpos($str, "-");
$amount = $form_state['values']['amount'];
$stock = $form_state['values']['stock'];
$balance = $form_state['values']['balance'];
$price = $form_state['values']['price'];
if(!is_numeric($form_state['values']['amount'])||($pos==1)){
form_set_error ('amount', t('Must be a positive number'));
}
if($amount>$stock){
form_set_error('amount', t('you can only buy a maximum of ').$stock.t(' units'));
}
if($balance<$price*$amount){
form_set_error('amount', t('insufficient balance'));
}
}
function guild_shop_purchase_submit_submit($form, &$form_state){
global $user;
$name= db_result(db_query('SELECT title FROM {node} WHERE nid = %d',
$_SESSION['id_item']));
unset($_SESSION['id_item']);
$actual_stock = $form_state['values']['stock']- $form_state['values']['amount'];
$actual_balance = $form_state['values']['balance'] ($form_state['values']['amount']*$form_state['values']['price']);
db_query('UPDATE {gs_item} SET stock = %d WHERE nid = %d', $actual_stock,
$form_state['values']['id']);
189
db_query('UPDATE {gs_internal_balance} SET internal_balance = %d WHERE uid =
%d', $actual_balance, $user->uid);
$node->type = 'gs_purchase';
$node->title = $user->name.' purchase '.$name;
$node->user_name = $user->name;
$node->item_name = $name;
$node->amount = $form_state['values']['amount'];
$node->uid = $user->uid;
$time = time();
db_query("INSERT INTO {node} (type, title, uid, status, created, changed, comment,
promote) VALUES ('%s', '%s', %d, %d, %d, %d, %d, %d)",$node->type, $node->title,
$user->uid, 1, $time, $time, 0,0);
$id = db_result(db_query('SELECT nid FROM {node} WHERE uid = %d AND created
= %d', $user->uid, $time));
db_query('UPDATE {node} SET vid = %d WHERE nid = %d', $id, $id);
db_query("INSERT INTO {node_revisions} (nid, vid, uid, title, timestamp) VALUES
(%d, %d, %d, '%s', %d)", $id, $id, $user->uid, $node->title, $time);
$node->nid = $id;
$node->vid = $id;
guild_shop_insert($node);
$form_state['redirect'] = 'complete_purchase';
}
function guild_shop_complete_purchase(){
global $user;
$balance_query = db_result(db_query('SELECT internal_balance FROM
{gs_internal_balance} WHERE uid = %d', $user->uid));
$balance = number_format($balance_query,0,'','.');
$output = '<p><font size = "3" >'.t('Purchase Complete.').' </font></p>';
$output .= t('Actual Balance: ').$balance;
return $output;
}
/**
* Implementation of hook_block()
*/
function guild_shop_block($op = 'list', $delta = 0, $edit = array ()){
switch($op) {
case 'list':
$blocks[0]['info'] = t('Last items added');
190
$blocks[0]['cache']= BLOCK_NO_CACHE;
$blocks[1]['info'] = t('Latest purchases');
$blocks[1]['cache']= BLOCK_NO_CACHE;
$blocks[2]['info'] = t('Guild Shop menu');
$blocks[2]['cache']= BLOCK_NO_CACHE;
$blocks[3]['info'] = t('Guild Shop user info');
$blocks[3]['cache']= BLOCK_NO_CACHE;
return $blocks;
case 'view':
if($delta == 0 && user_access('buy item')){
$result = db_query_range("SELECT title, nid FROM {node} WHERE type =
'gs_item'ORDER BY created desc",0,5);
$items = array();
while($row= db_fetch_array($result)){
$items[] = l($row['title'], drupal_get_path_alias('node/'.$row[nid]));
}
$block['subject'] = t('last items added');
$block['content'] = theme('item_list', $items);
}
if($delta == 1 && user_access('administer shop')){
$result = db_query_range("SELECT title, nid FROM {node} WHERE type =
'gs_purchase'ORDER BY created desc",0,5);
$items = array();
while($row= db_fetch_array($result)){
$items[] = l($row['title'], drupal_get_path_alias('node/'.$row[nid]));
}
$block['subject'] = t('latest purchases');
$block['content'] = theme('item_list', $items);
}
if($delta == 2 && user_access('buy item')){
$items = array();
$items[] = l(t('All items'), drupal_get_path_alias('guild_shop'));
$items[] = l(t('Cards'), drupal_get_path_alias('guild_shop/card'));
$items[] = l(t('Armors'), drupal_get_path_alias('guild_shop/armor'));
$items[] = l(t('Weapons'), drupal_get_path_alias('guild_shop/weapon'));
$items[] = l(t('Healing Item'), drupal_get_path_alias('guild_shop/healing_item'));
191
$items[] = l(t('Usable Item'), drupal_get_path_alias('guild_shop/usable_item'));
$items[] = l(t('Miscellaneous'),
drupal_get_path_alias('guild_shop/miscellaneous'));
$block['subject'] = t('Guild Shop');
$block['content'] = theme('item_list', $items);
}
if($delta == 3 && user_access('buy item')){
global $user;
$result = db_query_range("SELECT title, nid FROM {node} WHERE type =
'gs_purchase' AND uid = %d ORDER BY created desc",$user->uid,0,1);
$items = array();
$row=db_fetch_array($result);
if($row['title']==''){
$items[] = t('Last purchase: none');
}
else{
$items[] = t('Last purchase: ').l($row['title'],
drupal_get_path_alias('node/'.$row[nid]));
}
$punct = db_result(db_query('SELECT internal_balance FROM
{gs_internal_balance} WHERE uid = %d', $user->uid));
if($punct==''){
$punct = 0;
}
$balance = number_format($punct,0,'','.');
$items[] = t('Balance: ').$balance;
$block['subject'] = t('Guild Shop user info');
$block['content'] = theme('item_list', $items);
}
return $block;
}
}
/**
* Implementation of hook_views_api().
*/
function guild_shop_views_api(){
return array(
192
'api' => 2,
'path' => drupal_get_path('module', 'guild_shop'),
//'path' => drupal_get_path('module', 'guild_shop') . '/includes',
);
}
/*
* Implementation of hook_user().
*/
function guild_shop_user($op, &$edit, &$user, $category = NULL){
switch($op){
case 'delete':
db_query('DELETE FROM {gs_internal_balance} WHERE uid = %d', $user>uid);
$result = db_query("SELECT nid, vid FROM {node} WHERE uid = 0 AND type
= 'gs_purchase'");
while($row = db_fetch_array($result)){
db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid =
%d", $row['nid'], $row['vid']);
db_query("DELETE FROM {node} WHERE nid = %d AND vid = %d",
$row['nid'], $row['vid']);
}
}
}
Archivo guild_shop.admin.inc
<?php
//$Id$
/**
* @file
* Resultado de llamadas a páginas de administración para el módulo Guild
Shop
*/
function guild_shop_stocks(){
$items = get_items();
$form['items'] = array(
'#type' => 'select',
'#title' => t('Item Shop'),
'#options' => $items,
193
);
$form['stock'] = array(
'#type' => 'textfield',
'#title' => t('Amount'),
);
$form['add'] = array(
'#type' => 'submit',
'#value' => t('Add Stock'),
);
return $form;
}
function guild_shop_balances(){
$us = get_user_guild_shop();
$form['users'] = array(
'#type' => 'select',
'#title' => t('users'),
'#options' => $us,
);
$form['balance'] = array(
'#type' => 'textfield',
'#title' => t('Balance'),
);
$form['add'] = array(
'#type' => 'submit',
'#value' => t('Add Balance'),
);
return $form;
}
function get_items(){
$result = db_query("SELECT nid, title FROM {node} where type = 'gs_item'");
$items['blanco']='Escoge un item';
while($row = db_fetch_array($result)){
$items[ $row['nid']]=$row['title'];
}
return $items;
}
194
function get_user_guild_shop(){
$var = user_roles($membersonly = TRUE, $permission = 'buy item');
$str;
foreach ($var as $clave => $valor) { //para cada valor del array
if(isset($str)){ //miramos si ya hemos añadido algo al string, en ese caso la nueva id
del rol la mirarems en una or en la sentencia sql
$str.=" OR r.name = '".$valor."'";
}
else{ // si es la primera vez no ponemos or
$str="r.name = '".$valor."'";
}
}
$result = db_query("SELECT u.uid, u.name FROM ({users} u INNER JOIN
{users_roles} ur ON ur.uid = u.uid) INNER JOIN {role} r ON ur.rid = r.rid WHERE
".$str);
$users['blanco']='Escoge un usuario';
while($row = db_fetch_array($result)){
$users[ $row['uid']]=$row['name'];
}
return $users;
}
function guild_shop_stocks_validate($form, &$form_state){
$str = 'a'.$form_state['values']['stock'];
$pos = strpos($str, "-");
if(!is_numeric($form_state['values']['stock'])||($pos==1)){
form_set_error ('stock', t('Must be a positive number'));
}
if($form_state['values']['items']=='blanco'){
form_set_error ('items', t('Choose an item.'));
}
}
function guild_shop_stocks_submit($form, &$form_state){
$amount = db_result(db_query("SELECT stock FROM {gs_item} where nid = %d",
$form_state['values']['items']));
$amount += $form_state['values']['stock'];
db_query("UPDATE {gs_item} SET stock = %d WHERE nid = %d", $amount,
$form_state['values']['items']);
}
195
function guild_shop_balances_validate($form, &$form_state){
$str = 'a'.$form_state['values']['balance'];
$pos = strpos($str, "-");
if(!is_numeric($form_state['values']['balance'])||($pos==1)){
form_set_error ('balance', t('Must be a positive number'));
}
if($form_state['values']['users']=='blanco'){
form_set_error ('users', t('Choose an user.'));
}
}
function guild_shop_balances_submit($form, &$form_state){
$info = db_fetch_array(db_query("SELECT * FROM {gs_internal_balance} WHERE
uid = %d", $form_state['values']['users']));
$cont = count($info);
if($cont<2){
db_query("INSERT INTO {gs_internal_balance} (uid,internal_balance) VALUES
(%d, %d)", $form_state['values']['users'],$form_state['values']['balance']);
}
else{
$amount = $info['internal_balance']+$form_state['values']['balance'];
db_query("UPDATE {gs_internal_balance} SET internal_balance = %d WHERE uid
= %d", $amount, $form_state['values']['users']);
}
}
Archivo guild_shop.tpl.php
<?php
global $base_root, $base_path;
$price_format = number_format($price,0,'','.'); ?>
<div class="gs-price">
Precio: <?php print $price_format; ?>
</div>
<div class="gs-picture">
<img src=" <?php print $picture; ?>">
</div>
<div class="gs-description_item">
<b>Descripción:</b> <?php print $description_item; ?>
</div>
<?php if($stock==0){
196
print '<div class="ninguna">Sin Stock</div>';
} ?>
<?php if($stock==1){
print '<div class="ultima">Última unidad!</div>';
} ?>
<?php if(($stock>1)&&($stock<=5)){
print '<div class="pocas">Solo quedan '.$stock.' unidades</div>';
}?>
<?php if($stock>5){
print '<div class="normal"><b>Stock:</b> '.$stock.'
unidades</div>';
}?>
<?php if(user_access('buy item')&&($stock>0)){
print '<br><a
href="'.$base_root.$base_path.'purchase_submit/'.$nid.'"
class="comprar">Comprar</a><br>';
} ?>
Archivo purchase.tpl.php
<div class="gs-user" >
<b>Nombre:</b> <?php print $user_name; ?>
</div>
<div class="gs-item" >
<b>Item:</b> <?php print $item_name; ?>
</div>
<div class="gs-amount" >
<b>Cantidad:</b> <?php print $amount; ?>
</div>
Archivo guild_shop.css
.ninguna{
color: red;
font-size: 170%;
}
.ultima{
color: orange;
font-size: 16px;
}
.pocas{
color: #A69A00;
font-size: 16px;
}
197
.normal{
color: green;
font-size: 16px;
}
.gs-price{
float:right;
border-style:dotted;
border-width:1px;
padding: 7px;
border-color: black;
font-size: 170%;
font-weight: bold;
}
.comprar{
font-size: 22px;
}
12.5 Módulo Party
Archivo party.info
; $Id$
name= "Party"
description = "Module to create partys to events"
dependencies[] = assistance
core = 6.x
package = Ragnarok Guild
Archivo party.install
<?php
// $Id$
/**
* Implementation of hook_schema()
*/
function party_schema(){
$schema['party'] = array(
'description' => 'Store party info',
'fields' => array(
'enid' => array(
'type' => 'int',
198
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'party_name' => array(
'type' => 'varchar',
'length' => 255,
'default' => '',
),
'type_event' => array(
'type' => 'varchar',
'length' => 255,
'default' => '',
),
'anid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array('anid'),
);
$schema['party_members'] = array(
'description' => 'Store party info',
'fields' => array(
'enid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'party_name' => array(
'type' => 'varchar',
'length' => 255,
'default' => '',
),
'number' => array(
'type' => 'int',
199
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array('enid','party_name'),
);
return $schema;
}
/**
* Implementation of hook_install()
*/
function party_install(){
drupal_install_schema('party');
}
/**
* Implementation of hook_uninstall()
*/
function party_uninstall(){
drupal_uninstall_schema('party');
}
Archivo party.module
<?php
// $Id$
drupal_add_js(drupal_get_path('module', 'party') .'/js/party_event.js',
'module');
drupal_add_js(drupal_get_path('module', 'party') .'/js/party_build.js',
'module');
/*
** Implementacion de hook_menu()
*/
function party_menu(){
$items['party']= array(
'title' => t('Partys'),
'page callback' => 'party_page',
'description' => t('To manage partys'),
'access arguments' => array('view party'),
'type' => MENU_NORMAL_ITEM,
);
200
$items['party/add_party_event']= array(
'title' => t('Create Party Event'),
'description' => t('Content to add party for event'),
'page callback' => 'drupal_get_form',
'page arguments' => array('party_build_form'),
'access arguments' => array('create party event'),
'type' => MENU_NORMAL_ITEM,
);
$items['party/add_party_woe']= array(
'title' => t('Create Party WoE'),
'description' => t('Content to add party for event'),
'page callback' => 'drupal_get_form',
'page arguments' => array('party_build_form'),
'access arguments' => array('create party woe'),
'type' => MENU_NORMAL_ITEM,
);
$items['party/add_member_party_event']= array(
'title' => t('Add Member to Party Event'),
'description' => t('to add a member to a party event
created'),
'page callback' => 'drupal_get_form',
'page arguments' => array('party_member_form'),
'access arguments' => array('create party event'),
'type' => MENU_NORMAL_ITEM,
);
$items['party/add_member_party_woe']= array(
'title' => t('Add Member to Party WoE'),
'description' => t('to add a member to a party woe created'),
'page callback' => 'drupal_get_form',
'page arguments' => array('party_member_form'),
'access arguments' => array('create party woe'),
'type' => MENU_NORMAL_ITEM,
);
$items['party/delete_member_party_event']= array(
'title' => t('Delete Member of Party Event'),
'description' => t('to delete a member of party event
created'),
'page callback' => 'drupal_get_form',
'page arguments' => array('party_member_form'),
'access arguments' => array('create party event'),
'type' => MENU_NORMAL_ITEM,
201
);
$items['party/delete_member_party_woe']= array(
'title' => t('Delete Member of Party WoE'),
'description' => t('to delete a member of party woe
created'),
'page callback' => 'drupal_get_form',
'page arguments' => array('party_member_form'),
'access arguments' => array('create party woe'),
'type' => MENU_NORMAL_ITEM,
);
$items['party/event_view'] = array(
'title' => t('View Events Partys'),
'description' => t('View woe partys'),
'page callback' => 'drupal_get_form',
'page arguments' => array('party_view_js'),
'access arguments' => array('view party'),
'type' => MENU_NORMAL_ITEM,
);
$items['party/woe_view'] = array(
'title' => t('View
WoEs Partys'),
'description' => t('View event partys'),
'page callback' => 'drupal_get_form',
'page arguments' => array('party_view_js'),
'access arguments' => array('view party'),
'type' => MENU_NORMAL_ITEM,
);
$items['partys/get_partys'] = array(
'page callback' => 'get_partys',
'access arguments' => array('view party'),
'type' => MENU_CALLBACK,
);
$items['partys/get_partys_build'] = array(
'page callback' => 'get_partys_build',
'access arguments' => array('view party'),
'type' => MENU_CALLBACK,
);
return $items;
}
/*
202
** Implementacion de hook_perm()
*/
function party_perm(){
return array(
'create party event',
'create party woe',
'view party',
);
}
/**
** Funcion que crea el menu de las paginas del modulo
*/
function party_page(){
$list = party_menu();
$out .='<dl>';
foreach($list as $clave => $valor){
if($clave!='party'){
if(user_access($valor['access arguments']['0'])){
$out .= '<dt>'.l($valor['title'], $clave,
array('attributes' => array('title' => $valor['description'],))).'</dt>';
$out .= '<dd>'.$valor['description'].'</dd>';
}
}
}
$out.='</dl>';
return $out;
}
/*
** Implementacion of hook_user()
*/
function party_user($op, &$edit, &$account, $category){
global $user;
$id = $account->uid;
if($op == 'delete'){
$result=db_query('SELECT p.anid FROM {party} p INNER JOIN
{assistance_node} an ON p.anid=an.nid WHERE an.uid = %d', $id);
while($row=db_fetch_array($result)){
db_query('DELETE FROM {party} WHERE anid =
%d',$row['anid']);
}
203
$result = db_query("SELECT * FROM {node} WHERE (type =
'assistance_event' OR type = 'assistance_event') AND uid = 0");
while($data = db_fetch_object($result)){
assistance_delete($data);
db_query('DELETE FROM {node} WHERE nid = %d', $data>nid);
db_query('DELETE FROM {node_revisions} WHERE nid = %d',
$data->nid);
}
}
}
/*
** Funcion que crea el formulario para crear una party para eventos
*/
function party_build_form( &$form_state = NULL){
global $base_path;
//Miramos si ya estamos en un estado avanzado del formulario o si
estamos en el primer paso.
$step = isset($form_state['values']) ? (int)$form_state['storage']['step'] : 1;
//Guardamos el siguiente paso
$form_state['storage']['step'] = $step+1;
//ponemos el titulo la descripción y el nombre del boton de envio correspondiente al
paso en el que estamos
$form['indicator'] = array(
'#type' => 'fieldset',
'#title'=>t('Step @number', array('@number'=>$step))
);
switch($step){
case 1:
$type = 'event';
$title = 'Event';
if($_SERVER['REQUEST_URI']==$base_path.'party/add_party_woe'){
$type = 'woe';
$title = 'WoE';
}
$form_state['storage']['type']=$type;
$form['indicator']['event']= array(
'#title' => t($title),
'#type' => 'select',
'#options' => party_get_event($type),
204
);
$form['indicator']['submit']= array(
'#type' => 'submit',
'#value' => t('next'),
);
break;
case 2:
if(!isset($form_state['storage']['enid'])){
$form_state['storage']['enid'] =
$form_state['values']['event'];
}
$form['indicator']['name']= array(
'#title' => t('Party name'),
'#type' => 'textfield',
);
$form['indicator']['submit']= array(
'#type' => 'submit',
'#value' => t('next'),
);
break;
case 3:
if(!isset($form_state['storage']['party_name'])){
$form_state['storage']['party_name'] =
$form_state['values']['name'];
}
for($x=1; $x<16; $x++){
$var = variable_get('assistance_types',
'');
$no_rebirth = db_result(db_query("SELECT
name FROM {assistance_job} WHERE id = %d",$x));
$rebirth =db_result(db_query("SELECT name
FROM {assistance_job} WHERE id = %d",$x+16));
if($var!=''){
$str =
party_get_assistances($form_state['storage']['enid'], $no_rebirth,
$rebirth);
}
if($str!=""){
$form['indicator']['job'.$x] = array(
'#type' => 'fieldset',
'#title'=>$rebirth."/".$no_rebirth,
'#collapsible' => TRUE,
205
'#collapsed' => TRUE,
);
$form['indicator']['job'.$x][$x]=
array(
'#type' => 'checkboxes',
'#options' => $str,
);
}
}
$str =
party_get_assistances($form_state['storage']['enid'], 16,16);
if($str!=""){
$form['indicator']['job16'] = array(
'#type' => 'fieldset',
'#title'=> 'supernovice',
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['indicator']['job16']['16']= array(
'#type' => 'checkboxes',
'#options' => $str,
);
}
$form['indicator']['save']= array(
'#type' => 'submit',
'#value' => t('Save party'),
);
break;
}
return $form;
}
/*
* Funcion de validacion del formulario para crear partys de evento
*/
function party_build_form_validate($form, &$form_state){
if($form_state['storage']['step']==2){
if($form_state['values']['event']=='null'){
form_set_error('event', t('Choose one'));
}
return;
}
206
if($form_state['storage']['step']==3){
$result = db_query("SELECT DISTINCT party_name FROM {party}
WHERE enid = %d",$form_state['storage']['enid']);
if($form_state['values']['name']==''){
form_set_error('name', t('Enter name'));
}
while($row = db_fetch_array($result)){
if($row['party_name']==$form_state['values']['name']){
form_set_error('name', t('Name already in use on
this event'));
break;
}
}
return;
}
if($form_state['storage']['step']==4){
$marcados = 0;
for($x=1; $x<16; $x++){
if(is_array($form_state['values'][$x])){
foreach($form_state['values'][$x] as $clave =>
$valor){
if($valor==$clave){
$marcados++;
}
}
}
}
if(is_array($form_state['values']['16'])){
foreach($form_state['values']['16'] as $clave =>
$valor){
if($valor==$clave){
$marcados++;
}
}
}
if($marcados==0){
drupal_set_message('Has de añadir minimo 1 persona a la
party', 'error');
$form_state['storage']['step']=3;
return;
}
if($marcados>12){
207
drupal_set_message('Solo puedes añadir 12 personas a
una party', 'error');
$form_state['storage']['step']=3;
return;
}
}
}
/*
* Funcion de proceso del formulario para crear partys de evento
*/
function party_build_form_submit($form, &$form_state){
if($form_state['storage']['step']<4){
return;
}
db_query("INSERT INTO {party_members} (enid, party_name, number)
VALUES (%d, '%s',
0)",$form_state['storage']['enid'],$form_state['storage']['party_name']);
for($x=1; $x<16; $x++){
if(is_array($form_state['values'][$x])){
foreach($form_state['values'][$x] as $clave => $valor){
if($valor==$clave){
db_query("UPDATE {assistance_node} SET
status = 1 WHERE nid = %d",$valor);
db_query("UPDATE {party_members} SET number
= number+1 WHERE enid = %d AND party_name =
'%s'",$form_state['storage']['enid'],$form_state['storage']['party_name']
);
db_query("INSERT INTO {party} (enid,
party_name, type_event, anid) VALUES (%d, '%s', '%s',
%d)",$form_state['storage']['enid'],$form_state['storage']['party_name'],
$form_state['storage']['type'],$clave);
}
}
}
}
if(is_array($form_state['values']['16'])){
foreach($form_state['values']['16'] as $clave => $valor){
if($valor==$clave){
db_query("UPDATE {assistance_node} SET status = 1
WHERE nid = %d",$valor);
db_query("INSERT INTO {party} (enid, party_name,
type_event, anid) VALUES (%d, '%s', '%s',
%d)",$form_state['storage']['enid'],$form_state['storage']['party_name'],
$form_state['storage']['type'],$clave);
208
db_query("UPDATE {party_members} SET number =
number+1 WHERE enid = %d AND party_name =
'%s'",$form_state['storage']['enid'],$form_state['storage']['party_name']
);
}
}
}
unset($form_state['storage']);
}
/*
** Funcion que crea el formulario para eliminar un miembro de una party
*/
function party_member_form( &$form_state = NULL){
global $base_path;
//Miramos si ya estamos en un estado avanzado del formulario o si
estamos en el primer paso.
$step = isset($form_state['values']) ? (int)$form_state['storage']['step'] : 1;
//Guardamos el siguiente paso
$form_state['storage']['step'] = $step+1;
//ponemos el titulo la descripción y el nombre del boton de envio correspondiente al
paso en el que estamos
$form['indicator'] = array(
'#type' => 'fieldset',
'#title'=>t('Step @number', array('@number'=>$step))
);
switch($step){
case 1:
switch($_SERVER['REQUEST_URI']){
case $base_path.'party/add_member_party_event':
$title = 'Event';
$type = 'event';
$op = 'add';
$options = party_get_event_nofull($type);
break;
case
$base_path.'party/delete_member_party_event':
$title = 'Event';
$type = 'event';
$op = 'del';
$options = party_get_event_js($type);
break;
209
case $base_path.'party/add_member_party_woe':
$title = 'WoE';
$type = 'woe';
$op = 'add';
$options = party_get_event_nofull($type);
break;
case $base_path.'party/delete_member_party_woe':
$title = 'WoE';
$type = 'woe';
$op = 'del';
$options = party_get_event_js($type);
break;
}
$form_state['storage']['type']=$type;
$form['indicator']['event']= array(
'#title' => t($title),
'#type' => 'select',
'#options' => $options,
);
$form['indicator']['operation']= array(
'#type' => 'hidden',
'#value' => $op,
);
$form['indicator']['submit']= array(
'#type' => 'submit',
'#value' => t('next'),
);
break;
case 2:
if(!isset($form_state['storage']['enid'])){
$form_state['storage']['enid'] =
$form_state['values']['event'];
}
if(!isset($form_state['storage']['op'])){
$form_state['storage']['op'] =
$form_state['values']['operation'];
}
switch($_SERVER['REQUEST_URI']){
case $base_path.'party/add_member_party_event':
$options =
party_get_partys_nofull($form_state['storage']['enid']);
210
break;
case
$base_path.'party/delete_member_party_event':
$options =
party_get_partys($form_state['storage']['enid']);
break;
case $base_path.'party/add_member_party_woe':
$options =
party_get_partys_nofull($form_state['storage']['enid']);
break;
case $base_path.'party/delete_member_party_woe':
$options =
party_get_partys($form_state['storage']['enid']);
break;
}
$form['indicator']['partyjs']= array(
'#title' => t('Party name'),
'#type' => 'select',
'#options' => $options,
);
if($form_state['storage']['op']=='add'){
$form['indicator']['party'] = array(
'#value' => '<script type="text/javascript"
src="'.$base_root.$base_path.'/misc/drupal.js">
</script><script type="text/javascript"
src="'.$base_root.$base_path.'/misc/collapse.js"></script>
<form name="form1" method="post"
action="www.site.com"><div id="partyshow" style="padding: 10px;"></div>',
);
}
$form['indicator']['submit']= array(
'#type' => 'submit',
'#value' => t('next'),
);
break;
case 3:
if(!isset($form_state['storage']['party'])){
$party =
explode("/",$form_state['values']['partyjs']);
$form_state['storage']['party'] = $party[1];
}
switch($_SERVER['REQUEST_URI']){
case $base_path.'party/add_member_party_event':
211
for($x=1; $x<16; $x++){
$var =
variable_get('assistance_types', '');
$no_rebirth =
db_result(db_query("SELECT name FROM {assistance_job} WHERE id =
%d",$x));
$rebirth =db_result(db_query("SELECT
name FROM {assistance_job} WHERE id = %d",$x+16));
if($var!=''){
$str =
party_get_assistances($form_state['storage']['enid'], $no_rebirth,
$rebirth);
}
if($str!=""){
$form['indicator']['job'.$x] =
array(
'#type' => 'fieldset',
'#title'=>$rebirth."/".$no_rebirth,
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['indicator']['job'.$x][$x]= array(
'#type' => 'checkboxes',
'#options' => $str,
);
}
}
$str =
party_get_assistances($form_state['storage']['enid'], 16,16);
if($str!=""){
$form['indicator']['job16'] = array(
'#type' => 'fieldset',
'#title'=> 'supernovice',
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['indicator']['job16']['16']=
array(
'#type' => 'checkboxes',
'#options' => $str,
);
}
212
$form['indicator']['save']= array(
'#type' => 'submit',
'#value' => t('Add members'),
);
break;
case
$base_path.'party/delete_member_party_event':
$form['indicator']['members']= array(
'#type' => 'checkboxes',
'#options' =>
get_members_party($form_state['storage']['enid'] ,
$form_state['storage']['party']),
);
$form['indicator']['save']= array(
'#type' => 'submit',
'#value' => t('Delete members'),
);
break;
case $base_path.'party/add_member_party_woe':
for($x=1; $x<16; $x++){
$var =
variable_get('assistance_types', '');
$no_rebirth =
db_result(db_query("SELECT name FROM {assistance_job} WHERE id =
%d",$x));
$rebirth =db_result(db_query("SELECT
name FROM {assistance_job} WHERE id = %d",$x+16));
if($var!=''){
$str =
party_get_assistances($form_state['storage']['enid'], $no_rebirth,
$rebirth);
}
if($str!=""){
$form['indicator']['job'.$x] =
array(
'#type' => 'fieldset',
'#title'=>$rebirth."/".$no_rebirth,
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['indicator']['job'.$x][$x]= array(
'#type' => 'checkboxes',
213
'#options' => $str,
);
}
}
$str =
party_get_assistances($form_state['storage']['enid'], 16,16);
if($str!=""){
$form['indicator']['job16'] = array(
'#type' => 'fieldset',
'#title'=> 'supernovice',
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['indicator']['job16']['16']=
array(
'#type' => 'checkboxes',
'#options' => $str,
);
}
$form['indicator']['save']= array(
'#type' => 'submit',
'#value' => t('Add members'),
);
break;
case $base_path.'party/delete_member_party_woe':
$form['indicator']['members']= array(
'#type' => 'checkboxes',
'#options' =>
get_members_party($form_state['storage']['enid'] ,
$form_state['storage']['party']),
);
$form['indicator']['save']= array(
'#type' => 'submit',
'#value' => t('Delete members'),
);
break;
}
break;
}
return $form;
}
/*
214
* Funcion de validacion del formulario para añadir y eliminar miembros de
party
*/
function party_member_form_validate($form, &$form_state){
if($form_state['storage']['step']==2){
if($form_state['values']['event']=='null'){
form_set_error('event', t('Choose one'));
}
return;
}
if($form_state['storage']['step']==3){
if($form_state['values']['partyjs']=='null'){
form_set_error('party', t('Choose one'));
}
return;
}
if($form_state['storage']['step']==4){
if($form_state['storage']['op']=='add'){
$marcados = 0;
for($x=1; $x<16; $x++){
if(is_array($form_state['values'][$x])){
foreach($form_state['values'][$x] as $clave
=> $valor){
if($valor==$clave){
$marcados++;
}
}
}
}
if(is_array($form_state['values']['16'])){
foreach($form_state['values']['16'] as $clave =>
$valor){
if($valor==$clave){
$marcados++;
}
}
}
if($marcados==0){
drupal_set_message('Has de añadir minimo 1
persona a la party', 'error');
$form_state['storage']['step']=3;
return;
215
}
$actuales = db_result(db_query("SELECT number FROM
{party_members} WHERE enid = %d AND party_name = '%s'",
$form_state['storage']['enid'],$form_state['storage']['party']));
if(($marcados+$actuales)>12){
$num = 12-$actuales;
drupal_set_message('Solo puedes añadir '.$num.'
personas más a esta party', 'error');
$form_state['storage']['step']=3;
return;
}
}
else{
foreach($form_state['values']['members'] as $clave =>
$valor){
if($valor==$clave){
$marcados++;
}
}
if($marcados==0){
drupal_set_message('Has de eliminar minimo 1
persona a la party', 'error');
$form_state['storage']['step']=3;
return;
}
}
return;
}
}
/*
* Funcion de proceso del formulario para añadir y eliminar miembros de
party
*/
function party_member_form_submit($form, &$form_state){
if($form_state['storage']['step']<4){
return;
}
if($form_state['storage']['op']=='add'){
for($x=1; $x<16; $x++){
if(is_array($form_state['values'][$x])){
foreach($form_state['values'][$x] as $clave =>
$valor){
if($valor==$clave){
216
db_query("UPDATE {assistance_node}
SET status = 1 WHERE nid = %d",$valor);
db_query("UPDATE {party_members} SET
number = number+1 WHERE enid = %d AND party_name =
'%s'",$form_state['storage']['enid'],$form_state['storage']['party']);
db_query("INSERT INTO {party} (enid,
party_name, type_event, anid) VALUES (%d, '%s', '%s',
%d)",$form_state['storage']['enid'],$form_state['storage']['party'],$form
_state['storage']['type'],$clave);
}
}
}
}
if(is_array($form_state['values']['16'])){
foreach($form_state['values']['16'] as $clave =>
$valor){
if($valor==$clave){
db_query("UPDATE {assistance_node} SET
status = 1 WHERE nid = %d",$valor);
db_query("INSERT INTO {party} (enid,
party_name, type_event, anid) VALUES (%d, '%s', '%s',
%d)",$form_state['storage']['enid'],$form_state['storage']['party'],$form
_state['storage']['type'],$clave);
db_query("UPDATE {party_members} SET number
= number+1 WHERE enid = %d AND party_name =
'%s'",$form_state['storage']['enid'],$form_state['storage']['party']);
}
}
}
}
else{
foreach($form_state['values']['members'] as $clave =>
$valor){
if($valor==$clave){
db_query("UPDATE {assistance_node} SET status = 0
WHERE nid = %d",$valor);
db_query("DELETE FROM {party} WHERE anid =
%d",$valor);
db_query("UPDATE {party_members} SET number =
number-1 WHERE enid = %d AND party_name =
'%s'",$form_state['storage']['enid'],$form_state['storage']['party']);
}
}
$num = db_result(db_query("SELECT number FROM {party_members}
WHERE enid = %d AND party_name =
'%s'",$form_state['storage']['enid'],$form_state['storage']['party']));
if($num == 0){
217
db_query("DELETE FROM {party_members} WHERE enid = %d
AND party_name =
'%s'",$form_state['storage']['enid'],$form_state['storage']['party']);
}
}
unset($form_state['storage']);
}
/*
* Funcion que implementa la vista de las partys de eventos usando ajax
*/
function party_view_js(){
global $base_root, $base_path;
$type = 'event';
$title = 'Event';
if($_SERVER['REQUEST_URI']==$base_path.'party/woe_view'){
$type = 'woe';
$title = 'WoE';
}
$form['events'] = array(
'#type' => 'select',
'#title' => t($title),
'#options' => party_get_event_js($type),
);
$form['partys'] = array(
'#value' => '<script type="text/javascript"
src="'.$base_root.$base_path.'/misc/drupal.js">
</script><script type="text/javascript"
src="'.$base_root.$base_path.'/misc/collapse.js"></script>
<form name="form1" method="post" action="www.site.com"><div
id="capa" style="padding: 10px;"></div>',
);
return $form;
}
/*
** Funcion que devuelve los eventos que tienen alguna asistencia sin
asignar aun, son del tipo pasado por parametro y la fecha de inicio es
mayor que la fecha actual
*/
function party_get_event($type){
$time = time();
218
$event['null'] = 'Escoge uno';
if($type == 'woe'){
$event['null'] = 'Escoge una';
}
$result = db_query("SELECT n.nid, n.title, e.event_start FROM
{node} n INNER JOIN {event} e ON e.nid = n.nid WHERE n.type =
'%s'",$type);
while($row = db_fetch_array($result)){
if(strtotime($row[event_start])>$time){
$result2= db_query("SELECT status FROM
{assistance_node} WHERE enid = %d",$row['nid']);
$asistencia = FALSE;
while($row2 = db_fetch_array($result2)){
if($row2['status']==0){
$asistencia = TRUE;
break;
}
}
if($asistencia== TRUE){
$event[$row['nid']] = $row['title'];
}
}
}
return $event;
}
/*
** Funcion que devuelve el listado de asistencias sin asignar para un
evento pasado por parametro y para unos jobs concretos
*/
function party_get_assistances($nid, $job1, $job2){
$var = variable_get('assistance_types', '');
if($var!=''){
$result = db_query("SELECT an.nid, u.name, an.job FROM
({assistance_node} an INNER JOIN {users} u ON an.uid = u.uid) INNER JOIN
{content_field_job} pj ON an.job=pj.nid WHERE an.enid = %d AND an.status
= 0 AND (pj.field_job_value='%s' OR pj.field_job_value='%s')", $nid,
$job1, $job2);
while($row = db_fetch_array($result)){
$assistance[$row['nid']] =
l($row['name'],drupal_get_path_alias('node/'.$row[job]),array('attributes
' => array('target' => '_blank',)));
}
}
return $assistance;
219
}
/*
* Funcion que devuelve el codigo html que mostrará todas las partys de un
evento pasado por parametro
*/
function get_partys($id){
global $base_root, $base_path;
$result = db_query("SELECT DISTINCT (party_name) FROM {party} WHERE
enid = %d",$id);
$out.='<script type="text/javascript"
src="'.$base_root.$base_path.'/misc/drupal.js">
</script><script type="text/javascript"
src="'.$base_root.$base_path.'/misc/collapse.js"></script>
<form name="form1" method="post" action="www.site.com">';
while($row = db_fetch_array($result)) {
$x=0;
$out.='<fieldset class=" collapsible
collapsed"><legend>'.$row['party_name'].'</legend><table border="0">';
$result2 = db_query("SELECT u.name, p.anid FROM {party} p
INNER JOIN {assistance_node} an ON p.anid=an.nid INNER JOIN {users} u ON
an.uid=u.uid WHERE p.party_name = '%s' AND p.enid = %d",
$row['party_name'], $id);
while($row = db_fetch_array($result2)) {
$x++;
$out.='<tr><td width="20%">Miembro '.$x.': </td><td
align="left">'.l($row['name'],drupal_get_path_alias('node/'.$row[anid])).
'</td></tr>';
}
$out.='</table></fieldset>';
}
return drupal_json(array('set'=>$out));
return $out;
}
/*
* Funcion que devuelve los eventos que tienen alguna party creada
*/
function party_get_event_js($type){
$time = time();
$event['null'] = 'Escoge uno';
if($type == 'woe'){
$event['null'] = 'Escoge una';
}
220
$result = db_query("SELECT n.nid, n.title, e.event_start FROM
{node} n INNER JOIN {party} p ON n.nid =p.enid INNER JOIN {event} e ON
e.nid = n.nid WHERE n.type = '%s'",$type);
while($row = db_fetch_array($result)){
if(strtotime($row[event_start])>$time){
$event[$row['nid']] = $row['title'];
}
}
return $event;
}
/*
* Funcion que devuelve los eventos que tienen alguna party creada sin
llenar y asistencias pendientes
*/
function party_get_event_nofull($type){
$time = time();
$event['null'] = 'Escoge uno';
if($type == 'woe'){
$event['null'] = 'Escoge una';
}
$result = db_query("SELECT n.nid, n.title, e.event_start FROM
{node} n INNER JOIN {event} e ON e.nid = n.nid WHERE n.type =
'%s'",$type);
while($row = db_fetch_array($result)){
if(strtotime($row[event_start])>$time){
$num_partys =
count(party_get_partys_nofull($row['nid']));
if($num_partys>1){
$result2 = db_result(db_query("SELECT
COUNT(an.nid) FROM ({assistance_node} an INNER JOIN {users} u ON an.uid =
u.uid) WHERE an.enid = %d AND an.status = 0",$row['nid']));
if($result2>0){
$event[$row['nid']] = $row['title'];
}
}
}
}
return $event;
}
/*
* Funcion que devuelve el nombre de las partys de un evento
*/
function party_get_partys($id){
221
$partys['null'] = 'Escoge una';
$result = db_query("SELECT DISTINCT (party_name) FROM {party} WHERE
enid = %d",$id);
while($row = db_fetch_array($result)) {
$partys[$id.'/'.$row['party_name']]=$row['party_name'];
}
return $partys;
}
/*
* Funcion que devuelve el nombre de las partys de un evento que no esten
llenas
*/
function party_get_partys_nofull($id){
$partys['null'] = 'Escoge una';
$result = db_query("SELECT DISTINCT party_name FROM {party} WHERE
enid = %d", $id);
while ($row = db_fetch_array($result)){
$result2 = db_result(db_query("SELECT number FROM
{party_members} WHERE enid = %d AND party_name = '%s'",$id,
$row['party_name']));
if($result2<12){
$partys[$id.'/'.$row['party_name']]=$row['party_name'];
}
}
return $partys;
}
/*
* Funcion que devuelve el codigo html que mostrará la party del evento
pasada por parametro
*/
function get_partys_build($eid , $pid=0){
global $base_root, $base_path;
$result = db_query("SELECT DISTINCT (party_name) FROM {party} WHERE
enid = %d AND party_name = '%s'",$eid,$pid);
$out.='<script type="text/javascript"
src="'.$base_root.$base_path.'/misc/drupal.js">
</script><script type="text/javascript"
src="'.$base_root.$base_path.'/misc/collapse.js"></script>
<form name="form1" method="post" action="www.site.com">';
while($row = db_fetch_array($result)) {
$x=0;
$out.='<fieldset class=" collapsible
collapsed"><legend>'.$row['party_name'].'</legend><table border="0">';
222
$result2 = db_query("SELECT u.name, p.anid FROM {party} p
INNER JOIN {assistance_node} an ON p.anid=an.nid INNER JOIN {users} u ON
an.uid=u.uid WHERE p.party_name = '%s' AND p.enid = %d",
$row['party_name'], $eid);
while($row = db_fetch_array($result2)) {
$x++;
$out.='<tr><td width="14%">Miembro '.$x.': </td><td
align="left">'.l($row['name'],drupal_get_path_alias('node/'.$row[anid])).
'</td></tr>';
}
$out.='</table></fieldset>';
}
return drupal_json(array('set'=>$out));
}
/*
* Funcion que devuelve los miembros de una party de un evento
*/
function get_members_party($eid , $pid){
$result = db_query("SELECT an.nid, u.name, an.job FROM ({party} p
INNER JOIN {assistance_node} an ON p.anid=an.nid) INNER JOIN {users} u ON
u.uid=an.uid WHERE p.enid = %d AND p.party_name='%s'",$eid,$pid);
while($row = db_fetch_array($result)) {
$members[$row['nid']] =
l($row['name'],drupal_get_path_alias('node/'.$row[job]),array('attributes
' => array('target' => '_blank',)));
}
return $members;
}
Archivo party_build.js
/*
*Jquery para el modulo party
*/
// $Id$
// Global killswitch: only run if we are in a supported browser.
//comprobamos que este activado javascript
if (Drupal.jsEnabled) {
//si esta funcionando definimos la función
$(function(){
//Este código nos permite comprobar cada vez que seleccionamos un
elemento del select.
$('#edit-partyjs-wrapper').change(function(){
223
//Cada vez que seleccionamos un elemento del select recuperamos el valor
del atributo value.
$('#edit-partyjs').each(function () {
var valor = $(this).val();
//alert (valor);
//Montamos una función para crear la url mediante la cual pasaremos los
datos.
var ruta = 'partys/get_partys_build/';
var url2 = Drupal.settings.basePath + ruta + valor;
// alert (url2);
//La función que ejecutará el cambio de html con la información
recuperada.
var updateUsers = function(data) {
$('#partyshow').html(data.set);
}
//La magia de jquery con ajax, las explicaciones son de mucha ayuda
$.ajax({
type: 'POST',
url: url2, // Which url should be handle the ajax request. This is the url defined
in the <a> html tag
success: updateUsers, // The js function that will be called upon success
request
dataType: 'json', //define the type of data that is going to get back from the
server
data: 'js=1' //Pass a key/value pair
});
return false; // return false so the navigation stops here and not continue to the
page in the link
});
});
});
}
Archivo party_event.js
/*
*Jquery para el modulo party
*/
// $Id$
// Global killswitch: only run if we are in a supported browser.
224
//comprobamos que este activado javascript
if (Drupal.jsEnabled) {
//si esta funcionando definimos la función
$(function(){
//Este código nos permite comprobar cada vez que seleccionamos un
elemento del select.
$('#edit-events').change(function(){
//Cada vez que seleccionamos un elemento del select recuperamos el valor
del atributo value.
$(this).each(function () {
var valor = $(this).val();
// alert (valor);
//Montamos una función para crear la url mediante la cual pasaremos los
datos.
var ruta = 'partys/get_partys/';
var url2 = Drupal.settings.basePath + ruta + valor;
//alert (url2);
//La función que ejecutará el cambio de html con la información
recuperada.
var updateUsers = function(data) {
$('#capa').html(data.set);
}
//La magia de jquery con ajax, las explicaciones son de mucha ayuda
$.ajax({
type: 'POST',
url: url2, // Which url should be handle the ajax request. This is the url defined
in the <a> html tag
success: updateUsers, // The js function that will be called upon success
request
dataType: 'json', //define the type of data that is going to get back from the
server
data: 'js=1' //Pass a key/value pair
});
return false; // return false so the navigation stops here and not continue to the
page in the link
});
});
});
225
}
12.6 Tema Propio
Archivo ragnarok.info
name = Ragnarok
description = sin
screenshot = screenshot.gif
core = "6.x"
engine = phptemplate
regions[header] = Header
regions[left] = First sidebar
regions[right] = Second sidebar
regions[footer_block] = Footer
features[]
features[]
features[]
features[]
features[]
features[]
features[]
features[]
=
=
=
=
=
=
=
=
logo
name
node_user_picture
comment_user_picture
search
favicon
primary_links
secondary_links
stylesheets[all][] = css/style.css
Archivo page.tpl.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print
$language->language ?>" lang="<?php print $language->language ?>"
dir="<?php print $language->dir ?>">
<head>
<title><?php print $head_title; ?></title>
<?php print $head; ?>
<?php print $styles; ?>
<?php print $scripts; ?>
</head>
<body class="<?php print $body_classes; ?>">
<div id="page">
<div id="header"><!--header -->
<div id="logo-title">
<?php if ((!empty($logo))&&(!empty($site_name))): ?>
<a href="<?php print $front_page; ?>" title="<?php print
t('Home'); ?>" rel="home" id="logo">
<img src="<?php print $logo; ?>" alt="<?php print t('Home');
?>"/>
</a>
<!-- <h1 id="site-name">
<a href="<?php print $front_page ?>" title="<?php print
t('Home'); ?>" rel="home"><span><?php print $site_name; ?></span></a>
</h1>-->
<?php endif; ?>
226
</div> <!-- /logo-title -->
<?php if ($header): ?>
<div id="header-region">
<?php print $header; ?>
</div>
<?php endif; ?>
</div> <!-- /header -->
<div id="main"> <!-- main -->
<div id="content">
<div id="content-in" class="column">
<?php if ($breadcrumb || $messages || $help || $title ||
$tabs): ?>
<div id="content-header"> <!-- content-header -->
<?php print $breadcrumb; ?>
<?php if ($title): ?>
<h1 class="title"><?php print $title; ?></h1>
<?php endif; ?>
<?php if ($tabs): ?>
<div class="tabs"><?php print $tabs; ?></div>
<?php endif; ?>
<?php print $messages; ?>
<?php print $help; ?>
</div> <!-- /content-header -->
<?php endif; ?>
<div id="content-area">
<?php print $content; ?>
</div> <!-- /content-area -->
</div>
</div> <!-- /content-inner /content -->
<?php if (!empty($primary_links) || !empty($secondary_links)): ?>
<div id="navigation" class="menu <?php if
(!empty($primary_links)) { print "with-main-menu"; } if
(!empty($secondary_links)) { print " with-sub-menu"; } ?>">
<?php if (!empty($primary_links)){ print theme('links',
$primary_links, array('id' => 'primary', 'class' => 'links main-menu'));
} ?>
<?php if (!empty($secondary_links)){ print theme('links',
$secondary_links, array('id' => 'secondary', 'class' => 'links submenu')); } ?>
</div> <!-- /navigation -->
<?php endif; ?>
<?php if ($left): ?>
<div id="left" class="sidebar"><!-- sidebar-left -->
<?php print $left; ?>
</div>
<?php endif; ?> <!-- /sidebar-left -->
<?php if ($right): ?>
<div id="right" class="sidebar"><!-- /sidebar-right -->
<?php print $right; ?>
</div>
<?php endif; ?> <!-- /sidebar-right -->
</div> <!-- /main -->
<?php if(!empty($footer_message) || !empty($footer_block)): ?> <!-footer -->
<div id="footer">
<?php print $footer_message; ?>
<?php print $footer_block; ?>
</div> <!-- /footer -->
227
<?php endif; ?>
</div> <!-- /page -->
<?php print $closure; ?>
</body>
</html>
Archivo node.tpl.php
<div id="node-<?php print $node->nid; ?>" class="node<?php if ($sticky) {
print ' sticky'; } ?><?php if (!$status) { print ' node-unpublished'; }
?> clear-block">
<?php print $picture ?>
<?php if (!$page): ?>
<h2><a href="<?php print $node_url ?>" title="<?php print $title
?>"><?php print $title ?></a></h2>
<?php endif; ?>
<div class="meta">
<?php if ($submitted): ?>
<span class="submitted"><?php print $submitted ?></span>
<?php endif; ?>
</div>
<div class="content">
<?php print $content ?>
</div>
<?php print $links; ?>
</div>
Archivo template.php
<?php
function ragnarok_breadcrumb($breadcrumb){
$char[0] = ' <(o.o<) ';
$char[1] = ' ^(o.o)^ ';
$char[2] =' (>o.o)> ';
if(!empty($breadcrumb)){
$length= count($breadcrumb);
for($x=0; $x<$length; $x++){
$string .= $breadcrumb[$x].$char[$x%3];
/*else{
$string .= $breadcrumb[$x];
}*/
}
}
return '<div class="breadcrumb-ro">'.$string.'</div>';
}
228
Archivo style.css
body{
font-family:helvetica;
background-color:#92c489;
font-size:12px;
}
.sidebar a:link, .sidebar a:visited,.node a:link, .node a:visited{
color: #92c489;
text-decoration:none;
}
.sidebar a:hover,.node a:hover{
color: #92c489;
text-decoration:none;
font-weight:bold;
}
a:link, a:visited{
color: #32562b;
text-decoration:none;
}
a:hover{
color: #32562b;
text-decoration:none;
font-weight:bold;
}
#page {
width: 960px;
margin: 0 auto;
}
#header{
height:150px;
border-bottom:1px;
border-bottom-style:solid;
background-color:#7688a7;
}
#logo-title{
text-align:center;
}
#content {
float: left;
width: 100%;
margin-right: -100%;
padding: 0;
}
#content-header{
padding:10px;
background-color:#589a4d;
}
.sidebar {
float: left;
background-color:#32562b;
}
229
#right {
padding:10px;
width: 200px;
float: right;
}
#left {
padding:10px;
width: 190px;
margin-right:-190px;
}
.column, .sidebar left{
margin-left: 220px;
}
.column, .sidebar right{
margin-right: 230px;
}
#footer {
float: none;
clear: both;
}
#header,#footer,.mission,.breadcrumb,.node {
clear: both;
}
#navigation {
float: left;
margin-left: 0;
margin-right: -100%;
padding: 0;
width: 100%;
height: 40px;
}
.with-navigation #content,
.with-navigation .sidebar {
margin-top: 40px;
}
.node{
padding:0px 10px 10px 10px;
border-bottom: 1px;
border-bottom-style: solid;
background-color:#589a4d;
}
230