| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
from OFS.SimpleItem import SimpleItem |
|---|
| 20 |
from OFS.SimpleItem import Item |
|---|
| 21 |
from OFS.PropertyManager import PropertyManager |
|---|
| 22 |
from Products.CMFCore.utils import UniqueObject |
|---|
| 23 |
from Globals import InitializeClass |
|---|
| 24 |
from AccessControl import ClassSecurityInfo |
|---|
| 25 |
from Products.CMFCore.utils import getToolByName |
|---|
| 26 |
from ZODB.PersistentMapping import PersistentMapping |
|---|
| 27 |
import xmlrpclib |
|---|
| 28 |
from socket import gaierror |
|---|
| 29 |
from xmlrpclib import ProtocolError |
|---|
| 30 |
from Acquisition import aq_base |
|---|
| 31 |
from config import MANAGE_PORTAL, ALL_CONTENT_TYPES |
|---|
| 32 |
|
|---|
| 33 |
class myremotebrain: |
|---|
| 34 |
""" my brain """ |
|---|
| 35 |
__allow_access_to_unprotected_subobjects__=1 |
|---|
| 36 |
def __init__(self, ob, data): |
|---|
| 37 |
self.__ob = ob |
|---|
| 38 |
self.data = data |
|---|
| 39 |
self.meta_type = self.data['meta_type'] |
|---|
| 40 |
|
|---|
| 41 |
|
|---|
| 42 |
|
|---|
| 43 |
|
|---|
| 44 |
|
|---|
| 45 |
|
|---|
| 46 |
|
|---|
| 47 |
def __get__(self, value): |
|---|
| 48 |
""" bobo """ |
|---|
| 49 |
try: |
|---|
| 50 |
return self.data[name] |
|---|
| 51 |
except: |
|---|
| 52 |
raise 'aiai' |
|---|
| 53 |
|
|---|
| 54 |
def getURL(self): |
|---|
| 55 |
""" get url """ |
|---|
| 56 |
return self.data['getURL'] |
|---|
| 57 |
|
|---|
| 58 |
def __getitem__(self, name): |
|---|
| 59 |
""" get item """ |
|---|
| 60 |
try: |
|---|
| 61 |
return self.data[name] |
|---|
| 62 |
except: |
|---|
| 63 |
raise 'getitem1' |
|---|
| 64 |
raise 'getitem2' |
|---|
| 65 |
|
|---|
| 66 |
def getPortalTypeName(self): |
|---|
| 67 |
""" portal type """ |
|---|
| 68 |
return self.data['meta_type'] |
|---|
| 69 |
|
|---|
| 70 |
def getObject(self): |
|---|
| 71 |
""" fake """ |
|---|
| 72 |
return self |
|---|
| 73 |
|
|---|
| 74 |
def getCoverImage(self): |
|---|
| 75 |
""" get coverimage """ |
|---|
| 76 |
class coverImage: |
|---|
| 77 |
__allow_access_to_unprotected_subobjects__=1 |
|---|
| 78 |
def __init__(self, url): |
|---|
| 79 |
self.url = url |
|---|
| 80 |
def absolute_url(self): |
|---|
| 81 |
return self.url+'/coverImage' |
|---|
| 82 |
return coverImage(self.data['getURL']) |
|---|
| 83 |
|
|---|
| 84 |
class LeMillSearchTool(PropertyManager, SimpleItem, UniqueObject): |
|---|
| 85 |
""" lemill search. Performs standard plone search and xml-rpc search to query distant lemilles """ |
|---|
| 86 |
|
|---|
| 87 |
id = 'lemill_search' |
|---|
| 88 |
meta_type = 'LeMillSearch' |
|---|
| 89 |
security = ClassSecurityInfo() |
|---|
| 90 |
plone_tool = 1 |
|---|
| 91 |
toolicon = 'skins/lemill/tool.gif' |
|---|
| 92 |
__allow_access_to_unprotected_subobjects__ = 1 |
|---|
| 93 |
|
|---|
| 94 |
def __init__(self,id=None): |
|---|
| 95 |
|
|---|
| 96 |
try: |
|---|
| 97 |
SimpleItem.__init__(self,id) |
|---|
| 98 |
except AttributeError: |
|---|
| 99 |
pass |
|---|
| 100 |
try: |
|---|
| 101 |
PropertyManager.__init__(self,id) |
|---|
| 102 |
except AttributeError: |
|---|
| 103 |
pass |
|---|
| 104 |
try: |
|---|
| 105 |
UniqueObject.__init__(self,id) |
|---|
| 106 |
except AttributeError: |
|---|
| 107 |
pass |
|---|
| 108 |
self._setProperty('enable_remotesearch', True, 'boolean') |
|---|
| 109 |
self.remote_lemilles = {} |
|---|
| 110 |
|
|---|
| 111 |
|
|---|
| 112 |
|
|---|
| 113 |
def lemill_search(self, REQUEST, **kw): |
|---|
| 114 |
""" lemill search method. performs local and remote searches """ |
|---|
| 115 |
results = [] |
|---|
| 116 |
if not kw.has_key('portal_type'): |
|---|
| 117 |
|
|---|
| 118 |
kw['portal_type'] = ALL_CONTENT_TYPES |
|---|
| 119 |
if not kw.has_key('getState'): |
|---|
| 120 |
kw['getState'] = ('public','draft') |
|---|
| 121 |
local = self.local_search(REQUEST, **kw) |
|---|
| 122 |
remote = [] |
|---|
| 123 |
show_deleted=False |
|---|
| 124 |
if self.getEnableRemoteSearch(): |
|---|
| 125 |
remote = self.remote_search(REQUEST, **kw) |
|---|
| 126 |
for x in local: |
|---|
| 127 |
results.append(x) |
|---|
| 128 |
for y in remote: |
|---|
| 129 |
rbrain = myremotebrain(aq_base(self).__of__(self),y) |
|---|
| 130 |
results.append(rbrain) |
|---|
| 131 |
return results |
|---|
| 132 |
|
|---|
| 133 |
security.declarePrivate('local_search') |
|---|
| 134 |
def local_search(self, REQUEST, **kw): |
|---|
| 135 |
""" do a local search """ |
|---|
| 136 |
portal_catalog = getToolByName( self, 'portal_catalog' ) |
|---|
| 137 |
results = portal_catalog.searchResults(REQUEST, **kw) |
|---|
| 138 |
return results |
|---|
| 139 |
|
|---|
| 140 |
security.declarePrivate('remote_search') |
|---|
| 141 |
def remote_search(self, REQUEST, **kw): |
|---|
| 142 |
""" do remote search. |
|---|
| 143 |
connects to distant lemill via xml-rpc and invokes incoming_query method. |
|---|
| 144 |
""" |
|---|
| 145 |
|
|---|
| 146 |
tb_locations = self.get_urls_of_remote_lemilles() |
|---|
| 147 |
result = [] |
|---|
| 148 |
if tb_locations is None: |
|---|
| 149 |
return result |
|---|
| 150 |
for tb in tb_locations: |
|---|
| 151 |
ping = self.ping(tb) |
|---|
| 152 |
if not ping: |
|---|
| 153 |
|
|---|
| 154 |
|
|---|
| 155 |
r = xmlrpclib.Server(tb+'/'+self.getId(), allow_none=1) |
|---|
| 156 |
query_str = REQUEST.get('QUERY_STRING') |
|---|
| 157 |
query = {} |
|---|
| 158 |
q_tmp = query_str.split('&') |
|---|
| 159 |
params = [] |
|---|
| 160 |
for pair in q_tmp: |
|---|
| 161 |
key_tmp, value = pair.split('=') |
|---|
| 162 |
key = key_tmp.split('%')[0] |
|---|
| 163 |
if key not in params: |
|---|
| 164 |
params.append(key) |
|---|
| 165 |
for p in params: |
|---|
| 166 |
query[p] = REQUEST.get(p) |
|---|
| 167 |
|
|---|
| 168 |
try: |
|---|
| 169 |
query['created'] = str(query['created']) |
|---|
| 170 |
except KeyError: |
|---|
| 171 |
pass |
|---|
| 172 |
from xmlrpclib import Fault |
|---|
| 173 |
try: |
|---|
| 174 |
result += r.incoming_search(query) |
|---|
| 175 |
|
|---|
| 176 |
except Fault: |
|---|
| 177 |
pass |
|---|
| 178 |
|
|---|
| 179 |
|
|---|
| 180 |
else: |
|---|
| 181 |
print "LeMill @ %s is dead!" % tb |
|---|
| 182 |
return result |
|---|
| 183 |
|
|---|
| 184 |
security.declarePublic('incoming_search') |
|---|
| 185 |
def incoming_search(self, query): |
|---|
| 186 |
""" search request coming from remote lemill uses this method """ |
|---|
| 187 |
from DateTime import DateTime |
|---|
| 188 |
|
|---|
| 189 |
|
|---|
| 190 |
try: |
|---|
| 191 |
query['created'] = eval(query['created']) |
|---|
| 192 |
except KeyError: |
|---|
| 193 |
pass |
|---|
| 194 |
query_results = self.local_search(query) |
|---|
| 195 |
results = [] |
|---|
| 196 |
for x in query_results: |
|---|
| 197 |
|
|---|
| 198 |
rr = {'Title':x.Title, |
|---|
| 199 |
'meta_type':x.meta_type, |
|---|
| 200 |
'Description':x.Description, |
|---|
| 201 |
'pretty_title_or_id':x.pretty_title_or_id(), |
|---|
| 202 |
'Creator':x.Creator, |
|---|
| 203 |
'ModificationDate':x.ModificationDate, |
|---|
| 204 |
'getURL':x.getURL(), |
|---|
| 205 |
'portal_type':x.portal_type, |
|---|
| 206 |
'getState':x.getState, |
|---|
| 207 |
'data_record_normalized_score_':x.data_record_normalized_score_, |
|---|
| 208 |
'getTags':x.getTags, |
|---|
| 209 |
'Language':x.Language, |
|---|
| 210 |
'absolute_url':x.getURL(), |
|---|
| 211 |
'getURL':x.getURL(), |
|---|
| 212 |
'getHasCoverImage' : x.getHasCoverImage, |
|---|
| 213 |
} |
|---|
| 214 |
results.append(rr) |
|---|
| 215 |
return results |
|---|
| 216 |
|
|---|
| 217 |
def get_urls_of_remote_lemilles(self): |
|---|
| 218 |
|
|---|
| 219 |
result = [] |
|---|
| 220 |
for x in self.remote_lemilles.values(): |
|---|
| 221 |
result.append(x['URL']) |
|---|
| 222 |
return result |
|---|
| 223 |
|
|---|
| 224 |
def get_remote_lemilles(self): |
|---|
| 225 |
return self.remote_lemilles |
|---|
| 226 |
|
|---|
| 227 |
def ping(self, address): |
|---|
| 228 |
|
|---|
| 229 |
address = address +'/'+ self.getId() |
|---|
| 230 |
r = xmlrpclib.Server(address) |
|---|
| 231 |
try: |
|---|
| 232 |
remote = r.pong('ping') |
|---|
| 233 |
except (ProtocolError, gaierror): |
|---|
| 234 |
|
|---|
| 235 |
return 1 |
|---|
| 236 |
except: |
|---|
| 237 |
return 1 |
|---|
| 238 |
if remote != 'pong': |
|---|
| 239 |
return 1 |
|---|
| 240 |
return 0 |
|---|
| 241 |
|
|---|
| 242 |
def pong(self, ping): |
|---|
| 243 |
""" respond to ping """ |
|---|
| 244 |
if ping != 'ping': |
|---|
| 245 |
return 1 |
|---|
| 246 |
return "pong" |
|---|
| 247 |
|
|---|
| 248 |
security.declareProtected(MANAGE_PORTAL, 'setNewLocation') |
|---|
| 249 |
def setNewLocation(self, location): |
|---|
| 250 |
""" set remote search location and protocol """ |
|---|
| 251 |
import time |
|---|
| 252 |
timestamp = time.time() |
|---|
| 253 |
while self.remote_lemilles.has_key(str(int(timestamp))): |
|---|
| 254 |
timestamp = time.time() |
|---|
| 255 |
timestamp = str(int(timestamp)) |
|---|
| 256 |
self.remote_lemilles[timestamp] = {'URL': location, 'protocol': 'xmlrpc'} |
|---|
| 257 |
self._p_changed = True |
|---|
| 258 |
return 0 |
|---|
| 259 |
|
|---|
| 260 |
security.declareProtected(MANAGE_PORTAL, 'delete_remote_lemill') |
|---|
| 261 |
def delete_remote_lemill(self, id): |
|---|
| 262 |
|
|---|
| 263 |
del self.remote_lemilles[id] |
|---|
| 264 |
self._p_changed = True |
|---|
| 265 |
|
|---|
| 266 |
def getEnableRemoteSearch(self): |
|---|
| 267 |
return self.enable_remotesearch |
|---|
| 268 |
|
|---|
| 269 |
security.declareProtected(MANAGE_PORTAL, 'setEnableRemoteSearch') |
|---|
| 270 |
def setEnableRemoteSearch(self, enable): |
|---|
| 271 |
self.enable_remotesearch = enable |
|---|
| 272 |
|
|---|
| 273 |
|
|---|
| 274 |
InitializeClass(LeMillSearchTool) |
|---|