Skip to content
Browse files

Big round of bugfixes

- Fixes for django-registration
- Removed debugging print in stomp_client
- Gadget list now retrieved via manager connection
- Renamed events to comply with the desktop client
  onInsertText -> onInsertedText
  onDeleteText -> onDeletedText
  onInsertElement -> onInsertedElement
  onDeleteElement -> onDeletedElement
- Delete box for Gadgets now only displayed on editing
- Cursor placement on editing fixed on firefox and others
- Shift+Enter shortcut (finishes Blip editing)
- Statistics for RPC-Server
- Unicode problems fixed (also switched to simplejson)
- Gadget wrapper script URL now configurable on the http query
- Problem with same URL of hosted gadgets fixed (now the first
  one is taken)
  • Loading branch information...
1 parent 9215925 commit 9bcdc7f138f40ba87e750d265bba14c1b8ac7622 @p2k p2k committed Dec 16, 2009
View
1 media/css/pygowave-client-style.css
@@ -430,7 +430,6 @@
float: left;
margin-left: 6px;
margin-right: 3px;
- margin-top: 1px;
}
.blip_editor_control.blip_contributors > *
View
18 pygowave_client/src/controller/controller.js
@@ -290,6 +290,10 @@ pygowave.controller = $defined(pygowave.controller) ? pygowave.controller : new
else if (msg.property.result == "TOO_SHORT")
this._iview.invalidSearch(msg.property.data);
break;
+ case "GADGET_LIST":
+ this._cachedGadgetList = msg.property;
+ this._iview.updateGadgetList(msg.property);
+ break;
case "WAVELET_REMOVE_PARTICIPANT":
if (this.wavelets.has(msg.property.waveletId))
this.wavelets[msg.property.waveletId].model.removeParticipant(msg.property.id);
@@ -331,10 +335,6 @@ pygowave.controller = $defined(pygowave.controller) ? pygowave.controller : new
case "OPERATION_MESSAGE_BUNDLE":
this._queueMessageBundle(wavelet_model, false, msg.property.operations, msg.property.version, msg.property.blipsums, msg.property.timestamp, msg.property.contributor);
break;
- case "GADGET_LIST":
- this._cachedGadgetList = msg.property;
- this._iview.updateGadgetList(msg.property);
- break;
case "ERROR":
this._iview.showControllerError(gettext("The server reports the following error:<br/><br/>%s<br/><br/>Wavelet ID: %s<br/>Error Tag: %s").sprintf(msg.property.desc, wavelet_id, msg.property.tag));
break;
@@ -853,15 +853,11 @@ pygowave.controller = $defined(pygowave.controller) ? pygowave.controller : new
/**
* Callback from view on gadget adding.
* @function {private} _onRefreshGadgetList
- * @param {String} waveletId ID of the Wavelet
* @param {Boolean} forced True if the user explicitly clicked refresh
*/
- _onRefreshGadgetList: function (waveletId, forced) {
- if (forced || this._cachedGadgetList == null) {
- this.conn.sendJson(waveletId, {
- type: "GADGET_LIST"
- });
- }
+ _onRefreshGadgetList: function (forced) {
+ if (forced || this._cachedGadgetList == null)
+ this.conn.sendJson("manager", {type: "GADGET_LIST"});
else
this._iview.updateGadgetList(this._cachedGadgetList);
}
View
16 pygowave_client/src/model/model.py
@@ -517,30 +517,30 @@ class Blip(object):
"""
Fired on text insertion.
- @event onInsertText
+ @event onInsertedText
@param {int} index Offset where the text is inserted
@param {String} text The text to be inserted
"""
"""
Fired on text deletion.
- @event onDeleteText
+ @event onDeletedText
@param {int} index Offset where the text is deleted
@param {int} length Number of characters to delete
"""
"""
Fired on element insertion.
- @event onInsertElement
+ @event onInsertedElement
@param {int} index Offset where the element is inserted
"""
"""
Fired on element deletion.
- @event onDeleteElement
+ @event onDeletedElement
@param {int} index Offset where the element is deleted
"""
@@ -767,7 +767,7 @@ def insertText(self, index, text, contributor, noevent = False):
self._wavelet._setStatus("dirty")
if not noevent:
- self.fireEvent("insertText", [index, text])
+ self.fireEvent("insertedText", [index, text])
def deleteText(self, index, length, contributor, noevent = False):
"""
@@ -797,7 +797,7 @@ def deleteText(self, index, length, contributor, noevent = False):
self._wavelet._setStatus("dirty")
if not noevent:
- self.fireEvent("deleteText", [index, length])
+ self.fireEvent("deletedText", [index, length])
def insertElement(self, index, type, properties, contributor, noevent = False):
"""
@@ -825,7 +825,7 @@ def insertElement(self, index, type, properties, contributor, noevent = False):
self._wavelet._setStatus("dirty")
if not noevent:
- self.fireEvent("insertElement", index)
+ self.fireEvent("insertedElement", index)
def deleteElement(self, index, contributor, noevent = False):
"""
@@ -848,7 +848,7 @@ def deleteElement(self, index, contributor, noevent = False):
break
self.deleteText(index, 1, contributor, True)
if not noevent:
- self.fireEvent("deleteElement", index)
+ self.fireEvent("deletedElement", index)
def applyElementDelta(self, index, delta, contributor):
"""
View
54 pygowave_client/src/view/blip_editor.js
@@ -92,10 +92,10 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
'spellcheck': 'false'
});
- this._onInsertText = this._onInsertText.bind(this);
- this._onDeleteText = this._onDeleteText.bind(this);
- this._onInsertElement = this._onInsertElement.bind(this);
- this._onDeleteElement = this._onDeleteElement.bind(this);
+ this._onInsertedText = this._onInsertedText.bind(this);
+ this._onDeletedText = this._onDeletedText.bind(this);
+ this._onInsertedElement = this._onInsertedElement.bind(this);
+ this._onDeletedElement = this._onDeletedElement.bind(this);
this._onKeyDown = this._onKeyDown.bind(this);
this._onKeyPress = this._onKeyPress.bind(this);
this._onKeyUp = this._onKeyUp.bind(this);
@@ -140,11 +140,11 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
var ok = this.reloadContent();
blip.addEvents({
- insertText: this._onInsertText,
- deleteText: this._onDeleteText,
+ insertedText: this._onInsertedText,
+ deletedText: this._onDeletedText,
outOfSync: this._onOutOfSync,
- insertElement: this._onInsertElement,
- deleteElement: this._onDeleteElement,
+ insertedElement: this._onInsertedElement,
+ deletedElement: this._onDeletedElement,
lastModifiedChanged: this._onLastModifiedChanged,
contributorAdded: this._onContributorAdded
});
@@ -183,11 +183,11 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
it.next().removeEvent("dataChanged", this._updateContributorNames);
this._contributorObjects.empty();
this._blip.removeEvents({
- insertText: this._onInsertText,
- deleteText: this._onDeleteText,
+ insertedText: this._onInsertedText,
+ deletedText: this._onDeletedText,
outOfSync: this._onOutOfSync,
- insertElement: this._onInsertElement,
- deleteElement: this._onDeleteElement
+ insertedElement: this._onInsertedElement,
+ deletedElement: this._onDeletedElement
});
this.contentElement.removeEvents({
keydown: this._onKeyDown,
@@ -369,8 +369,11 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
this._editControls.inject(this.contentElement, "bottom");
this._editControls.contentEditable = "false";
}
+ for (var it = new _Iterator(this._elements); it.hasNext(); )
+ it.next().setDeleteBoxVisible(true);
this._editing = true;
this.fireEvent("blipEditing", this._blip.id());
+ this.contentElement.focus();
var ret = this._walkDown(this.contentElement, this._blip.content().length);
var sel = new Selection(ret[0], ret[1], ret[0], ret[1]);
sel.select();
@@ -386,6 +389,8 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
if (!this._editing)
return;
this.toggleDraft(false);
+ for (var it = new _Iterator(this._elements); it.hasNext(); )
+ it.next().setDeleteBoxVisible(false);
this._editControls.setStyle("visibility", "hidden");
this._editControls.setStyle("position", "absolute");
this._editControls.setStyle("top", "0");
@@ -549,7 +554,7 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
checkOrAddNewline: function (index) {
var text = this.contentToString();
if (index > 0 && text.substr(index-1, 1) != "\n") {
- this._onInsertText(index, "\n");
+ this._onInsertedText(index, "\n");
this._view.setBusy();
this._view.fireEvent(
'textInserted',
@@ -628,6 +633,12 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
},
_onKeyDown: function (e) {
+ // Capture Shift+Enter
+ if (e.shift && e.key == 'enter') {
+ e.stop();
+ this.finishBlip();
+ return;
+ }
this._firstKeyPress = true;
this._view.setBusy();
},
@@ -653,6 +664,7 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
_processKey: function(e) {
if (!this._editing)
return;
+
var newRange = this.currentTextRange(e.target);
if (!$defined(newRange))
return;
@@ -757,11 +769,11 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
/**
* Callback from model on text insertion
*
- * @function {private} _onInsertText
+ * @function {private} _onInsertedText
* @param {int} index Index of the inserion
* @param {String} text Text to be inserted
*/
- _onInsertText: function (index, text) {
+ _onInsertedText: function (index, text) {
//TODO: this function assumes no formatting elements
this._view.setBusy();
@@ -843,11 +855,11 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
/**
* Callback from model on text deletion
*
- * @function {private} _onDeleteText
+ * @function {private} _onDeletedText
* @param {int} index Index of the deletion
* @param {String} length How many characters to delete
*/
- _onDeleteText: function (index, length) {
+ _onDeletedText: function (index, length) {
// Safe for formatting elements
this._view.setBusy();
var rlength = length; // Remaining length
@@ -899,9 +911,10 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
/**
* Callback from model if an element was inserted.
*
+ * @function {private} _onInsertedElement
* @param {int} index Offset where the element is inserted
*/
- _onInsertElement: function (index) {
+ _onInsertedElement: function (index) {
this._view.setBusy();
var elt = this._blip.elementAt(index);
@@ -914,6 +927,8 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
//TODO other elements
var ew = new GadgetElementWidget(this._view, elt, para, 'before');
+ if (this._editing)
+ ew.setDeleteBoxVisible(true);
ew.addEvent('deleteClicked', this.deleteElementWidgetAt);
this._elements.push(ew);
@@ -929,9 +944,10 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
/**
* Callback from model if an element was deleted.
*
+ * @function {private} _onDeletedElement
* @param {int} index Offset where the element is deleted
*/
- _onDeleteElement: function (index) {
+ _onDeletedElement: function (index) {
this._view.setBusy();
this.deleteElementWidgetAt(index, true);
View
17 pygowave_client/src/view/gadgets.js
@@ -93,7 +93,7 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
* @function {public} initLoadGadgetList
*/
initLoadGadgetList: function () {
- this._view.fireEvent('refreshGadgetList', [this._waveletId, false]);
+ this._view.fireEvent('refreshGadgetList', false);
},
/**
@@ -175,7 +175,7 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
this._select.set('disabled', true);
this._select.grab(new Element('option', {'text': gettext("Loading..."), 'value': 0}));
this.showSpinner(this.spinnerEl);
- this._view.fireEvent('refreshGadgetList', [this._waveletId, true]);
+ this._view.fireEvent('refreshGadgetList', true);
}
});
@@ -232,6 +232,7 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
'class': 'delete_box' + (Browser.Engine.presto ? '_opera' : ''),
'title': gettext("Delete Gadget")
}).inject(contentElement);
+ this.setDeleteBoxVisible(false);
this._deleteBox.addEvent('click', function () {
this.fireEvent('deleteClicked', this._gadgetElement.position());
}.bind(this));
@@ -280,6 +281,18 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
position: function () {
return this._gadgetElement.position();
},
+ /**
+ * Shows or hides the delete box.
+ *
+ * @function {public} setDeleteBoxVisible
+ * @param {Boolean} visible True to show, false to hide
+ */
+ setDeleteBoxVisible: function (visible) {
+ if (visible)
+ this._deleteBox.setStyle("visibility", "visible");
+ else
+ this._deleteBox.setStyle("visibility", "hidden");
+ },
/**
* Callback from iframe on load. Invokes onLoad callbacks of the
View
5 pygowave_client/src/view/view.js
@@ -211,8 +211,10 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
deleteBlip: this._onDeleteBlip
});
blip.addEvent('idChanged', this._onBlipIdChanged);
- if (blip.id().startswith("TBD_"))
+ if (blip.id().startswith("TBD_") || (blip.isRoot() && blip.content().length == 0)) {
editor.editBlip();
+ new Fx.Scroll(this._blipContainerWidget.contentElement).toBottom();
+ }
},
/**
* Callback on Blip deletion
@@ -444,7 +446,6 @@ pygowave.view = $defined(pygowave.view) ? pygowave.view : new Hash();
* <br/>Note: This event is fired by a AddGadgetWindow instance.
*
* @event onRefreshGadgetList
- * @param {String} waveletId ID of the Wavelet
* @param {Boolean} forced True if the user explicitly clicked refresh
*/
View
37 pygowave_rpc/c2s_mp.py
@@ -90,6 +90,12 @@ class PyGoWaveClientMessageProcessor(object):
logger = logging.getLogger("pygowave")
conn_lifetime = datetime.timedelta(minutes=getattr(settings, "ACCESS_KEY_TIMEOUT_MINUTES", 2))
+ def __init__(self):
+ self.bundles = 0
+ self.curr_connections = set()
+ self.peak_connections = 0
+ self.total_connections = 0
+
def process(self, routing_key, message_data):
"""
Process a message in JSON format with the given routing key (= sender ID).
@@ -114,6 +120,11 @@ def process(self, routing_key, message_data):
if wavelet_id != "login":
try:
pconn = ParticipantConn.objects.get(tx_key=participant_conn_key)
+ if pconn.id not in self.curr_connections:
+ self.curr_connections.add(pconn.id)
+ self.total_connections += 1
+ if self.peak_connections < len(self.curr_connections):
+ self.peak_connections = len(self.curr_connections)
except ObjectDoesNotExist:
return self.reply_error(participant_conn_key, wavelet_id, "NO_CONNECTION", "Not logged in or disconnected by server")
@@ -254,6 +265,8 @@ def handle_participant_message(self, wavelet, pconn, message):
return False
elif message["type"] == "OPERATION_MESSAGE_BUNDLE":
+ self.bundles += 1
+
# Build OpManager
newdelta = OpManager(wavelet.wave.id, wavelet.id, participant.id)
newdelta.unserialize(message["property"]["operations"])
@@ -418,6 +431,7 @@ def handle_management_message(self, pconn, message):
elif message["type"] == "DISCONNECT":
self.logger.info("[%s/%s@manager] Connection to server closed (by client)" % (participant.name, pconn.id))
+ self.curr_connections.remove(pconn.id)
pconn.delete()
return False
@@ -551,6 +565,26 @@ def reply_error(self, conn_key, wavelet_id, tag, desc):
}
}
+ def log_stats(self):
+ """
+ Writes some statistics to the logfile. This method may be
+ called periodically; stats are reset after each call.
+
+ """
+ self.logger.info("""[Statistics]
+Bundles processed: %(bundles)s
+Curr. connections: %(curr_connections)s
+Peak connections: %(peak_connections)s
+Total connections: %(total_connections)s""" % {
+ "bundles": self.bundles,
+ "curr_connections": len(self.curr_connections),
+ "peak_connections": self.peak_connections,
+ "total_connections": self.total_connections,
+ })
+ self.bundles = 0
+ self.peak_connections = len(self.curr_connections)
+ self.total_connections = 0
+
def purge_connections(self):
"""
This method will check all connections to the server and throw out
@@ -564,5 +598,8 @@ def purge_connections(self):
for wavelet in conn.wavelets.all():
wavelet.participant_conns.remove(conn)
self.logger.info("[%s/%s@%s] Connection to wavelet closed (by timeout)" % (conn.participant.name, conn.id, wavelet.wave.id))
+ if conn_id in self.curr_connections:
+ self.curr_connections.remove(conn_id)
conn.delete()
self.logger.info("[%s/%s] Connection to server closed (by timeout)" % (conn_participant_name, conn_id))
+
View
9 pygowave_rpc/stomp_client.py
@@ -19,7 +19,7 @@
from twisted.internet.protocol import Protocol, ReconnectingClientFactory
from twisted.internet.task import LoopingCall
-import stomper, anyjson
+import stomper, simplejson
from c2s_mp import PyGoWaveClientMessageProcessor
@@ -54,8 +54,7 @@ def connected(self, msg):
def ack(self, message):
rkey = message["headers"]["destination"]
- self.pygo_mp.logger.info("Got "+message["body"])
- message_data = anyjson.deserialize(message["body"])
+ message_data = simplejson.loads(message["body"].decode("utf-8"))
msg_dict = self.pygo_mp.process(rkey, message_data)
@@ -68,7 +67,7 @@ def ack(self, message):
def send(self, routing_key, message_data):
"""Convert a routing_key and data dictionary into a STOMP message."""
f = stomper.Frame()
- f.unpack(stomper.send(routing_key, anyjson.serialize(message_data)))
+ f.unpack(stomper.send(routing_key, simplejson.dumps(message_data)))
f.headers["exchange"] = "wavelet.direct"
f.headers["content-type"] = "application/json"
return f.pack().encode("utf-8")
@@ -88,6 +87,8 @@ def connectionMade(self):
self.transport.write(self.mp.connect())
self.lc = LoopingCall(self.mp.pygo_mp.purge_connections)
self.lc.start(10 * 60) # Purge every 10 minutes
+ self.lc2 = LoopingCall(self.mp.pygo_mp.log_stats)
+ self.lc2.start(60 * 60, now=False) # Stats every 60 minutes
def connectionLost(self, reason):
if self.lc.running:
View
9 pygowave_rpc/stomp_server.py
@@ -19,7 +19,7 @@
from twisted.internet.protocol import Protocol, ServerFactory
from twisted.internet.task import LoopingCall
-import stomper, anyjson, traceback
+import stomper, simplejson, traceback
from c2s_mp import PyGoWaveClientMessageProcessor
import logger
@@ -97,6 +97,8 @@ def startFactory(self):
self.pygo_mp.logger.info("=> PyGoWave RPC Server starting <=")
self.lc = LoopingCall(self.pygo_mp.purge_connections)
self.lc.start(10 * 60) # Purge every 10 minutes
+ self.lc2 = LoopingCall(self.pygo_mp.log_stats)
+ self.lc2.start(15 * 60, now=False) # Stats every 15 minutes
self.pygo_mp.logger.info("=> PyGoWave RPC Server ready <=")
def stopFactory(self):
@@ -120,11 +122,12 @@ def disconnected(self, proto):
del self.subscriptions[proto.id]
def send(self, dest_name, body, headers={}):
- msg_dict = self.pygo_mp.process(dest_name, anyjson.deserialize(body))
+ msg_dict = self.pygo_mp.process(dest_name, simplejson.loads(body.decode("utf-8")))
for out_rkey, messages in msg_dict.iteritems():
if self.destinations.has_key(out_rkey):
- self.destinations[out_rkey].sendFrame('MESSAGE', {'destination': str(out_rkey)}, anyjson.serialize(messages).encode("utf-8"))
+ self.destinations[out_rkey].sendFrame('MESSAGE', {'destination': str(out_rkey)}, simplejson.dumps(messages).encode("utf-8"))
def __repr__(self):
return "StompServerFactory"
+
View
4 pygowave_server/models.py
@@ -496,7 +496,7 @@ def insertElement(self, index, type, properties, contributor):
self.addContributor(contributor)
- self.insertText(index, "\n")
+ self.insertText(index, "\n", contributor)
if type == 2:
elt = GadgetElement(blip=self, position=index)
else:
@@ -518,7 +518,7 @@ def deleteElement(self, index, contributor):
if elt.type == 2:
elt = elt.to_gadget()
elt.delete()
- self.deleteText(index, 1)
+ self.deleteText(index, 1, contributor)
@transaction.commit_on_success
def applyElementDelta(self, index, delta, contributor):
View
5 pygowave_server/templates/pygowave_server/gadgets/gadget_wrapper.html
@@ -6,9 +6,8 @@
<head>
<title>{% block title %}{{ gadget.title }}{% endblock %}</title>
- <link rel="icon" href="{{ MEDIA_URL }}images/favicon.ico" type="image/x-icon" />
<style type="text/css">html,body{height:100%;width:100%;margin:0;padding:0;}</style>
- <script type="text/javascript" src="{{ MEDIA_URL }}js/gadget-wrapper.js"></script>{% if gadget.features.wave_preview %}
+ <script type="text/javascript" src="{{ wrapper_script_url }}"></script>{% if gadget.features.wave_preview %}
<script type="text/javascript" src="http://wave-api.appspot.com/public/wave.js"></script>{% endif %}
<script type="text/javascript">
__MODULE_ID__ = {% if gadget_id %}{{ gadget_id }}{% else %}null{% endif %};
@@ -25,4 +24,4 @@
{% endblock %}
</body>
-</html>
+</html>
View
23 pygowave_server/views.py
@@ -279,12 +279,11 @@ def gadget_loader(request):
url = request.GET["url"]
# Directly load hosted gadgets
- try:
- gadget_obj = Gadget.objects.get(url=url)
+ gadget_obj = Gadget.objects.filter(url=url)
+ if gadget_obj.count() > 0:
+ gadget_obj = gadget_obj.all()[0]
if gadget_obj.is_hosted():
url = "file://%s%s" % (django_settings.GADGET_ROOT, gadget_obj.hosted_filename)
- except ObjectDoesNotExist:
- pass
try:
gadget = GadgetLoader(url)
@@ -306,4 +305,18 @@ def gadget_loader(request):
else:
gadget_id = None
- return render_to_response('pygowave_server/gadgets/gadget_wrapper.html', {"gadget": gadget, "url_parameters": simplejson.dumps(request.GET), "gadget_id": gadget_id}, context_instance=RequestContext(request))
+ if request.GET.has_key("wrapper_script"):
+ wrapper_script_url = request.GET["wrapper_script"]
+ else:
+ wrapper_script_url = django_settings.MEDIA_URL + "js/gadget-wrapper.js"
+
+ return render_to_response(
+ 'pygowave_server/gadgets/gadget_wrapper.html',
+ {
+ "gadget": gadget,
+ "url_parameters": simplejson.dumps(request.GET),
+ "gadget_id": gadget_id,
+ "wrapper_script_url": wrapper_script_url
+ },
+ context_instance=RequestContext(request)
+ )
View
10 templates/registration/activate.html
@@ -6,17 +6,7 @@
{% block container_class %}container_narrow{% endblock %}
{% block content %}
<h1>{% trans "Account activation" %}</h1>
- {% if account %}
- <p>
- {% trans "Congratulations! Your account was activated. Have fun." %}
- {% track_event "registration" "account activated" %}
- </p>
- <p>
- <a href="{% url django.contrib.auth.views.login %}">{% trans "Login" %} &raquo;</a>
- </p>
- {% else %}
<p>
{% trans "Sorry, your account could not be activated. Please contact the server administrator." %}
</p>
- {% endif %}
{% endblock %}
View
16 templates/registration/activation_complete.html
@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+{% load i18n %}
+{% load analytics %}
+
+{% block title %}{% trans "Account activation" %}{% endblock %}
+{% block container_class %}container_narrow{% endblock %}
+{% block content %}
+ <h1>{% trans "Account activation" %}</h1>
+ <p>
+ {% trans "Congratulations! Your account was activated. Have fun." %}
+ {% track_event "registration" "account activated" %}
+ </p>
+ <p>
+ <a href="{% url django.contrib.auth.views.login %}">{% trans "Login" %} &raquo;</a>
+ </p>
+{% endblock %}
View
5 urls.py
@@ -30,7 +30,10 @@
urlpatterns = patterns('',
(r'^admin/(.*)', admin.site.root),
- url(r'^accounts/register/$', register, name='registration_register', kwargs={"form_class": MyRegistrationForm}),
+ url(r'^accounts/register/$', register, name='registration_register', kwargs={
+ "form_class": MyRegistrationForm,
+ "backend": 'registration.backends.default.DefaultBackend'
+ }),
(r'^accounts/', include('registration.backends.default.urls')),
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
(r'^i18n/', include('django.conf.urls.i18n')),

0 comments on commit 9bcdc7f

Please sign in to comment.
Something went wrong with that request. Please try again.