bookmarkSvc.py (30920B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\bookmarks\bookmarkSvc.py 2 import heapq 3 from collections import defaultdict 4 import blue 5 import telemetry 6 import threadutils 7 import uthread 8 import locks 9 import utillib 10 from caching.memoize import Memoize 11 from carbon.common.script.sys.service import Service 12 from eve.client.script.ui.shared.bookmarks.linkedBookmarkFolderWindow import LinkedBookmarkFolderWindow 13 from eve.client.script.util.bookmarkUtil import IsBookmarkAvailable, GetACLBookmarkMenuForSystem 14 from eve.common.lib import appConst 15 from eve.common.script.mgt import bookmarkConst 16 from eve.common.script.mgt.bookmarkConst import SHARED_BOOKMARK_DELAY, MAX_BOOKMARKS_SENT_TO_CLIENT 17 from eve.common.script.sys import idCheckers 18 from eveexceptions import UserError 19 from evetypes import GetCategoryID 20 from localization import GetByLabel 21 from player_messaging.client.ui_message import prompt_player_fsd_dialog 22 from sensorsuite.overlay.bookmarkvisibilitymanager import ReleaseBookmarkFolderVisibilityManager 23 CACHE_EXPIRATION_TIME = 5 * appConst.MIN 24 MIN_DELAYED_UI_REFRESH_TIME = 5 * appConst.SEC 25 26 class BookmarkSvc(Service): 27 __guid__ = 'svc.bookmarkSvc' 28 __startupdependencies__ = ['machoNet'] 29 __notifyevents__ = ['OnSharedBookmarksFolderUpdated', 30 'OnSharedBookmarksFolderDeleted', 31 'OnSharedBookmarksFoldersAccessLost', 32 'OnSharedBookmarksFoldersAccessChanged', 33 'OnSessionReset'] 34 35 def Run(self, memStream = None): 36 Service.Run(self, memStream) 37 self.Initialize() 38 39 def Initialize(self): 40 self.accessGroupBookmarkMgr = sm.RemoteSvc('accessGroupBookmarkMgr') 41 self.lastUpdateTime = None 42 self.validCategories = (appConst.categoryCelestial, 43 appConst.categoryAsteroid, 44 appConst.categoryStation, 45 appConst.categoryShip, 46 appConst.categoryStarbase, 47 appConst.categoryPlanetaryInteraction) 48 self.bookmarksPrimed = False 49 self.foldersNew = {} 50 self.bookmarkCache = {} 51 self.bookmarkIDsBySolarystemID = defaultdict(set) 52 self.subfolders = {} 53 self.delayedUpdateQueue = [] 54 self.delayedUpdateThread = None 55 self.onlyPartiallyLoaded = False 56 57 def OnSessionReset(self): 58 if self.delayedUpdateThread is not None: 59 self.delayedUpdateThread.kill() 60 ReleaseBookmarkFolderVisibilityManager() 61 self.SearchFoldersWithAdminAccess.clear_memoized() 62 self.Initialize() 63 64 @telemetry.ZONE_METHOD 65 def GetBookmarks(self): 66 self.PrimeAndCleanupBookmarks() 67 return self.bookmarkCache 68 69 def PrimeAndCleanupBookmarks(self): 70 if not self.bookmarksPrimed: 71 self.ACLPrimeBookmarks() 72 if self.DoesCacheNeedUpdating(): 73 self.RefreshACLBookmarks() 74 self.lastUpdateTime = blue.os.GetWallclockTime() 75 76 def GetBookmarksForLocationID(self, locationID): 77 self.PrimeAndCleanupBookmarks() 78 ret = [] 79 bookmarksForLocationID = self.bookmarkIDsBySolarystemID.get(locationID, set()) 80 if not bookmarksForLocationID: 81 return ret 82 for eachBookmarkID in bookmarksForLocationID: 83 bm = self.GetBookmark(eachBookmarkID) 84 if bm: 85 ret.append(bm) 86 87 return ret 88 89 def DoesCacheNeedUpdating(self): 90 if self.lastUpdateTime is None: 91 return True 92 timeSinceLastUpdate = blue.os.GetWallclockTime() - self.lastUpdateTime 93 return timeSinceLastUpdate > CACHE_EXPIRATION_TIME 94 95 def GetBookmark(self, bookmarkID): 96 return self.bookmarkCache[bookmarkID] 97 98 @threadutils.Throttled(2) 99 def RefreshUIOnUpdate(self): 100 sm.ScatterEvent('OnRefreshBookmarks') 101 102 def GetPersonalAndSharedFolders(self): 103 personal = set() 104 shared = set() 105 for eachFolderID, eachFolder in self.GetFolders().iteritems(): 106 if eachFolder.isPersonal: 107 personal.add(eachFolderID) 108 else: 109 shared.add(eachFolderID) 110 111 return (personal, shared) 112 113 def GetAgentBookmarks(self): 114 bookmarks = {} 115 agentMenu = sm.GetService('journal').GetMyAgentJournalBookmarks() 116 if agentMenu: 117 for missionNameID, bms, agentID in agentMenu: 118 missionName = unicode(missionNameID) + unicode(agentID) 119 for bm in bms: 120 c = bm.copy() 121 c.missionName = missionName 122 c.hint = bm.hint 123 c.memo = c.hint + '\t' 124 c.missionNameID = missionNameID 125 c.bookmarkID = ('agentmissions', 126 c.agentID, 127 c.locationType, 128 c.locationNumber) 129 c.expiry = None 130 bookmarks[c.bookmarkID] = c 131 132 return bookmarks 133 134 def GetAllBookmarks(self): 135 bms = self.GetBookmarks().copy() 136 bms.update(self.GetAgentBookmarks()) 137 return bms 138 139 def UnzipMemo(self, s): 140 if s is None: 141 s = '' 142 if '\t' in s: 143 split = s.split('\t') 144 else: 145 split = [ each.replace('\\|', '|') for each in s.split('||') ] 146 if len(split) == 1: 147 return (split[0], '') 148 return split[:2] 149 150 @telemetry.ZONE_METHOD 151 def ACLPrimeBookmarks(self): 152 if self.bookmarksPrimed: 153 return 154 with locks.TempLock('PrimeACLBookmarks'): 155 if self.bookmarksPrimed: 156 return 157 folders, bookmarks, subfolders = self.accessGroupBookmarkMgr.GetMyActiveBookmarks() 158 self.foldersNew = {folder.folderID:folder for folder in folders} 159 for eachBookmark in bookmarks: 160 self.bookmarkCache[eachBookmark.bookmarkID] = eachBookmark 161 self.bookmarkIDsBySolarystemID[eachBookmark.locationID].add(eachBookmark.bookmarkID) 162 163 self.subfolders = {subfolder.subfolderID:subfolder for subfolder in subfolders} 164 self.lastUpdateTime = blue.os.GetWallclockTime() 165 self.bookmarksPrimed = True 166 if len(bookmarks) >= MAX_BOOKMARKS_SENT_TO_CLIENT: 167 self.onlyPartiallyLoaded = True 168 if not self.foldersNew: 169 self.CreateDefaultFolder() 170 self.CheckBookmarksForDelayedUpdate(bookmarks) 171 172 @telemetry.ZONE_METHOD 173 def RefreshACLBookmarks(self): 174 self.LogNotice('RefreshACLBookmarks called') 175 self.RemoveExpiredBookmarks() 176 self.RefreshUIOnUpdate() 177 178 def RemoveExpiredBookmarks(self): 179 for bookmarkID, bookmark in self.bookmarkCache.items(): 180 if bookmark.expiry and bookmark.expiry < blue.os.GetWallclockTime(): 181 del self.bookmarkCache[bookmarkID] 182 self.bookmarkIDsBySolarystemID[bookmark.locationID].discard(bookmark.bookmarkID) 183 184 def CheckBookmarksForDelayedUpdate(self, bookmarks): 185 refreshDelayedAt = [] 186 for bookmark in bookmarks: 187 if not bookmark.creatorID or bookmark.creatorID == session.charid: 188 continue 189 if bookmark.created + SHARED_BOOKMARK_DELAY > blue.os.GetWallclockTime(): 190 refreshDelayedAt.append(bookmark.created + SHARED_BOOKMARK_DELAY) 191 192 if refreshDelayedAt: 193 self.RefreshUIDelayed(refreshDelayedAt) 194 195 def RefreshUIDelayed(self, timeStamps): 196 for timeStamp in timeStamps: 197 heapq.heappush(self.delayedUpdateQueue, timeStamp) 198 199 if self.delayedUpdateThread: 200 return 201 self.delayedUpdateThread = uthread.worker('bookmarkSvc::DelayedUpdateThread', self.DelayedUpdateThread) 202 203 @telemetry.ZONE_METHOD 204 def DelayedUpdateThread(self): 205 time = 0 206 while self.delayedUpdateQueue: 207 while self.delayedUpdateQueue: 208 time = heapq.heappop(self.delayedUpdateQueue) 209 if time > blue.os.GetWallclockTime(): 210 break 211 212 sleep = int(max(MIN_DELAYED_UI_REFRESH_TIME, time - blue.os.GetWallclockTime()) / 10000) 213 blue.pyos.synchro.SleepWallclock(sleep) 214 self.RefreshUIOnUpdate() 215 216 self.delayedUpdateThread = None 217 218 @telemetry.ZONE_METHOD 219 def OnSharedBookmarksFolderUpdated(self, updates): 220 for target, updateType, updateArgs in updates: 221 if updateType == bookmarkConst.BOOKMARKS_MOVED: 222 bookmarks, oldFolderID, newFolderID = updateArgs 223 if newFolderID not in self.foldersNew or not self.foldersNew[newFolderID].isActive: 224 if oldFolderID in self.foldersNew and self.foldersNew[oldFolderID].isActive: 225 bookmarkIDs = [ bm.bookmarkID for bm in bookmarks ] 226 self._RemoveBookmarksFromCache(bookmarkIDs) 227 else: 228 self._AddBookmarksToCache(bookmarks) 229 continue 230 folderID = target[0] 231 if folderID not in self.foldersNew or not self.foldersNew[folderID].isActive: 232 self.LogInfo('Tried to update folder, which is not an active folder', folderID) 233 continue 234 if updateType == bookmarkConst.BOOKMARKS_ADDED: 235 bookmarks = updateArgs 236 self._AddBookmarksToCache(bookmarks) 237 elif updateType == bookmarkConst.BOOKMARKS_REMOVED: 238 deletedBookmarkIDs = updateArgs 239 self._RemoveBookmarksFromCache(deletedBookmarkIDs) 240 elif updateType == bookmarkConst.BOOKMARKS_UPDATED: 241 bookmarks = updateArgs 242 self._AddBookmarksToCache(bookmarks) 243 continue 244 elif updateType == bookmarkConst.FOLDER_UPDATED: 245 name, description = updateArgs 246 self._UpdateFolderInCache(folderID, name, description) 247 elif updateType == bookmarkConst.SUBFOLDER_ADDED: 248 subfolder = updateArgs 249 self._AddSubfolderToCache(subfolder) 250 elif updateType == bookmarkConst.SUBFOLDER_UPDATED: 251 subfolderID, subfolderName = updateArgs 252 self._UpdateSubfolderName(subfolderID, subfolderName) 253 elif updateType == bookmarkConst.SUBFOLDER_REMOVED: 254 subfolderID = updateArgs 255 self._RemoveSubfolderFromCache(subfolderID) 256 257 self.RefreshUIOnUpdate() 258 259 def _AddBookmarksToCache(self, bookmarks): 260 for bm in bookmarks: 261 self.bookmarkCache[bm.bookmarkID] = bm 262 self.bookmarkIDsBySolarystemID[bm.locationID].add(bm.bookmarkID) 263 264 self.CheckBookmarksForDelayedUpdate(bookmarks) 265 266 def _RemoveBookmarksFromCache(self, deletedBookmarkIDs): 267 for bookmarkID in deletedBookmarkIDs: 268 bm = self.bookmarkCache.pop(bookmarkID, None) 269 if bm: 270 self.bookmarkIDsBySolarystemID[bm.locationID].discard(bm.bookmarkID) 271 272 def _UpdateFolderInCache(self, folderID, folderName, description): 273 if folderID not in self.foldersNew: 274 return 275 self.foldersNew[folderID].folderName = folderName 276 self.foldersNew[folderID].description = description 277 278 def _AddSubfolderToCache(self, subfolder): 279 self.subfolders[subfolder.subfolderID] = subfolder 280 281 def _UpdateSubfolderName(self, subfolderID, subfolderName): 282 if subfolderID not in self.subfolders: 283 return 284 self.subfolders[subfolderID].subfolderName = subfolderName 285 286 def _RemoveSubfolderFromCache(self, subfolderID): 287 self.subfolders.pop(subfolderID, None) 288 289 def GetFolderNamesAndType(self, folderID, subfolderID): 290 folder = self.foldersNew.get(folderID, None) 291 isPersonal = folder.isPersonal if folder else True 292 subfolder = self.subfolders.get(subfolderID, None) 293 folderNames = [] 294 if folder: 295 folderNames.append(folder.folderName) 296 if subfolder: 297 folderNames.append(subfolder.subfolderName) 298 return (folderNames, isPersonal) 299 300 def OnSharedBookmarksFolderDeleted(self, folderID): 301 if folderID not in self.foldersNew: 302 self.LogInfo('Tried to remove folder, which is not a known folder: ', folderID) 303 return 304 self.foldersNew.pop(folderID, None) 305 self.RemoveFolderContentFromCache([folderID]) 306 self.RefreshUIOnUpdate() 307 308 def OnSharedBookmarksFoldersAccessLost(self, folderIDs): 309 for folderID in folderIDs: 310 if folderID not in self.foldersNew: 311 self.LogInfo('Tried to remove folder, which is not a known folder: ', folderID) 312 continue 313 self.foldersNew.pop(folderID, None) 314 315 self.RemoveFolderContentFromCache(folderIDs) 316 self.RefreshUIOnUpdate() 317 318 def OnSharedBookmarksFoldersAccessChanged(self, accessChanged): 319 for folderID, accessLevel in accessChanged.iteritems(): 320 if folderID in self.foldersNew: 321 self.foldersNew[folderID].accessLevel = accessLevel 322 323 def AddToKnownFolders(self, folderID, isActive): 324 maxKnownFolders = appConst.MAX_KNOWN_BOOKMARK_FOLDERS 325 if folderID in self.foldersNew: 326 self.LogWarn('Tried to add a folder, which has been added already: ', folderID) 327 return 328 if len(self.foldersNew) >= maxKnownFolders: 329 raise UserError('TooManyKnownFolders', {'maxKnownFolders': maxKnownFolders}) 330 folder, bookmarks, subfolders = self.accessGroupBookmarkMgr.AddToKnownFolders(folderID, isActive) 331 self.foldersNew[folderID] = folder 332 if folder.isActive: 333 for eachBookmark in bookmarks: 334 self.bookmarkCache[eachBookmark.bookmarkID] = eachBookmark 335 self.bookmarkIDsBySolarystemID[eachBookmark.locationID].add(eachBookmark.bookmarkID) 336 337 self.subfolders.update({subfolder.subfolderID:subfolder for subfolder in subfolders}) 338 self.CheckBookmarksForDelayedUpdate(bookmarks) 339 if len(bookmarks) >= MAX_BOOKMARKS_SENT_TO_CLIENT: 340 self.onlyPartiallyLoaded = True 341 if isActive and not folder.isActive: 342 prompt_player_fsd_dialog('CustomNotify', {'notify': GetByLabel('UI/AclBookmarks/FolderAddedAsInactiveFolder')}) 343 self.RefreshUIOnUpdate() 344 345 @telemetry.ZONE_METHOD 346 def GetActiveBookmarksFiltered(self, solarSystemID = None, usePersonalFilter = False, personal = True): 347 filteredFolderIDs = set() 348 if usePersonalFilter: 349 personalFolderIDs, sharedFolderIDs = self.GetPersonalAndSharedFolders() 350 if personal: 351 filteredFolderIDs = personalFolderIDs 352 else: 353 filteredFolderIDs = sharedFolderIDs 354 now = blue.os.GetWallclockTime() 355 filteredBookmarks = {} 356 for bmID, bm in self.GetBookmarks().iteritems(): 357 if solarSystemID and bm.locationID != solarSystemID: 358 continue 359 if usePersonalFilter and bm.folderID not in filteredFolderIDs: 360 continue 361 if IsBookmarkAvailable(bm.creatorID, bm.created, now): 362 filteredBookmarks[bmID] = bm 363 364 return filteredBookmarks 365 366 @telemetry.ZONE_METHOD 367 def GetFilteredFoldersAndSubfolders(self, forcedFolderID = None): 368 filteredFolders = [] 369 filteredFolderIDs = [] 370 for folder in self.foldersNew.itervalues(): 371 if folder.accessLevel == appConst.ACCESS_VIEW: 372 continue 373 if not folder.isActive: 374 continue 375 bmCount = sum((1 for bm in self.bookmarkCache.itervalues() if bm.folderID == folder.folderID)) 376 maxBookmarks = appConst.MAX_BOOKMARKS_IN_PERSONAL_FOLDER if folder.isPersonal else appConst.MAX_BOOKMARKS_IN_SHARED_FOLDER 377 if bmCount >= maxBookmarks and (not forcedFolderID or forcedFolderID != folder.folderID): 378 continue 379 filteredFolders.append(folder) 380 filteredFolderIDs.append(folder.folderID) 381 382 filteredSubfolders = [ subfolder for subfolder in self.subfolders.itervalues() if subfolder.folderID in filteredFolderIDs ] 383 return (filteredFolders, filteredSubfolders) 384 385 def GetBookmarksFoldersAndSubfolders(self): 386 return (self.GetBookmarks(), self.foldersNew, self.subfolders) 387 388 def GetBookmarksBySubfolderByFolder(self): 389 bookmarksBySubfolderByFolder = defaultdict(lambda : defaultdict(set)) 390 for bookmark in self.GetBookmarks().itervalues(): 391 bookmarksBySubfolderByFolder[bookmark.folderID][bookmark.subfolderID].add(bookmark) 392 393 return bookmarksBySubfolderByFolder 394 395 def CreateBookmarkFolder(self, isPersonal, folderName, description, adminGroupID, manageGroupID, useGroupID, viewGroupID): 396 folder = self.accessGroupBookmarkMgr.AddFolder(isPersonal, folderName, description, adminGroupID, manageGroupID, useGroupID, viewGroupID) 397 if folder: 398 self.foldersNew[folder.folderID] = folder 399 self.RefreshUIOnUpdate() 400 return folder 401 402 def CreateDefaultFolder(self): 403 name = GetByLabel('UI/AclBookmarks/DefaultFolderName') 404 self.CreateBookmarkFolder(True, name, '', None, None, None, None) 405 406 @telemetry.ZONE_METHOD 407 def UpdateBookmarkFolder(self, folderID, folderName, description, adminGroupID, manageGroupID, useGroupID, viewGroupID): 408 if folderID not in self.foldersNew: 409 raise UserError('BookmarkFolderNoLongerThere') 410 accessLevel = self.accessGroupBookmarkMgr.UpdateFolder(folderID, folderName, description, adminGroupID, manageGroupID, useGroupID, viewGroupID) 411 if accessLevel == appConst.ACCESS_NONE: 412 self.foldersNew.pop(folderID, None) 413 self.RemoveFolderContentFromCache([folderID]) 414 else: 415 self.foldersNew[folderID].update({'folderName': folderName, 416 'description': description, 417 'adminGroupID': adminGroupID, 418 'manageGroupID': manageGroupID, 419 'useGroupID': useGroupID, 420 'viewGroupID': viewGroupID, 421 'accessLevel': accessLevel}) 422 self.RefreshUIOnUpdate() 423 424 def DeleteBookmarkFolder(self, folderID): 425 self.accessGroupBookmarkMgr.DeleteFolder(folderID) 426 self.foldersNew.pop(folderID, None) 427 self.RemoveFolderContentFromCache([folderID]) 428 self.RefreshUIOnUpdate() 429 430 def RemoveFromKnownFolders(self, folderID): 431 self.accessGroupBookmarkMgr.RemoveFromKnownFolders(folderID) 432 self.foldersNew.pop(folderID, None) 433 self.RemoveFolderContentFromCache([folderID]) 434 self.RefreshUIOnUpdate() 435 436 def RemoveFolderContentFromCache(self, folderIDs): 437 for bookmarkID, bookmark in self.bookmarkCache.items(): 438 if bookmark.folderID in folderIDs: 439 del self.bookmarkCache[bookmarkID] 440 self.bookmarkIDsBySolarystemID[bookmark.locationID].discard(bookmarkID) 441 442 for subfolderID, subfolder in self.subfolders.items(): 443 if subfolder.folderID in folderIDs: 444 del self.subfolders[subfolderID] 445 446 @telemetry.ZONE_METHOD 447 def UpdateFolderActiveState(self, folderID, isActive): 448 if isActive: 449 self.ValidateActiveFolderCount(folderID) 450 try: 451 folder, bookmarks, subfolders = self.accessGroupBookmarkMgr.UpdateKnownFolderState(folderID, isActive) 452 except UserError as e: 453 if e.msg in ('BookmarkFolderNoLongerThere', 'FolderAccessDenied'): 454 self.foldersNew.pop(folderID, None) 455 self.RefreshUIOnUpdate() 456 raise 457 458 self.foldersNew[folderID] = folder 459 if isActive: 460 for eachBookmark in bookmarks: 461 self.bookmarkCache[eachBookmark.bookmarkID] = eachBookmark 462 self.bookmarkIDsBySolarystemID[eachBookmark.locationID].add(eachBookmark.bookmarkID) 463 464 self.subfolders.update({subfolder.subfolderID:subfolder for subfolder in subfolders}) 465 self.CheckBookmarksForDelayedUpdate(bookmarks) 466 if len(bookmarks) >= MAX_BOOKMARKS_SENT_TO_CLIENT: 467 self.onlyPartiallyLoaded = True 468 else: 469 self.RemoveFolderContentFromCache([folderID]) 470 self.RefreshUIOnUpdate() 471 472 def ValidateActiveFolderCount(self, folderID): 473 folder = self.foldersNew[folderID] 474 if folder.isPersonal: 475 maxActiveFolders = appConst.MAX_ACTIVE_PERSONAL_BOOKMARK_FOLDERS 476 activeFolder = sum((1 for f in self.foldersNew.itervalues() if f.isPersonal and f.isActive)) 477 else: 478 maxActiveFolders = appConst.MAX_ACTIVE_SHARED_BOOKMARK_FOLDERS 479 activeFolder = sum((1 for f in self.foldersNew.itervalues() if not f.isPersonal and f.isActive)) 480 if activeFolder >= maxActiveFolders: 481 raise UserError('TooManyActiveFolders', {'maxPersonalFolders': appConst.MAX_ACTIVE_PERSONAL_BOOKMARK_FOLDERS, 482 'maxSharedFolders': appConst.MAX_ACTIVE_SHARED_BOOKMARK_FOLDERS}) 483 484 def GetBookmarkFolder(self, folderID, refresh = False): 485 if refresh: 486 folder = self.accessGroupBookmarkMgr.GetFolderInfo(folderID) 487 folder.isActive = self.foldersNew[folderID].isActive 488 self.foldersNew[folderID] = folder 489 return self.foldersNew[folderID] 490 491 def GetFolderInfo(self, folderID): 492 if folderID in self.foldersNew: 493 return self.foldersNew[folderID] 494 else: 495 return self.accessGroupBookmarkMgr.GetFolderInfo(folderID) 496 497 def GetFolders(self): 498 return self.foldersNew 499 500 def GetFilteredFolders(self): 501 filteredFolders = [] 502 for folder in self.foldersNew.itervalues(): 503 if folder.accessLevel == appConst.ACCESS_VIEW: 504 continue 505 if not folder.isActive: 506 continue 507 filteredFolders.append(folder) 508 509 return filteredFolders 510 511 def ShowBookmarkFolderInfo(self, folderID): 512 alreadyKnown = folderID in self.foldersNew 513 try: 514 folder = self.GetFolderInfo(folderID) 515 except UserError as e: 516 if e.msg == 'FolderAccessDenied': 517 prompt_player_fsd_dialog('CustomInfo', {'info': GetByLabel('UI/AclBookmarks/NoAccessToBookmarkFolder')}) 518 return 519 raise 520 521 wnd = LinkedBookmarkFolderWindow.GetIfOpen() 522 if wnd: 523 if wnd.folder.folderID == folderID: 524 return wnd.Maximize() 525 wnd.Close() 526 LinkedBookmarkFolderWindow.Open(folder=folder, alreadyKnown=alreadyKnown) 527 528 def CreateSubfolder(self, folderID, subfolderName): 529 subfolder = self.accessGroupBookmarkMgr.CreateSubfolder(folderID, subfolderName) 530 if subfolder: 531 self.subfolders[subfolder.subfolderID] = subfolder 532 self.RefreshUIOnUpdate() 533 534 def UpdateSubfolder(self, folderID, subfolderID, subfolderName): 535 if self.accessGroupBookmarkMgr.UpdateSubfolder(folderID, subfolderID, subfolderName): 536 self.subfolders[subfolderID].subfolderName = subfolderName 537 self.RefreshUIOnUpdate() 538 else: 539 raise UserError('BookmarkSubfolderNoLongerThere') 540 541 def DeleteSubfolder(self, subfolderID): 542 if subfolderID not in self.subfolders: 543 raise UserError('BookmarkSubfolderNoLongerThere') 544 subfolder = self.subfolders[subfolderID] 545 folder = self.foldersNew[subfolder.folderID] 546 if folder.accessLevel == appConst.ACCESS_USE: 547 for bookmark in self.bookmarkCache.itervalues(): 548 if bookmark.subfolderID == subfolderID and bookmark.creatorID != session.charid: 549 raise UserError('CouldNotDeleteBookmarksInSubfolder') 550 551 deletedBookmarkIDs = self.accessGroupBookmarkMgr.DeleteSubfolder(subfolder.folderID, subfolderID) 552 self.subfolders.pop(subfolderID, None) 553 for bookmarkID in deletedBookmarkIDs: 554 bm = self.bookmarkCache.pop(bookmarkID, None) 555 if bm: 556 self.bookmarkIDsBySolarystemID[bm.locationID].discard(bm.bookmarkID) 557 558 self.RefreshUIOnUpdate() 559 560 def GetSubfolder(self, subfolderID): 561 return self.subfolders[subfolderID] 562 563 def GetSubfolders(self): 564 return self.subfolders 565 566 def GetSubfoldersInFolder(self, folderID): 567 return {subfolder.subfolderID:subfolder for subfolder in self.subfolders.itervalues() if subfolder.folderID == folderID} 568 569 @telemetry.ZONE_METHOD 570 def ACLBookmarkLocation(self, itemID, folderID, name, comment, itemTypeID, expiry, subfolderID = None): 571 categoryID = GetCategoryID(itemTypeID) 572 if idCheckers.IsRegion(itemID) or idCheckers.IsConstellation(itemID) or idCheckers.IsSolarSystem(itemID) or idCheckers.IsStation(itemID) or idCheckers.IsStructure(categoryID): 573 bookmarkID, itemID, typeID, x, y, z, locationID, expiryDate = self.accessGroupBookmarkMgr.BookmarkStaticLocation(itemID, folderID, name, comment, expiry, subfolderID=subfolderID) 574 else: 575 bp = sm.StartService('michelle').GetRemotePark() 576 if not bp: 577 raise UserError('BkmMustBeInFlight') 578 bookmarkID, itemID, typeID, x, y, z, locationID, expiryDate = bp.BookmarkLocation(itemID, folderID, name, comment, expiry, subfolderID=subfolderID) 579 if bookmarkID: 580 self.NewBookmarkCreated(bookmarkID, folderID, itemID, typeID, name, comment, expiryDate, locationID, x, y, z, subfolderID, itemTypeID) 581 582 @telemetry.ZONE_METHOD 583 def ACLBookmarkScanResult(self, locationID, name, comment, resultID, folderID, expiry, subfolderID = None): 584 itemID, typeID = sm.GetService('sensorSuite').GetPositionalSiteItemIDFromTargetID(resultID) 585 if itemID is not None: 586 self.ACLBookmarkLocation(itemID, folderID, name, comment, typeID, expiry, subfolderID=subfolderID) 587 return 588 bookmarkID, itemID, typeID, x, y, z, locationID, expiryDate = sm.StartService('michelle').GetRemotePark().BookmarkScanResult(locationID, name, comment, resultID, folderID, expiry, subfolderID=subfolderID) 589 if bookmarkID: 590 self.NewBookmarkCreated(bookmarkID, folderID, None, typeID, name, comment, expiryDate, locationID, x, y, z, subfolderID, None) 591 592 def NewBookmarkCreated(self, bookmarkID, folderID, itemID, typeID, name, comment, expiryDate, locationID, x, y, z, subfolderID, itemTypeID): 593 bm = utillib.KeyVal(bookmarkID=bookmarkID, folderID=folderID, itemID=itemID, typeID=typeID, flag=None, memo=name, created=blue.os.GetWallclockTimeNow(), expiry=expiryDate, x=x, y=y, z=z, locationID=locationID, note=comment, subfolderID=subfolderID, creatorID=session.charid) 594 self.bookmarkCache[bookmarkID] = bm 595 self.bookmarkIDsBySolarystemID[bm.locationID].add(bm.bookmarkID) 596 self.RefreshUIOnUpdate() 597 sm.ScatterEvent('OnBookmarkCreated', bookmarkID, comment, itemTypeID) 598 599 def UpdateACLBookmark(self, bookmarkID, folderID, name, note, subfolderID, newFolderID, expiryCancel): 600 if bookmarkID not in self.bookmarkCache: 601 raise UserError('BookmarkNotAvailable') 602 bookmark = self.bookmarkCache[bookmarkID] 603 self.accessGroupBookmarkMgr.UpdateBookmark(bookmarkID, folderID, name, note, subfolderID, newFolderID, expiryCancel) 604 bookmark.folderID = newFolderID 605 bookmark.memo = name 606 bookmark.note = note 607 bookmark.subfolderID = subfolderID 608 if expiryCancel: 609 bookmark.expiry = None 610 self.RefreshUIOnUpdate() 611 612 def DeleteBookmarks(self, bookmarkIDs): 613 bookmarksByFolder = defaultdict(set) 614 for bookmarkID in bookmarkIDs: 615 bookmark = self.bookmarkCache[bookmarkID] 616 bookmarksByFolder[bookmark.folderID].add(bookmarkID) 617 618 deletedBookmarks = [] 619 for folderID, bookmarks in bookmarksByFolder.iteritems(): 620 deleted = self.accessGroupBookmarkMgr.DeleteBookmarks(folderID, bookmarks) 621 deletedBookmarks.extend(deleted) 622 623 if not deletedBookmarks: 624 raise UserError('CouldNotDeleteBookmark') 625 for bookmarkID in deletedBookmarks: 626 bm = self.bookmarkCache.pop(bookmarkID, None) 627 if bm: 628 self.bookmarkIDsBySolarystemID[bm.locationID].discard(bookmarkID) 629 630 self.RefreshUIOnUpdate() 631 632 @telemetry.ZONE_METHOD 633 def MoveOrCopyBookmarks(self, folderID, subfolderID, bookmarkIDs, forceCopy): 634 bookmarksToMoveBySourceFolder = defaultdict(set) 635 bookmarksToCopyBySourceFolder = defaultdict(set) 636 for bookmarkID in bookmarkIDs: 637 bookmark = self.bookmarkCache[bookmarkID] 638 if bookmark.subfolderID == subfolderID and bookmark.folderID == folderID: 639 continue 640 if forceCopy or self.foldersNew[bookmark.folderID].accessLevel not in (appConst.ACCESS_PERSONAL, appConst.ACCESS_MANAGE, appConst.ACCESS_ADMIN): 641 bookmarksToCopyBySourceFolder[bookmark.folderID].add(bookmarkID) 642 else: 643 bookmarksToMoveBySourceFolder[bookmark.folderID].add(bookmarkID) 644 645 for oldFolderID, bookmarkIDs in bookmarksToMoveBySourceFolder.iteritems(): 646 rows, message = self.accessGroupBookmarkMgr.MoveBookmarksToFolderAndSubfolder(oldFolderID, folderID, subfolderID, bookmarkIDs) 647 if message is not None: 648 uthread.new(prompt_player_fsd_dialog, *message) 649 for row in rows: 650 try: 651 self.bookmarkCache[row.bookmarkID].folderID = row.folderID 652 self.bookmarkCache[row.bookmarkID].subfolderID = row.subfolderID 653 except KeyError: 654 self.LogInfo('Bookmark not found in cache after moving it:', row.bookmarkID) 655 656 for oldFolderID, bookmarkIDs in bookmarksToCopyBySourceFolder.iteritems(): 657 newBookmarks, message = self.accessGroupBookmarkMgr.CopyBookmarksToFolderAndSubfolder(oldFolderID, folderID, subfolderID, bookmarkIDs) 658 if message is not None: 659 uthread.new(prompt_player_fsd_dialog, *message) 660 for eachBookmark in newBookmarks.itervalues(): 661 self.bookmarkIDsBySolarystemID[eachBookmark.locationID].add(eachBookmark.bookmarkID) 662 663 self.bookmarkCache.update(newBookmarks) 664 665 self.RefreshUIOnUpdate() 666 667 @Memoize(2) 668 def SearchFoldersWithAdminAccess(self): 669 result = self.accessGroupBookmarkMgr.SearchFoldersWithAdminAccess() 670 return result 671 672 def GetBookmarkMenuForNavigation(self, includeTopLevel = True): 673 m = [] 674 bookmarks, folders, subfolders = self.GetBookmarksFoldersAndSubfolders() 675 bookmarkMenu = GetACLBookmarkMenuForSystem(bookmarks, folders, subfolders, includeTopLevel) 676 if bookmarkMenu: 677 m += bookmarkMenu 678 return m