From 794852f2924f850be668e5eeb36673b8e86a2c88 Mon Sep 17 00:00:00 2001 From: Sofia Papagiannaki Date: Mon, 23 Jan 2012 16:06:09 +0200 Subject: [PATCH] Several minor changes: - create im/migrations (for south use) - fixture for django_site - fix ExtendedUserCreationForm: use AstakosUser instead of django.contrib.auth.models.User - do not redirect to profile page after login if request.user is superuser --- README | 2 +- README.upgrade | 65 +--------------- astakos/im/admin/templates/admin_base.html | 3 + astakos/im/admin/urls.py | 24 +++--- astakos/im/auth_backends.py | 6 ++ astakos/im/backends/__init__.py | 23 +++--- astakos/im/fixtures/site.json | 10 +++ astakos/im/forms.py | 28 ++++--- astakos/im/migrations/0001_initial.py | 116 ++++++++++++++++++++++++++++ astakos/im/target/util.py | 2 +- astakos/im/templates/index.html | 17 +++- astakos/im/urls.py | 46 +++++------ astakos/im/views.py | 13 ++-- docs/source/adminguide.rst | 39 +++++++++- 14 files changed, 259 insertions(+), 135 deletions(-) create mode 100644 astakos/im/fixtures/site.json create mode 100644 astakos/im/migrations/0001_initial.py create mode 100644 astakos/im/migrations/__init__.py diff --git a/README b/README index 7aacf52..3fad5ae 100644 --- a/README +++ b/README @@ -29,7 +29,7 @@ Running the server ------------------ Make sure you have all required packages installed: - apt-get install python-django python-setuptools python-sphinx python-httplib2 + apt-get install python-django python-django-south python-setuptools python-sphinx python-httplib2 Then run: python manage.py syncdb diff --git a/README.upgrade b/README.upgrade index 3560795..6f9928b 100644 --- a/README.upgrade +++ b/README.upgrade @@ -1,65 +1,2 @@ UPGRADE -======= - -0.7.9 -> 0.7.10 ---------------- -* Update settings.py (BACKEND_*, SERVICE_NAME, *_EMAIL, *_TARGET, IM_*) -* Update 'attributes' table in mysql (backend): - - mysql> update attributes set `key`='ETag' where `key`='hash'; - -* Upgrade 'im_user' table (im app): - - ALTER TABLE im_user ADD COLUMN 'password' VARCHAR(255); - -0.7.10 -> 0.8.0 ---------------- -* Upgrade 'public' table in mysql (backend): - * Run: mysqldump pithosdb public > public-table.sql - * mysql> drop table public; - * Update the codebase and run the server so the new public table is created - * From the sql dump above, take the row: - - INSERT INTO `public` VALUES (...); - - Rewrite as: - - INSERT INTO `public`(`path`) VALUES (...); - - And execute in the database -* Create settings.local with local setting overrides -* Install python-django-south -* Setup south: - python manage.py syncdb - python manage.py migrate im 0001 --fake - python manage.py migrate im - -0.8.0 -> 0.8.1 --------------- -* Reset 'policy' table in mysql (backend): - - mysql> update policy set `value`='auto' where `key`='versioning'; - -0.8.1 -> 0.8.2 --------------- -* Add the 'X-Forwarded-Protocol' header directive in the apache configuration, as described in the admin guide -* Update 'attributes' table in mysql (backend): - - mysql> CREATE TABLE `attributes_new` ( - `serial` int(11) NOT NULL, - `domain` varchar(255) COLLATE utf8_bin NOT NULL, - `key` varchar(255) COLLATE utf8_bin NOT NULL, - `value` varchar(255) COLLATE utf8_bin DEFAULT NULL, - PRIMARY KEY (`serial`,`domain`,`key`), - CONSTRAINT FOREIGN KEY (`serial`) REFERENCES `versions` (`serial`) ON DELETE CASCADE ON UPDATE CASCADE - ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; - mysql> insert into attributes_new select `serial`, 'pithos', `key`, `value` from attributes; - mysql> drop table attributes; - mysql> alter table attributes_new rename to attributes; - -* Update 'versions' table in mysql (backend): - - mysql> create temporary table tmp_uuids as select distinct node, uuid() as `uuid` from versions; - mysql> alter table versions add column `uuid` varchar(64) DEFAULT '' NOT NULL after `muser`; - mysql> update versions v, tmp_uuids u set v.`uuid` = u.`uuid` where v.`node` = u.`node`; - mysql> create index idx_versions_node_uuid on versions(uuid); +======= \ No newline at end of file diff --git a/astakos/im/admin/templates/admin_base.html b/astakos/im/admin/templates/admin_base.html index 5fcb957..6b7ade7 100644 --- a/astakos/im/admin/templates/admin_base.html +++ b/astakos/im/admin/templates/admin_base.html @@ -14,6 +14,9 @@ Invitations + + Logout + {% endblock %} diff --git a/astakos/im/admin/urls.py b/astakos/im/admin/urls.py index c580104..a239837 100644 --- a/astakos/im/admin/urls.py +++ b/astakos/im/admin/urls.py @@ -31,20 +31,20 @@ # interpreted as representing official policies, either expressed # or implied, of GRNET S.A. -from django.conf.urls.defaults import patterns +from django.conf.urls.defaults import patterns, url urlpatterns = patterns('astakos.im.admin.views', - (r'^$', 'admin'), + url(r'^$', 'admin'), - (r'^users/?$', 'users_list'), - (r'^users/(\d+)/?$', 'users_info'), - (r'^users/create$', 'users_create'), - (r'^users/(\d+)/modify/?$', 'users_modify'), - (r'^users/(\d+)/delete/?$', 'users_delete'), - (r'^users/export/?$', 'users_export'), - (r'^users/pending/?$', 'pending_users'), - (r'^users/activate/(\d+)/?$', 'users_activate'), + url(r'^users/?$', 'users_list'), + url(r'^users/(\d+)/?$', 'users_info'), + url(r'^users/create$', 'users_create'), + url(r'^users/(\d+)/modify/?$', 'users_modify'), + url(r'^users/(\d+)/delete/?$', 'users_delete'), + url(r'^users/export/?$', 'users_export'), + url(r'^users/pending/?$', 'pending_users'), + url(r'^users/activate/(\d+)/?$', 'users_activate'), - (r'^invitations/?$', 'invitations_list'), - (r'^invitations/export/?$', 'invitations_export'), + url(r'^invitations/?$', 'invitations_list'), + url(r'^invitations/export/?$', 'invitations_export'), ) \ No newline at end of file diff --git a/astakos/im/auth_backends.py b/astakos/im/auth_backends.py index 96e546a..c474741 100644 --- a/astakos/im/auth_backends.py +++ b/astakos/im/auth_backends.py @@ -6,6 +6,9 @@ from django.contrib.auth.backends import ModelBackend from astakos.im.models import AstakosUser class AstakosUserModelCredentialsBackend(ModelBackend): + """ + AuthenticationBackend used to authenticate user creadentials + """ def authenticate(self, username=None, password=None): try: user = AstakosUser.objects.get(username=username) @@ -31,6 +34,9 @@ class AstakosUserModelCredentialsBackend(ModelBackend): # return self._user_class class AstakosUserModelTokenBackend(ModelBackend): + """ + AuthenticationBackend used to authenticate using token instead + """ def authenticate(self, username=None, auth_token=None): try: user = AstakosUser.objects.get(username=username) diff --git a/astakos/im/backends/__init__.py b/astakos/im/backends/__init__.py index 07e97bd..6fb7487 100644 --- a/astakos/im/backends/__init__.py +++ b/astakos/im/backends/__init__.py @@ -86,22 +86,21 @@ class InvitationsBackend(object): """ code = request.GET.get('code', '') formclass = 'ExtendedUserCreationForm' + initial_data = None if request.method == 'GET': - initial_data = None if code: formclass = 'Invited%s' %formclass self.invitation = Invitation.objects.get(code=code) if self.invitation.is_consumed: - return HttpResponseBadRequest('Invitation has beeen used') - initial_data.update({'username':self.invitation.username, - 'email':self.invitation.username, - 'realname':self.invitation.realname}) + raise Exception('Invitation has beeen used') + initial_data = {'username':self.invitation.username, + 'email':self.invitation.username, + 'realname':self.invitation.realname} inviter = AstakosUser.objects.get(username=self.invitation.inviter) initial_data['inviter'] = inviter.realname else: initial_data = request.POST - self.form = globals()[formclass](initial_data) - return self.form + return globals()[formclass](initial_data) def _is_preaccepted(self, user): """ @@ -125,12 +124,13 @@ class InvitationsBackend(object): In any other case the method returns the action status and a message. """ kwargs = {} - form = self.form - user = form.save(commit=False) + form = self.get_signup_form(request) + user = form.save() try: if self._is_preaccepted(user): user.is_active = True + user.save() message = _('Registration completed. You can now login.') next = request.POST.get('next') if next: @@ -177,8 +177,9 @@ class SimpleBackend(object): * DEFAULT_FROM_EMAIL: from email """ kwargs = {} - form = self.form - user = form.save(commit=False) + form = self.get_signup_form(request) + user = form.save() + status = messages.SUCCESS try: _send_verification(request, user, email_template_name) diff --git a/astakos/im/fixtures/site.json b/astakos/im/fixtures/site.json new file mode 100644 index 0000000..24cc580 --- /dev/null +++ b/astakos/im/fixtures/site.json @@ -0,0 +1,10 @@ +[ + { + "model": "sites.site", + "pk": 1, + "fields": { + "domain": "localhost:8000/im", + "name": "Astakos" + } + } +] diff --git a/astakos/im/forms.py b/astakos/im/forms.py index a869324..64c996e 100644 --- a/astakos/im/forms.py +++ b/astakos/im/forms.py @@ -58,12 +58,9 @@ class ExtendedUserCreationForm(UserCreationForm): """ Extends the built in UserCreationForm in several ways: - * Adds an email field, which uses the custom UniqueUserEmailField, - that is, the form does not validate if the email address already exists - in the User table. - * The username field is generated based on the email, and isn't visible. + * Adds an email field, which uses the custom UniqueUserEmailField. + * The username field isn't visible and it is assigned the email value. * first_name and last_name fields are added. - * Data not saved by the default behavior of UserCreationForm is saved. """ username = forms.CharField(required = False, max_length = 30) @@ -71,11 +68,15 @@ class ExtendedUserCreationForm(UserCreationForm): first_name = forms.CharField(required = False, max_length = 30) last_name = forms.CharField(required = False, max_length = 30) + class Meta: + model = AstakosUser + fields = ("username",) + def __init__(self, *args, **kwargs): """ Changes the order of fields, and removes the username field. """ - super(UserCreationForm, self).__init__(*args, **kwargs) + super(ExtendedUserCreationForm, self).__init__(*args, **kwargs) self.fields.keyOrder = ['email', 'first_name', 'last_name', 'password1', 'password2'] @@ -85,8 +86,6 @@ class ExtendedUserCreationForm(UserCreationForm): """ cleaned_data = super(UserCreationForm, self).clean(*args, **kwargs) if cleaned_data.has_key('email'): - #cleaned_data['username'] = self.__generate_username( - # cleaned_data['email']) cleaned_data['username'] = cleaned_data['email'] return cleaned_data @@ -96,12 +95,6 @@ class ExtendedUserCreationForm(UserCreationForm): save behavior is complete. """ user = super(UserCreationForm, self).save(commit) - if user: - kwargs = {} - for field in self.fields: - if hasattr(AstakosUser(), field): - kwargs[field] = self.cleaned_data[field] - user = get_or_create_user(username=self.cleaned_data['email'], **kwargs) return user class InvitedExtendedUserCreationForm(ExtendedUserCreationForm): @@ -112,12 +105,17 @@ class InvitedExtendedUserCreationForm(ExtendedUserCreationForm): """ inviter = forms.CharField(widget=forms.TextInput(), label=_('Inviter Real Name')) + class Meta: + model = AstakosUser + fields = ("username",) def __init__(self, *args, **kwargs): - super(RegisterForm, self).__init__(*args, **kwargs) + super(InvitedExtendedUserCreationForm, self).__init__(*args, **kwargs) #set readonly form fields self.fields['inviter'].widget.attrs['readonly'] = True + self.fields['email'].widget.attrs['readonly'] = True + self.fields['username'].widget.attrs['readonly'] = True class ProfileForm(forms.ModelForm): """ diff --git a/astakos/im/migrations/0001_initial.py b/astakos/im/migrations/0001_initial.py new file mode 100644 index 0000000..1ab9845 --- /dev/null +++ b/astakos/im/migrations/0001_initial.py @@ -0,0 +1,116 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'AstakosUser' + db.create_table('im_astakosuser', ( + ('user_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['auth.User'], unique=True, primary_key=True)), + ('affiliation', self.gf('django.db.models.fields.CharField')(default='', max_length=255)), + ('provider', self.gf('django.db.models.fields.CharField')(default='', max_length=255)), + ('level', self.gf('django.db.models.fields.IntegerField')(default=4)), + ('invitations', self.gf('django.db.models.fields.IntegerField')(default=0)), + ('auth_token', self.gf('django.db.models.fields.CharField')(max_length=32, null=True, blank=True)), + ('auth_token_created', self.gf('django.db.models.fields.DateTimeField')(null=True)), + ('auth_token_expires', self.gf('django.db.models.fields.DateTimeField')(null=True)), + ('updated', self.gf('django.db.models.fields.DateTimeField')()), + ('is_verified', self.gf('django.db.models.fields.BooleanField')(default=False)), + )) + db.send_create_signal('im', ['AstakosUser']) + + # Adding model 'Invitation' + db.create_table('im_invitation', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('inviter', self.gf('django.db.models.fields.related.ForeignKey')(related_name='invitations_sent', null=True, to=orm['im.AstakosUser'])), + ('realname', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('username', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('code', self.gf('django.db.models.fields.BigIntegerField')(db_index=True)), + ('is_accepted', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('is_consumed', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), + ('accepted', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)), + ('consumed', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)), + )) + db.send_create_signal('im', ['Invitation']) + + + def backwards(self, orm): + + # Deleting model 'AstakosUser' + db.delete_table('im_astakosuser') + + # Deleting model 'Invitation' + db.delete_table('im_invitation') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'im.astakosuser': { + 'Meta': {'object_name': 'AstakosUser', '_ormbases': ['auth.User']}, + 'affiliation': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'invitations': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'is_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'level': ('django.db.models.fields.IntegerField', [], {'default': '4'}), + 'provider': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {}), + 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}) + }, + 'im.invitation': { + 'Meta': {'object_name': 'Invitation'}, + 'accepted': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'code': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}), + 'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'inviter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invitations_sent'", 'null': 'True', 'to': "orm['im.AstakosUser']"}), + 'is_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_consumed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'realname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'username': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + } + } + + complete_apps = ['im'] diff --git a/astakos/im/migrations/__init__.py b/astakos/im/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/astakos/im/target/util.py b/astakos/im/target/util.py index c33f234..9316f3a 100644 --- a/astakos/im/target/util.py +++ b/astakos/im/target/util.py @@ -66,7 +66,7 @@ def prepare_response(request, user, next='', renew=False): parts[3] = urlencode({'user': user.username, 'token': auth_token}) next = urlunsplit(parts) - if settings.FORCE_PROFILE_UPDATE and not user.is_verified: + if settings.FORCE_PROFILE_UPDATE and not user.is_verified and not user.is_superuser: params = '' if next: params = '?' + urlencode({'next': next}) diff --git a/astakos/im/templates/index.html b/astakos/im/templates/index.html index 1a3cf7a..ac8d029 100644 --- a/astakos/im/templates/index.html +++ b/astakos/im/templates/index.html @@ -12,7 +12,22 @@

Local account

{% csrf_token %} - {{ form.as_p }} + {{ form.non_field_errors }} + {% for field in form %} +
+
+ {% if field.name == "username" %} + Email address or Username + {% else %} + {{ field.label_tag }} + {% endif %} +
+
+ {{ field }} + {{ field.errors }} +
+
+ {% endfor %} diff --git a/astakos/im/urls.py b/astakos/im/urls.py index b7b1b4f..7076b5a 100644 --- a/astakos/im/urls.py +++ b/astakos/im/urls.py @@ -32,66 +32,66 @@ # or implied, of GRNET S.A. from django.conf import settings -from django.conf.urls.defaults import patterns, include +from django.conf.urls.defaults import patterns, include, url from django.core.urlresolvers import reverse urlpatterns = patterns('astakos.im.views', - (r'^$', 'index'), - (r'^login/?$', 'index'), - (r'^profile/?$', 'edit_profile'), - (r'^feedback/?$', 'send_feedback'), - (r'^signup/?$', 'signup'), - (r'^admin/', include('astakos.im.admin.urls')), + url(r'^$', 'index'), + url(r'^login/?$', 'index'), + url(r'^profile/?$', 'edit_profile'), + url(r'^feedback/?$', 'send_feedback'), + url(r'^signup/?$', 'signup'), + url(r'^admin/', include('astakos.im.admin.urls')), ) urlpatterns += patterns('django.contrib.auth.views', - (r'^logout/?$', 'logout'), - (r'^password/?$', 'password_change', {'post_change_redirect':'admin'}), + url(r'^logout/?$', 'logout'), + url(r'^password/?$', 'password_change', {'post_change_redirect':'admin'}), ) urlpatterns += patterns('astakos.im.target', - (r'^login/dummy/?$', 'dummy.login') + url(r'^login/dummy/?$', 'dummy.login') ) urlpatterns += patterns('', - (r'^static/(?P.*)$', 'django.views.static.serve', + url(r'^static/(?P.*)$', 'django.views.static.serve', {'document_root': settings.PROJECT_PATH + '/im/static'}) ) if 'local' in settings.IM_MODULES: urlpatterns += patterns('astakos.im.target', - (r'^local/?$', 'local.login'), - (r'^local/activate/?$', 'local.activate'), + url(r'^local/?$', 'local.login'), + url(r'^local/activate/?$', 'local.activate'), ) urlpatterns += patterns('django.contrib.auth.views', - (r'^local/password_reset/?$', 'password_reset', + url(r'^local/password_reset/?$', 'password_reset', {'email_template_name':'registration/password_email.txt'}), - (r'^local/password_reset_done/?$', 'password_reset_done'), - (r'^local/reset/confirm/(?P[0-9A-Za-z]+)-(?P.+)/$', + url(r'^local/password_reset_done/?$', 'password_reset_done'), + url(r'^local/reset/confirm/(?P[0-9A-Za-z]+)-(?P.+)/$', 'password_reset_confirm'), - (r'^local/password/reset/complete/$', 'password_reset_complete') + url(r'^local/password/reset/complete/$', 'password_reset_complete') ) if settings.INVITATIONS_ENABLED: urlpatterns += patterns('astakos.im.views', - (r'^invite/?$', 'invite'), + url(r'^invite/?$', 'invite'), ) urlpatterns += patterns('astakos.im.target', - (r'^login/invitation/?$', 'invitation.login') + url(r'^login/invitation/?$', 'invitation.login') ) if 'shibboleth' in settings.IM_MODULES: urlpatterns += patterns('astakos.im.target', - (r'^login/shibboleth/?$', 'shibboleth.login') + url(r'^login/shibboleth/?$', 'shibboleth.login') ) if 'twitter' in settings.IM_MODULES: urlpatterns += patterns('astakos.im.target', - (r'^login/twitter/?$', 'twitter.login'), - (r'^login/twitter/authenticated/?$', 'twitter.authenticated') + url(r'^login/twitter/?$', 'twitter.login'), + url(r'^login/twitter/authenticated/?$', 'twitter.authenticated') ) urlpatterns += patterns('astakos.im.api', - (r'^authenticate/?$', 'authenticate') + url(r'^authenticate/?$', 'authenticate') ) diff --git a/astakos/im/views.py b/astakos/im/views.py index ba563ec..c72c2a5 100644 --- a/astakos/im/views.py +++ b/astakos/im/views.py @@ -111,15 +111,15 @@ def _generate_invitation_code(): except Invitation.DoesNotExist: return code -def _send_invitation(baseurl, inv): - url = settings.SIGNUP_TARGET % (baseurl, inv.code, quote(baseurl)) - subject = _('Invitation to Pithos') +def _send_invitation(request, baseurl, inv): + subject = _('Invitation to Astakos') site = get_current_site(request) + url = settings.SIGNUP_TARGET % (baseurl, inv.code, site.domain) message = render_to_string('invitation.txt', { 'invitation': inv, 'url': url, 'baseurl': baseurl, - 'service': site_name, + 'service': site.name, 'support': settings.DEFAULT_CONTACT_EMAIL}) sender = settings.DEFAULT_FROM_EMAIL send_mail(subject, message, sender, [inv.username]) @@ -178,7 +178,8 @@ def invite(request, template_name='invitations.html', extra_context={}): defaults={'code': code, 'realname': realname}) try: - _send_invitation(request.build_absolute_uri('/').rstrip('/'), invitation) + baseurl = request.build_absolute_uri('/').rstrip('/') + _send_invitation(request, baseurl, invitation) if created: inviter.invitations = max(0, inviter.invitations - 1) inviter.save() @@ -301,7 +302,7 @@ def signup(request, template_name='signup.html', extra_context={}, backend=None) if next: return redirect(next) messages.add_message(request, status, message) - except (Invitation.DoesNotExist), e: + except (Invitation.DoesNotExist, Exception), e: messages.add_message(request, messages.ERROR, e) return render_response(template_name, form = form if 'form' in locals() else UserCreationForm(), diff --git a/docs/source/adminguide.rst b/docs/source/adminguide.rst index 334fa46..bc55618 100644 --- a/docs/source/adminguide.rst +++ b/docs/source/adminguide.rst @@ -2,5 +2,42 @@ Administrator Guide =================== manage syncdb change django_site record +SITE_ID setting migrate -create twitter application \ No newline at end of file +create twitter application + +Administrator Guide +=================== + +Simple Setup +------------ + +Assuming a clean debian squeeze (stable) installation, use the following steps to run the software. + +Install packages:: + + apt-get install git python-django python-django-south python-setuptools python-sphinx python-httplib2 + apt-get install apache2 libapache2-mod-wsgi + +Get the source:: + + cd / + git clone https://code.grnet.gr/git/astakos + +Setup the files:: + + cd /astakos/astakos + python manage.py syncdb (At this point you will prompt to create a superuser) + python manage.py migrate im 0001 --fake + python manage.py migrate im + python loaddata im/fixtures/admin_user.json (Load additional information for the newly created superuser) + edit im/fixtures/site.json (Change the ``domain`` and ``name`` values according to your site information) + python loaddata im/fixtures/site.json + cd /astakos + python setup.py build_sphinx + python manage runserver + +It is advised that you create a ``settings.local`` file to place any configuration overrides (at least change ``SECRET_KEY``). + +Twitter Setup +------------- \ No newline at end of file -- 1.7.10.4