Paging code is really easy in SQLite. You do a SELECT statement as normally but add the LIMIT clause with two numbers separated by a comma. The first number is the offset, aka where you start from, and the second number is the number of results you want back. So if you wanted ten results starting from the thirtieth, you just SELECT ... LIMIT 30,10 and that's it!
Displaying the current paging links is something I might want to do a lot, so I made a function in Rockets to do it. The function works like this:
(display-paging-links int-start-page int-total-pages int-current-page str-page-url)
So to display the top ten pages you'd call (display-paging-links 1 10 1 "rockets-main").
Neat and easy!
Eliminating duplicate code is a great thing. If you have code that is duplicated on many pages, if you want to change it you have to remember to change it on all your pages.
I originally made a framework function (display-navbar) that displays a navigation bar and sign-in form. This was great, but (display-navbar) needs to take a list as an argument to decide what menus to actually show. I didn't want to repeat this list on each page, but I also needed a way to show which page was currently active.
One way would be just to define a new function, (display-rockets-nav "active page") that would then call (display-nav) and specify which page is actually active. But then I would want to make sure this function is defined on every page. Well, I already have a set of common functions in the partial "rockets-common-functions.lsp". I could just put it in there.
The other option is to define a new partial page, "rockets-navbar.lsp", and call this partial each time. Which approach is better? They both require the same amount of code (I have to add a line to either call the function or display the partial). The only real difference is that if I go the function route I would have to have two functions, one in the framework, and one in the application, that had similar names, and I'd have a function calling a function. If I put it in a partial file, it looks like it is doing something different.
Ultimately it's an aesthetic choice. If you make your own application you might decide to do it differently. I might even change my mind at some point!
An existential question, indeed...
For no apparent reason I decided to write a whole essay about it: http://newlisponrockets.com/rockets-why.lsp
Cookie security is something many sites don't bother with, because who would ever fake a cookie? Well, as it turns out, a lot of people could do just that.
Cookie security best practices have been known for a while. This article from 2005 lays them out pretty nicely: http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/
Basically, you want to have a random number as your cookie, but then the value should not just be the user Id. It should be hard to guess. And what if a user registers and then copies your carefully-selected random number cookie but just changes the user id? Then they could log in as any user they wanted!
So what we do is add some salt to the cookie in the form of ANOTHER random number, each one unique to each user. The salt is stored in the user database, so it isn't available to the public. This makes every cookie unique for each user.
You also want to be running everything under SSL (aka https) to avoid issues with people stealing cookies with things like FireSheep over WiFi connections, but that's something that can be up to the site administrator.
It's no Cave Troll, but it will have to do.
Click the "About" link on the top bar to read it!
I have implemented redirections, which are basically just HTTP status codes that point the site to a new page. The command is:
The way it works is that if the logic in your code (say, successfully signing in) should then move you to another page, it does so and immediately exits, without printing anything else, even if you have put (display-page) later on in the page. So, in our example, if the username and password are valid, it just puts you back to the main page. If they are not valid, it will display a message normally with (display-page).
Since I've disabled non-admins from posting new blog entries, I thought it was safe to move the newLISP on Rockets Blog to the front page of newlisponrockets.com. Wow, that's a lot of saying newlisp on rockets. Did I mention my email was email@example.com?
newlisp on Rockets.
Muahahahaa! Mine is an evil laugh!
No, this is just a side-effect of getting user sign-in working. I have the only account, since I haven't done the Registration part yet.
The plan is that only I will be able to make new blog posts, but anybody who has registered will be able to comment on blog posts.
It's generally considered to be a bad idea to keep clear-text passwords in your database. If the database is ever compromised, hackers will have everyone's passwords.
What most sites do is hash the passwords using a one-way algorithm, like SHA1, which is a 160-bit encryption. Newlisp has a SHA1 function included in the module crypto.lsp.
Unfortunately, hackers these days use dictionary-based attacks, where they take every word in the dictionary (and many common password combinations that include numbers or years) and then just run them through SHA1 or the equivalent, and check to see if they match the compromised stored password hash.
To prevent this, people have been adding salt to the passwords and then encrypting THAT. Salt is just a random number. Each user gets its own Salt, which is stored in the user database. This way, attackers would have to run separate dictionary attacks for every user, and that's assuming they know the salting algorithm.
I found a great article on password security here: http://phpsec.org/articles/2005/password-hashing.html
It outlines the whole process and shows how to handle it in PHP. I'm building in the equivalent in Rockets using newLISP code, which will be part of the user sign in process.
After much soul-searching, I went ahead and implemented the delayed-write method I talked about in my earlier posts.
At first I tried to overload (print) and (println) and it worked but jumping in and out of different contexts made messed up my ($POST) functions, and I thought I'd simplify my life by just defining new functions: (display) and (displayln). Then at the end you (display-page). You can also (display-image) and (display-post-box). Kind of a theme going there.
Anyway, (set-cookie) now adds a cookie to the header that will get posted when the page itself is displayed. It seems to be working, so hopefully I can now work on getting user sign-in happening on the Rockets blog!