# -*- coding: utf-8
# $Id$
#
# Copyright 2005 by IVA Team and contributors
#
# This file is part of IVA.
#
# IVA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# IVA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with IVA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
__version__ = "$Revision$"[11:-2]
from common import translate
import AccessControl
import OFS, Globals
from OFS import SimpleItem
import types
import time
from TraversableWrapper import Traversable
from Globals import Persistent
from AccessControl import ClassSecurityInfo
from Cruft import Cruft
from common import perm_view, perm_edit
from input_checks import strip_tags, strip_all, normal_entry_tags_and_link
from Products.ZCatalog.CatalogPathAwareness import CatalogAware
### Container for blog
#########################
class Blog(
OFS.Folder.Folder,
OFS.SimpleItem.Item,
Persistent,
AccessControl.Role.RoleManager,
Traversable,
Cruft
):
""" Container for a blog """
meta_type = "Blog"
security = ClassSecurityInfo()
security.declareObjectProtected('View')
entryID = 0
def manage_afterAdd(self, item, container):
""" give Change permission permission to Owner and Teacher """
item.manage_permission('Change permissions', ('Owner', 'Teacher',), 1)
def getTimeAsText(self, REQUEST, tiime):
"Displays nice time, translated as timestamp_format"
return time.strftime(translate(self,'timestamp_format',default="%H:%M %Y-%m-%d",target=self.giveLanguage(REQUEST)), time.localtime(tiime))
def course_id_from_url(self, REQUEST):
"Extract course id from webtop course folder: /fle_users/uname/webtop/cID/Blog/"
url = self.absolute_url()
start = url.find('/webtop/c')
if start>0:
stop = url.find('/',start+9)
return int(url[start+9:stop])
return -1
def __init__(self, id=''):
"Initialize Blog"
if id:
self.id = id
else:
self.id = 'Blog'
security.declareProtected(perm_view,'get_name')
def get_name(self):
"Get my name, for Leivapururiba"
return "Blog"
def get_author(self):
"""Return author (owner) of this item."""
return self.getOwnerTuple()[1]
security.declareProtected(perm_view,'isOwner')
def isOwner(self,REQUEST,user=False):
"Wether authenticated user is the owner of this blog or teacher, when this is course blog"
x = self.absolute_url()
if x.find('/fle_users/')>0:
return self.kasutajaNimi(REQUEST)==str(REQUEST.AUTHENTICATED_USER)
if x.find('/courses/')>0 and user:
return user.has_role(('Manager','IVAAdmin','Teacher',),self)
return False
security.declareProtected(perm_view,'getNumberOfEntries')
def getNumberOfEntries(self):
""" Number of entries in blog """
return len(self.objectValues('Blog'))
security.declareProtected(perm_view,'getEntries')
def getEntries(self,nr=0):
"Array with all entries in the blog"
objects = self.objectValues('Blog')
objects.reverse()
if nr>0:
return objects[:nr]
return objects
security.declareProtected(perm_view,'getArchiveEntries')
def getArchiveEntries(self,REQUEST):
"Array with entries from specified month"
month = REQUEST.get('month', None)
if month is None:
return []
entries = self.getEntries()
result = []
for x in entries:
if time.strftime("%m.%Y",time.localtime(x.getTime()))==month:
result.append(x)
return result
security.declareProtected(perm_view,'getEntriesArchive')
def getEntriesArchive(self,REQUEST):
"Array with entries archive data"
months = ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')
entries = self.getEntries()
archive = []
pmonth = ""
for x in entries:
month = time.strftime('%m.%Y',time.localtime(x.getTime()))
if month != pmonth:
pmonth = month
archive.append([month,months[int(month[:2])-1],month[-4:]])
return archive
security.declareProtected(perm_edit,'addEntry')
def addEntry(self, REQUEST=None, title='', intro='', content='', userLocation='', author='', ch_time=None, mod_time=None):
""" Data from addEntryForm """
if not author:
author = str(REQUEST.AUTHENTICATED_USER)
k=Entry(author, title,intro,content, ch_time, mod_time)
self.entryID += 1
k.id = "entry"+str(self.entryID)
self._setObject(k.id, k)
if REQUEST:
return REQUEST.RESPONSE.redirect(self.absolute_url()+"?userLocation="+userLocation)
return getattr(self, k.id)
security.declarePublic('rss')
def rss(self, REQUEST):
"Blogs RSS feed version 2.0"
REQUEST.RESPONSE.setHeader("Content-type","text/xml")
t = """\n"""
t += """\n"""
t += "\t\n"
# Create RSS channel description
cid = self.course_id_from_url(REQUEST)
cname = ""
description = ""
userLocation = ""
uname = self.kasutajaNimi(REQUEST)
url = self.absolute_url()
if cid>0: #We are on somebodys webtop -> course nr cid
cattr = getattr(self.fle_root().courses, str(cid))
cname = str(cattr.get_name())
description = str(cattr.get_description())
userLocation = "Webtop"
else: # It's course blog ...
if url.find('/courses/')>0:
cname = str(self.parent().get_name())
description = str(self.parent().get_description())
userLocation = "Bookshelf"
else: # ... or personal one
description = self.firstAndLast(uname)
userLocation = "Organizer"
t += "\t\t"+description+"\n"
# Create RSS channel title
titel = "IVA Blog"
if uname!="":
titel += ": "+self.firstAndLast(uname)
if cname!="":
titel += " @ "+cname
t += "\t\t"+titel+"\n"
t += "\t\t"+self.absolute_url()+"?userLocation="+userLocation+"\n"
#Create RSS channel image
url = ""
if cname=="":
if self.parent().has_photo:
url = self.parent().get_photo_url()
else:
if cid<=0:
if self.parent().hasLogo():
url = self.parent().getLogoURL()
#url = self.parent().absolute_url()+"/kysiLogo"
else:
if cattr.hasLogo():
url = cattr.getLogoURL()
#url = cattr.absolute_url()+"/kysiLogo"
if url != "": #If we have an image
t += "\t\t\n"
t += "\t\t\t"+url+"\n"
t += "\t\t\t"+titel+"\n"
t += "\t\t\t"+self.absolute_url()+"?userLocation="+userLocation+"\n"
t += "\t\t\n"
# Create RSS channel items - 20 last items
for x in self.getEntries(20):
t += "\t\t\n"
t += "\t\t\t"+x.getTitle()+" ("+str(x.getNumberOfComments())+")\n"
t += "\t\t\t"+x.absolute_url()+"/blog_entry?userLocation="+userLocation+"\n"
t += "\t\t\t"+x.getIntro()+"\n"
t += "\t\t\t"+x.getFormattedTime(REQUEST)+"\n"
t += "\t\t\t"+x.getAuthor()+"\n"
t += "\t\t\t"+x.absolute_url()+"/blog_entry?showComments=1&userLocation="+userLocation+"#Comments\n"
t += "\t\t\t"+x.absolute_url()+"\n"
t += "\t\t\n"
t += "\t\n"
t += "\n"
return t
security.declareProtected(perm_view, 'getNumberOfEntriesOnCourse')
def getNumberOfEntriesOnCourse(self, user_obj, course_id):
""" return a number of user's blog entries on specific course """
cat = getattr(self.fle_root(), 'blogs_zcatalog')
paths = []
bpath = '/'.join(user_obj.getPhysicalPath())+'/webtop/c'+course_id+'/portfolio'
paths.append(bpath)
query = {'getAuthor': user_obj.get_uname(),
'path':paths}
results = cat.search(query)
return len(results)
security.declareProtected(perm_view,'index_html')
def index_html(self, REQUEST, userLocation="Webtop"):
"Blogs index - should be redirected to blogs index page"
page = "blog"
if userLocation=="Bookshelf":
page = "course"
return REQUEST.RESPONSE.redirect(self.absolute_url()+"/"+page+"_index?userLocation="+userLocation)
### Container for blog entry
###############################
class Entry(
OFS.Folder.Folder,
OFS.SimpleItem.Item,
Persistent,
CatalogAware,
AccessControl.Role.RoleManager,
Traversable,
Cruft
):
"Blog entry - a folder, whose attributes are the entry and items are comments"
meta_type = "Blog" #For links in left menu on webtop, Entry is also Blog
security = ClassSecurityInfo()
security.declareObjectProtected('View')
commentID = 0
def __init__(self, author, title, intro, content, creation_time=None, change_time=None):
"Create an entry"
if title=="":
title="Untitled"
self.author = author
self.title = strip_all(title)
self.intro = strip_tags(intro,normal_entry_tags_and_link)
self.content = strip_tags(content,normal_entry_tags_and_link)
if creation_time:
self.time = creation_time
else:
self.time = time.time()
if change_time:
self.changeTime = changeTime
else:
self.changeTime = -1
self.default_catalog = 'blogs_zcatalog'
def manage_afterAdd(self, item, container):
""" index object """
self.index_object()
security.declareProtected(perm_view, 'isEntry')
def isEntry(self):
""" is this blog or entry """
return 1
security.declareProtected(perm_view,'getNumberOfComments')
def getNumberOfComments(self):
"Number of comments for this entry"
return len(self.objectValues('BlogComment'))
def getID(self):
"ID"
return self.id
security.declareProtected(perm_view,'get_name')
def get_name(self):
"Get my name, for Leivapururiba"
return self.title
security.declareProtected(perm_view,'getTitle')
def getTitle(self):
"Title of entry"
return self.title
security.declareProtected(perm_view,'getIntro')
def getIntro(self,formatted=False):
"Entrys intro. Formatted means that \n are replaced with \n. Unformatted is for changeEntryForm"
if formatted:
import re
return re.sub("\n"," \n",self.intro)
return self.intro
security.declareProtected(perm_view,'getContent')
def getContent(self,formatted=False):
"Content of entry. Formatted means that \n are replaced with \n. Unformatted is for changeEntryForm"
if formatted:
import re
return re.sub("\n"," \n",self.content)
return self.content
security.declareProtected(perm_view,'getAuthor')
def getAuthor(self,formatted=False):
""" Author of entry - formatted means first and last rather than user name """
if formatted:
return self.firstAndLast(self.author)
return self.author
security.declareProtected(perm_view,'getTime')
def getTime(self):
"Entry submission time"
return self.time
security.declareProtected(perm_view,'getTime')
def get_timestamp(self):
"Entry submission time"
return self.time
security.declareProtected(perm_view,'getFormattedTime')
def getFormattedTime(self, REQUEST):
"Entry submission time as formatted text"
return self.getTimeAsText(REQUEST, self.time)
security.declareProtected(perm_view,'getComments')
def getComments(self, REQUEST):
"Array with 'count' comments starting from 'start' for this entry"
start = int(REQUEST.get('start',1))-1
count = int(REQUEST.get('count',10))
comments = self.objectValues('BlogComment')
return comments[start:start+count]
security.declarePrivate('getAllComments')
def getAllComments(self):
return self.objectValues('BlogComment')
security.declareProtected(perm_view,'getIntervals')
def getIntervals(self, REQUEST):
"Get comment intervals"
count = int(REQUEST.get('count',10))
intervals = []
nr = self.getNumberOfComments()
for x in range(int(nr/count)+1):
f = x*count+1
l = (x+1)*count
if l>nr:
l = nr
if f<=l:
intervals.append([count, f, l])
return intervals
security.declareProtected(perm_view,'hasBeenChanged')
def hasBeenChanged(self):
"Wether this entry has been changed or not"
return self.changeTime>-1
security.declareProtected(perm_view,'getChangeTime')
def getChangeTime(self):
"Get entry's change time"
return self.changeTime
security.declareProtected(perm_view,'getFormattedChangeTime')
def getFormattedChangeTime(self, REQUEST):
"Get change time as formatted text"
if self.hasBeenChanged():
return self.getTimeAsText(REQUEST,self.changeTime)
return "*"
security.declareProtected(perm_edit,'changeEntry')
def changeEntry(self, REQUEST, title, intro, content, userLocation):
"Change entry"
if title=="":
title = "Untitled"
self.title = strip_all(title)
self.intro = strip_tags(intro,normal_entry_tags_and_link)
self.content = strip_tags(content,normal_entry_tags_and_link)
self.changeTime=time.time()
self.reindex_object()
return REQUEST.RESPONSE.redirect(self.absolute_url()+"/blog_entry?userLocation="+userLocation)
security.declareProtected(perm_view,'addComment')
def addComment(self, REQUEST, title, content, userLocation):
"Add comment to this entry"
c = Comment(str(REQUEST.AUTHENTICATED_USER), title, content)
self.commentID += 1
c.id = "comment"+str(self.commentID)
self._setObject(c.id, c)
self.reindex_object()
return REQUEST.RESPONSE.redirect(self.absolute_url()+"/blog_entry?showComments=1&start="+str(int(self.getNumberOfComments()/10)*10+1)+"&userLocation="+userLocation+"#"+c.id)
security.declareProtected(perm_view,'index_html')
def index_html(self, REQUEST, userLocation="Organizer"):
"Entrys index page"
return REQUEST.RESPONSE.redirect(self.absolute_url()+"/blog_entry?userLocation="+userLocation)
### Container for blog entry comments
########################################
class Comment(
OFS.SimpleItem.Item,
Persistent,
AccessControl.Role.RoleManager,
Traversable,
Cruft,
):
"Comments for entries"
meta_type = "BlogComment"
security = ClassSecurityInfo()
security.declareObjectProtected('View')
def __init__(self, author, title, content):
"Create a comment"
if title=="":
title="Untitled"
self.author = author
self.title = strip_all(title)
self.content = strip_all(content)
self.time = time.time()
def getID(self):
"ID"
return self.id
security.declareProtected(perm_view, 'isEntry')
def isEntry(self):
""" is this not a blog or entry """
return 0
security.declareProtected(perm_view,'getAuthor')
def getAuthor(self,formatted=False):
"Author of comment"
if formatted:
return self.firstAndLast(self.author)
return self.author
security.declareProtected(perm_view,'getTitle')
def getTitle(self):
"Title of comment"
return self.title
security.declareProtected(perm_view,'getContent')
def getContent(self,formatted=False):
"Content of comment. Formatted means that \n is replaced with \n"
if formatted:
import re
return re.sub("\n"," \n",self.content)
return self.content
security.declareProtected(perm_view,'getTime')
def getTime(self):
"Entry submission time"
return self.time
security.declareProtected(perm_view,'getFormattedTime')
def getFormattedTime(self, REQUEST):
"Entry submission time as formatted text"
return self.getTimeAsText(REQUEST, self.time)
security.declareProtected(perm_view,'index_html')
def index_html(self, REQUEST):
"Comments index page"
return REQUEST.RESPONSE.redirect(self.parent().absolute_url())