Luke Plant avatar Luke Plant committed b2a4b69

Removed trailing whitespace

Comments (0)

Files changed (56)

cciw/cciwmain/admin.py

     fieldsets = (
         (None, {'fields': ('short_name', 'long_name', 'info')}),
     )
-   
+
 class PersonAdmin(admin.ModelAdmin):
     filter_horizontal = ('users',)
 
 class CampAdmin(admin.ModelAdmin):
     fieldsets = (
-        (None, {'fields': ('year', 'number', 'age', 'start_date', 'end_date', 
-                           'chaplain', 'leaders', 'site', 'previous_camp', 
+        (None, {'fields': ('year', 'number', 'age', 'start_date', 'end_date',
+                           'chaplain', 'leaders', 'site', 'previous_camp',
                            'online_applications', 'admins')
                 }
         ),

cciw/cciwmain/common.py

 import cciw.middleware.threadlocals as threadlocals
 import datetime
 import urllib
-       
+
 def standard_extra_context(title=None, description=None, keywords=None):
     """
     Gets the 'extra_dict' dictionary used for all pages
     """
     Member = cciw.cciwmain.models.Member
-        
+
     if title is None:
         title = u"Christian Camps in Wales"
     if description is None:
         description = u"Details of camps, message boards and photos for the UK charity Christian Camps in Wales"
     if keywords is None:
         keywords = u"camp, camps, summer camp, Christian, Christian camp, charity"
-    
+
     extra_dict = {}
     extra_dict['title'] = title
-    extra_dict['meta_description'] = description 
+    extra_dict['meta_description'] = description
     extra_dict['meta_keywords'] = keywords
     extra_dict['thisyear'] = get_thisyear()
     extra_dict['misc'] = {
-        'logged_in_members': 
+        'logged_in_members':
             Member.objects.filter(last_seen__gte=datetime.datetime.now() \
                                            - datetime.timedelta(minutes=3)).count(),
     }
-    
+
     return extra_dict
 
 _thisyear = None
 def get_thisyear():
     """
     Get the year the website is currently on.  The website year is
-    equal to the year of the last camp in the database, or the year 
+    equal to the year of the last camp in the database, or the year
     afterwards if that camp is in the past.
     """
     global _thisyear, _thisyear_timestamp
     """Standard substitutions made on HTML content"""
     return value.replace('{{thisyear}}', str(get_thisyear()))\
                 .replace('{{media}}', settings.CCIW_MEDIA_URL)
-standard_subs.is_safe = True # provided our substitutions don't introduce anything that must be escaped 
+standard_subs.is_safe = True # provided our substitutions don't introduce anything that must be escaped
 
 def get_order_option(order_options, request, default_order_by):
-    """Get the order_by parameter from the request, if the request 
+    """Get the order_by parameter from the request, if the request
     contains any of the specified ordering parameters in the query string.
-    
-    order_options is a dict of query string params and the corresponding lookup argument.  
-    
+
+    order_options is a dict of query string params and the corresponding lookup argument.
+
     default_order_by is value to use for if there is no matching
     order query string.
     """
             l.isCurrentPage = True
         elif request.path.startswith(l.url) and l.url != u'/':
             l.isCurrentSection = True
-    
+
     context['menulinks'] = links
     context['current_member'] = threadlocals.get_current_member()
     context['pagevars'] = {
     }
 
     context.update(view_extras.get_view_extras_context(request))
-    
+
     return context
 
 

cciw/cciwmain/decorators.py

     else:
         # User's session must have expired; save their post data.
         post_data = _encode_post_data((request.method, request.POST))
-    
+
     c = template.RequestContext(request, standard_extra_context(title="Login"))
     return render_to_response('cciw/members/login.html', {
         'app_path': request.path,
 
     def decorator(view_func):
         """
-        Decorator for views that checks if data was POSTed back and 
+        Decorator for views that checks if data was POSTed back and
         if so requires the user to log in.
         It is also used by the normal '/login/' view.
         """
 
         def _checklogin(request, *args, **kwargs):
-            
+
             def _forward_to_original(req):
                 # helper function to go to the original view function.
                 if req.POST.has_key(LOGIN_FORM_POST_DATA_KEY):
                 #  - or they were logged out and so saw the login page.
                 #    But they then logged in through a different
                 #    browser tab, and so don't need to log in again.
-                
+
                 return _forward_to_original(request)
 
             # If this isn't already the login page, display it.

cciw/cciwmain/feeds.py

     response = HttpResponse(mimetype=feedgen.mime_type)
     feedgen.write(response, 'utf-8')
     return response
-    
+
 def add_domain(url):
     """Adds the domain onto the beginning of a URL"""
     return feeds.add_domain(get_current_domain(), url)
 
     def modify_query(self, query_set):
         return query_set.order_by('-created_at')[:TOPIC_FEED_MAX_ITEMS]
-        
+
     def item_author_name(self, topic):
         return topic.started_by_id
-        
+
     def item_author_link(self, topic):
         return add_domain(get_member_href(topic.started_by_id))
-        
+
     def item_pubdate(self, topic):
         return topic.created_at
 
 class PhotoFeed(CCIWFeed):
     template_name = 'photos'
     title = u'CCIW photos'
-    
+
     def modify_query(self, query_set):
         return query_set.order_by('-created_at')[:PHOTO_FEED_MAX_ITEMS]
-    
+
     def item_pubdate(self, photo):
         return photo.created_at
 
 class TagFeed(CCIWFeed):
     template_name = 'tags'
     title = 'CCIW - recent tags'
-    
+
     def modify_query(self, query_set):
         return query_set.order_by('-added')[:TAG_FEED_MAX_ITEMS]
-        
+
     def item_author_name(self, tag):
         return tag.creator_id
-        
+
     def item_author_link(self, tag):
         return add_domain(get_member_href(tag.creator_id))
-    
+
     def item_pubdate(self, tag):
         return tag.added
-        
+
     def item_link(self, tag):
         return add_domain("/tag_targets/%s/%s/%s/%s/" % (tag.target_ct.name, tag.target_id, tag.text, tag.id))
 

cciw/cciwmain/forms.py

         start = u'<div class="form">'
         end = u'</div>'
         required_text = u' <a href="#" title="This field is required">*</a>'
-        
+
         top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
         output, hidden_fields = [], []
         output.append(start)
                 else:
                     help_text = u''
                 output.append(normal_row % {
-                        'errors': force_unicode(bf_errors), 
-                        'label': force_unicode(label), 
-                        'field': unicode(bf), 
+                        'errors': force_unicode(bf_errors),
+                        'label': force_unicode(label),
+                        'field': unicode(bf),
                         'help_text': help_text,
                         'class': cssclass,
                         'divid': "div_id_%s" % bf.name

cciw/cciwmain/imageutils.py

 """
 
 # Using 'convert', because it's installed on my hosting and dev box,
-# and it's easier than getting 
+# and it's easier than getting
 
 from django.conf import settings
 import shutil
 def parse_image(filename):
     fp = open(filename, "rb")
     p = ImageFile.Parser()
-    
+
     while 1:
         s = fp.read(1024)
         if not s:
             break
         p.feed(s)
-    
+
     im = p.close()
     return im
 
     except IOError:
         safe_del(filename)
         raise ValidationError(u"The image format was not recognised.")
-    
+
     if img.size is None:
         safe_del(filename)
         raise ValidationError(u"The image format was not recognised.")
-    
+
     if img.size[0] > settings.MEMBER_ICON_MAX_SIZE or \
        img.size[1] > settings.MEMBER_ICON_MAX_SIZE:
         # For now, just complain
         safe_del(filename)
         raise ValidationError(u"The image was bigger than %s by %s." % \
             (settings.MEMBER_ICON_MAX_SIZE, settings.MEMBER_ICON_MAX_SIZE))
-        
+
         # Scale to fit - TODO
         #factor = max(img.size[0], img.size[1])/float(settings.MEMBER_ICON_MAX_SIZE)
         #new_width, new_height = size[0]/factor, size[1]/factor
-    
+
     # Give the icon a predictable name, with the same extension it had before.
     # We refer to it in views without its extension, and use content negotiation
     # to get the right one.
-    # This means we can just we only need the primary key (the username) of 
+    # This means we can just we only need the primary key (the username) of
     # the Member object to calculate this URL, saving on *lots* of db queries.
-    
+
     ext = filename.split('.')[-1]
     # Remove existing variants
     for f in glob.glob("%s/%s/%s" % (settings.MEDIA_ROOT, settings.MEMBER_ICON_PATH, member.user_name + ".*")):

cciw/cciwmain/models/camps.py

     slug_name = models.SlugField("Machine name", max_length="25", blank=True, unique=True)
     long_name = models.CharField("Long name", max_length="50", blank=False)
     info = models.TextField("Description (HTML)")
-    
+
     def __unicode__(self):
         return self.short_name
-        
+
     def get_absolute_url(self):
         return u"/sites/%s/" % self.slug_name
-    
+
     def save(self):
         from django.template.defaultfilters import slugify
         self.slug_name = slugify(self.short_name)
         super(Site, self).save()
-    
+
     class Meta:
         app_label = "cciwmain"
         pass
-        
+
 class Person(models.Model):
     name = models.CharField("Name", max_length=40)
-    info = models.TextField("Information (Plain text)", 
+    info = models.TextField("Information (Plain text)",
                         blank=True)
     users = models.ManyToManyField(User, verbose_name="Associated admin users")
 
                         choices=CAMP_AGES)
     start_date = models.DateField("start date")
     end_date = models.DateField("end date")
-    previous_camp = models.ForeignKey("self", 
-        related_name="next_camps", 
+    previous_camp = models.ForeignKey("self",
+        related_name="next_camps",
         verbose_name="previous camp",
         null=True, blank=True)
-    chaplain = models.ForeignKey(Person, 
-        related_name="camps_as_chaplain", 
-        verbose_name="chaplain", 
+    chaplain = models.ForeignKey(Person,
+        related_name="camps_as_chaplain",
+        verbose_name="chaplain",
         null=True, blank=True)
-    leaders = models.ManyToManyField(Person, 
-        related_name="camps_as_leader", 
+    leaders = models.ManyToManyField(Person,
+        related_name="camps_as_leader",
         verbose_name="leaders",
         null=True, blank=True)
-    admins = models.ManyToManyField(User, 
+    admins = models.ManyToManyField(User,
         related_name="camps_as_admin",
         verbose_name="admins",
         null=True, blank=True)
     site = models.ForeignKey(Site)
     online_applications = models.BooleanField("Accepts online applications from officers.")
-    
+
     def save(self):
         new = self.id is None
         super(Camp, self).save()
         else:
             leadertext = u""
         return u"%s-%s%s" % (self.year, self.number, leadertext)
-    
+
     @property
     def nice_name(self):
         return u"Camp %d, year %d" % (self.number, self.year)

cciw/cciwmain/models/forums.py

 class Forum(models.Model):
     open = models.BooleanField("Open", default=True)
     location = models.CharField("Location/path", db_index=True, unique=True, max_length=50)
-    
+
     def get_absolute_url(self):
         return '/' + self.location
-    
+
     def __unicode__(self):
         return self.location
 
         else:
             return u"forum at %s" % self.location
 
-    
+
     class Meta:
-        app_label = "cciwmain"   
+        app_label = "cciwmain"
 
 class NewsItem(models.Model):
     created_by = models.ForeignKey(Member, related_name="news_items_created")
     summary = models.TextField("Summary or short item, (bbcode)")
     full_item = models.TextField("Full post (HTML)", blank=True)
     subject = models.CharField("Subject", max_length=100)
-    
+
     def has_full_item(self):
         return len(self.full_item) > 0
 
     forum = models.ForeignKey(Forum, related_name="topics")
 
     # De-normalised fields needed for performance and simplicity in templates:
-    last_post_at = models.DateTimeField("Last post at", 
-        null=True, blank=True) 
+    last_post_at = models.DateTimeField("Last post at",
+        null=True, blank=True)
     last_post_by = models.ForeignKey(Member, verbose_name="Last post by",
-        null=True, blank=True, related_name='topics_with_last_post') 
+        null=True, blank=True, related_name='topics_with_last_post')
     # since we need 'last_post_by', may as well have this too:
-    post_count = models.PositiveSmallIntegerField("Number of posts", default=0) 
-    
+    post_count = models.PositiveSmallIntegerField("Number of posts", default=0)
+
     # Managers:
     objects = UserSpecificTopics()
     all_objects = models.Manager()
 
     def __unicode__(self):
         return  u"Topic: " + self.subject
-        
+
     def get_absolute_url(self):
         return self.forum.get_absolute_url() + str(self.id) + '/'
-    
+
     def get_link(self):
         return mark_safe(u'<a href="%s">%s</a>' % (self.get_absolute_url(), escape(self.subject)))
 
 
     def __unicode__(self):
         return self.location
-        
+
     def get_absolute_url(self):
         return '/' + self.location
-        
+
     class Meta:
         app_label = "cciwmain"
         verbose_name_plural = "Galleries"
     needs_approval = models.BooleanField("Needs approval", default=False)
 
     # De-normalised fields needed for performance and simplicity in templates:
-    last_post_at = models.DateTimeField("Last post at", 
-        null=True, blank=True) 
+    last_post_at = models.DateTimeField("Last post at",
+        null=True, blank=True)
     last_post_by = models.ForeignKey(Member, verbose_name="Last post by",
         null=True, blank=True, related_name='photos_with_last_post')
     # since we need 'last_post_by', may as well have this too:
                     approved=None,
                     needs_approval=False
         )
-        
+
     class Meta:
         app_label = "cciwmain"
 
            (user is None or user.is_anonymous() or \
             not user.has_perm('cciwmain.edit_post')):
             # Non-moderator user
-            
+
             member = threadlocals.get_current_member()
             if member is not None:
                 # include hidden posts by that user
             return queryset
 
 class Post(models.Model):
-    posted_by = models.ForeignKey(Member, 
+    posted_by = models.ForeignKey(Member,
         related_name="posts")
     subject = models.CharField("Subject", max_length=240, blank=True) # deprecated, supports legacy boards
     message = models.TextField("Message")
             changed = True
         if changed:
             parent.save()
-                
+
     def save(self):
         super(Post, self).save()
         # Update parent topic/photo
-        
+
         if self.topic_id is not None:
             self.updateParent(self.topic)
-            
+
         if self.photo_id is not None:
             self.updateParent(self.photo)
 
     def get_absolute_url(self):
-        """Returns the absolute URL of the post that is always correct.  
+        """Returns the absolute URL of the post that is always correct.
         (This does a redirect to a URL that depends on the member viewing the page)"""
         return "/posts/%s/" % self.id
 
         # looking at it.  This function takes this into account
         # and gives the correct URL.  This is important for the case
         # or feed readers that won't in general be logged in as the
-        # the user when they fetch the feed that may have absolute 
+        # the user when they fetch the feed that may have absolute
         # URLs in it.
         # Also it's useful in case we change the paging.
         if self.topic_id is not None:
                     needs_approval=(member.moderated == Member.MODERATE_ALL),
                     posted_at=datetime.now())
         return post
-        
-        
+
+
     class Meta:
         app_label = "cciwmain"
         # Order by the autoincrement id, rather than  posted_at, because
-        # this matches the old system (in the old system editing a post 
+        # this matches the old system (in the old system editing a post
         # would also cause its posted_at date to change, but not it's order,
         # and data for the original post date/time is now lost)
-        ordering = ('id',) 
+        ordering = ('id',)

cciw/cciwmain/models/members.py

 
     id = models.PositiveSmallIntegerField("ID", primary_key=True)
     description = models.CharField("Description", max_length=40)
-    
+
     def __unicode__(self):
         return self.description
-    
+
     class Meta:
         ordering = ('id',)
         app_label = "cciwmain"
     MESSAGES_WEBSITE = 1
     MESSAGES_EMAIL = 2
     MESSAGES_EMAIL_AND_WEBSITE = 3
-    
+
     MODERATE_OFF = 0
     MODERATE_NOTIFY = 1
     MODERATE_ALL = 2
-    
+
     MESSAGE_OPTIONS = (
         (MESSAGES_NONE,     u"Don't allow messages"),
         (MESSAGES_WEBSITE,  u"Store messages on the website"),
         (MESSAGES_EMAIL,    u"Send messages via email"),
         (MESSAGES_EMAIL_AND_WEBSITE, u"Store messages and send via email")
     )
-    
+
     MODERATE_OPTIONS = (
         (MODERATE_OFF,      u"Off"),
         (MODERATE_NOTIFY,   u"Unmoderated, but notify"),
         blank=True, null=True)
     icon         = models.ImageField("Icon", upload_to=settings.MEMBER_ICON_UPLOAD_PATH, blank=True)
     dummy_member = models.BooleanField("Dummy member status", default=False) # supports ancient posts in message boards
-    
+
     # Managers
     objects = UserSpecificMembers()
     all_objects = models.Manager()
-    
+
     def __unicode__(self):
         return self.user_name
-        
+
     def get_absolute_url(self):
         if self.dummy_member:
             return None
         else:
             return get_member_href(self.user_name)
-        
+
     def get_link(self):
         if self.dummy_member:
             return self.user_name
         """Checks a password is correct"""
         import crypt
         return crypt.crypt(plaintextPass, self.password) == self.password
-        
+
     def new_messages(self):
         return self.messages_received.filter(box=Message.MESSAGE_BOX_INBOX).count()
 
     def saved_messages(self):
         return self.messages_received.filter(box=Message.MESSAGE_BOX_SAVED).count()
-    
+
     def has_perm(self, perm):
         """Does the member has the specified permission?
         perm is one of the permission constants in Permission."""
         return len(self.permissions.filter(description=perm)) > 0
-    
+
     @property
     def can_add_news(self):
         return self.has_perm(Permission.NEWS_CREATOR)
-        
+
     @property
     def can_add_poll(self):
         return self.has_perm(Permission.POLL_CREATOR)
 
-    @staticmethod    
+    @staticmethod
     def generate_salt():
         import random, datetime
         rand64= "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
         random.seed(datetime.datetime.today().microsecond)
         return rand64[int(random.random()*64)] + rand64[int(random.random()*64)]
-    
+
     @staticmethod
     def encrypt_password(memberPass):
         import crypt
     value = models.SmallIntegerField("Value")
     year = models.PositiveSmallIntegerField("Year")
     description = models.CharField("Description", max_length=200)
-    image = models.ImageField("Award image", 
+    image = models.ImageField("Award image",
         upload_to=settings.AWARD_UPLOAD_PATH)
 
     def __unicode__(self):
         return self.name + u" " + unicode(self.year)
-        
+
     def nice_name(self):
         return str(self)
-    
+
     def imageurl(self):
         return settings.CCIW_MEDIA_URL + "/images/awards/" + self.image
-        
+
     def get_absolute_url(self):
         from django.template.defaultfilters import slugify
         return "/awards/#" + slugify(unicode(self))
-    
+
     class Meta:
         app_label = "cciwmain"
         ordering = ('-year', 'name',)
     reason = models.CharField("Reason for award", max_length=200)
     date_awarded = models.DateField("Date awarded", null=True, blank=True)
     award = models.ForeignKey(Award,
-        verbose_name="award", 
+        verbose_name="award",
         related_name="personal_awards")
     member = models.ForeignKey(Member,
         verbose_name="member",
         return "%s to %s" % (self.award.name, self.member.user_name)
 
     class Meta:
-        app_label = "cciwmain"   
+        app_label = "cciwmain"
         ordering = ('date_awarded',)
-        
+
 class Message(models.Model):
     MESSAGE_BOX_INBOX = 0
     MESSAGE_BOX_SAVED = 1
-    
+
     MESSAGE_BOXES = (
         (MESSAGE_BOX_INBOX, "Inbox"),
         (MESSAGE_BOX_SAVED, "Saved")
         verbose_name="from member",
         related_name="messages_sent"
     )
-    to_member = models.ForeignKey(Member, 
+    to_member = models.ForeignKey(Member,
         verbose_name="to member",
         related_name="messages_received")
     time = models.DateTimeField("At")
     text = models.TextField("Message")
     box = models.PositiveSmallIntegerField("Message box",
         choices=MESSAGE_BOXES)
-    
+
     @staticmethod
     def send_message(to_member, from_member, text):
         if to_member.message_option == Member.MESSAGES_NONE:
 """ % {'from': from_member.user_name, 'to': to_member.user_name,
         'domain': utils.get_current_domain(), 'message': text},
         "website@cciw.co.uk", [to_member.email])
-            
-    
+
+
     def __unicode__(self):
         return u"[%s] to %s from %s" % (unicode(self.id), unicode(self.to_member), unicode(self.from_member))
-    
+
     class Meta:
         app_label = "cciwmain"
         ordering = ('-time',)

cciw/cciwmain/models/polls.py

     voting_ends = models.DateTimeField("Voting ends")
     rules = models.PositiveSmallIntegerField("Rules",
         choices=VOTING_RULES)
-    rule_parameter = models.PositiveSmallIntegerField("Parameter for rule", 
+    rule_parameter = models.PositiveSmallIntegerField("Parameter for rule",
         default=1)
-    have_vote_info = models.BooleanField("Full vote information available", 
+    have_vote_info = models.BooleanField("Full vote information available",
         default=True)
     created_by = models.ForeignKey(Member, verbose_name="created by",
         related_name="polls_created")
-    
+
     def __unicode__(self):
         return self.title
-    
+
     def can_vote(self, member):
         """Returns true if member can vote on the poll"""
         if not self.can_anyone_vote():
             return False
         if not self.have_vote_info:
-            # Can't calculate this, but it will only happen 
+            # Can't calculate this, but it will only happen
             # for legacy polls, which are all closed.
             return True
         if self.rules == Poll.UNLIMITED:
             if self.rules == Poll.X_VOTES_PER_USER:
                 queries.append(po.votes.filter(member=member.user_name))
             elif self.rules == Poll.X_VOTES_PER_USER_PER_DAY:
-                queries.append(po.votes.filter(member=member.user_name, 
+                queries.append(po.votes.filter(member=member.user_name,
                                                 date__gte=datetime.now() - timedelta(1)))
         # combine them all and do an SQL count.
         if len(queries) == 0:
             return False
         else:
             return True
-        
+
     def total_votes(self):
         sum = 0
         # TODO - use SQL, or caching
         for option in self.poll_options.all():
             sum += option.total
         return sum
-    
+
     def can_anyone_vote(self):
         return (self.voting_ends > datetime.now()) and \
             (self.voting_starts < datetime.now())
-    
+
     def verbose_rules(self):
         if self.rules == Poll.UNLIMITED:
             return u"Unlimited number of votes."
             return u"%s vote(s) per user." % self.rule_parameter
         elif self.rules == Poll.X_VOTES_PER_USER_PER_DAY:
             return u"%s vote(s) per user per day." % self.rule_parameter
-        
+
     class Meta:
-        app_label = "cciwmain"   
+        app_label = "cciwmain"
         ordering = ('title',)
 
 class PollOption(models.Model):
     poll = models.ForeignKey(Poll, verbose_name="Associated poll",
         related_name="poll_options", edit_inline=True)
     listorder = models.PositiveSmallIntegerField("Order in list", core=True)
-        
+
     def __unicode__(self):
         return self.text
-        
+
     def percentage(self):
         """
-        Get the percentage of votes this option got 
+        Get the percentage of votes this option got
         compared to the total number of votes in the whole. Return
         'n/a' if total votes = 0
         """
                 return '0%'
             else:
                 return '%.1f' % (float(self.total)/sum*100) + '%'
-                
+
     def bar_width(self):
         sum = self.poll.total_votes()
         if sum == 0:
         ordering = ('poll', 'listorder',)
 
 class VoteInfo(models.Model):
-    poll_option = models.ForeignKey(PollOption, 
+    poll_option = models.ForeignKey(PollOption,
         related_name="votes")
     member = models.ForeignKey(Member,
         verbose_name="member",
 
     class Meta:
         app_label = "cciwmain"
-        
+

cciw/cciwmain/models/sitecontent.py

     def __unicode__(self):
         from cciw.cciwmain.common import standard_subs
         return  u"%s [%s]" % (self.url, standard_subs(self.title))
-    
+
     def get_visible_children(self, request):
         """Gets a list of child menu links that should be visible given the current url"""
         if request.path == self.url:
             return self.child_links
         else:
             return []
-    
+
     class Meta:
         app_label = "cciwmain"
         # put top level items at top of list, others into groups, for the admin
-        ordering = ('-parent_item__id', 'listorder') 
+        ordering = ('-parent_item__id', 'listorder')
 
 class HtmlChunk(models.Model):
     name = models.SlugField("name", primary_key=True, db_index=True)
         null=True, blank=True)
     page_title = models.CharField("page title (for chunks that are pages)", max_length=100,
         blank=True)
-    
+
     def __unicode__(self):
         return self.name
-        
+
     def render(self, request):
         """Render the HTML chunk as HTML, with replacements
         made and any member specific adjustments."""
         return mark_safe(html)
 
     class Meta:
-        app_label = "cciwmain"   
+        app_label = "cciwmain"
         verbose_name = "HTML chunk"

cciw/cciwmain/templatetags/bbcode.py

 #####################################################################
-##    Copyright (c) 2005-2006, Luke Plant 
+##    Copyright (c) 2005-2006, Luke Plant
 ##    All rights reserved.
 ##    E-mail: <L.Plant.98@cantab.net>
 ##    Web: http://lukeplant.me.uk/
-##    
+##
 ##    Redistribution and use in source and binary forms, with or without
 ##    modification, are permitted provided that the following conditions are
 ##    met:
-##    
+##
 ##        * Redistributions of source code must retain the above copyright
 ##          notice, this list of conditions and the following disclaimer.
-##    
+##
 ##        * Redistributions in binary form must reproduce the above
 ##          copyright notice, this list of conditions and the following
 ##          disclaimer in the documentation and/or other materials provided
 ##          with the distribution.
-##    
-##        * The name of Luke Plant may not be used to endorse or promote 
-##          products derived from this software without specific prior 
+##
+##        * The name of Luke Plant may not be used to endorse or promote
+##          products derived from this software without specific prior
 ##          written permission.
-##    
+##
 ##    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 ##    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 ##    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 ##
 ## 1) full XHTML compliance, including prohibited elements
 ## 2) intelligent handling/preserving of whitespace
-## 3) emoticons, with intelligent handling for tricky cases 
+## 3) emoticons, with intelligent handling for tricky cases
 ##    (e.g. inside <pre> tags)
 ## 4) ability to render out corrected BBCode as well as XHTML
 ## 5) XHTML output can be inserted into <body>, <div>, <td>
 ## 6) Excellent 'do what I mean' handling of bbcode input.
 ##
 ## IMPLEMENTATION NOTES
-## 
+##
 ## 1) I have implemented what I needed and used for my own needs,
 ##    which isn't necessarily 'standard' bbcode, if such a thing exists
 ## 2) There are some definitely web site specific extensions
 ## 4) Mostly it works on one-to-one correspondance between
 ##    'bbtags' and xhtml tags, but with some added constraints to force
 ##    extra elements to be inserted to comply with XHTML, and
-##    use some tricks to relax the nesting constraints, such 
+##    use some tricks to relax the nesting constraints, such
 ##    as some elements being context sensitive in the render phase
 
 import re
 # created in the 'rules' section.
 class BBTag(object):
     """Represents an allowed tag with its name and meta data."""
-    def __init__(self, name, allowed_children, implicit_tag, self_closing=False, 
+    def __init__(self, name, allowed_children, implicit_tag, self_closing=False,
         prohibited_elements=None, discardable=False):
         """Creates a new BBTag.
         - name is the text appears in square brackets e.g. for [b], name = 'b'
         - allowed_children is a list of the names of tags that can be added to this element
-        - implicit_tag is a tag that can automatically be added before this one 
+        - implicit_tag is a tag that can automatically be added before this one
           if necessary to allow it to be added.
         - self_closing means the element never has child elements
-        - prohibited_elements is a list of elements that can never be 
+        - prohibited_elements is a list of elements that can never be
           descendent elements of this one
-        - discardable = True indicates that the tag can be discarded if 
+        - discardable = True indicates that the tag can be discarded if
           it can't be added at the current point in the tree.
         """
-        
+
         if prohibited_elements is None:
             self.prohibited_elements = ()
         else:
         self.implicit_tag = implicit_tag
         self.allowed_children = set(allowed_children)
         self.discardable = discardable
-        
+
     def render_node_xhtml(self, node):
         """
         Renders a node of this BBTag as HTML.
         node is the node to render.
         """
         raise NotImplementedException()
-    
+
     def render_node_bbcode(self, node):
         opening = self.name # opening tag
         if node.parameter:
             return u'[%s]%s[/%s]' % \
                 (opening, node.render_children_bbcode(), self.name)
 
-## Subclasses that follow override the render_node_xhtml 
+## Subclasses that follow override the render_node_xhtml
 ## or render_node_bbcode method
-        
+
 class HtmlEquivTag(BBTag):
     """
     A BBTag that is a direct equivalent of an HTML tag, and can render itself.
         self.html_equiv = kwargs.pop('html_equiv')
         self.attributes = kwargs.pop('attributes', None)
         BBTag.__init__(self, *args, **kwargs)
-    
+
     def render_node_xhtml(self, node):
         opening = self.html_equiv
         if self.attributes:
             # Add any attributes
-            opening += u''.join(u' %s="%s"' % (k, escape(v)) 
+            opening += u''.join(u' %s="%s"' % (k, escape(v))
                                         for k, v in self.attributes.items())
         if self.self_closing:
-            ret = u'<%s/>' % opening 
+            ret = u'<%s/>' % opening
         else:
             if len(node.children) > 0:
                 ret = u'<%s>%s</%s>' % (opening, node.render_children_xhtml(), self.html_equiv)
             else:
                 ret = u''
         return ret
-    
+
     def render_node_bbcode(self, node):
         if self.name == 'div':
             # 'div' elements should never be printed out as [div]
             return u'<br/>'
         else:
             return u'\n'
-            
+
     def render_node_bbcode(self, node):
         return u'\n'
 
                 return u'<img src="%s" alt="%s" />' % (EMOTICONS_ROOT + imagename, escape(emoticon))
         else:
             return emoticon
-            
+
     def render_node_bbcode(self, node):
         return node.children[0].text
 
             return obfuscate_email(escape(node.children[0].text.strip()))
         else:
             return u''
-            
+
 class UrlTag(BBTag):
     def render_node_xhtml(self, node):
         if len(node.children) == 0:
                    (get_member_link(node.parameter),  node.render_children_xhtml())
         else:
             return '<blockquote>%s</blockquote>' % node.render_children_xhtml()
-        
+
 class BibleTag(BBTag):
     def render_node_xhtml(self, node):
         output = u''
 
 ###### DATA ######
 
-_COLORS = ('aqua', 'black', 'blue', 'fuchsia', 'gray', 'green', 'lime', 'maroon', 
+_COLORS = ('aqua', 'black', 'blue', 'fuchsia', 'gray', 'green', 'lime', 'maroon',
     'navy', 'olive', 'purple', 'red', 'silver', 'teal', 'white', 'yellow')
-    
+
 _COLOR_REGEXP = re.compile('|'.join(_COLORS) + r'|#[0-9A-F]{6}')
 _MEMBER_REGEXP = re.compile(r'^[0-9A-Za-z_]{1,30}$')
 _BBTAG_REGEXP = re.compile(r'\[\[?\/?([A-Za-z\*]+)(=[^\]]+)?\]?\]')
 
 # 'text' is a dummy entry for text nodes
 _INLINE_TAGS = (
-    'b', 'i', 'color', 'member', 'email', 'url', 
+    'b', 'i', 'color', 'member', 'email', 'url',
     'br', 'text', 'img', 'softbr', 'emoticon'
 )
 _BLOCK_LEVEL_TAGS = ('p', 'quote', 'list', 'pre', 'code', 'div', 'bible')
 
 _ANCHOR_TAGS = ('member', 'email', 'url')
 
-# Rules, defined so that the output after translation will be 
+# Rules, defined so that the output after translation will be
 # XHTML compatible. Other rules are implicit in the parsing routines.
 # Note that some bbtags can adapt to their context in the rendering
 # phase in order to generate correct XHTML, so have slacker rules than normal
 _TAGS = (
     #           name          allowed_children   implicit_tag
     # <br/>
-    HtmlEquivTag('br',         (),             'div', 
+    HtmlEquivTag('br',         (),             'div',
         self_closing=True, discardable=True, html_equiv='br'),
-    
+
     # <br/>, but can adapt during render
-    SoftBrTag   ('softbr',     (),             'div', 
+    SoftBrTag   ('softbr',     (),             'div',
         self_closing=True, discardable=True),
-    
+
     # <img/>,  but can adapt
     Emoticon    ('emoticon',   ('text',),      'div'),
-    
+
     # <b>
     HtmlEquivTag('b',          _INLINE_TAGS,   'div',
         html_equiv='b'),
-    
+
     # <i>
     HtmlEquivTag('i',          _INLINE_TAGS,   'div',
         html_equiv='i'),
-    
+
     # <span>
     ColorTag    ('color',      _INLINE_TAGS,   'div'),
-    
+
     # <a>
     MemberTag   ('member',     ('text',),      'div' ),
-    
+
     # <a>
     EmailTag    ('email',      ('text',),      'div'),
-    
+
     # <a>
     UrlTag      ('url',        ('text',),      'div'),
-    
+
     # <p>
     HtmlEquivTag('p',          _INLINE_TAGS,   None,
         html_equiv='p'),
-    
+
     # <div>
     HtmlEquivTag('div',        _FLOW_TAGS,     None,
         html_equiv='div'),
-    
+
     # <blockquote>
     QuoteTag    ('quote',      _BLOCK_LEVEL_TAGS + ('softbr',), 'div'),
-    
+
     # <blockquote>
     BibleTag    ('bible',      _BLOCK_LEVEL_TAGS + ('softbr',), 'div'),
-    
+
     # <ul>
     HtmlEquivTag('list',       ('*', 'softbr'),None,
         html_equiv='ul'),
-    
+
     # <pre> (only img currently needed out of the prohibited elements)
-    HtmlEquivTag('pre',        _INLINE_TAGS,   None, 
+    HtmlEquivTag('pre',        _INLINE_TAGS,   None,
         prohibited_elements=('img', 'big', 'small', 'sub', 'sup'),
-        html_equiv='pre'), 
-    
+        html_equiv='pre'),
+
     # <pre class="code">
-    HtmlEquivTag('code',       _INLINE_TAGS,   None, 
+    HtmlEquivTag('code',       _INLINE_TAGS,   None,
         prohibited_elements = ('img', 'big', 'small', 'sub', 'sup'),
         html_equiv='pre', attributes={'class':'code'}),
-        
+
     # <li>
     LiTag('*',                 _FLOW_TAGS,     'list',)
 )
 _EMOTICON_DICT = dict(_EMOTICONS)
 
 # Create a replacer (optimisation, plus this method is important
-# for correctness) 
+# for correctness)
 _replace_pairs = ((x, '[emoticon]%s[/emoticon]' % x) for x, y in _EMOTICONS)
 _emoticon_replacer = MultiReplace(dict(_replace_pairs))
 
     def __init__(self, parent):
         self.parent = parent
         self.children = []
-        
+
     def render_children_xhtml(self):
         """Render the child nodes as XHTML"""
         return u"".join([child.render_xhtml() for child in self.children])
         BBNode.__init__(self, None)
         self.children = []
         self.allow_inline = allow_inline
-    
+
     def render_xhtml(self):
         """Render the node as XHTML"""
         return self.render_children_xhtml()
     def __init__(self, parent, text):
         BBNode.__init__(self, parent)
         self.text = text
-        
+
     def render_xhtml(self):
         """Render the node as XHTML"""
         return escape(self.text)
         """Add a text node to the current node"""
         # escaped=True for text that has been wrapped in extra []
         # to stop interpretation as bbcode
-        
+
         if escaped:
             text_class = BBEscapedTextNode
         else:
             elif (self.current_node == self.root_node or \
                 self.current_node.bbtag.name in _BLOCK_LEVEL_TAGS) and\
                 not new_tag.implicit_tag is None:
-                
+
                 # E.g. [*] inside root, or [*] inside [quote]
                 # or inline inside root
                 # Add an implicit tag if possible
                 self.descend()
 
     def close_tag_node(self, name):
-        """Pop the stack back to the first node with the 
+        """Pop the stack back to the first node with the
         specified tag name, and 'close' that node."""
         temp_node = self.current_node
         while True:
     def _prepare(self, bbcode):
         # Replace newlines with 'soft' brs
         bbcode = bbcode.replace(u"\n", u'[softbr]')
-        
+
         # Replace emoticons with context-sensitive emoticon tags
         bbcode = _emoticon_replacer.replace(bbcode)
         return bbcode
             if not match is None:
                 # push all text up to the start of the match
                 self.push_text_node(bbcode[pos:match.start()])
-                
+
                 # push the tag itself
                 tagname = match.groups()[0]
                 parameter = match.groups()[1]
                 # push all remaining text
                 self.push_text_node(bbcode[pos:])
                 pos = len(bbcode)
-        
+
     def render_xhtml(self):
         """Render the parsed tree as XHTML"""
         return self.root_node.render_xhtml()
-        
+
     def render_bbcode(self):
         """Render the parsed tree as corrected BBCode"""
         return self.root_node.render_bbcode()
     parser = BBCodeParser(root_allows_inline)
     parser.parse(bbcode)
     return parser.render_xhtml()
-    
+
 def correct(bbcode):
     "Renders corrected bbcode"
     parser = BBCodeParser(True)

cciw/cciwmain/templatetags/forums.py

 def bb2html(value):
     """Converts message board 'BB code'-like formatting into HTML"""
     return bbcode.bb2xhtml(value, True)
-    
+
 register = template.Library()
 register.filter('bb2html', lambda s: mark_safe(bb2html(s)))
 
 def poll_vote_box(request, topic, poll, heading_level):
     """Displays a box for voting in a poll.  The request,
     the topic object and the poll object must be passed in."""
-    
+
     member = get_current_member()
     context = {
         'poll': poll,

cciw/cciwmain/templatetags/standardpage.py

 
 def do_email(parser, token):
     """
-    Obfuscates the email address between the 
+    Obfuscates the email address between the
     'email' and 'endemail' tags.
     """
     nodelist = parser.parse(('endemail',))
     def render(self, context):
         user_name = self.nodelist.render(context)
         return get_member_link(user_name)
-    
+
 def do_member_link(parser, token):
     """
-    Creates a link to a member, using the member name between the 
+    Creates a link to a member, using the member name between the
     'memberlink' and 'endmemberlink' tags.
     """
     nodelist = parser.parse(('endmemberlink',))
     parser.delete_first_token()
     return MemberLinkNode(nodelist)
-    
+
 class MemberIconNode(template.Node):
     def __init__(self, nodelist):
         self.nodelist = nodelist
     def render(self, context):
         user_name = self.nodelist.render(context)
         return get_member_icon(user_name)
-    
+
 def do_member_icon(parser, token):
     """
-    Creates an <img> tag for a member icon, using the member name between the 
+    Creates an <img> tag for a member icon, using the member name between the
     'membericon' and 'endmembericon' tags.
     """
     nodelist = parser.parse(('endmembericon',))
     parser.delete_first_token()
     return MemberIconNode(nodelist)
 
-    
+
 class SetVarNode(template.Node):
     def __init__(self, varname, varval):
         self.varname = varname
         context[self.varname] = template.resolve_variable(self.varval, context)
         return ''
 
-        
+
 def do_setvar(parser, token):
     """
-    Sets a variable in the context.  The first argument 
+    Sets a variable in the context.  The first argument
     must be the variable name, the second the variable value
     as a literal or a variable."""
     bits = token.contents.split(" ", 2)
 class RenderHtmlChunk(template.Node):
     def __init__(self, chunk_name):
         self.chunk_name = chunk_name
-        
+
     def render(self, context):
         chunk = getattr(self, 'chunk', None)
         if chunk is None:
             chunk = HtmlChunk.objects.get(name=self.chunk_name)
             self.chunk = chunk
         return chunk.render(context['request'])
-    
+
 def do_htmlchunk(parser, token):
     """
     Renders an HtmlChunk. It takes a single argument,
             % {'url': context['request'].path, 'title': title }
         else:
             return u''
-            
+
 class AtomFeedLinkVisible(template.Node):
     def __init__(self, parser, token):
         pass
         if title:
             thisurl = context['request'].path
             thisfullurl = 'http://%s%s' % (get_current_domain(), thisurl)
-            return (u'<a class="atomlink" href="%(atomurl)s" rel="external" title="%(atomtitle)s" >' + 
+            return (u'<a class="atomlink" href="%(atomurl)s" rel="external" title="%(atomtitle)s" >' +
                     u' <img src="%(atomimgurl)s" alt="Feed icon" /></a> ' +
                     u' <a href="/website/feeds/" title="Help on Atom feeds">?</a> |' +
                     u' <a class="atomlink" href="%(emailurl)s" rel="external" title="Subscribe to this page by email">' +
                     u' <img src="%(emailimgurl)s" alt="Email icon" /></a> ' +
                     u' <a href="/website/feeds/#emailupdates" title="Help on Email updates">?</a> |') \
-            % dict(atomurl="%s?format=atom" % thisurl, 
-                   atomtitle=title, 
+            % dict(atomurl="%s?format=atom" % thisurl,
+                   atomtitle=title,
                    atomimgurl="%s/images/feed.gif" % settings.MEDIA_URL,
                    emailurl=escape("http://www.rssfwd.com/rssfwd/preview?%s" % urlencode({'url':thisfullurl, 'submit url':'Submit'})),
                    emailimgurl="%s/images/email.gif" % settings.MEDIA_URL
     """
     Renders a list of tag summaries for an object, with links to
     full details.
-    
+
     Example::
-    
+
         {% tag_summary_list for post %}
     """
     tokens = token.contents.split()
 class AddTagLink(template.Node):
     def __init__(self, target_var_name):
         self.target_var_name = target_var_name
-        
+
     def render(self, context):
         target = template.resolve_variable(self.target_var_name, context)
         request = context['request'] # requires request to be in the context
         model_name = target.__class__.__name__.lower()
         model_id = tagging_utils.get_pk_as_str(target)
-        
+
         return u'<a class="addtag" href="/edit_tag/%s/%s/?r=%s" title="Add/edit tags for this %s">+</a>' % \
                 (model_name, model_id, escape(urlquote(request.get_full_path())), model_name)
 
 def do_add_tag_link(parser, token):
     """
     Renders a link for adding a tag to an object
-    
+
     Syntax::
-    
+
         {% add_tag_link for [object] %}
-        
+
     Example usage::
-        
+
         {% add_tag_link for post %}
     """
     tokens = token.contents.split()

cciw/cciwmain/templatetags/test_bbcode.py

 import os
 
 import bbcode
-from cciw.cciwmain.utils import get_member_link   
+from cciw.cciwmain.utils import get_member_link
 
 
 tests = (
     ('<test&',
         '<div>&lt;test&amp;</div>'),
-    ('[b]Incorrectly [i]nested tags[/b] must be dealt with[/i]', 
+    ('[b]Incorrectly [i]nested tags[/b] must be dealt with[/i]',
         '<div><b>Incorrectly <i>nested tags</i></b> must be dealt with</div>'),
-    ('[quote]this must be in a div[/quote]', 
+    ('[quote]this must be in a div[/quote]',
         '<blockquote><div>this must be in a div</div></blockquote>'),
-    ('Newlines\nconverted\n\nto brs', 
+    ('Newlines\nconverted\n\nto brs',
         '<div>Newlines<br/>converted<br/><br/>to brs</div>'),
-    ('[list][br][*]brs discarded when illegal', 
+    ('[list][br][*]brs discarded when illegal',
         '<ul><li>brs discarded when illegal</li></ul>'),
-    ('[list]\n[*]Newlines not discarded, or converted when brs would be illegal', 
+    ('[list]\n[*]Newlines not discarded, or converted when brs would be illegal',
         '<ul>\n<li>Newlines not discarded, or converted when brs would be illegal</li></ul>'),
-    ('[quote]\nNewlines not discarded at beginning of quote', 
+    ('[quote]\nNewlines not discarded at beginning of quote',
         '<blockquote>\n<div>Newlines not discarded at beginning of quote</div></blockquote>'),
     (u'[list]Text in root of list tag is moved outside[*]and put in a div é[/list]',
         u'<div>Text in root of list tag is moved outside<ul><li>and put in a div é</li></ul></div>'),
     ('0:-)',
         '<div><img src="' + bbcode.EMOTICONS_ROOT + 'angel.gif" alt="0:-)" /></div>' ),
     ('[code]:-) :bosh:[/code]',
-        '<pre class="code">:-) :bosh:</pre>'),    
+        '<pre class="code">:-) :bosh:</pre>'),
     ('[url]/foo/?a=1&b=2[/url]',
         '<div><a href="/foo/?a=1&amp;b=2">/foo/?a=1&amp;b=2</a></div>'),
     ('[url=/foo/?a=1&b=2]bar[/url]',
     # text that is accidentally similar to escaping:
     ('[[b]Just some bold text in square brackets[/b]]',
         '<div>[<b>Just some bold text in square brackets</b>]</div>'),
-    
+
     # non-existant tags come through as literals
-    (u'[nonéxistanttag]',    
+    (u'[nonéxistanttag]',
         u'<div>[nonéxistanttag]</div>'),
     # empty string should return nothing
     ('',
 
 def check_xhtml(bb, xhtml):
     assert bbcode.bb2xhtml(bb) == xhtml
-    
+
 def test_render_xhtml():
     for bb, xhtml in tests:
         yield check_xhtml, bb, xhtml

cciw/cciwmain/templatetags/view_extras.py

 
 def page_link(request, page_number, fragment = ''):
     """
-    Constructs a link to a specific page using the request.  
+    Constructs a link to a specific page using the request.
     Returns HTML escaped value
     """
     return html.escape(modified_query_string(request, {'page': unicode(page_number)}, fragment))
 class PagingControlNode(template.Node):
     def __init__(self, fragment = ''):
         self.fragment = fragment
-        
+
     def render(self, context):
         # context has been populated by
         # generic view paging mechanism
         cur_page = int(context['page'])
         total_pages = int(context['pages'])
         request = context['request']
-        
+
         output = []
         if (total_pages > 1):
             output.append(u"&mdash; Page %d  of %d &mdash;&nbsp;&nbsp; " %
                 (cur_page, total_pages))
-            
+
             # Constraints:
             # - Always have: first page, last page, next page, previous page
             # - Never have more than about 10 links
             #    show links at 10 page intervals.
 
             # Initial set
-            pages = set(p for p in range(cur_page - 2, cur_page + 3) 
+            pages = set(p for p in range(cur_page - 2, cur_page + 3)
                             if p >= 1 and p <= total_pages)
             pages.add(1)
             pages.add(total_pages)
-            
+
             # Add some more at intervals
             # Ensure that if we are using ellipses, we don't
             # get any adjacent numbers since that looks odd.
                     output.append(u" ")
                 if i > last_page + 1:
                     output.append(u"&hellip; ")
-                    
+
                 if i == cur_page:
                     output.append(u'<span class="pagingLinkCurrent">%s</span>' % unicode(i))
                 else:
             else:
                 output.append(u'<span class="pagingLinkCurrent">&raquo;</span>')
         return u''.join(output)
-        
-        
+
+
 
 def do_paging_control(parser, token):
     """
-    Creates a list of links to the pages of a generic view. The paging control 
+    Creates a list of links to the pages of a generic view. The paging control
     requires that the request object be in the context as 'request'
-    
-    An optional parameter can be used which contains the fragment to use for 
+
+    An optional parameter can be used which contains the fragment to use for
     paging links, which allows paging to skip any initial common content on the page.
-    
+
     Usage::
 
         {% paging_control %}
     return EarlierLaterNode()
 
 class SortingControlNode(template.Node):
-    def __init__(self, ascending_param, descending_param, 
+    def __init__(self, ascending_param, descending_param,
                  ascending_title, descending_title):
         self.ascending_param = ascending_param
         self.descending_param = descending_param
         self.ascending_title = ascending_title
         self.descending_title = descending_title
-    
+
     def render(self, context):
         request = context['request']
         output = u'<span class="sortingControl">'
                 current_order = context['default_order']
             except KeyError:
                 current_order = u''
-        
+
         if current_order == self.ascending_param:
             output += u'<a title="%s" href="%s">' % (self.descending_title, html.escape(modified_query_string(request, {'order': self.descending_param}))) + \
-                u'<img class="sortAscActive" src="%s/images/arrow-up.gif" alt="Sorted ascending" /></a>' % settings.CCIW_MEDIA_URL  
+                u'<img class="sortAscActive" src="%s/images/arrow-up.gif" alt="Sorted ascending" /></a>' % settings.CCIW_MEDIA_URL
         elif current_order == self.descending_param:
             output += u'<a title="%s" href="%s">' % (self.ascending_title, html.escape(modified_query_string(request, {'order': self.ascending_param}))) + \
                 u'<img class="sortDescActive" src="%s/images/arrow-down.gif" alt="Sorted descending" /></a>' % settings.CCIW_MEDIA_URL
             # query string resets page to zero if we use a new type of sorting
             output += u'<a title="%s" href="%s">' % (self.ascending_title, html.escape(modified_query_string(request, {'order': self.ascending_param, 'page': 1}))) + \
                 u'<img class="sortAsc" src="%s/images/arrow-up.gif" alt="Sort ascending" /></a>' % settings.CCIW_MEDIA_URL
-        
+
         output += u'</span>'
         return output
-        
+
 
 def do_sorting_control(parser, token):
     """
     Creates a pair of links that are used for sorting a list on a field.
-    Four parameters are accepted, which must be the query string parameter values that 
+    Four parameters are accepted, which must be the query string parameter values that
     should be used for ascending and descending sorts on a field, and the corresponding
     title text for those links (in that order). All arguments must be quoted with '"'
-    
+
     The query string parameter name is always 'order', and the view function
     will need to check that parameter and adjust accordingly.  The view function
-    should also add 'default_order' to the context, which allows the 
+    should also add 'default_order' to the context, which allows the
     sorting control to determine what the current sort order is if no
     'order' parameter exists in the query string.
-    
-    The sorting control requires that the request object be in the context 
-    as 'request'. (It is used for various things, including passing on 
+
+    The sorting control requires that the request object be in the context
+    as 'request'. (It is used for various things, including passing on
     other query string parameters in the generated URLs.)
-    
+
     Usage::
-    
+
         {% sorting_control "ad" "dd" "Sort date ascending" "Sort date descending" %}
-        
+
     """
     bits = token.contents.split('"')
     if len(bits) != 9:
         return u'<div><input type="hidden" name="%s" value="%s" /></div>' % \
                (self.param_name, html.escape(request.GET.get(self.param_name, '')))
 
-        
+
 # forward_query_param - turn a param in query string into a hidden
 # input field.  Needs to be able to get the request object from the context
 def do_forward_query_param(parser, token):
     Turns a parameter in a query string into a hidden input field,
     allowing it to be 'forwarded' as part of the next request in
     a form submission.  It requires one argument (the name of the parameter),
-    and also requires that the request object be in the context as 
+    and also requires that the request object be in the context as
     by putting the standard 'pagevars' object in the context.
     """
     try:
     param_name = param_name.strip('"')
     return ForwardQueryParamNode(param_name)
 
-register = template.Library()    
+register = template.Library()
 register.tag('paging_control', do_paging_control)
 register.tag('earlier_later', do_ealier_later)
 register.tag('sorting_control', do_sorting_control)

cciw/cciwmain/tests/client.py

         }
         if post_data is not None:
             form_data[cciw.cciwmain.decorators.LOGIN_FORM_POST_DATA_KEY] = post_data
-        
+
         return form_data
 
     def member_login(self, membername, password, **extra):
         Does a member login, setting the cookies that are needed.
         """
         path = '/login/'
-        
+
         response = self.post(path, data=self.get_member_login_data(membername, password))
         if response.status_code != 302: # Expect a redirect on successful login
             raise Exception("Failed to log in")

cciw/cciwmain/tests/decorators.py

 
 
 # Test our decorators, which are quite complex.
-# We use existing views which have the different 
+# We use existing views which have the different
 # decorators
 
 def _get_login_post_data(response):
     bs = BeautifulSoup(response.content)
     inp = bs.find(name='input', attrs={'name': LOGIN_FORM_POST_DATA_KEY})
-    if inp is None: 
+    if inp is None:
         return inp
     else:
         return inp.attrMap['value']
         self.assert_(LOGIN_FORM_KEY in r.content, "Should get a login form.")
 
     def test_get_logged_in(self):
-        self.client.member_login(members.TEST_POLL_CREATOR_USERNAME, 
+        self.client.member_login(members.TEST_POLL_CREATOR_USERNAME,
                                  members.TEST_POLL_CREATOR_PASSWORD)
         r = self.client.get(ADD_POLL_URL)
         self.assert_(LOGIN_FORM_KEY not in r.content, "Should not get a login form.")
         """Ensure that when we start with a GET request and have to log in, the view ultimately receives a 'GET' request, not a 'POST'"""
         r = self.client.get(ADD_POLL_URL)
 
-        data = self.client.get_member_login_data(members.TEST_POLL_CREATOR_USERNAME, 
+        data = self.client.get_member_login_data(members.TEST_POLL_CREATOR_USERNAME,
                                                  members.TEST_POLL_CREATOR_PASSWORD,
                                                  post_data = _get_login_post_data(r))
         r2 = self.client.post(ADD_POLL_URL, data=data)
         orig_data = {'some':'random_data', 'details':'dont matter'}
         r = self.client.post(ADD_POLL_URL, data=orig_data)
 
-        data = self.client.get_member_login_data(members.TEST_POLL_CREATOR_USERNAME, 
+        data = self.client.get_member_login_data(members.TEST_POLL_CREATOR_USERNAME,
                                                  members.TEST_POLL_CREATOR_PASSWORD,
                                                  post_data = _get_login_post_data(r))
         r2 = self.client.post(ADD_POLL_URL, data=data)
         # which is good enough for now.
         orig_request2 = get_context_var(r2.context, 'request')
         self.assertEqual(orig_request2.method, 'POST', "Should reproduce a 'POST' method")
-        self.assertEqual(sorted(orig_request2.POST.items()), 
-                         sorted(orig_data.items()), 
+        self.assertEqual(sorted(orig_request2.POST.items()),
+                         sorted(orig_data.items()),
                          "Original post data should be present")
 
-        # Also, validation should have been done, so context should 
+        # Also, validation should have been done, so context should
         # have an 'errors' value
         form = get_context_var(r2.context, 'form')
         self.assertNotEqual(form.errors, {}, "Page should have done some validation")

cciw/cciwmain/tests/forums.py

 from cciw.cciwmain.tests.client import CciwClient
-from cciw.cciwmain.tests.members import TEST_MEMBER_USERNAME, TEST_MEMBER_PASSWORD, TEST_POLL_CREATOR_USERNAME, TEST_POLL_CREATOR_PASSWORD 
+from cciw.cciwmain.tests.members import TEST_MEMBER_USERNAME, TEST_MEMBER_PASSWORD, TEST_POLL_CREATOR_USERNAME, TEST_POLL_CREATOR_PASSWORD
 from django.test import TestCase
 from cciw.cciwmain.models import Topic, Member, Poll
 from django.core.urlresolvers import reverse
 
 FORUM_1_YEAR = 2000
 FORUM_1_CAMP_NUMBER = 1
-ADD_POLL_URL =  reverse("cciwmain.camps.add_poll", 
+ADD_POLL_URL =  reverse("cciwmain.camps.add_poll",
                         kwargs=dict(year=FORUM_1_YEAR, number=FORUM_1_CAMP_NUMBER))
 
 class TopicPage(TestCase):
 
     def setUp(self):
         self.client = CciwClient()
-        
+
     def path(self):
         return Topic.objects.get(id=1).get_absolute_url()
 
     def test_topic_html(self):
         response = self.client.get(self.path())
         self.failUnlessEqual(response.status_code, 200)
-        self.assert_("<h2>&lt;Jill &amp; Jane&gt;</h2>" in response.content, 
+        self.assert_("<h2>&lt;Jill &amp; Jane&gt;</h2>" in response.content,
                      "Subject not escaped correctly")
-        self.assert_("A <b>unique message</b> with some bbcode &amp; &lt;stuff&gt; to be escaped" in response.content, 
+        self.assert_("A <b>unique message</b> with some bbcode &amp; &lt;stuff&gt; to be escaped" in response.content,
                      "Posts not escaped correctly")
-        self.assert_('<a href="/camps/">Forums and photos</a>' in response.content, 
+        self.assert_('<a href="/camps/">Forums and photos</a>' in response.content,
                      "Breadcrumb not escaped properly")
 
     def test_topic_atom(self):
             rules="0",
             rule_parameter="1",
             )
-    def test_cant_create_poll_if_anonymous(self):        
+    def test_cant_create_poll_if_anonymous(self):
         response = self.client.get(ADD_POLL_URL)
         # response should be a login form
         self.assert_(decorators.LOGIN_FORM_KEY in response.content)
             p = Poll.objects.get(title=poll_data['title'])
         except Poll.ObjectDoesNotExist:
             self.fail("Poll not created.")
-        
+
         self.assertEqual(p.intro_text, poll_data['intro_text'])
         self.assertEqual(p.poll_options.count(), 4, "Poll does not have right number of options created")
 
     def test_cant_edit_someone_elses_poll(self):
-        p = Poll(title="test", 
-                 voting_starts=datetime.now(), 
+        p = Poll(title="test",
+                 voting_starts=datetime.now(),
                  voting_ends=datetime.now(),
                  rules = 0,
                  rule_parameter=1,
         p.save()
 
         self.client.member_login(TEST_POLL_CREATOR_USERNAME, TEST_POLL_CREATOR_PASSWORD)
-        url = reverse("cciwmain.camps.edit_poll", 
-                      kwargs=dict(year=FORUM_1_YEAR, 
+        url = reverse("cciwmain.camps.edit_poll",
+                      kwargs=dict(year=FORUM_1_YEAR,
                                   number=FORUM_1_CAMP_NUMBER,
                                   poll_id=p.id))
         response = self.client.get(url)

cciw/cciwmain/tests/htmlchunks.py

 from cciw.cciwmain.tests.client import CciwClient
 from django.test import TestCase
 
-class HtmlChunkPage(TestCase):    
+class HtmlChunkPage(TestCase):
     fixtures = ['basic.yaml', 'users.yaml', 'htmlchunks.yaml']
 
     def setUp(self):
 
     def _test_page(self, should_see_edit_link):
         response = self.client.get('/')
-        self.assert_('<p>CCIW is a charitable company' in response.content, 
+        self.assert_('<p>CCIW is a charitable company' in response.content,
                      "HtmlChunk not visible or not escaped properly")
         if should_see_edit_link:
             self.assert_("Edit home_page" in response.content,

cciw/cciwmain/tests/members.py

 # created by fixture
 TEST_MEMBER_USERNAME = 'test_member_1'
 TEST_MEMBER_PASSWORD = 'password'
-TEST_MEMBER_EMAIL = 'test@test.com' 
+TEST_MEMBER_EMAIL = 'test@test.com'
 
 TEST_POLL_CREATOR_USERNAME = 'test_poll_creator_1'
 TEST_POLL_CREATOR_PASSWORD = 'password'
         post_data['icon'] = f
         resp = self.client.post(MEMBER_ADMIN_URL, data=post_data)
         f.close()
-        return resp        
+        return resp
 
     def test_upload_icon(self):
         new_icon = os.path.join(settings.TEST_DIR, TEST_MEMBER_USERNAME + ".png")
         # get length of file, used for heuristic
         fs = _get_file_size(new_icon)
-        self.failIfEqual(fs, 0, "something has happened to %s" % new_icon) 
+        self.failIfEqual(fs, 0, "something has happened to %s" % new_icon)
 
         # ensure the file isn't there already
         _remove_member_icons(TEST_MEMBER_USERNAME)
 
     def _assert_icon_upload_fails(self, filename):
         new_icon = os.path.join(settings.TEST_DIR, filename)
-        
+
         # ensure the file isn't there already
         _remove_member_icons(TEST_MEMBER_USERNAME)
 
         url, path, querydata = self._read_email_change_email(mail.outbox[0])
         resp2 = self.client.get(path, querydata)
         self.failUnlessEqual(resp.status_code, 200)
-        
+
         m = Member.objects.get(user_name=TEST_MEMBER_USERNAME)
         self.assertEqual(m.email, data['email'])
 
         _remove_member_icons(TEST_MEMBER_USERNAME)
 
 def url_to_path_and_query(url):
-    scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)    
+    scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
     querydata_t = cgi.parse_qs(query)
     querydata = {}
     for key, val in querydata_t.items():
         post_data = dict(submit_email='Submit', email=TEST_MEMBER_EMAIL)
         response = self.client.post(MEMBER_SIGNUP, data=post_data)
         self.failUnlessEqual(response.status_code, 200)
-   
+
         self.assert_("already used" in response.content,
                      "Signing up should not allow an existing email to be reused")
         self.assertEqual(len(mail.outbox), 0)
         post_data = dict(submit_email='Submit', email=NEW_MEMBER_EMAIL)
         response = self.client.post(MEMBER_SIGNUP, data=post_data)
         self.failUnlessEqual(response.status_code, 200)
-   
+
         self.assert_("an e-mail has been sent" in response.content,
                      "An message saying that an email has been sent should be seen")
         self.assertEqual(len(mail.outbox), 1, "An email should be sent")

cciw/cciwmain/tests/news.py

 from django.test import TestCase
 from cciw.cciwmain.models import Topic
 
-class NewsPage(TestCase):    
+class NewsPage(TestCase):
     fixtures = ['basic.yaml', 'test_members.yaml', 'news.yaml']
 
     def setUp(self):
         topic = Topic.objects.get(id=1)
         response = self.client.get(topic.forum.get_absolute_url(), {'format':'atom'})
         self.assertEqual(response.status_code, 200)
-        
+
         self.assert_("Bits &amp; Pieces" in response.content,
                      "Subject not present or not escaped properly")
 
 
         self.assert_("Fish &amp; Chips" in response.content,
                      "Subject not present or not escaped properly")
-        
+
         self.assert_("&lt;p&gt;Full item with &lt;i&gt;html" in response.content,
                      "HTML content not present or not escaped properly")

cciw/cciwmain/tests/sites.py

 from django.test import TestCase
 from cciw.cciwmain.models import Site
 
-class SitePage(TestCase):    
+class SitePage(TestCase):
     fixtures = ['basic.yaml', 'sites.yaml']
 
     def setUp(self):

cciw/cciwmain/tests/twillhelpers.py

         tc.go(make_django_url("cciw.officers.views.index"))
         tc.fv(1, 'id_username', creds[0])
         tc.fv(1, 'id_password', creds[1])
-        tc.submit()        
+        tc.submit()
 
     def tearDown(self):
         twill_teardown()