This is a system that contains all data related to the European Lisp Symposium, and is able to compile it into a static website for publishing.
This repository makes use of Git LFS for storage of several large files (images, pdfs, etc.) In order to properly clone all the data and contribute to the repository, please first make sure Git LFS is installed on your machine. Typically it should be available as a git-lfs
package. Following that, run these commands to clone the repository:
git lfs install
git clone git@github.com:european-lisp-symposium/els-web
If all went fine, the file at els-web/output/static/favicon.png
should be a binary image. If something went wrong it will be a plain text file. In that case, Git LFS was not properly set up. Please make sure you have installed it correctly and try again.
When pulling, please make sure to pull with rebase to avoid merge commits and branching history. You can do so either explicitly with git pull --rebase
or configure rebase as the default with git config --bool pull.rebase true
.
An edition is created by defining a new package of the editions' name --usually its year-- and following it up with various data definitions. The basic outline is as follows:
(in-package #:els-web-editions)
(define-edition "2025")
(in-package "2025")
(define-text :announcement
(:div :class "announcement" "A new edition is coming along!"))
(define-date "Conference start" @2025-05-23)
(define-date "Conference end" @2025-05-24)
;; etc.
When a definition is recompiled, its data is updated if possible. Each data entry is identified by one or more key fields. If those are changed, the data will instead be added again. To avoid this, you can recompile the entire file, which will first clear out all the data through the define-edition
macro, and then add it all anew.
If you add a new edition, you should place it into the editions
directory, and then add the file to the ASDF system definition, such that the edition is automatically recognised once the system is loaded.
define-person
Define a new person that is relevant to this edition. All programme members and speakers should be defined in this way. The name should either be a name string directly, or ideally a list of the relevant name parts. See the list of fields below.define-location
Define a new location. This can be used to define the location of the conference itself, as well as nearby hotels and such. See the list of fields below.define-text
Define a new text to be displayed on the page. The body of the definition should be a set of cl-who template structures.define-programme-entry
Define an entry in the programme. You will probably want to use define-programme-day
directly, however, as it makes the date definition much more simple.define-programme-day
Define a fully day of the programme. The body should be pairs of time dates and the entry that is started at that time. See the list of fields below.define-date
Define a deadline or date that people should know about.define-sponsor
Define a sponsor for the conference. The body should include website and logo fields.define-proceedings
Publish a link to the public proceedings document.define-registration
Define the registration prices and other metadata.Many of these definitions accept arbitrary data fields in the form of a plist. The following fields are specially treated and respected by the templates.
:full-name
The full name string. Usually calculated automatically from the name.:name
Should be a plist where the following keys are recognised:
:honorific-prefix
The honorific prefix, if any.:given-name
The person's first, or given name.:additional-name
The person's middle, or additional name.:family-name
The person's last, or family name.:honorific-suffix
The honorific suffix, if any.:photo
A link to a photo of the person or location.:nickname
An online nickname.:email
The e-mail address of the person or location.:website
A link to the website.:telephone
The telephone number to contact the person or location.:organization
The organisation the person is a part of.:category
Which category the location belongs to.:role
Which roles the location or person fulfils. The following roles are recognised:
:conference
This is the conference's primary location.:hotel
This is a suitable hotel near the conference.:programme-chair
This person is the programme chair.:local-chair
This person is the local conference chair.:committee
This person is on the committee.:virtualization
This person is on the virtualization team.:local-organizer
This person is the local organiser.:speaker
This person is a speaker and has an official talk.:address
Should be a plist where the following keys are recognised:
:po-box
The post office box number.:street
The basic street name and number.:extended
The extended street address.:city
The locality or city.:region
The region the city is in.:post-code
The local post-code.:country
The country name.:title
The primary title of the talk or event.:speakers
The list of speakers that hold the talk. Each speaker should be referenced by their full name string, which is usually the given name and family name together, separated by a string.:role
The roles of the programme entry. The following roles are recognised:
:talk
This entry is a talk.:keynote
This talk is also a keynote.:break
This represents a coffee break or some other kind of downtime.:organization
This event is about information of the conference.:lightning
This is a lightning talk session.:dinner
This is for the conference dinner time.:description
The long description used for keynote talks. This is displayed in the highlights section of the page.:note
An additional note to display in the programme about this event. Can be used in cases where an event is cancelled or something to that effect.:website
If present turns the title into a link. Intended to be used to link to a video or slides of the entry.:website
A link to the sponsor's website.:logo
A link to the logo image of the sponsor. The logo should be no bigger than 256px², should be hosted locally, and ideally should be a vector graphics image.The registration definition is composed of a number of items. Each item has the following structure: a type, a name, and attributes. The type should be either :kind
for primary registration types, and :option
for optional features attendees can request. The name should uniquely identify the item in the list. The following attributes can also be specified:
:price
The price of the item in €. If you need cents, use a float. Defaults to 0
.:status
Should be :active
if one can buy the item, and :inactive
if not. Useful for managing early-bird items. Defaults to the status of the entire registration block.:description
A textual description of the item, explaining it in more detail.Once registrations are closed, you should set the entire registration block to :inactive
.
The data can be easily retrieved through the query
function that does some light matching. The filter argument can be of the following structure:
FILTER ::= everything | CLAUSE
CLAUSE ::= (= DATA DATA)
| (in DATA DATA)
| (and CLAUSE*)
| (or CLAUSE*)
| (not CLAUSE)
DATA ::= keyword | data-field | data-value
everything --- The symbol T to represent all data
keyword --- A keyword symbol that is directly used as a value
data-field --- A symbol representing the value of a field in a data entry
data-value --- Any kind of object that is directly used as a value
Comparison between values is done through g=
, which is a form of "generalised equality." Specifically, the following holds:
timestamp
s are g=
if they are timestamp=
.symbol
s are g=
if they are string-equal
.string
s are g=
if they are string-equal
.equalp
.These weakened comparisons are done to make it more convenient to extract the data within templates.
Some parts of the website require keys and tokens that should not be made public in a repository like this. Thus, this includes a simple "secrets" mechanism. The system expects a file called secrets.lisp
within its root directory. This file should contain a single plist of keywords to strings. The following keys are required:
:google-api-key
The public key provided to you by Google.:stripe
A path to the Stripe PHP library root folder.:stripe-public-key
The public key provided by Stripe.:stripe-private-key
The private key provided by Stripe.:mailer
A path to the PHPMailer root folder.:mailer-host
The hostname of the SMTP server.:mailer-port
The port to connect through (usually 465 for SSL, 587 for TLS).:mailer-ssl
One of "false"
, "true"
, "self-signed"
. Note that the self-signed option disables certificate checking.:mailer-tls
Either "true"
or "false"
.:mailer-user
The username to connect to the SMTP server with.:mailer-pass
The password for the user account.:mailer-from
Both the recipient of email receipts and the From:
address.Note that for Stripe you should use the provided testing keys during development, and use the production keys for the deployed website. Using either key set on the other environment is a very bad idea.
The templates are written using the Clip system. For the most part the data is introduced using the aforementioned query
function, and its abbreviations query1
and queryf
. Common structures like locations, people, and programme entries are separated out of the primary index.ctml
template and spliced back in using the <c:splice>
tag.
What's going on in the templates should not be too difficult to figure out. Otherwise, have a look at Clip's and perhaps also lQuery's documentation.
You can compile the edition data using compile-edition
. When you add or remove an edition, you should also compile all the other ones as well, in order to ensure the cross-links are still valid. You can do so with compile-all-editions
.
The resulting static files will be placed in the output
directory, automatically overwriting previous files. In order to publish the site, you simply need to copy the entire output
directory, or make it visible through a webserver somehow.
In order to deploy ELS-web on a server, you will need a PHP5 capable server. I'm well aware that using PHP sounds like heresy for a Lisp project, but many servers don't offer direct root access to run a Lisp instance.
Either way, in order to deploy it, you will need the full ELS-web repository, including a filled out secrets.lisp
file. The server-side registration script will access this file to retrieve some options. While the root of the project does need to be accessible to PHP, it should naturally not be accessible to the web. The document root that your web server should serve is the output
directory.