summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-05-27 18:50:47 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-05-27 18:50:47 -0400
commit098b8335dcdbe236d9d82e65126b6010f5ece3aa (patch)
tree43dd5ec18280e884c4febcff73d54d6ee9082340
parentcc62cf46af63cb65afb8e322a5ebb86462d6fb45 (diff)
downloadaskbot-098b8335dcdbe236d9d82e65126b6010f5ece3aa.tar.gz
askbot-098b8335dcdbe236d9d82e65126b6010f5ece3aa.tar.bz2
askbot-098b8335dcdbe236d9d82e65126b6010f5ece3aa.zip
a possibility to add a custom user profile tab
-rw-r--r--askbot/doc/source/changelog.rst4
-rw-r--r--askbot/doc/source/optional-modules.rst43
-rw-r--r--askbot/skins/default/templates/user_profile/custom_tab.html3
-rw-r--r--askbot/skins/default/templates/user_profile/user.html2
-rw-r--r--askbot/skins/default/templates/user_profile/user_tabs.html5
-rw-r--r--askbot/startup_procedures.py32
-rw-r--r--askbot/views/users.py28
7 files changed, 115 insertions, 2 deletions
diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst
index e9c0da6a..7d1a2fc0 100644
--- a/askbot/doc/source/changelog.rst
+++ b/askbot/doc/source/changelog.rst
@@ -4,7 +4,9 @@ Changes in Askbot
In development
---------------------
* Hide "website" and "about" section of the blocked user profiles
- to help prevent user profile spam. (Evgeny)
+ to help prevent user profile spam (Evgeny)
+* Added a function to create a custom user profile tab,
+ the feature requires access to the server (Evgeny)
0.7.43 (May 14, 2012)
---------------------
diff --git a/askbot/doc/source/optional-modules.rst b/askbot/doc/source/optional-modules.rst
index 0c013121..6e211f4d 100644
--- a/askbot/doc/source/optional-modules.rst
+++ b/askbot/doc/source/optional-modules.rst
@@ -124,6 +124,49 @@ Also, settings ``MEDIA_ROOT`` and ``MEDIA_URL`` will need to be added to your ``
be up to date, so please take the development version from the
github repository
+Custom section in the user profile
+==================================
+Sometimes you might want to add a completely custom section
+to the user profile, available via an additional tab.
+
+This is possible by editing the ``settings.py`` file,
+which means that to use this feature you must have sufficient
+access to the webserver file system.
+
+Add a following setting to your ``settings.py``::
+
+ ASKBOT_CUSTOM_USER_PROFILE_TAB = {
+ 'NAME': 'some name',
+ 'SLUG': 'some-name',
+ 'CONTENT_GENERATOR': 'myapp.views.somefunc'
+ }
+
+The value of ``ASKBOT_CUSTOM_USER_PROFILE_TAB['CONTENT_GENERATOR']``
+should be a path to the function that returns the widget content
+as string.
+
+Here is a simple example of the content generator
+implemented as part of the fictional application called ``myapp``::
+
+ from myapp.models import Thing#definition not shown here
+ from django.template.loader import get_template
+ from django.template import Context
+
+ def somefunc(request, profile_owner):
+ """loads things for the ``profile_owner``
+ and returns output rendered as html string
+ """
+ template = get_template('mytemplate.html')
+ things = Thing.objects.filter(user = profile_owner)
+ return template.render(Context({'things': things}))
+
+The function is very similar to the regular
+Django view, but returns a string instead of the ``HttpResponse``
+instance.
+
+Also, the method must accept one additional argument -
+an instance of the ``django.contrib.auth.models.User`` object.
+
Wordpress Integration
=====================
diff --git a/askbot/skins/default/templates/user_profile/custom_tab.html b/askbot/skins/default/templates/user_profile/custom_tab.html
new file mode 100644
index 00000000..bc5647f7
--- /dev/null
+++ b/askbot/skins/default/templates/user_profile/custom_tab.html
@@ -0,0 +1,3 @@
+{% extends "user_profile/user.html" %}
+{% block profilesection %}{{ custom_tab_name }}{% endblock %}
+{% block usercontent %}{{ custom_tab_content|safe }}{% endblock %}
diff --git a/askbot/skins/default/templates/user_profile/user.html b/askbot/skins/default/templates/user_profile/user.html
index 15e0622a..dfe9b787 100644
--- a/askbot/skins/default/templates/user_profile/user.html
+++ b/askbot/skins/default/templates/user_profile/user.html
@@ -1,7 +1,7 @@
{% extends "one_column_body.html" %}
<!-- user.html -->
{% block title %}{% spaceless %}{{ page_title }}{% endspaceless %}{% endblock %}
-{% block forestyle%}
+{% block forestyle %}
<style type="text/css">
.history-table td { padding: 5px; }
</style>
diff --git a/askbot/skins/default/templates/user_profile/user_tabs.html b/askbot/skins/default/templates/user_profile/user_tabs.html
index b8c56479..c7df4187 100644
--- a/askbot/skins/default/templates/user_profile/user_tabs.html
+++ b/askbot/skins/default/templates/user_profile/user_tabs.html
@@ -49,6 +49,11 @@
href="{% url user_profile view_user.id, view_user.username|slugify %}?sort=moderation"
><span>{% trans %}moderation{% endtrans %}</span></a>
{% endif %}
+ {% if custom_tab_slug %}
+ <a id="{{ custom_tab_slug }}" {% if tab_name == custom_tab_slug %}class="on"{% endif %}
+ href="{% url user_profile view_user.id, view_user.username|slugify %}?sort={{ custom_tab_slug }}"
+ ><span>{{ custom_tab_name }}</span></a>
+ {% endif %}
</div>
</div>
<div class="clean"></div>
diff --git a/askbot/startup_procedures.py b/askbot/startup_procedures.py
index a5b0c940..0fec6d5f 100644
--- a/askbot/startup_procedures.py
+++ b/askbot/startup_procedures.py
@@ -10,6 +10,7 @@ the main function is run_startup_tests
import sys
import os
import re
+import urllib
import askbot
import south
from django.db import transaction, connection
@@ -481,6 +482,36 @@ def test_avatar():
short_message = True
)
+def test_custom_user_profile_tab():
+ setting_name = 'ASKBOT_CUSTOM_USER_PROFILE_TAB'
+ tab_settings = getattr(django_settings, setting_name, None)
+ if tab_settings:
+ if not isinstance(tab_settings, dict):
+ print "Setting %s must be a dictionary!!!" % setting_name
+
+ name = tab_settings.get('NAME', None)
+ slug = tab_settings.get('SLUG', None)
+ func_name = tab_settings.get('CONTENT_GENERATOR', None)
+
+ errors = list()
+ if (name is None) or (not(isinstance(name, basestring))):
+ errors.append("%s['NAME'] must be a string" % setting_name)
+ if (slug is None) or (not(isinstance(slug, str))):
+ errors.append("%s['SLUG'] must be an ASCII string" % setting_name)
+
+ if urllib.quote_plus(slug) != slug:
+ errors.append(
+ "%s['SLUG'] must be url safe, make it simple" % setting_name
+ )
+
+ try:
+ func = load_module(func_name)
+ except ImportError:
+ errors.append("%s['CONTENT_GENERATOR'] must be a dotted path to a function" % setting_name)
+ header = 'Custom user profile tab is configured incorrectly in your settings.py file'
+ footer = 'Please carefully read about adding a custom user profile tab.'
+ print_errors(errors, header = header, footer = footer)
+
def run_startup_tests():
"""function that runs
all startup tests, mainly checking settings config so far
@@ -532,6 +563,7 @@ def run_startup_tests():
test_media_url()
if 'manage.py test' in ' '.join(sys.argv):
test_settings_for_test_runner()
+ test_custom_user_profile_tab()
@transaction.commit_manually
def run():
diff --git a/askbot/views/users.py b/askbot/views/users.py
index c17ddd43..0997f21e 100644
--- a/askbot/views/users.py
+++ b/askbot/views/users.py
@@ -41,6 +41,7 @@ from askbot.skins.loaders import render_into_skin
from askbot.templatetags import extra_tags
from askbot.search.state_manager import SearchState
from askbot.utils import url_utils
+from askbot.utils.loading import load_module
def owner_or_moderator_required(f):
@functools.wraps(f)
@@ -840,6 +841,24 @@ def user_email_subscriptions(request, user, context):
request
)
+@csrf.csrf_protect
+def user_custom_tab(request, user, context):
+ """works only if `ASKBOT_CUSTOM_USER_PROFILE_TAB`
+ setting in the ``settings.py`` is properly configured"""
+ tab_settings = django_settings.ASKBOT_CUSTOM_USER_PROFILE_TAB
+ module_path = tab_settings['CONTENT_GENERATOR']
+ content_generator = load_module(module_path)
+
+ page_title = _('profile - %(section)s') % \
+ {'section': tab_settings['NAME']}
+
+ context.update({
+ 'custom_tab_content': content_generator(request, user),
+ 'tab_name': tab_settings['SLUG'],
+ 'page_title': page_title
+ })
+ return render_into_skin('user_profile/custom_tab.html', context, request)
+
USER_VIEW_CALL_TABLE = {
'stats': user_stats,
'recent': user_recent,
@@ -851,6 +870,12 @@ USER_VIEW_CALL_TABLE = {
'email_subscriptions': user_email_subscriptions,
'moderation': user_moderate,
}
+
+CUSTOM_TAB = getattr(django_settings, 'ASKBOT_CUSTOM_USER_PROFILE_TAB', None)
+if CUSTOM_TAB:
+ CUSTOM_SLUG = CUSTOM_TAB['SLUG']
+ USER_VIEW_CALL_TABLE[CUSTOM_SLUG] = user_custom_tab
+
#todo: rename this function - variable named user is everywhere
def user(request, id, slug=None, tab_name=None):
"""Main user view function that works as a switchboard
@@ -897,6 +922,9 @@ def user(request, id, slug=None, tab_name=None):
'search_state': search_state,
'user_follow_feature_on': ('followit' in django_settings.INSTALLED_APPS),
}
+ if CUSTOM_TAB:
+ context['custom_tab_name'] = CUSTOM_TAB['NAME']
+ context['custom_tab_slug'] = CUSTOM_TAB['SLUG']
return user_view_func(request, profile_owner, context)
@csrf.csrf_exempt