Show
Ignore:
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • lib/sct/AUTHORS

    r41 r147  
    2525 
    2626 
     27Daniele Varrazzo - for providing various patches especially for the 
     28blog. 
     29 
     30 
    2731Eric Simorre <eric.simorre@c-s.fr> - contributed french 
    2832translations for all apps and communitydraft. 
     
    4347 
    4448 
     49Walter Woods <woodswalben@gmail.com> - contributing patch for the forum and testing many posting/permission related problems. 
     50 
     51 
    4552Young Gyu Park <ygpark2@gmail.com> - for contributing korean  
    4653translations for all applications. 
  • lib/sct/dist/scripts/compile-all-sph-messages.py

    r40 r81  
    55## SCT apps. 
    66 
    7 #from django.bin.compile-messages import compile_messages 
    8 c = __import__('django.bin.compile-messages', None, None, 'compile_messages') 
     7from django.core.management.commands.compilemessages import compile_messages 
    98 
    109import os 
     
    2423for app in sphapps: 
    2524    os.chdir( os.path.join(ROOT_PATH, 'sphenecoll', 'sphene', app ) ) 
    26     c.compile_messages() 
     25    compile_messages() 
    2726 
    2827os.chdir( olddir ) 
  • lib/sct/sphenecoll/sphene/community/context_processors.py

    r40 r147  
    3131        return { 'navigation_left': Navigation.objects.filter( group = group, 
    3232                                                               navigationType = 0 ), 
     33                 'navigation_top': Navigation.objects.filter( group = group, 
     34                                                               navigationType = 1 ), 
    3335                 'urlPrefix': urlPrefix, 
    3436                 'group': group, 
  • lib/sct/sphenecoll/sphene/community/middleware.py

    r41 r169  
    11from django.conf import settings 
    22from django.conf.urls.defaults import * 
     3from django.core import urlresolvers 
     4 
    35from django.http import Http404 
    46from django.shortcuts import get_object_or_404 
    5 from sphene.community.models import Group 
    6 from django.core import urlresolvers 
     7 
     8from django.contrib.sites.models import SiteManager, Site 
     9 
     10 
     11from sphene.community.models import Group, get_group 
     12from sphene.community.sphsettings import get_sph_setting 
     13 
     14 
    715import re 
    8  
    9 from django.contrib.sites.models import SiteManager, Site 
     16import logging 
     17 
     18 
     19logger = logging.getLogger('sphene.community.middleware') 
    1020 
    1121def my_get_current(self): 
     
    2232 
    2333# If all are used the following order has to remain: 
    24 # 1.) ThreadLocals 
    25 # 2.) MultiHostMiddleware 
    26 # 3.) GroupMiddleware 
     34# 1.) ThreadLocals (required) 
     35# 2.) MultiHostMiddleware (optional, but very much recommended!) 
     36# 3.) GroupMiddleware (required) 
    2737# all other orders will lead to problems .. 
     38 
     39 
     40# 
     41# Short descriptions: 
     42#  every module within SCT requires a Group object - this can either come from the 
     43#  MultiHostMiddleware - ie. from the domain/host name (vhosts) or from an URL parameter. 
     44#  we need to somehow distuingish between those two within the reverse URL lookups. 
     45# 
    2846 
    2947class MultiHostMiddleware: 
    3048    def process_request(self, request): 
    3149        try: 
     50            sphdata = get_current_sphdata() 
    3251            host = request.META['HTTP_HOST'] 
    3352            if host[-3:] == ':80': 
     
    5271                    break 
    5372            if not urlconf: 
    54                 print "Unable to find urlconf for %s / map: %s !!!" % (host, str(settings.SPH_HOST_MIDDLEWARE_URLCONF_MAP)) 
     73                logging.info("Unable to find urlconf for %s / map: %s !!!" % (host, str(settings.SPH_HOST_MIDDLEWARE_URLCONF_MAP))) 
    5574                return 
    5675            while 'alias' in urlconf: 
     
    6382            if myparams and 'groupName' in myparams: 
    6483                try: 
    65                     set_current_group( Group.objects.get( name__exact = myparams['groupName'] ) ) 
     84                    set_current_group( get_group( myparams['groupName'] ) ) 
     85                    sphdata['group_fromhost'] = True 
    6686                except Group.DoesNotExist: 
    6787                    pass 
     
    97117                groupName = view_kwargs['groupName'] 
    98118                if groupName == None: groupName = get_current_urlconf_params()['groupName'] 
     119                sphdata = get_current_sphdata() 
    99120                if group == None: 
    100121                    group = get_object_or_404(Group, name = groupName ) 
     122                    sphdata['group_fromhost'] = not get_sph_setting('community_groups_in_url') 
    101123                del view_kwargs['groupName'] 
    102124                view_kwargs['group'] = group 
     
    135157 
    136158def get_current_group(): 
    137     return getattr(_thread_locals, 'group', None) 
     159    try: 
     160        return _thread_locals.group 
     161    except AttributeError, e: 
     162        logger.error('Unable to retrieve group. Is GroupMiddleware enabled?') 
     163        raise e 
    138164 
    139165def get_current_urlconf_params(): 
  • lib/sct/sphenecoll/sphene/community/models.py

    r41 r169  
    11from django.db import models 
     2from django.db.models import signals 
     3from django.core.cache import cache 
    24from django.contrib import admin 
    35from django.contrib.auth.models import User 
    46from django.contrib.contenttypes.models import ContentType 
    57from django.contrib.contenttypes import generic 
    6 from sphene.community.sphpermalink import sphpermalink as permalink, get_urlconf 
     8from sphene.community.sphpermalink import sphpermalink 
    79from django.utils.translation import ugettext as _, ugettext_lazy 
    810from django.db import connection 
     
    4951        return self.name; 
    5052 
    51  
    52  
     53def get_group(name): 
     54    """Return a `Group` by name. 
     55 
     56    Cache the group and return the cached version if available. 
     57    Raise `Group.DoesNotExist` if not found. 
     58    """ 
     59    group = cache.get(_get_group_cache_key(name)) 
     60    if group is not None: 
     61        return group 
     62 
     63    # raise if not found 
     64    group = Group.objects.get( name__exact = name ) 
     65    cache.add(_get_group_cache_key(name), group) 
     66 
     67    return group 
     68 
     69def invalidate_group_cache(sender, instance, **kwargs): 
     70    """Signal handler to remove a `Group` from the cache.""" 
     71    if instance.name: 
     72        cache.delete(_get_group_cache_key(instance.name)) 
     73 
     74signals.pre_save.connect( 
     75    invalidate_group_cache, 
     76    sender=Group) 
     77 
     78def _get_group_cache_key(name): 
     79    return "__group__" + name 
     80     
    5381USERLEVEL_CHOICES = ( 
    5482    (0, ugettext_lazy('Normal User')), 
     
    222250    def get_absolute_editurl(self): 
    223251        return ('sphene.community.views.admin_permission_role_edit', (), { 'groupName': self.group.name, 'role_id': self.id, } ) 
    224     get_absolute_editurl = permalink(get_absolute_editurl, get_urlconf
     252    get_absolute_editurl = sphpermalink(get_absolute_editurl
    225253 
    226254    def get_absolute_memberlisturl(self): 
    227255        return ('sphene.community.views.admin_permission_role_member_list', (), { 'groupName': self.group.name, 'role_id': self.id, } ) 
    228     get_absolute_memberlisturl = permalink(get_absolute_memberlisturl, get_urlconf
     256    get_absolute_memberlisturl = sphpermalink(get_absolute_memberlisturl
    229257 
    230258    def get_absolute_memberaddurl(self): 
    231259        return ('sphene.community.views.admin_permission_role_member_add', (), { 'groupName': self.group.name, 'role_id': self.id, } ) 
    232     get_absolute_memberaddurl = permalink(get_absolute_memberaddurl, get_urlconf
     260    get_absolute_memberaddurl = sphpermalink(get_absolute_memberaddurl
    233261 
    234262    def get_absolute_groupmemberaddurl(self): 
    235263        return ('sphene.community.views.admin_permission_role_groupmember_add', (), { 'groupName': self.group.name, 'role_id': self.id, } ) 
    236     get_absolute_groupmemberaddurl = permalink(get_absolute_groupmemberaddurl, get_urlconf
     264    get_absolute_groupmemberaddurl = sphpermalink(get_absolute_groupmemberaddurl
    237265 
    238266    class Meta: 
     
    302330    def get_absolute_editurl(self): 
    303331        return ('sphene.community.views.admin_permission_rolegroup_edit', (), { 'groupName': self.group.name, 'rolegroup_id': self.id, } ) 
    304     get_absolute_editurl = permalink(get_absolute_editurl, get_urlconf
     332    get_absolute_editurl = sphpermalink(get_absolute_editurl
    305333 
    306334    class Meta: 
  • lib/sct/sphenecoll/sphene/community/sphpermalink.py

    r40 r147  
    1 from django.core.urlresolvers import reverse 
    21 
    32 
     
    54# Decorator. Takes a function that returns a tuple in this format: 
    65#     (viewname, viewargs, viewkwargs) 
    7 #   Optionally takes a function which should either return an object with 
    8 #     an attribute 'urlconf' or directly a python list which is used instead of 
    9 #     settings.ROOT_URLCONF 
    106# Returns a function that calls urlresolvers.reverse() on that data, to return 
    117# the URL for those parameters. 
    12 def sphpermalink(func, get_urlconf_func = None): 
    13     from django.core.urlresolvers import reverse 
     8def sphpermalink(func): 
    149    def inner(*args, **kwargs): 
     10        from sphene.community.sphutils import sph_reverse 
    1511        # Find urlconf ... 
    16         urlconf = None 
    17         if get_urlconf_func != None: 
    18             urlconf = get_urlconf_func() 
    19             if hasattr(urlconf, 'urlconf'): 
    20                 # If type is no list, we assume it is a request object and 
    21                 # look for a 'urlconf' attribute 
    22                 urlconf = getattr(urlconf, 'urlconf', None) 
    23          
    2412        bits = func(*args, **kwargs) 
    25         viewname = bits[0] 
    26         # OMG that is an ugly hack !! 
    27         if 'groupName' in bits[2]: 
    28             del bits[2]['groupName'] 
     13        viewname, args, kwargs = bits 
    2914 
    30         if not hasattr( urlconf, '__iter__' ) \ 
    31                 and not isinstance( urlconf, str ): 
    32             # If urlconf is not a list / tuple set it to None. 
    33             urlconf = None 
    34  
    35         return reverse(bits[0], urlconf, *bits[1:3]) 
     15        return sph_reverse(viewname, args=args, kwargs=kwargs) 
    3616    return inner 
    3717 
  • lib/sct/sphenecoll/sphene/community/sphsettings.py

    r40 r147  
    2323    # $(dir)/$(groupName)/$(templateName) 
    2424    'community_groupaware_template_dir': None, 
     25 
     26    # If True, the group name is set in the URL 
     27    'community_groups_in_url': False, 
    2528 
    2629    # used by sphene.community.views.groupaware_redirect_to which looks up this variable 
  • lib/sct/sphenecoll/sphene/community/sphutils.py

    r41 r147  
    55from django.core.urlresolvers import reverse 
    66from django.shortcuts import render_to_response 
    7 from sphene.community.middleware import get_current_request, get_current_sphdata 
     7from sphene.community.middleware import get_current_request, get_current_sphdata, get_current_group 
    88from sphene.community.sphpermalink import sphpermalink as imported_sphpermalink 
    99from sphene.community import sphsettings 
     
    198198    req = get_current_request() 
    199199    urlconf = getattr(req, 'urlconf', None) 
     200    sphdata = get_current_sphdata() 
     201    if 'group_fromhost' in sphdata and \ 
     202            not sphdata.get('group_fromhost', False): 
     203        kwargs['groupName'] = get_current_group().name 
     204    elif 'groupName' in kwargs: 
     205        del kwargs['groupName'] 
    200206    return reverse( viewname, urlconf, args, kwargs ) 
    201207 
  • lib/sct/sphenecoll/sphene/community/templates/sphene/community/_display_username.html

    r40 r145  
    33{% if user %} 
    44  <a href="{{ user|sph_user_profile_link }}"> 
    5          {{ user|sph_user_displayname }} 
    6   </a> 
     5    {{ user|sph_user_displayname }} 
     6  </a>{{ suffix }} 
    77{% else %} 
    88        {% trans "Anonymous" %} 
  • lib/sct/sphenecoll/sphene/community/templatetags/sph_extras.py

    r41 r147  
    1919     
    2020import logging 
    21 log = logging.getLogger('sph_extras') 
     21log = logging.getLogger('sphene.community.sph_extras') 
    2222     
    2323register = template.Library() 
     
    240240def sph_user_profile_link(value): 
    241241    """ Returns the URL to the user profile. """ 
    242     req = get_current_request() 
    243     urlconf = getattr(req, 'urlconf', None) 
    244     return reverse('sphene.community.views.profile', urlconf, (), { 'user_id': value.id } ) 
     242    kwargs = { 'user_id': value.id, } 
     243    return sph_reverse('sphene.community.views.profile', kwargs = kwargs ) 
    245244 
    246245 
     
    273272                       for k, v in self.kwargs.items()]) 
    274273 
    275         #if not 'groupName' in kwargs: 
    276         #    kwargs['groupName'] = get_current_group().name 
    277  
    278         req = get_current_request() 
    279         urlconf = getattr(req, 'urlconf', None) 
    280  
    281274        try: 
    282             return reverse(self.view_name, urlconf=urlconf
    283                            args=args, kwargs=kwargs) 
     275            return sph_reverse(self.view_name
     276                               args=args, kwargs=kwargs) 
    284277        except NoReverseMatch: 
    285278            try: 
    286279                project_name = settings.SETTINGS_MODULE.split('.')[0] 
    287                 return reverse(project_name + '.' + self.view_name, 
    288                                urlconf=urlconf, 
    289                                args=args, kwargs=kwargs) 
     280                return sph_reverse(project_name + '.' + self.view_name, 
     281                                   args=args, kwargs=kwargs) 
    290282            except NoReverseMatch: 
    291283                return '' 
     
    302294    urlconf = getattr(req, 'urlconf', None) 
    303295    try: 
    304         return reverse(view, urlconf
     296        return sph_reverse(view
    305297    except: 
     298        log.exception('Unable to reverse sph_url for view %r' % view) 
    306299        return 'NOT FOUND' 
    307300 
  • lib/sct/sphenecoll/sphene/contrib/libs/common/text/bbcode.py

    r40 r112  
    386386 
    387387_EMOTICONS = { 
    388         '0:-)': 'angel.gif', 
    389         'O:-)':'angel.gif', 
    390         ':angel:':'angel.gif', 
    391         ':)':'smile.gif', 
    392         ':(':'sad.gif', 
    393         ':D':'grin.gif', 
    394         ':p':'tongue.gif', 
    395         ';)':'wink.gif', 
    396         ':-)':'smile.gif', 
    397         ':-(': 'sad.gif', 
    398         ':-D': 'grin.gif', 
    399         ':-P': 'tongue.gif', 
    400         ':-p': 'tongue.gif', 
    401         ':-/': 'unsure.gif', 
    402         ':-\\': 'unsure.gif', 
    403         ';-)': 'wink.gif', 
    404         ':-$': 'confused.gif', 
    405         ':-S': 'confused.gif', 
    406         'B-)': 'cool.gif', 
    407         ':lol:': 'lol.gif', 
    408         ':batman:': 'batman.gif', 
    409         ':rolleyes:': 'rolleyes.gif', 
    410         ':icymad:': 'bluemad.gif', 
    411         ':mad:': 'mad.gif', 
    412         ':crying:': 'crying.gif', 
    413         ':eek:': 'eek.gif', 
    414         ':eyebrow:': 'eyebrow.gif', 
    415         ':grim:': 'grim_reaper.gif', 
    416         ':idea:': 'idea.gif', 
    417         ':rotfl:': 'rotfl.gif', 
    418         ':shifty:': 'shifty.gif', 
    419         ':sleep:': 'sleep.gif', 
    420         ':thinking:': 'thinking.gif', 
    421         ':wave:': 'wave.gif', 
    422         ':bow:': 'bow.gif', 
    423         ':sheep:':  'sheep.gif', 
    424         ':santa:':  'santaclaus.gif', 
    425         ':anvil:': 'anvil.gif', 
    426         ':bandit:': 'bandit.gif', 
    427         ':chop:': 'behead.gif', 
    428         ':biggun:': 'biggun.gif', 
    429         ':mouthful:': 'blowingup,gif', 
    430         ':gun:': 'bluekillsred.gif', 
    431         ':box:': 'boxing.gif', 
    432         ':gallows:': 'hanged.gif', 
    433         ':jedi:': 'lightsaber1.gif', 
    434         ':bosh:': 'mallet1.gif', 
    435         ':saw:': 'saw.gif', 
    436         ':stupid:': 'youarestupid.gif', 
     388    # __replace_start__: emoticons_map 
     389    ':)': 'smile.png', 
     390    ';)': 'wink.png', 
     391    ':thinking:': 'thinking.png', 
     392    ':dont-know:': 'dont-know.png', 
     393    ':eyeroll:': 'eyeroll.png', 
     394    ':|': 'neutral.png', 
     395    ':embarrassed:': 'embarrassed.png', 
     396    ':confused:': 'confused.png', 
     397    ':sarcastic:': 'sarcastic.png', 
     398    ':(': 'sad.png', 
     399    ';(': 'crying.png', 
     400    ':angry:': 'angry.png', 
     401    ':O': 'shock.png', 
     402    ':ok:': 'good.png', 
     403    ':ko:': 'bad.png', 
     404    ':fingers-crossed:': 'fingers-crossed.png', 
     405    ':foot-in-mouth:': 'foot-in-mouth.png', 
     406    ':glasses-cool:': 'glasses-cool.png', 
     407    '8)': 'glasses-nerdy.png', 
     408    ':batti5:': 'highfive.png', 
     409    ':hug-left:': 'hug-left.png', 
     410    ':hug-right:': 'hug-right.png', 
     411    ':*': 'kiss.png', 
     412    ':D': 'laugh.png', 
     413    ':party:': 'party.png', 
     414    ':question:': 'question.png', 
     415    ':quiet:': 'quiet.png', 
     416    ':segreto:': 'secret.png', 
     417    ':sick:': 'sick.png', 
     418    ':sleepy:': 'sleepy.png', 
     419    ':teeth:': 'teeth.png', 
     420    ':P': 'tongue.png', 
     421    ':vampire:': 'vampire.png', 
     422    ':angel:': 'angel.png', 
     423    ':devil:': 'devil.png', 
     424    ':birrame:': 'beer.png', 
     425    u':caff\xe8:': 'coffee.png', 
     426    ':py:': 'pitoncino.png', 
     427    # __replace_end__: emoticons_map 
    437428} 
    438429 
  • lib/sct/sphenecoll/sphene/contrib/libs/markdown/markdown.py

    r40 r107  
    14891489        for i in range(self.htmlStash.html_counter) : 
    14901490            html = self.htmlStash.rawHtmlBlocks[i] 
    1491             if self.safeMode
     1491            if self.safeMode and html not in (u'<hr />', u'<br />')
    14921492                html = "[HTML_REMOVED]" 
    14931493                 
  • lib/sct/sphenecoll/sphene/sphblockframework/models.py

    r40 r147  
    66 
    77from sphene.community.middleware import get_current_group, get_current_request 
    8 from sphene.community.sphutils import sphpermalink as permalink 
     8from sphene.community.sphutils import sphpermalink 
    99from sphene.community.models import Group 
    1010 
     
    128128    def get_absolute_edit_url(self): 
    129129        return ('sphene.sphblockframework.views.edit_block_config', (), { 'block_config_id': self.id }) 
    130     get_absolute_edit_url = permalink(get_absolute_edit_url, get_current_request
     130    get_absolute_edit_url = sphpermalink(get_absolute_edit_url
    131131 
    132132 
  • lib/sct/sphenecoll/sphene/sphblog/categorytypes.py

    r41 r147  
    33from django.utils.safestring import mark_safe 
    44 
     5 
    56from sphene.community.middleware import get_current_user, get_current_sphdata, get_current_urlconf 
     7from sphene.community.sphutils import sph_reverse 
    68from sphene.community.models import Tag, TagLabel, TaggedItem, tag_set_labels, tag_get_labels 
    79from sphene.community.fields import TagField 
     
    2931            slug = slugify(self.cleaned_data['subject'], model=BlogPostExtension) 
    3032        else: 
    31             slug = slugify(slug, model=BlogPostExtension)  
     33            slug = slugify(slug, model=BlogPostExtension, pk=self.__ext_id)  
    3234        return slug 
    3335 
     
    109111    def get_absolute_url_for_category(self): 
    110112        try: 
    111             blog_url = reverse('sphblog_category_index', urlconf=get_current_urlconf(), args = (), kwargs = { 'category_id': self.category.id }) 
     113            blog_url = sph_reverse('sphblog_category_index', kwargs = { 'category_id': self.category.id }) 
    112114            return blog_url 
    113115        except Exception, e: 
  • lib/sct/sphenecoll/sphene/sphblog/feeds.py

    r41 r136  
    66from sphene.community.middleware import get_current_group 
    77from sphene.sphblog.models import BlogPostExtension 
    8 from sphene.sphblog.views import get_board_categories, get_posts_queryset 
     8from sphene.sphblog.views import get_board_categories, get_blog_posts_queryset 
    99from sphene.sphboard.models import Post 
    1010 
     
    3939        group = get_current_group() 
    4040        categories = obj 
    41         threads = get_posts_queryset(group, categories ) 
     41        threads = get_blog_posts_queryset(group, categories ) 
    4242        return threads 
    4343 
    44  
    4544    def item_pubdate(self, item): 
    46         return item.postdate 
     45        return item.post.postdate 
    4746 
    4847    def item_link(self, item): 
    49         try: 
    50             return item.blogpostextension_set.get().get_absolute_url() 
    51         except BlogPostExtension.DoesNotExist: 
    52             # This should never happen. 
    53             return item.get_absolute_url() 
     48        return item.get_absolute_url() 
    5449 
     50    def item_categories(self, item): 
     51        return item.get_tag_labels() 
     52 
  • lib/sct/sphenecoll/sphene/sphblog/models.py

    r41 r147  
    55 
    66from sphene.community.models import tag_get_labels 
    7 from sphene.community.sphutils import sphpermalink as permalink 
     7from sphene.community.sphutils import sphpermalink 
    88from sphene.community.middleware import get_current_request 
    99 
     
    3939                                                          'slug': self.slug, 
    4040                                                          }) 
    41     get_absolute_url = permalink(get_absolute_url, get_current_request
     41    get_absolute_url = sphpermalink(get_absolute_url
    4242 
    4343 
  • lib/sct/sphenecoll/sphene/sphblog/templates/sphene/sphblog/blogindex.html

    r41 r147  
    5050  {% endif %} 
    5151 
     52  {% if not threads.object_list %} 
     53    <p>{% trans "There are no blog posts yet." %}</p> 
     54  {% endif %} 
    5255 
    5356  {% for thread in threads.object_list %} 
     
    100103 
    101104  <p> 
    102     <a href="{% sph_url2 sphblog-feeds "latestposts" %}">{% trans "RSS Feed" %}</a> 
     105    <a href="{% sph_url2 sphblog-feeds url="latestposts" %}">{% trans "RSS Feed" %}</a> 
    103106  </p> 
    104107 
  • lib/sct/sphenecoll/sphene/sphblog/templates/sphene/sphblog/feeds/latestposts_description.html

    r40 r136  
    1 {{ obj.body_escaped }} 
     1{{ obj.post.body_escaped }} 
  • lib/sct/sphenecoll/sphene/sphblog/templates/sphene/sphblog/feeds/latestposts_title.html

    r40 r137  
    1 {{ obj.subject }} 
     1{{ obj.post.subject|safe }} 
  • lib/sct/sphenecoll/sphene/sphblog/templates/sphene/sphblog/nopost.html

    r41 r147  
    1 {% extends "sphene/sphblog/base.html" %} 
    2  
    3 {% block content %} 
    4     No posts matched the given criteria. 
    5 {% endblock %} 
  • lib/sct/sphenecoll/sphene/sphblog/views.py

    r41 r147  
    88from django.template.context import RequestContext 
    99from django.http import HttpResponse, HttpResponseRedirect, Http404 
    10 from django.core.urlresolvers import reverse 
    1110from django.db.models import Q 
    1211from django.core.paginator import Paginator, InvalidPage, EmptyPage 
     12 
    1313 
    1414from sphene.community.models import Tag, tag_get_models_by_tag 
     
    1818from sphene.sphboard.models import Category, ThreadInformation, Post, get_tags_for_categories 
    1919from sphene.sphblog.models import BlogPostExtension 
    20 from sphene.community.sphutils import get_sph_setting 
     20from sphene.community.sphutils import get_sph_setting, sph_reverse 
    2121 
    2222def get_board_categories(group): 
     
    3232    return blogcategories 
    3333 
     34def get_blog_posts_queryset(group, categories, year=None, month=None): 
     35    """ 
     36    Return a list of blog posts. 
     37    If given, year and month should be integers. 
     38    """ 
     39    threads = BlogPostExtension.objects.filter( post__thread__isnull = True, 
     40                                   post__category__group__id = group.id, 
     41                                   post__category__id__in = map(lambda x: x.id, categories) ).order_by( '-post__postdate' ) 
     42 
     43    return _year_month_filter(threads, year, month) 
     44 
    3445def get_posts_queryset(group, categories, year=None, month=None): 
    3546    """ 
     
    3748    If given, year and month should be integers. 
    3849    """ 
    39     if month is not None and (month > 12 or month < 1): 
    40         return None 
    41  
    4250    threads = Post.objects.filter( thread__isnull = True, 
    4351                                   category__group__id = group.id, 
    4452                                   category__id__in = map(lambda x: x.id, categories) ).order_by( '-postdate' ) 
     53 
     54    return _year_month_filter(threads, year, month) 
     55 
     56def _year_month_filter(threads, year=None, month=None): 
     57    """ 
     58    Filter a queryset containing a 'postdate' field by year/month. 
     59    """ 
     60    if month is not None and not 1 <= month <= 12: 
     61        return None 
    4562 
    4663    if year is not None: 
     
    100117 
    101118    threads = get_posts_queryset(group, category_info[0], year, month) 
    102     if not threads: 
    103         return render_to_response('sphene/sphblog/nopost.html', {}, 
    104                                   context_instance = RequestContext(request)) 
    105119 
    106120    paged_threads = get_paged_objects(threads, page) 
     
    108122    allowpostcategories = filter(Category.has_post_thread_permission, category_info[0]) 
    109123    #blog_feed_url = reverse('sphblog-feeds', urlconf=get_current_urlconf(), args = ('latestposts',), kwargs = { 'groupName': group.name }) 
    110     blog_feed_url = reverse('sphblog-feeds', urlconf=get_current_urlconf(), kwargs = { 'url': 'latestposts' }) 
     124    blog_feed_url = sph_reverse('sphblog-feeds', kwargs = { 'url': 'latestposts' }) 
    111125    add_rss_feed( blog_feed_url, 'Blog RSS Feed' ) 
    112126    all_tags = get_tags_for_categories( category_info[0] ) 
  • lib/sct/sphenecoll/sphene/sphboard/categorytypes.py

    r41 r146  
    22from django.utils.safestring import mark_safe 
    33 
    4 from sphene.sphboard.models import ExtendedCategoryConfig 
    5 from sphene.sphboard.views import PostForm 
     4from sphene.sphboard.models import ExtendedCategoryConfig, PostRecipient 
     5from sphene.sphboard.forms import PostForm, PrivatePostForm 
    66from sphene.sphboard.categorytyperegistry import CategoryType 
    77 
     
    5555         
    5656 
     57class PrivateMessagesCategoryType(CategoryType): 
     58    name = "privatemessages" 
     59 
     60    label = "Private Messages" 
     61 
     62    def is_displayed(self): 
     63        return True 
     64 
     65    def get_show_thread_template(self): 
     66        return 'sphene/sphboard/showPrivateMessages.html' 
     67 
     68    def get_post_form_class(self, replypost, editpost): 
     69        return PrivatePostForm 
     70 
     71    def save_post(self, newpost, data): 
     72        super(PrivateMessagesCategoryType, self).save_post(newpost, data) 
     73 
     74        for user in data['to']: 
     75            rec = PostRecipient(post=newpost, user=user, type='TO') 
     76            rec.save() 
     77 
     78 
    5779class ExtendedCategoryType(CategoryType): 
    5880    name = "extendedconfig" 
  • lib/sct/sphenecoll/sphene/sphboard/forms.py

    r41 r146  
    1717from sphene.sphboard.renderers import describe_render_choices 
    1818from sphene.sphboard.models import POST_MARKUP_CHOICES, PostAttachment 
     19from sphene.sphboard.widgets import UsersField, IconSelect 
    1920from sphene.sphboard import boardforms 
    2021 
     
    5657class PostForm(forms.Form): 
    5758    subject = forms.CharField( label = _(u"Subject" ) ) 
     59    to = UsersField( label = _(u"To" ) ) 
     60    icon = forms.CharField(label=_(u"Post Icon"), widget = IconSelect())  
    5861    body = forms.CharField( label = _(u"Body"), 
    5962                            widget = forms.Textarea( attrs = { 'rows': 10, 'cols': 70 } ), 
     
    6871    def __init__(self, *args, **kwargs): 
    6972        super(PostForm, self).__init__(*args, **kwargs) 
     73        if not self.has_recipients(): 
     74            del self.fields['to'] 
    7075        if not sphutils.has_captcha_support() or get_current_user().is_authenticated(): 
    7176            del self.fields['captcha'] 
    7277        if len( POST_MARKUP_CHOICES ) == 1: 
    7378            del self.fields['markup'] 
     79 
     80    def has_recipients(self): 
     81        return False 
    7482 
    7583    def init_for_category_type(self, category_type, post): 
     
    8290        """ 
    8391        pass 
     92 
     93 
     94class PrivatePostForm(PostForm): 
     95    def has_recipients(self): 
     96        return True 
    8497 
    8598 
  • lib/sct/sphenecoll/sphene/sphboard/locale/en/LC_MESSAGES/django.po

    r40 r83  
    365365msgstr "" 
    366366 
     367#: templates/sphene/sphboard/listCategories.html:96 
     368msgid "Mark all as read" 
     369msgstr "" 
     370 
    367371#: templates/sphene/sphboard/move.html:10 
    368372#, python-format 
     
    375379msgstr "" 
    376380 
     381#: templates/sphene/sphboard/new_post_email.txt:3 
     382#, python-format 
     383msgid "" 
     384"\n" 
     385"%(full_name)s just posted in a thread or forum you are monitoring:\n" 
     386"\n" 
     387"visit http://%(baseurl)s%(abs_url)s to view the post.\n" 
     388msgstr "" 
     389 
    377390#: templates/sphene/sphboard/post.html:14 
    378391msgid "Editing post" 
     
    434447#: templates/sphene/sphboard/showThread.html:106 
    435448msgid "Attachments" 
     449msgstr "" 
     450 
     451#: templates/sphene/sphboard/showThread.html:141 
     452msgid "Edit this poll" 
    436453msgstr "" 
    437454 
  • lib/sct/sphenecoll/sphene/sphboard/models.py

    r41 r147  
    1616import sphene.community.signals 
    1717from sphene.community.middleware import get_current_request, get_current_user, get_current_group, get_current_session 
    18 from sphene.community.sphutils import sphpermalink as permalink, get_urlconf, get_sph_setting, get_method_by_name 
     18from sphene.community.sphutils import sphpermalink, get_urlconf, get_sph_setting, get_method_by_name 
    1919from sphene.community.signals import profile_edit_init_form, profile_edit_save_form, profile_display 
    2020from sphene.community.permissionutils import has_permission_flag 
     
    254254        return self.allowthreads != 3 
    255255 
     256    def is_private(self): 
     257        return self.category_type == 'privatemessages' 
     258     
     259    @property 
     260    def posts(self): 
     261        posts = self._posts 
     262        if self.is_private(): 
     263            user = get_current_user() 
     264            recps = PostRecipient.objects.filter(user=user).values('post').query 
     265            posts = posts.filter(Q(id__in=recps) | Q(author=user)) 
     266          
     267        return posts 
     268 
    256269    def get_thread_list(self): 
    257270        #return self.posts.filter( thread__isnull = True ) 
     
    259272            # See http://code.djangoproject.com/ticket/4789 
    260273            return self.threadinformation_set 
    261         return self.threadinformation_set.filter(root_post__is_hidden = 0).select_related( depth = 1 ) 
     274        qs = self.threadinformation_set.filter(root_post__is_hidden = 0).select_related( depth = 1 ) 
     275 
     276        if self.is_private(): 
     277            user = get_current_user() 
     278            recps = PostRecipient.objects.filter(user=user).values('post').query 
     279            qs = qs.filter(Q(latest_post__id__in=recps) | Q(root_post__author=user)) 
     280            print qs.query 
     281 
     282        return qs 
    262283 
    263284    def threadCount(self): 
     
    450471            name = 'sphboard_show_category_without_slug' 
    451472        return (name, (), kwargs) 
    452     _get_absolute_url = permalink(_get_absolute_url, get_current_request
     473    _get_absolute_url = sphpermalink(_get_absolute_url
    453474 
    454475    def get_absolute_post_thread_url(self): 
    455476        return ('sphboard_post_thread', (), { 'groupName': self.group.name, 'category_id': self.id }) 
    456     get_absolute_post_thread_url = permalink(get_absolute_post_thread_url, get_current_request
     477    get_absolute_post_thread_url = sphpermalink(get_absolute_post_thread_url
    457478 
    458479    def get_absolute_url_rss_latest_threads(self): 
     
    465486    def get_absolute_latest_url(self): 
    466487        return ('sphboard_latest', (), { 'groupName': self.group.name, 'category_id': self.id, }) 
    467     get_absolute_latest_url = permalink(get_absolute_latest_url, get_current_request
     488    get_absolute_latest_url = sphpermalink(get_absolute_latest_url
    468489 
    469490    def get_absolute_togglemonitor_url(self): 
    470491        return ('sphene.sphboard.views.toggle_monitor', (), { 'groupName': self.group.name, 'monitortype': 'category', 'object_id': self.id, }) 
    471     get_absolute_togglemonitor_url = permalink(get_absolute_togglemonitor_url, get_current_request
     492    get_absolute_togglemonitor_url = sphpermalink(get_absolute_togglemonitor_url
    472493     
    473494    def __unicode__(self): 
     
    544565    """ 
    545566    status = models.IntegerField(default = 0, editable = False ) 
    546     category = models.ForeignKey(Category, related_name = 'posts', editable = False ) 
     567    category = models.ForeignKey(Category, related_name = '_posts', editable = False ) 
    547568    subject = models.CharField(max_length = 250) 
     569    icon = models.CharField(max_length=24, default='standard') 
    548570    body = models.TextField() 
    549571    thread = models.ForeignKey('self', null = True, editable = False ) 
    550572    postdate = models.DateTimeField( auto_now_add = True, editable = False ) 
    551573    author = models.ForeignKey(User, editable = False, null = True, blank = True, related_name = 'sphboard_post_author_set' ) 
     574    author_ip = models.CharField(max_length = 39, null = True, blank = True) 
    552575    markup = models.CharField(max_length = 250, 
    553576                              null = True, 
     
    570593                  ( '2008-01-06 01', 'update', 'SET is_hidden = 0', ), 
    571594                  ( '2008-01-06 02', 'alter', 'ALTER is_hidden SET NOT NULL', ), 
     595                  ( '2009-07-30 00', 'alter', 'ADD author_ip varchar(39) NULL', ), 
    572596                  ) 
    573597 
     
    686710 
    687711    def _allow_adminfunctionality(self, flag, user = None): 
     712        if self.is_private(): 
     713            return False 
     714 
    688715        if user == None: 
    689716            user = get_current_user() 
     
    711738        return self._allow_adminfunctionality( 'sphboard_sticky', user ) 
    712739 
     740    def has_view_permission(self, user = None): 
     741        if not user: 
     742            user = get_current_user() 
     743 
     744        if self.is_private(): 
     745            if self.author_id == user.id: 
     746                return True 
     747 
     748            for rec in self.recipient_set.all(): 
     749                if rec.user_id == user.id: 
     750                    return True 
     751 
     752            return False 
     753 
     754        else: 
     755            return self.category.has_view_permission(user) 
     756 
     757    def is_private(self): 
     758        return self.category.is_private() 
     759     
    713760    def __get_render_cachekey(self): 
    714761        return 'sphboard_rendered_body_%s' % str(self.id) 
     
    882929                    #monitors = Monitor.objects.filter(myQ) 
    883930                     
    884                 subject = 'New Forum Post in "%s": %s' % (self.category.name, self.subject,) 
     931                subject = '%sNew Forum Post in "%s": %s' % (settings.EMAIL_SUBJECT_PREFIX, self.category.name, self.subject,) 
    885932                group = get_current_group() or self.category.group 
    886933                t = loader.get_template('sphene/sphboard/new_post_email.txt') 
     
    9551002            name = 'sphboard_show_thread_without_slug' 
    9561003        return (name, (), kwargs) 
    957     _get_absolute_url = permalink(_get_absolute_url, get_current_request
     1004    _get_absolute_url = sphpermalink(_get_absolute_url
    9581005     
    9591006    def get_absolute_editurl(self): 
    9601007        return ('sphene.sphboard.views.post', (), { 'groupName': self.category.group.name, 'category_id': self.category.id, 'post_id': self.id }) 
    961     get_absolute_editurl = permalink(get_absolute_editurl, get_current_request
     1008    get_absolute_editurl = sphpermalink(get_absolute_editurl
    9621009 
    9631010    def get_absolute_postreplyurl(self): 
    9641011        return ('sphene.sphboard.views.reply', (), { 'groupName': self.category.group.name, 'category_id': self.category.id, 'thread_id': self.get_thread().id }) 
    965     get_absolute_postreplyurl = permalink(get_absolute_postreplyurl, get_current_request
     1012    get_absolute_postreplyurl = sphpermalink(get_absolute_postreplyurl
    9661013 
    9671014    def get_absolute_annotate_url(self): 
    9681015        return ('sphene.sphboard.views.annotate', (), { 'groupName': self.category.group.name, 'post_id': self.id }) 
    969     get_absolute_annotate_url = permalink(get_absolute_annotate_url, get_current_request
     1016    get_absolute_annotate_url = sphpermalink(get_absolute_annotate_url
    9701017 
    9711018 
     
    11311178        return self.root_post.subject 
    11321179 
     1180    @property # to make thread and post interfaces uniform 
     1181    def icon(self): 
     1182        return self.root_post.icon 
     1183 
    11331184    def is_poll(self): 
    11341185        return self.root_post.is_poll() 
     
    11691220                kwargs['slug'] = slug 
    11701221        return (name, (), kwargs) 
    1171     _get_absolute_url = permalink(_get_absolute_url, get_current_request
     1222    _get_absolute_url = sphpermalink(_get_absolute_url
    11721223 
    11731224    def __unicode__(self): 
     
    12921343    def get_absolute_editurl(self): 
    12931344        return ('sphboard_edit_poll', (), { 'poll_id': self.id, }) 
    1294     get_absolute_editurl = permalink(get_absolute_editurl, get_current_request
     1345    get_absolute_editurl = sphpermalink(get_absolute_editurl
    12951346 
    12961347 
     
    14821533profile_edit_save_form.connect(board_profile_edit_save_form, sender = EditProfileForm) 
    14831534profile_display.connect(board_profile_display) 
     1535 
     1536 
     1537class PostRecipient(models.Model): 
     1538    """ 
     1539    The recipient of a private post. 
     1540    """ 
     1541    RECIPIENT_TYPE_CHOICES = ( 
     1542        (u'TO', _("To")), 
     1543        (u'CC', _("Cc")), 
     1544        (u'BCC', _("Bcc")), ) 
     1545    user = models.ForeignKey( User ) 
     1546    post = models.ForeignKey( Post, related_name = 'recipient_set' ) 
     1547    type = models.CharField( max_length = 4, choices = RECIPIENT_TYPE_CHOICES ) 
     1548 
     1549    __labels = dict(RECIPIENT_TYPE_CHOICES) 
     1550 
     1551    def label(self): 
     1552        return self.__labels.get(self.type, self.type)  
  • lib/sct/sphenecoll/sphene/sphboard/templates/sphene/sphboard/_displayPostForm.html

    r41 r113  
    3535    {% if bbcodewysiwyg %} 
    3636    <script type="text/javascript"> 
     37      var emoticons_url = "{{ MEDIA_URL }}sphene/emoticons"; 
    3738      var editor_static = "{{ MEDIA_URL }}sphene/sphboard"; 
    3839    </script> 
  • lib/sct/sphenecoll/sphene/sphboard/templates/sphene/sphboard/base.html

    r40 r183  
    55  <link rel="stylesheet" href="{{ MEDIA_URL }}sphene/sphboard/styles/base.css" /> 
    66{% endblock %} 
     7 
     8{# The sidebar content doesn't change in the whole forum #} 
     9{# so don't fetching and rendering the sidebar for every thread #} 
     10{% load cache %} 
     11{% block left_hand_navigation %} 
     12  {% cache 300 lhnav_sphboard_base %} 
     13    {{ block.super }} 
     14        {% endcache %} 
     15{% endblock %} 
     16 
  • lib/sct/sphenecoll/sphene/sphboard/templates/sphene/sphboard/listCategories.html

    r41 r117  
    5252      {% block thread_list_header %} 
    5353      <tr> 
    54         <th class="sphboard_mainhead" colspan="{% if sph_settings.board_count_views %}5{% else %}4{% endif %}">{% trans "Threads" %}</th> 
     54        <th class="sphboard_mainhead" colspan="{% if sph_settings.board_count_views %}6{% else %}5{% endif %}">{% trans "Threads" %}</th> 
    5555      </tr> 
    5656      <tr> 
    57         <th colspan="2">{% trans "Subject / Author" %}</th> 
     57        <th colspan="3">{% trans "Subject / Author" %}</th> 
    5858        {% if sph_settings.board_count_views %} 
    5959          <th>{% trans "Views" %}</th> 
     
    6666        <tr> 
    6767          <td width="20px"><img src="{{ MEDIA_URL }}sphene/sphboard/icons/{% if thread.has_new_posts %}new{% endif %}folder.gif" width='16px' height='16px' title='Heat: {{ thread.heat }}' /></td> 
     68          <td width="20px">{% sphboard_displayPostIcon thread %}</td> 
    6869          {% if thread.is_moved %} 
    6970            <td colspan="4"><small> 
     
    8384      {% endfor %} 
    8485      <tr> 
    85         <td colspan="{% if sph_settings.board_count_views %}5{% else %}4{% endif %}"><span class="board_threadcount">{% blocktrans %}{{ hits }} Threads in this category.{% endblocktrans %}</span><span class="board_pagination">{% sph_pagination pages page %}</span></td> 
     86        <td colspan="{% if sph_settings.board_count_views %}6{% else %}5{% endif %}"><span class="board_threadcount">{% blocktrans %}{{ hits }} Threads in this category.{% endblocktrans %}</span><span class="board_pagination">{% sph_pagination pages page %}</span></td> 
    8687      </tr> 
    8788    </table> 
  • lib/sct/sphenecoll/sphene/sphboard/templates/sphene/sphboard/showThread.html

    r41 r146  
    3636    {% sphboard_displayBreadcrumbsForThread thread %} 
    3737  {% endblock %} 
     38  {% block top_controls %} 
    3839  <br/> 
    3940  {% if perms.post.change_post %} 
     
    7677    <br/><br/> 
    7778  {% endif %} 
     79  {% endblock %} {# top_controls #} 
    7880  {% block above_post_list %} 
    7981    <p>{% sph_pagination pages page %}</p> 
    8082  {% endblock %} 
    8183  <table class="sphboard_post_list"> 
     84    {% if not post_list %} 
     85      <tr><td>{% trans "No message to display." %}</td></tr> 
     86    {% endif %} 
    8287    {% for post in post_list %} 
    8388      {% block post_list_element %} 
     
    8792        </td> 
    8893        <td class="sphboard_post_subject"> 
    89           <div class="board_postdate"><a name="post-{{ post.id }}"></a>{{ post.postdate|date:"Y-m-d H:i:s" }} - <strong>{{ post.subject|escape }}</strong></div> 
     94          {% sphboard_post_header post %} 
    9095          <div class="board_controls"> 
    9196            {% if post.allow_annotating %} 
  • lib/sct/sphenecoll/sphene/sphboard/templatetags/sphboard_extras.py

    r41 r146  
     1from collections import defaultdict 
     2 
    13from django import template 
    24from django import forms 
     5from django.conf import settings 
    36from django.contrib.auth.models import User 
    47from django.core.cache import cache 
     
    7275 
    7376@register.inclusion_tag('sphene/sphboard/_displayUserName.html') 
    74 def sphboard_displayUserName( user ): 
    75     return { 'user': user
     77def sphboard_displayUserName( user, suffix="" ): 
     78    return { 'user': user, 'suffix': suffix
    7679 
    7780@register.inclusion_tag('sphene/sphboard/_displayPostForm.html') 
    7881def sphboard_quick_reply( thread ): 
    7982    return { 'form': PostForm(initial={'subject': u'Re: ' + thread.subject} ), 'form_action': thread.get_absolute_postreplyurl() } 
     83 
     84@register.inclusion_tag('sphene/sphboard/_displayPostIcon.html') 
     85def sphboard_displayPostIcon( post ): 
     86   image_url = "%ssphene/emoticons/%s.png" % (settings.MEDIA_URL, post.icon or "standard") 
     87   return { 'image_url': image_url } 
    8088 
    8189### sphboard_displayPostForm is deprecated, there is a view function for this !! 
     
    147155 
    148156 
     157@register.inclusion_tag('sphene/sphboard/_post_header.html') 
     158def sphboard_post_header(post): 
     159    if post.is_private(): 
     160        recgroups = defaultdict(list) 
     161        for rec in post.recipient_set.all(): 
     162            recgroups[rec.type].append(rec) 
     163        recipients = [] 
     164        for k in ('TO','CC'): 
     165            if k in recgroups: 
     166                recs = recgroups[k] 
     167                recipients.append((recs[0].label(), recs)) 
     168    else: 
     169        recipients = () 
     170 
     171    return {'post': post, 'recipients': recipients } 
     172 
    149173def clear_cache_all_languages(user_id, group_id): 
    150     from django.conf import settings 
    151174    if not hasattr(settings, 'LANGUAGES'): 
    152175        return 
  • lib/sct/sphenecoll/sphene/sphboard/views.py

    r41 r184  
    2020 
    2121 
    22 def showCategory(request, group = None, category_id = None, showType = None, slug = None): 
     22def showCategory(request, group, category_id = None, showType = None, slug = None): 
    2323    """ 
    2424    displays either all root categories, or the contents of a category. 
     
    2828    this function - this is is probably the oldest and ugliest in  
    2929    the whole SCT source. 
     30 
     31    We no longer support having no group !! 
    3032    """ 
    3133    args = { 
     
    4446            raise PermissionDenied() 
    4547        categoryObject.touch(request.session, request.user) 
    46         blog_feed_url = reverse('sphboard-feeds', urlconf=get_current_urlconf(), args = (), kwargs = { 'url': 'latest/2' }) 
     48        blog_feed_url = sph_reverse('sphboard-feeds', kwargs = { 'url': 'latest/%s' % categoryObject.id }) 
    4749        add_rss_feed( blog_feed_url, 'Latest Threads in %s RSS Feed' % categoryObject.name ) 
    4850 
     
    144146def showThread(request, thread_id, group = None, slug = None): 
    145147    thread = get_object_or_404(Post.objects, pk = thread_id ) 
    146     if not thread.category.has_view_permission(request.user): 
     148    if not thread.has_view_permission(request.user): 
    147149        raise PermissionDenied() 
    148150    thread.viewed( request.session, request.user ) 
     
    203205        get_sph_setting('board_wysiwyg') 
    204206 
    205 def post(request, group = None, category_id = None, post_id = None, thread_id = None): 
     207def post(request, group = None, category_id = None, post_id = None, thread_id = None, 
     208        with_monitor=True, with_poll=True): 
     209    """ 
     210    View method to allow users to: 
     211    - create new threads (post_id and thread_id is None) 
     212    - reply to threads (post_id is None) 
     213    - edit posts (post_id is the post which should be edited, thread_id is None) 
     214 
     215    post_id and thread_id can either be passed in by URL (named parameters  
     216    to this method) or by request.REQUEST parameters. 
     217    """ 
    206218    if 'type' in request.REQUEST and request.REQUEST['type'] == 'preview': 
     219         # If user just wants a preview, simply create a dummy post so it can be rendered. 
    207220        previewpost = Post( body = request.REQUEST['body'], 
    208221                            markup = request.REQUEST.get('markup', None), ) 
    209222        return HttpResponse( unicode(previewpost.body_escaped()) ) 
    210223 
    211      
     224 
     225    # All available objects should be loaded from the _id variables. 
    212226    post = None 
    213227    thread = None 
     
    222236        post_id = request.REQUEST['post_id'] 
    223237 
    224     if post_id: 
     238    if post_id is not None: 
     239        # User wants to edit a post .. 
    225240        try: 
    226241            post = Post.allobjects.get( pk = post_id ) 
     
    231246            raise PermissionDenied() 
    232247        thread = post.thread 
    233      
    234     if 'thread' in request.REQUEST: 
    235         thread_id = request.REQUEST['thread'] 
    236  
    237     if thread_id: 
    238         try: 
    239             thread = Post.allobjects.get( pk = thread_id ) 
    240         except Post.DoesNotExist: 
    241             raise Http404 
    242  
    243         category = thread.category 
    244         context['thread'] = thread 
     248        category = post.category 
     249     
     250    else: 
     251        # User wants to create a new post (thread or reply) 
     252        if 'thread' in request.REQUEST: 
     253            thread_id = request.REQUEST['thread'] 
     254 
     255        if thread_id is not None: 
     256            # User is posting (replying) to a thread. 
     257            try: 
     258                thread = Post.allobjects.get( pk = thread_id ) 
     259            except Post.DoesNotExist: 
     260                raise Http404 
     261 
     262            category = thread.category 
    245263         
    246         if not thread.allowPosting( request.user ): 
    247             raise PermissionDenied() 
    248     else: 
    249         category = get_object_or_404(Category, pk = category_id) 
    250         if not category.allowPostThread( request.user ): 
    251             raise PermissionDenied() 
    252  
     264            if not thread.allowPosting( request.user ): 
     265                raise PermissionDenied() 
     266        else: 
     267            # User is creating a new thread. 
     268            category = get_object_or_404(Category, pk = category_id) 
     269            if not category.allowPostThread( request.user ): 
     270                raise PermissionDenied() 
     271 
     272    context['thread'] = thread 
    253273    context['category'] = category 
    254274 
     
    304324                newpost = post 
    305325                newpost.subject = data['subject'] 
     326                newpost.icon = data['icon'] 
    306327                newpost.body = data['body'] 
    307328                # make post visible 
     
    313334                newpost = Post( category = category, 
    314335                                subject = data['subject'], 
     336                                icon = data['icon'], 
    315337                                body = data['body'], 
    316338                                author = user, 
    317                                 thread = thread
     339                                thread = (thread is not None and not thread.is_private()) and thread or None
    318340                                ) 
    319341            if 'markup' in data: 
     
    323345                newpost.markup = POST_MARKUP_CHOICES[0][0] 
    324346                 
     347            newpost.author_ip = request.META.get('REMOTE_ADDR') 
    325348            newpost.save(additional_data = data) 
    326349 
     
    329352 
    330353            # Creating monitor 
    331             if request.POST.get( 'addmonitor', False ): 
     354            if with_monitor and request.POST.get( 'addmonitor', False ): 
    332355                newpost.toggle_monitor() 
    333356 
    334357 
    335             if 'createpoll' in request.POST and request.POST['createpoll'] == '1': 
     358            if with_poll and 'createpoll' in request.POST and request.POST['createpoll'] == '1': 
    336359                newpost.set_poll( True ); 
    337360                newpost.save() 
     
    374397    if post: 
    375398        postForm.fields['subject'].initial = post.subject 
     399        postForm.fields['icon'].initial = post.icon 
    376400        postForm.fields['body'].initial = post.body 
    377401        if 'markup' in postForm.fields: 
     
    379403        context['post'] = post 
    380404        context['thread'] = post.thread or post 
    381     elif 'quote' in request.REQUEST: 
    382         quotepost = Post.objects.get( pk = request.REQUEST['quote'] ) 
    383         postForm.fields['subject'].initial = 'Re: %s' % thread.subject 
    384         if quotepost.author == None: 
    385             username = 'anonymous' 
    386         else: 
    387             username = quotepost.author.username 
    388         postForm.fields['body'].initial = '[quote=%s;%s]\n%s\n[/quote]\n' % (username, quotepost.id, quotepost.body) 
    389405    elif thread: 
    390406        postForm.fields['subject'].initial = 'Re: %s' % thread.subject 
     407        if postForm.has_recipients(): 
     408            postForm.fields['to'].initial = thread.author.username 
     409        if 'quote' in request.REQUEST: 
     410            quotepost = Post.objects.get( pk = request.REQUEST['quote'] ) 
     411            if quotepost.author == None: 
     412                username = 'anonymous' 
     413            else: 
     414                username = quotepost.author.username 
     415            postForm.fields['body'].initial = '[quote=%s;%s]\n%s\n[/quote]\n' % (username, quotepost.id, quotepost.body) 
    391416    context['form'] = postForm 
    392417 
    393418    # Only allow polls if this is a new _thread_ (not a reply) 
    394     if (not thread and not post) or (post and post.is_new() and post.thread is None): 
     419    if with_poll and (not thread and not post) or (post and post.is_new() and post.thread is None): 
    395420        context['pollform'] = pollForm 
    396421    context['attachmentForm'] = attachmentForm 
     
    583608     
    584609 
    585     return HttpResponseRedirect( '../../thread/%s/' % thread.id
     610    return HttpResponseRedirect( thread.get_absolute_url()
    586611 
    587612def toggle_monitor(request, group, monitortype, object_id): 
    588     redirectview = 'show' 
     613    if not request.user.is_authenticated(): 
     614        raise PermissionDenied() 
    589615    obj = None 
    590616    if monitortype == 'group': 
     
    595621    elif monitortype == 'thread': 
    596622        obj = Post.objects.get( pk = object_id ) 
    597         redirectview = 'thread' 
    598623 
    599624    if obj.toggle_monitor(): 
     
    604629    if 'next' in request.GET: 
    605630        return HttpResponseRedirect( request.GET['next'] ) 
    606     return HttpResponseRedirect( '../../%s/%s/' % (redirectview, object_id) ) 
     631    if monitortype == 'group': 
     632        return HttpResponseRedirect( sph_reverse( 'sphboard-index' ) ) 
     633    return HttpResponseRedirect( obj.get_absolute_url() ) 
    607634 
    608635def catchup(request, group, category_id): 
  • lib/sct/sphenecoll/sphene/sphwiki/__init__.py

    r40 r166  
    2121    # This class is added to the <img> tag as well as to the <a> tag. 
    2222    'wiki_macros_default_image_class': None, 
     23 
     24    # The language used in wiki pages. 
     25    # currently supported are: 'markdown', 'restructuredtext'. 
     26    'wiki_markup_language': 'markdown', 
     27 
     28    # Configuration for docutils used in wiki snip rendering 
     29    'wiki_docutils_settings': { 
     30        # Without this, the first title is always promoted to an h1; furthermore 
     31        # the body is split in ``body_pre_docinfo``, ``docinfo`` and ``fragment`` 
     32        # which then should be joined together 
     33        'doctitle_xform': False, 
     34 
     35        'initial_header_level': 2, 
     36 
     37        # Security-related settings 
     38        'file_insertion_enabled': False, 
     39        'raw_enabled': False, 
     40        'cloak_email_addresses': True, 
     41        }, 
    2342    }) 
  • lib/sct/sphenecoll/sphene/sphwiki/models.py

    r41 r179  
    11from django.db import models 
     2from django.core import exceptions 
    23from django.core.urlresolvers import reverse 
    34from django.contrib.auth.models import User 
     
    56from django.utils.safestring import mark_safe 
    67from django.utils.translation import ugettext, ugettext_lazy 
     8from django.core.cache import cache 
     9from django.db.models import signals 
    710 
    811 
    912from sphene.community.templatetags.sph_extras import sph_markdown 
    1013#from django.db.models import permalink 
    11 from sphene.community.sphutils import sphpermalink as permalink, get_sph_setting 
     14from sphene.community.sphutils import sphpermalink, get_sph_setting, sph_reverse 
    1215 
    1316from sphene.community.models import Group 
     
    1922import os 
    2023import re 
    21  
    22 """ 
    23 def permalink(func): 
    24     from django.core.urlresolvers import reverse 
    25     from django.conf import settings 
    26     def inner(*args, **kwargs): 
    27         bits = func(*args, **kwargs) 
    28         viewname = bits[0] 
    29         req = get_current_request() 
    30         urlconf = getattr(req, 'urlconf', settings.ROOT_URLCONF) 
    31         return reverse(bits[0], urlconf, *bits[1:3]) 
    32     return inner 
    33 """ 
    3424 
    3525WIKI_PERMISSIONS_ALLOWED_CHOICES = ( 
     
    5646                  ) 
    5747 
     48    def _get_cache_key(self): 
     49        if self.id is not None: 
     50            return "__wiki_snip__%s" % self.id 
     51        else: 
     52            return None 
     53 
    5854    def render(self): 
     55        # Assume the appearance of the rendered page is the same for all the users 
     56        key = self._get_cache_key() 
     57        if key is not None: 
     58            rv = cache.get(key) 
     59            if rv is not None: return rv 
     60 
     61        lang = get_sph_setting( 'wiki_markup_language' ) 
     62        meth = getattr(self, 'render_%s' % lang, None) 
     63        if meth is not None: 
     64            rv = meth() 
     65            if key is not None: 
     66                cache.set(key, rv) 
     67            return rv 
     68 
     69        raise exceptions.ImproperlyConfigured("unknown markup language: '%s'" % lang) 
     70 
     71    def render_markdown(self): 
    5972        from sphene.sphwiki import wikimacros 
    6073        return mark_safe(sph_markdown(self.body, 
     
    6578                                             })) 
    6679 
     80    def render_restructuredtext(self): 
     81        from docutils_extras import render_wiki_snip 
     82        # returning an empty string creates an infinite recursion downstream 
     83        return render_wiki_snip(self) or '\n' 
     84         
    6785    def get_title(self): 
    6886        return self.title or self.name 
     
    178196    def get_absolute_url(self): 
    179197        return ('sphene.sphwiki.views.showSnip', (), { 'groupName': self.group.name, 'snipName': self.name }) 
    180     get_absolute_url = permalink(get_absolute_url, get_current_request
     198    get_absolute_url = sphpermalink(get_absolute_url
    181199 
    182200    def get_absolute_editurl(self): 
    183201        return ('sphene.sphwiki.views.editSnip', (), { 'groupName': self.group.name, 'snipName': self.name }) 
    184     get_absolute_editurl = permalink(get_absolute_editurl, get_current_request
     202    get_absolute_editurl = sphpermalink(get_absolute_editurl
    185203 
    186204    def get_absolute_attachmenturl(self): 
    187205        return ('sphene.sphwiki.views.attachment', (), { 'groupName': self.group.name, 'snipName': self.name }) 
    188     get_absolute_attachmenturl = permalink(get_absolute_attachmenturl, get_current_request
     206    get_absolute_attachmenturl = sphpermalink(get_absolute_attachmenturl
    189207 
    190208    def get_absolute_create_attachmenturl(self): 
    191209        return ('sphene.sphwiki.views.attachmentCreate', (), { 'groupName': self.group.name, 'snipName': self.name }) 
    192     get_absolute_create_attachmenturl = permalink(get_absolute_create_attachmenturl, get_current_request
     210    get_absolute_create_attachmenturl = sphpermalink(get_absolute_create_attachmenturl
    193211 
    194212    def get_absolute_historyurl(self): 
    195213        return ('sphene.sphwiki.views.history', (), { 'groupName': self.group.name, 'snipName': self.name}) 
    196     get_absolute_historyurl = permalink(get_absolute_historyurl, get_current_request
     214    get_absolute_historyurl = sphpermalink(get_absolute_historyurl
    197215 
    198216    def get_absolute_recentchangesurl(self): 
    199217        return ('sphene.sphwiki.views.recentChanges', (), { 'groupName': self.group.name }) 
    200     get_absolute_recentchangesurl = permalink(get_absolute_recentchangesurl, get_current_request
     218    get_absolute_recentchangesurl = sphpermalink(get_absolute_recentchangesurl
    201219 
    202220    def get_absolute_pdfurl(self): 
    203221        return ('sphene.sphwiki.views.generatePDF', (), { 'groupName': self.group.name, 'snipName': self.name }) 
    204     get_absolute_pdfurl = permalink(get_absolute_pdfurl, get_current_request
     222    get_absolute_pdfurl = sphpermalink(get_absolute_pdfurl
    205223 
    206224    def get_parent(self): 
     
    302320 
    303321 
     322# Invalidate the cache when a snip is altered 
     323def clear_cache_wiki_snip(sender, instance, **kwargs): 
     324    key = instance._get_cache_key() 
     325    if key is not None: 
     326        cache.delete(key) 
     327 
     328signals.post_save.connect(clear_cache_wiki_snip, sender=WikiSnip) 
     329 
     330 
    304331class WikiSnipChange(models.Model): 
    305332    snip = models.ForeignKey(WikiSnip) 
     
    338365    def get_absolute_url(self): 
    339366        return ('sphene.sphwiki.views.diff', (), { 'groupName': self.snip.group.name, 'snipName': self.snip.name, 'changeId': self.id}) 
    340     get_absolute_url = permalink(get_absolute_url, get_current_request
     367    get_absolute_url = sphpermalink(get_absolute_url
    341368 
    342369    def get_absolute_editurl(self): 
    343         return reverse( 'sphwiki_editversion',  
    344                         urlconf = getattr( get_current_request(), 'urlconf', None ),  
    345                         kwargs = { 'snipName': self.snip.name, 
    346                                    'versionId': self.id } ); 
     370        return sph_reverse( 'sphwiki_editversion',  
     371                            kwargs = { 'snipName': self.snip.name, 
     372                                       'versionId': self.id } ); 
    347373 
    348374 
     
    364390    def get_absolute_editurl(self): 
    365391        return ('sphene.sphwiki.views.attachmentEdit', (), { 'groupName': self.snip.group.name, 'snipName': self.snip.name, 'attachmentId': self.id } ) 
    366     get_absolute_editurl = permalink(get_absolute_editurl, get_current_request
     392    get_absolute_editurl = sphpermalink(get_absolute_editurl
    367393 
    368394    def save(self, force_insert=False, force_update=False): 
  • lib/sct/sphenecoll/sphene/sphwiki/urls.py

    r40 r178  
    77                                              ) 
    88 
    9 snip = r'(?P<snipName>[\w/:\-.]+?)' 
     9snip = r'(?P<snipName>[ \w/:\-.]+?)' 
    1010 
    1111urlpatterns += patterns('sphene.sphwiki.views', 
  • lib/sct/static/sphene/emoticons/README.txt

    r40 r110  
    1 These icons were copied from http://svn.zyons.python-hosting.com/trunk/zilbo/ 
    2 no idea who made them originally .. and i hope noone is bothered that i reuse 
    3 them ... 
     1These icons are from the Tango Desktop Project, released to the Public Domain: 
    42 
     3http://tango.freedesktop.org/Tango_Desktop_Project 
    54 
     5We are extremely grateful to the Tango Desktop Project artists: 
     6thank you for your patient and wonderful work! 
  • lib/sct/static/sphene/sphboard/js/editor.js

    r41 r113  
    3636        rep(/rgb\(128,\s?0,\s?128\)/gi,"purple"); 
    3737        rep(/rgb\(0,\s?128,\s?128\)/gi,"teal"); 
     38 
     39        // __replace_start__: emoticons_html_to_bbcode 
     40        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/smile\.png\"?(\s[^<>]*)?\/?>/gi," :)"); 
     41        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/wink\.png\"?(\s[^<>]*)?\/?>/gi," ;)"); 
     42        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/thinking\.png\"?(\s[^<>]*)?\/?>/gi," :thinking:"); 
     43        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/dont-know\.png\"?(\s[^<>]*)?\/?>/gi," :dont-know:"); 
     44        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/eyeroll\.png\"?(\s[^<>]*)?\/?>/gi," :eyeroll:"); 
     45        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/neutral\.png\"?(\s[^<>]*)?\/?>/gi," :|"); 
     46        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/embarrassed\.png\"?(\s[^<>]*)?\/?>/gi," :embarrassed:"); 
     47        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/confused\.png\"?(\s[^<>]*)?\/?>/gi," :confused:"); 
     48        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/sarcastic\.png\"?(\s[^<>]*)?\/?>/gi," :sarcastic:"); 
     49        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/sad\.png\"?(\s[^<>]*)?\/?>/gi," :("); 
     50        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/crying\.png\"?(\s[^<>]*)?\/?>/gi," ;("); 
     51        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/angry\.png\"?(\s[^<>]*)?\/?>/gi," :angry:"); 
     52        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/shock\.png\"?(\s[^<>]*)?\/?>/gi," :O"); 
     53        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/good\.png\"?(\s[^<>]*)?\/?>/gi," :ok:"); 
     54        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/bad\.png\"?(\s[^<>]*)?\/?>/gi," :ko:"); 
     55        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/fingers-crossed\.png\"?(\s[^<>]*)?\/?>/gi," :fingers-crossed:"); 
     56        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/foot-in-mouth\.png\"?(\s[^<>]*)?\/?>/gi," :foot-in-mouth:"); 
     57        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/glasses-cool\.png\"?(\s[^<>]*)?\/?>/gi," :glasses-cool:"); 
     58        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/glasses-nerdy\.png\"?(\s[^<>]*)?\/?>/gi," 8)"); 
     59        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/highfive\.png\"?(\s[^<>]*)?\/?>/gi," :batti5:"); 
     60        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/hug-left\.png\"?(\s[^<>]*)?\/?>/gi," :hug-left:"); 
     61        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/hug-right\.png\"?(\s[^<>]*)?\/?>/gi," :hug-right:"); 
     62        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/kiss\.png\"?(\s[^<>]*)?\/?>/gi," :*"); 
     63        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/laugh\.png\"?(\s[^<>]*)?\/?>/gi," :D"); 
     64        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/party\.png\"?(\s[^<>]*)?\/?>/gi," :party:"); 
     65        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/question\.png\"?(\s[^<>]*)?\/?>/gi," :question:"); 
     66        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/quiet\.png\"?(\s[^<>]*)?\/?>/gi," :quiet:"); 
     67        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/secret\.png\"?(\s[^<>]*)?\/?>/gi," :segreto:"); 
     68        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/sick\.png\"?(\s[^<>]*)?\/?>/gi," :sick:"); 
     69        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/sleepy\.png\"?(\s[^<>]*)?\/?>/gi," :sleepy:"); 
     70        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/teeth\.png\"?(\s[^<>]*)?\/?>/gi," :teeth:"); 
     71        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/tongue\.png\"?(\s[^<>]*)?\/?>/gi," :P"); 
     72        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/vampire\.png\"?(\s[^<>]*)?\/?>/gi," :vampire:"); 
     73        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/angel\.png\"?(\s[^<>]*)?\/?>/gi," :angel:"); 
     74        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/devil\.png\"?(\s[^<>]*)?\/?>/gi," :devil:"); 
     75        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/beer\.png\"?(\s[^<>]*)?\/?>/gi," :birrame:"); 
     76        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/coffee\.png\"?(\s[^<>]*)?\/?>/gi," :caffÚ:"); 
     77        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\/static\/sphene\/emoticons\/pitoncino\.png\"?(\s[^<>]*)?\/?>/gi," :py:"); 
     78        // __replace_end__: emoticons_html_to_bbcode 
    3879 
    3980        rep(/<img\s[^<>]*?src=\"?([^<>]*?)\"?(\s[^<>]*)?\/?>/gi,"[img]$1[/img]"); 
     
    127168        } 
    128169        rep(/\[img\]([\s\S]*?)\[\/img\]/gi,"<img src=\"$1\" />"); 
     170        // __replace_start__: emoticons_bbcode_to_html 
     171        rep(/\:fingers\-crossed\:/g,"<img src=\"/static/sphene/emoticons/fingers-crossed.png\" alt=\":fingers-crossed:\" title=\":fingers-crossed:\"/>"); 
     172        rep(/\:foot\-in\-mouth\:/g,"<img src=\"/static/sphene/emoticons/foot-in-mouth.png\" alt=\":foot-in-mouth:\" title=\":foot-in-mouth:\"/>"); 
     173        rep(/\:glasses\-cool\:/g,"<img src=\"/static/sphene/emoticons/glasses-cool.png\" alt=\":glasses-cool:\" title=\":glasses-cool:\"/>"); 
     174        rep(/\:embarrassed\:/g,"<img src=\"/static/sphene/emoticons/embarrassed.png\" alt=\":embarrassed:\" title=\":embarrassed:\"/>"); 
     175        rep(/\:dont\-know\:/g,"<img src=\"/static/sphene/emoticons/dont-know.png\" alt=\":dont-know:\" title=\":dont-know:\"/>"); 
     176        rep(/\:sarcastic\:/g,"<img src=\"/static/sphene/emoticons/sarcastic.png\" alt=\":sarcastic:\" title=\":sarcastic:\"/>"); 
     177        rep(/\:hug\-right\:/g,"<img src=\"/static/sphene/emoticons/hug-right.png\" alt=\":hug-right:\" title=\":hug-right:\"/>"); 
     178        rep(/\:thinking\:/g,"<img src=\"/static/sphene/emoticons/thinking.png\" alt=\":thinking:\" title=\":thinking:\"/>"); 
     179        rep(/\:confused\:/g,"<img src=\"/static/sphene/emoticons/confused.png\" alt=\":confused:\" title=\":confused:\"/>"); 
     180        rep(/\:hug\-left\:/g,"<img src=\"/static/sphene/emoticons/hug-left.png\" alt=\":hug-left:\" title=\":hug-left:\"/>"); 
     181        rep(/\:question\:/g,"<img src=\"/static/sphene/emoticons/question.png\" alt=\":question:\" title=\":question:\"/>"); 
     182        rep(/\:eyeroll\:/g,"<img src=\"/static/sphene/emoticons/eyeroll.png\" alt=\":eyeroll:\" title=\":eyeroll:\"/>"); 
     183        rep(/\:segreto\:/g,"<img src=\"/static/sphene/emoticons/secret.png\" alt=\":segreto:\" title=\":segreto:\"/>"); 
     184        rep(/\:vampire\:/g,"<img src=\"/static/sphene/emoticons/vampire.png\" alt=\":vampire:\" title=\":vampire:\"/>"); 
     185        rep(/\:birrame\:/g,"<img src=\"/static/sphene/emoticons/beer.png\" alt=\":birrame:\" title=\":birrame:\"/>"); 
     186        rep(/\:batti5\:/g,"<img src=\"/static/sphene/emoticons/highfive.png\" alt=\":batti5:\" title=\":batti5:\"/>"); 
     187        rep(/\:sleepy\:/g,"<img src=\"/static/sphene/emoticons/sleepy.png\" alt=\":sleepy:\" title=\":sleepy:\"/>"); 
     188        rep(/\:angry\:/g,"<img src=\"/static/sphene/emoticons/angry.png\" alt=\":angry:\" title=\":angry:\"/>"); 
     189        rep(/\:party\:/g,"<img src=\"/static/sphene/emoticons/party.png\" alt=\":party:\" title=\":party:\"/>"); 
     190        rep(/\:quiet\:/g,"<img src=\"/static/sphene/emoticons/quiet.png\" alt=\":quiet:\" title=\":quiet:\"/>"); 
     191        rep(/\:teeth\:/g,"<img src=\"/static/sphene/emoticons/teeth.png\" alt=\":teeth:\" title=\":teeth:\"/>"); 
     192        rep(/\:angel\:/g,"<img src=\"/static/sphene/emoticons/angel.png\" alt=\":angel:\" title=\":angel:\"/>"); 
     193        rep(/\:devil\:/g,"<img src=\"/static/sphene/emoticons/devil.png\" alt=\":devil:\" title=\":devil:\"/>"); 
     194        rep(/:caffÚ:/g,"<img src=\"/static/sphene/emoticons/coffee.png\" alt=\":caffÚ:\" title=\":caffÚ:\"/>"); 
     195        rep(/\:sick\:/g,"<img src=\"/static/sphene/emoticons/sick.png\" alt=\":sick:\" title=\":sick:\"/>"); 
     196        rep(/\:ok\:/g,"<img src=\"/static/sphene/emoticons/good.png\" alt=\":ok:\" title=\":ok:\"/>"); 
     197        rep(/\:ko\:/g,"<img src=\"/static/sphene/emoticons/bad.png\" alt=\":ko:\" title=\":ko:\"/>"); 
     198        rep(/\:py\:/g,"<img src=\"/static/sphene/emoticons/pitoncino.png\" alt=\":py:\" title=\":py:\"/>"); 
     199        rep(/\:\)/g,"<img src=\"/static/sphene/emoticons/smile.png\" alt=\":)\" title=\":)\"/>"); 
     200        rep(/\;\)/g,"<img src=\"/static/sphene/emoticons/wink.png\" alt=\";)\" title=\";)\"/>"); 
     201        rep(/\:\|/g,"<img src=\"/static/sphene/emoticons/neutral.png\" alt=\":|\" title=\":|\"/>"); 
     202        rep(/\:\(/g,"<img src=\"/static/sphene/emoticons/sad.png\" alt=\":(\" title=\":(\"/>"); 
     203        rep(/\;\(/g,"<img src=\"/static/sphene/emoticons/crying.png\" alt=\";(\" title=\";(\"/>"); 
     204        rep(/\:O/g,"<img src=\"/static/sphene/emoticons/shock.png\" alt=\":O\" title=\":O\"/>"); 
     205        rep(/8\)/g,"<img src=\"/static/sphene/emoticons/glasses-nerdy.png\" alt=\"8)\" title=\"8)\"/>"); 
     206        rep(/\:\*/g,"<img src=\"/static/sphene/emoticons/kiss.png\" alt=\":*\" title=\":*\"/>"); 
     207        rep(/\:D/g,"<img src=\"/static/sphene/emoticons/laugh.png\" alt=\":D\" title=\":D\"/>"); 
     208        rep(/\:P/g,"<img src=\"/static/sphene/emoticons/tongue.png\" alt=\":P\" title=\":P\"/>"); 
     209        // __replace_end__: emoticons_bbcode_to_html 
    129210        var sc; 
    130211        do { 
     
    366447} 
    367448 
    368 function insertSmiley(n){ 
     449function insertSmiley(name){ 
    369450  ifm.contentWindow.focus(); 
    370   if(n<10){n = '0'+n.toString();}else{n = n.toString();} 
    371   myeditor.execCommand('InsertImage', false, editor_static + '/smilies/n0'+n+'.gif'); 
     451  myeditor.execCommand('InsertImage', false, emoticons_url + '/'+name+'.png'); 
    372452} 
    373453 
  • lib/sct/static/sphene/sphboard/js/inline.js

    r41 r113  
    66  var alt = new Array("undo","redo","bold","italic","underline","clear","link","unlink","picture","quote","code"); 
    77  var c = new Array("black","red","blue","green","orange","fuchsia","aqua","lime","maroon","purple","teal"); 
    8  
     8  var smn = new Array( 
     9// __replace_start__: smile_names 
     10"smile","wink","thinking","dont-know","eyeroll","neutral","embarrassed","confused","sarcastic","sad","crying","angry","shock","good","bad","fingers-crossed","foot-in-mouth","glasses-cool","glasses-nerdy","highfive","hug-left","hug-right","kiss","laugh","party","question","quiet","secret","sick","sleepy","teeth","tongue","vampire","angel","devil","beer","coffee","pitoncino" 
     11// __replace_end__: smile_names 
     12  ); 
    913  var str = "<table><tr>"; 
    1014  for(i=0;i<11;i++) { 
     
    2125 
    2226  str = p.innerHTML + '<div id="smilies"><table>'; 
    23   for(i=1;i<=24;i++) { 
    24     if(i%3==1) { 
    25       str += '<tr align="center" height="36">'; 
     27  for(i=0;i<=smn.length;i++) { 
     28    if(i%4==0) { 
     29      str += '<tr align="center">'; 
    2630    } 
    2731    if(i<10){n = '0'+i.toString();}else{n = i.toString();} 
    28     str += '<td valign="middle"><div class="bn" onmouseover="switchBtn(this, 1)" onmouseout="switchBtn(this, 0)" onclick="insertSmiley(' + i + ')" style="cursor:pointer;"><img src="'+editor_static+'/smilies/n0' + n + '.gif" width=30 border=0 height=30></div></td>'; 
    29     if(i%3==0) { 
     32    str += '<td valign="middle"><div class="bn" onmouseover="switchBtn(this, 1)" onmouseout="switchBtn(this, 0)" onclick="insertSmiley(\'' + smn[i] + '\')" style="cursor:pointer;"><img src="'+emoticons_url+'/' + smn[i] + '.png" width=24 height=24 border=0></div></td>'; 
     33    if((i+1)%4==0) { 
    3034      str += '</tr>'; 
    3135    } 
  • lib/sct/static/sphene/sphboard/styles/base.css

    r40 r146  
    148148  float:right; 
    149149} 
    150 .board_postdate { 
     150.board_posticon { 
     151  float:left; 
     152  margin-right: 5px; 
     153
     154.board_postheaders { 
    151155  float:left; 
    152156} 
     
    207211  max-height:20em; 
    208212} 
     213img.sphboard_post_icon { 
     214  vertical-align: middle; 
     215} 
    209216 
    210217 
  • lib/sct/static/sphene/sphboard/styles/editor.css

    r41 r109  
     1body { 
     2  font-family: Arial, Verdana, Geneva, "Bitstream Vera Sans", Helvetica, sans-serif; 
     3  font-size: 100%; 
     4} 
    15 
    26.memberquote {