# -*- coding: utf-8 # Copyright (c) 2008, iCamp Consortium # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. from __future__ import division import simplejson from Products.Five.site.localsite import FiveSite as BaseSite from OFS.Folder import Folder from zope.interface import implements, Interface from Globals import Persistent, InitializeClass from zope.schema.fieldproperty import FieldProperty from zope.component import getUtility from zope.sendmail.interfaces import IMailer from email.MIMEText import MIMEText from email.Header import Header from email.Utils import parseaddr, formataddr from AccessControl import getSecurityManager, ClassSecurityInfo from Persistence.mapping import PersistentMapping import time from StringIO import StringIO from interfaces import ImFolio, IAffordanceManager, IToolsManager, IUsersManager class mFolio(Persistent, Folder): implements(ImFolio) title = FieldProperty(ImFolio['title']) security = ClassSecurityInfo() def __init__(self, *data, **kw): from Products.Five.component import enableSite enableSite(self) # # getter methods # def getAffordances(self, REQUEST): """ get a list of affordances """ am = getUtility(IAffordanceManager) l = am.getAffordances() tmp = [] for a in l: tt = a.title.encode('utf-8') tt = tt.replace("'", "XYZ") tmp.append([a.id, tt]) xx = str(tmp).replace("'", '"') xx = xx.replace("XYZ", "'") return xx def getPerspectiveData(self, REQUEST): """ returns perspective data. """ v = {} uname = REQUEST.get('username') pers = REQUEST.get('perspective', 'default') am = getUtility(IAffordanceManager) userobj = getUtility(IUsersManager).getUser(uname) if userobj is None: return v for a in am.getAffordances(): v[a.id] = userobj.getAffordanceData(pers, a.id) return str(v).replace("'", '"') def getUsersData(self, REQUEST): """ returns users perspective data. similar to tools but instead tools there are users. return str({'userids' : ['vahur', 'pjotr'], 'vahur' : { 'x_title' : 'Vahur', 'x_url' : 'https://vahur.net', 'searching': 5 }, 'pjotr' : { 'x_title' : 'Pjotr', 'x_url' : 'https://pjotr.net', 'searching': 6 } } ).replace("'", '"') """ am = getUtility(IAffordanceManager) um = getUtility(IUsersManager) users = um._getAllUsers() res = {} res['userids'] = [ u.getId() for u in users ] pers = 'default' for u in users: tmp = {} tmp['x_title'] = u.getTitle() tmp['x_url'] = '' for a in am.getAffordances(): tmp[a.id] = u.getAffordanceData(pers, a.id) res[u.getId()] = tmp return str(res).replace("'", '"') def kml_generator(self, REQUEST, name): stack = REQUEST.get('TraversalRequestNameStack') v = self.restrictedTraverse('kml.xml') while stack: n = stack.pop() n = n[:n.index('.')] v.setKMLName(n) return v def getToolsData(self, REQUEST): """ returns perspective data: tool aff1 aff2 aff3 aff4 toolid1 0 2 1 2 1 2 str({'toolids': ['toolid1', 'toolid2'], 'toolid1': { 'x_title':'Flickr', 'x_url': 'http://www.flickr.com', 'Affordance': 8, 'blah': 6, 'ff': 7}, 'toolid2': { 'x_title':'Google', 'x_url': 'http://www.google.com', 'Affordance': 6, 'blah': 8, 'ff': 1} } ).replace("'", '"') """ tm = getUtility(IToolsManager) tools = tm.getTools() affordances = getUtility(IAffordanceManager).getAffordances() res = {} res['toolids'] = tm.getToolIds() um = getUtility(IUsersManager) users = um._getAllUsers() for t in tools: tmp = {} tmp['x_title'] = t.title.encode('utf-8') tmp['x_url'] = t.url.encode('utf-8') for a in affordances: base = t.getAffordanceData(a.id) comb = [base] # average of all users inputs for u in users: v = u.getToolData(t.id, a.id) if v != -1: comb.append(v) combined = sum(comb)/len(comb) tmp[a.id] = float(combined) res[t.id] = tmp return str(res).replace("'", '"') def getToolsCombinedAffordanceData(self, tool, af): um = getUtility(IUsersManager) users = um._getAllUsers() base = tool.getAffordanceData(af.id) comb = [base] for u in users: v = u.getToolData(tool.id, af.id) if v != -1: comb.append(v) combined = sum(comb)/len(comb) return combined # # Data saving methods # def saveUserPerspective(self, REQUEST): """ save user's perspective """ user = getSecurityManager().getUser() pers = REQUEST.get('perspective') uname = REQUEST.get('uname') if uname != str(user): return str({'result': 2, 'msg':'Cannot save this perspective.'}).replace("'", '"') if not pers or not uname: return str({'result': 1, 'msg':'No data.'}).replace("'", '"') um = getUtility(IUsersManager) um.getUser(uname).savePerspective(REQUEST) return str({'result': 0, 'msg':'Saved'}).replace("'", '"') def userinfo_handler(self, REQUEST): """ handle user info change """ fname = REQUEST.get('firstname') lname = REQUEST.get('lastname') email = REQUEST.get('email') if not fname or not lname or not email: return '{"errno":2}' u = getSecurityManager().getUser() uname = None if u is None or u.getUserName() == 'Anonymous User': return '{"errno":3}' uname = u.getUserName() um = getUtility(IUsersManager) # This try: part might not be needed try: user = um.getUser(uname) fullname = ' '.join((fname,lname)) user.title = fullname user.firstname = fname user.lastname = lname user.email = email except: return '{"errno":2}' return '{"errno":0}' # # registration # def register_handler(self, REQUEST): """ handler user's registration """ uname = REQUEST.get('username') fname = REQUEST.get('firstname') lname = REQUEST.get('lastname') email = REQUEST.get('email') if not uname or not fname or not lname or not email: return '{"errno":2}' # all ok from utils import _genPwd exu = self.acl_users.getUserById(uname) if exu is not None: return '{"errno":3}' pwd = _genPwd() self.acl_users._doAddUser(uname, pwd, [], []) mailer = getUtility(IMailer, 'mfolio.smtp') charset = 'utf-8' message = "You have successfully created an account at %s\n" % self.absolute_url() message += 'Your password:'+pwd msg = MIMEText(message.encode('utf-8'), 'plain', charset) msg['From'] = formataddr(('', 'mfolio-dont-reply@htk.tlu.ee')) msg['To'] = formataddr((fname+" "+lname, email)) subject = 'mFolio registration' msg['Subject'] = Header(subject, charset) mailer.send('mfolio-dont-reply@htk.tlu.ee', email, msg.as_string()) # Create user object with prefilled data um = getUtility(IUsersManager) um.createUser(uname, fname, lname, email) return '{"errno":0}' def _setupPAS(self): """ Setup Pluggable Auth Service """ from zExceptions import BadRequest from Products.PluggableAuthService.PluggableAuthService import addPluggableAuthService # PAS try: addPluggableAuthService(self) except BadRequest: pass #cookie auth from Products.PluggableAuthService.plugins.CookieAuthHelper import addCookieAuthHelper try: addCookieAuthHelper(self.acl_users, 'cookie', '', '__ac') except BadRequest: pass self.acl_users.cookie.manage_activateInterfaces(['IExtractionPlugin', 'IChallengePlugin', 'ICredentialsUpdatePlugin', 'ICredentialsResetPlugin']) # acl_users/ZODBUser source from Products.PluggableAuthService.plugins.ZODBUserManager import addZODBUserManager try: addZODBUserManager(self.acl_users, 'users', '') except BadRequest: pass self.acl_users.users.manage_activateInterfaces(['IAuthenticationPlugin', 'IUserEnumerationPlugin', 'IUserAdderPlugin']) # roles from Products.PluggableAuthService.plugins.ZODBRoleManager import addZODBRoleManager try: addZODBRoleManager(self.acl_users, 'roles', '') except BadRequest: pass self.acl_users.roles.manage_activateInterfaces(['IRolesPlugin', 'IRoleEnumerationPlugin', 'IRoleAssignerPlugin']) security.declareProtected('Manage Portal', 'resetDatabase') def resetDatabase(self, REQUEST): """ reset database """ if REQUEST.get("resetButton", None): if REQUEST.get("yes_reset", None): am = getUtility(IAffordanceManager) ids = am.objectIds() for id in ids: am._delObject(id) tm = getUtility(IToolsManager) ids = tm.objectIds() for id in ids: tm._delObject(id) del self.seeds if REQUEST.has_key('noredirect'): return 0 return REQUEST.RESPONSE.redirect('manage.html') security.declareProtected('Manage Portal', 'importCSV') def importCSV(self, REQUEST): """ import a .csv file """ f = REQUEST.get("cvsfile", None) but = REQUEST.get("submitB", None) toolcount = 1 affcount = 1 if but: if not hasattr(self, '_datastore'): self._datastore = PersistentMapping() if REQUEST.get('saveToDisc', None): dc = 1 while self._datastore.has_key(dc): dc = dc + 1 self._datastore[dc] = { 'order': dc, 'timstamp': time.time(), 'filename': f.filename, 'data': f.read()} f.seek(0) if REQUEST.get('savedID', None): self.resetDatabase({'noredirect': True, 'resetButton': 'Reset', 'yes_reset': 'yes'}) f = StringIO(self._datastore[int(REQUEST.get('savedID', None))]['data']) f.seek(0) # import from Tool import Tool from Affordance import Affordance import zope from interfaces import IAffordance tm = getUtility(IToolsManager) am = getUtility(IAffordanceManager) lines = f.readlines() if len(lines) == 1: lines = lines[0].split('\r') headraw = lines.pop(0) head = headraw.split('\t') head.pop(0) second = head.pop(0) skipsecond = True if second.lower() != 'url': skipsecond = False head.insert(0, second) affs = [] for h in head: while hasattr(am, 'af'+str(affcount)): affcount = affcount + 1 a = Affordance('af'+str(affcount), h.strip()) a.id = 'af'+str(affcount) affs.append(a.id) am._setObject('af'+str(affcount), a) sch = zope.schema.getFields(IAffordance) ttle = sch.get('title') ttle.set(a, h.strip()) for t in lines: while hasattr(tm, 'tool'+str(toolcount)): toolcount = toolcount + 1 tvs = t.split('\t') toolname = tvs.pop(0).strip() toollink = '' if skipsecond: toollink = tvs.pop(0) tool = Tool('tool'+str(toolcount), toolname) tool.url = toollink tm._setObject('tool'+str(toolcount), tool) for aff in range(0,len(affs)): cvb = float(tvs[aff])*10 tool.setAffordanceData(affs[aff], cvb) return REQUEST.RESPONSE.redirect('manage.html') InitializeClass(mFolio) def added(obj, event): # add portal_skins from OFS.Folder import manage_addFolder # add folders #sm = obj.getSiteManager() from zope.component import queryMultiAdapter from zope.interface import Interface components_view = queryMultiAdapter((obj, obj.REQUEST), Interface, 'components.html') components_view.makeSite() sm = obj.getSiteManager() from AffordanceManager import AffordanceManager from UsersManager import UsersManager from ToolsManager import ToolsManager # add affordances folder am = AffordanceManager() obj._setObject(am.id, am) sm.registerUtility(getattr(obj, am.id), IAffordanceManager) # add tools folder tm = ToolsManager() obj._setObject(tm.id, tm) sm.registerUtility(getattr(obj, tm.id), IToolsManager) # add users folder um = UsersManager() obj._setObject(um.id, um) sm.registerUtility(getattr(obj, um.id), IUsersManager) # setup PAS obj._setupPAS()