From 098b8335dcdbe236d9d82e65126b6010f5ece3aa Mon Sep 17 00:00:00 2001 From: Evgeny Fadeev Date: Sun, 27 May 2012 18:50:47 -0400 Subject: a possibility to add a custom user profile tab --- askbot/doc/source/changelog.rst | 4 +- askbot/doc/source/optional-modules.rst | 43 ++++++++++++++++++++++ .../default/templates/user_profile/custom_tab.html | 3 ++ .../skins/default/templates/user_profile/user.html | 2 +- .../default/templates/user_profile/user_tabs.html | 5 +++ askbot/startup_procedures.py | 32 ++++++++++++++++ askbot/views/users.py | 28 ++++++++++++++ 7 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 askbot/skins/default/templates/user_profile/custom_tab.html 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" %} {% block title %}{% spaceless %}{{ page_title }}{% endspaceless %}{% endblock %} -{% block forestyle%} +{% block forestyle %} 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" >{% trans %}moderation{% endtrans %} {% endif %} + {% if custom_tab_slug %} + {{ custom_tab_name }} + {% endif %}
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 -- cgit v1.2.3-1-g7c22