# -*- coding: utf-8 -*- # (c) Copyright 2005, CodeSyntax <http://www.codesyntax.com> # Authors: Mikel Larreategi <mlarreategi@codesyntax.com> # See also LICENSE.txt """ Bitakora community """ # Zope modules from AccessControl import ClassSecurityInfo import Globals from Globals import HTMLFile # Modules from Localizer from Products.Localizer.Localizer import Localizer from Products.Localizer.MessageCatalog import MessageCatalog from Products.Localizer.LocalContent import LocalContent # ZCatalog from Products.ZCatalog import ZCatalog # CookieCrumbler try: from Products.CookieCrumbler.CookieCrumbler import CookieCrumbler except: from Products.CMFCore.CookieCrumbler import CookieCrumbler # BTreeFolder2 from Products.BTreeFolder2.BTreeFolder2 import BTreeFolder2 from utils import addDTML, addPythonScript, addImage from utils import addFile, fillMessageCatalog import DateTime try: True except: True = 1 False = 0 manage_addBitakoraCommunityForm = HTMLFile('ui/BitakoraCommunity_add', globals()) def manage_addBitakoraCommunity(self, id, admin_mail, REQUEST=None): """ add Bitakora Community """ self._setObject(id, BitakoraCommunity(id, admin_mail)) com = getattr(self, id) com.Catalog.refreshCatalog(1) if REQUEST is not None: return self.manage_main(self, REQUEST) class BitakoraCommunity(BTreeFolder2): """ BTreeFolder2 container for Bitakora community. It will contain blogs and methods for the main page of the community """ meta_type = 'BitakoraCommunity' security = ClassSecurityInfo() security.setPermissionDefault('Manage BitakoraCommunity', ('Manager', )) _properties = ({'id': 'admin_mail', 'type': 'ustring', 'mode': 'w'}, {'id': 'management_page_charset', 'type': 'string', 'mode': 'w'}, {'id': 'title', 'type': 'ustring', 'mode': 'w'}) manage_adminBlogs = HTMLFile('ui/admin_blogs', globals()) manage_adminUsers = HTMLFile('ui/admin_users', globals()) def __init__(self, id, admin_mail): """ Create Bitakora community """ BTreeFolder2.__init__(self, id) self.id = id self.admin_mail = admin_mail self.management_page_charset = 'UTF-8' self.title = u'blog community' self._addLocalizer() self._addCatalog() self._addMethods() self._addTemplates() self._addContent() self._addOthers() self._buildIndexes() def _addLocalizer(self): """ Add Localizer stuff """ try: # old MessageCatalog self._setObject('gettext', MessageCatalog('gettext', '', ('en', 'eu', 'es'))) except: # new MessageCatalog self._setObject('gettext', MessageCatalog('gettext', '', 'en', ['en', 'eu', 'es'])) # fill the gettext with 'es' and 'eu' locales gettext = getattr(self, 'gettext') fillMessageCatalog(gettext) localizer = Localizer('Localizer', ('en',)) localizer._v_hook = 1 self._setObject('Localizer', localizer) def manage_options(self): """ """ options = (BTreeFolder2.manage_options[0],) \ + ({'label': ('Admin'), 'action': 'manage_adminBlogs'}, {'label': ('Users'), 'action': 'manage_adminUsers'}) \ + BTreeFolder2.manage_options[1:] return options def _addOthers(self): """ Add other stuff """ self.manage_addUserFolder() self._setObject('cookie_authentication', CookieCrumbler('cookie_authentication')) def _addCatalog(self): """ Add ZCatalog instance """ self._setObject('Catalog', ZCatalog.ZCatalog('Catalog', 'Catalog')) def _buildIndexes(self): """ Stuff to create Catalog indexes """ # get the Catalog in a BTreeFolder2 way: as if it was a dictionary catalog = self.get('Catalog') # delete any existing indexes for name in catalog.indexes(): catalog.delIndex(name) # add the default indexes for (name, index_type) in [('meta_type', 'FieldIndex'), ('published', 'FieldIndex'), ('date', 'DateIndex'), ('tags', 'KeywordIndex'), ('yearmonth', 'KeywordIndex'), ('postcount', 'FieldIndex'), ('users', 'FieldIndex')]: catalog.addIndex(name, index_type) # delete the default metadata columns for name in catalog.schema(): catalog.delColumn(name) def _addMethods(self): """ method for adding templates, scripts, ... """ dtmls = ['blogs_main', 'column', 'create_blog_form', 'index_html', 'last_posts'] dtmls.extend(['logged_in', 'logged_out', 'login_form', 'entry_body_community']) dtmls.extend(['menu', 'mini_login_form', 'preheader', 'default_template']) dtmls.extend(['standard_html_footer', 'standard_html_header', 'step1', 'step2', 'step3']) dtmls.extend(['step3.done', 'tag_all_html', 'tag_html']) dtmls.extend(['reminder', 'reminder.done', 'changepass']) for dtml in dtmls: addDTML(self, dtml, '', 'ui/communityTemplates/%s' % dtml) scripts = ['step1.do', 'step2.do', 'step3.do', 'tag', 'tagsAndPixels', 'usersBlog', 'logout'] scripts.extend(['reminder.do', 'changepass.do']) for script in scripts: addPythonScript(self, script, 'ui/communityTemplates/%s' % script) ob = getattr(self, script) ob._proxy_roles = ('Manager',) def _addTemplates(self): """ add some CSS and images """ self.manage_addFolder('img') self.manage_addFolder('templates') import os file_path = Globals.package_home(globals()) # just files all = os.listdir(file_path + '/ui/communityTemplates') imgs = [f for f in all if f.endswith('jpg') or f.endswith('gif')] for img in imgs: addImage(self.img, img, 'ui/communityTemplates/%s' % img) files = [f for f in all if f.endswith('css')] for file in files: addFile(self.img, file, 'ui/communityTemplates/%s' % file) for num in range(1, 5): self.templates.manage_addFolder('%s' % num) fol = getattr(self.templates, '%s' % num) addFile(fol, 'blog.css', 'ui/communityTemplates/%s/blog.css' % num) def _addContent(self): """ add some LocalContents for fixed content """ languages = 'en' contents = ['about', 'us', 'contents'] for content in contents: try: #old LocalContent self._setObject(content, LocalContent(content, tuple(languages))) except: # new LocalContent self._setObject(content, LocalContent(content, 'en', tuple(languages))) security.declareProtected('Manage BitakoraCommunity', 'delBlogs') def delBlogs(self, ids=[], REQUEST=None): """ delete selected blogs """ del_users = [] for id in ids: blog = self.get(id) rol = blog.get_local_roles() del_users.extend([user for user, roles in rol]) blog_path = '/'.join(blog.getPhysicalPath()) self.Catalog.uncatalog_object(blog_path) for post in blog.published_posts(size=99999): self.Catalog.uncatalog_object(post.getPath()) self.manage_delObjects(ids) self.delUsers(del_users) if REQUEST is not None: url = REQUEST.HTTP_REFERER.split('?')[0] return REQUEST.RESPONSE.redirect(url + '?msg=%s' % 'Blogs deleted successfully') security.declareProtected('Manage BitakoraCommunity', 'delUsers') def delUsers(self, ids=[], REQUEST=None): """ delete selected blogs """ self.acl_users.userFolderDelUsers(ids) if REQUEST is not None: url = REQUEST.HTTP_REFERER.split('?')[0] return REQUEST.RESPONSE.redirect(url+'?msg=%s' % 'Users deleted successfully') security.declarePublic('cleanHTML') def cleanHTML(self, html): """ clean html from posts """ # Which one is more efficient? # One way... try: from EpozPostTidy import cleanHTML as clean return clean(html) except: # perhaps more efficient but needed for old Zopes # Another way... (from Zopelabs) intag = [False] def chk(c, intag): if intag[0]: intag[0] = (c != '>') return False elif c == '<': intag[0] = True return False return True return ''.join([c for c in html if chk(c, intag)]) security.declarePublic('community') def community(self): """ return the community """ return self security.declarePublic('communityTitle') def communityTitle(self): """ return the title """ return self.title security.declarePublic('communityUrl') def communityUrl(self): """ return the URL of the community """ return self.absolute_url() security.declarePublic('communityLastPosts') def communityLastPosts(self, size=10, start=None): """ The method for getting 'size' published posts""" if start is None: return self.Catalog.searchResults(meta_type='Post', published=1, sort_limit=size, date={'query': DateTime.DateTime(), 'range': 'max'}, sort_on='date', sort_order='descending') else: return self.Catalog.searchResults(meta_type='Post', published=1, date={'query': DateTime.DateTime(), 'range': 'max'}, sort_on='date', sort_order='descending') security.declareProtected('Manage Bitakora', 'migrate_textindexng2') def migrate_textindexng2(self): """ remove all textindeng2 indexes """ from logging import getLogger log = getLogger('migrate_textindexng2') indexes = ['author', 'body', 'excerpt', 'title'] for index in indexes: if index in self.Catalog.indexes(): self.Catalog.manage_delIndex(index) log.info('Deleted %s index' % index) log.info('Deleted TextIndexNG2 indexes') security.declareProtected('Manage Bitakora', 'migrate_to_1_dot_0') def migrate_to_1_dot_0(self): """ migrate to Bitakora 1.0 """ import transaction from logging import getLogger log = getLogger('migrate_to_1_dot_0') self.migrate_textindexng2() for blog in self.objectValues('Bitakora'): log.info('Migrating: %s' % blog.getId()) blog.migrate_to_1_dot_0() transaction.savepoint(optimistic=True) log.info('done') Globals.InitializeClass(BitakoraCommunity)