I'd been putting off doing a Forgot Password module for newLISP on Rockets because it is such a pain doing it properly. You can't just have one click to reset a password, because what if someone else knows your user name or email? Then they could change your password to whatever they want!
So what most sites do is let you trigger a reset, then send a confirmation message to that email address, and then make you retrieve the email and click on a special link to reset your password.
Funnily enough, on another site I'm developing I was testing logging out and logging in, and you know what? I forgot my password. So I figured this was as good as an excuse as any to build a Forgot Module! (And no, I couldn't just grab the password from the database, because it's encrypted for security!)
I wanted the whole thing to be only a single page for simplicity. rockets-forgotpassword.lsp is the page that handles triggering the email, confirming and sending the email, and resetting the password, so the code flow may not seem obvious at first glance. The emails contain links of unique identifiers (sometimes called GUIDs) that expire after an hour and are matched with email addresses of the people who sent them, so people won't be able to guess them either. The tokens are stored in a file called reset-tokens.lisp. This file is automatically generated if it doesn't previously exist.
One more thing: to get the email links to work, the module needs two additional configuration options in Rockets-config.lisp:
(set 'AdminEmail "firstname.lastname@example.org")
(set 'SiteURL "newlisponrockets.com")
I've been wanting to update newLISP on my development box to see what neat new changes and features are available. Unfortunately, it's a 64-bit Ubuntu install, and pre-packaged binaries are only available for i386 (32-bit) on newlisp.org.
So what to do? Well, compile from source of course!
First get the source:
tar zxvf newlisp-10.4.5.tgz
sudo apt-get install libffi-dev
sudo apt-get install libreadline6 libreadline6-dev
sudo make install
sudo nano sqlite3.lsp
"/usr/lib/x86_64-linux-gnu/libsqlite3.so" ; Ubuntu
"/usr/lib/x86_64-linux-gnu/libcrypto.so.0.9.8" ; Ubuntu
Today I relaunched my personal website at http://www.jeremyreimer.com. It had previously been running on Dragonfly, a web development framework that inspired me to write Rockets.
Converting the code was really easy. All it took was the following:
1. Replace all instances of (print) with (display) and (println) with (displayln)
2. Remove Dragonfly-specific functions like (web-root) that are no longer necessary.
3. Make sure to start each page with:
(load "newlisp-rockets.lisp") ; this is where the magic happens!
(display-footer "Jeremy Reimer")
I've made some changes to the code base that will make it easier to start new custom sites based on Rockets. This is for my benefit as well as everyone else's-- I'm currently developing a bunch of new sites with this technology!
Now, when you run setup-rockets.lisp, the script asks you for a long and short name for your blog, an owner name, and the database name. These are automatically saved in a new configuration file called Rockets-config.lisp. I went through every page in the Rockets blog and changed it so that it reads various custom data about the blog from the config file.
The config file looks like this:
(set 'Database "ROCKETS-BLOG")
(set 'Name "The newLISP on Rockets Blog")
(set 'ShortName "newLISP on Rockets")
(set 'Owner "Rocket Man")
The basic format is something like this:
"streetAddress": "21 2nd Street",
"city": "New York",
"number": "212 555-1234"
"number": "646 555-4567"
RSS feeds are useful and great, but the XML structure they come in is rather unwieldy to read through and parse. newLISP has a great function called (parse-xml) that converts an XML tree into a list, but now you just have an unwieldy list. It's helpful to be able to extract only the data we want and put it in a simple nested list.
I've written a new function in Rockets that lets you do just that.
First, get the data from the RSS feed URL that you want:
(set 'feed-url " http://penny-arcade.com/feed"))
(set 'rss-result (xml-parse (get-url feed-url)))
Now, we want to extract the fields "title", "author", and "link" from that feed.
(set 'field-result (get-fields-from-rss rss-result '("title" "author" "link")))
(("News Post: The Book Of Divine Wisdom" "email@example.com (Tycho)" " http://penny-arcade.com/2013/01/25/the-book-of-divine-wisdom1")
("News Post: So many games!" "firstname.lastname@example.org (Gabe)" " http://penny-arcade.com/2013/01/25/so-many-games")
...etc ... )
Apache log files typically just sit around filling up your hard drive space, a vast array of text too unwieldy to search through.
A useful thing to do is to parse these files and copy them to a database. I've written a script that will do this using Rockets. It's not a web page-- it's a script that you should run from the command line (use sudo newlisp log-to-database.lsp) It will create a new database from scratch called SERVER-LOGS.db that you can then query and search using SQLite.
The script can be found here: https://github.com/newlisponrockets/newLISP-on-Rockets/blob/master/log-to-database.lsp
Note: I may be updating this later, as the database files seems quite large (only slightly smaller than the logs themselves)
This is a trickier issue than it appears at first.
The obvious solution is to just check the date of the last posted message and compare it with, say, the last time the user logged in. But in practice this doesn't work, because you want to view a post and have it removed from your "New" list right away, not at some later date. You actually have to bite the bullet and store a list of posts that you have read or unread. I chose "read" because by default users don't have anything in that list, which is easier to implement.
The list is stored as a string of post Id numbers, delimited by hyphens. When displaying the list of forum posts, it checks each one to see if the post Id is in your list of read posts, just by doing a (find) search on the string.
That part is easy. But what about when someone adds a new comment to a thread you've read? Ideally you want it to be bumped back to "Unread" status.
The solution I came up with is to get a list of every user's Read list whenever someone posts a comment. Then you loop through it and if you find the Post Id in there, you just snip it out using (replace).
Oh, I also added a "Mark All as Read" button, for people who just want all those pesky "New" icons to go away, RIGHT NOW. It gets a list of every post and adds them all to your Read list.
Is it as efficient as it could be? Will it bog down when you have a million users? I have no idea. I'll cross that bridge when I come to it. For now, it seems to work pretty well.
I've added a small feature that shows the number of views each forum thread or blog post has gained. Each time you view a thread in the forum view or view a complete blog post by clicking on the link, the number is bumped.
Because this is a new feature, all the old views aren't counted. :( So they are starting at zero.
This did require a change to the database, as I didn't already have the column "PostViews" in the Posts table. This can present a problem when people are upgrading from an earlier version of Rockets that doesn't have that column. I've updated setup-rockets.lisp to create this field when making a new database, but people's existing databases won't have it. I'll probably have to add a "update database to latest version" script that will just add the missing columns for people with older versions. One nice thing is that the database doesn't need any values in there. It just needs to be altered to add this missing field.