Hi guys,
There has always been basic account features in mezzanine.core - a single view/template/form for login and signup with an email and password field. While this served the most basic use of signing up and logging in, it missed some mandatory features, namely letting a user update their email/password (including forgotten passwords), and letting the developer extend the user info with extra fields. So I've moved those existing parts from mezzanine.core into the new mezzanine.accounts app. Here's a breakdown of everything:
- Removed the ACCOUNTS_ENABLED setting which would toggle the existing account features. This is now controlled by having mezzanine.accounts in INSTALLED_APPS.
- Separated the login/signup templates and views.
- Added handling for Django's AUTH_PROFILE_MODULE setting, which accepts the app.model name of a profile model to use.
- Added signal for creating a related profile instance when a user is created.
- Added a view for the logged in user updating their info.
- Added a view for displaying a user's profile (only when AUTH_PROFILE_MODULE is defined)
- Signup and update profile forms now include user fields (username, first name, last name) as well as any profile fields defined by the AUTH_PROFILE_MODULE model. User form in the admin will also include any profile fields.
- Lost password form/view - this is actually very similar to the signup verification feature recently added. It just sends an email to the user with login token that redirects them to update their password via the update profile form.
- I've added an auth backend for Mezzanine that accepts either username or email address along with the password for logging in. It also handles logins via access tokens for signup verification and password reset. This means you can login using email instead of password via the admin as well.
One thing I was considering but didn't do, is to hide all fields but the email address and password field on the signup/update forms, if a profile model isn't defined. That way there's a clean configuration point of "I just want logins" versus "I want full blown profiles".
Some other housekeeping bits that came out of it:
- Created a Html5Mixin class for forms. With the new account forms, there were 3 different instances of adding custom HTML5 attributes to form fields. The forms in mezzanine.forms still use their own as they're a bit more advanced, but the others use the Html5Mixin. By default it just adds the "required" attribute to required fields, which means you get nice client-side validation without any JavaScript. As previously, if the FORMS_USE_HTML5 setting is True, more enhancements are made such as custom field types which result is more client-side validation.
- Deprecated the try_url template tag. All it did was wrap url resolving in an exception and return an empty string if it failed, which was needed for certain admin urls to work during tests being run. I've also started using it to check for urls that legitimately might not exist, such as for an app not being installed. Anyway it turns out if you use the "as" arg of Django's normal url template tag, you can achieve the same result, so I've updated all instance of try_url will that, and left the template tag in with a warning.
- Removed pre-hashing of email addresses for gravatar URLs. Previously this existing on comments - the email address given would be hashed and stored in the DB to use for showing gravatar avatars. I've added gravatar avatars to the new profile view, and since there's nowhere to store the hash, I've changed the gravatar_url template tag to take an email and hash it on the fly, rather than the pre-computed hash.
- Made settings defined in TEMPLATE_ACCESSIBLE_SETTINGS that don't exist just return an empty string in templates rather than raising an exception.
- Made primary nav items in the admin navigation clickable - they just go to the first item in the dropdown lists which for the default setup makes sense: Content->Pages Sites->Sites Users->Users
This of course will make up one of the bigger features of 1.1. I'm not going to release that for a little while longer though, so there's plenty of time now to give feedback and collaborate on this new stuff. Please have a look at the code and if you think anything should be different, or have any idea around how this could be better, now is definitely the time to chime in. As always, all feedback is welcome.
The other things that might go into 1.1 are:
- Basic multi-tenancy. We briefly mentioned a while back about introducing a "current request" object using threadlocals into the code base, which would make certain things very easy to develop. What we could do with this is dynamically have access to the current host name, and use that to look up the site object to load anything for, instead of the single SITE_ID. This is just a high-level thought at the moment, but theoretically with that in place we could have multiple domains with their own content (or shared) running off a single Django instance. If this turns out to be a considerable amount of work (eg not as simple as I'm describing it right now), I don't think we will include it in 1.1.
- A fabric script for deployment. There's been mention before about including some default files for deploying Mezzanine such as web server configs. I've been working on a fabric deploy script that takes a vanilla Ubuntu image and by the end of it has a complete Mezzanine instance running using Postgres, Memcached, gunicorn, nginx, supervisord, virtualenv, etc. It still needs a bit more work, and is obviously very opinionated, but I think it'll make a starting point for a very good tool for people new to deploying Django projects in general, as I think a lot of newcomers to Mezzanine are. The nice thing about this is that it can always be an ongoing work in progress. Hopefully over time it'll grow into something very powerful.